43972
|
1 |
/*
|
|
2 |
* Copyright (c) 2013, 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 |
package org.graalvm.compiler.hotspot.sparc;
|
|
24 |
|
|
25 |
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
|
26 |
import static jdk.vm.ci.code.ValueUtil.isRegister;
|
|
27 |
import static jdk.vm.ci.sparc.SPARC.g0;
|
|
28 |
import static jdk.vm.ci.sparc.SPARC.g5;
|
|
29 |
import static jdk.vm.ci.sparc.SPARC.i0;
|
|
30 |
import static jdk.vm.ci.sparc.SPARC.i7;
|
|
31 |
import static jdk.vm.ci.sparc.SPARC.l0;
|
|
32 |
import static jdk.vm.ci.sparc.SPARC.l7;
|
|
33 |
import static jdk.vm.ci.sparc.SPARC.o0;
|
|
34 |
import static jdk.vm.ci.sparc.SPARC.o7;
|
|
35 |
import static jdk.vm.ci.sparc.SPARC.sp;
|
46344
|
36 |
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
|
|
37 |
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isGlobalRegister;
|
|
38 |
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
|
|
39 |
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
|
|
40 |
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
|
|
41 |
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
|
|
42 |
import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
|
43972
|
43 |
|
46344
|
44 |
import java.util.ArrayList;
|
43972
|
45 |
import java.util.HashSet;
|
|
46 |
import java.util.Set;
|
|
47 |
import java.util.concurrent.ConcurrentHashMap;
|
|
48 |
|
48861
|
49 |
import org.graalvm.collections.EconomicMap;
|
|
50 |
import org.graalvm.collections.EconomicSet;
|
|
51 |
import org.graalvm.collections.Equivalence;
|
43972
|
52 |
import org.graalvm.compiler.asm.Assembler;
|
|
53 |
import org.graalvm.compiler.asm.Label;
|
|
54 |
import org.graalvm.compiler.asm.sparc.SPARCAddress;
|
|
55 |
import org.graalvm.compiler.asm.sparc.SPARCAssembler;
|
|
56 |
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
|
|
57 |
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
|
|
58 |
import org.graalvm.compiler.code.CompilationResult;
|
|
59 |
import org.graalvm.compiler.code.DataSection;
|
|
60 |
import org.graalvm.compiler.code.DataSection.Data;
|
|
61 |
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
|
62 |
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
|
|
63 |
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
|
|
64 |
import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules;
|
46640
|
65 |
import org.graalvm.compiler.debug.CounterKey;
|
|
66 |
import org.graalvm.compiler.debug.DebugContext;
|
46344
|
67 |
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
43972
|
68 |
import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
|
|
69 |
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
|
|
70 |
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
|
|
71 |
import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
|
|
72 |
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
|
|
73 |
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
|
|
74 |
import org.graalvm.compiler.hotspot.stubs.Stub;
|
|
75 |
import org.graalvm.compiler.lir.InstructionValueConsumer;
|
|
76 |
import org.graalvm.compiler.lir.LIR;
|
|
77 |
import org.graalvm.compiler.lir.LIRFrameState;
|
|
78 |
import org.graalvm.compiler.lir.LIRInstruction;
|
|
79 |
import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
|
|
80 |
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
|
81 |
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
|
|
82 |
import org.graalvm.compiler.lir.asm.DataBuilder;
|
|
83 |
import org.graalvm.compiler.lir.asm.FrameContext;
|
|
84 |
import org.graalvm.compiler.lir.framemap.FrameMap;
|
|
85 |
import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
|
|
86 |
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
|
|
87 |
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
|
|
88 |
import org.graalvm.compiler.lir.sparc.SPARCCall;
|
|
89 |
import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
|
|
90 |
import org.graalvm.compiler.lir.sparc.SPARCFrameMap;
|
|
91 |
import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder;
|
|
92 |
import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin;
|
|
93 |
import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate;
|
|
94 |
import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction;
|
|
95 |
import org.graalvm.compiler.nodes.StructuredGraph;
|
|
96 |
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
46344
|
97 |
import org.graalvm.compiler.options.OptionValues;
|
43972
|
98 |
|
|
99 |
import jdk.vm.ci.code.CallingConvention;
|
|
100 |
import jdk.vm.ci.code.Register;
|
|
101 |
import jdk.vm.ci.code.RegisterConfig;
|
|
102 |
import jdk.vm.ci.code.StackSlot;
|
|
103 |
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
|
|
104 |
import jdk.vm.ci.meta.JavaType;
|
|
105 |
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
|
106 |
|
|
107 |
/**
|
|
108 |
* HotSpot SPARC specific backend.
|
|
109 |
*/
|
|
110 |
public class SPARCHotSpotBackend extends HotSpotHostBackend {
|
|
111 |
|
|
112 |
private static final SizeEstimateStatistics CONSTANT_ESTIMATED_STATS = new SizeEstimateStatistics("ESTIMATE");
|
|
113 |
private static final SizeEstimateStatistics CONSTANT_ACTUAL_STATS = new SizeEstimateStatistics("ACTUAL");
|
|
114 |
|
|
115 |
public SPARCHotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
|
|
116 |
super(config, runtime, providers);
|
|
117 |
}
|
|
118 |
|
|
119 |
private static class SizeEstimateStatistics {
|
46640
|
120 |
private static final ConcurrentHashMap<String, CounterKey> counters = new ConcurrentHashMap<>();
|
43972
|
121 |
private final String suffix;
|
|
122 |
|
|
123 |
SizeEstimateStatistics(String suffix) {
|
|
124 |
super();
|
|
125 |
this.suffix = suffix;
|
|
126 |
}
|
|
127 |
|
46640
|
128 |
public void add(Class<?> c, int count, DebugContext debug) {
|
43972
|
129 |
String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix;
|
46640
|
130 |
CounterKey m = counters.computeIfAbsent(name, (n) -> DebugContext.counter(n));
|
|
131 |
m.add(debug, count);
|
43972
|
132 |
}
|
|
133 |
}
|
|
134 |
|
|
135 |
@Override
|
|
136 |
public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
|
|
137 |
RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
|
|
138 |
return new SPARCFrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
|
|
139 |
}
|
|
140 |
|
|
141 |
@Override
|
|
142 |
public FrameMap newFrameMap(RegisterConfig registerConfig) {
|
|
143 |
return new SPARCFrameMap(getCodeCache(), registerConfig, this);
|
|
144 |
}
|
|
145 |
|
|
146 |
@Override
|
|
147 |
public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) {
|
|
148 |
return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getVMConfig(), lirGenRes);
|
|
149 |
}
|
|
150 |
|
|
151 |
@Override
|
|
152 |
public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) {
|
|
153 |
return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub);
|
|
154 |
}
|
|
155 |
|
|
156 |
@Override
|
|
157 |
public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
|
|
158 |
return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen));
|
|
159 |
}
|
|
160 |
|
|
161 |
@Override
|
|
162 |
protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) {
|
|
163 |
// Use SPARCAddress to get the final displacement including the stack bias.
|
|
164 |
SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
|
|
165 |
SPARCAddress address = new SPARCAddress(sp, -bangOffset);
|
|
166 |
if (SPARCAssembler.isSimm13(address.getDisplacement())) {
|
|
167 |
masm.stx(g0, address);
|
|
168 |
} else {
|
|
169 |
try (ScratchRegister sc = masm.getScratchRegister()) {
|
|
170 |
Register scratch = sc.getRegister();
|
|
171 |
assert isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch;
|
|
172 |
masm.setx(address.getDisplacement(), scratch, false);
|
|
173 |
masm.stx(g0, new SPARCAddress(sp, scratch));
|
|
174 |
}
|
|
175 |
}
|
|
176 |
}
|
|
177 |
|
|
178 |
public class HotSpotFrameContext implements FrameContext {
|
|
179 |
|
|
180 |
final boolean isStub;
|
|
181 |
|
|
182 |
HotSpotFrameContext(boolean isStub) {
|
|
183 |
this.isStub = isStub;
|
|
184 |
}
|
|
185 |
|
|
186 |
@Override
|
|
187 |
public boolean hasFrame() {
|
|
188 |
return true;
|
|
189 |
}
|
|
190 |
|
|
191 |
@Override
|
|
192 |
public void enter(CompilationResultBuilder crb) {
|
|
193 |
final int frameSize = crb.frameMap.totalFrameSize();
|
|
194 |
final int stackpoinerChange = -frameSize;
|
|
195 |
SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
|
|
196 |
emitStackOverflowCheck(crb);
|
|
197 |
|
|
198 |
if (SPARCAssembler.isSimm13(stackpoinerChange)) {
|
|
199 |
masm.save(sp, stackpoinerChange, sp);
|
|
200 |
} else {
|
|
201 |
try (ScratchRegister sc = masm.getScratchRegister()) {
|
|
202 |
Register scratch = sc.getRegister();
|
|
203 |
assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch;
|
|
204 |
masm.setx(stackpoinerChange, scratch, false);
|
|
205 |
masm.save(sp, scratch, sp);
|
|
206 |
}
|
|
207 |
}
|
|
208 |
|
46344
|
209 |
if (ZapStackOnMethodEntry.getValue(crb.getOptions())) {
|
43972
|
210 |
final int slotSize = 8;
|
|
211 |
for (int i = 0; i < frameSize / slotSize; ++i) {
|
|
212 |
// 0xC1C1C1C1
|
|
213 |
masm.stx(g0, new SPARCAddress(sp, i * slotSize));
|
|
214 |
}
|
|
215 |
}
|
|
216 |
}
|
|
217 |
|
|
218 |
@Override
|
|
219 |
public void leave(CompilationResultBuilder crb) {
|
|
220 |
SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
|
|
221 |
masm.restoreWindow();
|
|
222 |
}
|
|
223 |
}
|
|
224 |
|
|
225 |
@Override
|
|
226 |
protected Assembler createAssembler(FrameMap frameMap) {
|
|
227 |
return new SPARCMacroAssembler(getTarget());
|
|
228 |
}
|
|
229 |
|
|
230 |
@Override
|
|
231 |
public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
|
|
232 |
HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRes;
|
|
233 |
LIR lir = gen.getLIR();
|
|
234 |
assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
|
|
235 |
|
|
236 |
Stub stub = gen.getStub();
|
|
237 |
Assembler masm = createAssembler(frameMap);
|
|
238 |
// On SPARC we always use stack frames.
|
|
239 |
HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
|
|
240 |
DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget());
|
46344
|
241 |
OptionValues options = lir.getOptions();
|
46640
|
242 |
DebugContext debug = lir.getDebug();
|
|
243 |
CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, options, debug,
|
|
244 |
compilationResult);
|
43972
|
245 |
crb.setTotalFrameSize(frameMap.totalFrameSize());
|
|
246 |
crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize());
|
|
247 |
StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
|
|
248 |
if (deoptimizationRescueSlot != null && stub == null) {
|
|
249 |
crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot);
|
|
250 |
}
|
|
251 |
|
|
252 |
if (stub != null) {
|
|
253 |
// Even on sparc we need to save floating point registers
|
46344
|
254 |
EconomicSet<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir);
|
|
255 |
EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo();
|
43972
|
256 |
updateStub(stub, destroyedCallerRegisters, calleeSaveInfo, frameMap);
|
|
257 |
}
|
46640
|
258 |
assert registerSizePredictionValidator(crb, debug);
|
43972
|
259 |
return crb;
|
|
260 |
}
|
|
261 |
|
|
262 |
/**
|
|
263 |
* Registers a verifier which checks if the LIRInstructions estimate of constants size is
|
|
264 |
* greater or equal to the actual one.
|
|
265 |
*/
|
46640
|
266 |
private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb, DebugContext debug) {
|
43972
|
267 |
/**
|
|
268 |
* Used to hold state between beforeOp and afterOp
|
|
269 |
*/
|
|
270 |
class ValidationState {
|
|
271 |
LIRInstruction op;
|
46640
|
272 |
final DebugContext debug;
|
43972
|
273 |
int constantSizeBefore;
|
|
274 |
|
46640
|
275 |
ValidationState(DebugContext debug) {
|
|
276 |
this.debug = debug;
|
|
277 |
}
|
|
278 |
|
43972
|
279 |
public void before(LIRInstruction before) {
|
|
280 |
assert op == null : "LIRInstruction " + op + " no after call received";
|
|
281 |
op = before;
|
|
282 |
constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection());
|
|
283 |
}
|
|
284 |
|
|
285 |
public void after(LIRInstruction after) {
|
|
286 |
assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after;
|
|
287 |
int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection());
|
|
288 |
int actual = constantSizeAfter - constantSizeBefore;
|
|
289 |
if (op instanceof SPARCLIRInstructionMixin) {
|
|
290 |
org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize();
|
|
291 |
assert size != null : "No size prediction available for op: " + op;
|
|
292 |
Class<?> c = op.getClass();
|
46640
|
293 |
CONSTANT_ESTIMATED_STATS.add(c, size.constantSize, debug);
|
|
294 |
CONSTANT_ACTUAL_STATS.add(c, actual, debug);
|
43972
|
295 |
assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual;
|
|
296 |
} else {
|
|
297 |
assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate.";
|
|
298 |
}
|
|
299 |
op = null;
|
|
300 |
constantSizeBefore = 0;
|
|
301 |
}
|
|
302 |
}
|
46640
|
303 |
final ValidationState state = new ValidationState(debug);
|
43972
|
304 |
crb.setOpCallback(op -> state.before(op), op -> state.after(op));
|
|
305 |
return true;
|
|
306 |
}
|
|
307 |
|
|
308 |
private static int calculateDataSectionSize(DataSection ds) {
|
|
309 |
int sum = 0;
|
|
310 |
for (Data d : ds) {
|
|
311 |
sum += d.getSize();
|
|
312 |
}
|
|
313 |
return sum;
|
|
314 |
}
|
|
315 |
|
|
316 |
@Override
|
|
317 |
public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
|
|
318 |
SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
|
|
319 |
// TODO: (sa) Fold the two traversals into one
|
|
320 |
stuffDelayedControlTransfers(lir);
|
|
321 |
int constantSize = calculateConstantSize(lir);
|
|
322 |
boolean canUseImmediateConstantLoad = constantSize < (1 << 13);
|
|
323 |
masm.setImmediateConstantLoad(canUseImmediateConstantLoad);
|
|
324 |
FrameMap frameMap = crb.frameMap;
|
|
325 |
RegisterConfig regConfig = frameMap.getRegisterConfig();
|
|
326 |
Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
|
|
327 |
for (int i = 0; i < 2; i++) {
|
|
328 |
if (i > 0) {
|
|
329 |
crb.resetForEmittingCode();
|
|
330 |
lir.resetLabels();
|
|
331 |
resetDelayedControlTransfers(lir);
|
|
332 |
}
|
|
333 |
|
|
334 |
// Emit the prefix
|
|
335 |
if (unverifiedStub != null) {
|
|
336 |
crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
|
|
337 |
// We need to use JavaCall here because we haven't entered the frame yet.
|
|
338 |
CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this);
|
|
339 |
Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
|
|
340 |
|
|
341 |
try (ScratchRegister sc = masm.getScratchRegister()) {
|
|
342 |
Register scratch = sc.getRegister();
|
|
343 |
Register receiver = asRegister(cc.getArgument(0));
|
|
344 |
SPARCAddress src = new SPARCAddress(receiver, config.hubOffset);
|
|
345 |
|
|
346 |
masm.ldx(src, scratch);
|
|
347 |
masm.cmp(scratch, inlineCacheKlass);
|
|
348 |
}
|
|
349 |
BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub);
|
|
350 |
masm.nop(); // delay slot
|
|
351 |
}
|
|
352 |
|
|
353 |
masm.align(config.codeEntryAlignment);
|
|
354 |
crb.recordMark(config.MARKID_OSR_ENTRY);
|
|
355 |
crb.recordMark(config.MARKID_VERIFIED_ENTRY);
|
|
356 |
|
|
357 |
// Emit code for the LIR
|
|
358 |
crb.emit(lir);
|
|
359 |
}
|
|
360 |
profileInstructions(lir, crb);
|
|
361 |
|
|
362 |
HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
|
|
363 |
HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
|
|
364 |
if (!frameContext.isStub) {
|
|
365 |
crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
|
|
366 |
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
|
|
367 |
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
|
368 |
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null);
|
|
369 |
} else {
|
|
370 |
// No need to emit the stubs for entries back into the method since
|
|
371 |
// it has no calls that can cause such "return" entries
|
|
372 |
}
|
|
373 |
|
|
374 |
if (unverifiedStub != null) {
|
|
375 |
masm.bind(unverifiedStub);
|
|
376 |
try (ScratchRegister sc = masm.getScratchRegister()) {
|
|
377 |
Register scratch = sc.getRegister();
|
|
378 |
SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER));
|
|
379 |
}
|
|
380 |
}
|
|
381 |
masm.peephole();
|
|
382 |
}
|
|
383 |
|
|
384 |
private static int calculateConstantSize(LIR lir) {
|
|
385 |
int size = 0;
|
|
386 |
for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
|
|
387 |
if (block == null) {
|
|
388 |
continue;
|
|
389 |
}
|
|
390 |
for (LIRInstruction inst : lir.getLIRforBlock(block)) {
|
|
391 |
if (inst instanceof SPARCLIRInstructionMixin) {
|
|
392 |
SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize();
|
|
393 |
if (pred != null) {
|
|
394 |
size += pred.constantSize;
|
|
395 |
}
|
|
396 |
}
|
|
397 |
}
|
|
398 |
}
|
|
399 |
return size;
|
|
400 |
}
|
|
401 |
|
|
402 |
private static void resetDelayedControlTransfers(LIR lir) {
|
|
403 |
for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
|
|
404 |
if (block == null) {
|
|
405 |
continue;
|
|
406 |
}
|
|
407 |
for (LIRInstruction inst : lir.getLIRforBlock(block)) {
|
|
408 |
if (inst instanceof SPARCDelayedControlTransfer) {
|
|
409 |
((SPARCDelayedControlTransfer) inst).resetState();
|
|
410 |
}
|
|
411 |
}
|
|
412 |
}
|
|
413 |
}
|
|
414 |
|
|
415 |
/**
|
|
416 |
* Fix-up over whole LIR.
|
|
417 |
*
|
|
418 |
* @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase)
|
|
419 |
* @param l
|
|
420 |
*/
|
|
421 |
private static void stuffDelayedControlTransfers(LIR l) {
|
|
422 |
for (AbstractBlockBase<?> b : l.codeEmittingOrder()) {
|
|
423 |
if (b != null) {
|
|
424 |
stuffDelayedControlTransfers(l, b);
|
|
425 |
}
|
|
426 |
}
|
|
427 |
}
|
|
428 |
|
|
429 |
/**
|
|
430 |
* Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also
|
|
431 |
* it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if
|
|
432 |
* possible.
|
|
433 |
*/
|
|
434 |
private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase<?> block) {
|
46344
|
435 |
ArrayList<LIRInstruction> instructions = l.getLIRforBlock(block);
|
43972
|
436 |
if (instructions.size() >= 2) {
|
|
437 |
LIRDependencyAccumulator acc = new LIRDependencyAccumulator();
|
|
438 |
SPARCDelayedControlTransfer delayedTransfer = null;
|
|
439 |
int delayTransferPosition = -1;
|
|
440 |
for (int i = instructions.size() - 1; i >= 0; i--) {
|
|
441 |
LIRInstruction inst = instructions.get(i);
|
|
442 |
boolean adjacent = delayTransferPosition - i == 1;
|
|
443 |
if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) {
|
|
444 |
delayedTransfer = null;
|
|
445 |
}
|
|
446 |
if (inst instanceof SPARCDelayedControlTransfer) {
|
|
447 |
delayedTransfer = (SPARCDelayedControlTransfer) inst;
|
|
448 |
acc.start(inst);
|
|
449 |
delayTransferPosition = i;
|
|
450 |
} else if (delayedTransfer != null) {
|
|
451 |
boolean overlap = acc.add(inst);
|
|
452 |
if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) {
|
|
453 |
// We have found a non overlapping LIR instruction which can be delayed
|
|
454 |
((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer);
|
|
455 |
delayedTransfer = null;
|
|
456 |
}
|
|
457 |
}
|
|
458 |
}
|
|
459 |
}
|
|
460 |
}
|
|
461 |
|
|
462 |
private static boolean leavesRegisterWindow(LIRInstruction inst) {
|
|
463 |
return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow();
|
|
464 |
}
|
|
465 |
|
|
466 |
/**
|
|
467 |
* Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and
|
|
468 |
* detects, if there is any overlap. In this way LIRInstructions can be detected, which can be
|
|
469 |
* moved nearer to the DelayedControlTransfer instruction.
|
|
470 |
*/
|
|
471 |
private static class LIRDependencyAccumulator {
|
|
472 |
private final Set<Object> inputs = new HashSet<>(10);
|
|
473 |
private boolean overlap = false;
|
|
474 |
|
|
475 |
private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> {
|
|
476 |
Object valueObject = value;
|
|
477 |
if (isRegister(value)) { // Canonicalize registers
|
|
478 |
valueObject = asRegister(value);
|
|
479 |
}
|
|
480 |
if (!inputs.add(valueObject)) {
|
|
481 |
overlap = true;
|
|
482 |
}
|
|
483 |
};
|
|
484 |
|
|
485 |
public void start(LIRInstruction initial) {
|
|
486 |
inputs.clear();
|
|
487 |
overlap = false;
|
|
488 |
initial.visitEachInput(valueConsumer);
|
|
489 |
initial.visitEachTemp(valueConsumer);
|
|
490 |
initial.visitEachAlive(valueConsumer);
|
|
491 |
}
|
|
492 |
|
|
493 |
/**
|
|
494 |
* Adds the inputs of lir instruction to the accumulator and returns, true if there was any
|
|
495 |
* overlap of parameters.
|
|
496 |
*
|
|
497 |
* @param inst
|
|
498 |
* @return true if an overlap was found
|
|
499 |
*/
|
|
500 |
public boolean add(LIRInstruction inst) {
|
|
501 |
overlap = false;
|
|
502 |
inst.visitEachOutput(valueConsumer);
|
|
503 |
inst.visitEachTemp(valueConsumer);
|
|
504 |
inst.visitEachInput(valueConsumer);
|
|
505 |
inst.visitEachAlive(valueConsumer);
|
|
506 |
return overlap;
|
|
507 |
}
|
|
508 |
}
|
|
509 |
|
|
510 |
@Override
|
46344
|
511 |
public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) {
|
43972
|
512 |
RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
|
46344
|
513 |
return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull, allocationRestrictedTo);
|
43972
|
514 |
}
|
|
515 |
|
|
516 |
@Override
|
46344
|
517 |
public EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters) {
|
|
518 |
EconomicSet<Register> callerRegisters = EconomicSet.create(Equivalence.IDENTITY, calleeRegisters.size());
|
43972
|
519 |
for (Register register : calleeRegisters) {
|
|
520 |
if (l0.number <= register.number && register.number <= l7.number) {
|
|
521 |
// do nothing
|
|
522 |
} else if (o0.number <= register.number && register.number <= o7.number) {
|
|
523 |
// do nothing
|
|
524 |
} else if (i0.number <= register.number && register.number <= i7.number) {
|
|
525 |
// translate input to output registers
|
|
526 |
callerRegisters.add(translateInputToOutputRegister(register));
|
|
527 |
} else {
|
|
528 |
callerRegisters.add(register);
|
|
529 |
}
|
|
530 |
}
|
|
531 |
return callerRegisters;
|
|
532 |
}
|
|
533 |
|
|
534 |
private Register translateInputToOutputRegister(Register register) {
|
|
535 |
assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register;
|
|
536 |
return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number);
|
|
537 |
}
|
|
538 |
}
|