changeset 17082:f8586d059f9d

[SPARC] make compatible for CPU without VIS3 and do some cleanup
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Tue, 09 Sep 2014 12:09:58 -0700
parents 62505bdc6960
children 2b7c005ae93a
files graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java
diffstat 9 files changed, 364 insertions(+), 279 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Sep 09 12:09:58 2014 -0700
@@ -3136,6 +3136,15 @@
         }
     }
 
+    public static class Fxtos extends Fmt3n {
+
+        public Fxtos(Register src2, Register dst) {
+            super(Ops.ArithOp.getValue(), Op3s.Fpop1.getValue(), Opfs.Fxtos.getValue(), src2.encoding(), dst.encoding());
+            assert isDoubleFloatRegister(src2);
+            assert isSingleFloatRegister(dst);
+        }
+    }
+
     public static class Fxtod extends Fmt3n {
 
         public Fxtod(Register src2, Register dst) {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Tue Sep 09 12:09:58 2014 -0700
@@ -27,6 +27,9 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.sparc.*;
+import com.oracle.graal.sparc.SPARC.CPUFeature;
 
 public class SPARCMacroAssembler extends SPARCAssembler {
 
@@ -64,6 +67,10 @@
         fmt.write(this, branch);
     }
 
+    protected boolean hasFeature(CPUFeature feature) {
+        return ((SPARC) this.target.arch).features.contains(feature);
+    }
+
     @Override
     public AbstractAddress makeAddress(Register base, int displacement) {
         return new SPARCAddress(base, displacement);
@@ -338,6 +345,27 @@
         }
     }
 
+    public static class MoveXtoDouble {
+        private final Register src;
+        private final Register dst;
+        private final StackSlot tmp;
+
+        public MoveXtoDouble(Register src, Register dst, StackSlot tmp) {
+            super();
+            this.src = src;
+            this.dst = dst;
+            this.tmp = tmp;
+        }
+
+        public void emit(SPARCMacroAssembler masm) {
+            if (masm.hasFeature(CPUFeature.VIS3)) {
+                new Movxtod(src, dst).emit(masm);
+            } else {
+                GraalInternalError.unimplemented();
+            }
+        }
+    }
+
     /**
      * This instruction is like sethi but for 64-bit values.
      */
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Sep 09 12:09:58 2014 -0700
@@ -27,15 +27,12 @@
 import static com.oracle.graal.lir.sparc.SPARCArithmetic.*;
 import static com.oracle.graal.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.sparc.SPARCCompare.*;
-import static com.oracle.graal.lir.sparc.SPARCControlFlow.*;
 import static com.oracle.graal.lir.sparc.SPARCMathIntrinsicOp.IntrinsicOpcode.*;
-import static com.oracle.graal.lir.sparc.SPARCMove.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -43,7 +40,29 @@
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegConst;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.MulHighOp;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.ShiftOp;
+import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op;
+import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
+import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
+import com.oracle.graal.lir.sparc.SPARCMove.LoadDataAddressOp;
+import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
+import com.oracle.graal.lir.sparc.SPARCMove.MoveFpGp;
+import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
+import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
+import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
 import com.oracle.graal.phases.util.*;
+import com.oracle.graal.sparc.*;
+import com.oracle.graal.sparc.SPARC.*;
 
 /**
  * This class implements the SPARC specific portion of the LIR generator.
@@ -149,15 +168,6 @@
                 } else {
                     indexRegister = asAllocatable(index);
                 }
-
-                // if (baseRegister.equals(Value.ILLEGAL)) {
-                // baseRegister = asAllocatable(indexRegister);
-                // } else {
-                // Variable newBase = newVariable(Kind.Long);
-                // emitMove(newBase, baseRegister);
-                // baseRegister = newBase;
-                // baseRegister = emitAdd(baseRegister, indexRegister);
-                // }
             }
         } else {
             indexRegister = Value.ILLEGAL;
@@ -453,53 +463,53 @@
 
     @Override
     public Value emitNegate(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind().getStackKind()) {
             case Long:
-                append(new Unary2Op(LNEG, result, load(input)));
-                break;
+                return emitUnary(LNEG, input);
             case Int:
-                append(new Unary2Op(INEG, result, load(input)));
-                break;
+                return emitUnary(INEG, input);
             case Float:
-                append(new Unary2Op(FNEG, result, load(input)));
-                break;
+                return emitUnary(FNEG, input);
             case Double:
-                append(new Unary2Op(DNEG, result, load(input)));
-                break;
+                return emitUnary(DNEG, input);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
     }
 
     @Override
     public Value emitNot(Value input) {
-        Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind().getStackKind()) {
             case Int:
-                append(new Unary2Op(INOT, result, load(input)));
-                break;
+                return emitUnary(INOT, input);
             case Long:
-                append(new Unary2Op(LNOT, result, load(input)));
-                break;
+                return emitUnary(LNOT, input);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
+    }
+
+    private Variable emitUnary(SPARCArithmetic op, Value input) {
+        Variable result = newVariable(LIRKind.derive(input));
+        append(new Unary2Op(op, result, load(input)));
         return result;
     }
 
+    private Variable emitBinary(SPARCArithmetic op, boolean commutative, Value a, Value b) {
+        return emitBinary(op, commutative, a, b, null);
+    }
+
     private Variable emitBinary(SPARCArithmetic op, boolean commutative, Value a, Value b, LIRFrameState state) {
-        if (isConstant(b)) {
-            return emitBinaryConst(op, commutative, asAllocatable(a), asConstant(b), state);
-        } else if (commutative && isConstant(a)) {
-            return emitBinaryConst(op, commutative, asAllocatable(b), asConstant(a), state);
+        if (isConstant(b) && canInlineConstant(asConstant(b))) {
+            return emitBinaryConst(op, load(a), asConstant(b), state);
+        } else if (commutative && isConstant(a) && canInlineConstant(asConstant(a))) {
+            return emitBinaryConst(op, load(b), asConstant(a), state);
         } else {
-            return emitBinaryVar(op, commutative, asAllocatable(a), asAllocatable(b), state);
+            return emitBinaryVar(op, load(a), load(b), state);
         }
     }
 
-    private Variable emitBinaryConst(SPARCArithmetic op, boolean commutative, AllocatableValue a, Constant b, LIRFrameState state) {
+    private Variable emitBinaryConst(SPARCArithmetic op, AllocatableValue a, Constant b, LIRFrameState state) {
         switch (op) {
             case IADD:
             case LADD:
@@ -513,24 +523,19 @@
             case LXOR:
             case IMUL:
             case LMUL:
-                if (NumUtil.isInt(b.asLong())) {
+                if (canInlineConstant(b)) {
                     Variable result = newVariable(LIRKind.derive(a, b));
                     append(new BinaryRegConst(op, result, a, b, state));
                     return result;
                 }
                 break;
         }
-
-        return emitBinaryVar(op, commutative, a, asAllocatable(b), state);
+        return emitBinaryVar(op, a, asAllocatable(b), state);
     }
 
-    private Variable emitBinaryVar(SPARCArithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b, LIRFrameState state) {
+    private Variable emitBinaryVar(SPARCArithmetic op, AllocatableValue a, AllocatableValue b, LIRFrameState state) {
         Variable result = newVariable(LIRKind.derive(a, b));
-        if (commutative) {
-            append(new BinaryCommutative(op, result, a, b));
-        } else {
-            append(new BinaryRegReg(op, result, a, b, state));
-        }
+        append(new BinaryRegReg(op, result, a, b, state));
         return result;
     }
 
@@ -538,13 +543,13 @@
     public Variable emitAdd(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IADD, true, a, b, null);
+                return emitBinary(IADD, true, a, b);
             case Long:
-                return emitBinary(LADD, true, a, b, null);
+                return emitBinary(LADD, true, a, b);
             case Float:
-                return emitBinary(FADD, true, a, b, null);
+                return emitBinary(FADD, true, a, b);
             case Double:
-                return emitBinary(DADD, true, a, b, null);
+                return emitBinary(DADD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -552,46 +557,34 @@
 
     @Override
     public Variable emitSub(Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
         switch (a.getKind().getStackKind()) {
             case Int:
-                append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(ISUB, false, a, b);
             case Long:
-                append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LSUB, false, a, b);
             case Float:
-                append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(FSUB, false, a, b);
             case Double:
-                append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(DSUB, false, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
         }
-        return result;
     }
 
     @Override
     public Variable emitMul(Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
         switch (a.getKind().getStackKind()) {
             case Int:
-                append(new BinaryRegReg(IMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IMUL, true, a, b);
             case Long:
-                append(new BinaryRegReg(LMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LMUL, true, a, b);
             case Float:
-                append(new Op2Stack(FMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(FMUL, true, a, b);
             case Double:
-                append(new Op2Stack(DMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(DMUL, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
         }
-        return result;
     }
 
     @Override
@@ -627,24 +620,18 @@
 
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
-        SPARCArithmetic op = null;
         switch (a.getKind().getStackKind()) {
             case Int:
-                op = IDIV;
-                break;
+                return emitBinary(IDIV, false, a, b, state);
             case Long:
-                op = LDIV;
-                break;
+                return emitBinary(LDIV, false, a, b, state);
             case Float:
-                op = FDIV;
-                break;
+                return emitBinary(FDIV, false, a, b, state);
             case Double:
-                op = DDIV;
-                break;
+                return emitBinary(DDIV, false, a, b, state);
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
         }
-        return emitBinary(op, false, a, b, state);
     }
 
     @Override
@@ -660,19 +647,19 @@
                 break;
             case Float:
                 q = newVariable(LIRKind.value(Kind.Float));
-                append(new Op2Stack(FDIV, q, a, b));
+                append(new BinaryRegReg(FDIV, q, a, b));
                 append(new Unary2Op(F2I, q, q));
                 append(new Unary2Op(I2F, q, q));
-                append(new Op2Stack(FMUL, q, q, b));
-                append(new Op2Stack(FSUB, result, a, q));
+                append(new BinaryRegReg(FMUL, q, q, b));
+                append(new BinaryRegReg(FSUB, result, a, q));
                 break;
             case Double:
                 q = newVariable(LIRKind.value(Kind.Double));
-                append(new Op2Stack(DDIV, q, a, b));
+                append(new BinaryRegReg(DDIV, q, a, b));
                 append(new Unary2Op(D2L, q, q));
                 append(new Unary2Op(L2D, q, q));
-                append(new Op2Stack(DMUL, q, q, b));
-                append(new Op2Stack(DSUB, result, a, q));
+                append(new BinaryRegReg(DMUL, q, q, b));
+                append(new BinaryRegReg(DSUB, result, a, q));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
@@ -719,60 +706,47 @@
 
     @Override
     public Variable emitAnd(Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
         switch (a.getKind().getStackKind()) {
             case Int:
-                append(new Op2Stack(IAND, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IAND, true, a, b);
             case Long:
-                append(new Op2Stack(LAND, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LAND, true, a, b);
 
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
         }
-        return result;
     }
 
     @Override
     public Variable emitOr(Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
         switch (a.getKind().getStackKind()) {
             case Int:
-                append(new Op2Stack(IOR, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IOR, true, a, b);
             case Long:
-                append(new Op2Stack(LOR, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LOR, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
         }
-        return result;
     }
 
     @Override
     public Variable emitXor(Value a, Value b) {
-        Variable result = newVariable(LIRKind.derive(a, b));
         switch (a.getKind().getStackKind()) {
             case Int:
-                append(new Op2Stack(IXOR, result, load(a), loadNonConst(b)));
-                break;
+                return emitBinary(IXOR, true, a, b);
             case Long:
-                append(new Op2Stack(LXOR, result, load(a), loadNonConst(b)));
-                break;
+                return emitBinary(LXOR, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
     }
 
     private Variable emitShift(SPARCArithmetic op, Value a, Value b) {
         Variable result = newVariable(LIRKind.derive(a, b).changeType(a.getPlatformKind()));
-        AllocatableValue input = asAllocatable(a);
-        if (isConstant(b)) {
-            append(new BinaryRegConst(op, result, input, asConstant(b), null));
+        if (isConstant(b) && canInlineConstant((Constant) b)) {
+            append(new BinaryRegConst(op, result, load(a), asConstant(b), null));
         } else {
-            append(new BinaryRegReg(op, result, input, b));
+            append(new BinaryRegReg(op, result, load(a), load(b)));
         }
         return result;
     }
@@ -833,47 +807,82 @@
                 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), D2F, input);
             case F2D:
                 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input);
-            case I2F:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), I2F, input);
-            case L2D:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), L2D, input);
+            case I2F: {
+                AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                moveBetweenFpGp(convertedFloatReg, input);
+                append(new Unary2Op(I2F, convertedFloatReg, convertedFloatReg));
+                return convertedFloatReg;
+            }
+            case I2D: {
+                // Unfortunately we must do int -> float -> double because fitod has float
+                // and double encoding in one instruction
+                AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                moveBetweenFpGp(convertedFloatReg, input);
+                AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                append(new Unary2Op(I2D, convertedDoubleReg, convertedFloatReg));
+                return convertedDoubleReg;
+            }
+            case L2D: {
+                AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                moveBetweenFpGp(convertedDoubleReg, input);
+                append(new Unary2Op(L2D, convertedDoubleReg, convertedDoubleReg));
+                return convertedDoubleReg;
+            }
             case D2I: {
                 AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Float), D2I, input);
                 AllocatableValue convertedIntReg = newVariable(LIRKind.derive(convertedFloatReg).changeType(Kind.Int));
-                emitMove(convertedIntReg, convertedFloatReg);
+                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
                 return convertedIntReg;
             }
             case F2L: {
                 AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Double), F2L, input);
                 AllocatableValue convertedLongReg = newVariable(LIRKind.derive(convertedDoubleReg).changeType(Kind.Long));
-                emitMove(convertedLongReg, convertedDoubleReg);
+                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
                 return convertedLongReg;
             }
             case F2I: {
                 AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Float), F2I, input);
                 AllocatableValue convertedIntReg = newVariable(LIRKind.derive(convertedFloatReg).changeType(Kind.Int));
-                emitMove(convertedIntReg, convertedFloatReg);
+                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
                 return convertedIntReg;
             }
             case D2L: {
                 AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.derive(input).changeType(Kind.Double), D2L, input);
                 AllocatableValue convertedLongReg = newVariable(LIRKind.derive(convertedDoubleReg).changeType(Kind.Long));
-                emitMove(convertedLongReg, convertedDoubleReg);
+                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
                 return convertedLongReg;
             }
-            case I2D: {
-                AllocatableValue tmp = emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), I2L, input);
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), L2D, tmp);
-            }
             case L2F: {
-                AllocatableValue tmp = emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), L2D, input);
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), D2F, tmp);
+                // long -> double -> float see above
+                AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double));
+                moveBetweenFpGp(convertedDoubleReg, input);
+                AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float));
+                append(new Unary2Op(L2F, convertedFloatReg, convertedDoubleReg));
+                return convertedFloatReg;
             }
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
+    private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) {
+// boolean isVis3 = getArchitecture().features.contains(CPUFeature.VIS3);
+// if (isVis3) {
+//
+// } else {
+        StackSlot tempSlot = getTempSlot(LIRKind.derive(dst));
+        append(new MoveFpGp(dst, src, tempSlot));
+// }
+    }
+
+    private StackSlot getTempSlot(LIRKind kind) {
+        return getResult().getFrameMap().allocateSpillSlot(kind);
+    }
+
+    protected SPARC getArchitecture() {
+        return (SPARC) target().arch;
+    }
+
     @Override
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
@@ -954,35 +963,39 @@
     public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
         Kind from = inputVal.getKind();
         AllocatableValue input = asAllocatable(inputVal);
-
+        Variable result = newVariable(to);
         // These cases require a move between CPU and FPU registers:
         switch ((Kind) to.getPlatformKind()) {
             case Int:
                 switch (from) {
                     case Float:
                     case Double:
-                        return emitConvert2Op(to, MOV_F2I, input);
+                        moveBetweenFpGp(result, input);
+                        return result;
                 }
                 break;
             case Long:
                 switch (from) {
                     case Float:
                     case Double:
-                        return emitConvert2Op(to, MOV_D2L, input);
+                        moveBetweenFpGp(result, input);
+                        return result;
                 }
                 break;
             case Float:
                 switch (from) {
                     case Int:
                     case Long:
-                        return emitConvert2Op(to, MOV_I2F, input);
+                        moveBetweenFpGp(result, input);
+                        return result;
                 }
                 break;
             case Double:
                 switch (from) {
                     case Int:
                     case Long:
-                        return emitConvert2Op(to, MOV_L2D, input);
+                        moveBetweenFpGp(result, input);
+                        return result;
                 }
                 break;
         }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Sep 09 12:09:58 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
@@ -30,24 +32,25 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.sparc.*;
+import com.oracle.graal.sparc.SPARC.*;
 
 @ServiceProvider(HotSpotBackendFactory.class)
 public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory {
 
-    protected static Architecture createArchitecture() {
-        return new SPARC();
+    protected Architecture createArchitecture(HotSpotVMConfig config) {
+        return new SPARC(computeFeatures(config));
     }
 
-    protected TargetDescription createTarget() {
+    protected TargetDescription createTarget(HotSpotVMConfig config) {
         final int stackFrameAlignment = 16;
         final int implicitNullCheckLimit = 4096;
         final boolean inlineObjects = true;
-        return new HotSpotTargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
+        return new HotSpotTargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
     }
 
     public HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend host) {
         assert host == null;
-        TargetDescription target = createTarget();
+        TargetDescription target = createTarget(runtime.getConfig());
 
         HotSpotRegistersProvider registers = createRegisters();
         HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime);
@@ -71,6 +74,20 @@
         return new SPARCHotSpotBackend(runtime, providers);
     }
 
+    protected Set<CPUFeature> computeFeatures(HotSpotVMConfig config) {
+        Set<CPUFeature> features = EnumSet.noneOf(CPUFeature.class);
+        if (config.vis1Instructions != 0) {
+            features.add(CPUFeature.VIS1);
+        }
+        if (config.vis2Instructions != 0) {
+            features.add(CPUFeature.VIS2);
+        }
+        if (config.vis3Instructions != 0) {
+            features.add(CPUFeature.VIS3);
+        }
+        return features;
+    }
+
     protected HotSpotRegistersProvider createRegisters() {
         return new HotSpotRegisters(SPARC.g2, SPARC.g6, SPARC.sp);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Sep 09 12:09:58 2014 -0700
@@ -793,6 +793,12 @@
     @HotSpotVMConstant(name = "VM_Version::CPU_ERMS", archs = {"amd64"}) @Stable public int cpuERMS;
     @HotSpotVMConstant(name = "VM_Version::CPU_CLMUL", archs = {"amd64"}) @Stable public int cpuCLMUL;
 
+    // SPARC specific values
+    @HotSpotVMField(name = "VM_Version::_features", type = "int", get = HotSpotVMField.Type.VALUE, archs = {"sparc"}) @Stable public int sparcFeatures;
+    @HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int vis3Instructions;
+    @HotSpotVMConstant(name = "VM_Version::vis2_instructions_m", archs = {"sparc"}) @Stable public int vis2Instructions;
+    @HotSpotVMConstant(name = "VM_Version::vis1_instructions_m", archs = {"sparc"}) @Stable public int vis1Instructions;
+
     // offsets, ...
     @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages;
     @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Sep 09 12:09:58 2014 -0700
@@ -47,8 +47,7 @@
     L2I, B2I, S2I, B2L, S2L, I2L,
     F2D, D2F,
     I2F, I2D, F2I, D2I,
-    L2F, L2D, F2L, D2L,
-    MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
+    L2F, L2D, F2L, D2L;
     // @formatter:on
 
     /**
@@ -72,50 +71,6 @@
         }
     }
 
-    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(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            emitUnary(crb, masm, opcode, result, x, null);
-        }
-    }
-
-    public static class Op2Stack extends SPARCLIRInstruction {
-
-        @Opcode private final SPARCArithmetic opcode;
-        @Def({REG}) protected Value result;
-        @Use({REG, CONST}) protected Value x;
-        @Alive({REG, CONST}) protected Value y;
-
-        public Op2Stack(SPARCArithmetic opcode, Value result, Value x, Value y) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            emit(crb, masm, opcode, result, x, y, null);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
     /**
      * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand must be a register.
@@ -124,8 +79,8 @@
 
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG}) protected Value result;
-        @Use({REG, CONST}) protected Value x;
-        @Alive({REG, CONST}) protected Value y;
+        @Use({REG}) protected Value x;
+        @Alive({REG}) protected Value y;
         @State LIRFrameState state;
 
         public BinaryRegReg(SPARCArithmetic opcode, Value result, Value x, Value y) {
@@ -187,41 +142,6 @@
         }
     }
 
-    /**
-     * Commutative binary operation with two operands.
-     */
-    public static class BinaryCommutative extends SPARCLIRInstruction {
-
-        @Opcode private final SPARCArithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG}) protected AllocatableValue x;
-        @Use({REG}) protected AllocatableValue y;
-        @State protected LIRFrameState state;
-
-        public BinaryCommutative(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
-            this(opcode, result, x, y, null);
-        }
-
-        public BinaryCommutative(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y, LIRFrameState state) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-            this.state = state;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            emit(crb, masm, opcode, result, x, y, null);
-        }
-
-        @Override
-        protected void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
     public static class ShiftOp extends SPARCLIRInstruction {
 
         @Opcode private final SPARCArithmetic opcode;
@@ -713,14 +633,13 @@
                     new Fdtos(asDoubleReg(src), asFloatReg(dst)).emit(masm);
                     break;
                 case L2D:
-                    if (src.getPlatformKind() == Kind.Long) {
-                        new Movxtod(asLongReg(src), asDoubleReg(dst)).emit(masm);
-                        new Fxtod(asDoubleReg(dst), asDoubleReg(dst)).emit(masm);
-                    } else if (src.getPlatformKind() == Kind.Double) {
-                        new Fxtod(asDoubleReg(src), asDoubleReg(dst)).emit(masm);
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("cannot handle source register " + src.getPlatformKind());
-                    }
+                    new Fxtod(asDoubleReg(src), asDoubleReg(dst)).emit(masm);
+                    break;
+                case L2F:
+                    new Fxtos(asDoubleReg(src), asFloatReg(dst)).emit(masm);
+                    break;
+                case I2D:
+                    new Fitod(asFloatReg(src), asDoubleReg(dst)).emit(masm);
                     break;
                 case I2L:
                     new Signx(asIntReg(src), asLongReg(dst)).emit(masm);
@@ -745,14 +664,7 @@
                     new Sra(asIntReg(dst), 16, asIntReg(dst)).emit(masm);
                     break;
                 case I2F:
-                    if (src.getPlatformKind() == Kind.Int || src.getPlatformKind() == Kind.Char || src.getPlatformKind() == Kind.Short || src.getPlatformKind() == Kind.Byte) {
-                        new Movwtos(asIntReg(src), asFloatReg(dst)).emit(masm);
-                        new Fitos(asFloatReg(dst), asFloatReg(dst)).emit(masm);
-                    } else if (src.getPlatformKind() == Kind.Float) {
-                        new Fitos(asFloatReg(src), asFloatReg(dst)).emit(masm);
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("cannot handle source register " + src.getPlatformKind());
-                    }
+                    new Fitos(asFloatReg(src), asFloatReg(dst)).emit(masm);
                     break;
                 case F2D:
                     new Fstod(asFloatReg(src), asDoubleReg(dst)).emit(masm);
@@ -772,18 +684,18 @@
                     new Fsubs(asFloatReg(dst), asFloatReg(dst), asFloatReg(dst)).emit(masm);
                     masm.bind(notOrdered);
                     break;
-                case MOV_D2L:
-                    new Movdtox(asDoubleReg(src), asLongReg(dst)).emit(masm);
-                    break;
-                case MOV_L2D:
-                    new Movxtod(asLongReg(src), asDoubleReg(dst)).emit(masm);
-                    break;
-                case MOV_F2I:
-                    new Movstosw(asFloatReg(src), asIntReg(dst)).emit(masm);
-                    break;
-                case MOV_I2F:
-                    new Movwtos(asIntReg(src), asFloatReg(dst)).emit(masm);
-                    break;
+// case MOV_D2L:
+// new Movdtox(asDoubleReg(src), asLongReg(dst)).emit(masm);
+// break;
+// case MOV_L2D:
+// new Movxtod(asLongReg(src), asDoubleReg(dst)).emit(masm);
+// break;
+// case MOV_F2I:
+// new Movstosw(asFloatReg(src), asIntReg(dst)).emit(masm);
+// break;
+// case MOV_I2F:
+// new Movwtos(asIntReg(src), asFloatReg(dst)).emit(masm);
+// break;
                 case D2L:
                     new Fcmp(CC.Fcc0, Opfs.Fcmpd, asDoubleReg(src), asDoubleReg(src)).emit(masm);
                     new Fbo(false, notOrdered).emit(masm);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Sep 09 12:09:58 2014 -0700
@@ -96,6 +96,74 @@
         }
     }
 
+    /**
+     * Move between floating-point and general purpose register domain (WITHOUT VIS3)
+     */
+    @Opcode("MOVE")
+    public static class MoveFpGp extends SPARCLIRInstruction implements MoveOp {
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Use({STACK}) protected StackSlot temp;
+
+        public MoveFpGp(AllocatableValue result, AllocatableValue input, StackSlot temp) {
+            super();
+            this.result = result;
+            this.input = input;
+            this.temp = temp;
+        }
+
+        public Value getInput() {
+            return input;
+        }
+
+        public AllocatableValue getResult() {
+            return result;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            PlatformKind inputKind = input.getPlatformKind();
+            PlatformKind resultKind = result.getPlatformKind();
+            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                Register scratch = sc.getRegister();
+                SPARCAddress tempAddress = guaranueeLoadable((SPARCAddress) crb.asAddress(temp), masm, scratch);
+                if (inputKind == Kind.Float) {
+                    new Stf(asFloatReg(input), tempAddress).emit(masm);
+                } else if (inputKind == Kind.Double) {
+                    new Stdf(asDoubleReg(input), tempAddress).emit(masm);
+                } else if (inputKind == Kind.Int) {
+                    new Stw(asIntReg(input), tempAddress).emit(masm);
+                } else if (inputKind == Kind.Short || inputKind == Kind.Char) {
+                    new Sth(asIntReg(input), tempAddress).emit(masm);
+                } else if (inputKind == Kind.Byte) {
+                    new Stb(asIntReg(input), tempAddress).emit(masm);
+                } else if (inputKind == Kind.Long) {
+                    new Stx(asLongReg(input), tempAddress).emit(masm);
+                } else {
+                    GraalInternalError.shouldNotReachHere();
+                }
+                if (resultKind == Kind.Int) {
+                    new Ldsw(tempAddress, asIntReg(result)).emit(masm);
+                } else if (inputKind == Kind.Short) {
+                    new Ldsh(tempAddress, asIntReg(input)).emit(masm);
+                } else if (inputKind == Kind.Char) {
+                    new Lduh(tempAddress, asIntReg(input)).emit(masm);
+                } else if (inputKind == Kind.Byte) {
+                    new Ldsb(tempAddress, asIntReg(input)).emit(masm);
+                } else if (resultKind == Kind.Float) {
+                    new Ldf(tempAddress, asFloatReg(result)).emit(masm);
+                } else if (resultKind == Kind.Long) {
+                    new Ldx(tempAddress, asLongReg(result)).emit(masm);
+                } else if (resultKind == Kind.Double) {
+                    new Lddf(tempAddress, asDoubleReg(result)).emit(masm);
+                } else {
+                    GraalInternalError.shouldNotReachHere();
+                }
+            }
+        }
+    }
+
     public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck {
 
         protected final Kind kind;
@@ -408,18 +476,23 @@
                 throw GraalInternalError.shouldNotReachHere();
             }
         } else if (isConstant(input)) {
+            Constant constant = asConstant(input);
             if (isRegister(result)) {
-                const2reg(crb, masm, result, (Constant) input);
+                const2reg(crb, masm, result, constant);
             } else if (isStackSlot(result)) {
-                try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
-                    Register scratch = sc.getRegister();
-                    Constant constant = asConstant(input);
-                    if (constant.isNull()) {
-                        new Clr(scratch).emit(masm);
-                    } else {
-                        new Setx(constant.asLong(), scratch).emit(masm);
+                if (constant.isDefaultForKind() || constant.isNull()) {
+                    reg2stack(crb, masm, result, g0.asValue(LIRKind.derive(input)));
+                } else {
+                    try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                        Register scratch = sc.getRegister();
+                        long value = constant.asLong();
+                        if (isSimm13(value)) {
+                            new Or(g0, (int) value, scratch).emit(masm);
+                        } else {
+                            new Setx(value, scratch).emit(masm);
+                        }
+                        reg2stack(crb, masm, result, scratch.asValue(LIRKind.derive(input)));
                     }
-                    reg2stack(crb, masm, result, scratch.asValue(LIRKind.derive(input)));
                 }
             } else {
                 throw GraalInternalError.shouldNotReachHere("Result is a: " + result);
@@ -432,10 +505,7 @@
     private static void reg2reg(SPARCAssembler masm, Value result, Value input) {
         final Register src = asRegister(input);
         final Register dst = asRegister(result);
-        // implicit conversions between double and float registers can happen in the "same Register"
-        // f0->d0
-        boolean isFloatToDoubleConversion = result.getKind() == Kind.Double && input.getKind() == Kind.Float;
-        if (src.equals(dst) && !isFloatToDoubleConversion) {
+        if (src.equals(dst)) {
             return;
         }
         switch (input.getKind()) {
@@ -449,30 +519,17 @@
                 new Mov(src, dst).emit(masm);
                 break;
             case Float:
-                switch (result.getKind()) {
-                    case Long:
-                        new Movstosw(src, dst).emit(masm);
-                        break;
-                    case Int:
-                        new Movstouw(src, dst).emit(masm);
-                        break;
-                    case Float:
-                        new Fmovs(src, dst).emit(masm);
-                        break;
-                    case Double:
-                        new Fstod(src, dst).emit(masm);
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
+                if (result.getPlatformKind() == Kind.Float) {
+                    new Fmovs(src, dst).emit(masm);
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
                 }
                 break;
             case Double:
-                if (result.getPlatformKind() == Kind.Long) {
-                    new Movdtox(src, dst).emit(masm);
-                } else if (result.getPlatformKind() == Kind.Int) {
-                    new Movstouw(src, dst).emit(masm);
+                if (result.getPlatformKind() == Kind.Double) {
+                    new Fmovd(src, dst).emit(masm);
                 } else {
-                    new Fmovd(src, dst).emit(masm);
+                    throw GraalInternalError.shouldNotReachHere();
                 }
                 break;
             default:
@@ -574,10 +631,22 @@
             Register scratch = sc.getRegister();
             switch (input.getKind().getStackKind()) {
                 case Int:
-                    new Setx(input.asLong(), asIntReg(result)).emit(masm);
+                    if (input.isDefaultForKind()) {
+                        new Clr(asIntReg(result)).emit(masm);
+                    } else if (isSimm13(input.asLong())) {
+                        new Or(g0, input.asInt(), asIntReg(result)).emit(masm);
+                    } else {
+                        new Setx(input.asLong(), asIntReg(result)).emit(masm);
+                    }
                     break;
                 case Long:
-                    new Setx(input.asLong(), asLongReg(result)).emit(masm);
+                    if (input.isDefaultForKind()) {
+                        new Clr(asLongReg(result)).emit(masm);
+                    } else if (isSimm13(input.asLong())) {
+                        new Or(g0, input.asInt(), asLongReg(result)).emit(masm);
+                    } else {
+                        new Setx(input.asLong(), asLongReg(result)).emit(masm);
+                    }
                     break;
                 case Float:
                     // TODO: Handle it the same way, as in the double case with Movwtos
@@ -591,9 +660,15 @@
                     // instead loading this from memory and do the complicated lookup,
                     // just load it directly into a scratch register
                     // First load the address into the scratch register
-                    new Setx(Double.doubleToLongBits(input.asDouble()), scratch, true).emit(masm);
+                    // new Setx(Double.doubleToLongBits(input.asDouble()), scratch,
+                    // true).emit(masm);
                     // Now load the float value
-                    new Movxtod(scratch, asDoubleReg(result)).emit(masm);
+                    // new Movxtod(scratch, asDoubleReg(result)).emit(masm);
+                    crb.asDoubleConstRef(input);
+                    // First load the address into the scratch register
+                    new Setx(0, scratch, true).emit(masm);
+                    // Now load the float value
+                    new Lddf(scratch, asDoubleReg(result)).emit(masm);
                     break;
                 case Object:
                     if (input.isNull()) {
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Tue Sep 09 12:09:58 2014 -0700
@@ -27,8 +27,11 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf;
 import com.oracle.graal.asm.sparc.SPARCAssembler.Movxtod;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
@@ -75,12 +78,20 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Can be used with VIS3
+        // new Movxtod(SPARC.i0, RETURN_REGISTER_STORAGE).emit(masm);
+        // We abuse the first stackslot for transferring i0 to return_register_storage
+        // assert slots.length >= 1;
+        SPARCAddress slot0Address = (SPARCAddress) crb.asAddress(slots[0]);
+        new Stx(SPARC.i0, slot0Address).emit(masm);
+        new Lddf(slot0Address, RETURN_REGISTER_STORAGE).emit(masm);
+
+        // Now save the registers
         for (int i = 0; i < savedRegisters.length; i++) {
             if (savedRegisters[i] != null) {
                 saveRegister(crb, masm, slots[i], savedRegisters[i]);
             }
         }
-        new Movxtod(SPARC.i0, RETURN_REGISTER_STORAGE).emit(masm);
     }
 
     public StackSlot[] getSlots() {
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Fri Sep 05 18:28:11 2014 -0700
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Sep 09 12:09:58 2014 -0700
@@ -25,6 +25,7 @@
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 
 import java.nio.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.Register.RegisterCategory;
@@ -222,8 +223,11 @@
      */
     public static final int MEMORY_ACCESS_ALIGN = 4;
 
-    public SPARC() {
+    public final Set<CPUFeature> features;
+
+    public SPARC(Set<CPUFeature> features) {
         super("SPARC", 8, ByteOrder.BIG_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 1, r31.encoding + FLOAT_REGISTER_COUNT + 1, 8);
+        this.features = features;
     }
 
     @Override
@@ -282,4 +286,14 @@
     public static boolean isDoubleFloatRegister(Register r) {
         return r.name.startsWith("d");
     }
+
+    public Set<CPUFeature> getFeatures() {
+        return features;
+    }
+
+    public enum CPUFeature {
+        VIS1,
+        VIS2,
+        VIS3
+    }
 }