001/* 002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.sparc; 024 025import static com.oracle.graal.hotspot.HotSpotBackend.*; 026import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 027import static jdk.internal.jvmci.code.ValueUtil.*; 028import static jdk.internal.jvmci.hotspot.HotSpotCompressedNullConstant.*; 029import static jdk.internal.jvmci.sparc.SPARC.*; 030 031import java.util.*; 032 033import jdk.internal.jvmci.code.*; 034import jdk.internal.jvmci.common.*; 035import jdk.internal.jvmci.hotspot.*; 036import jdk.internal.jvmci.hotspot.HotSpotVMConfig.CompressEncoding; 037import jdk.internal.jvmci.meta.*; 038import jdk.internal.jvmci.sparc.*; 039 040import com.oracle.graal.compiler.common.calc.*; 041import com.oracle.graal.compiler.common.spi.*; 042import com.oracle.graal.compiler.sparc.*; 043import com.oracle.graal.hotspot.*; 044import com.oracle.graal.hotspot.debug.*; 045import com.oracle.graal.hotspot.meta.*; 046import com.oracle.graal.hotspot.stubs.*; 047import com.oracle.graal.lir.*; 048import com.oracle.graal.lir.StandardOp.SaveRegistersOp; 049import com.oracle.graal.lir.gen.*; 050import com.oracle.graal.lir.sparc.*; 051import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp; 052import com.oracle.graal.lir.sparc.SPARCMove.LoadOp; 053import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp; 054import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp; 055import com.oracle.graal.lir.sparc.SPARCMove.StoreOp; 056 057public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { 058 059 final HotSpotVMConfig config; 060 private HotSpotLockStack lockStack; 061 private LIRFrameState currentRuntimeCallInfo; 062 063 public SPARCHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) { 064 this(new DefaultLIRKindTool(providers.getCodeCache().getTarget().wordKind), providers, config, cc, lirGenRes); 065 } 066 067 protected SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) { 068 super(lirKindTool, providers, cc, lirGenRes); 069 assert config.basicLockSize == 8; 070 this.config = config; 071 } 072 073 @Override 074 public HotSpotProviders getProviders() { 075 return (HotSpotProviders) super.getProviders(); 076 } 077 078 /** 079 * The slot reserved for storing the original return address when a frame is marked for 080 * deoptimization. The return address slot in the callee is overwritten with the address of a 081 * deoptimization stub. 082 */ 083 private StackSlot deoptimizationRescueSlot; 084 085 /** 086 * Value where the address for safepoint poll is kept. 087 */ 088 private AllocatableValue safepointAddressValue; 089 090 @Override 091 public StackSlotValue getLockSlot(int lockDepth) { 092 return getLockStack().makeLockSlot(lockDepth); 093 } 094 095 private HotSpotLockStack getLockStack() { 096 assert lockStack != null; 097 return lockStack; 098 } 099 100 protected void setLockStack(HotSpotLockStack lockStack) { 101 assert this.lockStack == null; 102 this.lockStack = lockStack; 103 } 104 105 @Override 106 public boolean needOnlyOopMaps() { 107 // Stubs only need oop maps 108 return getStub() != null; 109 } 110 111 public Stub getStub() { 112 return ((SPARCHotSpotLIRGenerationResult) getResult()).getStub(); 113 } 114 115 @Override 116 public void beforeRegisterAllocation() { 117 super.beforeRegisterAllocation(); 118 boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); 119 if (hasDebugInfo) { 120 ((SPARCHotSpotLIRGenerationResult) getResult()).setDeoptimizationRescueSlot(((SPARCFrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); 121 } 122 } 123 124 @Override 125 protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { 126 currentRuntimeCallInfo = info; 127 super.emitForeignCallOp(linkage, result, arguments, temps, info); 128 } 129 130 @Override 131 public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { 132 HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; 133 Variable result; 134 LIRFrameState debugInfo = null; 135 if (hotspotLinkage.needsDebugInfo()) { 136 debugInfo = state; 137 assert debugInfo != null || getStub() != null; 138 } 139 140 if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) { 141 HotSpotRegistersProvider registers = getProviders().getRegisters(); 142 Register thread = registers.getThreadRegister(); 143 Value threadTemp = newVariable(LIRKind.value(Kind.Long)); 144 Register stackPointer = registers.getStackPointerRegister(); 145 Variable spScratch = newVariable(LIRKind.value(target().wordKind)); 146 append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch)); 147 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); 148 append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp)); 149 } else { 150 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); 151 } 152 153 return result; 154 } 155 156 @Override 157 public void emitReturn(Value input) { 158 AllocatableValue operand = Value.ILLEGAL; 159 if (input != null) { 160 operand = resultOperandFor(input.getLIRKind()); 161 emitMove(operand, input); 162 } 163 append(new SPARCHotSpotReturnOp(operand, getStub() != null, runtime().getConfig(), getSafepointAddressValue())); 164 } 165 166 @Override 167 public void emitTailcall(Value[] args, Value address) { 168 throw JVMCIError.unimplemented(); 169 } 170 171 @Override 172 public void emitUnwind(Value exception) { 173 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); 174 CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); 175 assert linkageCc.getArgumentCount() == 2; 176 RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0); 177 emitMove(exceptionParameter, exception); 178 append(new SPARCHotSpotUnwindOp(exceptionParameter)); 179 } 180 181 private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { 182 moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); 183 moveValueToThread(speculation, config.pendingFailedSpeculationOffset); 184 } 185 186 private void moveValueToThread(Value v, int offset) { 187 LIRKind wordKind = LIRKind.value(getProviders().getCodeCache().getTarget().wordKind); 188 RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); 189 SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset); 190 append(new StoreOp(v.getKind(), pendingDeoptAddress, load(v), null)); 191 } 192 193 @Override 194 public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { 195 moveDeoptValuesToThread(actionAndReason, speculation); 196 append(new SPARCDeoptimizeOp(state, target().wordKind)); 197 } 198 199 @Override 200 public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { 201 moveDeoptValuesToThread(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0), JavaConstant.NULL_POINTER); 202 append(new SPARCHotSpotDeoptimizeCallerOp()); 203 } 204 205 @Override 206 public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { 207 SPARCAddressValue loadAddress = asAddressValue(address); 208 Variable result = newVariable(kind); 209 append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state)); 210 return result; 211 } 212 213 private static boolean canStoreConstant(JavaConstant c) { 214 // SPARC can only store integer null constants (via g0) 215 switch (c.getKind()) { 216 case Float: 217 case Double: 218 return false; 219 default: 220 return c.isDefaultForKind(); 221 } 222 } 223 224 @Override 225 public boolean canInlineConstant(JavaConstant c) { 226 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { 227 return true; 228 } else if (c instanceof HotSpotObjectConstant) { 229 return false; 230 } else { 231 return super.canInlineConstant(c); 232 } 233 } 234 235 @Override 236 public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) { 237 SPARCAddressValue storeAddress = asAddressValue(address); 238 if (isConstant(inputVal)) { 239 JavaConstant c = asConstant(inputVal); 240 if (canStoreConstant(c)) { 241 append(new StoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state)); 242 return; 243 } 244 } 245 Variable input = load(inputVal); 246 append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state)); 247 } 248 249 public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { 250 251 LIRKind kind = newValue.getLIRKind(); 252 assert kind.equals(expectedValue.getLIRKind()); 253 Kind memKind = (Kind) kind.getPlatformKind(); 254 Variable result = newVariable(newValue.getLIRKind()); 255 append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue))); 256 return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue); 257 } 258 259 public void emitPrefetchAllocate(Value address) { 260 SPARCAddressValue addr = asAddressValue(address); 261 append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr)); 262 } 263 264 public StackSlot getDeoptimizationRescueSlot() { 265 return deoptimizationRescueSlot; 266 } 267 268 @Override 269 protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) { 270 Value usedSource; 271 if (COMPRESSED_NULL.equals(src)) { 272 usedSource = INT_0; 273 } else { 274 usedSource = src; 275 } 276 return super.createMove(dst, usedSource); 277 } 278 279 @Override 280 public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, 281 double trueDestinationProbability) { 282 Value localX = x; 283 Value localY = y; 284 if (localX instanceof HotSpotObjectConstant) { 285 localX = load(localX); 286 } 287 if (localY instanceof HotSpotObjectConstant) { 288 localY = load(localY); 289 } 290 super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); 291 } 292 293 @Override 294 protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b) { 295 Value localA = a; 296 Value localB = b; 297 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localA)) { 298 localA = SPARC.g0.asValue(LIRKind.value(Kind.Int)); 299 } else if (localA instanceof HotSpotObjectConstant) { 300 localA = load(localA); 301 } 302 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localB)) { 303 localB = SPARC.g0.asValue(LIRKind.value(Kind.Int)); 304 } else if (localB instanceof HotSpotObjectConstant) { 305 localB = load(localB); 306 } 307 return super.emitCompare(cmpKind, localA, localB); 308 } 309 310 @Override 311 public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 312 LIRKind inputKind = pointer.getLIRKind(); 313 assert inputKind.getPlatformKind() == Kind.Long || inputKind.getPlatformKind() == Kind.Object; 314 if (inputKind.isReference(0)) { 315 // oop 316 Variable result = newVariable(LIRKind.reference(Kind.Int)); 317 append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 318 return result; 319 } else { 320 // metaspace pointer 321 Variable result = newVariable(LIRKind.value(Kind.Int)); 322 AllocatableValue base = Value.ILLEGAL; 323 if (encoding.base != 0) { 324 base = emitMove(JavaConstant.forLong(encoding.base)); 325 } 326 append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 327 return result; 328 } 329 } 330 331 @Override 332 public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 333 LIRKind inputKind = pointer.getLIRKind(); 334 assert inputKind.getPlatformKind() == Kind.Int; 335 if (inputKind.isReference(0)) { 336 // oop 337 Variable result = newVariable(LIRKind.reference(Kind.Object)); 338 append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 339 return result; 340 } else { 341 // metaspace pointer 342 Variable result = newVariable(LIRKind.value(Kind.Long)); 343 AllocatableValue base = Value.ILLEGAL; 344 if (encoding.base != 0) { 345 base = emitMove(JavaConstant.forLong(encoding.base)); 346 } 347 append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 348 return result; 349 } 350 } 351 352 /** 353 * @param savedRegisters the registers saved by this operation which may be subject to pruning 354 * @param savedRegisterLocations the slots to which the registers are saved 355 * @param supportsRemove determines if registers can be pruned 356 */ 357 protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlotValue[] savedRegisterLocations, boolean supportsRemove) { 358 SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove); 359 append(save); 360 return save; 361 } 362 363 public SaveRegistersOp emitSaveAllRegisters() { 364 // We save all registers that were not saved by the save instruction. 365 // @formatter:off 366 Register[] savedRegisters = { 367 // CPU 368 g1, g3, g4, g5, 369 // FPU, use only every second register as doubles are stored anyways 370 f0, /*f1, */ f2, /*f3, */ f4, /*f5, */ f6, /*f7, */ 371 f8, /*f9, */ f10, /*f11,*/ f12, /*f13,*/ f14, /*f15,*/ 372 f16, /*f17,*/ f18, /*f19,*/ f20, /*f21,*/ f22, /*f23,*/ 373 f24, /*f25,*/ f26, /*f27,*/ f28, /*f29,*/ f30, /*f31 */ 374 d32, d34, d36, d38, 375 d40, d42, d44, d46, 376 d48, d50, d52, d54, 377 d56, d58, d60, d62 378 }; 379 // @formatter:on 380 StackSlotValue[] savedRegisterLocations = new StackSlotValue[savedRegisters.length]; 381 for (int i = 0; i < savedRegisters.length; i++) { 382 PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); 383 assert kind != Kind.Illegal; 384 VirtualStackSlot spillSlot = getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind)); 385 savedRegisterLocations[i] = spillSlot; 386 } 387 return emitSaveRegisters(savedRegisters, savedRegisterLocations, false); 388 } 389 390 public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { 391 append(new SPARCHotSpotLeaveCurrentStackFrameOp()); 392 } 393 394 public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { 395 append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp()); 396 } 397 398 public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { 399 Register thread = getProviders().getRegisters().getThreadRegister(); 400 Variable framePcVariable = load(framePc); 401 Variable senderSpVariable = load(senderSp); 402 Variable scratchVariable = newVariable(LIRKind.value(getHostWordKind())); 403 append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable, 404 target().wordKind)); 405 } 406 407 public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { 408 Register thread = getProviders().getRegisters().getThreadRegister(); 409 append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset())); 410 } 411 412 public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { 413 Variable frameSizeVariable = load(frameSize); 414 Variable framePcVariable = load(framePc); 415 Variable senderSpVariable = load(senderSp); 416 Variable initialInfoVariable = load(initialInfo); 417 append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable)); 418 } 419 420 public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) { 421 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP); 422 423 Register threadRegister = getProviders().getRegisters().getThreadRegister(); 424 Value threadTemp = newVariable(LIRKind.value(target().wordKind)); 425 Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister(); 426 Variable spScratch = newVariable(LIRKind.value(target().wordKind)); 427 append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch)); 428 Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().wordKind)), trapRequest); 429 append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp)); 430 431 Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((SPARCHotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo(); 432 assert currentRuntimeCallInfo != null; 433 assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); 434 calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); 435 436 return result; 437 } 438 439 @Override 440 public Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) { 441 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO); 442 443 Register threadRegister = getProviders().getRegisters().getThreadRegister(); 444 Value threadTemp = newVariable(LIRKind.value(target().wordKind)); 445 Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister(); 446 Variable spScratch = newVariable(LIRKind.value(target().wordKind)); 447 append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch)); 448 Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().wordKind))); 449 append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp)); 450 451 Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((SPARCHotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo(); 452 assert currentRuntimeCallInfo != null; 453 assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); 454 calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); 455 456 return result; 457 } 458 459 @Override 460 public void emitNullCheck(Value address, LIRFrameState state) { 461 PlatformKind kind = address.getPlatformKind(); 462 if (kind == Kind.Int) { 463 CompressEncoding encoding = config.getOopEncoding(); 464 Value uncompressed = emitUncompress(address, encoding, false); 465 append(new NullCheckOp(asAddressValue(uncompressed), state)); 466 } else { 467 super.emitNullCheck(address, state); 468 } 469 } 470 471 @Override 472 public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { 473 if (BenchmarkCounters.enabled) { 474 return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config); 475 } else { 476 return null; 477 } 478 } 479 480 @Override 481 public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { 482 if (BenchmarkCounters.enabled) { 483 return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config); 484 } else { 485 return null; 486 } 487 } 488 489 public AllocatableValue getSafepointAddressValue() { 490 if (this.safepointAddressValue == null) { 491 this.safepointAddressValue = newVariable(LIRKind.value(target().wordKind)); 492 } 493 return this.safepointAddressValue; 494 } 495}