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         append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, getSafepointAddressValue()));
 194     }
 195 
 196     @Override
 197     public void emitTailcall(Value[] args, Value address) {
 198         throw GraalError.unimplemented();
 199     }
 200 
 201     @Override
 202     public void emitUnwind(Value exception) {
 203         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
 204         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
 205         assert linkageCc.getArgumentCount() == 2;
 206         RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0);
 207         emitMove(exceptionParameter, exception);
 208         append(new SPARCHotSpotUnwindOp(exceptionParameter));
 209     }
 210 
 211     private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
 212         moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
 213         moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
 214     }
 215 
 216     private void moveValueToThread(Value v, int offset) {
 217         LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
 218         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
 219         SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset);
 220         append(new StoreOp(v.getPlatformKind(), pendingDeoptAddress, load(v), null));
 221     }
 222 
 223     @Override
 224     public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
 225         moveDeoptValuesToThread(actionAndReason, speculation);
 226         append(new SPARCDeoptimizeOp(state, target().arch.getWordKind()));
 227     }
 228 
 229     @Override
 230     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
 231         Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
 232         Value nullValue = emitJavaConstant(JavaConstant.NULL_POINTER);
 233         moveDeoptValuesToThread(actionAndReason, nullValue);
 234         append(new SPARCHotSpotDeoptimizeCallerOp());
 235     }
 236 
 237     @Override
 238     public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
 239         ValueKind<?> kind = newValue.getValueKind();
 240         assert kind.equals(expectedValue.getValueKind());
 241         SPARCKind memKind = (SPARCKind) kind.getPlatformKind();
 242         Variable result = newVariable(newValue.getValueKind());
 243         append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
 244         return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue);
 245     }
 246 
 247     @Override
 248     public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
 249         ValueKind<?> kind = newValue.getValueKind();
 250         assert kind.equals(expectedValue.getValueKind());
 251         Variable result = newVariable(newValue.getValueKind());
 252         append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
 253         return result;
 254     }
 255 
 256     @Override
 257     public void emitPrefetchAllocate(Value address) {
 258         SPARCAddressValue addr = asAddressValue(address);
 259         append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads));
 260     }
 261 
 262     public StackSlot getDeoptimizationRescueSlot() {
 263         return deoptimizationRescueSlot;
 264     }
 265 
 266     @Override
 267     public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 268                     double trueDestinationProbability) {
 269         Value localX = x;
 270         Value localY = y;
 271         if (localX instanceof HotSpotObjectConstant) {
 272             localX = load(localX);
 273         }
 274         if (localY instanceof HotSpotObjectConstant) {
 275             localY = load(localY);
 276         }
 277         super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
 278     }
 279 
 280     @Override
 281     protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
 282         Value localA = a;
 283         Value localB = b;
 284         if (isConstantValue(a)) {
 285             Constant c = asConstant(a);
 286             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 287                 localA = SPARC.g0.asValue(LIRKind.value(WORD));
 288             } else if (c instanceof HotSpotObjectConstant) {
 289                 localA = load(localA);
 290             }
 291         }
 292         if (isConstantValue(b)) {
 293             Constant c = asConstant(b);
 294             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 295                 localB = SPARC.g0.asValue(LIRKind.value(WORD));
 296             } else if (c instanceof HotSpotObjectConstant) {
 297                 localB = load(localB);
 298             }
 299         }
 300         return super.emitCompare(cmpKind, localA, localB);
 301     }
 302 
 303     @Override
 304     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 305         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 306         assert inputKind.getPlatformKind() == XWORD : inputKind;
 307         if (inputKind.isReference(0)) {
 308             // oop
 309             Variable result = newVariable(LIRKind.reference(WORD));
 310             append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 311             return result;
 312         } else {
 313             // metaspace pointer
 314             Variable result = newVariable(LIRKind.value(WORD));
 315             AllocatableValue base = Value.ILLEGAL;
 316             if (encoding.hasBase()) {
 317                 base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase()));
 318             }
 319             append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 320             return result;
 321         }
 322     }
 323 
 324     @Override
 325     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 326         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 327         assert inputKind.getPlatformKind() == WORD;
 328         if (inputKind.isReference(0)) {
 329             // oop
 330             Variable result = newVariable(LIRKind.reference(XWORD));
 331             append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 332             return result;
 333         } else {
 334             // metaspace pointer
 335             Variable result = newVariable(LIRKind.value(XWORD));
 336             AllocatableValue base = Value.ILLEGAL;
 337             if (encoding.hasBase()) {
 338                 base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase()));
 339             }
 340             append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 341             return result;
 342         }
 343     }
 344 
 345     /**
 346      * @param savedRegisters the registers saved by this operation which may be subject to pruning
 347      * @param savedRegisterLocations the slots to which the registers are saved
 348      * @param supportsRemove determines if registers can be pruned
 349      */
 350     protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
 351         SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
 352         append(save);
 353         return save;
 354     }
 355 
 356     @Override
 357     public void emitNullCheck(Value address, LIRFrameState state) {
 358         PlatformKind kind = address.getPlatformKind();
 359         if (kind == WORD) {
 360             CompressEncoding encoding = config.getOopEncoding();
 361             Value uncompressed = emitUncompress(address, encoding, false);
 362             append(new NullCheckOp(asAddressValue(uncompressed), state));
 363         } else {
 364             super.emitNullCheck(address, state);
 365         }
 366     }
 367 
 368     @Override
 369     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
 370         if (BenchmarkCounters.enabled) {
 371             return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
 372         }
 373         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 374     }
 375 
 376     @Override
 377     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
 378         if (BenchmarkCounters.enabled) {
 379             return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
 380         }
 381         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 382     }
 383 
 384     public AllocatableValue getSafepointAddressValue() {
 385         if (this.safepointAddressValue == null) {
 386             this.safepointAddressValue = newVariable(LIRKind.value(target().arch.getWordKind()));
 387         }
 388         return this.safepointAddressValue;
 389     }
 390 
 391     @Override
 392     protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
 393         return new SPARCHotSpotStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
 394     }
 395 
 396     public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
 397         this.debugInfoBuilder = debugInfoBuilder;
 398     }
 399 
 400     @Override
 401     public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
 402         throw GraalError.unimplemented();
 403     }
 404 
 405     @Override
 406     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
 407         throw GraalError.unimplemented();
 408     }
 409 }