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