changeset 12698:d59a65c11feb

HSAIL support for difference between compression of oops and class pointers Contributed-by: Tom Deneau <tom.deneau@amd.com>
author Doug Simon <doug.simon@oracle.com>
date Wed, 06 Nov 2013 18:49:59 +0100
parents 8577cb721f51
children 38b84d5a66fd
files graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/InstanceOfTest.java graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java
diffstat 4 files changed, 220 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Wed Nov 06 18:43:45 2013 +0100
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Wed Nov 06 18:49:59 2013 +0100
@@ -355,39 +355,75 @@
     }
 
     /**
-     * Emit code to build a 64-bit pointer from a compressed-oop and the associated base and shift.
-     * We only emit this if base and shift are not both zero.
+     * Emits code to build a 64-bit pointer from a compressed value and the associated base and
+     * shift. The compressed value could represent either a normal oop or a klass ptr. If the
+     * compressed value is 0, the uncompressed must also be 0. We only emit this if base and shift
+     * are not both zero.
+     * 
+     * @param result the register containing the compressed value on input and the uncompressed ptr
+     *            on output
+     * @param base the amount to be added to the compressed value
+     * @param shift the number of bits to shift left the compressed value
+     * @param testForNull true if the compressed value might be null
      */
-    public void emitCompressedOopDecode(Value result, long narrowOopBase, int narrowOopShift) {
-        if (narrowOopBase == 0) {
-            emit("shl", result, result, Constant.forInt(narrowOopShift));
-        } else if (narrowOopShift == 0) {
-            // only use add if result is not starting as null (unsigned compare)
-            emitCompare(result, Constant.forLong(0), "eq", false, true);
-            emit("add", result, result, Constant.forLong(narrowOopBase));
-            emitConditionalMove(result, Constant.forLong(0), result, 64);
+    public void emitCompressedOopDecode(Value result, long base, int shift, boolean testForNull) {
+        assert (base != 0 || shift != 0);
+        assert (!isConstant(result));
+        if (base == 0) {
+            // we don't have to test for null if shl is the only operation
+            emitForceUnsigned("shl", result, result, Constant.forInt(shift));
+        } else if (shift == 0) {
+            // only use add if result is not starting as null (test only if testForNull is true)
+            emitWithOptionalTestForNull(testForNull, "add", result, result, Constant.forLong(base));
         } else {
-            // only use mad if result is not starting as null (unsigned compare)
-            emitCompare(result, Constant.forLong(0), "eq", false, true);
-            emitTextFormattedInstruction("mad_u64 ", result, result, Constant.forInt(1 << narrowOopShift), Constant.forLong(narrowOopBase));
-            emitConditionalMove(result, Constant.forLong(0), result, 64);
+            // only use mad if result is not starting as null (test only if testForNull is true)
+            emitWithOptionalTestForNull(testForNull, "mad", result, result, Constant.forInt(1 << shift), Constant.forLong(base));
         }
     }
 
     /**
-     * Emit code to build a 32-bit compressed pointer from a full 64-bit pointer using the
-     * associated base and shift. We only emit this if base and shift are not both zero.
+     * Emits code to build a compressed value from a full 64-bit pointer using the associated base
+     * and shift. The compressed value could represent either a normal oop or a klass ptr. If the
+     * ptr is 0, the compressed value must also be 0. We only emit this if base and shift are not
+     * both zero.
+     * 
+     * @param result the register containing the 64-bit pointer on input and the compressed value on
+     *            output
+     * @param base the amount to be subtracted from the 64-bit pointer
+     * @param shift the number of bits to shift right the 64-bit pointer
+     * @param testForNull true if the 64-bit pointer might be null
      */
-    public void emitCompressedOopEncode(Value result, long narrowOopBase, int narrowOopShift) {
-        if (narrowOopBase != 0) {
-            // only use sub if result is not starting as null (unsigned compare)
+    public void emitCompressedOopEncode(Value result, long base, int shift, boolean testForNull) {
+        assert (base != 0 || shift != 0);
+        assert (!isConstant(result));
+        if (base != 0) {
+            // only use sub if result is not starting as null (test only if testForNull is true)
+            emitWithOptionalTestForNull(testForNull, "sub", result, result, Constant.forLong(base));
+        }
+        if (shift != 0) {
+            // note that the shr can still be done even if the result is null
+            emitForceUnsigned("shr", result, result, Constant.forInt(shift));
+        }
+    }
+
+    /**
+     * Emits code for the requested mnemonic on the result and sources. In addition, if testForNull
+     * is true, surrounds the instruction with code that will guarantee that if the result starts as
+     * 0, it will remain 0.
+     * 
+     * @param testForNull true if we want to add the code to check for and preserve null
+     * @param mnemonic the instruction to be applied (without size prefix)
+     * @param result the register which is both an input and the final output
+     * @param sources the sources for the mnemonic instruction
+     */
+    private void emitWithOptionalTestForNull(boolean testForNull, String mnemonic, Value result, Value... sources) {
+        if (testForNull) {
             emitCompare(result, Constant.forLong(0), "eq", false, true);
-            emit("sub", result, result, Constant.forLong(narrowOopBase));
+        }
+        emitForceUnsigned(mnemonic, result, sources);
+        if (testForNull) {
             emitConditionalMove(result, Constant.forLong(0), result, 64);
         }
-        if (narrowOopShift != 0) {
-            emit("shr", result, result, Constant.forInt(narrowOopShift));
-        }
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/InstanceOfTest.java	Wed Nov 06 18:49:59 2013 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests instanceof operator. Requires correct support for decompression of klass ptrs.
+ */
+public class InstanceOfTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    abstract static class Shape {
+
+        public abstract float getArea();
+    }
+
+    static class Circle extends Shape {
+
+        private float radius;
+
+        Circle(float r) {
+            radius = r;
+        }
+
+        @Override
+        public float getArea() {
+            return (float) (Math.PI * radius * radius);
+        }
+    }
+
+    static class Square extends Shape {
+
+        private float len;
+
+        Square(float len) {
+            this.len = len;
+        }
+
+        @Override
+        public float getArea() {
+            return len * len;
+        }
+    }
+
+    @Result public float[] outArray = new float[NUM];
+    public Shape[] inShapeArray = new Shape[NUM];
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            if (i % 2 == 0) {
+                inShapeArray[i] = new Circle(i + 1);
+            } else {
+                inShapeArray[i] = new Square(i + 1);
+            }
+            outArray[i] = -i;
+        }
+    }
+
+    public void run(int gid) {
+        outArray[gid] = (inShapeArray[gid] instanceof Circle ? 1.0f : 2.0f);
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Wed Nov 06 18:43:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Wed Nov 06 18:49:59 2013 +0100
@@ -46,6 +46,30 @@
         this.config = config;
     }
 
+    private int getLogMinObjectAlignment() {
+        return config.logMinObjAlignment();
+    }
+
+    private int getNarrowOopShift() {
+        return config.narrowOopShift;
+    }
+
+    private long getNarrowOopBase() {
+        return config.narrowOopBase;
+    }
+
+    private int getLogKlassAlignment() {
+        return config.logKlassAlignment;
+    }
+
+    private int getNarrowKlassShift() {
+        return config.narrowKlassShift;
+    }
+
+    private long getNarrowKlassBase() {
+        return config.narrowKlassBase;
+    }
+
     private static boolean isCompressCandidate(DeoptimizingNode access) {
         return access != null && ((HeapAccess) access).isCompressible();
     }
@@ -56,9 +80,12 @@
         Variable result = newVariable(kind);
         LIRFrameState state = access != null ? state(access) : null;
         assert access == null || access instanceof HeapAccess;
-        if (config.useCompressedOops && isCompressCandidate(access)) {
+        if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
             Variable scratch = newVariable(Kind.Long);
-            append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, config.narrowOopBase, config.narrowOopShift, config.logMinObjAlignment()));
+            append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
+        } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) {
+            Variable scratch = newVariable(Kind.Long);
+            append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment()));
         } else {
             append(new LoadOp(kind, result, loadAddress, state));
         }
@@ -70,9 +97,12 @@
         HSAILAddressValue storeAddress = asAddressValue(address);
         LIRFrameState state = access != null ? state(access) : null;
         Variable input = load(inputVal);
-        if (config.useCompressedOops && isCompressCandidate(access)) {
+        if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
             Variable scratch = newVariable(Kind.Long);
-            append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, config.narrowOopBase, config.narrowOopShift, config.logMinObjAlignment()));
+            append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
+        } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) {
+            Variable scratch = newVariable(Kind.Long);
+            append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment()));
         } else {
             append(new StoreOp(kind, storeAddress, input, state));
         }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Wed Nov 06 18:43:45 2013 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Wed Nov 06 18:49:59 2013 +0100
@@ -188,57 +188,57 @@
 
     public static class LoadCompressedPointer extends LoadOp {
 
-        private long narrowOopBase;
-        private int narrowOopShift;
-        private int logMinObjAlignment;
+        private final long base;
+        private final int shift;
+        private final int alignment;
         @Temp({REG}) private AllocatableValue scratch;
 
-        public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long narrowOopBase, int narrowOopShift,
-                        int logMinObjAlignment) {
+        public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long base, int shift, int alignment) {
             super(kind, result, address, state);
-            this.narrowOopBase = narrowOopBase;
-            this.narrowOopShift = narrowOopShift;
-            this.logMinObjAlignment = logMinObjAlignment;
+            this.base = base;
+            this.shift = shift;
+            this.alignment = alignment;
             this.scratch = scratch;
-            assert kind == Kind.Object;
+            assert kind == Kind.Object || kind == Kind.Long;
         }
 
         @Override
         public void emitMemAccess(HSAILAssembler masm) {
             // we will do a 32 bit load, zero extending into a 64 bit register
             masm.emitLoad(result, address.toAddress(), "u32");
-            decodePointer(masm, result, narrowOopBase, narrowOopShift, logMinObjAlignment);
+            boolean testForNull = (kind == Kind.Object);
+            decodePointer(masm, result, base, shift, alignment, testForNull);
         }
     }
 
     public static class StoreCompressedPointer extends HSAILLIRInstruction {
 
         protected final Kind kind;
-        private long narrowOopBase;
-        private int narrowOopShift;
-        private int logMinObjAlignment;
+        private final long base;
+        private final int shift;
+        private final int alignment;
         @Temp({REG}) private AllocatableValue scratch;
         @Alive({REG}) protected AllocatableValue input;
         @Alive({COMPOSITE}) protected HSAILAddressValue address;
         @State protected LIRFrameState state;
 
-        public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long narrowOopBase, int narrowOopShift,
-                        int logMinObjAlignment) {
-            this.narrowOopBase = narrowOopBase;
-            this.narrowOopShift = narrowOopShift;
-            this.logMinObjAlignment = logMinObjAlignment;
+        public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long base, int shift, int alignment) {
+            this.base = base;
+            this.shift = shift;
+            this.alignment = alignment;
             this.scratch = scratch;
             this.kind = kind;
             this.address = address;
             this.state = state;
             this.input = input;
-            assert kind == Kind.Object;
+            assert kind == Kind.Object || kind == Kind.Long;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
             masm.emitMov(scratch, input);
-            encodePointer(masm, scratch, narrowOopBase, narrowOopShift, logMinObjAlignment);
+            boolean testForNull = (kind == Kind.Object);
+            encodePointer(masm, scratch, base, shift, alignment, testForNull);
             if (state != null) {
                 throw new InternalError("NYI");
                 // tasm.recordImplicitException(masm.codeBuffer.position(), state);
@@ -247,24 +247,24 @@
         }
     }
 
-    private static void encodePointer(HSAILAssembler masm, Value scratch, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) {
-        if (narrowOopBase == 0 && narrowOopShift == 0) {
+    private static void encodePointer(HSAILAssembler masm, Value scratch, long base, int shift, int alignment, boolean testForNull) {
+        if (base == 0 && shift == 0) {
             return;
         }
-        if (narrowOopShift != 0) {
-            assert logMinObjAlignment == narrowOopShift : "Encode algorithm is wrong";
+        if (shift != 0) {
+            assert alignment == shift : "Encode algorithm is wrong";
         }
-        masm.emitCompressedOopEncode(scratch, narrowOopBase, narrowOopShift);
+        masm.emitCompressedOopEncode(scratch, base, shift, testForNull);
     }
 
-    private static void decodePointer(HSAILAssembler masm, Value result, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) {
-        if (narrowOopBase == 0 && narrowOopShift == 0) {
+    private static void decodePointer(HSAILAssembler masm, Value result, long base, int shift, int alignment, boolean testForNull) {
+        if (base == 0 && shift == 0) {
             return;
         }
-        if (narrowOopShift != 0) {
-            assert logMinObjAlignment == narrowOopShift : "Decode algorithm is wrong";
+        if (shift != 0) {
+            assert alignment == shift : "Decode algorithm is wrong";
         }
-        masm.emitCompressedOopDecode(result, narrowOopBase, narrowOopShift);
+        masm.emitCompressedOopDecode(result, base, shift, testForNull);
     }
 
     public static class LeaOp extends HSAILLIRInstruction {