1 /* |
1 /* |
2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * Copyright (c) 2018, Red Hat Inc. All rights reserved. |
3 * Copyright (c) 2018, Red Hat Inc. All rights reserved. |
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
5 * |
5 * |
6 * This code is free software; you can redistribute it and/or modify it |
6 * This code is free software; you can redistribute it and/or modify it |
7 * under the terms of the GNU General Public License version 2 only, as |
7 * under the terms of the GNU General Public License version 2 only, as |
36 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; |
36 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; |
37 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; |
37 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE; |
38 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; |
38 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; |
39 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; |
39 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; |
40 |
40 |
|
41 import java.util.EnumSet; |
41 import java.util.function.Function; |
42 import java.util.function.Function; |
42 |
43 |
43 import org.graalvm.compiler.asm.Label; |
44 import org.graalvm.compiler.asm.Label; |
44 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; |
45 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; |
45 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; |
46 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; |
46 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.PrefetchMode; |
47 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.PrefetchMode; |
47 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; |
48 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; |
48 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; |
49 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; |
49 import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool; |
50 import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool; |
50 import org.graalvm.compiler.core.common.CompressEncoding; |
51 import org.graalvm.compiler.core.common.CompressEncoding; |
|
52 import org.graalvm.compiler.core.common.GraalOptions; |
51 import org.graalvm.compiler.core.common.LIRKind; |
53 import org.graalvm.compiler.core.common.LIRKind; |
52 import org.graalvm.compiler.core.common.calc.Condition; |
54 import org.graalvm.compiler.core.common.calc.Condition; |
53 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; |
55 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; |
54 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; |
56 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; |
55 import org.graalvm.compiler.core.common.spi.LIRKindTool; |
57 import org.graalvm.compiler.core.common.spi.LIRKindTool; |
66 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; |
68 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; |
67 import org.graalvm.compiler.hotspot.stubs.Stub; |
69 import org.graalvm.compiler.hotspot.stubs.Stub; |
68 import org.graalvm.compiler.lir.LIRFrameState; |
70 import org.graalvm.compiler.lir.LIRFrameState; |
69 import org.graalvm.compiler.lir.LIRInstruction; |
71 import org.graalvm.compiler.lir.LIRInstruction; |
70 import org.graalvm.compiler.lir.LabelRef; |
72 import org.graalvm.compiler.lir.LabelRef; |
71 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; |
73 import org.graalvm.compiler.lir.StandardOp.ZapRegistersOp; |
72 import org.graalvm.compiler.lir.SwitchStrategy; |
74 import org.graalvm.compiler.lir.SwitchStrategy; |
73 import org.graalvm.compiler.lir.Variable; |
75 import org.graalvm.compiler.lir.Variable; |
74 import org.graalvm.compiler.lir.VirtualStackSlot; |
76 import org.graalvm.compiler.lir.VirtualStackSlot; |
75 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; |
77 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; |
76 import org.graalvm.compiler.lir.aarch64.AArch64CCall; |
78 import org.graalvm.compiler.lir.aarch64.AArch64CCall; |
80 import org.graalvm.compiler.lir.aarch64.AArch64Move; |
82 import org.graalvm.compiler.lir.aarch64.AArch64Move; |
81 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; |
83 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; |
82 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp; |
84 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp; |
83 import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp; |
85 import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp; |
84 import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp; |
86 import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp; |
|
87 import org.graalvm.compiler.lir.aarch64.AArch64ZeroMemoryOp; |
85 import org.graalvm.compiler.lir.gen.LIRGenerationResult; |
88 import org.graalvm.compiler.lir.gen.LIRGenerationResult; |
86 import org.graalvm.compiler.options.OptionValues; |
89 import org.graalvm.compiler.options.OptionValues; |
87 |
90 |
88 import jdk.vm.ci.aarch64.AArch64; |
91 import jdk.vm.ci.aarch64.AArch64; |
89 import jdk.vm.ci.aarch64.AArch64Kind; |
92 import jdk.vm.ci.aarch64.AArch64Kind; |
165 } |
168 } |
166 |
169 |
167 /** |
170 /** |
168 * @param savedRegisters the registers saved by this operation which may be subject to pruning |
171 * @param savedRegisters the registers saved by this operation which may be subject to pruning |
169 * @param savedRegisterLocations the slots to which the registers are saved |
172 * @param savedRegisterLocations the slots to which the registers are saved |
170 * @param supportsRemove determines if registers can be pruned |
|
171 */ |
173 */ |
172 protected AArch64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) { |
174 protected AArch64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations) { |
173 AArch64SaveRegistersOp save = new AArch64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove); |
175 AArch64SaveRegistersOp save = new AArch64SaveRegistersOp(savedRegisters, savedRegisterLocations); |
174 append(save); |
176 append(save); |
175 return save; |
177 return save; |
176 } |
178 } |
177 |
179 |
178 /** |
180 /** |
180 */ |
182 */ |
181 protected VirtualStackSlot allocateSaveRegisterLocation(Register register) { |
183 protected VirtualStackSlot allocateSaveRegisterLocation(Register register) { |
182 PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory()); |
184 PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory()); |
183 if (kind.getVectorLength() > 1) { |
185 if (kind.getVectorLength() > 1) { |
184 // we don't use vector registers, so there is no need to save them |
186 // we don't use vector registers, so there is no need to save them |
185 kind = AArch64Kind.QWORD; |
187 kind = AArch64Kind.DOUBLE; |
186 } |
188 } |
187 return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind)); |
189 return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind)); |
188 } |
190 } |
189 |
191 |
190 /** |
192 /** |
191 * Adds a node to the graph that saves all allocatable registers to the stack. |
193 * Adds a node to the graph that saves all allocatable registers to the stack. |
192 * |
194 * |
193 * @param supportsRemove determines if registers can be pruned |
|
194 * @return the register save node |
195 * @return the register save node |
195 */ |
196 */ |
196 private AArch64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) { |
197 private AArch64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters) { |
197 AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length]; |
198 AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length]; |
198 for (int i = 0; i < savedRegisters.length; i++) { |
199 for (int i = 0; i < savedRegisters.length; i++) { |
199 savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]); |
200 savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]); |
200 } |
201 } |
201 return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove); |
202 return emitSaveRegisters(savedRegisters, savedRegisterLocations); |
202 } |
203 } |
203 |
204 |
204 protected void emitRestoreRegisters(AArch64SaveRegistersOp save) { |
205 protected void emitRestoreRegisters(AArch64SaveRegistersOp save) { |
205 append(new AArch64RestoreRegistersOp(save.getSlots().clone(), save)); |
206 append(new AArch64RestoreRegistersOp(save.getSlots().clone(), save)); |
206 } |
207 } |
345 HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; |
346 HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; |
346 boolean destroysRegisters = hotspotLinkage.destroysRegisters(); |
347 boolean destroysRegisters = hotspotLinkage.destroysRegisters(); |
347 |
348 |
348 AArch64SaveRegistersOp save = null; |
349 AArch64SaveRegistersOp save = null; |
349 Stub stub = getStub(); |
350 Stub stub = getStub(); |
350 if (destroysRegisters) { |
351 if (destroysRegisters && stub != null && stub.shouldSaveRegistersAroundCalls()) { |
351 if (stub != null && stub.preservesRegisters()) { |
352 Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray(); |
352 Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray(); |
353 save = emitSaveAllRegisters(savedRegisters); |
353 save = emitSaveAllRegisters(savedRegisters, true); |
|
354 } |
|
355 } |
354 } |
356 |
355 |
357 Variable result; |
356 Variable result; |
358 LIRFrameState debugInfo = null; |
357 LIRFrameState debugInfo = null; |
359 if (hotspotLinkage.needsDebugInfo()) { |
358 if (hotspotLinkage.needsDebugInfo()) { |
377 label = null; |
376 label = null; |
378 } else { |
377 } else { |
379 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); |
378 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); |
380 } |
379 } |
381 |
380 |
382 if (destroysRegisters) { |
381 if (save != null) { |
383 if (stub != null) { |
382 HotSpotLIRGenerationResult generationResult = getResult(); |
384 if (stub.preservesRegisters()) { |
383 LIRFrameState key = currentRuntimeCallInfo; |
385 HotSpotLIRGenerationResult generationResult = getResult(); |
384 if (key == null) { |
386 LIRFrameState key = currentRuntimeCallInfo; |
385 key = LIRFrameState.NO_STATE; |
387 if (key == null) { |
|
388 key = LIRFrameState.NO_STATE; |
|
389 } |
|
390 assert !generationResult.getCalleeSaveInfo().containsKey(key); |
|
391 generationResult.getCalleeSaveInfo().put(key, save); |
|
392 emitRestoreRegisters(save); |
|
393 } |
|
394 } |
386 } |
|
387 assert !generationResult.getCalleeSaveInfo().containsKey(key); |
|
388 generationResult.getCalleeSaveInfo().put(key, save); |
|
389 emitRestoreRegisters(save); |
395 } |
390 } |
396 |
391 |
397 return result; |
392 return result; |
398 } |
393 } |
399 |
394 |
537 public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { |
532 public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { |
538 this.debugInfoBuilder = debugInfoBuilder; |
533 this.debugInfoBuilder = debugInfoBuilder; |
539 } |
534 } |
540 |
535 |
541 @Override |
536 @Override |
542 public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { |
537 public ZapRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { |
543 throw GraalError.unimplemented(); |
538 throw GraalError.unimplemented(); |
544 } |
539 } |
545 |
540 |
546 @Override |
541 @Override |
547 public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { |
542 public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { |
548 throw GraalError.unimplemented(); |
543 throw GraalError.unimplemented(); |
549 } |
544 } |
|
545 |
|
546 @Override |
|
547 public void emitZeroMemory(Value address, Value length) { |
|
548 int dczidValue = config.psrInfoDczidValue; |
|
549 EnumSet<AArch64.Flag> flags = ((AArch64) target().arch).getFlags(); |
|
550 |
|
551 // ARMv8-A architecture reference manual D12.2.35 Data Cache Zero ID register says: |
|
552 // * BS, bits [3:0] indicate log2 of the DC ZVA block size in (4-byte) words. |
|
553 // * DZP, bit [4] of indicates whether use of DC ZVA instruction is prohibited. |
|
554 int zvaLength = 4 << (dczidValue & 0xF); |
|
555 boolean isDcZvaProhibited = ((dczidValue & 0x10) != 0); |
|
556 |
|
557 // Use DC ZVA if it's not prohibited and AArch64 HotSpot flag UseBlockZeroing is on. |
|
558 boolean useDcZva = !isDcZvaProhibited && flags.contains(AArch64.Flag.UseBlockZeroing); |
|
559 |
|
560 // Set zva length negative (unknown at compile-time) for AOT compilation, since the value |
|
561 // could be different on different AArch64 CPU implementations. |
|
562 if (GraalOptions.ImmutableCode.getValue(getResult().getLIR().getOptions())) { |
|
563 useDcZva = false; |
|
564 } |
|
565 |
|
566 // Value address is 8-byte aligned; Value length is multiple of 8. |
|
567 append(new AArch64ZeroMemoryOp(asAllocatable(address), asAllocatable(length), useDcZva, zvaLength)); |
|
568 } |
550 } |
569 } |