1 /*
   2  * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 
  26 package org.graalvm.compiler.core.sparc;
  27 
  28 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add;
  29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc;
  30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And;
  31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx;
  32 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx;
  33 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx;
  34 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra;
  35 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax;
  36 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl;
  37 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub;
  38 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
  39 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx;
  40 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor;
  41 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd;
  42 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds;
  43 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos;
  44 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod;
  45 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos;
  46 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld;
  47 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls;
  48 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd;
  49 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs;
  50 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod;
  51 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod;
  52 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi;
  53 import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM;
  54 import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM;
  55 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
  56 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  57 import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF;
  58 import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR;
  59 import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR;
  60 import static jdk.vm.ci.code.CodeUtil.mask;
  61 import static jdk.vm.ci.meta.JavaConstant.forLong;
  62 import static jdk.vm.ci.sparc.SPARC.g0;
  63 import static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
  64 import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
  65 import static jdk.vm.ci.sparc.SPARCKind.WORD;
  66 import static jdk.vm.ci.sparc.SPARCKind.XWORD;
  67 
  68 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
  69 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
  70 import org.graalvm.compiler.core.common.LIRKind;
  71 import org.graalvm.compiler.core.common.calc.FloatConvert;
  72 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  73 import org.graalvm.compiler.debug.GraalError;
  74 import org.graalvm.compiler.lir.ConstantValue;
  75 import org.graalvm.compiler.lir.LIRFrameState;
  76 import org.graalvm.compiler.lir.Variable;
  77 import org.graalvm.compiler.lir.VirtualStackSlot;
  78 import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
  79 import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
  80 import org.graalvm.compiler.lir.sparc.SPARCArithmetic;
  81 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp;
  82 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp;
  83 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh;
  84 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp;
  85 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem;
  86 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp;
  87 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp;
  88 import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp;
  89 import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
  90 import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp;
  91 import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp;
  92 import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp;
  93 import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
  94 import org.graalvm.compiler.lir.sparc.SPARCOPFOp;
  95 
  96 import jdk.vm.ci.meta.AllocatableValue;
  97 import jdk.vm.ci.meta.JavaConstant;
  98 import jdk.vm.ci.meta.PlatformKind;
  99 import jdk.vm.ci.meta.Value;
 100 import jdk.vm.ci.meta.ValueKind;
 101 import jdk.vm.ci.sparc.SPARC;
 102 import jdk.vm.ci.sparc.SPARC.CPUFeature;
 103 import jdk.vm.ci.sparc.SPARCKind;
 104 
 105 /**
 106  * This class implements the SPARC specific portion of the LIR generator.
 107  */
 108 public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
 109 
 110     @Override
 111     public SPARCLIRGenerator getLIRGen() {
 112         return (SPARCLIRGenerator) super.getLIRGen();
 113     }
 114 
 115     @Override
 116     public Variable emitBitCount(Value operand) {
 117         Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
 118         AllocatableValue usedOperand = asAllocatable(emitZeroExtend(operand));
 119         getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result));
 120         return result;
 121     }
 122 
 123     @Override
 124     public Variable emitBitScanForward(Value operand) {
 125         Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
 126         getLIRGen().append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), getLIRGen()));
 127         return result;
 128     }
 129 
 130     @Override
 131     public Variable emitBitScanReverse(Value operand) {
 132         Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
 133         if (operand.getPlatformKind() == SPARCKind.XWORD) {
 134             getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, asAllocatable(operand), getLIRGen()));
 135         } else {
 136             getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), getLIRGen()));
 137         }
 138         return result;
 139     }
 140 
 141     @Override
 142     public Value emitMathAbs(Value inputValue) {
 143         Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
 144         SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
 145         Opfs opf;
 146         switch (kind) {
 147             case SINGLE:
 148                 opf = Opfs.Fabss;
 149                 break;
 150             case DOUBLE:
 151                 opf = Opfs.Fabsd;
 152                 break;
 153             default:
 154                 throw GraalError.shouldNotReachHere("Input kind: " + kind);
 155         }
 156         getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result));
 157         return result;
 158     }
 159 
 160     @Override
 161     public Value emitMathSqrt(Value inputValue) {
 162         Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
 163         SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
 164         Opfs opf;
 165         switch (kind) {
 166             case SINGLE:
 167                 opf = Opfs.Fsqrts;
 168                 break;
 169             case DOUBLE:
 170                 opf = Opfs.Fsqrtd;
 171                 break;
 172             default:
 173                 throw GraalError.shouldNotReachHere("Input kind: " + kind);
 174         }
 175         getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result));
 176         return result;
 177     }
 178 
 179     @Override
 180     public Value emitNegate(Value input) {
 181         PlatformKind inputKind = input.getPlatformKind();
 182         if (isNumericInteger(inputKind)) {
 183             return emitUnary(Sub, input);
 184         } else {
 185             return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input);
 186         }
 187     }
 188 
 189     @Override
 190     public Value emitNot(Value input) {
 191         return emitUnary(Xnor, input);
 192     }
 193 
 194     private Variable emitUnary(Opfs opf, Value inputValue) {
 195         Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
 196         getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result));
 197         return result;
 198     }
 199 
 200     private Variable emitUnary(Op3s op3, Value input) {
 201         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
 202         getLIRGen().append(SPARCOP3Op.newUnary(op3, getLIRGen().loadSimm13(input), result));
 203         return result;
 204     }
 205 
 206     private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b) {
 207         return emitBinary(resultKind, opf, a, b, null);
 208     }
 209 
 210     private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) {
 211         Variable result = getLIRGen().newVariable(resultKind);
 212         getLIRGen().append(new SPARCOPFOp(opf, asAllocatable(a), asAllocatable(b), result, state));
 213         return result;
 214     }
 215 
 216     private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, int b) {
 217         return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b)));
 218     }
 219 
 220     private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b) {
 221         return emitBinary(resultKind, op3, a, b, null);
 222     }
 223 
 224     private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b, LIRFrameState state) {
 225         Variable result = getLIRGen().newVariable(resultKind);
 226         if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
 227             getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), getLIRGen().loadSimm13(a), result, state));
 228         } else {
 229             getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), getLIRGen().loadSimm13(b), result, state));
 230         }
 231         return result;
 232     }
 233 
 234     @Override
 235     protected boolean isNumericInteger(PlatformKind kind) {
 236         return ((SPARCKind) kind).isInteger();
 237     }
 238 
 239     @Override
 240     public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
 241         if (isNumericInteger(a.getPlatformKind())) {
 242             return emitBinary(resultKind, setFlags ? Addcc : Add, a, b);
 243         } else {
 244             boolean isDouble = a.getPlatformKind().equals(DOUBLE);
 245             return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b);
 246         }
 247     }
 248 
 249     @Override
 250     public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
 251         if (isNumericInteger(a.getPlatformKind())) {
 252             return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b);
 253         } else {
 254             boolean isDouble = a.getPlatformKind().equals(DOUBLE);
 255             return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b);
 256         }
 257     }
 258 
 259     @Override
 260     public Variable emitMul(Value a, Value b, boolean setFlags) {
 261         LIRKind resultKind = LIRKind.combine(a, b);
 262         PlatformKind aKind = a.getPlatformKind();
 263         if (isNumericInteger(aKind)) {
 264             if (setFlags) {
 265                 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
 266                 if (aKind == XWORD) {
 267                     getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen()));
 268                 } else if (aKind == WORD) {
 269                     getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b)));
 270                 } else {
 271                     throw GraalError.shouldNotReachHere();
 272                 }
 273                 return result;
 274             } else {
 275                 return emitBinary(resultKind, Op3s.Mulx, a, b);
 276             }
 277         } else {
 278             boolean isDouble = a.getPlatformKind().equals(DOUBLE);
 279             return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b);
 280         }
 281     }
 282 
 283     @Override
 284     public Value emitMulHigh(Value a, Value b) {
 285         MulHigh opcode;
 286         switch (((SPARCKind) a.getPlatformKind())) {
 287             case WORD:
 288                 opcode = MulHigh.IMUL;
 289                 break;
 290             case XWORD:
 291                 opcode = MulHigh.LMUL;
 292                 break;
 293             default:
 294                 throw GraalError.shouldNotReachHere();
 295         }
 296         return emitMulHigh(opcode, a, b);
 297     }
 298 
 299     @Override
 300     public Value emitUMulHigh(Value a, Value b) {
 301         switch (((SPARCKind) a.getPlatformKind())) {
 302             case WORD:
 303                 Value result = emitBinary(LIRKind.combine(a, b), Mulx, emitZeroExtend(a), emitZeroExtend(b));
 304                 return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits());
 305             case XWORD:
 306                 return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b);
 307             default:
 308                 throw GraalError.shouldNotReachHere();
 309         }
 310     }
 311 
 312     private Value emitMulHigh(MulHigh opcode, Value a, Value b) {
 313         Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
 314         MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b)));
 315         getLIRGen().append(mulHigh);
 316         return result;
 317     }
 318 
 319     @Override
 320     public Value emitDiv(Value a, Value b, LIRFrameState state) {
 321         LIRKind resultKind = LIRKind.combine(a, b);
 322         if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero
 323             Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD));
 324             return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state);
 325         } else if (isNumericInteger(a.getPlatformKind())) {
 326             return emitBinary(resultKind, Op3s.Sdivx, emitSignExtend(a), emitSignExtend(b), state);
 327         } else {
 328             boolean isDouble = a.getPlatformKind() == DOUBLE;
 329             return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state);
 330         }
 331     }
 332 
 333     @Override
 334     public Value emitRem(Value a, Value b, LIRFrameState state) {
 335         Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
 336         Variable q1; // Intermediate values
 337         Variable q2;
 338         switch ((SPARCKind) a.getPlatformKind()) {
 339             case WORD:
 340                 // Sign extend a and b
 341                 Value as = emitSignExtend(a);
 342                 Value bs = emitSignExtend(b);
 343                 q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state);
 344                 q2 = emitBinary(as.getValueKind(), Mulx, q1, bs);
 345                 result = emitSub(as, q2, false);
 346                 break;
 347             case XWORD:
 348                 q1 = emitBinary(result.getValueKind(), Sdivx, a, b, state);
 349                 q2 = emitBinary(result.getValueKind(), Mulx, q1, b);
 350                 result = emitSub(a, q2, false);
 351                 break;
 352             case SINGLE:
 353                 ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM);
 354                 result = getLIRGen().emitForeignCall(fremCall, state, a, b);
 355                 break;
 356             case DOUBLE:
 357                 ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM);
 358                 result = getLIRGen().emitForeignCall(dremCall, state, a, b);
 359                 break;
 360             default:
 361                 throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind());
 362         }
 363         return result;
 364     }
 365 
 366     @Override
 367     public Value emitURem(Value a, Value b, LIRFrameState state) {
 368         Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
 369         Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b));
 370         Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b));
 371         Rem opcode;
 372         switch (((SPARCKind) a.getPlatformKind())) {
 373             case WORD:
 374                 opcode = Rem.IUREM;
 375                 break;
 376             case XWORD:
 377                 opcode = Rem.LUREM;
 378                 break;
 379             default:
 380                 throw GraalError.shouldNotReachHere();
 381         }
 382         getLIRGen().append(new RemOp(opcode, result, asAllocatable(a), asAllocatable(b), scratch1, scratch2, state));
 383         return result;
 384 
 385     }
 386 
 387     @Override
 388     public Value emitUDiv(Value a, Value b, LIRFrameState state) {
 389         return emitBinary(LIRKind.combine(a, b), Udivx, emitZeroExtend(a), emitZeroExtend(b), state);
 390     }
 391 
 392     @Override
 393     public Variable emitAnd(Value a, Value b) {
 394         LIRKind resultKind = LIRKind.combine(a, b);
 395         return emitBinary(resultKind, Op3s.And, a, b);
 396     }
 397 
 398     @Override
 399     public Variable emitOr(Value a, Value b) {
 400         LIRKind resultKind = LIRKind.combine(a, b);
 401         return emitBinary(resultKind, Op3s.Or, a, b);
 402     }
 403 
 404     @Override
 405     public Variable emitXor(Value a, Value b) {
 406         LIRKind resultKind = LIRKind.combine(a, b);
 407         return emitBinary(resultKind, Op3s.Xor, a, b);
 408     }
 409 
 410     @Override
 411     public Variable emitShl(Value a, Value b) {
 412         SPARCKind aKind = (SPARCKind) a.getPlatformKind();
 413         LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
 414         Op3s op;
 415         switch (aKind) {
 416             case WORD:
 417                 op = Op3s.Sll;
 418                 break;
 419             case XWORD:
 420                 op = Op3s.Sllx;
 421                 break;
 422             default:
 423                 throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind));
 424         }
 425         return emitBinary(resultKind, op, a, b);
 426     }
 427 
 428     @Override
 429     public Variable emitShr(Value a, Value b) {
 430         SPARCKind aKind = (SPARCKind) a.getPlatformKind();
 431         LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
 432         Op3s op;
 433         switch (aKind) {
 434             case WORD:
 435                 op = Op3s.Sra;
 436                 break;
 437             case XWORD:
 438                 op = Op3s.Srax;
 439                 break;
 440             default:
 441                 throw GraalError.shouldNotReachHere();
 442         }
 443         return emitBinary(resultKind, op, a, b);
 444     }
 445 
 446     @Override
 447     public Variable emitUShr(Value a, Value b) {
 448         SPARCKind aKind = (SPARCKind) a.getPlatformKind();
 449         LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
 450         Op3s op;
 451         switch (aKind) {
 452             case WORD:
 453                 op = Op3s.Srl;
 454                 break;
 455             case XWORD:
 456                 op = Op3s.Srlx;
 457                 break;
 458             default:
 459                 throw GraalError.shouldNotReachHere();
 460         }
 461         return emitBinary(resultKind, op, a, b);
 462     }
 463 
 464     private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) {
 465         Variable result = getLIRGen().newVariable(kind);
 466         getLIRGen().emitMove(result, input);
 467         return result;
 468     }
 469 
 470     @Override
 471     public Value emitFloatConvert(FloatConvert op, Value inputValue) {
 472         AllocatableValue inputAllocatable = asAllocatable(inputValue);
 473         AllocatableValue result;
 474         switch (op) {
 475             case D2F:
 476                 result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE));
 477                 getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result));
 478                 break;
 479             case F2D:
 480                 result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE));
 481                 getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result));
 482                 break;
 483             case I2F: {
 484                 AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
 485                 result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind());
 486                 moveBetweenFpGp(intEncodedFloatReg, inputAllocatable);
 487                 getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result));
 488                 break;
 489             }
 490             case I2D: {
 491                 // Unfortunately we must do int -> float -> double because fitod has float
 492                 // and double encoding in one instruction
 493                 AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
 494                 result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
 495                 moveBetweenFpGp(convertedFloatReg, inputAllocatable);
 496                 getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result));
 497                 break;
 498             }
 499             case L2D: {
 500                 AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
 501                 moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable);
 502                 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind());
 503                 getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg));
 504                 result = convertedDoubleReg;
 505                 break;
 506             }
 507             case D2I: {
 508                 AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
 509                 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg));
 510                 AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
 511                 moveBetweenFpGp(convertedIntReg, convertedFloatReg);
 512                 result = convertedIntReg;
 513                 break;
 514             }
 515             case F2L: {
 516                 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
 517                 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg));
 518                 AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
 519                 moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
 520                 result = convertedLongReg;
 521                 break;
 522             }
 523             case F2I: {
 524                 AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
 525                 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg));
 526                 AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
 527                 moveBetweenFpGp(convertedIntReg, convertedFloatReg);
 528                 result = convertedIntReg;
 529                 break;
 530             }
 531             case D2L: {
 532                 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
 533                 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg));
 534                 AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
 535                 moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
 536                 result = convertedLongReg;
 537                 break;
 538             }
 539             case L2F: {
 540                 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
 541                 result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
 542                 moveBetweenFpGp(convertedDoubleReg, inputAllocatable);
 543                 getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result));
 544                 break;
 545             }
 546             default:
 547                 throw GraalError.shouldNotReachHere();
 548         }
 549         return result;
 550     }
 551 
 552     protected VirtualStackSlot getTempSlot(LIRKind kind) {
 553         return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind);
 554     }
 555 
 556     private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) {
 557         AllocatableValue tempSlot;
 558         PlatformKind dstKind = dst.getPlatformKind();
 559         PlatformKind srcKind = src.getPlatformKind();
 560         if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) {
 561             tempSlot = AllocatableValue.ILLEGAL;
 562         } else {
 563             tempSlot = getTempSlot(LIRKind.value(XWORD));
 564         }
 565         getLIRGen().append(new MoveFpGp(dst, src, tempSlot));
 566     }
 567 
 568     @Override
 569     public Value emitNarrow(Value inputVal, int bits) {
 570         if (inputVal.getPlatformKind() == XWORD && bits <= 32) {
 571             LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD);
 572             Variable result = getLIRGen().newVariable(resultKind);
 573             getLIRGen().emitMove(result, inputVal);
 574             return result;
 575         } else {
 576             return inputVal;
 577         }
 578     }
 579 
 580     private Value emitSignExtend(Value inputValue) {
 581         int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8;
 582         return emitNarrow(emitSignExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits);
 583     }
 584 
 585     @Override
 586     public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
 587         assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
 588         LIRKind shiftKind = LIRKind.value(WORD);
 589         LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD);
 590         int shiftCount = XWORD.getSizeInBits() - fromBits;
 591         if (fromBits == toBits) {
 592             return inputVal;
 593         } else if (isJavaConstant(inputVal)) {
 594             JavaConstant javaConstant = asJavaConstant(inputVal);
 595             long constant;
 596             if (javaConstant.isNull()) {
 597                 constant = 0;
 598             } else {
 599                 constant = javaConstant.asLong();
 600             }
 601             return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
 602         } else {
 603             AllocatableValue inputAllocatable = asAllocatable(inputVal);
 604             Variable result = getLIRGen().newVariable(resultKind);
 605             if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
 606                 getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result));
 607             } else {
 608                 Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
 609                 getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
 610                 getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
 611             }
 612             return result;
 613         }
 614     }
 615 
 616     private Value emitZeroExtend(Value inputValue) {
 617         int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8;
 618         return emitNarrow(emitZeroExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits);
 619     }
 620 
 621     @Override
 622     public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) {
 623         assert fromBits <= toBits && toBits <= 64;
 624         if (fromBits == toBits) {
 625             return inputValue;
 626         }
 627         Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
 628         AllocatableValue inputAllocatable = asAllocatable(inputValue);
 629         if (fromBits == 32) {
 630             getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result));
 631         } else {
 632             Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits)));
 633             getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, mask, result));
 634         }
 635         return result;
 636     }
 637 
 638     @Override
 639     public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
 640         SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind();
 641         SPARCKind toKind = (SPARCKind) to.getPlatformKind();
 642         AllocatableValue input = asAllocatable(inputVal);
 643         Variable result = getLIRGen().newVariable(to);
 644         // These cases require a move between CPU and FPU registers:
 645         if (fromKind.isFloat() != toKind.isFloat()) {
 646             moveBetweenFpGp(result, input);
 647             return result;
 648         } else {
 649             // Otherwise, just emit an ordinary move instruction.
 650             // Instructions that move or generate 32-bit register values also set the upper 32
 651             // bits of the register to zero.
 652             // Consequently, there is no need for a special zero-extension move.
 653             return emitConvertMove(to, input);
 654         }
 655     }
 656 
 657     @Override
 658     public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
 659         SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address);
 660         Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
 661         getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
 662         return result;
 663     }
 664 
 665     @Override
 666     public void emitStore(ValueKind<?> kind, Value address, Value inputVal, LIRFrameState state) {
 667         SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address);
 668         if (isJavaConstant(inputVal)) {
 669             JavaConstant c = asJavaConstant(inputVal);
 670             if (c.isDefaultForKind()) {
 671                 getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state));
 672                 return;
 673             }
 674         }
 675         Variable input = getLIRGen().load(inputVal);
 676         getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state));
 677     }
 678 }