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 }