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