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 }