1 /*
   2  * Copyright (c) 2009, 2018, 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.FMOVDCC;
  29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVSCC;
  30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MOVICC;
  31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0;
  32 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
  33 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd;
  34 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps;
  35 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
  36 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  37 import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
  38 import static jdk.vm.ci.sparc.SPARCKind.WORD;
  39 import static jdk.vm.ci.sparc.SPARCKind.XWORD;
  40 
  41 import org.graalvm.compiler.asm.sparc.SPARCAssembler;
  42 import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
  43 import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV;
  44 import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
  45 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
  46 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
  47 import org.graalvm.compiler.core.common.LIRKind;
  48 import org.graalvm.compiler.core.common.calc.Condition;
  49 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  50 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  51 import org.graalvm.compiler.debug.GraalError;
  52 import org.graalvm.compiler.lir.LIR;
  53 import org.graalvm.compiler.lir.LIRFrameState;
  54 import org.graalvm.compiler.lir.LIRValueUtil;
  55 import org.graalvm.compiler.lir.LabelRef;
  56 import org.graalvm.compiler.lir.StandardOp.NoOp;
  57 import org.graalvm.compiler.lir.SwitchStrategy;
  58 import org.graalvm.compiler.lir.Variable;
  59 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  60 import org.graalvm.compiler.lir.gen.LIRGenerator;
  61 import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
  62 import org.graalvm.compiler.lir.sparc.SPARCArrayEqualsOp;
  63 import org.graalvm.compiler.lir.sparc.SPARCByteSwapOp;
  64 import org.graalvm.compiler.lir.sparc.SPARCCall;
  65 import org.graalvm.compiler.lir.sparc.SPARCControlFlow;
  66 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.BranchOp;
  67 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.CondMoveOp;
  68 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp;
  69 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp;
  70 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.TableSwitchOp;
  71 import org.graalvm.compiler.lir.sparc.SPARCFloatCompareOp;
  72 import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue;
  73 import org.graalvm.compiler.lir.sparc.SPARCJumpOp;
  74 import org.graalvm.compiler.lir.sparc.SPARCLoadConstantTableBaseOp;
  75 import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
  76 import org.graalvm.compiler.lir.sparc.SPARCMove.MembarOp;
  77 import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp;
  78 import org.graalvm.compiler.lir.sparc.SPARCMove.StackLoadAddressOp;
  79 import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
  80 import org.graalvm.compiler.lir.sparc.SPARCPauseOp;
  81 import org.graalvm.compiler.phases.util.Providers;
  82 
  83 import jdk.vm.ci.meta.AllocatableValue;
  84 import jdk.vm.ci.meta.Constant;
  85 import jdk.vm.ci.meta.JavaConstant;
  86 import jdk.vm.ci.meta.JavaKind;
  87 import jdk.vm.ci.meta.PlatformKind;
  88 import jdk.vm.ci.meta.Value;
  89 import jdk.vm.ci.meta.ValueKind;
  90 import jdk.vm.ci.sparc.SPARC;
  91 import jdk.vm.ci.sparc.SPARCKind;
  92 
  93 /**
  94  * This class implements the SPARC specific portion of the LIR generator.
  95  */
  96 public abstract class SPARCLIRGenerator extends LIRGenerator {
  97 
  98     private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp;
  99     private final ConstantTableBaseProvider constantTableBaseProvider;
 100 
 101     public static final class ConstantTableBaseProvider {
 102         private Variable constantTableBase;
 103         private boolean useConstantTableBase = false;
 104 
 105         public Variable getConstantTableBase() {
 106             useConstantTableBase = true;
 107             return constantTableBase;
 108         }
 109     }
 110 
 111     public SPARCLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes,
 112                     ConstantTableBaseProvider constantTableBaseProvider) {
 113         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
 114         this.constantTableBaseProvider = constantTableBaseProvider;
 115     }
 116 
 117     @Override
 118     protected JavaConstant zapValueForKind(PlatformKind kind) {
 119         long dead = 0xDEADDEADDEADDEADL;
 120         switch ((SPARCKind) kind) {
 121             case BYTE:
 122                 return JavaConstant.forByte((byte) dead);
 123             case HWORD:
 124                 return JavaConstant.forShort((short) dead);
 125             case WORD:
 126                 return JavaConstant.forInt((int) dead);
 127             case XWORD:
 128                 return JavaConstant.forLong(dead);
 129             case SINGLE:
 130             case V32_BYTE:
 131             case V32_HWORD:
 132                 return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
 133             case DOUBLE:
 134             case V64_BYTE:
 135             case V64_HWORD:
 136             case V64_WORD:
 137                 return JavaConstant.forDouble(Double.longBitsToDouble(dead));
 138             default:
 139                 throw new IllegalArgumentException(kind.toString());
 140         }
 141     }
 142 
 143     /**
 144      * The SPARC backend only uses WORD and DWORD values in registers because except to the ld/st
 145      * instructions no instruction deals either with 32 or 64 bits. This function converts small
 146      * integer kinds to WORD.
 147      */
 148     @Override
 149     public <K extends ValueKind<K>> K toRegisterKind(K kind) {
 150         switch ((SPARCKind) kind.getPlatformKind()) {
 151             case BYTE:
 152             case HWORD:
 153                 return kind.changeType(SPARCKind.WORD);
 154             default:
 155                 return kind;
 156         }
 157     }
 158 
 159     public SPARCAddressValue asAddressValue(Value address) {
 160         if (address instanceof SPARCAddressValue) {
 161             return (SPARCAddressValue) address;
 162         } else {
 163             ValueKind<?> kind = address.getValueKind();
 164             if (address instanceof JavaConstant) {
 165                 long displacement = ((JavaConstant) address).asLong();
 166                 if (SPARCAssembler.isSimm13(displacement)) {
 167                     return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement);
 168                 }
 169             }
 170             return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0);
 171         }
 172     }
 173 
 174     @Override
 175     public Variable emitAddress(AllocatableValue stackslot) {
 176         Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
 177         append(new StackLoadAddressOp(result, stackslot));
 178         return result;
 179     }
 180 
 181     @Override
 182     public void emitReturn(JavaKind javaKind, Value input) {
 183         AllocatableValue operand = Value.ILLEGAL;
 184         if (input != null) {
 185             operand = resultOperandFor(javaKind, input.getValueKind());
 186             emitMove(operand, input);
 187         }
 188         append(new ReturnOp(operand));
 189     }
 190 
 191     @Override
 192     public void emitJump(LabelRef label) {
 193         append(new SPARCJumpOp(label));
 194     }
 195 
 196     @Override
 197     public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 198                     double trueDestinationProbability) {
 199         AllocatableValue left;
 200         Value right;
 201         Condition actualCondition;
 202         if (isJavaConstant(x)) {
 203             left = load(y);
 204             right = loadSimm13(x);
 205             actualCondition = cond.mirror();
 206         } else {
 207             left = load(x);
 208             right = loadSimm13(y);
 209             actualCondition = cond;
 210         }
 211         SPARCKind actualCmpKind = (SPARCKind) cmpKind;
 212         if (actualCmpKind.isInteger()) {
 213             assert actualCmpKind.equals(XWORD) || actualCmpKind.equals(WORD) : "SPARC does not support compare of: " + actualCmpKind;
 214             append(new SPARCControlFlow.CompareBranchOp(left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability));
 215         } else if (actualCmpKind.isFloat()) {
 216             emitFloatCompare(actualCmpKind, x, y, Fcc0);
 217             ConditionFlag cf = SPARCControlFlow.fromCondition(false, cond, unorderedIsTrue);
 218             append(new SPARCControlFlow.BranchOp(cf, trueDestination, falseDestination, actualCmpKind, trueDestinationProbability));
 219         } else {
 220             throw GraalError.shouldNotReachHere();
 221         }
 222     }
 223 
 224     @Override
 225     public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) {
 226         SPARCKind cmpKind = (SPARCKind) cmpLIRKind.getPlatformKind();
 227         append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability));
 228     }
 229 
 230     @Override
 231     public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
 232         emitIntegerTest(left, right);
 233         append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, (SPARCKind) left.getPlatformKind(), trueDestinationProbability));
 234     }
 235 
 236     private void emitIntegerTest(Value a, Value b) {
 237         assert ((SPARCKind) a.getPlatformKind()).isInteger();
 238         if (LIRValueUtil.isVariable(b)) {
 239             append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadSimm13(a)));
 240         } else {
 241             append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadSimm13(b)));
 242         }
 243     }
 244 
 245     private Value loadSimm11(Value value) {
 246         if (isJavaConstant(value)) {
 247             JavaConstant c = asJavaConstant(value);
 248             if (c.isNull() || SPARCAssembler.isSimm11(c)) {
 249                 return value;
 250             }
 251         }
 252         return load(value);
 253     }
 254 
 255     public Value loadSimm13(Value value) {
 256         if (isJavaConstant(value)) {
 257             JavaConstant c = asJavaConstant(value);
 258             if (c.isNull() || SPARCAssembler.isSimm13(c)) {
 259                 return value;
 260             }
 261         }
 262         return load(value);
 263     }
 264 
 265     @Override
 266     public Value loadNonConst(Value value) {
 267         // SPARC does not support a proper way of loadNonConst. Please use the appropriate
 268         // loadSimm11 or loadSimm13 variants.
 269         throw GraalError.shouldNotReachHere("This operation is not available for SPARC.");
 270     }
 271 
 272     @Override
 273     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
 274         // Emit compare
 275         SPARCKind cmpSPARCKind = (SPARCKind) cmpKind;
 276         boolean mirrored = emitCompare(cmpSPARCKind, left, right);
 277 
 278         // Emit move
 279         Value actualTrueValue = trueValue;
 280         Value actualFalseValue = falseValue;
 281         SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind();
 282         CMOV cmove;
 283         if (valueKind.isFloat()) {
 284             actualTrueValue = load(trueValue); // Floats cannot be immediate at all
 285             actualFalseValue = load(falseValue);
 286             cmove = valueKind.equals(SINGLE) ? FMOVSCC : FMOVDCC;
 287         } else if (valueKind.isInteger()) {
 288             actualTrueValue = loadSimm11(trueValue);
 289             actualFalseValue = loadSimm11(falseValue);
 290             cmove = MOVICC;
 291         } else {
 292             throw GraalError.shouldNotReachHere();
 293         }
 294         Variable result = newVariable(trueValue.getValueKind());
 295         ConditionFlag finalCondition = SPARCControlFlow.fromCondition(cmpSPARCKind.isInteger(), mirrored ? cond.mirror() : cond, unorderedIsTrue);
 296         CC cc = CC.forKind(cmpSPARCKind);
 297         append(new CondMoveOp(cmove, cc, finalCondition, actualTrueValue, actualFalseValue, result));
 298         return result;
 299     }
 300 
 301     /**
 302      * This method emits the compare instruction, and may reorder the operands. It returns true if
 303      * it did so.
 304      *
 305      * @param cmpKind Kind how a and b have to be compared
 306      * @param a the left operand of the comparison
 307      * @param b the right operand of the comparison
 308      * @return true if the left and right operands were switched, false otherwise
 309      */
 310     protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
 311         boolean mirrored;
 312         if (cmpKind.isInteger()) { // Integer case
 313             mirrored = emitIntegerCompare(cmpKind, a, b);
 314         } else if (cmpKind.isFloat()) { // Float case
 315             mirrored = false; // No mirroring done on floats
 316             emitFloatCompare(cmpKind, a, b, Fcc0);
 317         } else {
 318             throw GraalError.shouldNotReachHere();
 319         }
 320         return mirrored;
 321     }
 322 
 323     private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) {
 324         boolean mirrored;
 325         assert cmpKind.isInteger();
 326         AllocatableValue left;
 327         Value right;
 328         if (LIRValueUtil.isVariable(b)) {
 329             left = load(b);
 330             right = loadSimm13(a);
 331             mirrored = true;
 332         } else {
 333             left = load(a);
 334             right = loadSimm13(b);
 335             mirrored = false;
 336         }
 337         int compareBytes = cmpKind.getSizeInBytes();
 338         // SPARC compares 32 or 64 bits
 339         if (compareBytes < left.getPlatformKind().getSizeInBytes()) {
 340             left = asAllocatable(arithmeticLIRGen.emitSignExtend(left, cmpKind.getSizeInBits(), XWORD.getSizeInBits()));
 341         }
 342         if (compareBytes < right.getPlatformKind().getSizeInBytes()) {
 343             right = arithmeticLIRGen.emitSignExtend(right, cmpKind.getSizeInBits(), XWORD.getSizeInBits());
 344         }
 345         append(SPARCOP3Op.newBinaryVoid(Subcc, left, right));
 346         return mirrored;
 347     }
 348 
 349     private void emitFloatCompare(SPARCKind cmpJavaKind, Value a, Value b, CC cc) {
 350         Opfs floatCompareOpcode;
 351         assert cmpJavaKind.isFloat();
 352         switch (cmpJavaKind) {
 353             case DOUBLE:
 354                 floatCompareOpcode = Fcmpd;
 355                 break;
 356             case SINGLE:
 357                 floatCompareOpcode = Fcmps;
 358                 break;
 359             default:
 360                 throw GraalError.shouldNotReachHere();
 361         }
 362         append(new SPARCFloatCompareOp(floatCompareOpcode, cc, load(a), load(b)));
 363     }
 364 
 365     @Override
 366     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
 367         emitIntegerTest(left, right);
 368         Variable result = newVariable(trueValue.getValueKind());
 369         ConditionFlag flag = SPARCControlFlow.fromCondition(true, Condition.EQ, false);
 370         CC cc = CC.forKind(left.getPlatformKind());
 371         append(new CondMoveOp(MOVICC, cc, flag, loadSimm11(trueValue), loadSimm11(falseValue), result));
 372         return result;
 373     }
 374 
 375     @Override
 376     protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
 377         long maxOffset = linkage.getMaxCallTargetOffset();
 378         if (SPARCAssembler.isWordDisp30(maxOffset)) {
 379             append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
 380         } else {
 381             append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
 382         }
 383     }
 384 
 385     @Override
 386     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
 387         Variable scratchValue = newVariable(key.getValueKind());
 388         AllocatableValue base = AllocatableValue.ILLEGAL;
 389         for (Constant c : strategy.getKeyConstants()) {
 390             if (!getMoveFactory().canInlineConstant(c)) {
 391                 base = constantTableBaseProvider.getConstantTableBase();
 392                 break;
 393             }
 394         }
 395         append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue));
 396     }
 397 
 398     protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
 399         return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
 400     }
 401 
 402     @Override
 403     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
 404         // Making a copy of the switch value is necessary because jump table destroys the input
 405         // value
 406         Variable tmp = newVariable(key.getValueKind());
 407         emitMove(tmp, key);
 408         append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().arch.getWordKind()))));
 409     }
 410 
 411     protected SPARC getArchitecture() {
 412         return (SPARC) target().arch;
 413     }
 414 
 415     @Override
 416     public Variable emitByteSwap(Value input) {
 417         Variable result = newVariable(LIRKind.combine(input));
 418         append(new SPARCByteSwapOp(this, result, asAllocatable(input)));
 419         return result;
 420     }
 421 
 422     @Override
 423     public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers) {
 424         Variable result = newVariable(LIRKind.value(SPARCKind.WORD));
 425         append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length), directPointers));
 426         return result;
 427     }
 428 
 429     @Override
 430     public void emitMembar(int barriers) {
 431         int necessaryBarriers = target().arch.requiredBarriers(barriers);
 432         if (target().isMP && necessaryBarriers != 0) {
 433             append(new MembarOp(necessaryBarriers));
 434         }
 435     }
 436 
 437     @Override
 438     public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
 439         append(new ReturnOp(Value.ILLEGAL));
 440     }
 441 
 442     public Value emitSignExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) {
 443         SPARCAddressValue loadAddress = asAddressValue(address);
 444         Variable result = newVariable(resultKind);
 445         append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state, true));
 446         return result;
 447     }
 448 
 449     public Value emitZeroExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) {
 450         SPARCAddressValue loadAddress = asAddressValue(address);
 451         Variable result = newVariable(resultKind);
 452         append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
 453         return result;
 454     }
 455 
 456     @Override
 457     public void emitNullCheck(Value address, LIRFrameState state) {
 458         PlatformKind kind = address.getPlatformKind();
 459         assert kind == XWORD : address + " - " + kind + " not an object!";
 460         append(new NullCheckOp(asAddressValue(address), state));
 461     }
 462 
 463     public void emitLoadConstantTableBase() {
 464         constantTableBaseProvider.constantTableBase = newVariable(LIRKind.value(XWORD));
 465         int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size();
 466         NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition));
 467         loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBaseProvider.constantTableBase, placeHolder);
 468     }
 469 
 470     @Override
 471     public void beforeRegisterAllocation() {
 472         LIR lir = getResult().getLIR();
 473         loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase);
 474     }
 475 
 476     @Override
 477     public void emitPause() {
 478         append(new SPARCPauseOp());
 479     }
 480 
 481     @Override
 482     public void emitSpeculationFence() {
 483         throw GraalError.unimplemented();
 484     }
 485 }