blob: 0023a12738c6965832923aca110f9a5739ac0396 [file] [log] [blame]
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
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;
/**
* This class implements the SPARC specific portion of the LIR generator.
*/
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());
}
}
/**
* The SPARC backend only uses WORD and DWORD values in registers because except to the ld/st
* instructions no instruction deals either with 32 or 64 bits. This function converts small
* integer kinds to WORD.
*/
@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) {
Value left;
Value right;
Condition actualCondition;
if (isJavaConstant(x)) {
left = load(y);
right = loadNonConst(x);
actualCondition = cond.mirror();
} else {
left = load(x);
right = loadNonConst(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), loadNonConst(a)));
} else {
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadNonConst(b)));
}
}
private Value loadSimm11(Value value) {
if (isJavaConstant(value)) {
JavaConstant c = asJavaConstant(value);
if (c.isNull() || SPARCAssembler.isSimm11(c)) {
return value;
}
}
return load(value);
}
@Override
public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
// Emit compare
SPARCKind cmpSPARCKind = (SPARCKind) cmpKind;
boolean mirrored = emitCompare(cmpSPARCKind, left, right);
// Emit move
Value actualTrueValue = trueValue;
Value actualFalseValue = falseValue;
SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind();
CMOV cmove;
if (valueKind.isFloat()) {
actualTrueValue = load(trueValue); // Floats cannot be immediate at all
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;
}
/**
* This method emits the compare instruction, and may reorder the operands. It returns true if
* it did so.
*
* @param cmpKind Kind how a and b have to be compared
* @param a the left operand of the comparison
* @param b the right operand of the comparison
* @return true if the left and right operands were switched, false otherwise
*/
protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) {
boolean mirrored;
if (cmpKind.isInteger()) { // Integer case
mirrored = emitIntegerCompare(cmpKind, a, b);
} else if (cmpKind.isFloat()) { // Float case
mirrored = false; // No mirroring done on floats
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();
Value left;
Value right;
if (LIRValueUtil.isVariable(b)) {
left = load(b);
right = loadNonConst(a);
mirrored = true;
} else {
left = load(a);
right = loadNonConst(b);
mirrored = false;
}
int compareBytes = cmpKind.getSizeInBytes();
// SPARC compares 32 or 64 bits
if (compareBytes < left.getPlatformKind().getSizeInBytes()) {
left = arithmeticLIRGen.emitSignExtend(left, compareBytes * 8, XWORD.getSizeInBytes() * 8);
}
if (compareBytes < right.getPlatformKind().getSizeInBytes()) {
right = arithmeticLIRGen.emitSignExtend(right, compareBytes * 8, XWORD.getSizeInBytes() * 8);
}
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) {
AllocatableValue scratchValue = newVariable(key.getValueKind());
AllocatableValue base = AllocatableValue.ILLEGAL;
for (Constant c : strategy.getKeyConstants()) {
if (!(c instanceof JavaConstant) || !getMoveFactory().canInlineConstant((JavaConstant) 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, AllocatableValue scratchValue) {
return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
}
@Override
protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
// Making a copy of the switch value is necessary because jump table destroys the input
// value
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, 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());
}
}