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