# HG changeset patch # User Stefan Anzinger # Date 1410836816 25200 # Node ID 881fa8b6ca9dfcdb6eb6d2ba2e51847b16824f19 # Parent fe935dbf9863d81df9f78b8d76b75ab02c7a1f51# Parent dbb08e742d872243e5639518f88c0456b4a9ea3b Merge diff -r dbb08e742d87 -r 881fa8b6ca9d graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Mon Sep 15 17:16:53 2014 +0200 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Mon Sep 15 20:06:56 2014 -0700 @@ -85,6 +85,8 @@ return Fmt00a.read(masm, pos); case Bp: return Fmt00c.read(masm, pos); + case Bpr: + return Fmt00d.read(masm, pos); default: throw GraalInternalError.shouldNotReachHere("Unknown op2 " + op2); } @@ -481,16 +483,112 @@ } } - public static class Fmt00d { - - public Fmt00d(SPARCAssembler masm, int op, int a, int rcond, int op2, int d16hi, int predict, int rs1, int d16lo) { - assert predict == 0 || predict == 1; - assert rcond >= 0 && rcond < 0x8; - assert op == 0; - assert op2 >= 0 && op2 < 0x8; - assert rs1 >= 0 && rs1 < 0x20; - - masm.emitInt(op << 30 | a << 29 | rcond << 25 | op2 << 22 | d16hi & 3 | predict << 18 | rs1 << 14 | (d16lo & 0x003fff)); + // @formatter:off + /** + * Instruction format for Branch on Integer Register with Prediction. + * + * |00 |a |- |rcond | 011 |d16hi|p | rs1 | d16lo | + * |31 30|29|28|27 25|24 22|21 20|19|18 14| 0| + */ + // @formatter:on + public static class Fmt00d extends Fmt00 { + + private static final int A_SHIFT = 29; + private static final int RCOND_SHIFT = 25; + private static final int D16HI_SHIFT = 20; + private static final int P_SHIFT = 19; + private static final int RS1_SHIFT = 14; + private static final int D16LO_SHIFT = 0; + + // @formatter:off + private static final int A_MASK = 0b0010_0000_0000_0000_0000_0000_0000_0000; + private static final int RCOND_MASK = 0b0000_1110_0000_0000_0000_0000_0000_0000; + private static final int D16HI_MASK = 0b0000_0000_0011_0000_0000_0000_0000_0000; + private static final int P_MASK = 0b0000_0000_0000_1000_0000_0000_0000_0000; + private static final int RS1_MASK = 0b0000_0000_0000_0111_1100_0000_0000_0000; + private static final int D16LO_MASK = 0b0000_0000_0000_0000_0011_1111_1111_1111; + // @formatter:on + + private int annul; + private int rCondition; + private int disp16; + private int predictTaken; + private int rs1; + private Label label; + + public Fmt00d(int op2, int rCondition, int predictTaken, int annul, int d16, int rs1, Label label) { + super(op2); + this.annul = annul; + this.rCondition = rCondition; + this.disp16 = d16; + this.predictTaken = predictTaken; + this.rs1 = rs1; + this.label = label; + } + + @Override + public void setImm(int imm) { + setDisp16(imm); + } + + public void setDisp16(int disp16) { + this.disp16 = disp16 >> 2; + } + + public void emit(SPARCAssembler masm) { + if (label != null) { + final int pos = label.isBound() ? label.position() : patchUnbound(masm, label); + final int disp = pos - masm.position(); + setDisp16(disp); + } + verify(); + masm.emitInt(getInstructionBits()); + } + + private static int patchUnbound(SPARCAssembler masm, Label label) { + label.addPatchAt(masm.position()); + return 0; + } + + @Override + protected int getInstructionBits() { + int d16Split = 0; + d16Split |= (disp16 & 0b1100_0000_0000_0000) << D16HI_SHIFT - 14; + d16Split |= (disp16 & 0b0011_1111_1111_1111) << D16LO_SHIFT; + return super.getInstructionBits() | annul << A_SHIFT | rCondition << RCOND_SHIFT | d16Split | predictTaken << P_SHIFT | rs1 << RS1_SHIFT; + } + + public static Fmt00d read(SPARCAssembler masm, int pos) { + final int inst = masm.getInt(pos); + + // Make sure it's the right instruction: + final int op = (inst & OP_MASK) >> OP_SHIFT; + assert op == Ops.BranchOp.getValue(); + + // Get the instruction fields: + final int a = (inst & A_MASK) >> A_SHIFT; + final int cond = (inst & RCOND_MASK) >> RCOND_SHIFT; + final int op2 = (inst & OP2_MASK) >> OP2_SHIFT; + final int p = (inst & P_MASK) >> P_SHIFT; + final int rs1 = (inst & RS1_MASK) >> RS1_SHIFT; + final int d16hi = (inst & D16HI_MASK) >> D16HI_SHIFT; + assert (d16hi & ~0b11) == 0; + final int d16lo = (inst & D16LO_MASK) >> D16LO_SHIFT; + assert (d16lo & ~((1 << 14) - 1)) == 0; + final int d16 = (short) (((d16hi << 14) | d16lo) << 2); // sign extend + Fmt00d fmt = new Fmt00d(op2, cond, p, a, d16, rs1, null); + fmt.verify(); + return fmt; + } + + @Override + public void verify() { + super.verify(); + assert (annul & ~1) == 0 : annul; + assert (rCondition & ~0b111) == 0 : rCondition; + assert isSimm(disp16, 16) : disp16; + assert (predictTaken & ~1) == 0 : predictTaken; + assert (rs1 & ~((1 << 5) - 1)) == 0 : rs1; } } @@ -1710,12 +1808,12 @@ public enum RCondition { // @formatter:off - Rc_z(1, "rc_z"), - Rc_lez(2, "rc_lez"), - Rc_lz(3, "rc_lz"), - Rc_nz(5, "rc_nz"), - Rc_gz(6, "rc_gz"), - Rc_gez(7, "rc_gez"), + Rc_z(0b001, "rc_z"), + Rc_lez(0b010, "rc_lez"), + Rc_lz(0b011, "rc_lz"), + Rc_nz(0b101, "rc_nz"), + Rc_gz(0b110, "rc_gz"), + Rc_gez(0b111, "rc_gez"), Rc_last(Rc_gez.getValue(), "rc_last"); // @formatter:on @@ -2050,6 +2148,12 @@ } } + public static class Bpr extends Fmt00d { + public Bpr(RCondition rcond, boolean annul, boolean predictTaken, Register rs1, Label label) { + super(Op2s.Bpr.getValue(), rcond.getValue(), predictTaken ? 1 : 0, annul ? 1 : 0, 0, rs1.encoding(), label); + } + } + public static class Bpa extends Fmt00c { public Bpa(int simm19) { @@ -2089,6 +2193,14 @@ super(0, ConditionFlag.Equal, Op2s.Bp, cc, 1, simm19); } + public Bpe(CC cc, Label label, boolean predictTaken) { + super(0, ConditionFlag.Equal, Op2s.Bp, cc, predictTaken ? 1 : 0, label); + } + + public Bpe(boolean annul, CC cc, Label label, boolean predictTaken) { + super(annul ? 1 : 0, ConditionFlag.Equal, Op2s.Bp, cc, predictTaken ? 1 : 0, label); + } + public Bpe(CC cc, Label label) { super(0, ConditionFlag.Equal, Op2s.Bp, cc, 1, label); } @@ -2136,6 +2248,10 @@ public Bpl(CC cc, Label label) { super(0, ConditionFlag.Less, Op2s.Bp, cc, 1, label); } + + public Bpl(CC cc, boolean annul, boolean predictTaken, Label label) { + super(annul ? 1 : 0, ConditionFlag.Less, Op2s.Bp, cc, predictTaken ? 1 : 0, label); + } } public static class Bple extends Fmt00c { @@ -2147,6 +2263,10 @@ public Bple(CC cc, Label label) { super(0, ConditionFlag.LessEqual, Op2s.Bp, cc, 1, label); } + + public Bple(CC cc, boolean annul, boolean predictTaken, Label label) { + super(annul ? 1 : 0, ConditionFlag.LessEqual, Op2s.Bp, cc, predictTaken ? 1 : 0, label); + } } public static class Bpleu extends Fmt00c { @@ -2180,6 +2300,10 @@ public Bpne(CC cc, Label label) { super(0, ConditionFlag.NotZero, Op2s.Bp, cc, 1, label); } + + public Bpne(CC cc, boolean annul, boolean predictTaken, Label label) { + super(annul ? 1 : 0, ConditionFlag.NotZero, Op2s.Bp, cc, predictTaken ? 1 : 0, label); + } } public static class Bpneg extends Fmt00c { @@ -3615,6 +3739,13 @@ } } + public static class Ldub extends Fmt11 { + + public Ldub(SPARCAddress src, Register dst) { + super(Op3s.Ldub, src, dst); + } + } + public static class Ldsw extends Fmt11 { public Ldsw(SPARCAddress src, Register dst) { diff -r dbb08e742d87 -r 881fa8b6ca9d graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon Sep 15 17:16:53 2014 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon Sep 15 20:06:56 2014 -0700 @@ -44,7 +44,6 @@ import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg; import com.oracle.graal.lir.sparc.SPARCArithmetic.MulHighOp; import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp; -//import com.oracle.graal.lir.sparc.SPARCArithmetic.ShiftOp; import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op; import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp; @@ -458,8 +457,9 @@ @Override public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + Variable result = newVariable(LIRKind.value(Kind.Int)); + append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length))); + return result; } @Override @@ -871,8 +871,13 @@ append(new MoveFpGp(dst, src, tempSlot)); } + private StackSlot tmp; + private StackSlot getTempSlot(LIRKind kind) { - return getResult().getFrameMap().allocateSpillSlot(kind); + if (tmp == null) { + tmp = getResult().getFrameMap().allocateSpillSlot(kind); + } + return tmp; } protected SPARC getArchitecture() { diff -r dbb08e742d87 -r 881fa8b6ca9d graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java Mon Sep 15 20:06:56 2014 -0700 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2013, 2014, 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 com.oracle.graal.lir.sparc; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.common.UnsafeAccess.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; +import static com.oracle.graal.sparc.SPARC.*; +import static com.oracle.graal.asm.sparc.SPARCAssembler.*; +import static com.oracle.graal.asm.sparc.SPARCAssembler.CC.*; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cmp; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Nop; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.gen.*; + +/** + * Emits code which compares two arrays of the same length. + */ +@Opcode("ARRAY_EQUALS") +public class SPARCArrayEqualsOp extends SPARCLIRInstruction { + + private final Kind kind; + private final int arrayBaseOffset; + private final int arrayIndexScale; + + @Def({REG}) protected Value resultValue; + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Alive({REG}) protected Value lengthValue; + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + @Temp({REG}) protected Value temp3; + @Temp({REG}) protected Value temp4; + @Temp({REG}) protected Value temp5; + + public SPARCArrayEqualsOp(LIRGeneratorTool tool, Kind kind, Value result, Value array1, Value array2, Value length) { + this.kind = kind; + + Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); + this.arrayBaseOffset = unsafe.arrayBaseOffset(arrayClass); + this.arrayIndexScale = unsafe.arrayIndexScale(arrayClass); + + this.resultValue = result; + this.array1Value = array1; + this.array2Value = array2; + this.lengthValue = length; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind)); + this.temp2 = tool.newVariable(LIRKind.derivedReference(tool.target().wordKind)); + this.temp3 = tool.newVariable(LIRKind.value(tool.target().wordKind)); + this.temp4 = tool.newVariable(LIRKind.value(tool.target().wordKind)); + this.temp5 = tool.newVariable(LIRKind.value(tool.target().wordKind)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register result = asRegister(resultValue); + Register array1 = asRegister(temp1); + Register array2 = asRegister(temp2); + Register length = asRegister(temp3); + + Label trueLabel = new Label(); + Label falseLabel = new Label(); + Label done = new Label(); + + // Load array base addresses. + new Add(asObjectReg(array1Value), arrayBaseOffset, array1).emit(masm); + new Add(asObjectReg(array2Value), arrayBaseOffset, array2).emit(masm); + + // Get array length in bytes. + new Mulx(asIntReg(lengthValue), arrayIndexScale, length).emit(masm); + new Mov(length, result).emit(masm); // copy + + emit8ByteCompare(masm, result, array1, array2, length, trueLabel, falseLabel); + emitTailCompares(masm, result, array1, array2, trueLabel, falseLabel); + + // Return true + masm.bind(trueLabel); + new Mov(1, result).emit(masm); + new Bpa(done).emit(masm); + new Nop().emit(masm); + + // Return false + masm.bind(falseLabel); + new Mov(g0, result).emit(masm); + + // That's it + masm.bind(done); + } + + /** + * Vector size used in {@link #emit8ByteCompare}. + */ + private static final int VECTOR_SIZE = 8; + + /** + * Emits code that uses 8-byte vector compares. + */ + private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label loop = new Label(); + Label compareTail = new Label(); + + Register tempReg1 = asRegister(temp4); + Register tempReg2 = asRegister(temp5); + new And(result, VECTOR_SIZE - 1, result).emit(masm); // tail count (in bytes) + new Andcc(length, ~(VECTOR_SIZE - 1), length).emit(masm); // vector count (in bytes) + new Bpe(CC.Xcc, compareTail).emit(masm); + new Nop().emit(masm); + + new Add(array1, length, array1).emit(masm); + new Add(array2, length, array2).emit(masm); + new Sub(g0, length, length).emit(masm); + + // Load the first value from array 1 (Later done in back branch delay-slot) + new Ldx(new SPARCAddress(array1, length), tempReg1).emit(masm); + masm.bind(loop); + new Ldx(new SPARCAddress(array2, length), tempReg2).emit(masm); + + new Cmp(tempReg1, tempReg2).emit(masm); + new Bpne(Xcc, false, false, falseLabel).emit(masm); + // Delay slot, not annul, add for next iteration + new Add(length, VECTOR_SIZE, length).emit(masm); + + new Bpr(RCondition.Rc_nz, true, true, length, loop).emit(masm); + new Ldx(new SPARCAddress(array1, length), tempReg1).emit(masm); // Load in delay slot + + // Tail count zero, therefore we can go to the end + new Bpr(RCondition.Rc_z, true, true, result, trueLabel).emit(masm); + new Nop().emit(masm); + + masm.bind(compareTail); + } + + /** + * Emits code to compare the remaining 1 to 4 bytes. + */ + private void emitTailCompares(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Label trueLabel, Label falseLabel) { + Label compare2Bytes = new Label(); + Label compare1Byte = new Label(); + + Register tempReg1 = asRegister(temp3); + Register tempReg2 = asRegister(temp4); + + if (kind.getByteCount() <= 4) { + // Compare trailing 4 bytes, if any. + new Cmp(result, 4).emit(masm); + new Bpl(Xcc, false, false, compare2Bytes).emit(masm); + new Nop().emit(masm); + new Lduw(new SPARCAddress(array1, 0), tempReg1).emit(masm); + new Lduw(new SPARCAddress(array2, 0), tempReg2).emit(masm); + new Cmp(tempReg1, tempReg2).emit(masm); + + new Bpne(Xcc, false, false, falseLabel).emit(masm); + new Nop().emit(masm); + + if (kind.getByteCount() <= 2) { + // Move array pointers forward. + new Add(array1, 4, array1).emit(masm); + new Add(array2, 4, array2).emit(masm); + new Sub(result, 4, result).emit(masm); + + // Compare trailing 2 bytes, if any. + masm.bind(compare2Bytes); + + new Cmp(result, 2).emit(masm); + new Bpl(Xcc, false, true, compare1Byte).emit(masm); + new Nop().emit(masm); + new Lduh(new SPARCAddress(array1, 0), tempReg1).emit(masm); + new Lduh(new SPARCAddress(array2, 0), tempReg2).emit(masm); + new Cmp(tempReg1, tempReg2).emit(masm); + new Bpne(Xcc, false, true, falseLabel).emit(masm); + new Nop().emit(masm); + + // The one-byte tail compare is only required for boolean and byte arrays. + if (kind.getByteCount() <= 1) { + // Move array pointers forward before we compare the last trailing byte. + new Add(array1, 2, array1).emit(masm); + new Add(array2, 2, array2).emit(masm); + new Sub(result, 2, result).emit(masm); + + // Compare trailing byte, if any. + masm.bind(compare1Byte); + new Cmp(result, 1).emit(masm); + new Bpne(Xcc, trueLabel).emit(masm); + new Nop().emit(masm); + new Ldub(new SPARCAddress(array1, 0), tempReg1).emit(masm); + new Ldub(new SPARCAddress(array2, 0), tempReg2).emit(masm); + new Cmp(tempReg1, tempReg2).emit(masm); + new Bpne(Xcc, falseLabel).emit(masm); + new Nop().emit(masm); + } else { + masm.bind(compare1Byte); + } + } else { + masm.bind(compare2Bytes); + } + } + } +} diff -r dbb08e742d87 -r 881fa8b6ca9d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java Mon Sep 15 17:16:53 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java Mon Sep 15 20:06:56 2014 -0700 @@ -28,7 +28,7 @@ /** * Substitutions for {@link java.util.Arrays} methods. */ -@ClassSubstitution(value = java.util.Arrays.class, defaultGuard = UnsafeSubstitutions.GetAndSetGuard.class) +@ClassSubstitution(value = java.util.Arrays.class) public class ArraysSubstitutions { @MethodSubstitution diff -r dbb08e742d87 -r 881fa8b6ca9d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Mon Sep 15 17:16:53 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Mon Sep 15 20:06:56 2014 -0700 @@ -35,7 +35,7 @@ /** * Substitutions for {@link java.lang.String} methods. */ -@ClassSubstitution(value = java.lang.String.class, defaultGuard = UnsafeSubstitutions.GetAndSetGuard.class) +@ClassSubstitution(value = java.lang.String.class) public class StringSubstitutions { /**