1 /*
   2  * Copyright (c) 2013, 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 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 
  32 import org.graalvm.compiler.asm.sparc.SPARCAssembler;
  33 import org.graalvm.compiler.core.common.CompressEncoding;
  34 import org.graalvm.compiler.core.common.LIRKind;
  35 import org.graalvm.compiler.core.common.calc.Condition;
  36 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  37 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  38 import org.graalvm.compiler.core.sparc.SPARCArithmeticLIRGenerator;
  39 import org.graalvm.compiler.core.sparc.SPARCLIRGenerator;
  40 import org.graalvm.compiler.core.sparc.SPARCLIRKindTool;
  41 import org.graalvm.compiler.debug.GraalError;
  42 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  43 import org.graalvm.compiler.hotspot.HotSpotBackend;
  44 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
  45 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
  46 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
  47 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
  48 import org.graalvm.compiler.hotspot.HotSpotLockStack;
  49 import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
  50 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  51 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
  52 import org.graalvm.compiler.hotspot.stubs.Stub;
  53 import org.graalvm.compiler.lir.LIRFrameState;
  54 import org.graalvm.compiler.lir.LIRInstruction;
  55 import org.graalvm.compiler.lir.LabelRef;
  56 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
  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 Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
 243         ValueKind<?> kind = newValue.getValueKind();
 244         assert kind.equals(expectedValue.getValueKind());
 245         SPARCKind memKind = (SPARCKind) kind.getPlatformKind();
 246         Variable result = newVariable(newValue.getValueKind());
 247         append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
 248         return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue);
 249     }
 250 
 251     @Override
 252     public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
 253         ValueKind<?> kind = newValue.getValueKind();
 254         assert kind.equals(expectedValue.getValueKind());
 255         Variable result = newVariable(newValue.getValueKind());
 256         append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
 257         return result;
 258     }
 259 
 260     @Override
 261     public void emitPrefetchAllocate(Value address) {
 262         SPARCAddressValue addr = asAddressValue(address);
 263         append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads));
 264     }
 265 
 266     public StackSlot getDeoptimizationRescueSlot() {
 267         return deoptimizationRescueSlot;
 268     }
 269 
 270     @Override
 271     public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 272                     double trueDestinationProbability) {
 273         Value localX = x;
 274         Value localY = y;
 275         if (localX instanceof HotSpotObjectConstant) {
 276             localX = load(localX);
 277         }
 278         if (localY instanceof HotSpotObjectConstant) {
 279             localY = load(localY);
 280         }
 281         super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
 282     }
 283 
 284     @Override
 285     protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
 286         Value localA = a;
 287         Value localB = b;
 288         if (isConstantValue(a)) {
 289             Constant c = asConstant(a);
 290             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 291                 localA = SPARC.g0.asValue(LIRKind.value(WORD));
 292             } else if (c instanceof HotSpotObjectConstant) {
 293                 localA = load(localA);
 294             }
 295         }
 296         if (isConstantValue(b)) {
 297             Constant c = asConstant(b);
 298             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 299                 localB = SPARC.g0.asValue(LIRKind.value(WORD));
 300             } else if (c instanceof HotSpotObjectConstant) {
 301                 localB = load(localB);
 302             }
 303         }
 304         return super.emitCompare(cmpKind, localA, localB);
 305     }
 306 
 307     @Override
 308     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 309         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 310         assert inputKind.getPlatformKind() == XWORD : inputKind;
 311         if (inputKind.isReference(0)) {
 312             // oop
 313             Variable result = newVariable(LIRKind.compressedReference(WORD));
 314             append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 315             return result;
 316         } else {
 317             // metaspace pointer
 318             Variable result = newVariable(LIRKind.value(WORD));
 319             AllocatableValue base = Value.ILLEGAL;
 320             if (encoding.hasBase()) {
 321                 base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase()));
 322             }
 323             append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 324             return result;
 325         }
 326     }
 327 
 328     @Override
 329     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 330         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 331         assert inputKind.getPlatformKind() == WORD;
 332         if (inputKind.isReference(0)) {
 333             // oop
 334             Variable result = newVariable(LIRKind.reference(XWORD));
 335             append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 336             return result;
 337         } else {
 338             // metaspace pointer
 339             Variable result = newVariable(LIRKind.value(XWORD));
 340             AllocatableValue base = Value.ILLEGAL;
 341             if (encoding.hasBase()) {
 342                 base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase()));
 343             }
 344             append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 345             return result;
 346         }
 347     }
 348 
 349     /**
 350      * @param savedRegisters the registers saved by this operation which may be subject to pruning
 351      * @param savedRegisterLocations the slots to which the registers are saved
 352      * @param supportsRemove determines if registers can be pruned
 353      */
 354     protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
 355         SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
 356         append(save);
 357         return save;
 358     }
 359 
 360     @Override
 361     public void emitNullCheck(Value address, LIRFrameState state) {
 362         PlatformKind kind = address.getPlatformKind();
 363         if (kind == WORD) {
 364             CompressEncoding encoding = config.getOopEncoding();
 365             Value uncompressed = emitUncompress(address, encoding, false);
 366             append(new NullCheckOp(asAddressValue(uncompressed), state));
 367         } else {
 368             super.emitNullCheck(address, state);
 369         }
 370     }
 371 
 372     @Override
 373     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
 374         if (BenchmarkCounters.enabled) {
 375             return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
 376         }
 377         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 378     }
 379 
 380     @Override
 381     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
 382         if (BenchmarkCounters.enabled) {
 383             return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
 384         }
 385         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 386     }
 387 
 388     public AllocatableValue getSafepointAddressValue() {
 389         if (this.safepointAddressValue == null) {
 390             this.safepointAddressValue = SPARCHotSpotSafepointOp.getSafepointAddressValue(this);
 391         }
 392         return this.safepointAddressValue;
 393     }
 394 
 395     @Override
 396     protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
 397         return new SPARCHotSpotStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
 398     }
 399 
 400     public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
 401         this.debugInfoBuilder = debugInfoBuilder;
 402     }
 403 
 404     @Override
 405     public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
 406         throw GraalError.unimplemented();
 407     }
 408 
 409     @Override
 410     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
 411         throw GraalError.unimplemented();
 412     }
 413 }