package org.graalvm.compiler.core.sparc;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVDCC;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVSCC;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MOVicc;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
import static jdk.vm.ci.sparc.SPARCKind.WORD;
import static jdk.vm.ci.sparc.SPARCKind.XWORD;
import org.graalvm.compiler.asm.sparc.SPARCAssembler;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.LIR;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRValueUtil;
import org.graalvm.compiler.lir.LabelRef;
import org.graalvm.compiler.lir.StandardOp.NoOp;
import org.graalvm.compiler.lir.SwitchStrategy;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.lir.gen.LIRGenerator;
import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
import org.graalvm.compiler.lir.sparc.SPARCArrayEqualsOp;
import org.graalvm.compiler.lir.sparc.SPARCByteSwapOp;
import org.graalvm.compiler.lir.sparc.SPARCCall;
import org.graalvm.compiler.lir.sparc.SPARCControlFlow;
import org.graalvm.compiler.lir.sparc.SPARCControlFlow.BranchOp;
import org.graalvm.compiler.lir.sparc.SPARCControlFlow.CondMoveOp;
import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp;
import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.sparc.SPARCControlFlow.TableSwitchOp;
import org.graalvm.compiler.lir.sparc.SPARCFloatCompareOp;
import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue;
import org.graalvm.compiler.lir.sparc.SPARCJumpOp;
import org.graalvm.compiler.lir.sparc.SPARCLoadConstantTableBaseOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.MembarOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.StackLoadAddressOp;
import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
import org.graalvm.compiler.lir.sparc.SPARCPauseOp;
import org.graalvm.compiler.phases.util.Providers;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.Value;
import jdk.vm.ci.meta.ValueKind;
import jdk.vm.ci.sparc.SPARC;
import jdk.vm.ci.sparc.SPARCKind;
public abstract class SPARCLIRGenerator extends LIRGenerator {
private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp;
private final ConstantTableBaseProvider constantTableBaseProvider;
public static final class ConstantTableBaseProvider {
private Variable constantTableBase;
private boolean useConstantTableBase = false;
public Variable getConstantTableBase() {
useConstantTableBase = true;
return constantTableBase;
}
}
public SPARCLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes,
ConstantTableBaseProvider constantTableBaseProvider) {
super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
this.constantTableBaseProvider = constantTableBaseProvider;
}
@Override
protected JavaConstant zapValueForKind(PlatformKind kind) {
long dead = 0xDEADDEADDEADDEADL;
switch ((SPARCKind) kind) {
case BYTE:
return JavaConstant.forByte((byte) dead);
case HWORD:
return JavaConstant.forShort((short) dead);
case WORD:
return JavaConstant.forInt((int) dead);
case XWORD:
return JavaConstant.forLong(dead);
case SINGLE:
case V32_BYTE:
case V32_HWORD:
return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
case DOUBLE:
case V64_BYTE:
case V64_HWORD:
case V64_WORD:
return JavaConstant.forDouble(Double.longBitsToDouble(dead));
default:
throw new IllegalArgumentException(kind.toString());
}
}
@Override
public <K extends ValueKind<K>> K toRegisterKind(K kind) {
switch ((SPARCKind) kind.getPlatformKind()) {
case BYTE:
case HWORD:
return kind.changeType(SPARCKind.WORD);
default:
return kind;
}
}
public SPARCAddressValue asAddressValue(Value address) {
if (address instanceof SPARCAddressValue) {
return (SPARCAddressValue) address;
} else {
ValueKind<?> kind = address.getValueKind();
if (address instanceof JavaConstant) {
long displacement = ((JavaConstant) address).asLong();
if (SPARCAssembler.isSimm13(displacement)) {
return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement);
}
}
return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0);
}
}
@Override
public Variable emitAddress(AllocatableValue stackslot) {
Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
append(new StackLoadAddressOp(result, stackslot));
return result;
}
@Override
public void emitReturn(JavaKind javaKind, Value input) {
AllocatableValue operand = Value.ILLEGAL;
if (input != null) {
operand = resultOperandFor(javaKind, input.getValueKind());
emitMove(operand, input);
}
append(new ReturnOp(operand));
}
@Override
public void emitJump(LabelRef label) {
append(new SPARCJumpOp(label));
}
@Override
public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
double trueDestinationProbability) {
AllocatableValue left;
Value right;
Condition actualCondition;
if (isJavaConstant(x)) {
left = load(y);
right = loadSimm13(x);
actualCondition = cond.mirror();
} else {
left = load(x);
right = loadSimm13(y);
actualCondition = cond;
}
SPARCKind actualCmpKind = (SPARCKind) cmpKind;
if (actualCmpKind.isInteger()) {
assert actualCmpKind.equals(XWORD) || actualCmpKind.equals(WORD) : "SPARC does not support compare of: " + actualCmpKind;
append(new SPARCControlFlow.CompareBranchOp(left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability));
} else if (actualCmpKind.isFloat()) {
emitFloatCompare(actualCmpKind, x, y, Fcc0);
ConditionFlag cf = SPARCControlFlow.fromCondition(false, cond, unorderedIsTrue);
append(new SPARCControlFlow.BranchOp(cf, trueDestination, falseDestination, actualCmpKind, trueDestinationProbability));
} else {
throw GraalError.shouldNotReachHere();
}
}
@Override
public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) {
SPARCKind cmpKind = (SPARCKind) cmpLIRKind.getPlatformKind();
append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability));
}
@Override
public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
emitIntegerTest(left, right);
append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, (SPARCKind) left.getPlatformKind(), trueDestinationProbability));
}
private void emitIntegerTest(Value a, Value b) {
assert ((SPARCKind) a.getPlatformKind()).isInteger();
if (LIRValueUtil.isVariable(b)) {
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadSimm13(a)));
} else {
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadSimm13(b)));
}
}
private Value loadSimm11(Value value) {
if (isJavaConstant(value)) {
JavaConstant c = asJavaConstant(value);
if (c.isNull() || SPARCAssembler.isSimm11(c)) {
return value;
}
}
return load(value);
}
public Value loadSimm13(Value value) {
if (isJavaConstant(value)) {
JavaConstant c = asJavaConstant(value);
if (c.isNull() || SPARCAssembler.isSimm13(c)) {
return value;
}
}
return load(value);
}
@Override
public Value loadNonConst(Value value) {
throw GraalError.shouldNotReachHere("This operation is not available for SPARC.");
}
@Override
public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
SPARCKind cmpSPARCKind = (SPARCKind) cmpKind;
boolean mirrored = emitCompare(cmpSPARCKind, left, right);
Value actualTrueValue = trueValue;
Value actualFalseValue = falseValue;
SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind();
CMOV cmove;
if (valueKind.isFloat()) {
actualTrueValue = load(trueValue);
actualFalseValue = load(falseValue);
cmove = valueKind.equals(SINGLE) ? FMOVSCC : FMOVDCC;
} else if (valueKind.isInteger()) {
actualTrueValue = loadSimm11(trueValue);
actualFalseValue = loadSimm11(falseValue);
cmove = MOVicc;
} else {
throw GraalError.shouldNotReachHere();
}
Variable result = newVariable(trueValue.getValueKind());
ConditionFlag finalCondition = SPARCControlFlow.fromCondition(cmpSPARCKind.isInteger(), mirrored ? cond.mirror() : cond, unorderedIsTrue);
CC cc = CC.forKind(cmpSPARCKind);
append(new CondMoveOp(cmove, cc, finalCondition, actualTrueValue, actualFalseValue, result));
return result;
}
protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
boolean mirrored;
if (cmpKind.isInteger()) {
mirrored = emitIntegerCompare(cmpKind, a, b);
} else if (cmpKind.isFloat()) {
mirrored = false;
emitFloatCompare(cmpKind, a, b, Fcc0);
} else {
throw GraalError.shouldNotReachHere();
}
return mirrored;
}
private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) {
boolean mirrored;
assert cmpKind.isInteger();
AllocatableValue left;
Value right;
if (LIRValueUtil.isVariable(b)) {
left = load(b);
right = loadSimm13(a);
mirrored = true;
} else {
left = load(a);
right = loadSimm13(b);
mirrored = false;
}
int compareBytes = cmpKind.getSizeInBytes();
if (compareBytes < left.getPlatformKind().getSizeInBytes()) {
left = asAllocatable(arithmeticLIRGen.emitSignExtend(left, cmpKind.getSizeInBits(), XWORD.getSizeInBits()));
}
if (compareBytes < right.getPlatformKind().getSizeInBytes()) {
right = arithmeticLIRGen.emitSignExtend(right, cmpKind.getSizeInBits(), XWORD.getSizeInBits());
}
append(SPARCOP3Op.newBinaryVoid(Subcc, left, right));
return mirrored;
}
private void emitFloatCompare(SPARCKind cmpJavaKind, Value a, Value b, CC cc) {
Opfs floatCompareOpcode;
assert cmpJavaKind.isFloat();
switch (cmpJavaKind) {
case DOUBLE:
floatCompareOpcode = Fcmpd;
break;
case SINGLE:
floatCompareOpcode = Fcmps;
break;
default:
throw GraalError.shouldNotReachHere();
}
append(new SPARCFloatCompareOp(floatCompareOpcode, cc, load(a), load(b)));
}
@Override
public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
emitIntegerTest(left, right);
Variable result = newVariable(trueValue.getValueKind());
ConditionFlag flag = SPARCControlFlow.fromCondition(true, Condition.EQ, false);
CC cc = CC.forKind(left.getPlatformKind());
append(new CondMoveOp(MOVicc, cc, flag, loadSimm11(trueValue), loadSimm11(falseValue), result));
return result;
}
@Override
protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
long maxOffset = linkage.getMaxCallTargetOffset();
if (SPARCAssembler.isWordDisp30(maxOffset)) {
append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
} else {
append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
}
}
@Override
public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
Variable scratchValue = newVariable(key.getValueKind());
AllocatableValue base = AllocatableValue.ILLEGAL;
for (Constant c : strategy.getKeyConstants()) {
if (!getMoveFactory().canInlineConstant(c)) {
base = constantTableBaseProvider.getConstantTableBase();
break;
}
}
append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue));
}
protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
}
@Override
protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
Variable tmp = newVariable(key.getValueKind());
emitMove(tmp, key);
append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().arch.getWordKind()))));
}
protected SPARC getArchitecture() {
return (SPARC) target().arch;
}
@Override
public Variable emitByteSwap(Value input) {
Variable result = newVariable(LIRKind.combine(input));
append(new SPARCByteSwapOp(this, result, asAllocatable(input)));
return result;
}
@Override
public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
Variable result = newVariable(LIRKind.value(SPARCKind.WORD));
append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length)));
return result;
}
@Override
public void emitMembar(int barriers) {
int necessaryBarriers = target().arch.requiredBarriers(barriers);
if (target().isMP && necessaryBarriers != 0) {
append(new MembarOp(necessaryBarriers));
}
}
@Override
public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
append(new ReturnOp(Value.ILLEGAL));
}
public Value emitSignExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) {
SPARCAddressValue loadAddress = asAddressValue(address);
Variable result = newVariable(resultKind);
append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state, true));
return result;
}
public Value emitZeroExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) {
SPARCAddressValue loadAddress = asAddressValue(address);
Variable result = newVariable(resultKind);
append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
return result;
}
@Override
public void emitNullCheck(Value address, LIRFrameState state) {
PlatformKind kind = address.getPlatformKind();
assert kind == XWORD : address + " - " + kind + " not an object!";
append(new NullCheckOp(asAddressValue(address), state));
}
public void emitLoadConstantTableBase() {
constantTableBaseProvider.constantTableBase = newVariable(LIRKind.value(XWORD));
int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size();
NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition));
loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBaseProvider.constantTableBase, placeHolder);
}
@Override
public void beforeRegisterAllocation() {
LIR lir = getResult().getLIR();
loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase);
}
@Override
public void emitPause() {
append(new SPARCPauseOp());
}
}