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