1 /* 2 * Copyright (c) 2015, 2016, 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 package org.graalvm.compiler.hotspot.aarch64; 25 26 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; 27 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; 28 29 import java.util.function.Function; 30 31 import org.graalvm.compiler.asm.Label; 32 import org.graalvm.compiler.asm.NumUtil; 33 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; 34 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; 35 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; 36 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; 37 import org.graalvm.compiler.core.common.LIRKind; 38 import org.graalvm.compiler.core.common.calc.Condition; 39 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 40 import org.graalvm.compiler.core.common.spi.LIRKindTool; 41 import org.graalvm.compiler.debug.GraalError; 42 import org.graalvm.compiler.hotspot.CompressEncoding; 43 import org.graalvm.compiler.hotspot.HotSpotBackend; 44 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; 45 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; 46 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; 47 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; 48 import org.graalvm.compiler.hotspot.HotSpotLockStack; 49 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 50 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 51 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; 52 import org.graalvm.compiler.hotspot.stubs.Stub; 53 import org.graalvm.compiler.lir.LIRFrameState; 54 import org.graalvm.compiler.lir.LIRInstruction; 55 import org.graalvm.compiler.lir.LabelRef; 56 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; 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.aarch64.AArch64AddressValue; 61 import org.graalvm.compiler.lir.aarch64.AArch64Call; 62 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp; 63 import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder; 64 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; 65 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp; 66 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 67 68 import jdk.vm.ci.aarch64.AArch64; 69 import jdk.vm.ci.aarch64.AArch64Kind; 70 import jdk.vm.ci.code.CallingConvention; 71 import jdk.vm.ci.code.Register; 72 import jdk.vm.ci.code.RegisterValue; 73 import jdk.vm.ci.code.StackSlot; 74 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; 75 import jdk.vm.ci.hotspot.HotSpotObjectConstant; 76 import jdk.vm.ci.meta.AllocatableValue; 77 import jdk.vm.ci.meta.Constant; 78 import jdk.vm.ci.meta.DeoptimizationAction; 79 import jdk.vm.ci.meta.DeoptimizationReason; 80 import jdk.vm.ci.meta.JavaConstant; 81 import jdk.vm.ci.meta.JavaKind; 82 import jdk.vm.ci.meta.PlatformKind; 83 import jdk.vm.ci.meta.Value; 84 85 /** 86 * LIR generator specialized for AArch64 HotSpot. 87 */ 88 public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator { 89 90 final GraalHotSpotVMConfig config; 91 private HotSpotDebugInfoBuilder debugInfoBuilder; 92 93 protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { 94 this(new AArch64HotSpotLIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes); 95 } 96 97 protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, 98 LIRGenerationResult lirGenRes) { 99 super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); 100 this.config = config; 101 } 102 103 @Override 104 public HotSpotProviders getProviders() { 105 return (HotSpotProviders) super.getProviders(); 106 } 107 108 @Override 109 public boolean needOnlyOopMaps() { 110 // Stubs only need oop maps 111 return getResult().getStub() != null; 112 } 113 114 @SuppressWarnings("unused") private LIRFrameState currentRuntimeCallInfo; 115 116 @Override 117 protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { 118 currentRuntimeCallInfo = info; 119 if (AArch64Call.isNearCall(linkage)) { 120 append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label)); 121 } else { 122 append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label)); 123 } 124 } 125 126 @Override 127 public void emitTailcall(Value[] args, Value address) { 128 throw GraalError.unimplemented(); 129 } 130 131 @Override 132 public SaveRegistersOp emitSaveAllRegisters() { 133 throw GraalError.unimplemented(); 134 } 135 136 @Override 137 public VirtualStackSlot getLockSlot(int lockDepth) { 138 return getLockStack().makeLockSlot(lockDepth); 139 } 140 141 private HotSpotLockStack getLockStack() { 142 assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; 143 return debugInfoBuilder.lockStack(); 144 } 145 146 @Override 147 public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, 148 double trueDestinationProbability) { 149 Value localX = x; 150 Value localY = y; 151 if (localX instanceof HotSpotObjectConstant) { 152 localX = load(localX); 153 } 154 if (localY instanceof HotSpotObjectConstant) { 155 localY = load(localY); 156 } 157 super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); 158 } 159 160 @Override 161 protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) { 162 Value localA = a; 163 Value localB = b; 164 if (isConstantValue(a)) { 165 Constant c = asConstant(a); 166 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { 167 localA = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD)); 168 } else if (c instanceof HotSpotObjectConstant) { 169 localA = load(localA); 170 } 171 } 172 if (isConstantValue(b)) { 173 Constant c = asConstant(b); 174 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { 175 localB = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD)); 176 } else if (c instanceof HotSpotObjectConstant) { 177 localB = load(localB); 178 } 179 } 180 return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue); 181 } 182 183 @Override 184 public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 185 LIRKind inputKind = pointer.getValueKind(LIRKind.class); 186 assert inputKind.getPlatformKind() == AArch64Kind.QWORD; 187 if (inputKind.isReference(0)) { 188 // oop 189 Variable result = newVariable(LIRKind.reference(AArch64Kind.DWORD)); 190 append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 191 return result; 192 } else { 193 // metaspace pointer 194 Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); 195 AllocatableValue base = Value.ILLEGAL; 196 if (encoding.base != 0) { 197 base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base)); 198 } 199 append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 200 return result; 201 } 202 } 203 204 @Override 205 public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 206 LIRKind inputKind = pointer.getValueKind(LIRKind.class); 207 assert inputKind.getPlatformKind() == AArch64Kind.DWORD; 208 if (inputKind.isReference(0)) { 209 // oop 210 Variable result = newVariable(LIRKind.reference(AArch64Kind.QWORD)); 211 append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 212 return result; 213 } else { 214 // metaspace pointer 215 Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD)); 216 AllocatableValue base = Value.ILLEGAL; 217 if (encoding.base != 0) { 218 base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base)); 219 } 220 append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 221 return result; 222 } 223 } 224 225 @Override 226 public void emitPrefetchAllocate(Value address) { 227 append(new AArch64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr)); 228 } 229 230 @Override 231 public void beforeRegisterAllocation() { 232 super.beforeRegisterAllocation(); 233 boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); 234 if (hasDebugInfo) { 235 getResult().setDeoptimizationRescueSlot(((AArch64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); 236 } 237 238 getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); 239 } 240 241 private Label label; 242 243 @Override 244 public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { 245 HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; 246 Variable result; 247 LIRFrameState debugInfo = null; 248 if (hotspotLinkage.needsDebugInfo()) { 249 debugInfo = state; 250 assert debugInfo != null || getStub() != null; 251 } 252 253 if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) { 254 HotSpotRegistersProvider registers = getProviders().getRegisters(); 255 Register thread = registers.getThreadRegister(); 256 Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind())); 257 258 // We need a label for the return address. 259 label = new Label(); 260 261 append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), thread, scratch, label)); 262 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); 263 append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread)); 264 265 // Clear it out so it's not being reused later. 266 label = null; 267 } else { 268 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); 269 } 270 271 return result; 272 } 273 274 @Override 275 public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { 276 Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); 277 Value nullValue = emitConstant(LIRKind.reference(AArch64Kind.QWORD), JavaConstant.NULL_POINTER); 278 moveDeoptValuesToThread(actionAndReason, nullValue); 279 append(new AArch64HotSpotDeoptimizeCallerOp(config)); 280 } 281 282 @Override 283 public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) { 284 moveDeoptValuesToThread(actionAndReason, failedSpeculation); 285 append(new AArch64HotSpotDeoptimizeOp(state)); 286 } 287 288 private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { 289 moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); 290 moveValueToThread(speculation, config.pendingFailedSpeculationOffset); 291 } 292 293 private void moveValueToThread(Value value, int offset) { 294 LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); 295 RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); 296 final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes(); 297 final int scaledDisplacement = offset >> NumUtil.log2Ceil(transferSize); 298 AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, scaledDisplacement, true, AddressingMode.IMMEDIATE_SCALED); 299 append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null)); 300 } 301 302 @Override 303 public void emitUnwind(Value exception) { 304 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); 305 CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); 306 assert outgoingCc.getArgumentCount() == 2; 307 RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0); 308 emitMove(exceptionParameter, exception); 309 append(new AArch64HotSpotUnwindOp(config, exceptionParameter)); 310 } 311 312 @Override 313 public void emitReturn(JavaKind kind, Value input) { 314 AllocatableValue operand = Value.ILLEGAL; 315 if (input != null) { 316 operand = resultOperandFor(kind, input.getValueKind()); 317 emitMove(operand, input); 318 } 319 append(new AArch64HotSpotReturnOp(operand, getStub() != null, config)); 320 } 321 322 /** 323 * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not 324 * being generated. 325 */ 326 public Stub getStub() { 327 return getResult().getStub(); 328 } 329 330 @Override 331 public HotSpotLIRGenerationResult getResult() { 332 return ((HotSpotLIRGenerationResult) super.getResult()); 333 } 334 335 @Override 336 protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, 337 Function<Condition, ConditionFlag> converter) { 338 return new AArch64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter); 339 } 340 341 public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { 342 this.debugInfoBuilder = debugInfoBuilder; 343 } 344 345 @Override 346 public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { 347 throw GraalError.unimplemented(); 348 } 349 350 @Override 351 public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { 352 throw GraalError.unimplemented(); 353 } 354 }