8159368: [JVMCI] SPARCHotSpotRegisterConfig.callingConvention gives incorrect calling convention for native calls containing fp args
Reviewed-by: kvn, iveresov
--- a/hotspot/make/test/JtregNative.gmk Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/make/test/JtregNative.gmk Tue Jul 12 20:42:46 2016 +0000
@@ -52,6 +52,7 @@
$(HOTSPOT_TOPDIR)/test/compiler/calls \
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
$(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
+ $(HOTSPOT_TOPDIR)/test/compiler/jvmci/jdk.vm.ci.code.test \
#
# Add conditional directories here when needed.
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Jul 12 20:42:46 2016 +0000
@@ -26,17 +26,41 @@
import static jdk.vm.ci.meta.Value.ILLEGAL;
import static jdk.vm.ci.sparc.SPARC.REGISTER_SAFE_AREA_SIZE;
import static jdk.vm.ci.sparc.SPARC.d0;
+import static jdk.vm.ci.sparc.SPARC.d10;
+import static jdk.vm.ci.sparc.SPARC.d12;
+import static jdk.vm.ci.sparc.SPARC.d14;
+import static jdk.vm.ci.sparc.SPARC.d16;
+import static jdk.vm.ci.sparc.SPARC.d18;
import static jdk.vm.ci.sparc.SPARC.d2;
+import static jdk.vm.ci.sparc.SPARC.d20;
+import static jdk.vm.ci.sparc.SPARC.d22;
+import static jdk.vm.ci.sparc.SPARC.d24;
+import static jdk.vm.ci.sparc.SPARC.d26;
+import static jdk.vm.ci.sparc.SPARC.d28;
+import static jdk.vm.ci.sparc.SPARC.d30;
import static jdk.vm.ci.sparc.SPARC.d4;
import static jdk.vm.ci.sparc.SPARC.d6;
+import static jdk.vm.ci.sparc.SPARC.d8;
import static jdk.vm.ci.sparc.SPARC.f0;
import static jdk.vm.ci.sparc.SPARC.f1;
+import static jdk.vm.ci.sparc.SPARC.f11;
+import static jdk.vm.ci.sparc.SPARC.f13;
+import static jdk.vm.ci.sparc.SPARC.f15;
+import static jdk.vm.ci.sparc.SPARC.f17;
+import static jdk.vm.ci.sparc.SPARC.f19;
import static jdk.vm.ci.sparc.SPARC.f2;
+import static jdk.vm.ci.sparc.SPARC.f21;
+import static jdk.vm.ci.sparc.SPARC.f23;
+import static jdk.vm.ci.sparc.SPARC.f25;
+import static jdk.vm.ci.sparc.SPARC.f27;
+import static jdk.vm.ci.sparc.SPARC.f29;
import static jdk.vm.ci.sparc.SPARC.f3;
+import static jdk.vm.ci.sparc.SPARC.f31;
import static jdk.vm.ci.sparc.SPARC.f4;
import static jdk.vm.ci.sparc.SPARC.f5;
import static jdk.vm.ci.sparc.SPARC.f6;
import static jdk.vm.ci.sparc.SPARC.f7;
+import static jdk.vm.ci.sparc.SPARC.f9;
import static jdk.vm.ci.sparc.SPARC.g0;
import static jdk.vm.ci.sparc.SPARC.g2;
import static jdk.vm.ci.sparc.SPARC.g6;
@@ -95,11 +119,6 @@
private final RegisterAttributes[] attributesMap;
- /**
- * Does native code (C++ code) spill arguments in registers to the parent frame?
- */
- private final boolean addNativeRegisterArgumentSlots;
-
@Override
public RegisterArray getAllocatableRegisters() {
return allocatable;
@@ -124,10 +143,18 @@
private final RegisterArray cpuCallerParameterRegisters = new RegisterArray(o0, o1, o2, o3, o4, o5);
private final RegisterArray cpuCalleeParameterRegisters = new RegisterArray(i0, i1, i2, i3, i4, i5);
- private final RegisterArray fpuFloatParameterRegisters = new RegisterArray(f0, f1, f2, f3, f4, f5, f6, f7);
- private final RegisterArray fpuDoubleParameterRegisters = new RegisterArray(d0, null, d2, null, d4, null, d6, null);
+ private final RegisterArray fpuFloatJavaParameterRegisters = new RegisterArray(f0, f1, f2, f3, f4, f5, f6, f7);
+ private final RegisterArray fpuDoubleJavaParameterRegisters = new RegisterArray(d0, null, d2, null, d4, null, d6, null);
// @formatter:off
+ private final RegisterArray fpuFloatNativeParameterRegisters = new RegisterArray(
+ f1, f3, f5, f7, f9, f11, f13, f15,
+ f17, f19, f21, f23, f25, f27, f29, f31);
+
+ private final RegisterArray fpuDoubleNativeParameterRegisters = new RegisterArray(
+ d0, d2, d4, d6, d8, d10, d12, d14,
+ d16, d18, d20, d22, d24, d26, d28, d30);
+
private final RegisterArray callerSaveRegisters;
/**
@@ -170,7 +197,6 @@
public SPARCHotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable) {
this.target = target;
this.allocatable = allocatable;
- this.addNativeRegisterArgumentSlots = false;
HashSet<Register> callerSaveSet = new HashSet<>(target.arch.getAvailableValueRegisters().asList());
for (Register cs : windowSaveRegisters) {
callerSaveSet.remove(cs);
@@ -220,7 +246,7 @@
return hotspotType == HotSpotCallingConventionType.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters;
case Double:
case Float:
- return fpuFloatParameterRegisters;
+ return fpuFloatJavaParameterRegisters;
default:
throw JVMCIError.shouldNotReachHere("Unknown JavaKind " + kind);
}
@@ -233,48 +259,77 @@
int currentGeneral = 0;
int currentFloating = 0;
int currentStackOffset = 0;
+ boolean isNative = type == HotSpotCallingConventionType.NativeCall;
for (int i = 0; i < parameterTypes.length; i++) {
final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind();
-
- switch (kind) {
- case Byte:
- case Boolean:
- case Short:
- case Char:
- case Int:
- case Long:
- case Object:
- if (currentGeneral < generalParameterRegisters.size()) {
- Register register = generalParameterRegisters.get(currentGeneral++);
- locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
- }
- break;
- case Double:
- if (currentFloating < fpuFloatParameterRegisters.size()) {
- if (currentFloating % 2 != 0) {
- // Make register number even to be a double reg
- currentFloating++;
+ if (isNative) {
+ RegisterArray registerSet;
+ switch (kind) {
+ case Byte:
+ case Boolean:
+ case Short:
+ case Char:
+ case Int:
+ case Long:
+ case Object:
+ registerSet = generalParameterRegisters;
+ break;
+ case Double:
+ registerSet = fpuDoubleNativeParameterRegisters;
+ break;
+ case Float:
+ registerSet = fpuFloatNativeParameterRegisters;
+ break;
+ default:
+ throw JVMCIError.shouldNotReachHere();
+ }
+ if (i < registerSet.size()) {
+ locations[i] = registerSet.get(i).asValue(valueKindFactory.getValueKind(kind));
+ currentStackOffset += target.arch.getWordSize();
+ }
+ } else {
+ switch (kind) {
+ case Byte:
+ case Boolean:
+ case Short:
+ case Char:
+ case Int:
+ case Long:
+ case Object:
+ if (currentGeneral < generalParameterRegisters.size()) {
+ Register register = generalParameterRegisters.get(currentGeneral++);
+ locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
}
- Register register = fpuDoubleParameterRegisters.get(currentFloating);
- currentFloating += 2; // Only every second is a double register
- locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
- }
- break;
- case Float:
- if (currentFloating < fpuFloatParameterRegisters.size()) {
- Register register = fpuFloatParameterRegisters.get(currentFloating++);
- locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
- }
- break;
- default:
- throw JVMCIError.shouldNotReachHere();
+ break;
+ case Double:
+ if (currentFloating < fpuFloatJavaParameterRegisters.size()) {
+ if (currentFloating % 2 != 0) {
+ // Make register number even to be a double reg
+ currentFloating++;
+ }
+ Register register = fpuDoubleJavaParameterRegisters.get(currentFloating);
+ currentFloating += 2; // Only every second is a double register
+ locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
+ }
+ break;
+ case Float:
+ if (currentFloating < fpuFloatJavaParameterRegisters.size()) {
+ Register register = fpuFloatJavaParameterRegisters.get(currentFloating++);
+ locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
+ }
+ break;
+ default:
+ throw JVMCIError.shouldNotReachHere();
+ }
}
if (locations[i] == null) {
ValueKind<?> valueKind = valueKindFactory.getValueKind(kind);
- // Stack slot is always aligned to its size in bytes but minimum wordsize
int typeSize = valueKind.getPlatformKind().getSizeInBytes();
+ if (isNative) {
+ currentStackOffset += target.arch.getWordSize() - typeSize;
+ }
currentStackOffset = roundUp(currentStackOffset, typeSize);
int slotOffset = currentStackOffset + REGISTER_SAFE_AREA_SIZE;
locations[i] = StackSlot.get(valueKind, slotOffset, !type.out);
@@ -284,15 +339,7 @@
JavaKind returnKind = returnType == null ? Void : returnType.getJavaKind();
AllocatableValue returnLocation = returnKind == Void ? ILLEGAL : getReturnRegister(returnKind, type).asValue(valueKindFactory.getValueKind(returnKind.getStackKind()));
-
- int outArgSpillArea;
- if (type == HotSpotCallingConventionType.NativeCall && addNativeRegisterArgumentSlots) {
- // Space for native callee which may spill our outgoing arguments
- outArgSpillArea = Math.min(locations.length, generalParameterRegisters.size()) * target.wordSize;
- } else {
- outArgSpillArea = 0;
- }
- return new CallingConvention(currentStackOffset + outArgSpillArea, returnLocation, locations);
+ return new CallingConvention(currentStackOffset, returnLocation, locations);
}
private static int roundUp(int number, int mod) {
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java Tue Jul 12 20:42:46 2016 +0000
@@ -23,10 +23,12 @@
package jdk.vm.ci.code.test;
+import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueKindFactory;
import jdk.vm.ci.code.site.Call;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataPatch;
@@ -41,6 +43,7 @@
import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
import jdk.vm.ci.hotspot.HotSpotConstant;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.Assumptions.Assumption;
import jdk.vm.ci.meta.InvokeTarget;
import jdk.vm.ci.meta.JavaKind;
@@ -145,6 +148,11 @@
public abstract StackSlot emitFloatToStack(Register a);
/**
+ * Emit code to store a double-precision float from a register to a new stack slot.
+ */
+ public abstract StackSlot emitDoubleToStack(Register a);
+
+ /**
* Emit code to store a wide pointer from a register to a new stack slot.
*/
public abstract StackSlot emitPointerToStack(Register a);
@@ -165,6 +173,11 @@
public abstract void emitIntRet(Register a);
/**
+ * Emit code to return from a function, returning a single precision float.
+ */
+ public abstract void emitFloatRet(Register a);
+
+ /**
* Emit code to return from a function, returning a wide oop pointer.
*/
public abstract void emitPointerRet(Register a);
@@ -193,7 +206,13 @@
private StackSlot deoptRescue;
- private static class TestValueKind extends ValueKind<TestValueKind> {
+ public ValueKindFactory<TestValueKind> valueKindFactory = new ValueKindFactory<TestAssembler.TestValueKind>() {
+ public TestValueKind getValueKind(JavaKind javaKind) {
+ return (TestValueKind) TestAssembler.this.getValueKind(javaKind);
+ }
+ };
+
+ static class TestValueKind extends ValueKind<TestValueKind> {
TestValueKind(PlatformKind kind) {
super(kind);
@@ -340,6 +359,11 @@
data.putFloat(f);
}
+ public void emitDouble(double f) {
+ ensureSize(data.position() + 8);
+ data.putDouble(f);
+ }
+
public void align(int alignment) {
int pos = data.position();
int misaligned = pos % alignment;
@@ -353,4 +377,27 @@
return Arrays.copyOf(data.array(), data.position());
}
}
+
+ /**
+ * Loads a primitive into the Allocatable <code>av</code>. Implementors may only implement
+ * primitive types.
+ */
+ public abstract void emitLoad(AllocatableValue av, Object prim);
+
+ /**
+ * Emit a call to a fixed address <code>addr</code>
+ */
+ public abstract void emitCall(long addr);
+
+ /**
+ * Emit code which is necessary to call a method with {@link CallingConvention} <code>cc</code>
+ * and arguments <coe>prim</code>.
+ */
+ public abstract void emitCallPrologue(CallingConvention cc, Object... prim);
+
+ /**
+ * Emit code which is necessary after calling a method with CallingConvention <code>cc</code>.
+ */
+ public abstract void emitCallEpilogue(CallingConvention cc);
+
}
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java Tue Jul 12 20:42:46 2016 +0000
@@ -23,11 +23,15 @@
package jdk.vm.ci.code.test.amd64;
+import static jdk.vm.ci.amd64.AMD64.xmm0;
+
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataSectionReference;
@@ -36,6 +40,7 @@
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.hotspot.HotSpotConstant;
import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
+import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.VMConstant;
@@ -116,6 +121,10 @@
@Override
public Register emitLoadInt(int c) {
Register ret = newRegister();
+ return emitLoadInt(ret, c);
+ }
+
+ public Register emitLoadInt(Register ret, int c) {
emitREX(false, 0, 0, ret.encoding);
code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32
code.emitInt(c);
@@ -125,6 +134,10 @@
@Override
public Register emitLoadLong(long c) {
Register ret = newRegister();
+ return emitLoadLong(ret, c);
+ }
+
+ public Register emitLoadLong(Register ret, long c) {
emitREX(true, 0, 0, ret.encoding);
code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r64, imm64
code.emitLong(c);
@@ -133,12 +146,16 @@
@Override
public Register emitLoadFloat(float c) {
+ Register ret = AMD64.xmm0;
+ return emitLoadFloat(ret, c);
+ }
+
+ public Register emitLoadFloat(Register ret, float c) {
DataSectionReference ref = new DataSectionReference();
ref.setOffset(data.position());
data.emitFloat(c);
recordDataPatchInCode(ref);
- Register ret = AMD64.xmm0;
emitREX(false, ret.encoding, 0, 0);
code.emitByte(0xF3);
code.emitByte(0x0F);
@@ -148,6 +165,26 @@
return ret;
}
+ public Register emitLoadDouble(double c) {
+ Register ret = AMD64.xmm0;
+ return emitLoadDouble(ret, c);
+ }
+
+ public Register emitLoadDouble(Register ret, double c) {
+ DataSectionReference ref = new DataSectionReference();
+ ref.setOffset(data.position());
+ data.emitDouble(c);
+
+ recordDataPatchInCode(ref);
+ emitREX(false, ret.encoding, 0, 0);
+ code.emitByte(0xF2);
+ code.emitByte(0x0F);
+ code.emitByte(0x10); // MOVSD xmm1, xmm2/m32
+ code.emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // xmm, [rip+offset]
+ code.emitInt(0xDEADDEAD);
+ return ret;
+ }
+
@Override
public Register emitLoadPointer(HotSpotConstant c) {
recordDataPatchInCode(new ConstantReference((VMConstant) c));
@@ -192,6 +229,10 @@
@Override
public StackSlot emitIntToStack(Register a) {
StackSlot ret = newStackSlot(AMD64Kind.DWORD);
+ return emitIntToStack(ret, a);
+ }
+
+ public StackSlot emitIntToStack(StackSlot ret, Register a) {
// MOV r/m32,r32
emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16);
return ret;
@@ -200,6 +241,10 @@
@Override
public StackSlot emitLongToStack(Register a) {
StackSlot ret = newStackSlot(AMD64Kind.QWORD);
+ return emitLongToStack(ret, a);
+ }
+
+ public StackSlot emitLongToStack(StackSlot ret, Register a) {
// MOV r/m64,r64
emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16);
return ret;
@@ -208,12 +253,40 @@
@Override
public StackSlot emitFloatToStack(Register a) {
StackSlot ret = newStackSlot(AMD64Kind.SINGLE);
+ return emitFloatToStack(ret, a);
+ }
+
+ public StackSlot emitFloatToStack(StackSlot ret, Register a) {
emitREX(false, a.encoding, 0, 0);
code.emitByte(0xF3);
code.emitByte(0x0F);
code.emitByte(0x11); // MOVSS xmm2/m32, xmm1
code.emitByte(0x85 | ((a.encoding & 0x7) << 3)); // [rbp+offset]
- code.emitInt(ret.getRawOffset() + 16);
+ if (ret.getRawOffset() < 0) {
+ code.emitInt(ret.getRawOffset() + 16);
+ } else {
+ code.emitInt(-(frameSize - ret.getRawOffset()) + 16);
+ }
+ return ret;
+ }
+
+ @Override
+ public StackSlot emitDoubleToStack(Register a) {
+ StackSlot ret = newStackSlot(AMD64Kind.DOUBLE);
+ return emitDoubleToStack(ret, a);
+ }
+
+ public StackSlot emitDoubleToStack(StackSlot ret, Register a) {
+ emitREX(false, a.encoding, 0, 0);
+ code.emitByte(0xF2);
+ code.emitByte(0x0F);
+ code.emitByte(0x11); // MOVSD xmm2/m32, xmm1
+ code.emitByte(0x85 | ((a.encoding & 0x7) << 3)); // [rbp+offset]
+ if (ret.getRawOffset() < 0) {
+ code.emitInt(ret.getRawOffset() + 16);
+ } else {
+ code.emitInt(-(frameSize - ret.getRawOffset()) + 16);
+ }
return ret;
}
@@ -269,6 +342,14 @@
}
@Override
+ public void emitFloatRet(Register a) {
+ assert a == xmm0 : "Unimplemented move " + a;
+ emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp
+ code.emitByte(0x58 | AMD64.rbp.encoding); // POP rbp
+ code.emitByte(0xC3); // RET
+ }
+
+ @Override
public void emitPointerRet(Register a) {
emitMove(true, AMD64.rax, a); // MOV rax, ...
emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp
@@ -285,4 +366,64 @@
code.emitByte(0x25);
code.emitInt(0);
}
+
+ @Override
+ public void emitLoad(AllocatableValue av, Object prim) {
+ if (av instanceof RegisterValue) {
+ Register reg = ((RegisterValue) av).getRegister();
+ if (prim instanceof Float) {
+ emitLoadFloat(reg, (Float) prim);
+ } else if (prim instanceof Double) {
+ emitLoadDouble(reg, (Double) prim);
+ } else if (prim instanceof Integer) {
+ emitLoadInt(reg, (Integer) prim);
+ } else if (prim instanceof Long) {
+ emitLoadLong(reg, (Long) prim);
+ }
+ } else if (av instanceof StackSlot) {
+ StackSlot slot = (StackSlot) av;
+ if (prim instanceof Float) {
+ emitFloatToStack(slot, emitLoadFloat((Float) prim));
+ } else if (prim instanceof Double) {
+ emitDoubleToStack(slot, emitLoadDouble((Double) prim));
+ } else if (prim instanceof Integer) {
+ emitIntToStack(slot, emitLoadInt((Integer) prim));
+ } else if (prim instanceof Long) {
+ emitLongToStack(slot, emitLoadLong((Long) prim));
+ }
+ assert false : "Unimplemented";
+ } else {
+ throw new IllegalArgumentException("Unknown value " + av);
+ }
+ }
+
+ @Override
+ public void emitCallPrologue(CallingConvention cc, Object... prim) {
+ emitGrowStack(cc.getStackSize());
+ frameSize += cc.getStackSize();
+ AllocatableValue[] args = cc.getArguments();
+ // Do the emission in reverse, this avoids register collisons of xmm0 - which is used a
+ // scratch register when putting arguments on the stack.
+ for (int i = args.length - 1; i >= 0; i--) {
+ emitLoad(args[i], prim[i]);
+ }
+ }
+
+ @Override
+ public void emitCall(long addr) {
+ Register target = emitLoadLong(addr);
+ code.emitByte(0xFF); // CALL r/m64
+ int enc = target.encoding;
+ if (enc >= 8) {
+ code.emitByte(0x41);
+ enc -= 8;
+ }
+ code.emitByte(0xD0 | enc);
+ }
+
+ @Override
+ public void emitCallEpilogue(CallingConvention cc) {
+ emitGrowStack(-cc.getStackSize());
+ frameSize -= cc.getStackSize();
+ }
}
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/sparc/SPARCTestAssembler.java Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/sparc/SPARCTestAssembler.java Tue Jul 12 20:42:46 2016 +0000
@@ -23,9 +23,12 @@
package jdk.vm.ci.code.test.sparc;
+import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
+import jdk.vm.ci.code.RegisterValue;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataSectionReference;
@@ -36,6 +39,7 @@
import jdk.vm.ci.hotspot.HotSpotConstant;
import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.VMConstant;
import jdk.vm.ci.sparc.SPARC;
@@ -44,6 +48,9 @@
public class SPARCTestAssembler extends TestAssembler {
private static final int MASK13 = (1 << 13) - 1;
+ private static final Register scratchRegister = SPARC.g5;
+ private static final Register floatScratch = SPARC.f30;
+ private static final Register doubleScratch = SPARC.d62;
public SPARCTestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) {
super(codeCache, config, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7);
@@ -136,7 +143,7 @@
return ret;
}
- private void loadIntToRegister(int c, Register ret) {
+ private Register loadIntToRegister(int c, Register ret) {
int hi = c >>> 10;
int lo = c & ((1 << 10) - 1);
if (hi == 0) {
@@ -147,6 +154,7 @@
emitOp3(0b10, ret, 0b000010, ret, lo); // OR ret, lo, ret
}
}
+ return ret;
}
@Override
@@ -164,12 +172,13 @@
emitLoadPointerToRegister(ref, ret);
}
- public void emitLoadLongToRegister(long c, Register r) {
+ public Register emitLoadLongToRegister(long c, Register r) {
if ((c & 0xFFFF_FFFFL) == c) {
loadIntToRegister((int) c, r);
} else {
loadLongToRegister(c, r);
}
+ return r;
}
private void emitPatchableSethi(Register ret, boolean wide) {
@@ -185,16 +194,39 @@
@Override
public Register emitLoadFloat(float c) {
+ return emitLoadFloat(SPARC.f0, c);
+ }
+
+ public Register emitLoadFloat(Register reg, float c) {
+ return emitLoadFloat(reg, c, newRegister());
+ }
+
+ public Register emitLoadFloat(Register reg, float c, Register scratch) {
DataSectionReference ref = new DataSectionReference();
data.align(4);
ref.setOffset(data.position());
data.emitFloat(c);
- Register ptr = newRegister();
recordDataPatchInCode(ref);
- emitPatchableSethi(ptr, true);
- emitOp3(0b11, SPARC.f0, 0b100000, ptr, 0); // LDF [ptr+0], f0
- return SPARC.f0;
+ emitPatchableSethi(scratch, true);
+ emitOp3(0b11, reg, 0b100000, scratch, 0); // LDF [scratch+0], f0
+ return reg;
+ }
+
+ public Register emitLoadDouble(Register reg, double c) {
+ return emitLoadDouble(reg, c, newRegister());
+ }
+
+ public Register emitLoadDouble(Register reg, double c, Register scratch) {
+ DataSectionReference ref = new DataSectionReference();
+ data.align(8);
+ ref.setOffset(data.position());
+ data.emitDouble(c);
+
+ recordDataPatchInCode(ref);
+ emitPatchableSethi(scratch, true);
+ emitOp3(0b11, reg, 0b100011, scratch, 0); // LDDF [ptr+0], f0
+ return reg;
}
@Override
@@ -240,24 +272,48 @@
@Override
public StackSlot emitIntToStack(Register a) {
StackSlot ret = newStackSlot(SPARCKind.WORD);
- // STW a, [fp+offset]
+ intToStack(a, ret);
+ return ret;
+ }
+
+ public void intToStack(Register a, StackSlot ret) {
+ // STW a, [(s|f)p+offset]
emitStore(0b000100, a, ret);
- return ret;
}
@Override
public StackSlot emitLongToStack(Register a) {
StackSlot ret = newStackSlot(SPARCKind.XWORD);
- // STX a, [sp+offset]
+ longToStack(a, ret);
+ return ret;
+ }
+
+ public void longToStack(Register a, StackSlot ret) {
+ // STX a, [(f|s)p+offset]
emitStore(0b001110, a, ret);
- return ret;
}
@Override
public StackSlot emitFloatToStack(Register a) {
StackSlot ret = newStackSlot(SPARCKind.SINGLE);
+ floatToStack(a, ret);
+ return ret;
+ }
+
+ public void floatToStack(Register a, StackSlot ret) {
// STF a, [fp+offset]
emitStore(0b100100, a, ret);
+ }
+
+ @Override
+ public StackSlot emitDoubleToStack(Register a) {
+ StackSlot ret = newStackSlot(SPARCKind.DOUBLE);
+ return doubleToStack(a, ret);
+ }
+
+ public StackSlot doubleToStack(Register a, StackSlot ret) {
+ // STD a, [(s|f)p+offset]
+ emitStore(0b100111, a, ret);
return ret;
}
@@ -278,16 +334,22 @@
}
private void emitStore(int op3, Register a, StackSlot ret) {
+ Register base;
+ if (ret.getRawOffset() < 0) {
+ base = SPARC.fp;
+ } else {
+ base = SPARC.sp;
+ }
int offset = ret.getRawOffset() + SPARC.STACK_BIAS;
if (isSimm(offset, 13)) {
// op3 a, [sp+offset]
- emitOp3(0b11, a, op3, SPARC.fp, offset);
+ emitOp3(0b11, a, op3, base, offset);
} else {
assert a != SPARC.g3;
Register r = SPARC.g3;
loadLongToRegister(offset, r);
// op3 a, [sp+g3]
- emitOp3(0b11, a, op3, SPARC.fp, r);
+ emitOp3(0b11, a, op3, base, r);
}
}
@@ -328,6 +390,13 @@
}
@Override
+ public void emitFloatRet(Register a) {
+ assert a == SPARC.f0 : "Unimplemented";
+ emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8); // JMPL [i7+8], g0
+ emitOp3(0b10, SPARC.g0, 0b111101, SPARC.g0, SPARC.g0); // RESTORE g0, g0, g0
+ }
+
+ @Override
public void emitPointerRet(Register a) {
emitMove(SPARC.i0, a);
emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8); // JMPL [i7+8], g0
@@ -349,4 +418,57 @@
}
return super.emitDataItem(c);
}
+
+ @Override
+ public void emitCall(long addr) {
+ Register dst = emitLoadLong(addr);
+ emitOp3(0b10, SPARC.o7, 0b111000, dst, 0); // JMPL [dst+0], o7
+ emitNop();
+ }
+
+ @Override
+ public void emitLoad(AllocatableValue av, Object prim) {
+ if (av instanceof RegisterValue) {
+ Register reg = ((RegisterValue) av).getRegister();
+ RegisterCategory cat = reg.getRegisterCategory();
+ if (cat.equals(SPARC.FPUs)) {
+ emitLoadFloat(reg, (Float) prim, scratchRegister);
+ } else if (cat.equals(SPARC.FPUd)) {
+ emitLoadDouble(reg, (Double) prim, scratchRegister);
+ } else if (prim instanceof Integer) {
+ loadIntToRegister((Integer) prim, reg);
+ } else if (prim instanceof Long) {
+ loadLongToRegister((Long) prim, reg);
+ }
+ } else if (av instanceof StackSlot) {
+ StackSlot slot = (StackSlot) av;
+ if (prim instanceof Float) {
+ floatToStack(emitLoadFloat(floatScratch, (Float) prim, scratchRegister), slot);
+ } else if (prim instanceof Double) {
+ doubleToStack(emitLoadDouble(doubleScratch, (Double) prim, scratchRegister), slot);
+ } else if (prim instanceof Integer) {
+ intToStack(loadIntToRegister((Integer) prim, scratchRegister), slot);
+ } else if (prim instanceof Long) {
+ longToStack(emitLoadLongToRegister((Long) prim, scratchRegister), slot);
+ }
+ } else {
+ throw new IllegalArgumentException("Unknown value " + av);
+ }
+ }
+
+ @Override
+ public void emitCallEpilogue(CallingConvention cc) {
+ // Nothing to do here.
+ }
+
+ @Override
+ public void emitCallPrologue(CallingConvention cc, Object... prim) {
+ emitGrowStack(cc.getStackSize());
+ frameSize += cc.getStackSize();
+ AllocatableValue[] args = cc.getArguments();
+ for (int i = 0; i < args.length; i++) {
+ emitLoad(args[i], prim[i]);
+ }
+ }
+
}