--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java 2016-12-07 13:48:11.137002238 -0800 @@ -0,0 +1,461 @@ +/* + * 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 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()); + } +}