1 /*
   2  * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.hotspot.sparc;
  24 
  25 import static jdk.vm.ci.sparc.SPARCKind.WORD;
  26 import static jdk.vm.ci.sparc.SPARCKind.XWORD;
  27 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
  28 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
  29 
  30 import org.graalvm.compiler.core.common.CompressEncoding;
  31 import org.graalvm.compiler.core.common.LIRKind;
  32 import org.graalvm.compiler.core.common.calc.Condition;
  33 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  34 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  35 import org.graalvm.compiler.core.sparc.SPARCArithmeticLIRGenerator;
  36 import org.graalvm.compiler.core.sparc.SPARCLIRGenerator;
  37 import org.graalvm.compiler.core.sparc.SPARCLIRKindTool;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  40 import org.graalvm.compiler.hotspot.HotSpotBackend;
  41 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
  42 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
  43 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
  44 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
  45 import org.graalvm.compiler.hotspot.HotSpotLockStack;
  46 import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
  47 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  48 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
  49 import org.graalvm.compiler.hotspot.stubs.Stub;
  50 import org.graalvm.compiler.lir.LIRFrameState;
  51 import org.graalvm.compiler.lir.LIRInstruction;
  52 import org.graalvm.compiler.lir.LabelRef;
  53 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
  54 import org.graalvm.compiler.lir.SwitchStrategy;
  55 import org.graalvm.compiler.lir.Variable;
  56 import org.graalvm.compiler.lir.VirtualStackSlot;
  57 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  58 import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
  59 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp;
  60 import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder;
  61 import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue;
  62 import org.graalvm.compiler.lir.sparc.SPARCMove.CompareAndSwapOp;
  63 import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp;
  64 import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp;
  65 import org.graalvm.compiler.lir.sparc.SPARCPrefetchOp;
  66 import org.graalvm.compiler.lir.sparc.SPARCSaveRegistersOp;
  67 
  68 import jdk.vm.ci.code.CallingConvention;
  69 import jdk.vm.ci.code.Register;
  70 import jdk.vm.ci.code.RegisterValue;
  71 import jdk.vm.ci.code.StackSlot;
  72 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
  73 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
  74 import jdk.vm.ci.meta.AllocatableValue;
  75 import jdk.vm.ci.meta.Constant;
  76 import jdk.vm.ci.meta.DeoptimizationAction;
  77 import jdk.vm.ci.meta.DeoptimizationReason;
  78 import jdk.vm.ci.meta.JavaConstant;
  79 import jdk.vm.ci.meta.JavaKind;
  80 import jdk.vm.ci.meta.PlatformKind;
  81 import jdk.vm.ci.meta.Value;
  82 import jdk.vm.ci.meta.ValueKind;
  83 import jdk.vm.ci.sparc.SPARC;
  84 import jdk.vm.ci.sparc.SPARCKind;
  85 
  86 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
  87 
  88     final GraalHotSpotVMConfig config;
  89     private HotSpotDebugInfoBuilder debugInfoBuilder;
  90 
  91     public SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
  92         this(providers, config, lirGenRes, new ConstantTableBaseProvider());
  93     }
  94 
  95     private SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
  96         this(new SPARCLIRKindTool(), new SPARCArithmeticLIRGenerator(), new SPARCHotSpotMoveFactory(constantTableBaseProvider), providers, config, lirGenRes, constantTableBaseProvider);
  97     }
  98 
  99     public SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
 100                     LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
 101         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes, constantTableBaseProvider);
 102         assert config.basicLockSize == 8;
 103         this.config = config;
 104     }
 105 
 106     @Override
 107     public HotSpotProviders getProviders() {
 108         return (HotSpotProviders) super.getProviders();
 109     }
 110 
 111     /**
 112      * The slot reserved for storing the original return address when a frame is marked for
 113      * deoptimization. The return address slot in the callee is overwritten with the address of a
 114      * deoptimization stub.
 115      */
 116     private StackSlot deoptimizationRescueSlot;
 117 
 118     /**
 119      * Value where the address for safepoint poll is kept.
 120      */
 121     private AllocatableValue safepointAddressValue;
 122 
 123     @Override
 124     public VirtualStackSlot getLockSlot(int lockDepth) {
 125         return getLockStack().makeLockSlot(lockDepth);
 126     }
 127 
 128     private HotSpotLockStack getLockStack() {
 129         assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
 130         return debugInfoBuilder.lockStack();
 131     }
 132 
 133     @Override
 134     public boolean needOnlyOopMaps() {
 135         // Stubs only need oop maps
 136         return getStub() != null;
 137     }
 138 
 139     public Stub getStub() {
 140         return getResult().getStub();
 141     }
 142 
 143     @Override
 144     public HotSpotLIRGenerationResult getResult() {
 145         return ((HotSpotLIRGenerationResult) super.getResult());
 146     }
 147 
 148     @Override
 149     public void beforeRegisterAllocation() {
 150         super.beforeRegisterAllocation();
 151         boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
 152         if (hasDebugInfo) {
 153             getResult().setDeoptimizationRescueSlot(((SPARCFrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
 154         }
 155 
 156         getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
 157     }
 158 
 159     @Override
 160     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
 161         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
 162         Variable result;
 163         LIRFrameState debugInfo = null;
 164         if (hotspotLinkage.needsDebugInfo()) {
 165             debugInfo = state;
 166             assert debugInfo != null || getStub() != null;
 167         }
 168 
 169         if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) {
 170             HotSpotRegistersProvider registers = getProviders().getRegisters();
 171             Register thread = registers.getThreadRegister();
 172             Value threadTemp = newVariable(LIRKind.value(SPARCKind.XWORD));
 173             Register stackPointer = registers.getStackPointerRegister();
 174             Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind()));
 175             append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch));
 176             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 177             append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp));
 178         } else {
 179             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 180         }
 181 
 182         return result;
 183     }
 184 
 185     @Override
 186     public void emitReturn(JavaKind javaKind, Value input) {
 187         AllocatableValue operand = Value.ILLEGAL;
 188         if (input != null) {
 189             operand = resultOperandFor(javaKind, input.getValueKind());
 190             emitMove(operand, input);
 191         }
 192         append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, getSafepointAddressValue()));
 193     }
 194 
 195     @Override
 196     public void emitTailcall(Value[] args, Value address) {
 197         throw GraalError.unimplemented();
 198     }
 199 
 200     @Override
 201     public void emitUnwind(Value exception) {
 202         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
 203         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
 204         assert linkageCc.getArgumentCount() == 2;
 205         RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0);
 206         emitMove(exceptionParameter, exception);
 207         append(new SPARCHotSpotUnwindOp(exceptionParameter));
 208     }
 209 
 210     private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
 211         moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
 212         moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
 213     }
 214 
 215     private void moveValueToThread(Value v, int offset) {
 216         LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
 217         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
 218         SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset);
 219         append(new StoreOp(v.getPlatformKind(), pendingDeoptAddress, load(v), null));
 220     }
 221 
 222     @Override
 223     public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
 224         moveDeoptValuesToThread(actionAndReason, speculation);
 225         append(new SPARCDeoptimizeOp(state, target().arch.getWordKind()));
 226     }
 227 
 228     @Override
 229     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
 230         Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
 231         Value nullValue = emitJavaConstant(JavaConstant.NULL_POINTER);
 232         moveDeoptValuesToThread(actionAndReason, nullValue);
 233         append(new SPARCHotSpotDeoptimizeCallerOp());
 234     }
 235 
 236     @Override
 237     public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
 238         ValueKind<?> kind = newValue.getValueKind();
 239         assert kind.equals(expectedValue.getValueKind());
 240         SPARCKind memKind = (SPARCKind) kind.getPlatformKind();
 241         Variable result = newVariable(newValue.getValueKind());
 242         append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
 243         return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue);
 244     }
 245 
 246     @Override
 247     public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
 248         ValueKind<?> kind = newValue.getValueKind();
 249         assert kind.equals(expectedValue.getValueKind());
 250         Variable result = newVariable(newValue.getValueKind());
 251         append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
 252         return result;
 253     }
 254 
 255     @Override
 256     public void emitPrefetchAllocate(Value address) {
 257         SPARCAddressValue addr = asAddressValue(address);
 258         append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr));
 259     }
 260 
 261     public StackSlot getDeoptimizationRescueSlot() {
 262         return deoptimizationRescueSlot;
 263     }
 264 
 265     @Override
 266     public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 267                     double trueDestinationProbability) {
 268         Value localX = x;
 269         Value localY = y;
 270         if (localX instanceof HotSpotObjectConstant) {
 271             localX = load(localX);
 272         }
 273         if (localY instanceof HotSpotObjectConstant) {
 274             localY = load(localY);
 275         }
 276         super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
 277     }
 278 
 279     @Override
 280     protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
 281         Value localA = a;
 282         Value localB = b;
 283         if (isConstantValue(a)) {
 284             Constant c = asConstant(a);
 285             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 286                 localA = SPARC.g0.asValue(LIRKind.value(WORD));
 287             } else if (c instanceof HotSpotObjectConstant) {
 288                 localA = load(localA);
 289             }
 290         }
 291         if (isConstantValue(b)) {
 292             Constant c = asConstant(b);
 293             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 294                 localB = SPARC.g0.asValue(LIRKind.value(WORD));
 295             } else if (c instanceof HotSpotObjectConstant) {
 296                 localB = load(localB);
 297             }
 298         }
 299         return super.emitCompare(cmpKind, localA, localB);
 300     }
 301 
 302     @Override
 303     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 304         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 305         assert inputKind.getPlatformKind() == XWORD : inputKind;
 306         if (inputKind.isReference(0)) {
 307             // oop
 308             Variable result = newVariable(LIRKind.reference(WORD));
 309             append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 310             return result;
 311         } else {
 312             // metaspace pointer
 313             Variable result = newVariable(LIRKind.value(WORD));
 314             AllocatableValue base = Value.ILLEGAL;
 315             if (encoding.hasBase()) {
 316                 base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase()));
 317             }
 318             append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 319             return result;
 320         }
 321     }
 322 
 323     @Override
 324     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 325         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 326         assert inputKind.getPlatformKind() == WORD;
 327         if (inputKind.isReference(0)) {
 328             // oop
 329             Variable result = newVariable(LIRKind.reference(XWORD));
 330             append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 331             return result;
 332         } else {
 333             // metaspace pointer
 334             Variable result = newVariable(LIRKind.value(XWORD));
 335             AllocatableValue base = Value.ILLEGAL;
 336             if (encoding.hasBase()) {
 337                 base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase()));
 338             }
 339             append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 340             return result;
 341         }
 342     }
 343 
 344     /**
 345      * @param savedRegisters the registers saved by this operation which may be subject to pruning
 346      * @param savedRegisterLocations the slots to which the registers are saved
 347      * @param supportsRemove determines if registers can be pruned
 348      */
 349     protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
 350         SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
 351         append(save);
 352         return save;
 353     }
 354 
 355     @Override
 356     public void emitNullCheck(Value address, LIRFrameState state) {
 357         PlatformKind kind = address.getPlatformKind();
 358         if (kind == WORD) {
 359             CompressEncoding encoding = config.getOopEncoding();
 360             Value uncompressed = emitUncompress(address, encoding, false);
 361             append(new NullCheckOp(asAddressValue(uncompressed), state));
 362         } else {
 363             super.emitNullCheck(address, state);
 364         }
 365     }
 366 
 367     @Override
 368     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
 369         if (BenchmarkCounters.enabled) {
 370             return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
 371         }
 372         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 373     }
 374 
 375     @Override
 376     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
 377         if (BenchmarkCounters.enabled) {
 378             return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
 379         }
 380         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 381     }
 382 
 383     public AllocatableValue getSafepointAddressValue() {
 384         if (this.safepointAddressValue == null) {
 385             this.safepointAddressValue = newVariable(LIRKind.value(target().arch.getWordKind()));
 386         }
 387         return this.safepointAddressValue;
 388     }
 389 
 390     @Override
 391     protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
 392         return new SPARCHotSpotStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
 393     }
 394 
 395     public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
 396         this.debugInfoBuilder = debugInfoBuilder;
 397     }
 398 
 399     @Override
 400     public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
 401         throw GraalError.unimplemented();
 402     }
 403 
 404     @Override
 405     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
 406         throw GraalError.unimplemented();
 407     }
 408 }