package com.oracle.svm.core.graal.amd64;
import static jdk.vm.ci.amd64.AMD64.r12;
import static jdk.vm.ci.amd64.AMD64.r13;
import static jdk.vm.ci.amd64.AMD64.r14;
import static jdk.vm.ci.amd64.AMD64.r15;
import static jdk.vm.ci.amd64.AMD64.r8;
import static jdk.vm.ci.amd64.AMD64.r9;
import static jdk.vm.ci.amd64.AMD64.rax;
import static jdk.vm.ci.amd64.AMD64.rbp;
import static jdk.vm.ci.amd64.AMD64.rbx;
import static jdk.vm.ci.amd64.AMD64.rcx;
import static jdk.vm.ci.amd64.AMD64.rdi;
import static jdk.vm.ci.amd64.AMD64.rdx;
import static jdk.vm.ci.amd64.AMD64.rsi;
import static jdk.vm.ci.amd64.AMD64.valueRegistersSSE;
import static jdk.vm.ci.amd64.AMD64.xmm0;
import static jdk.vm.ci.amd64.AMD64.xmm1;
import static jdk.vm.ci.amd64.AMD64.xmm10;
import static jdk.vm.ci.amd64.AMD64.xmm11;
import static jdk.vm.ci.amd64.AMD64.xmm12;
import static jdk.vm.ci.amd64.AMD64.xmm13;
import static jdk.vm.ci.amd64.AMD64.xmm14;
import static jdk.vm.ci.amd64.AMD64.xmm15;
import static jdk.vm.ci.amd64.AMD64.xmm2;
import static jdk.vm.ci.amd64.AMD64.xmm3;
import static jdk.vm.ci.amd64.AMD64.xmm4;
import static jdk.vm.ci.amd64.AMD64.xmm5;
import static jdk.vm.ci.amd64.AMD64.xmm6;
import static jdk.vm.ci.amd64.AMD64.xmm7;
import static jdk.vm.ci.amd64.AMD64.xmm8;
import static jdk.vm.ci.amd64.AMD64.xmm9;
import java.util.ArrayList;
import com.oracle.svm.core.OS;
import com.oracle.svm.core.ReservedRegisters;
import com.oracle.svm.core.config.ObjectLayout;
import com.oracle.svm.core.graal.code.SubstrateCallingConvention;
import com.oracle.svm.core.graal.code.SubstrateCallingConventionType;
import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig;
import com.oracle.svm.core.util.VMError;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.CallingConvention.Type;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterArray;
import jdk.vm.ci.code.RegisterAttributes;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.code.ValueKindFactory;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Value;
import jdk.vm.ci.meta.ValueKind;
public class SubstrateAMD64RegisterConfig implements SubstrateRegisterConfig {
private final TargetDescription target;
private final int nativeParamsStackOffset;
private final RegisterArray javaGeneralParameterRegs;
private final RegisterArray nativeGeneralParameterRegs;
private final RegisterArray xmmParameterRegs;
private final RegisterArray allocatableRegs;
private final RegisterArray calleeSaveRegisters;
private final RegisterAttributes[] attributesMap;
private final MetaAccessProvider metaAccess;
private final boolean useBasePointer;
public SubstrateAMD64RegisterConfig(ConfigKind config, MetaAccessProvider metaAccess, TargetDescription target, boolean useBasePointer) {
this.target = target;
this.metaAccess = metaAccess;
this.useBasePointer = useBasePointer;
if (OS.getCurrent() == OS.WINDOWS) {
nativeGeneralParameterRegs = new RegisterArray(rcx, rdx, r8, r9);
javaGeneralParameterRegs = new RegisterArray(rdx, r8, r9, rdi, rsi, rcx);
xmmParameterRegs = new RegisterArray(xmm0, xmm1, xmm2, xmm3);
nativeParamsStackOffset = 4 * target.wordSize;
ArrayList<Register> regs = new ArrayList<>(valueRegistersSSE.asList());
regs.remove(ReservedRegisters.singleton().getFrameRegister());
regs.remove(rbp);
regs.remove(ReservedRegisters.singleton().getHeapBaseRegister());
regs.remove(ReservedRegisters.singleton().getThreadRegister());
allocatableRegs = new RegisterArray(regs);
} else {
javaGeneralParameterRegs = new RegisterArray(rdi, rsi, rdx, rcx, r8, r9);
nativeGeneralParameterRegs = javaGeneralParameterRegs;
xmmParameterRegs = new RegisterArray(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
nativeParamsStackOffset = 0;
ArrayList<Register> regs = new ArrayList<>(valueRegistersSSE.asList());
regs.remove(ReservedRegisters.singleton().getFrameRegister());
if (useBasePointer) {
regs.remove(rbp);
}
regs.remove(ReservedRegisters.singleton().getHeapBaseRegister());
regs.remove(ReservedRegisters.singleton().getThreadRegister());
allocatableRegs = new RegisterArray(regs);
}
switch (config) {
case NORMAL:
calleeSaveRegisters = new RegisterArray();
break;
case NATIVE_TO_JAVA:
if (OS.getCurrent() == OS.WINDOWS) {
calleeSaveRegisters = new RegisterArray(rbx, rdi, rsi, r12, r13, r14, r15, rbp,
xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15);
} else {
calleeSaveRegisters = new RegisterArray(rbx, r12, r13, r14, r15, rbp);
}
break;
default:
throw VMError.shouldNotReachHere();
}
attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters);
}
@Override
public Register getReturnRegister(JavaKind kind) {
switch (kind) {
case Boolean:
case Byte:
case Char:
case Short:
case Int:
case Long:
case Object:
return rax;
case Float:
case Double:
return xmm0;
case Void:
return null;
default:
throw VMError.shouldNotReachHere();
}
}
@Override
public RegisterArray getAllocatableRegisters() {
return allocatableRegs;
}
@Override
public RegisterArray getCalleeSaveRegisters() {
return calleeSaveRegisters;
}
@Override
public RegisterArray getCallerSaveRegisters() {
return getAllocatableRegisters();
}
@Override
public boolean areAllAllocatableRegistersCallerSaved() {
return true;
}
@Override
public RegisterAttributes[] getAttributesMap() {
return attributesMap;
}
@Override
public RegisterArray getCallingConventionRegisters(Type t, JavaKind kind) {
SubstrateCallingConventionType type = (SubstrateCallingConventionType) t;
switch (kind) {
case Boolean:
case Byte:
case Short:
case Char:
case Int:
case Long:
case Object:
return (type.nativeABI ? nativeGeneralParameterRegs : javaGeneralParameterRegs);
case Float:
case Double:
return xmmParameterRegs;
default:
throw VMError.shouldNotReachHere();
}
}
public boolean shouldUseBasePointer() {
return this.useBasePointer;
}
@Override
public CallingConvention getCallingConvention(Type t, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory<?> valueKindFactory) {
SubstrateCallingConventionType type = (SubstrateCallingConventionType) t;
boolean isEntryPoint = type.nativeABI && !type.outgoing;
AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
int currentGeneral = 0;
int currentXMM = 0;
int currentStackOffset = (type.nativeABI ? nativeParamsStackOffset : target.wordSize);
JavaKind[] kinds = new JavaKind[locations.length];
for (int i = 0; i < parameterTypes.length; i++) {
JavaKind kind = ObjectLayout.getCallSignatureKind(isEntryPoint, (ResolvedJavaType) parameterTypes[i], metaAccess, target);
kinds[i] = kind;
if (type.nativeABI && OS.getCurrent() == OS.WINDOWS) {
currentGeneral = i;
currentXMM = i;
}
switch (kind) {
case Byte:
case Boolean:
case Short:
case Char:
case Int:
case Long:
case Object:
if (currentGeneral < (type.nativeABI ? nativeGeneralParameterRegs.size() : javaGeneralParameterRegs.size())) {
Register register = (type.nativeABI ? nativeGeneralParameterRegs.get(currentGeneral++) : javaGeneralParameterRegs.get(currentGeneral++));
locations[i] = register.asValue(valueKindFactory.getValueKind(kind.getStackKind()));
}
break;
case Float:
case Double:
if (currentXMM < xmmParameterRegs.size()) {
Register register = xmmParameterRegs.get(currentXMM++);
locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
}
break;
default:
throw VMError.shouldNotReachHere();
}
if (locations[i] == null) {
ValueKind<?> valueKind = valueKindFactory.getValueKind(kind.getStackKind());
locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.outgoing);
currentStackOffset += Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize);
}
}
JavaKind returnKind = returnType == null ? JavaKind.Void : ObjectLayout.getCallSignatureKind(isEntryPoint, (ResolvedJavaType) returnType, metaAccess, target);
AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind()));
return new SubstrateCallingConvention(type, kinds, currentStackOffset, returnLocation, locations);
}
@Override
public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) {
ArrayList<Register> list = new ArrayList<>();
for (Register reg : registers) {
if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) {
list.add(reg);
}
}
return new RegisterArray(list);
}
}