--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java 2017-02-15 17:05:07.026683433 -0800 @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2013, 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.lir.sparc; + +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; +import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered; +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.LIRInstruction.OperandFlag.CONST; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; +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.Label; +import org.graalvm.compiler.asm.sparc.SPARCAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; +import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.sparc.SPARC; + +public class SPARCArithmetic { + public static final class FloatConvertOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatConvertOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(5); + + @Opcode private final FloatConvert opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG}) protected Value x; + + public enum FloatConvert { + F2I, + D2I, + F2L, + D2L + } + + public FloatConvertOp(FloatConvert opcode, Value x, Value result) { + super(TYPE, SIZE); + this.opcode = opcode; + this.x = x; + this.result = result; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Label notOrdered = new Label(); + switch (opcode) { + case F2L: + masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE)); + masm.fxtod(asRegister(result), asRegister(result)); + masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); + masm.bind(notOrdered); + break; + case F2I: + masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE)); + masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.bind(notOrdered); + break; + case D2L: + masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE)); + masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE)); + masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); + masm.bind(notOrdered); + break; + case D2I: + masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); + FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); + masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE)); + masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); + masm.bind(notOrdered); + break; + default: + throw GraalError.shouldNotReachHere("missing: " + opcode); + } + } + } + + /** + * Special LIR instruction as it requires a bunch of scratch registers. + */ + public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RemOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(4); + + @Opcode private final Rem opcode; + @Def({REG}) protected Value result; + @Alive({REG, CONST}) protected Value x; + @Alive({REG, CONST}) protected Value y; + @Temp({REG}) protected Value scratch1; + @Temp({REG}) protected Value scratch2; + @State protected LIRFrameState state; + + public enum Rem { + IUREM, + LUREM + } + + public RemOp(Rem opcode, Value result, Value x, Value y, Value scratch1, Value scratch2, LIRFrameState state) { + super(TYPE, SIZE); + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + this.scratch1 = scratch1; + this.scratch2 = scratch2; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + if (!isJavaConstant(x) && isJavaConstant(y)) { + assert isSimm13(crb.asIntConst(y)); + assert !x.equals(scratch1); + assert !x.equals(scratch2); + assert !y.equals(scratch1); + switch (opcode) { + case LUREM: + crb.recordImplicitException(masm.position(), state); + masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD)); + masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD)); + getDelayedControlTransfer().emitControlTransfer(crb, masm); + masm.sub(asRegister(x, XWORD), asRegister(scratch2, XWORD), asRegister(result, XWORD)); + break; + case IUREM: + GraalError.unimplemented(); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } else if (isRegister(x) && isRegister(y)) { + Value xLeft = x; + switch (opcode) { + case LUREM: + if (isJavaConstant(x)) { + masm.setx(crb.asLongConst(x), asRegister(scratch2, XWORD), false); + xLeft = scratch2; + } + assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD)); + assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD)); + crb.recordImplicitException(masm.position(), state); + masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); + masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); + getDelayedControlTransfer().emitControlTransfer(crb, masm); + masm.sub(asRegister(xLeft, XWORD), asRegister(scratch1, XWORD), asRegister(result, XWORD)); + break; + case IUREM: + assert !asRegister(result, WORD).equals(asRegister(scratch1, WORD)); + assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD)); + masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD)); + masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD)); + crb.recordImplicitException(masm.position(), state); + masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD)); + masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD)); + getDelayedControlTransfer().emitControlTransfer(crb, masm); + masm.sub(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(result, WORD)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } else { + throw GraalError.shouldNotReachHere(); + } + } + } + + public static final class SPARCIMulccOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCIMulccOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(10); + @Def({REG}) protected Value result; + @Alive({REG}) protected Value x; + @Alive({REG}) protected Value y; + + public SPARCIMulccOp(Value result, Value x, Value y) { + super(TYPE, SIZE); + this.result = result; + this.x = x; + this.y = y; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + try (ScratchRegister tmpScratch = masm.getScratchRegister()) { + Register tmp = tmpScratch.getRegister(); + Register resultRegister = asRegister(result, WORD); + Register xRegister = asRegister(x, WORD); + Register yRegister = asRegister(y, WORD); + masm.sra(xRegister, 0, xRegister); + masm.sra(yRegister, 0, yRegister); + masm.mulx(xRegister, yRegister, resultRegister); + Label noOverflow = new Label(); + masm.sra(resultRegister, 0, tmp); + masm.compareBranch(tmp, resultRegister, Equal, Xcc, noOverflow, PREDICT_TAKEN, null); + masm.wrccr(SPARC.g0, 1 << (SPARCAssembler.CCR_ICC_SHIFT + SPARCAssembler.CCR_V_SHIFT)); + masm.bind(noOverflow); + } + } + } + + /** + * Calculates the product and condition code for long multiplication of long values. + */ + public static final class SPARCLMulccOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCLMulccOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(13); + + @Def({REG}) protected Value result; + @Alive({REG}) protected Value x; + @Alive({REG}) protected Value y; + @Temp({REG}) protected Value scratch1; + @Temp({REG}) protected Value scratch2; + + public SPARCLMulccOp(Value result, Value x, Value y, LIRGeneratorTool gen) { + super(TYPE, SIZE); + this.result = result; + this.x = x; + this.y = y; + this.scratch1 = gen.newVariable(LIRKind.combine(x, y)); + this.scratch2 = gen.newVariable(LIRKind.combine(x, y)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Label noOverflow = new Label(); + masm.mulx(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); + + // Calculate the upper 64 bit signed := (umulxhi product - (x{63}&y + y{63}&x)) + masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); + masm.srax(asRegister(x, XWORD), 63, asRegister(scratch2, XWORD)); + masm.and(asRegister(scratch2, XWORD), asRegister(y, XWORD), asRegister(scratch2, XWORD)); + masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); + + masm.srax(asRegister(y, XWORD), 63, asRegister(scratch2, XWORD)); + masm.and(asRegister(scratch2, XWORD), asRegister(x, XWORD), asRegister(scratch2, XWORD)); + masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); + + // Now construct the lower half and compare + masm.srax(asRegister(result, XWORD), 63, asRegister(scratch2, XWORD)); + masm.cmp(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD)); + BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_TAKEN, noOverflow); + masm.nop(); + masm.wrccr(g0, 1 << (CCR_XCC_SHIFT + CCR_V_SHIFT)); + masm.bind(noOverflow); + } + } + + public static final class MulHighOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MulHighOp.class); + public static final SizeEstimate SIZE = SizeEstimate.create(4); + + @Opcode private final MulHigh opcode; + @Def({REG}) public AllocatableValue result; + @Alive({REG}) public AllocatableValue x; + @Alive({REG}) public AllocatableValue y; + @Temp({REG}) public AllocatableValue scratch; + + public enum MulHigh { + IMUL, + LMUL + } + + public MulHighOp(MulHigh opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) { + super(TYPE, SIZE); + this.opcode = opcode; + this.x = x; + this.y = y; + this.scratch = scratch; + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + assert isRegister(x) && isRegister(y) && isRegister(result) && isRegister(scratch); + switch (opcode) { + case IMUL: + masm.sra(asRegister(x), 0, asRegister(x)); + masm.sra(asRegister(y), 0, asRegister(y)); + masm.mulx(asRegister(x, WORD), asRegister(y, WORD), asRegister(result, WORD)); + masm.srax(asRegister(result, WORD), 32, asRegister(result, WORD)); + break; + case LMUL: + assert !asRegister(scratch, XWORD).equals(asRegister(result, XWORD)); + masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); + + masm.srlx(asRegister(x, XWORD), 63, asRegister(scratch, XWORD)); + masm.mulx(asRegister(scratch, XWORD), asRegister(y, XWORD), asRegister(scratch, XWORD)); + masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); + + masm.srlx(asRegister(y, XWORD), 63, asRegister(scratch, XWORD)); + masm.mulx(asRegister(scratch, XWORD), asRegister(x, XWORD), asRegister(scratch, XWORD)); + masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); + break; + default: + throw GraalError.shouldNotReachHere(); + } + } + } +}