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