changeset 9817:26960d32552c

SPARC integer arithmetic
author Morris Meyer <morris.meyer@oracle.com>
date Sat, 25 May 2013 16:24:05 -0400
parents 4e9854086532
children a9517aa587c7
files graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/IntegerSPARCTest.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java
diffstat 4 files changed, 593 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri May 24 22:51:36 2013 -0400
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Sat May 25 16:24:05 2013 -0400
@@ -169,6 +169,18 @@
         }
     }
 
+    public static class Fmt3n {
+        public Fmt3n(SPARCAssembler masm, int op, int op3, int opf, int rs2, int rd) {
+            assert  op == 2 || op == 3;
+            assert op3 >= 0 && op3 < 0x40;
+            assert opf >= 0 && opf < 0x200;
+            assert rs2 >= 0 && rs2 < 0x20;
+            assert  rd >= 0 &&  rd < 0x20;
+
+            masm.emitInt(op << 30 | rd << 25 | op3 << 19 | opf << 5 | rs2);
+        }
+    }
+
     public static class Fmt3q {
         public Fmt3q(SPARCAssembler masm, int op, int op3, int rs1, int rd) {
             assert  op == 2 || op == 3;
@@ -313,12 +325,14 @@
     }
 
     public enum Opfs {
-        Fadds((0x41 << 5) & 0x00003FE0, "fadds"),
-        Faddd((0x42 << 5) & 0x00003FE0, "faddd"),
-        Faddq((0x43 << 5) & 0x00003FE0, "faddq"),
-        Fsubs((0x45 << 5) & 0x00003FE0, "fsubs"),
-        Fsubd((0x46 << 5) & 0x00003FE0, "fsubd"),
-        Fsubq((0x47 << 5) & 0x00003FE0, "fsubq");
+        Fadds(0x41, "fadds"),
+        Faddd(0x42, "faddd"),
+        Faddq(0x43, "faddq"),
+        Fsubs(0x45, "fsubs"),
+        Fsubd(0x46, "fsubd"),
+        Fsubq(0x47, "fsubq"),
+        Fstoi(0xD1, "fstoi"),
+        Fdtoi(0xD2, "fdtoi");
 
         private final int value;
         private final String operator;
@@ -602,6 +616,20 @@
         }
     }
 
+    public static class Fstoi extends Fmt3n {
+        public Fstoi(SPARCAssembler masm, Register src2, Register dst) {
+            super(masm, Ops.ArithOp.getValue(), Op3s.Fpop1.getValue(), Opfs.Fstoi.getValue(),
+                  src2.encoding(), dst.encoding());
+        }
+    }
+
+    public static class Fdtoi extends Fmt3n {
+        public Fdtoi(SPARCAssembler masm, Register src2, Register dst) {
+            super(masm, Ops.ArithOp.getValue(), Op3s.Fpop1.getValue(), Opfs.Fdtoi.getValue(),
+                  src2.encoding(), dst.encoding());
+        }
+    }
+
     public final void flushw() {
         emitInt(Ops.ArithOp.getValue() | Op3s.Flushw.getValue());
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/IntegerSPARCTest.java	Sat May 25 16:24:05 2013 -0400
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.sparc.test;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+public class IntegerSPARCTest extends SPARCTestBase {
+
+    @Test
+    public void testAdd() {
+        compile("testAdd2I");
+        compile("testAdd2L");
+        compile("testAdd2B");
+        compile("testAddIConst");
+        compile("testAddConstI");
+    }
+
+    public static int testAdd2I(int a, int b) {
+        return a + b;
+    }
+
+    public static long testAdd2L(long a, long b) {
+        return a + b;
+    }
+
+    public static int testAdd2B(byte a, byte b) {
+        return a + b;
+    }
+
+    public static int testAddIConst(int a) {
+        return a + 32;
+    }
+
+    public static int testAddConstI(int a) {
+        return 32 + a;
+    }
+
+    @Test
+    public void testSub() {
+        compile("testSub2I");
+        compile("testSub2L");
+        compile("testSubIConst");
+        compile("testSubConstI");
+    }
+
+    public static int testSub2I(int a, int b) {
+        return a - b;
+    }
+
+    public static long testSub2L(long a, long b) {
+        return a - b;
+    }
+
+    public static int testSubIConst(int a) {
+        return a - 32;
+    }
+
+    public static int testSubConstI(int a) {
+        return 32 - a;
+    }
+
+    @Test
+    public void testMul() {
+        compile("testMul2I");
+        compile("testMul2L");
+        compile("testMulIConst");
+        compile("testMulConstI");
+    }
+
+    public static int testMul2I(int a, int b) {
+        return a * b;
+    }
+
+    public static long testMul2L(long a, long b) {
+        return a * b;
+    }
+
+    public static int testMulIConst(int a) {
+        return a * 32;
+    }
+
+    public static int testMulConstI(int a) {
+        return 32 * a;
+    }
+
+    @Test
+    public void testDiv() {
+        compile("testDiv2I");
+        compile("testDiv2L");
+        compile("testDivIConst");
+    }
+
+    public static int testDiv2I(int a, int b) {
+        return a / b;
+    }
+
+    public static long testDiv2L(long a, long b) {
+        return a / b;
+    }
+
+    public static int testDivIConst(int a) {
+        return a / 32;
+    }
+
+    @Ignore
+    public void testRem() {
+        compile("testRem2I");
+        compile("testRem2L");
+    }
+
+    public static int testRem2I(int a, int b) {
+        return a % b;
+    }
+
+    public static long testRem2L(long a, long b) {
+        return a % b;
+    }
+
+    @Test
+    public void testIntConversion() {
+        compile("testI2L");
+        compile("testI2C");
+        compile("testI2B");
+        compile("testI2F");
+        compile("testI2D");
+    }
+
+    public static long testI2L(int a) {
+        return a;
+    }
+
+    public static char testI2C(int a) {
+        return (char) a;
+    }
+
+    public static byte testI2B(int a) {
+        return (byte) a;
+    }
+
+    public static float testI2F(int a) {
+        return a;
+    }
+
+    public static double testI2D(int a) {
+        return a;
+    }
+
+    public static void main(String[] args) {
+        IntegerSPARCTest test = new IntegerSPARCTest();
+        for (Method m : IntegerSPARCTest.class.getMethods()) {
+            String name = m.getName();
+            if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
+                // CheckStyle: stop system..print check
+                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
+                // CheckStyle: resume system..print check
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 24 22:51:36 2013 -0400
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Sat May 25 16:24:05 2013 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -25,10 +25,7 @@
 
 import static com.oracle.graal.api.code.ValueUtil.isRegister;
 import static com.oracle.graal.api.code.ValueUtil.isStackSlot;
-import static com.oracle.graal.lir.sparc.SPARCArithmetic.DADD;
-import static com.oracle.graal.lir.sparc.SPARCArithmetic.FADD;
-import static com.oracle.graal.lir.sparc.SPARCArithmetic.IADD;
-import static com.oracle.graal.lir.sparc.SPARCArithmetic.LADD;
+import static com.oracle.graal.lir.sparc.SPARCArithmetic.*;
 
 import com.oracle.graal.api.code.CallingConvention;
 import com.oracle.graal.api.code.CodeCacheProvider;
@@ -40,7 +37,7 @@
 import com.oracle.graal.api.meta.Constant;
 import com.oracle.graal.api.meta.Kind;
 import com.oracle.graal.api.meta.Value;
-import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.NumUtil;
 import com.oracle.graal.compiler.gen.LIRGenerator;
 import com.oracle.graal.compiler.target.LIRGenLowerable;
 import com.oracle.graal.graph.GraalInternalError;
@@ -53,7 +50,10 @@
 import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.Op1Stack;
 import com.oracle.graal.lir.sparc.SPARCArithmetic.Op2Stack;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary1Op;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op;
 import com.oracle.graal.nodes.BreakpointNode;
 import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.DirectCallTargetNode;
@@ -296,23 +296,84 @@
 
     @Override
     public Value emitSub(Value a, Value b) {
-        throw new InternalError("NYI");
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
+                break;
+            case Long:
+                append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
+                break;
+            case Float:
+                append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
+                break;
+            case Double:
+                append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+        }
+        return result;
     }
 
     @Override
     public Value emitMul(Value a, Value b) {
-        throw new InternalError("NYI");
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new Op2Reg(IMUL, result, a, loadNonConst(b)));
+                break;
+            case Long:
+                append(new Op2Reg(LMUL, result, a, loadNonConst(b)));
+                break;
+            case Float:
+                append(new Op2Stack(FMUL, result, a, loadNonConst(b)));
+                break;
+            case Double:
+                append(new Op2Stack(DMUL, result, a, loadNonConst(b)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+        }
+        return result;
     }
 
     @Override
     public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
-        // SPARC: Auto-generated method stub
-        return null;
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new Op2Reg(IDIV, result, a, loadNonConst(b)));
+                break;
+            case Long:
+                append(new Op2Reg(LDIV, result, a, loadNonConst(b)));
+                break;
+            case Float:
+                append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
+                break;
+            case Double:
+                append(new Op2Stack(DDIV, result, a, loadNonConst(b)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+        }
+        return result;
     }
 
     @Override
     public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
-        throw new InternalError("NYI");
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new Op2Reg(IREM, result, a, loadNonConst(b)));
+                break;
+            case Long:
+                append(new Op2Reg(LREM, result, a, loadNonConst(b)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+        }
+        return result;
     }
 
     @Override
@@ -342,22 +403,124 @@
 
     @Override
     public Value emitShl(Value a, Value b) {
-        throw new InternalError("NYI");
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new Op2Stack(ISHL, result, a, loadNonConst(b)));
+                break;
+            case Long:
+                append(new Op1Stack(LSHL, result, loadNonConst(b)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        return result;
     }
 
     @Override
     public Value emitShr(Value a, Value b) {
-        throw new InternalError("NYI");
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new Op2Stack(ISHR, result, a, loadNonConst(b)));
+                break;
+            case Long:
+                append(new Op1Stack(LSHR, result, loadNonConst(b)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        return result;
     }
 
     @Override
     public Value emitUShr(Value a, Value b) {
-        throw new InternalError("NYI");
+        Variable result = newVariable(a.getKind());
+        switch (a.getKind()) {
+            case Int:
+                append(new ShiftOp(IUSHR, result, a, b));
+                break;
+            case Long:
+                append(new ShiftOp(LUSHR, result, a, b));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        return result;
     }
 
     @Override
     public Value emitConvert(Op opcode, Value inputVal) {
-        throw new InternalError("NYI");
+        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();
+        }
+        return result;
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Fri May 24 22:51:36 2013 -0400
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Sat May 25 16:24:05 2013 -0400
@@ -22,21 +22,12 @@
  */
 package com.oracle.graal.lir.sparc;
 
-import static com.oracle.graal.api.code.ValueUtil.asFloatReg;
-import static com.oracle.graal.api.code.ValueUtil.asIntReg;
-import static com.oracle.graal.api.code.ValueUtil.asLongReg;
-import static com.oracle.graal.api.code.ValueUtil.isConstant;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
-
-import com.oracle.graal.api.meta.Kind;
-import com.oracle.graal.api.meta.Value;
-import com.oracle.graal.asm.sparc.SPARCAssembler;
+import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Add;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.And;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Fadds;
+import static com.oracle.graal.asm.sparc.SPARCAssembler.Fdtoi;
+import static com.oracle.graal.asm.sparc.SPARCAssembler.Fstoi;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Fsubs;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Mulx;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Or;
@@ -46,7 +37,13 @@
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Sra;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Sub;
 import static com.oracle.graal.asm.sparc.SPARCAssembler.Xor;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler;
 import com.oracle.graal.graph.GraalInternalError;
 import com.oracle.graal.lir.LIRFrameState;
 import com.oracle.graal.lir.asm.TargetMethodAssembler;
@@ -64,6 +61,65 @@
     L2F, L2D, F2L, D2L,
     MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
 
+
+    /**
+     * Unary operation with separate source and destination operand. 
+     */
+    public static class Unary2Op extends SPARCLIRInstruction {
+        @Opcode private final SPARCArithmetic opcode;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+
+        public Unary2Op(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, SPARCAssembler masm) {
+            SPARCMove.move(tasm, masm, result, x);
+            emit(tasm, masm, opcode, result, x, null);
+        }
+    }
+
+    /**
+     * Unary operation with single operand for source and destination. 
+     */
+    public static class Unary1Op extends SPARCLIRInstruction {
+        @Opcode private final SPARCArithmetic opcode;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+
+        public Unary1Op(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, SPARCAssembler masm) {
+            emit(masm, opcode, result);
+        }
+    }
+
+    public static class Op1Stack extends SPARCLIRInstruction {
+        @Opcode private final SPARCArithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+
+        public Op1Stack(SPARCArithmetic opcode, Value result, Value x) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, SPARCAssembler masm) {
+            emit(tasm, masm, opcode, result, x, null);
+        }
+    }
+
     public static class Op2Stack extends SPARCLIRInstruction {
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG, HINT}) protected Value result;
@@ -89,19 +145,92 @@
         }
     }
 
+    public static class Op2Reg extends SPARCLIRInstruction {
+        @Opcode private final SPARCArithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+        @Alive({REG, CONST}) protected Value y;
+
+        public Op2Reg(SPARCArithmetic opcode, Value result, Value x, Value y) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, SPARCAssembler masm) {
+            emit(tasm, masm, opcode, result, x, y, null);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            verifyKind(opcode, result, x, y);
+        }
+    }
+
+    public static class ShiftOp extends SPARCLIRInstruction {
+        @Opcode private final SPARCArithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+        @Alive({REG, CONST}) protected Value y;
+
+        public ShiftOp(SPARCArithmetic opcode, Value result, Value x, Value y) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, SPARCAssembler masm) {
+            emit(tasm, masm, opcode, result, x, y, null);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            verifyKind(opcode, result, x, x);
+            assert y.getKind().getStackKind() == Kind.Int;
+        }
+    }
+    protected static void emit(SPARCAssembler masm, SPARCArithmetic opcode, Value result) {
+        switch (opcode) {
+            case L2I:
+                new Sra(masm, asLongReg(result), 0, asIntReg(result));
+                break;
+            case I2C:
+                new Sll(masm, asIntReg(result), 16, asIntReg(result));
+                new Srl(masm, asIntReg(result), 16, asIntReg(result));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
+        }
+    }
+
+
     public static void emit(TargetMethodAssembler tasm, SPARCAssembler masm, SPARCArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) {
         int exceptionOffset = -1;
         if (isConstant(src1)) {
-            switch (opcode) {
-            case ISUB:  throw new InternalError("NYI");
-            case IAND:  throw new InternalError("NYI");
-            case IDIV:  throw new InternalError("NYI");
-            case FSUB:  throw new InternalError("NYI");
-            case FDIV:  throw new InternalError("NYI");
-            case DSUB:  throw new InternalError("NYI");
-            case DDIV:  throw new InternalError("NYI");
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+            if (is_simm13(tasm.asIntConst(src1))) {
+                switch (opcode) {
+                case ISUB:
+                    new Add(masm, asIntReg(src2), -(tasm.asIntConst(src1)), asIntReg(dst));
+                    break;
+                case IAND:  throw new InternalError("NYI");
+                case IDIV:
+                    throw new InternalError("NYI");
+                    // new Sdivx(masm, asIntReg(src1), asIntReg(src2), asIntReg(dst));
+                case FSUB:  throw new InternalError("NYI");
+                case FDIV:  throw new InternalError("NYI");
+                case DSUB:  throw new InternalError("NYI");
+                case DDIV:  throw new InternalError("NYI");
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                throw new InternalError("NYI");
             }
         } else if (isConstant(src2)) {
             if (is_simm13(tasm.asIntConst(src2))) {
@@ -118,9 +247,15 @@
                 case IAND:
                     new And(masm, asIntReg(src1), tasm.asIntConst(src2), asIntReg(dst));
                     break;
-                case ISHL:  throw new InternalError("NYI");
-                case ISHR:  throw new InternalError("NYI");
-                case IUSHR: throw new InternalError("NYI");
+                case ISHL:
+                    new Sll(masm, asIntReg(src1), tasm.asIntConst(src2), asIntReg(dst));
+                    break;
+                case ISHR:
+                    new Srl(masm, asIntReg(src1), tasm.asIntConst(src2), asIntReg(dst));
+                    break;
+                case IUSHR:
+                    new Sra(masm, asIntReg(src1), tasm.asIntConst(src2), asIntReg(dst));
+                    break;
                 case IXOR:  throw new InternalError("NYI");
                 case LXOR:  throw new InternalError("NYI");
                 case LUSHR: throw new InternalError("NYI");
@@ -225,6 +360,45 @@
         }
     }
 
+    public static void emit(TargetMethodAssembler tasm, SPARCAssembler masm, SPARCArithmetic opcode,
+                            Value dst, Value src, LIRFrameState info) {
+        int exceptionOffset = -1;
+        if (isRegister(src)) {
+            switch (opcode) {
+                case I2L:
+                    new Sra(masm, asIntReg(src), 0, asLongReg(dst));
+                    break;
+                case I2B:
+                    new Sll(masm, asIntReg(src), 24, asIntReg(src));
+                    new Srl(masm, asIntReg(dst), 24, asIntReg(src));
+                    break;
+                case I2F:
+                    new Fstoi(masm, asIntReg(src), asFloatReg(dst));
+                    break;
+                case I2D:
+                    new Fdtoi(masm, asIntReg(src), asDoubleReg(dst));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
+            }
+        } else if (isConstant(src)) {
+            switch (opcode) {
+                default:
+                    throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
+            }
+        } else {
+            switch (opcode) {
+                default:
+                    throw GraalInternalError.shouldNotReachHere("missing: "  + opcode);
+            }
+        }
+
+        if (info != null) {
+            assert exceptionOffset != -1;
+            tasm.recordImplicitException(exceptionOffset, info);
+        }
+    }
+
     private static final int max13 =  ((1 << 12) - 1);
     private static final int min13 = -(1 << 12);