changeset 12663:7f507f082daa

Merge.
author Christian Humer <christian.humer@gmail.com>
date Mon, 04 Nov 2013 16:12:48 +0100
parents c6cc96cc6a1f (current diff) a2b1ee69ce46 (diff)
children 1fdecc36c8ac d9c34e8337f4
files
diffstat 32 files changed, 851 insertions(+), 832 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Mon Nov 04 16:12:48 2013 +0100
@@ -235,37 +235,11 @@
         emitString(prefix + " $c0, " + mapRegOrConstToString(src0) + ", " + mapRegOrConstToString(src1) + ";" + comment);
     }
 
-    /**
-     * I2S requires special handling because Graal passes an int for the destination operand instead
-     * of a short.
-     */
-    public void emitConvertIntToShort(Value dest, Value src) {
-        emitString("cvt_s16_s32 " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
-    }
-
-    /**
-     * I2C requires special handling because Graal passes an int for the destination operand instead
-     * of a char.
-     */
-    public void emitConvertIntToChar(Value dest, Value src) {
-        emitString("cvt_u16_s32 " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
-    }
-
-    /**
-     * I2B requires special handling because Graal passes an int for the destination operand instead
-     * of a byte.
-     */
-    public void emitConvertIntToByte(Value dest, Value src) {
-        emitString("cvt_s8_s32 " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
-    }
-
-    /**
-     * Generic handler for all other conversions.
-     * 
-     */
-    public void emitConvert(Value dest, Value src) {
-        String prefix = (getArgType(dest).equals("f32") && getArgType(src).equals("f64")) ? "cvt_near_" : "cvt_";
-        emitString(prefix + getArgType(dest) + "_" + getArgType(src) + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
+    public void emitConvert(Value dest, Value src, Kind destKind, Kind srcKind) {
+        String destType = getArgTypeFromKind(destKind);
+        String srcType = getArgTypeFromKind(srcKind);
+        String prefix = (destType.equals("f32") && srcType.equals("f64")) ? "cvt_near_" : "cvt_";
+        emitString(prefix + destType + "_" + srcType + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
     }
 
     public static String mapAddress(HSAILAddress addr) {
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Mon Nov 04 16:12:48 2013 +0100
@@ -344,13 +344,18 @@
 
     public static class ConversionFormat extends SingleOperandFormat {
 
-        public ConversionFormat(Variable dst, Value src) {
+        private final Kind dstKind;
+        private final Kind srcKind;
+
+        public ConversionFormat(Variable dst, Value src, Kind dstKind, Kind srcKind) {
             super(dst, src);
+            this.dstKind = dstKind;
+            this.srcKind = srcKind;
         }
 
         @Override
         public String emit() {
-            return (typeForKind(dest.getKind()) + "." + typeForKind(source.getKind()) + " " + emitVariable(dest) + ", " + emitValue(source) + ";");
+            return (typeForKind(dstKind) + "." + typeForKind(srcKind) + " " + emitVariable(dest) + ", " + emitValue(source) + ";");
         }
     }
 
@@ -538,8 +543,8 @@
 
     public static class Cvt extends ConversionFormat {
 
-        public Cvt(Variable dst, Variable src) {
-            super(dst, src);
+        public Cvt(Variable dst, Variable src, Kind dstKind, Kind srcKind) {
+            super(dst, src, dstKind, srcKind);
         }
 
         public void emit(PTXAssembler asm) {
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Nov 04 16:12:48 2013 +0100
@@ -685,95 +685,170 @@
         }
     }
 
+    private AllocatableValue emitConvertMove(Kind kind, AllocatableValue input) {
+        Variable result = newVariable(kind);
+        emitMove(result, input);
+        return result;
+    }
+
+    private AllocatableValue emitConvert1Op(Kind kind, AMD64Arithmetic op, AllocatableValue input) {
+        Variable result = newVariable(kind);
+        append(new Unary1Op(op, result, input));
+        return result;
+    }
+
+    private AllocatableValue emitConvert2Op(Kind kind, AMD64Arithmetic op, AllocatableValue input) {
+        Variable result = newVariable(kind);
+        append(new Unary2Op(op, result, input));
+        return result;
+    }
+
     @Override
-    public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) {
-        Variable input = load(inputVal);
-        Variable result = newVariable(opcode.to);
-        switch (opcode) {
-            case B2L:
-            case S2L:
-            case C2L:
-                // x2L == x2I . I2L
-                // since byte, short and char are stored as int in registers, x2I is a nop
-            case I2L:
-                append(new Unary2Op(I2L, result, input));
-                break;
-            case L2I:
-                append(new Unary1Op(L2I, result, input));
+    public AllocatableValue emitConvert(Kind from, Kind to, Value inputVal) {
+        assert inputVal.getKind() == from.getStackKind();
+
+        AllocatableValue input = asAllocatable(inputVal);
+        if (from == to) {
+            return input;
+        }
+        switch (to) {
+            case Byte:
+                switch (from) {
+                    case Short:
+                    case Char:
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, I2B, input);
+                    case Float:
+                    case Double:
+                        AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal);
+                        return emitConvert(Kind.Int, to, intVal);
+                }
                 break;
-            case C2B:
-            case S2B:
-            case I2B:
-            case L2B:
-                append(new Unary2Op(I2B, result, input));
-                break;
-            case B2C:
-            case S2C:
-            case I2C:
-            case L2C:
-                append(new Unary1Op(I2C, result, input));
+            case Char:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Int:
+                    case Long:
+                        return emitConvert1Op(to, I2C, input);
+                    case Float:
+                    case Double:
+                        AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal);
+                        return emitConvert(Kind.Int, to, intVal);
+                }
                 break;
-            case B2S:
-            case C2S:
-            case I2S:
-            case L2S:
-                append(new Unary2Op(I2S, result, input));
+            case Short:
+                switch (from) {
+                    case Byte:
+                    case Char:
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, I2S, input);
+                    case Float:
+                    case Double:
+                        AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal);
+                        return emitConvert(Kind.Int, to, intVal);
+                }
                 break;
-            case F2D:
-                append(new Unary2Op(F2D, result, input));
-                break;
-            case D2F:
-                append(new Unary2Op(D2F, result, input));
-                break;
-            case I2F:
-                append(new Unary2Op(I2F, result, input));
+            case Int:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                        return emitConvertMove(to, input);
+                    case Long:
+                        return emitConvert1Op(to, L2I, input);
+                    case Float:
+                        return emitConvert2Op(to, F2I, input);
+                    case Double:
+                        return emitConvert2Op(to, D2I, input);
+                }
                 break;
-            case I2D:
-                append(new Unary2Op(I2D, result, input));
-                break;
-            case F2I:
-                append(new Unary2Op(F2I, result, input));
-                break;
-            case D2I:
-                append(new Unary2Op(D2I, result, input));
+            case Long:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                    case Int:
+                        return emitConvert2Op(to, I2L, input);
+                    case Float:
+                        return emitConvert2Op(to, F2L, input);
+                    case Double:
+                        return emitConvert2Op(to, D2L, input);
+                }
                 break;
-            case L2F:
-                append(new Unary2Op(L2F, result, input));
-                break;
-            case L2D:
-                append(new Unary2Op(L2D, result, input));
+            case Float:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                    case Int:
+                        return emitConvert2Op(to, I2F, input);
+                    case Long:
+                        return emitConvert2Op(to, L2F, input);
+                    case Double:
+                        return emitConvert2Op(to, D2F, input);
+                }
                 break;
-            case F2L:
-                append(new Unary2Op(F2L, result, input));
-                break;
-            case D2L:
-                append(new Unary2Op(D2L, result, input));
+            case Double:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                    case Int:
+                        return emitConvert2Op(to, I2D, input);
+                    case Long:
+                        return emitConvert2Op(to, L2D, input);
+                    case Float:
+                        return emitConvert2Op(to, F2D, input);
+                }
                 break;
-            case MOV_I2F:
-                append(new Unary2Op(MOV_I2F, result, input));
-                break;
-            case MOV_L2D:
-                append(new Unary2Op(MOV_L2D, result, input));
-                break;
-            case MOV_F2I:
-                append(new Unary2Op(MOV_F2I, result, input));
-                break;
-            case MOV_D2L:
-                append(new Unary2Op(MOV_D2L, result, input));
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    public AllocatableValue emitReinterpret(Kind to, Value inputVal) {
+        Kind from = inputVal.getKind();
+        AllocatableValue input = asAllocatable(inputVal);
+
+        // These cases require a move between CPU and FPU registers:
+        switch (to) {
+            case Int:
+                switch (from) {
+                    case Float:
+                    case Double:
+                        return emitConvert2Op(to, MOV_F2I, input);
+                }
                 break;
-            case UNSIGNED_I2L:
-                // Instructions that move or generate 32-bit register values also set the upper 32
-                // bits of the register to zero.
-                // Consequently, there is no need for a special zero-extension move.
-            case B2I:
-            case C2I:
-            case S2I:
-                emitMove(result, input);
+            case Long:
+                switch (from) {
+                    case Float:
+                    case Double:
+                        return emitConvert2Op(to, MOV_D2L, input);
+                }
+                break;
+            case Float:
+                switch (from) {
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, MOV_I2F, input);
+                }
                 break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+            case Double:
+                switch (from) {
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, MOV_L2D, input);
+                }
+                break;
         }
-        return result;
+
+        // Otherwise, just emit an ordinary move instruction.
+        // Instructions that move or generate 32-bit register values also set the upper 32
+        // bits of the register to zero.
+        // Consequently, there is no need for a special zero-extension move.
+        return emitConvertMove(to, input);
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Mon Nov 04 16:12:48 2013 +0100
@@ -146,7 +146,7 @@
             } else {
                 Value indexRegister;
                 Value convertedIndex;
-                convertedIndex = this.emitConvert(ConvertNode.Op.I2L, index);
+                convertedIndex = this.emitConvert(Kind.Int, Kind.Long, index);
                 if (scale != 1) {
                     indexRegister = emitUMul(convertedIndex, Constant.forInt(scale));
                 } else {
@@ -593,55 +593,17 @@
     }
 
     @Override
-    public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) {
+    public Variable emitConvert(Kind from, Kind to, Value inputVal) {
         Variable input = load(inputVal);
-        Variable result = newVariable(opcode.to);
-        switch (opcode) {
-            case I2F:
-                append(new Op1Stack(I2F, result, input));
-                break;
-            case I2L:
-                append(new Op1Stack(I2L, result, input));
-                break;
-            case I2S:
-                append(new Op1Stack(I2S, result, input));
-                break;
-            case I2C:
-                append(new Op1Stack(I2C, result, input));
-                break;
-            case I2B:
-                append(new Op1Stack(I2B, result, input));
-                break;
-            case I2D:
-                append(new Op1Stack(I2D, result, input));
-                break;
-            case D2I:
-                append(new Op1Stack(D2I, result, input));
-                break;
-            case D2F:
-                append(new Op1Stack(D2F, result, input));
-                break;
-            case D2L:
-                append(new Op1Stack(D2L, result, input));
-                break;
-            case L2I:
-                append(new Op1Stack(L2I, result, input));
-                break;
-            case L2F:
-                append(new Op1Stack(L2F, result, input));
-                break;
-            case L2D:
-                append(new Op1Stack(L2D, result, input));
-                break;
-            case F2D:
-                append(new Op1Stack(F2D, result, input));
-                break;
-            case F2L:
-                append(new Op1Stack(F2L, result, input));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
+        Variable result = newVariable(to);
+        append(new ConvertOp(result, input, to, from));
+        return result;
+    }
+
+    @Override
+    public Value emitReinterpret(Kind to, Value inputVal) {
+        Variable result = newVariable(to);
+        emitMove(result, inputVal);
         return result;
     }
 
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Nov 04 16:12:48 2013 +0100
@@ -40,12 +40,11 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.ptx.*;
+import com.oracle.graal.lir.ptx.PTXArithmetic.ConvertOp;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Reg;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Stack;
 import com.oracle.graal.lir.ptx.PTXArithmetic.ShiftOp;
-import com.oracle.graal.lir.ptx.PTXArithmetic.Unary1Op;
-import com.oracle.graal.lir.ptx.PTXArithmetic.Unary2Op;
 import com.oracle.graal.lir.ptx.PTXCompare.CompareOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.CondMoveOp;
@@ -63,7 +62,6 @@
 import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.util.*;
 
@@ -236,7 +234,7 @@
                 Value convertedIndex;
                 Value indexRegister;
 
-                convertedIndex = emitConvert(Op.I2L, index);
+                convertedIndex = emitConvert(Kind.Int, Kind.Long, index);
                 if (scale != 1) {
                     if (CodeUtil.isPowerOf2(scale)) {
                         indexRegister = emitShl(convertedIndex, Constant.forInt(CodeUtil.log2(scale)));
@@ -678,76 +676,16 @@
     }
 
     @Override
-    public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) {
+    public Variable emitConvert(Kind from, Kind to, Value inputVal) {
         Variable input = load(inputVal);
-        Variable result = newVariable(opcode.to);
-        switch (opcode) {
-            case I2L:
-                append(new Unary2Op(I2L, result, input));
-                break;
-            case L2I:
-                append(new Unary1Op(L2I, result, input));
-                break;
-            case I2B:
-                append(new Unary2Op(I2B, result, input));
-                break;
-            case I2C:
-                append(new Unary1Op(I2C, result, input));
-                break;
-            case I2S:
-                append(new Unary2Op(I2S, result, input));
-                break;
-            case F2D:
-                append(new Unary2Op(F2D, result, input));
-                break;
-            case D2F:
-                append(new Unary2Op(D2F, result, input));
-                break;
-            case I2F:
-                append(new Unary2Op(I2F, result, input));
-                break;
-            case I2D:
-                append(new Unary2Op(I2D, result, input));
-                break;
-            case F2I:
-                append(new Unary2Op(F2I, result, input));
-                break;
-            case D2I:
-                append(new Unary2Op(D2I, result, input));
-                break;
-            case L2F:
-                append(new Unary2Op(L2F, result, input));
-                break;
-            case L2D:
-                append(new Unary2Op(L2D, result, input));
-                break;
-            case F2L:
-                append(new Unary2Op(F2L, result, input));
-                break;
-            case D2L:
-                append(new Unary2Op(D2L, result, input));
-                break;
-            case MOV_I2F:
-                append(new Unary2Op(MOV_I2F, result, input));
-                break;
-            case MOV_L2D:
-                append(new Unary2Op(MOV_L2D, result, input));
-                break;
-            case MOV_F2I:
-                append(new Unary2Op(MOV_F2I, result, input));
-                break;
-            case MOV_D2L:
-                append(new Unary2Op(MOV_D2L, result, input));
-                break;
-            case UNSIGNED_I2L:
-                // Instructions that move or generate 32-bit register values also set the upper 32
-                // bits of the register to zero.
-                // Consequently, there is no need for a special zero-extension move.
-                emitMove(result, input);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
+        Variable result = newVariable(to);
+        append(new ConvertOp(result, input, to, from));
+        return result;
+    }
+
+    public Value emitReinterpret(Kind to, Value inputVal) {
+        Variable result = newVariable(to);
+        emitMove(result, inputVal);
         return result;
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Nov 04 16:12:48 2013 +0100
@@ -61,7 +61,6 @@
 import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.util.*;
 
@@ -156,7 +155,7 @@
             } else {
                 if (scale != 1) {
                     // Variable longIndex = newVariable(Kind.Long);
-                    Variable longIndex = emitConvert(Op.I2L, index);
+                    AllocatableValue longIndex = emitConvert(Kind.Int, Kind.Long, index);
                     if (CodeUtil.isPowerOf2(scale)) {
                         indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
                     } else {
@@ -755,78 +754,164 @@
         }
     }
 
+    private AllocatableValue emitConvertMove(Kind kind, AllocatableValue input) {
+        Variable result = newVariable(kind);
+        emitMove(result, input);
+        return result;
+    }
+
+    private AllocatableValue emitConvert2Op(Kind kind, SPARCArithmetic op, AllocatableValue input) {
+        Variable result = newVariable(kind);
+        append(new Unary2Op(op, result, input));
+        return result;
+    }
+
     @Override
-    public Variable emitConvert(Op opcode, Value inputVal) {
-        Variable input = load(inputVal);
-        Variable result = newVariable(opcode.to);
-        switch (opcode) {
-            case I2L:
-                append(new Unary2Op(I2L, result, input));
-                break;
-            case L2I:
-                append(new Unary2Op(L2I, result, input));
-                break;
-            case I2B:
-                append(new Unary2Op(I2B, result, input));
-                break;
-            case I2C:
-                append(new Unary2Op(I2C, result, input));
+    public AllocatableValue emitConvert(Kind from, Kind to, Value inputVal) {
+        assert inputVal.getKind() == from.getStackKind();
+
+        AllocatableValue input = asAllocatable(inputVal);
+        if (from == to) {
+            return input;
+        }
+        switch (to) {
+            case Byte:
+                switch (from) {
+                    case Short:
+                    case Char:
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, I2B, input);
+                    case Float:
+                    case Double:
+                        AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal);
+                        return emitConvert(Kind.Int, to, intVal);
+                }
                 break;
-            case I2S:
-                append(new Unary2Op(I2S, result, input));
-                break;
-            case F2D:
-                append(new Unary2Op(F2D, result, input));
-                break;
-            case D2F:
-                append(new Unary2Op(D2F, result, input));
+            case Char:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, I2C, input);
+                    case Float:
+                    case Double:
+                        AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal);
+                        return emitConvert(Kind.Int, to, intVal);
+                }
                 break;
-            case I2F:
-                append(new Unary2Op(I2F, result, input));
+            case Short:
+                switch (from) {
+                    case Byte:
+                    case Char:
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, I2S, input);
+                    case Float:
+                    case Double:
+                        AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal);
+                        return emitConvert(Kind.Int, to, intVal);
+                }
                 break;
-            case I2D:
-                append(new Unary2Op(I2D, result, input));
-                break;
-            case F2I:
-                append(new Unary2Op(F2I, result, input));
+            case Int:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                        return emitConvertMove(to, input);
+                    case Long:
+                        return emitConvert2Op(to, L2I, input);
+                    case Float:
+                        return emitConvert2Op(to, F2I, input);
+                    case Double:
+                        return emitConvert2Op(to, D2I, input);
+                }
                 break;
-            case D2I:
-                append(new Unary2Op(D2I, result, input));
-                break;
-            case L2F:
-                append(new Unary2Op(L2F, result, input));
-                break;
-            case L2D:
-                append(new Unary2Op(L2D, result, input));
+            case Long:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                    case Int:
+                        return emitConvert2Op(to, I2L, input);
+                    case Float:
+                        return emitConvert2Op(to, F2L, input);
+                    case Double:
+                        return emitConvert2Op(to, D2L, input);
+                }
                 break;
-            case F2L:
-                append(new Unary2Op(F2L, result, input));
+            case Float:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                    case Int:
+                        return emitConvert2Op(to, I2F, input);
+                    case Long:
+                        return emitConvert2Op(to, L2F, input);
+                    case Double:
+                        return emitConvert2Op(to, D2F, input);
+                }
                 break;
-            case D2L:
-                append(new Unary2Op(D2L, result, input));
-                break;
-            case MOV_I2F:
-                append(new Unary2Op(MOV_I2F, result, input));
+            case Double:
+                switch (from) {
+                    case Byte:
+                    case Short:
+                    case Char:
+                    case Int:
+                        return emitConvert2Op(to, I2D, input);
+                    case Long:
+                        return emitConvert2Op(to, L2D, input);
+                    case Float:
+                        return emitConvert2Op(to, F2D, input);
+                }
                 break;
-            case MOV_L2D:
-                append(new Unary2Op(MOV_L2D, result, input));
-                break;
-            case MOV_F2I:
-                append(new Unary2Op(MOV_F2I, result, input));
-                break;
-            case MOV_D2L:
-                append(new Unary2Op(MOV_D2L, result, input));
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    public AllocatableValue emitReinterpret(Kind to, Value inputVal) {
+        Kind from = inputVal.getKind();
+        AllocatableValue input = asAllocatable(inputVal);
+
+        // These cases require a move between CPU and FPU registers:
+        switch (to) {
+            case Int:
+                switch (from) {
+                    case Float:
+                    case Double:
+                        return emitConvert2Op(to, MOV_F2I, input);
+                }
                 break;
-            case UNSIGNED_I2L:
-                // Instructions that move or generate 32-bit register values also set the upper 32
-                // bits of the register to zero.
-                // Consequently, there is no need for a special zero-extension move.
-                emitMove(result, input);
+            case Long:
+                switch (from) {
+                    case Float:
+                    case Double:
+                        return emitConvert2Op(to, MOV_D2L, input);
+                }
+                break;
+            case Float:
+                switch (from) {
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, MOV_I2F, input);
+                }
                 break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+            case Double:
+                switch (from) {
+                    case Int:
+                    case Long:
+                        return emitConvert2Op(to, MOV_L2D, input);
+                }
+                break;
         }
-        return result;
+
+        // Otherwise, just emit an ordinary move instruction.
+        // Instructions that move or generate 32-bit register values also set the upper 32
+        // bits of the register to zero.
+        // Consequently, there is no need for a special zero-extension move.
+        return emitConvertMove(to, input);
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Mon Nov 04 16:12:48 2013 +0100
@@ -35,10 +35,10 @@
 
         appendPhase(new LoweringPhase(canonicalizer));
 
+        appendPhase(new RemoveValueProxyPhase());
+
         appendPhase(new ExpandLogicPhase());
 
         appendPhase(new DeadCodeEliminationPhase());
-
-        appendPhase(new RemoveValueProxyPhase());
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Nov 04 16:12:48 2013 +0100
@@ -700,7 +700,9 @@
                     }
                 } else {
                     Object o = unsafe.getObject(n, dataOffsets[i]);
-                    if (o != null) {
+                    if (o instanceof Object[]) {
+                        number += Arrays.deepHashCode((Object[]) o);
+                    } else if (o != null) {
                         number += o.hashCode();
                     }
                 }
@@ -780,8 +782,14 @@
                 Object objectB = unsafe.getObject(b, dataOffsets[i]);
                 if (objectA != objectB) {
                     if (objectA != null && objectB != null) {
-                        if (!(objectA.equals(objectB))) {
-                            return false;
+                        if (objectA instanceof Object[] && objectB instanceof Object[]) {
+                            if (!Arrays.deepEquals((Object[]) objectA, (Object[]) objectB)) {
+                                return false;
+                            }
+                        } else {
+                            if (!(objectA.equals(objectB))) {
+                                return false;
+                            }
                         }
                     } else {
                         return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Mon Nov 04 16:12:48 2013 +0100
@@ -27,7 +27,14 @@
 
 public class G1PostWriteBarrier extends WriteBarrier {
 
-    public G1PostWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
+    private boolean alwaysNull;
+
+    public G1PostWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise, boolean alwaysNull) {
         super(object, value, location, precise);
+        this.alwaysNull = alwaysNull;
+    }
+
+    public boolean alwaysNull() {
+        return alwaysNull;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Mon Nov 04 16:12:48 2013 +0100
@@ -27,7 +27,14 @@
 
 public class SerialWriteBarrier extends WriteBarrier {
 
-    public SerialWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
-        super(object, value, location, precise);
+    private boolean alwaysNull;
+
+    public SerialWriteBarrier(ValueNode object, LocationNode location, boolean precise, boolean alwaysNull) {
+        super(object, null, location, precise);
+        this.alwaysNull = alwaysNull;
+    }
+
+    public boolean alwaysNull() {
+        return alwaysNull;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Mon Nov 04 16:12:48 2013 +0100
@@ -26,10 +26,11 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 
 public class WriteBarrierAdditionPhase extends Phase {
@@ -74,11 +75,14 @@
     }
 
     protected void addG1PostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
-        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(object, value, location, precise)));
+        final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value);
+        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(object, value, location, precise, alwaysNull)));
     }
 
     protected void addSerialPostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
-        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(object, value, location, precise)));
+        final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value);
+        final LocationNode loc = (precise ? location : null);
+        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(object, loc, precise, alwaysNull)));
     }
 
     private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Mon Nov 04 16:12:48 2013 +0100
@@ -36,7 +36,6 @@
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
@@ -346,7 +345,7 @@
             args.add("object", writeBarrier.getObject());
             args.add("location", writeBarrier.getLocation());
             args.addConst("usePrecise", writeBarrier.usePrecise());
-            args.addConst("alwaysNull", ObjectStamp.isObjectAlwaysNull(writeBarrier.getValue()));
+            args.addConst("alwaysNull", writeBarrier.alwaysNull());
             template(args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
         }
 
@@ -386,7 +385,7 @@
             args.add("value", writeBarrierPost.getValue());
             args.add("location", writeBarrierPost.getLocation());
             args.addConst("usePrecise", writeBarrierPost.usePrecise());
-            args.addConst("alwaysNull", ObjectStamp.isObjectAlwaysNull(writeBarrierPost.getValue()));
+            args.addConst("alwaysNull", writeBarrierPost.alwaysNull());
             args.addConst("trace", traceBarrier());
             template(args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Nov 04 16:12:48 2013 +0100
@@ -688,9 +688,9 @@
         frameState.ipush(append(new NormalizeCompareNode(x, y, isUnorderedLess)));
     }
 
-    private void genConvert(ConvertNode.Op opcode) {
-        ValueNode input = frameState.pop(opcode.from.getStackKind());
-        frameState.push(opcode.to.getStackKind(), append(new ConvertNode(opcode, input)));
+    private void genConvert(Kind from, Kind to) {
+        ValueNode input = frameState.pop(from.getStackKind());
+        frameState.push(to.getStackKind(), append(new ConvertNode(from, to, input)));
     }
 
     private void genIncrement() {
@@ -1940,21 +1940,21 @@
             case LOR            : // fall through
             case LXOR           : genLogicOp(Kind.Long, opcode); break;
             case IINC           : genIncrement(); break;
-            case I2L            : genConvert(ConvertNode.Op.I2L); break;
-            case I2F            : genConvert(ConvertNode.Op.I2F); break;
-            case I2D            : genConvert(ConvertNode.Op.I2D); break;
-            case L2I            : genConvert(ConvertNode.Op.L2I); break;
-            case L2F            : genConvert(ConvertNode.Op.L2F); break;
-            case L2D            : genConvert(ConvertNode.Op.L2D); break;
-            case F2I            : genConvert(ConvertNode.Op.F2I); break;
-            case F2L            : genConvert(ConvertNode.Op.F2L); break;
-            case F2D            : genConvert(ConvertNode.Op.F2D); break;
-            case D2I            : genConvert(ConvertNode.Op.D2I); break;
-            case D2L            : genConvert(ConvertNode.Op.D2L); break;
-            case D2F            : genConvert(ConvertNode.Op.D2F); break;
-            case I2B            : genConvert(ConvertNode.Op.I2B); break;
-            case I2C            : genConvert(ConvertNode.Op.I2C); break;
-            case I2S            : genConvert(ConvertNode.Op.I2S); break;
+            case I2L            : genConvert(Kind.Int, Kind.Long); break;
+            case I2F            : genConvert(Kind.Int, Kind.Float); break;
+            case I2D            : genConvert(Kind.Int, Kind.Double); break;
+            case L2I            : genConvert(Kind.Long, Kind.Int); break;
+            case L2F            : genConvert(Kind.Long, Kind.Float); break;
+            case L2D            : genConvert(Kind.Long, Kind.Double); break;
+            case F2I            : genConvert(Kind.Float, Kind.Int); break;
+            case F2L            : genConvert(Kind.Float, Kind.Long); break;
+            case F2D            : genConvert(Kind.Float, Kind.Double); break;
+            case D2I            : genConvert(Kind.Double, Kind.Int); break;
+            case D2L            : genConvert(Kind.Double, Kind.Long); break;
+            case D2F            : genConvert(Kind.Double, Kind.Float); break;
+            case I2B            : genConvert(Kind.Int, Kind.Byte); break;
+            case I2C            : genConvert(Kind.Int, Kind.Char); break;
+            case I2S            : genConvert(Kind.Int, Kind.Short); break;
             case LCMP           : genCompareOp(Kind.Long, false); break;
             case FCMPL          : genCompareOp(Kind.Float, true); break;
             case FCMPG          : genCompareOp(Kind.Float, false); break;
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java	Mon Nov 04 16:12:48 2013 +0100
@@ -38,28 +38,16 @@
     CALL,
     FDIV,
     FREM,
-    D2F,
-    D2I,
-    D2L,
     DADD,
     DDIV,
     DMUL,
     DNEG,
     DREM,
     DSUB,
-    F2D,
-    F2I,
-    F2L,
     FADD,
     FMUL,
     FNEG,
     FSUB,
-    I2B,
-    I2C,
-    I2D,
-    I2F,
-    I2L,
-    I2S,
     IADD,
     IAND,
     ICARRY,
@@ -84,9 +72,6 @@
     IUSHR,
     IUSUB,
     IXOR,
-    L2D,
-    L2F,
-    L2I,
     LADD,
     LAND,
     LCARRY,
@@ -111,14 +96,29 @@
     LUSHR,
     LUSUB,
     LXOR,
-    MOV_F2I,
-    MOV_D2L,
-    MOV_I2F,
-    MOV_L2D,
     OADD,
     SQRT,
     UNDEF;
 
+    public static class ConvertOp extends HSAILLIRInstruction {
+        private final Kind from;
+        private final Kind to;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+
+        public ConvertOp(AllocatableValue result, AllocatableValue x, Kind to, Kind from) {
+            this.from = from;
+            this.to = to;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) {
+            masm.emitConvert(result, x, to, from);
+        }
+    }
+
     public static class Op1Stack extends HSAILLIRInstruction {
         @Opcode private final HSAILArithmetic opcode;
         @Def({REG, HINT}) protected Value result;
@@ -293,29 +293,6 @@
         int exceptionOffset = -1;
         if (isRegister(src)) {
             switch (opcode) {
-                case I2F:
-                case I2D:
-                case I2L:
-                case F2I:
-                case F2D:
-                case F2L:
-                case D2I:
-                case D2L:
-                case D2F:
-                case L2I:
-                case L2F:
-                case L2D:
-                    masm.emitConvert(dst, src);
-                    break;
-                case I2S:
-                    masm.emitConvertIntToShort(dst, src);
-                    break;
-                case I2C:
-                    masm.emitConvertIntToChar(dst, src);
-                    break;
-                case I2B:
-                    masm.emitConvertIntToByte(dst, src);
-                    break;
                 case SQRT:
                     masm.emit("sqrt", dst, src);
                     break;
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Mon Nov 04 16:12:48 2013 +0100
@@ -39,84 +39,33 @@
     LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
-    INEG, LNEG, FNEG, DNEG, INOT, LNOT,
-    I2L, L2I, I2B, I2C, I2S,
-    F2D, D2F,
-    I2F, I2D, F2I, D2I,
-    L2F, L2D, F2L, D2L,
-    MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
+    INEG, LNEG, FNEG, DNEG, INOT, LNOT;
 
 
-    /**
-     * Unary operation with separate source and destination operand. 
-     */
-    public static class Unary2Op extends PTXLIRInstruction {
-        @Opcode private final PTXArithmetic opcode;
+    public static class ConvertOp extends PTXLIRInstruction {
+        private final Kind from;
+        private final Kind to;
         @Def({REG}) protected AllocatableValue result;
         @Use({REG, STACK}) protected AllocatableValue x;
 
-        public Unary2Op(PTXArithmetic opcode, AllocatableValue result, AllocatableValue x) {
-            this.opcode = opcode;
+        public ConvertOp(AllocatableValue result, AllocatableValue x, Kind to, Kind from) {
+            this.from = from;
+            this.to = to;
             this.result = result;
             this.x = x;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            switch (opcode) {
-                case I2L:
-                case I2C:
-                case I2B:
-                case I2F:
-                case I2D:
-                case F2I:
-                case F2L:
-                case F2D:
-                case D2I:
-                case D2L:
-                case D2F:
-                    break;  // cvt handles the move
-                default:
-                    PTXMove.move(tasm, masm, result, x);
+            Variable dst = (Variable) result;
+            Variable src = (Variable) x;
+            if (from == Kind.Long && to == Kind.Int) {
+                new And(dst, src, Constant.forLong(0xFFFFFFFF)).emit(masm);
+            } else if ((from == Kind.Int || from == Kind.Long) && to == Kind.Short) {
+                new And(dst, src, Constant.forInt((short) 0xFFFF)).emit(masm);
+            } else {
+                new Cvt((Variable) result, (Variable) x, to, from).emit(masm);
             }
-            emit(tasm, masm, opcode, result, x, null);
-        }
-    }
-
-    /**
-     * Unary operation with single operand for source and destination. 
-     */
-    public static class Unary1Op extends PTXLIRInstruction {
-        @Opcode private final PTXArithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-
-        public Unary1Op(PTXArithmetic opcode, AllocatableValue result, AllocatableValue x) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            emit(tasm, masm, opcode, result);
-        }
-    }
-
-    public static class Op1Reg extends PTXLIRInstruction {
-        @Opcode private final PTXArithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG}) protected Value x;
-
-        public Op1Reg(PTXArithmetic opcode, Value result, Value x) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            emit(tasm, masm, opcode, result, x, null);
         }
     }
 
@@ -270,22 +219,6 @@
         }
     }
 
-    protected static void emit(@SuppressWarnings("unused") TargetMethodAssembler tasm,
-                               PTXAssembler masm, PTXArithmetic opcode, Value result) {
-
-        Variable var = (Variable) result;
-        switch (opcode) {
-            case L2I:
-                new And(var, var, Constant.forLong(0xFFFFFFFF)).emit(masm);
-                break;
-            case I2C:
-                new And(var, var, Constant.forInt((short) 0xFFFF)).emit(masm);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
-        }
-    }
-
     public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src, LIRFrameState info) {
         int exceptionOffset = -1;
         Variable dest = (Variable) dst;
@@ -302,19 +235,6 @@
                 case LNOT:
                     new Not(dest, source).emit(masm);
                     break;
-                case I2L:
-                case I2C:
-                case I2B:
-                case I2F:
-                case I2D:
-                case F2I:
-                case F2L:
-                case F2D:
-                case D2I:
-                case D2L:
-                case D2F:
-                    new Cvt(dest, source).emit(masm);
-                    break;
                 case LSHL:
                     new Shl(dest, dest, src).emit(masm);
                     break;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon Nov 04 16:12:48 2013 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.type.*;
 
 public class BasicInductionVariable extends InductionVariable {
@@ -127,10 +126,9 @@
         ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
         ValueNode initNode = this.initNode();
         if (fromKind != kind) {
-            Op convertOp = Op.getOp(fromKind, kind);
-            stride = graph.unique(new ConvertNode(convertOp, stride));
-            maxTripCount = graph.unique(new ConvertNode(convertOp, maxTripCount));
-            initNode = graph.unique(new ConvertNode(convertOp, initNode));
+            stride = graph.unique(new ConvertNode(fromKind, kind, stride));
+            maxTripCount = graph.unique(new ConvertNode(fromKind, kind, maxTripCount));
+            initNode = graph.unique(new ConvertNode(fromKind, kind, initNode));
         }
         return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode);
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon Nov 04 16:12:48 2013 +0100
@@ -93,7 +93,7 @@
 
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
-        return op(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, offset));
+        return op(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(graph(), kind, offset));
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Mon Nov 04 16:12:48 2013 +0100
@@ -103,7 +103,7 @@
 
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
-        return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, scale));
+        return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(graph(), kind, scale));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon Nov 04 16:12:48 2013 +0100
@@ -126,32 +126,35 @@
     @Test
     public void testNarrowingConversions() {
         // byte cases
-        assertEquals(StampFactory.forInteger(Kind.Int, 0, 0), StampTool.intToByte(StampFactory.forInteger(Kind.Int, 0, 0)));
-        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.intToByte(StampFactory.forInteger(Kind.Int, 0, 10)));
-        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.intToByte(StampFactory.forInteger(Kind.Int, 10, 20)));
-        assertEquals(StampFactory.forInteger(Kind.Int, -10, 0), StampTool.intToByte(StampFactory.forInteger(Kind.Int, -10, 0)));
-        assertEquals(StampFactory.forInteger(Kind.Int, -20, -10), StampTool.intToByte(StampFactory.forInteger(Kind.Int, -20, -10)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), StampTool.intToByte(StampFactory.forInteger(Kind.Int, 100, 200)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), StampTool.intToByte(StampFactory.forInteger(Kind.Int, -100, 200)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), StampTool.intToByte(StampFactory.forInteger(Kind.Int, -200, -100)));
+        assertEquals(StampFactory.forInteger(Kind.Int, 0, 0), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 0, 0), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 0, 10), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 10, 20), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, -10, 0), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -10, 0), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, -20, -10), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -20, -10), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 100, 200), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -100, 200), Kind.Byte));
+        assertEquals(StampFactory.forInteger(Kind.Int, Byte.MIN_VALUE, Byte.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -200, -100), Kind.Byte));
         // char cases
-        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.intToChar(StampFactory.forInteger(Kind.Int, 0, 10)));
-        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.intToChar(StampFactory.forInteger(Kind.Int, 10, 20)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Character.MIN_VALUE, Character.MAX_VALUE), StampTool.intToChar(StampFactory.forInteger(Kind.Int, 20000, 80000)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Character.MIN_VALUE, Character.MAX_VALUE), StampTool.intToChar(StampFactory.forInteger(Kind.Int, -10000, 40000)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Character.MIN_VALUE, Character.MAX_VALUE), StampTool.intToChar(StampFactory.forInteger(Kind.Int, -40000, -10000)));
+        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 0, 10), Kind.Char));
+        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 10, 20), Kind.Char));
+        assertEquals(StampFactory.forInteger(Kind.Int, Character.MIN_VALUE, Character.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 20000, 80000), Kind.Char));
+        assertEquals(StampFactory.forInteger(Kind.Int, Character.MIN_VALUE, Character.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -10000, 40000), Kind.Char));
+        assertEquals(StampFactory.forInteger(Kind.Int, Character.MIN_VALUE, Character.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -40000, -10000), Kind.Char));
         // short cases
-        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.intToShort(StampFactory.forInteger(Kind.Int, 0, 10)));
-        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.intToShort(StampFactory.forInteger(Kind.Int, 10, 20)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Short.MIN_VALUE, Short.MAX_VALUE), StampTool.intToShort(StampFactory.forInteger(Kind.Int, 20000, 40000)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Short.MIN_VALUE, Short.MAX_VALUE), StampTool.intToShort(StampFactory.forInteger(Kind.Int, -10000, 40000)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Short.MIN_VALUE, Short.MAX_VALUE), StampTool.intToShort(StampFactory.forInteger(Kind.Int, -40000, -10000)));
+        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 0, 10), Kind.Short));
+        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 10, 20), Kind.Short));
+        assertEquals(StampFactory.forInteger(Kind.Int, Short.MIN_VALUE, Short.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, 20000, 40000), Kind.Short));
+        assertEquals(StampFactory.forInteger(Kind.Int, Short.MIN_VALUE, Short.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -10000, 40000), Kind.Short));
+        assertEquals(StampFactory.forInteger(Kind.Int, Short.MIN_VALUE, Short.MAX_VALUE), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Int, -40000, -10000), Kind.Short));
         // int cases
-        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.longToInt(StampFactory.forInteger(Kind.Long, 0, 10)));
-        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.longToInt(StampFactory.forInteger(Kind.Long, 10, 20)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE), StampTool.longToInt(StampFactory.forInteger(Kind.Long, 20000000000L, 40000000000L)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE), StampTool.longToInt(StampFactory.forInteger(Kind.Long, -10000000000L, 40000000000L)));
-        assertEquals(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE), StampTool.longToInt(StampFactory.forInteger(Kind.Long, -40000000000L, -10000000000L)));
+        assertEquals(StampFactory.forInteger(Kind.Int, 0, 10), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Long, 0, 10), Kind.Int));
+        assertEquals(StampFactory.forInteger(Kind.Int, 10, 20), StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Long, 10, 20), Kind.Int));
+        assertEquals(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE),
+                        StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Long, 20000000000L, 40000000000L), Kind.Int));
+        assertEquals(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE),
+                        StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Long, -10000000000L, 40000000000L), Kind.Int));
+        assertEquals(StampFactory.forInteger(Kind.Int, Integer.MIN_VALUE, Integer.MAX_VALUE),
+                        StampTool.narrowingKindConversion(StampFactory.forInteger(Kind.Long, -40000000000L, -10000000000L), Kind.Int));
     }
 
     @Test
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Nov 04 16:12:48 2013 +0100
@@ -136,7 +136,7 @@
         if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
-            if (convertX.opcode.isLossless() && convertY.opcode.isLossless()) {
+            if (convertX.isLossless() && convertY.isLossless()) {
                 setX(convertX.value());
                 setY(convertY.value());
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon Nov 04 16:12:48 2013 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import static com.oracle.graal.api.meta.Kind.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -36,165 +34,10 @@
  */
 public class ConvertNode extends FloatingNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
 
-    public static enum Op {
-        // formatter:off
-        B2S(Byte, Short, true),
-        B2C(Byte, Char, true),
-        B2I(Byte, Int, true),
-        B2L(Byte, Long, true),
-        S2B(Short, Byte, false),
-        S2C(Short, Char, true),
-        S2I(Short, Int, true),
-        S2L(Short, Long, true),
-        C2B(Char, Byte, false),
-        C2S(Char, Short, true),
-        C2I(Char, Int, true),
-        C2L(Char, Long, true),
-        I2L(Int, Long, true),
-        L2I(Long, Int, false),
-        I2B(Int, Byte, false),
-        I2C(Int, Char, false),
-        I2S(Int, Short, false),
-        L2B(Long, Byte, false),
-        L2C(Long, Char, false),
-        L2S(Long, Short, false),
-        F2D(Float, Double, true),
-        D2F(Double, Float, false),
-        I2F(Int, Float, false),
-        I2D(Int, Double, true),
-        F2I(Float, Int, false),
-        D2I(Double, Int, false),
-        L2F(Long, Float, false),
-        L2D(Long, Double, false),
-        F2L(Float, Long, false),
-        D2L(Double, Long, false),
-        UNSIGNED_I2L(Int, Long, true),
-        MOV_I2F(Int, Float, false),
-        MOV_L2D(Long, Double, false),
-        MOV_F2I(Float, Int, false),
-        MOV_D2L(Double, Long, false);
-        // formatter:on
-
-        public final Kind from;
-        public final Kind to;
-        public final boolean lossless;
-
-        private Op(Kind from, Kind to, boolean lossless) {
-            this.from = from;
-            this.to = to;
-            this.lossless = lossless;
-        }
-
-        public boolean isLossless() {
-            return lossless;
-        }
-
-        public static Op getOp(Kind from, Kind to) {
-            switch (from) {
-                case Byte:
-                    switch (to) {
-                        case Char:
-                            return B2C;
-                        case Short:
-                            return B2S;
-                        case Int:
-                            return B2I;
-                        case Long:
-                            return B2L;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                case Char:
-                    switch (to) {
-                        case Byte:
-                            return C2B;
-                        case Short:
-                            return C2S;
-                        case Int:
-                            return C2I;
-                        case Long:
-                            return C2L;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                case Short:
-                    switch (to) {
-                        case Byte:
-                            return S2B;
-                        case Char:
-                            return S2C;
-                        case Int:
-                            return S2I;
-                        case Long:
-                            return S2L;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                case Int:
-                    switch (to) {
-                        case Byte:
-                            return I2B;
-                        case Char:
-                            return I2C;
-                        case Short:
-                            return I2S;
-                        case Long:
-                            return I2L;
-                        case Float:
-                            return I2F;
-                        case Double:
-                            return I2D;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                case Long:
-                    switch (to) {
-                        case Byte:
-                            return L2B;
-                        case Char:
-                            return L2C;
-                        case Short:
-                            return L2S;
-                        case Int:
-                            return L2I;
-                        case Float:
-                            return L2F;
-                        case Double:
-                            return L2D;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                case Float:
-                    switch (to) {
-                        case Int:
-                            return F2I;
-                        case Long:
-                            return F2L;
-                        case Double:
-                            return F2D;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                case Double:
-                    switch (to) {
-                        case Int:
-                            return D2I;
-                        case Long:
-                            return D2L;
-                        case Float:
-                            return D2F;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
     @Input private ValueNode value;
 
-    public final Op opcode;
+    private final Kind from;
+    private final Kind to;
 
     public ValueNode value() {
         return value;
@@ -203,93 +46,186 @@
     /**
      * Constructs a new Convert instance.
      * 
-     * @param opcode the operation
+     * @param from the kind of the incoming value
+     * @param to the result kind
      * @param value the instruction producing the input value
      */
-    public ConvertNode(Op opcode, ValueNode value) {
-        super(StampFactory.forKind(opcode.to.getStackKind()));
-        assert value.kind() == opcode.from.getStackKind() : opcode + " : " + value.kind() + " != " + opcode.from;
-        this.opcode = opcode;
+    public ConvertNode(Kind from, Kind to, ValueNode value) {
+        super(StampFactory.forKind(to.getStackKind()));
+        assert value.kind() == from.getStackKind() : "convert(" + from + ", " + to + ") : " + value.kind() + " != " + from;
+        this.from = from;
+        this.to = to;
         this.value = value;
     }
 
+    public Kind getFromKind() {
+        return from;
+    }
+
+    public Kind getToKind() {
+        return to;
+    }
+
+    public boolean isLossless() {
+        if (from == to) {
+            return true;
+        }
+        switch (from) {
+            case Byte:
+                return true;
+            case Short:
+            case Char:
+                return to != Kind.Byte;
+            case Int:
+                return to == Kind.Long || to == Kind.Double;
+            case Float:
+                return to == Kind.Double;
+            case Long:
+            case Double:
+                return false;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
         Constant c = inputs[0];
-        switch (opcode) {
-            case B2C:
-                return Constant.forChar((char) (byte) c.asInt());
-            case B2S:
-                return Constant.forShort((byte) c.asInt());
-            case B2I:
-                return Constant.forInt((byte) c.asInt());
-            case B2L:
-                return Constant.forLong((byte) c.asInt());
-            case C2B:
-                return Constant.forByte((byte) (char) c.asInt());
-            case C2S:
-                return Constant.forShort((short) (char) c.asInt());
-            case C2I:
-                return Constant.forInt((char) c.asInt());
-            case C2L:
-                return Constant.forLong((char) c.asInt());
-            case S2B:
-                return Constant.forByte((byte) (short) c.asInt());
-            case S2C:
-                return Constant.forChar((char) (short) c.asInt());
-            case S2I:
-                return Constant.forInt((short) c.asInt());
-            case S2L:
-                return Constant.forLong((short) c.asInt());
-            case I2L:
-                return Constant.forLong(c.asInt());
-            case L2I:
-                return Constant.forInt((int) c.asLong());
-            case I2B:
-                return Constant.forByte((byte) c.asInt());
-            case I2C:
-                return Constant.forChar((char) c.asInt());
-            case I2S:
-                return Constant.forShort((short) c.asInt());
-            case L2B:
-                return Constant.forByte((byte) c.asLong());
-            case L2C:
-                return Constant.forChar((char) c.asLong());
-            case L2S:
-                return Constant.forShort((short) c.asLong());
-            case F2D:
-                return Constant.forDouble(c.asFloat());
-            case D2F:
-                return Constant.forFloat((float) c.asDouble());
-            case I2F:
-                return Constant.forFloat(c.asInt());
-            case I2D:
-                return Constant.forDouble(c.asInt());
-            case F2I:
-                return Constant.forInt((int) c.asFloat());
-            case D2I:
-                return Constant.forInt((int) c.asDouble());
-            case L2F:
-                return Constant.forFloat(c.asLong());
-            case L2D:
-                return Constant.forDouble(c.asLong());
-            case F2L:
-                return Constant.forLong((long) c.asFloat());
-            case D2L:
-                return Constant.forLong((long) c.asDouble());
-            case UNSIGNED_I2L:
-                return Constant.forLong(c.asInt() & 0xffffffffL);
-            case MOV_I2F:
-                return Constant.forFloat(java.lang.Float.intBitsToFloat(c.asInt()));
-            case MOV_L2D:
-                return Constant.forDouble(java.lang.Double.longBitsToDouble(c.asLong()));
-            case MOV_F2I:
-                return Constant.forInt(java.lang.Float.floatToRawIntBits(c.asFloat()));
-            case MOV_D2L:
-                return Constant.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble()));
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+        switch (from) {
+            case Byte:
+                byte byteVal = (byte) c.asInt();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte(byteVal);
+                    case Short:
+                        return Constant.forShort(byteVal);
+                    case Char:
+                        return Constant.forChar((char) byteVal);
+                    case Int:
+                        return Constant.forInt(byteVal);
+                    case Long:
+                        return Constant.forLong(byteVal);
+                    case Float:
+                        return Constant.forFloat(byteVal);
+                    case Double:
+                        return Constant.forDouble(byteVal);
+                }
+                break;
+            case Char:
+                char charVal = (char) c.asInt();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte((byte) charVal);
+                    case Short:
+                        return Constant.forShort((short) charVal);
+                    case Char:
+                        return Constant.forChar(charVal);
+                    case Int:
+                        return Constant.forInt(charVal);
+                    case Long:
+                        return Constant.forLong(charVal);
+                    case Float:
+                        return Constant.forFloat(charVal);
+                    case Double:
+                        return Constant.forDouble(charVal);
+                }
+                break;
+            case Short:
+                short shortVal = (short) c.asInt();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte((byte) shortVal);
+                    case Short:
+                        return Constant.forShort(shortVal);
+                    case Char:
+                        return Constant.forChar((char) shortVal);
+                    case Int:
+                        return Constant.forInt(shortVal);
+                    case Long:
+                        return Constant.forLong(shortVal);
+                    case Float:
+                        return Constant.forFloat(shortVal);
+                    case Double:
+                        return Constant.forDouble(shortVal);
+                }
+                break;
+            case Int:
+                int intVal = c.asInt();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte((byte) intVal);
+                    case Short:
+                        return Constant.forShort((short) intVal);
+                    case Char:
+                        return Constant.forChar((char) intVal);
+                    case Int:
+                        return Constant.forInt(intVal);
+                    case Long:
+                        return Constant.forLong(intVal);
+                    case Float:
+                        return Constant.forFloat(intVal);
+                    case Double:
+                        return Constant.forDouble(intVal);
+                }
+                break;
+            case Long:
+                long longVal = c.asLong();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte((byte) longVal);
+                    case Short:
+                        return Constant.forShort((short) longVal);
+                    case Char:
+                        return Constant.forChar((char) longVal);
+                    case Int:
+                        return Constant.forInt((int) longVal);
+                    case Long:
+                        return Constant.forLong(longVal);
+                    case Float:
+                        return Constant.forFloat(longVal);
+                    case Double:
+                        return Constant.forDouble(longVal);
+                }
+                break;
+            case Float:
+                float floatVal = c.asFloat();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte((byte) floatVal);
+                    case Short:
+                        return Constant.forShort((short) floatVal);
+                    case Char:
+                        return Constant.forChar((char) floatVal);
+                    case Int:
+                        return Constant.forInt((int) floatVal);
+                    case Long:
+                        return Constant.forLong((long) floatVal);
+                    case Float:
+                        return Constant.forFloat(floatVal);
+                    case Double:
+                        return Constant.forDouble(floatVal);
+                }
+                break;
+            case Double:
+                double doubleVal = c.asDouble();
+                switch (to) {
+                    case Byte:
+                        return Constant.forByte((byte) doubleVal);
+                    case Short:
+                        return Constant.forShort((short) doubleVal);
+                    case Char:
+                        return Constant.forChar((char) doubleVal);
+                    case Int:
+                        return Constant.forInt((int) doubleVal);
+                    case Long:
+                        return Constant.forLong((long) doubleVal);
+                    case Float:
+                        return Constant.forFloat((float) doubleVal);
+                    case Double:
+                        return Constant.forDouble(doubleVal);
+                }
+                break;
         }
+        throw GraalInternalError.shouldNotReachHere();
     }
 
     @Override
@@ -312,21 +248,15 @@
         }
         Stamp newStamp;
         IntegerStamp integerStamp = (IntegerStamp) stamp;
-        switch (opcode) {
-            case I2L:
-                newStamp = StampTool.intToLong(integerStamp);
-                break;
-            case L2I:
-                newStamp = StampTool.longToInt(integerStamp);
+        switch (to) {
+            case Byte:
+            case Short:
+            case Char:
+            case Int:
+                newStamp = StampTool.narrowingKindConversion(integerStamp, to);
                 break;
-            case I2B:
-                newStamp = StampTool.intToByte(integerStamp);
-                break;
-            case I2C:
-                newStamp = StampTool.intToChar(integerStamp);
-                break;
-            case I2S:
-                newStamp = StampTool.intToShort(integerStamp);
+            case Long:
+                newStamp = StampTool.intToLong(integerStamp);
                 break;
             default:
                 return false;
@@ -341,27 +271,14 @@
 
     @Override
     public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitConvert(opcode, gen.operand(value())));
+        gen.setResult(this, gen.emitConvert(from, to, gen.operand(value())));
     }
 
-    public static ValueNode convert(Kind toKind, ValueNode value) {
+    public static ValueNode convert(StructuredGraph graph, Kind toKind, ValueNode value) {
         Kind fromKind = value.kind();
         if (fromKind == toKind) {
             return value;
         }
-        return value.graph().unique(new ConvertNode(Op.getOp(fromKind, toKind), value));
+        return graph.unique(new ConvertNode(fromKind, toKind, value));
     }
-
-    @NodeIntrinsic
-    public static native float convert(@ConstantNodeParameter Op op, int value);
-
-    @NodeIntrinsic
-    public static native int convert(@ConstantNodeParameter Op op, float value);
-
-    @NodeIntrinsic
-    public static native double convert(@ConstantNodeParameter Op op, long value);
-
-    @NodeIntrinsic
-    public static native long convert(@ConstantNodeParameter Op op, double value);
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Mon Nov 04 16:12:48 2013 +0100
@@ -0,0 +1,137 @@
+/*
+ * 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.nodes.calc;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * The {@code ReinterpretNode} class represents a reinterpreting conversion between primitive types.
+ */
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
+
+    @Input private ValueNode value;
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public ReinterpretNode(Kind to, ValueNode value) {
+        super(StampFactory.forKind(to.getStackKind()));
+        this.value = value;
+    }
+
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        Constant c = inputs[0];
+        assert c.getKind() == value.kind();
+        switch (c.getKind()) {
+            case Int:
+                switch (kind()) {
+                    case Int:
+                        return c;
+                    case Long:
+                        return Constant.forLong(c.asInt() & 0xFFFFFFFFL);
+                    case Float:
+                        return Constant.forFloat(Float.intBitsToFloat(c.asInt()));
+                    case Double:
+                        return Constant.forDouble(Double.longBitsToDouble(c.asInt() & 0xFFFFFFFFL));
+                }
+                break;
+            case Long:
+                switch (kind()) {
+                    case Int:
+                        return Constant.forInt((int) c.asLong());
+                    case Long:
+                        return c;
+                    case Float:
+                        return Constant.forFloat(Float.intBitsToFloat((int) c.asLong()));
+                    case Double:
+                        return Constant.forDouble(Double.longBitsToDouble(c.asLong()));
+                }
+                break;
+            case Float:
+                switch (kind()) {
+                    case Int:
+                        return Constant.forInt(Float.floatToRawIntBits(c.asFloat()));
+                    case Long:
+                        return Constant.forLong(Float.floatToRawIntBits(c.asFloat()) & 0xFFFFFFFFL);
+                    case Float:
+                        return c;
+                    case Double:
+                        return Constant.forDouble(Double.longBitsToDouble(Float.floatToRawIntBits(c.asFloat()) & 0xFFFFFFFFL));
+                }
+                break;
+            case Double:
+                switch (kind()) {
+                    case Int:
+                        return Constant.forInt((int) Double.doubleToRawLongBits(c.asDouble()));
+                    case Long:
+                        return Constant.forLong(Double.doubleToRawLongBits(c.asDouble()));
+                    case Float:
+                        return Constant.forFloat(Float.intBitsToFloat((int) Double.doubleToRawLongBits(c.asDouble())));
+                    case Double:
+                        return c;
+                }
+                break;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(ArithmeticLIRGenerator gen) {
+        gen.setResult(this, gen.emitReinterpret(kind(), gen.operand(value())));
+    }
+
+    public static ValueNode reinterpret(Kind toKind, ValueNode value) {
+        Kind fromKind = value.kind();
+        if (fromKind == toKind) {
+            return value;
+        }
+        return value.graph().unique(new ReinterpretNode(toKind, value));
+    }
+
+    @NodeIntrinsic
+    public static native float reinterpret(@ConstantNodeParameter Kind kind, int value);
+
+    @NodeIntrinsic
+    public static native int reinterpret(@ConstantNodeParameter Kind kind, float value);
+
+    @NodeIntrinsic
+    public static native double reinterpret(@ConstantNodeParameter Kind kind, long value);
+
+    @NodeIntrinsic
+    public static native long reinterpret(@ConstantNodeParameter Kind kind, double value);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Mon Nov 04 16:12:48 2013 +0100
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 
 /**
  * This interface can be used to generate LIR for arithmetic operations (@see
@@ -66,7 +65,9 @@
 
     Value emitUShr(Value a, Value b);
 
-    Value emitConvert(ConvertNode.Op opcode, Value inputVal);
+    Value emitConvert(Kind from, Kind to, Value inputVal);
+
+    Value emitReinterpret(Kind to, Value inputVal);
 
     Value emitMathAbs(Value input);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Nov 04 16:12:48 2013 +0100
@@ -304,7 +304,7 @@
         return StampFactory.forInteger(Kind.Long, intStamp.lowerBound(), intStamp.upperBound(), signExtend(intStamp.downMask(), Kind.Int), signExtend(intStamp.upMask(), Kind.Int));
     }
 
-    private static IntegerStamp narrowingKindConvertion(IntegerStamp fromStamp, Kind toKind) {
+    public static IntegerStamp narrowingKindConversion(IntegerStamp fromStamp, Kind toKind) {
         assert toKind == Kind.Byte || toKind == Kind.Char || toKind == Kind.Short || toKind == Kind.Int;
         final long upperBound;
         if (fromStamp.lowerBound() < toKind.getMinValue()) {
@@ -334,26 +334,6 @@
         }
     }
 
-    public static IntegerStamp intToByte(IntegerStamp intStamp) {
-        assert intStamp.kind() == Kind.Int;
-        return narrowingKindConvertion(intStamp, Kind.Byte);
-    }
-
-    public static IntegerStamp intToShort(IntegerStamp intStamp) {
-        assert intStamp.kind() == Kind.Int;
-        return narrowingKindConvertion(intStamp, Kind.Short);
-    }
-
-    public static IntegerStamp intToChar(IntegerStamp intStamp) {
-        assert intStamp.kind() == Kind.Int;
-        return narrowingKindConvertion(intStamp, Kind.Char);
-    }
-
-    public static IntegerStamp longToInt(IntegerStamp longStamp) {
-        assert longStamp.kind() == Kind.Long;
-        return narrowingKindConvertion(longStamp, Kind.Int);
-    }
-
     public static long saturate(long v, Kind kind) {
         long max = kind.getMaxValue();
         if (v > max) {
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java	Mon Nov 04 16:12:48 2013 +0100
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -37,12 +36,14 @@
 public class AMD64ConvertNode extends FloatingNode implements ArithmeticLIRLowerable {
 
     @Input private ValueNode value;
-    public final Op opcode;
+    private final Kind from;
+    private final Kind to;
 
-    public AMD64ConvertNode(Op opcode, ValueNode value) {
-        super(StampFactory.forKind(opcode.to.getStackKind()));
-        this.opcode = opcode;
+    public AMD64ConvertNode(Kind from, Kind to, ValueNode value) {
+        super(StampFactory.forKind(to.getStackKind()));
         this.value = value;
+        this.from = from;
+        this.to = to;
     }
 
     public Constant evalConst(Constant... inputs) {
@@ -52,6 +53,6 @@
     }
 
     public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitConvert(opcode, gen.operand(value)));
+        gen.setResult(this, gen.emitConvert(from, to, gen.operand(value)));
     }
 }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon Nov 04 16:12:48 2013 +0100
@@ -25,13 +25,10 @@
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
-import java.util.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
@@ -147,20 +144,44 @@
 
     public static class Templates extends AbstractTemplates {
 
-        private final EnumMap<Op, SnippetInfo> snippets;
+        private final SnippetInfo f2i;
+        private final SnippetInfo f2l;
+        private final SnippetInfo d2i;
+        private final SnippetInfo d2l;
 
         public Templates(Providers providers, TargetDescription target) {
             super(providers, target);
 
-            snippets = new EnumMap<>(Op.class);
-            snippets.put(Op.F2I, snippet(AMD64ConvertSnippets.class, "f2i"));
-            snippets.put(Op.F2L, snippet(AMD64ConvertSnippets.class, "f2l"));
-            snippets.put(Op.D2I, snippet(AMD64ConvertSnippets.class, "d2i"));
-            snippets.put(Op.D2L, snippet(AMD64ConvertSnippets.class, "d2l"));
+            f2i = snippet(AMD64ConvertSnippets.class, "f2i");
+            f2l = snippet(AMD64ConvertSnippets.class, "f2l");
+            d2i = snippet(AMD64ConvertSnippets.class, "d2i");
+            d2l = snippet(AMD64ConvertSnippets.class, "d2l");
         }
 
         public void lower(ConvertNode convert, LoweringTool tool) {
-            SnippetInfo key = snippets.get(convert.opcode);
+            SnippetInfo key = null;
+            switch (convert.getFromKind()) {
+                case Float:
+                    switch (convert.getToKind()) {
+                        case Int:
+                            key = f2i;
+                            break;
+                        case Long:
+                            key = f2l;
+                            break;
+                    }
+                    break;
+                case Double:
+                    switch (convert.getToKind()) {
+                        case Int:
+                            key = d2i;
+                            break;
+                        case Long:
+                            key = d2l;
+                            break;
+                    }
+                    break;
+            }
             if (key == null) {
                 return;
             }
@@ -169,10 +190,10 @@
 
             Arguments args = new Arguments(key, graph.getGuardsStage());
             args.add("input", convert.value());
-            args.add("result", graph.unique(new AMD64ConvertNode(convert.opcode, convert.value())));
+            args.add("result", graph.unique(new AMD64ConvertNode(convert.getFromKind(), convert.getToKind(), convert.value())));
 
             SnippetTemplate template = template(args);
-            Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, args);
+            Debug.log("Lowering %c2%c in %s: node=%s, template=%s, arguments=%s", convert.getFromKind().getTypeChar(), convert.getToKind().getTypeChar(), graph, convert, template, args);
             template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args);
             graph.removeFloating(convert);
         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Nov 04 16:12:48 2013 +0100
@@ -111,7 +111,8 @@
 
         if (indexConvert) {
             ConvertNode convert = (ConvertNode) location.getIndex();
-            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(Kind.Int, convert.getFromKind());
+            Assert.assertEquals(Kind.Long, convert.getToKind());
             Assert.assertEquals(graph.getLocal(1), convert.value());
         } else {
             Assert.assertEquals(graph.getLocal(1), location.getIndex());
@@ -135,7 +136,8 @@
 
         if (indexConvert) {
             ConvertNode convert = (ConvertNode) location.getIndex();
-            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(Kind.Int, convert.getFromKind());
+            Assert.assertEquals(Kind.Long, convert.getToKind());
             Assert.assertEquals(graph.getLocal(1), convert.value());
         } else {
             Assert.assertEquals(graph.getLocal(1), location.getIndex());
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Nov 04 16:12:48 2013 +0100
@@ -122,7 +122,8 @@
 
         if (indexConvert) {
             ConvertNode convert = (ConvertNode) location.getIndex();
-            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(Kind.Int, convert.getFromKind());
+            Assert.assertEquals(Kind.Long, convert.getToKind());
             Assert.assertEquals(graph.getLocal(1), convert.value());
         } else {
             Assert.assertEquals(graph.getLocal(1), location.getIndex());
@@ -151,7 +152,8 @@
 
         if (indexConvert) {
             ConvertNode convert = (ConvertNode) location.getIndex();
-            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(Kind.Int, convert.getFromKind());
+            Assert.assertEquals(Kind.Long, convert.getToKind());
             Assert.assertEquals(graph.getLocal(1), convert.value());
         } else {
             Assert.assertEquals(graph.getLocal(1), location.getIndex());
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Mon Nov 04 16:12:48 2013 +0100
@@ -422,7 +422,7 @@
 
     @Test
     public void testFloatSubstitutions() {
-        assertInGraph(test("floatToIntBits"), ConvertNode.class); // Java
+        assertInGraph(test("floatToIntBits"), ReinterpretNode.class); // Java
         test("intBitsToFloat");
     }
 
@@ -438,7 +438,7 @@
 
     @Test
     public void testDoubleSubstitutions() {
-        assertInGraph(test("doubleToLongBits"), ConvertNode.class); // Java
+        assertInGraph(test("doubleToLongBits"), ReinterpretNode.class); // Java
         test("longBitsToDouble");
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java	Mon Nov 04 16:12:48 2013 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.calc.*;
 
@@ -35,9 +36,7 @@
 
     @MethodSubstitution
     public static long doubleToRawLongBits(double value) {
-        @JavacBug(id = 6995200)
-        Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value);
-        return result;
+        return ReinterpretNode.reinterpret(Kind.Long, value);
     }
 
     // TODO This method is not necessary, since the JDK method does exactly this
@@ -52,8 +51,6 @@
 
     @MethodSubstitution
     public static double longBitsToDouble(long bits) {
-        @JavacBug(id = 6995200)
-        Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits);
-        return result;
+        return ReinterpretNode.reinterpret(Kind.Double, bits);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java	Mon Nov 04 16:12:48 2013 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.calc.*;
 
@@ -35,9 +36,7 @@
 
     @MethodSubstitution
     public static int floatToRawIntBits(float value) {
-        @JavacBug(id = 6995200)
-        Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value);
-        return result;
+        return ReinterpretNode.reinterpret(Kind.Int, value);
     }
 
     // TODO This method is not necessary, since the JDK method does exactly this
@@ -52,8 +51,6 @@
 
     @MethodSubstitution
     public static float intBitsToFloat(int bits) {
-        @JavacBug(id = 6995200)
-        Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits);
-        return result;
+        return ReinterpretNode.reinterpret(Kind.Float, bits);
     }
 }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Nov 04 12:20:17 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Nov 04 16:12:48 2013 +0100
@@ -312,31 +312,33 @@
     }
 
     protected ValueNode fromUnsigned(StructuredGraph graph, ValueNode value) {
-        return convert(graph, value, wordKind, ConvertNode.Op.L2I, ConvertNode.Op.UNSIGNED_I2L);
+        return convert(graph, value, wordKind, true);
     }
 
     private ValueNode fromSigned(StructuredGraph graph, ValueNode value) {
-        return convert(graph, value, wordKind, ConvertNode.Op.L2I, ConvertNode.Op.I2L);
+        return convert(graph, value, wordKind, false);
     }
 
     protected ValueNode toUnsigned(StructuredGraph graph, ValueNode value, Kind toKind) {
-        return convert(graph, value, toKind, ConvertNode.Op.L2I, ConvertNode.Op.UNSIGNED_I2L);
+        return convert(graph, value, toKind, true);
     }
 
-    private static ValueNode convert(StructuredGraph graph, ValueNode value, Kind toKind, ConvertNode.Op longToIntOp, ConvertNode.Op intToLongOp) {
-        assert longToIntOp.from == Kind.Long && longToIntOp.to == Kind.Int;
-        assert intToLongOp.from == Kind.Int && intToLongOp.to == Kind.Long;
+    private static ValueNode convert(StructuredGraph graph, ValueNode value, Kind toKind, boolean unsigned) {
         if (value.kind() == toKind) {
             return value;
         }
 
         if (toKind == Kind.Int) {
             assert value.kind() == Kind.Long;
-            return graph.unique(new ConvertNode(longToIntOp, value));
+            return graph.unique(new ConvertNode(Kind.Long, Kind.Int, value));
         } else {
             assert toKind == Kind.Long;
             assert value.kind().getStackKind() == Kind.Int;
-            return graph.unique(new ConvertNode(intToLongOp, value));
+            if (unsigned) {
+                return graph.unique(new ReinterpretNode(Kind.Long, value));
+            } else {
+                return graph.unique(new ConvertNode(Kind.Int, Kind.Long, value));
+            }
         }
     }