# HG changeset patch # User David Piorkowski # Date 1409070908 25200 # Node ID 7ef0a23555402c71734ccee51efa300dc145333f # Parent 5ed920f3aa1813ef4d2f66b5e278d40a6c0442e2# Parent 85020469ed2b7d334972f3e5dce9efffaeab9564 Merged. diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java --- a/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java Tue Aug 26 09:35:08 2014 -0700 @@ -22,6 +22,8 @@ */ package com.oracle.graal.asm.amd64.test; +import static org.junit.Assume.*; + import java.nio.*; import org.junit.*; @@ -35,6 +37,11 @@ public class SimpleAssemblerTest extends AssemblerTest { + @Before + public void assumeNotSparc() { + assumeFalse(System.getProperty("os.arch").toLowerCase().contains("sparc")); + } + @Test public void intTest() { CodeGenTest test = new CodeGenTest() { diff -r 5ed920f3aa18 -r 7ef0a2355540 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 Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Tue Aug 26 09:35:08 2014 -0700 @@ -77,6 +77,7 @@ final int inst = masm.getInt(pos); Op2s op2 = Op2s.byValue((inst&OP2_MASK) >> OP2_SHIFT); switch(op2) { + case Br: case Fb: return Fmt00b.read(masm, op2, pos); case Sethi: @@ -213,6 +214,10 @@ private static final int DISP22_MASK = 0b00000000001111111111111111111111; // @formatter:on + public Fmt00b(boolean annul, ConditionFlag cond, Op2s op2, Label label) { + this(annul ? 1 : 0, cond.getValue(), op2.getValue(), 0, label); + } + public Fmt00b(boolean annul, FCond cond, Op2s op2, Label label) { this(annul ? 1 : 0, cond.getValue(), op2.getValue(), 0, label); } @@ -810,14 +815,19 @@ } public void verify() { - assert ((rd << RD_SHIFT) & RD_MASK) == (rd << RD_SHIFT); - assert ((op3 << OP3_SHIFT) & OP3_MASK) == (op3 << OP3_SHIFT); - assert ((rs1 << RS1_SHIFT) & RS1_MASK) == (rs1 << RS1_SHIFT); - assert ((i << I_SHIFT) & I_MASK) == (i << I_SHIFT); - assert ((x << X_SHIFT) & X_MASK) == (x << X_SHIFT); - assert ((immAsi << IMM_ASI_SHIFT) & IMM_ASI_MASK) == (immAsi << IMM_ASI_SHIFT); - assert ((rs2 << RS2_SHIFT) & RS2_MASK) == (rs2 << RS2_SHIFT); - assert isSimm13(simm13); + assert ((rd << RD_SHIFT) & RD_MASK) == (rd << RD_SHIFT) : this; + assert ((op3 << OP3_SHIFT) & OP3_MASK) == (op3 << OP3_SHIFT) : this; + assert ((rs1 << RS1_SHIFT) & RS1_MASK) == (rs1 << RS1_SHIFT) : this; + assert ((i << I_SHIFT) & I_MASK) == (i << I_SHIFT) : this; + assert ((x << X_SHIFT) & X_MASK) == (x << X_SHIFT) : this; + assert ((immAsi << IMM_ASI_SHIFT) & IMM_ASI_MASK) == (immAsi << IMM_ASI_SHIFT) : this; + assert ((rs2 << RS2_SHIFT) & RS2_MASK) == (rs2 << RS2_SHIFT) : this; + assert isSimm13(simm13) : this; + } + + @Override + public String toString() { + return String.format("%s: [rd: 0x%x, op3: 0x%x, rs1: 0x%x, i: 0x%x, x: 0x%x, immAsi: 0x%x, rs2: 0x%x, simm13: 0x%x", getClass().getName(), rd, op3, rs1, i, x, immAsi, rs2, simm13); } } @@ -1432,7 +1442,8 @@ Movstouw(0x111, "movstouw"), Movstosw(0x113, "movstosw"), Movxtod(0x118, "movxtod"), - Movwtos(0x119, "movwtos"), + Movwtos(0b1_0001_1001, "movwtos"), + UMulxhi(0b0_0001_0110, "umulxhi"), // end VIS3 // start CAMMELLIA @@ -1682,6 +1693,18 @@ public String getOperator() { return operator; } + + public ConditionFlag negate() { + switch (this) { + case CarrySet: + return CarryClear; + case CarryClear: + return CarrySet; + default: + GraalInternalError.unimplemented(); + } + return null; + } } public enum RCondition { @@ -1978,6 +2001,13 @@ } } + public static class Umulxhi extends Fmt3p { + public Umulxhi(Register src1, Register src2, Register dst) { + /* VIS3 only */ + super(Ops.ArithOp, Op3s.Impdep1, Opfs.UMulxhi, src1, src2, dst); + } + } + public static class Movxtod extends Fmt3p { public Movxtod(Register src, Register dst) { /* VIS3 only */ @@ -2812,6 +2842,13 @@ } } + public static class Fsmuld extends Fmt3p { + + public Fsmuld(Register src1, Register src2, Register dst) { + super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fsmuld, src1, src2, dst); + } + } + public static class Fmul8x16 extends Fmt3p { public Fmul8x16(Register src1, Register src2, Register dst) { diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Tue Aug 26 09:35:08 2014 -0700 @@ -327,7 +327,7 @@ public void emit(SPARCMacroAssembler masm) { if (value == 0) { new Clr(dst).emit(masm); - } else if (-4095 <= value && value <= 4096) { + } else if (isSimm13(value)) { new Or(g0, value, dst).emit(masm); } else if (value >= 0 && ((value & 0x3FFF) == 0)) { new Sethi(hi22(value), dst).emit(masm); diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/AMD64AllocatorTest.java --- a/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/AMD64AllocatorTest.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/AMD64AllocatorTest.java Tue Aug 26 09:35:08 2014 -0700 @@ -32,7 +32,7 @@ @Before public void setUp() { - assumeTrue(isArchitecture("AMD64")); + assumeTrue(isArchitecture("x86_64")); } @Test diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/DominatorOptimizationProblem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/DominatorOptimizationProblem.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2014, 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.compiler.common.cfg; + +import java.util.*; +import java.util.stream.*; + +/** + * This class represents a dominator tree problem, i.e. a problem which can be solved by traversing + * the dominator (sub-)tree. + * + * @param An enum that describes the flags that can be associated with a block. + * @param An arbitrary cost type that is associated with a block. It is intended to carry + * information needed to calculate the solution. Note that {@code C} should not contain + * boolean flags. Use an enum entry in {@code E} instead. + */ +public abstract class DominatorOptimizationProblem, C> { + + private List> blocks; + private EnumMap flags; + private BlockMap costs; + + protected DominatorOptimizationProblem(Class flagType, AbstractControlFlowGraph cfg) { + this.blocks = cfg.getBlocks(); + flags = new EnumMap<>(flagType); + costs = new BlockMap<>(cfg); + assert verify(blocks); + } + + private static boolean verify(List> blocks) { + for (int i = 0; i < blocks.size(); i++) { + AbstractBlock block = blocks.get(i); + if (i != block.getId()) { + assert false : String.format("Id index mismatch @ %d vs. %s.getId()==%d", i, block, block.getId()); + return false; + } + } + return true; + } + + public final List> getBlocks() { + return blocks; + } + + public final AbstractBlock getBlockForId(int id) { + AbstractBlock block = blocks.get(id); + assert block.getId() == id : "wrong block-to-id mapping"; + return block; + } + + /** + * Sets a flag for a block. + */ + public final void set(E flag, AbstractBlock block) { + BitSet bitSet = flags.get(flag); + if (bitSet == null) { + bitSet = new BitSet(blocks.size()); + flags.put(flag, bitSet); + } + bitSet.set(block.getId()); + } + + /** + * Checks whether a flag is set for a block. + */ + public final boolean get(E flag, AbstractBlock block) { + BitSet bitSet = flags.get(flag); + return bitSet == null ? false : bitSet.get(block.getId()); + } + + /** + * Returns a {@linkplain Stream} of blocks for which {@code flag} is set. + */ + public final Stream> stream(E flag) { + return getBlocks().stream().filter(block -> get(flag, block)); + } + + /** + * Returns the cost object associated with {@code block}. Might return {@code null} if not set. + */ + public final C getCost(AbstractBlock block) { + C cost = costs.get(block); + return cost; + } + + /** + * Sets the cost for a {@code block}. + */ + public final void setCost(AbstractBlock block, C cost) { + costs.put(block, cost); + } + + /** + * Sets {@code flag} for all blocks along the dominator path from {@code block} to the root + * until a block it finds a block where {@code flag} is already set. + */ + public final void setDominatorPath(E flag, AbstractBlock block) { + BitSet bitSet = flags.get(flag); + if (bitSet == null) { + bitSet = new BitSet(blocks.size()); + flags.put(flag, bitSet); + } + for (AbstractBlock b = block; b != null && !bitSet.get(b.getId()); b = b.getDominator()) { + // mark block + bitSet.set(b.getId()); + } + } + + /** + * Returns a {@link Stream} of flags associated with {@code block}. + */ + public final Stream getFlagsForBlock(AbstractBlock block) { + return getFlags().stream().filter(flag -> get(flag, block)); + } + + /** + * Returns the {@link Set} of flags that can be set for this + * {@linkplain DominatorOptimizationProblem problem}. + */ + public final Set getFlags() { + return flags.keySet(); + } + + /** + * Returns the name of a flag. + */ + public String getName(E flag) { + return flag.toString(); + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableCFG.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableCFG.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, 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.compiler.common.cfg; + +import java.util.*; +import java.util.function.*; + +/** + * Represents a control-flow graph where each node can be annotated with arbitrary property pairs of + * the form ({@linkplain String name}, {@linkplain String value}). + */ +public interface PrintableCFG { + + List> getBlocks(); + + /** + * Applies {@code action} to all extra property pairs (name, value) of {@code block}. + * + * @param block a block from {@link #getBlocks()}. + * @param action a {@link BiConsumer consumer}. + */ + default void forEachPropertyPair(AbstractBlock block, BiConsumer action) { + // no extra properties per default + } +} diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableDominatorOptimizationProblem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableDominatorOptimizationProblem.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, 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.compiler.common.cfg; + +import java.util.function.*; + +/** + * A {@linkplain PrintableCFG printable} {@link DominatorOptimizationProblem}. + */ +public abstract class PrintableDominatorOptimizationProblem, C extends PropertyConsumable> extends DominatorOptimizationProblem implements PrintableCFG { + + protected PrintableDominatorOptimizationProblem(Class keyType, AbstractControlFlowGraph cfg) { + super(keyType, cfg); + } + + public void forEachPropertyPair(AbstractBlock block, BiConsumer action) { + // for each flag + getFlags().forEach(flag -> ((BiConsumer) (name, value) -> action.accept(name, value ? "true" : "false")).accept(getName(flag), get(flag, block))); + // for each property + C cost = getCost(block); + if (cost != null) { + cost.forEachProperty((name, value) -> action.accept(name, value)); + } + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PropertyConsumable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PropertyConsumable.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014, 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.compiler.common.cfg; + +import java.util.function.*; + +public interface PropertyConsumable { + + void forEachProperty(BiConsumer action); +} diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java --- a/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java Tue Aug 26 09:35:08 2014 -0700 @@ -55,7 +55,7 @@ @Test public void test3() { - test("test3snippet", 4, 0, 0); + test("test3snippet", 3, 1, 0); } public static long test3snippet(long x) { diff -r 5ed920f3aa18 -r 7ef0a2355540 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 Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue Aug 26 09:35:08 2014 -0700 @@ -35,6 +35,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; @@ -232,7 +233,7 @@ break; case Float: case Double: - append(new BranchOp(cond, trueDestination, falseDestination, kind)); + append(new BranchOp(finalCondition, trueDestination, falseDestination, kind)); break; default: throw GraalInternalError.shouldNotReachHere("" + left.getKind()); @@ -241,8 +242,7 @@ @Override public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { - // append(new BranchOp(negated ? ConditionFlag.NoOverflow : ConditionFlag.Overflow, label)); - throw GraalInternalError.unimplemented(); + append(new BranchOp(ConditionFlag.CarrySet, overflow, noOverflow, Kind.Long)); } @Override @@ -308,10 +308,10 @@ switch ((Kind) cmpKind) { case Short: case Char: - append(new CompareOp(ICMP, emitZeroExtend(left, 16, 32), emitZeroExtend(right, 16, 32))); + append(new CompareOp(ICMP, emitSignExtend(left, 16, 32), emitSignExtend(right, 16, 32))); break; case Byte: - append(new CompareOp(ICMP, emitZeroExtend(left, 8, 32), emitZeroExtend(right, 8, 32))); + append(new CompareOp(ICMP, emitSignExtend(left, 8, 32), emitSignExtend(right, 8, 32))); break; case Int: append(new CompareOp(ICMP, left, right)); @@ -355,9 +355,7 @@ @Override public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { - // a temp is needed for loading long and object constants - boolean needsTemp = key.getKind() == Kind.Long || key.getKind() == Kind.Object; - append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getLIRKind()) : Value.ILLEGAL)); + append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getLIRKind()))); } @Override @@ -457,16 +455,16 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind().getStackKind()) { case Long: - append(new Op1Stack(LNEG, result, input)); + append(new Unary2Op(LNEG, result, load(input))); break; case Int: - append(new Op1Stack(INEG, result, input)); + append(new Unary2Op(INEG, result, load(input))); break; case Float: - append(new Op1Stack(FNEG, result, input)); + append(new Unary2Op(FNEG, result, load(input))); break; case Double: - append(new Op1Stack(DNEG, result, input)); + append(new Unary2Op(DNEG, result, load(input))); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -479,10 +477,10 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind().getStackKind()) { case Int: - append(new Op1Stack(INOT, result, input)); + append(new Unary2Op(INOT, result, load(input))); break; case Long: - append(new Op1Stack(LNOT, result, input)); + append(new Unary2Op(LNOT, result, load(input))); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -597,12 +595,33 @@ @Override public Value emitMulHigh(Value a, Value b) { - throw GraalInternalError.unimplemented(); + switch (a.getKind().getStackKind()) { + case Int: + return emitMulHigh(IMUL, a, b); + case Long: + return emitMulHigh(LMUL, a, b); + default: + throw GraalInternalError.shouldNotReachHere(); + } } @Override public Value emitUMulHigh(Value a, Value b) { - throw GraalInternalError.unimplemented(); + switch (a.getKind().getStackKind()) { + case Int: + return emitMulHigh(IUMUL, a, b); + case Long: + return emitMulHigh(LUMUL, a, b); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private Value emitMulHigh(SPARCArithmetic opcode, Value a, Value b) { + Variable result = newVariable(LIRKind.derive(a, b)); + MulHighOp mulHigh = new MulHighOp(opcode, load(a), load(b), result, newVariable(LIRKind.derive(a, b))); + append(mulHigh); + return result; } @Override @@ -665,10 +684,10 @@ Variable result = newVariable(LIRKind.derive(a, b)); switch (a.getKind().getStackKind()) { case Int: - append(new RemOp(IUREM, result, a, loadNonConst(b), state, this)); + append(new RemOp(IUREM, result, load(a), load(b), state, this)); break; case Long: - append(new RemOp(LUREM, result, a, loadNonConst(b), state, this)); + append(new RemOp(LUREM, result, load(a), loadNonConst(b), state, this)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -680,9 +699,13 @@ @Override public Value emitUDiv(Value a, Value b, LIRFrameState state) { SPARCArithmetic op; + Value actualA = a; + Value actualB = b; switch (a.getKind().getStackKind()) { case Int: op = IUDIV; + actualA = emitZeroExtend(actualA, 32, 64); + actualB = emitZeroExtend(actualB, 32, 64); break; case Long: op = LUDIV; @@ -690,7 +713,7 @@ default: throw GraalInternalError.shouldNotReachHere(); } - return emitBinary(op, false, a, b, state); + return emitBinary(op, false, actualA, actualB, state); } @Override @@ -912,14 +935,14 @@ append(new BinaryRegConst(SPARCArithmetic.LAND, result, asAllocatable(inputVal), Constant.forLong(mask), null)); return result; } else { - assert inputVal.getKind() == Kind.Int || inputVal.getKind() == Kind.Short || inputVal.getKind() == Kind.Byte : inputVal.getKind(); + assert inputVal.getKind() == Kind.Int || inputVal.getKind() == Kind.Short || inputVal.getKind() == Kind.Byte || inputVal.getKind() == Kind.Char : inputVal.getKind(); Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); long mask = IntegerStamp.defaultMask(fromBits); - Constant constant = Constant.forLong(mask); - if (canInlineConstant(constant)) { + Constant constant = Constant.forInt((int) mask); + if (fromBits == 32) { + append(new ShiftOp(IUSHR, result, inputVal, Constant.forInt(0))); + } else if (canInlineConstant(constant)) { append(new BinaryRegConst(SPARCArithmetic.IAND, result, asAllocatable(inputVal), constant, null)); - } else if (fromBits == 32) { - append(new ShiftOp(IUSHR, result, inputVal, Constant.forInt(0))); } else { Variable maskVar = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); emitMove(maskVar, constant); diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Aug 26 09:35:08 2014 -0700 @@ -41,6 +41,7 @@ import com.oracle.graal.debug.internal.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.constopt.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; @@ -256,6 +257,15 @@ throw Debug.handle(e); } + if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) { + try (Scope s = Debug.scope("ConstantLoadOptimization", lir)) { + ConstantLoadOptimization.optimize(lirGenRes.getLIR(), lirGen); + Debug.dump(lir, "After constant load optimization"); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + try (Scope s = Debug.scope("Allocator", nodeLirGen)) { if (backend.shouldAllocateRegisters()) { new LinearScan(target, lir, frameMap).allocate(); diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Tue Aug 26 09:35:08 2014 -0700 @@ -929,6 +929,9 @@ private static DebugMetric createMetric(String format, Object arg1, Object arg2) { String name = formatDebugName(format, arg1, arg2); boolean conditional = enabledMetrics == null || !enabledMetrics.contains(name); + if (!ENABLED && conditional) { + return VOID_METRIC; + } return new MetricImpl(name, conditional); } @@ -1203,6 +1206,9 @@ private static DebugTimer createTimer(String format, Object arg1, Object arg2) { String name = formatDebugName(format, arg1, arg2); boolean conditional = enabledTimers == null || !enabledTimers.contains(name); + if (!ENABLED && conditional) { + return VOID_TIMER; + } return new TimerImpl(name, conditional); } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Tue Aug 26 09:35:08 2014 -0700 @@ -42,12 +42,12 @@ /** * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time. */ - private Node[] nodes; + Node[] nodes; /** * The number of valid entries in {@link #nodes}. */ - private int nodesSize; + int nodesSize; /** * Records the modification count for nodes. This is only used in assertions. @@ -562,56 +562,6 @@ return new Mark(this); } - private class NodeIterator implements Iterator { - - private int index; - - public NodeIterator() { - this(0); - } - - public NodeIterator(int index) { - this.index = index - 1; - forward(); - } - - private void forward() { - if (index < nodesSize) { - do { - index++; - } while (index < nodesSize && nodes[index] == null); - } - } - - @Override - public boolean hasNext() { - checkForDeletedNode(); - return index < nodesSize; - } - - private void checkForDeletedNode() { - if (index < nodesSize) { - while (index < nodesSize && nodes[index] == null) { - index++; - } - } - } - - @Override - public Node next() { - try { - return nodes[index]; - } finally { - forward(); - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - /** * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark() * mark}. @@ -622,7 +572,7 @@ @Override public Iterator iterator() { - return new NodeIterator(index); + return new GraphNodeIterator(Graph.this, index); } }; } @@ -637,7 +587,7 @@ @Override public Iterator iterator() { - return new NodeIterator(); + return new GraphNodeIterator(Graph.this); } @Override @@ -709,15 +659,17 @@ return true; } - private class TypedNodeIterator implements Iterator { + private static class TypedNodeIterator implements Iterator { + private final Graph graph; private final int[] ids; private final Node[] current; private int currentIdIndex; private boolean needsForward; - public TypedNodeIterator(NodeClass clazz) { + public TypedNodeIterator(NodeClass clazz, Graph graph) { + this.graph = graph; ids = clazz.iterableIds(); currentIdIndex = 0; current = new Node[ids.length]; @@ -743,7 +695,7 @@ return current(); } - private Node skipDeleted(Node node) { + private static Node skipDeleted(Node node) { Node n = node; while (n != null && n.isDeleted()) { n = n.typeCacheNext; @@ -757,7 +709,7 @@ while (true) { Node next; if (current() == PLACE_HOLDER) { - next = getStartNode(ids[currentIdIndex]); + next = graph.getStartNode(ids[currentIdIndex]); } else { next = current().typeCacheNext; } @@ -821,7 +773,7 @@ @Override public Iterator iterator() { - return new TypedNodeIterator<>(nodeClass); + return new TypedNodeIterator<>(nodeClass, Graph.this); } }; } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphNodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphNodeIterator.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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.graph; + +import java.util.*; + +/** + * Iterates over the nodes in a given graph. + */ +class GraphNodeIterator implements Iterator { + + private final Graph graph; + private int index; + + public GraphNodeIterator(Graph graph) { + this(graph, 0); + } + + public GraphNodeIterator(Graph graph, int index) { + this.graph = graph; + this.index = index - 1; + forward(); + } + + private void forward() { + if (index < graph.nodesSize) { + do { + index++; + } while (index < graph.nodesSize && graph.nodes[index] == null); + } + } + + @Override + public boolean hasNext() { + checkForDeletedNode(); + return index < graph.nodesSize; + } + + private void checkForDeletedNode() { + while (index < graph.nodesSize && graph.nodes[index] == null) { + index++; + } + } + + @Override + public Node next() { + try { + return graph.nodes[index]; + } finally { + forward(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Aug 26 09:35:08 2014 -0700 @@ -152,16 +152,16 @@ // therefore points to the next Node of the same type. Node typeCacheNext; - private static final int INLINE_USAGE_COUNT = 2; + static final int INLINE_USAGE_COUNT = 2; private static final Node[] NO_NODES = {}; /** * Head of usage list. The elements of the usage list in order are {@link #usage0}, * {@link #usage1} and {@link #extraUsages}. The first null entry terminates the list. */ - private Node usage0; - private Node usage1; - private Node[] extraUsages; + Node usage0; + Node usage1; + Node[] extraUsages; private Node predecessor; @@ -210,95 +210,6 @@ return getNodeClass().getSuccessorIterable(this); } - class NodeUsageIterator implements java.util.Iterator { - - int index = -1; - Node current; - - private void advance() { - current = null; - index++; - if (index == 0) { - current = usage0; - } else if (index == 1) { - current = usage1; - } else { - if (index - INLINE_USAGE_COUNT < extraUsages.length) { - current = extraUsages[index - INLINE_USAGE_COUNT]; - } - } - } - - public NodeUsageIterator() { - advance(); - } - - public boolean hasNext() { - return current != null; - } - - public Node next() { - Node result = current; - if (result == null) { - throw new NoSuchElementException(); - } - advance(); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - class NodeUsageWithModCountIterator extends NodeUsageIterator { - - private final int expectedModCount = usageModCount(); - - @Override - public boolean hasNext() { - if (expectedModCount != usageModCount()) { - throw new ConcurrentModificationException(); - } - return super.hasNext(); - } - - @Override - public Node next() { - if (expectedModCount != usageModCount()) { - throw new ConcurrentModificationException(); - } - return super.next(); - } - } - - class NodeUsageIterable implements com.oracle.graal.graph.iterators.NodeIterable { - - public NodeUsageIterator iterator() { - if (MODIFICATION_COUNTS_ENABLED) { - return new NodeUsageWithModCountIterator(); - } else { - return new NodeUsageIterator(); - } - } - - @Override - public boolean isEmpty() { - return usage0 == null; - } - - @Override - public boolean isNotEmpty() { - return usage0 != null; - } - - @Override - public int count() { - return usageCount(); - } - } - int getUsageCountUpperBound() { assert recordsUsages(); if (usage0 == null) { @@ -315,7 +226,7 @@ */ public final NodeIterable usages() { assert recordsUsages() : this; - return new NodeUsageIterable(); + return new NodeUsageIterable(this); } /** @@ -392,7 +303,7 @@ } } - private int usageCount() { + int usageCount() { if (usage0 == null) { return 0; } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsageIterable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsageIterable.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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.graph; + +import static com.oracle.graal.graph.Graph.*; + +import com.oracle.graal.graph.iterators.*; + +class NodeUsageIterable implements NodeIterable { + + final Node node; + + NodeUsageIterable(Node node) { + this.node = node; + } + + public NodeUsageIterator iterator() { + if (MODIFICATION_COUNTS_ENABLED) { + return new NodeUsageWithModCountIterator(node); + } else { + return new NodeUsageIterator(node); + } + } + + @Override + public boolean isEmpty() { + return node.usage0 == null; + } + + @Override + public boolean isNotEmpty() { + return node.usage0 != null; + } + + @Override + public int count() { + return node.usageCount(); + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsageIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsageIterator.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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.graph; + +import java.util.*; + +class NodeUsageIterator implements Iterator { + + final Node node; + int index = -1; + Node current; + + void advance() { + current = null; + index++; + if (index == 0) { + current = node.usage0; + } else if (index == 1) { + current = node.usage1; + } else { + if (index - Node.INLINE_USAGE_COUNT < node.extraUsages.length) { + current = node.extraUsages[index - Node.INLINE_USAGE_COUNT]; + } + } + } + + public NodeUsageIterator(Node node) { + this.node = node; + advance(); + } + + public boolean hasNext() { + return current != null; + } + + public Node next() { + Node result = current; + if (result == null) { + throw new NoSuchElementException(); + } + advance(); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsageWithModCountIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsageWithModCountIterator.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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.graph; + +import java.util.*; + +class NodeUsageWithModCountIterator extends NodeUsageIterator { + + public NodeUsageWithModCountIterator(Node n) { + super(n); + } + + private final int expectedModCount = node.usageModCount(); + + @Override + public boolean hasNext() { + if (expectedModCount != node.usageModCount()) { + throw new ConcurrentModificationException(); + } + return super.hasNext(); + } + + @Override + public Node next() { + if (expectedModCount != node.usageModCount()) { + throw new ConcurrentModificationException(); + } + return super.next(); + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Tue Aug 26 09:35:08 2014 -0700 @@ -26,11 +26,10 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.sparc.SPARC.*; +import static com.oracle.graal.compiler.common.UnsafeAccess.*; import java.util.*; -import sun.misc.*; - import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; @@ -61,8 +60,6 @@ */ public class SPARCHotSpotBackend extends HotSpotHostBackend { - private static final Unsafe unsafe = Unsafe.getUnsafe(); - public SPARCHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) { super(runtime, providers); } @@ -139,12 +136,18 @@ @Override public void enter(CompilationResultBuilder crb) { final int frameSize = crb.frameMap.totalFrameSize(); - + final int stackpoinerChange = -frameSize; SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; if (!isStub && pagesToBang > 0) { emitStackOverflowCheck(crb, pagesToBang, false); } - new Save(sp, -frameSize, sp).emit(masm); + + if (SPARCAssembler.isSimm13(stackpoinerChange)) { + new Save(sp, stackpoinerChange, sp).emit(masm); + } else { + new Setx(stackpoinerChange, g3).emit(masm); + new Save(sp, g3, sp).emit(masm); + } if (ZapStackOnMethodEntry.getValue()) { final int slotSize = 8; diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java Tue Aug 26 09:35:08 2014 -0700 @@ -29,12 +29,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCAssembler.CC; -import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag; -import com.oracle.graal.asm.sparc.SPARCAssembler.Jmpl; -import com.oracle.graal.asm.sparc.SPARCAssembler.Lduw; -import com.oracle.graal.asm.sparc.SPARCAssembler.Movcc; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cmp; +import com.oracle.graal.asm.sparc.SPARCAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -74,5 +70,6 @@ new Movcc(ConditionFlag.NotZero, CC.Icc, l7, sp).emit(masm); new Jmpl(asRegister(handlerInCallerPc), 0, g0).emit(masm); + new Nop().emit(masm); } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue Aug 26 09:35:08 2014 -0700 @@ -206,12 +206,15 @@ } public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { + Variable newValueTemp = newVariable(newValue.getLIRKind()); + emitMove(newValueTemp, newValue); + LIRKind kind = newValue.getLIRKind(); assert kind.equals(expectedValue.getLIRKind()); Kind memKind = (Kind) kind.getPlatformKind(); SPARCAddressValue addressValue = asAddressValue(address); - append(new CompareAndSwapOp(asAllocatable(addressValue), asAllocatable(expectedValue), asAllocatable(newValue))); - return emitConditionalMove(memKind, expectedValue, newValue, Condition.EQ, true, trueValue, falseValue); + append(new CompareAndSwapOp(asAllocatable(addressValue), asAllocatable(expectedValue), asAllocatable(newValueTemp))); + return emitConditionalMove(memKind, expectedValue, newValueTemp, Condition.EQ, true, trueValue, falseValue); } public StackSlot getDeoptimizationRescueSlot() { diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java Tue Aug 26 09:35:08 2014 -0700 @@ -36,6 +36,9 @@ @Opcode("LEAVE_CURRENT_STACK_FRAME") final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCLIRInstruction { + public SPARCHotSpotLeaveCurrentStackFrameOp() { + } + @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { // Save O registers over restore. diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java Tue Aug 26 09:35:08 2014 -0700 @@ -63,5 +63,7 @@ new Stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm); new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm); new Stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)).emit(masm); + + new Movdtox(f31, i0).emit(masm); } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Aug 26 09:35:08 2014 -0700 @@ -30,6 +30,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; @@ -85,8 +86,14 @@ private final Register[] cpuCalleeParameterRegisters = {i0, i1, i2, i3, i4, i5}; private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7}; - - private final Register[] callerSaveRegisters = {g1, g3, g4, g5, o0, o1, o2, o3, o4, o5, o7}; + // @formatter:off + private final Register[] callerSaveRegisters = + {g1, g3, g4, g5, o0, o1, o2, o3, o4, o5, o7, + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31}; + // @formatter:on /** * Registers saved by the callee. This lists all L and I registers which are saved in the @@ -238,10 +245,7 @@ if (locations[i] == null) { // Stack slot is always aligned to its size in bytes but minimum wordsize int typeSize = SPARC.spillSlotSize(target, kind); - int modulus = currentStackOffset % typeSize; - if (modulus != 0) { - currentStackOffset += typeSize - modulus; - } + currentStackOffset = NumUtil.roundUp(currentStackOffset, typeSize); locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), currentStackOffset, !type.out); currentStackOffset += typeSize; } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java Tue Aug 26 09:35:08 2014 -0700 @@ -28,6 +28,7 @@ import static com.oracle.graal.sparc.SPARC.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.asm.sparc.*; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov; import com.oracle.graal.hotspot.stubs.*; @@ -61,7 +62,7 @@ // Get return address (is in o7 after leave). Register returnAddress = asRegister(cc.getArgument(1)); - new Mov(o7, returnAddress).emit(masm); + new Add(o7, Return.PC_RETURN_OFFSET, returnAddress).emit(masm); Register scratch = g5; SPARCCall.indirectJmp(crb, masm, scratch, linkage); } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java Tue Aug 26 09:35:08 2014 -0700 @@ -223,25 +223,48 @@ int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + Unsigned vectorSize = Word.unsigned(VECTOR_SIZE); Unsigned srcOffset = Word.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize); Unsigned destOffset = Word.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize); Unsigned destStart = destOffset; - Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize); Unsigned destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); - Unsigned nonVectorBytes = sizeInBytes.unsignedRemainder(Word.unsigned(VECTOR_SIZE)); + Unsigned destVectorEnd = null; + Unsigned nonVectorBytes = null; + Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize); + if (supportsUnalignedMemoryAccess) { + nonVectorBytes = sizeInBytes.unsignedRemainder(vectorSize); + destVectorEnd = destEnd; + } else { + boolean inPhase = srcOffset.and((int) VECTOR_SIZE - 1).equal(destOffset.and((int) VECTOR_SIZE - 1)); + boolean hasAtLeastOneVector = sizeInBytes.aboveOrEqual(vectorSize); + // We must have at least one full vector, otherwise we must copy each byte separately + if (hasAtLeastOneVector && inPhase) { // If in phase, we can vectorize + nonVectorBytes = vectorSize.subtract(destStart.unsignedRemainder(vectorSize)); + } else { // fallback is byte-wise + nonVectorBytes = sizeInBytes; + } + destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(vectorSize)); + } + Unsigned destNonVectorEnd = destStart.add(nonVectorBytes); - while (destOffset.belowThan(destNonVectorEnd)) { ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION); destOffset = destOffset.add(1); srcOffset = srcOffset.add(1); } - while (destOffset.belowThan(destEnd)) { + // Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8)); + while (destOffset.belowThan(destVectorEnd)) { ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, ANY_LOCATION), ANY_LOCATION); destOffset = destOffset.add(wordSize()); srcOffset = srcOffset.add(wordSize()); } + // Do the last bytes each when it is required to have absolute alignment. + while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) { + ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } } public static class Templates extends AbstractTemplates { diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_ddiv.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_ddiv.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_ddiv.java Tue Aug 26 09:35:08 2014 -0700 @@ -39,4 +39,8 @@ runTest("test", 311.0D, 10D); } + @Test + public void run1() throws Throwable { + runTest("test", 311.0D, 0D); + } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_fdiv.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_fdiv.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_fdiv.java Tue Aug 26 09:35:08 2014 -0700 @@ -39,4 +39,8 @@ runTest("test", 311.0f, 10f); } + @Test + public void run1() throws Throwable { + runTest("test", 311.0f, 0f); + } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/IntegerBits.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/IntegerBits.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/IntegerBits.java Tue Aug 26 09:35:08 2014 -0700 @@ -103,4 +103,60 @@ public void run10() { runTest("test4", 0xffffffff); } + + @Test + public void run11() { + runTest("test2", 0xFFFFFFFF); + } + + @Test + public void run12() { + runTest("test2", 0x7FFFFFFF); + } + + @Test + public void run17() { + runTest("test2", 0x80000000); + } + + @Test + public void run18() { + runTest("test2", 0x40000000); + } + + @Test + public void run13() { + runTest("test3", 0x7FFFFFFF); + } + + @Test + public void run14() { + runTest("test3", 0xFFFFFFFF); + } + + @Test + public void run15() { + runTest("test3", 0x80000000); + } + + @Test + public void run16() { + runTest("test3", 0x40000000); + } + + @Test + public void run19() { + runTest("test4", 0x80000000); + } + + @Test + public void run20() { + runTest("test4", 0x40000000); + } + + @Test + public void run21() { + runTest("test4", 0x00000001); + } + } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigMixedParams04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigMixedParams04.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigMixedParams04.java Tue Aug 26 09:35:08 2014 -0700 @@ -53,6 +53,212 @@ return 42; } + /** + * Test SPARC mixed params with double/single float register overlapping + * + * @param f1 + * @param d2 + * @param f3 + * @return Must always return the argument d2 + */ + @SuppressWarnings("all") + public static double test2(int i1, float f1, double d2, float f3, + // @formatter:off + double ad1 , + double ad2 , + double ad3 , + double ad4 , + double ad5 , + double ad6 , + double ad7 , + double ad8 , + double ad9 , + double ad10, + double ad11, + double ad12, + double ad13, + double ad14, + double ad15, + double ad16, + float af1 , + float af2 , + float af3 , + float af4 , + float af5 , + float af6 , + float af7 , + float af8 , + float af9 , + float af10, + float af11, + float af12, + float af13, + float af14, + float af15, + float af16 + // @formatter:on + ) { + + // now do something with the locals to make sure the locals don't get optimized away. + for (int i = 0; i < i1; i++) { + af1 += f1; + af2 += f1; + af3 += f1; + af4 += f1; + af5 += f1; + af6 += f1; + af7 += f1; + af8 += f1; + af9 += f1; + af10 += f1; + af11 += f1; + af12 += f1; + af13 += f1; + af14 += f1; + af15 += f1; + af16 += f1; + ad1 += f1; + ad2 += f1; + ad3 += f1; + ad4 += f1; + ad5 += f1; + ad6 += f1; + ad7 += f1; + ad8 += f1; + ad9 += f1; + ad10 += f1; + ad11 += f1; + ad12 += f1; + ad13 += f1; + ad14 += f1; + ad15 += f1; + ad16 += f1; + } + // @formatter:off + boolean orderFloat = + af1 < af2 && + af2 < af3 && + af3 < af4 && + af4 < af5 && + af5 < af6 && + af6 < af7 && + af7 < af8 && + af8 < af9 && + af9 < af10 && + af10 < af11 && + af11 < af12 && + af12 < af13 && + af13 < af14 && + af14 < af15 && + af15 < af16; + boolean orderDouble = + ad1 < ad2 && + ad2 < ad3 && + ad3 < ad4 && + ad4 < ad5 && + ad5 < ad6 && + ad6 < ad7 && + ad7 < ad8 && + ad8 < ad9 && + ad9 < ad10 && + ad10 < ad11 && + ad11 < ad12 && + ad12 < ad13 && + ad13 < ad14 && + ad14 < ad15 && + ad15 < ad16; + // @formatter:on + if (orderDouble && orderFloat) { + return f1 + d2 + f3; // this should not be destroyed + } + Assert.fail(); + return 0.0; + } + + /** + * Test SPARC mixed params with double/single float register overlapping + * + * @param f1 + * @param d2 + * @param f3 + * @return Must always return the argument d2 + */ + @SuppressWarnings("all") + public static double test3(boolean f, int idx, + // @formatter:off + double ad1 , + double ad2 , + double ad3 , + double ad4 , + double ad5 , + double ad6 , + double ad7 , + double ad8 , + double ad9 , + double ad10, + double ad11, + double ad12, + double ad13, + double ad14, + double ad15, + double ad16, + float af1 , + float af2 , + float af3 , + float af4 , + float af5 , + float af6 , + float af7 , + float af8 , + float af9 , + float af10, + float af11, + float af12, + float af13, + float af14, + float af15, + float af16 + ) { + switch(f ? idx + 16 : idx) { + case 1 : return ad1 ; + case 2 : return ad2 ; + case 3 : return ad3 ; + case 4 : return ad4 ; + case 5 : return ad5 ; + case 6 : return ad6 ; + case 7 : return ad7 ; + case 8 : return ad8 ; + case 9 : return ad9 ; + case 10: return ad10; + case 11: return ad11; + case 12: return ad12; + case 13: return ad13; + case 14: return ad14; + case 15: return ad15; + case 16: return ad16; + case 1 + 16: return af1 ; + case 2 + 16: return af2 ; + case 3 + 16: return af3 ; + case 4 + 16: return af4 ; + case 5 + 16: return af5 ; + case 6 + 16: return af6 ; + case 7 + 16: return af7 ; + case 8 + 16: return af8 ; + case 9 + 16: return af9 ; + case 10 + 16: return af10; + case 11 + 16: return af11; + case 12 + 16: return af12; + case 13 + 16: return af13; + case 14 + 16: return af14; + case 15 + 16: return af15; + case 16 + 16: return af16; + } + Assert.fail(); // should not reach here + return 0; + + } + // @formatter:on + @Test public void run0() throws Throwable { runTest("test", 0, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); @@ -82,4 +288,86 @@ public void run5() throws Throwable { runTest("test", 5, -1, -1, -1, -1, 1d, 2d, true, false, (byte) -128, (short) -0x7FFF, (char) 0xFFFF, -0x7FFFFFF); } + + @Test + public void run6() throws Throwable { + // @formatter:off + runTest("test2", 20, 1.0f, -3.2912948246387967943231233d, 3.0f, + 1d, + 2d, + 3d, + 4d, + 5d, + 6d, + 7d, + 8d, + 9d, + 10d, + 11d, + 12d, + 13d, + 14d, + 15d, + 16d, + 1f, + 2f, + 3f, + 4f, + 5f, + 6f, + 7f, + 8f, + 9f, + 10f, + 11f, + 12f, + 13f, + 14f, + 15f, + 16f + ); + // @formatter:on + } + + @Test + public void run7() throws Throwable { + // @formatter:off + for(int i =0; i<32*2; i++) + runTest("test3", i%2==0, i/2, + 1d, + 2d, + 3d, + 4d, + 5d, + 6d, + 7d, + 8d, + 9d, + 10d, + 11d, + 12d, + 13d, + 14d, + 15d, + 16d, + 1f, + 2f, + 3f, + 4f, + 5f, + 6f, + 7f, + 8f, + 9f, + 10f, + 11f, + 12f, + 13f, + 14f, + 15f, + 16f + ); + // @formatter:on + } + } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/SignExtendShort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/SignExtendShort.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, 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.jtt.optimize; + +import org.junit.*; + +import com.oracle.graal.jtt.*; + +/* + */ +public class SignExtendShort extends JTTTest { + + public static int val; + + public static boolean test(short[] b) { + val = b[2]; + int x = 0; + return val >= x; + } + + @Test + public void run0() throws Throwable { + runTest("test", new short[]{0, 0, 0}); + } + + @Test + public void run1() throws Throwable { + runTest("test", new short[]{0, 0, 1}); + } + + @Test + public void run2() throws Throwable { + runTest("test", new short[]{0, 0, -1}); + } + + @Test + public void run3() throws Throwable { + runTest("test", new short[]{0, 0, Short.MAX_VALUE}); + } + + @Test + public void run4() throws Throwable { + runTest("test", new short[]{0, 0, Short.MIN_VALUE}); + } +} diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Switch02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Switch02.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Switch02.java Tue Aug 26 09:35:08 2014 -0700 @@ -22,6 +22,8 @@ */ package com.oracle.graal.jtt.optimize; +import java.util.*; + import org.junit.*; import com.oracle.graal.jtt.*; @@ -30,6 +32,9 @@ * Tests optimization of switches. */ public class Switch02 extends JTTTest { + private static char staticCharVal = 0; + private static short staticShortVal = 0; + private static byte staticByteVal = 0; public static int test(int arg) { switch (arg) { @@ -40,6 +45,168 @@ } } + public static int test2char(char arg) { + int result = 392123; + Object x = null; + char val = staticCharVal != 0 ? staticCharVal : arg; + switch (val) { + case (char) 0xFFFF: + result = 23212 / val; + break; + case (char) 0xFFFF - 3: + result = 932991439 / val; + break; + case (char) 0xFFFF - 6: + result = 47329561 / val; + break; + case (char) 0xFFFF - 9: + result = 1950976984 / val; + break; + case (char) 0xFFFF - 10: + result = 97105581 / val; + switch (result) { + case 1: + result = 321; + break; + default: + result = 2391; + break; + } + break; + case (char) 0xFFFF - 12: + result = 99757362 / val; + break; + case (char) 0xFFFF - 15: + result = 912573 / val; + x = new LinkedList<>(); + break; + case (char) 0xFFFF - 18: + x = new HashSet<>(); + result = 876765 / val; + break; + case (char) 0xFFFF - 19: + result = 75442917 / val; + break; + case (char) 0xFFFF - 21: + result = 858112498 / val; + x = new Hashtable<>(); + break; + default: + result = 34324341 / val; + } + result = result + (x == null ? 0 : x.hashCode()); + return result; + } + + public static int test2short(short arg) { + int result = 392123; + Object x = null; + short val = staticShortVal != 0 ? staticShortVal : arg; + switch (val) { + case (short) -0x7FFF: + result = 23212 / val; + break; + case (short) -0x7FFF + 3: + result = 932991439 / val; + break; + case (short) -0x7FFF + 6: + result = 47329561 / val; + break; + case (short) -0x7FFF + 9: + result = 1950976984 / val; + break; + case (short) -0x7FFF + 10: + result = 97105581 / val; + switch (result) { + case 1: + result = 321; + break; + default: + result = 2391; + break; + } + break; + case (short) -0x7FFF + 12: + result = 99757362 / val; + break; + case (short) -0x7FFF + 15: + result = 912573 / val; + x = new LinkedList<>(); + break; + case (short) -0x7FFF + 18: + x = new HashSet<>(); + result = 876765 / val; + break; + case (short) -0x7FFF + 19: + result = 75442917 / val; + break; + case (short) -0x7FFF + 21: + result = 858112498 / val; + x = new Hashtable<>(); + break; + default: + result = 34324341 / val; + } + result = result + (x == null ? 0 : x.hashCode()); + return result; + } + + public static int test2byte(byte arg) { + int result = 392123; + Object x = null; + byte val = staticByteVal != 0 ? staticByteVal : arg; + switch (val) { + case (byte) -0x7F: + result = 23212 / val; + break; + case (byte) -0x7F + 3: + result = 932991439 / val; + break; + case (byte) -0x7F + 6: + result = 47329561 / val; + break; + case (byte) -0x7F + 9: + result = 1950976984 / val; + break; + case (byte) -0x7F + 10: + result = 97105581 / val; + switch (result) { + case 1: + result = 321; + break; + default: + result = 2391; + break; + } + break; + case (byte) -0x7F + 12: + result = 99757362 / val; + break; + case (byte) -0x7F + 15: + result = 912573 / val; + x = new LinkedList<>(); + break; + case (byte) -0x7F + 18: + x = new HashSet<>(); + result = 876765 / val; + break; + case (byte) -0x7F + 19: + result = 75442917 / val; + break; + case (byte) -0x7F + 20: + result = 856261268 / val; + break; + case (byte) -0x7F + 21: + result = 858112498 / val; + x = new Hashtable<>(); + break; + default: + result = 34324341 / val; + } + result = result + (x == null ? 0 : x.hashCode()); + return result; + } + @Test public void run0() throws Throwable { runTest("test", 0); @@ -50,4 +217,63 @@ runTest("test", 1); } + @Test + public void run2() throws Throwable { + runTest("test2char", (char) (0x0)); + runTest("test2char", (char) (0xFFFF)); + runTest("test2char", (char) (0xFFFF - 21)); // miss + runTest("test2char", (char) (0xFFFF - 22)); // hit + runTest("test2char", (char) (0xFFFF - 23)); // miss (out of bound) + + staticCharVal = (char) 0xFFFF; + runTest("test2char", (char) 0); + staticCharVal = (char) (0xFFFF - 21); + runTest("test2char", (char) 0xFFFF); + staticCharVal = (char) (0xFFFF - 22); + runTest("test2char", (char) 0xFFFF); + staticCharVal = (char) (0xFFFF - 23); + runTest("test2char", (char) 0xFFFF); + } + + @Test + public void run3() throws Throwable { + runTest("test2short", (short) 0x0); + runTest("test2short", (short) -0x7FFF); + runTest("test2short", (short) (-0x7FFF + 21)); // Miss + runTest("test2short", (short) (-0x7FFF + 22)); // hit + runTest("test2short", (short) (-0x7FFF + 23)); // miss (out of bound) + runTest("test2short", (short) 0x7FFF); // miss (out of bound) + + staticShortVal = (short) -0x7FFF; + runTest("test2short", (short) 0); + staticShortVal = (short) (-0x7FFF + 21); + runTest("test2short", (short) 0); + staticShortVal = (short) (-0x7FFF + 22); + runTest("test2short", (short) 0); + staticShortVal = (short) (-0x7FFF + 23); + runTest("test2short", (short) 0); + staticShortVal = (short) 0x7FFF; + runTest("test2short", (short) 0); + } + + @Test + public void run4() throws Throwable { + runTest("test2byte", (byte) 0); + runTest("test2byte", (byte) -0x7F); + runTest("test2byte", (byte) (-0x7F + 21)); // Miss + runTest("test2byte", (byte) (-0x7F + 22)); // hit + runTest("test2byte", (byte) (-0x7F + 23)); // miss (out of bound) + runTest("test2byte", (byte) 0x7F); // miss (out of bound) + + staticByteVal = (byte) -0x7F; + runTest("test2short", (short) 0); + staticByteVal = (byte) (-0x7F + 21); + runTest("test2short", (short) 0); + staticByteVal = (byte) (-0x7F + 22); + runTest("test2short", (short) 0); + staticByteVal = (byte) (-0x7F + 23); + runTest("test2short", (short) 0); + staticByteVal = (byte) 0x7F; + runTest("test2short", (short) 0); + } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Tue Aug 26 09:35:08 2014 -0700 @@ -27,6 +27,7 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.compiler.common.*; @@ -37,8 +38,8 @@ public enum SPARCArithmetic { // @formatter:off - IADD, ISUB, IMUL, IDIV, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, - LADD, LSUB, LMUL, LDIV, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, + IADD, ISUB, IMUL, IUMUL, IDIV, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, + LADD, LSUB, LMUL, LUMUL, LDIV, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, INEG, LNEG, FNEG, DNEG, INOT, LNOT, @@ -161,6 +162,10 @@ @State protected LIRFrameState state; protected Constant y; + public BinaryRegConst(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x, Constant y) { + this(opcode, result, x, y, null); + } + public BinaryRegConst(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x, Constant y, LIRFrameState state) { this.opcode = opcode; this.result = result; @@ -248,7 +253,7 @@ @Opcode private final SPARCArithmetic opcode; @Def({REG}) protected Value result; - @Use({REG, CONST}) protected Value x; + @Alive({REG, CONST}) protected Value x; @Alive({REG, CONST}) protected Value y; @Temp({REG}) protected Value scratch1; @Temp({REG}) protected Value scratch2; @@ -282,9 +287,16 @@ switch (opcode) { case ISUB: assert isSimm13(crb.asIntConst(src1)); - new Sub(SPARC.g0, asIntReg(src2), asIntReg(src2)).emit(masm); - new Add(asIntReg(src2), crb.asIntConst(src1), asIntReg(dst)).emit(masm); + new Sub(SPARC.g0, asIntReg(src2), asIntReg(dst)).emit(masm); + new Add(asIntReg(dst), crb.asIntConst(src1), asIntReg(dst)).emit(masm); break; + case LSUB: { + long c = crb.asLongConst(src1); + assert isSimm13(c); + new Sub(SPARC.g0, asLongReg(src2), asLongReg(dst)).emit(masm); + new Add(asLongReg(dst), (int) c, asLongReg(dst)).emit(masm); + break; + } case IAND: throw GraalInternalError.unimplemented(); case IDIV: @@ -292,13 +304,14 @@ exceptionOffset = masm.position(); new Sdivx(asIntReg(dst), asIntReg(src2), asIntReg(dst)).emit(masm); break; - case LDIV: + case LDIV: { int c = crb.asIntConst(src1); assert isSimm13(c); exceptionOffset = masm.position(); new Sdivx(asLongReg(src2), c, asLongReg(dst)).emit(masm); new Mulx(asLongReg(src1), asLongReg(dst), asLongReg(dst)).emit(masm); break; + } case FSUB: case FDIV: case DSUB: @@ -410,6 +423,7 @@ break; case DAND: SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(asConstant(src2), 4); + addr = SPARCMove.guaranueeLoadable(addr, masm); new Lddf(addr, asDoubleReg(dst)).emit(masm); new Fandd(asDoubleReg(src1), asDoubleReg(dst), asDoubleReg(dst)).emit(masm); break; @@ -440,7 +454,6 @@ new Sdivx(asIntReg(src1), asIntReg(src2), asIntReg(dst)).emit(masm); break; case IUDIV: - new Srl(asIntReg(src1), 0, asIntReg(src1)).emit(masm); exceptionOffset = masm.position(); new Udivx(asIntReg(src1), asIntReg(src2), asIntReg(dst)).emit(masm); break; @@ -506,7 +519,11 @@ new Fsubs(asFloatReg(src1), asFloatReg(src2), asFloatReg(dst)).emit(masm); break; case FMUL: - new Fmuls(asFloatReg(src1), asFloatReg(src2), asFloatReg(dst)).emit(masm); + if (dst.getPlatformKind() == Kind.Double) { + new Fsmuld(asFloatReg(src1), asFloatReg(src2), asDoubleReg(dst)).emit(masm); + } else if (dst.getPlatformKind() == Kind.Float) { + new Fmuls(asFloatReg(src1), asFloatReg(src2), asFloatReg(dst)).emit(masm); + } break; case FDIV: new Fdivs(asFloatReg(src1), asFloatReg(src2), asFloatReg(dst)).emit(masm); @@ -569,22 +586,25 @@ } else if (isConstant(src2)) { switch (opcode) { case IREM: + assert !src1.equals(scratch1); + assert !src1.equals(scratch2); + assert !src2.equals(scratch1); + // But src2 can be scratch2 assert isSimm13(crb.asIntConst(src2)); - new Sra(asIntReg(src1), 0, asIntReg(src1)).emit(masm); exceptionOffset = masm.position(); new Sdivx(asIntReg(src1), crb.asIntConst(src2), asIntReg(scratch1)).emit(masm); new Mulx(asIntReg(scratch1), crb.asIntConst(src2), asIntReg(scratch2)).emit(masm); new Sub(asIntReg(src1), asIntReg(scratch2), asIntReg(dst)).emit(masm); break; case IUREM: - new Sra(asIntReg(src1), 0, asIntReg(scratch1)).emit(masm); - exceptionOffset = masm.position(); - new Udivx(asIntReg(scratch1), crb.asIntConst(src2), asIntReg(scratch1)).emit(masm); - new Mulx(asIntReg(scratch1), crb.asIntConst(src2), asIntReg(scratch1)).emit(masm); - new Sub(asIntReg(src1), asIntReg(scratch1), asIntReg(dst)).emit(masm); + GraalInternalError.unimplemented(); break; case LREM: assert isSimm13(crb.asIntConst(src2)); + assert !src1.equals(scratch1); + assert !src1.equals(scratch2); + assert !src2.equals(scratch1); + // But src2 can be scratch2 exceptionOffset = masm.position(); new Sdivx(asLongReg(src1), crb.asIntConst(src2), asLongReg(scratch1)).emit(masm); new Mulx(asLongReg(scratch1), crb.asIntConst(src2), asLongReg(scratch2)).emit(masm); @@ -592,6 +612,10 @@ break; case LUREM: assert isSimm13(crb.asIntConst(src2)); + assert !src1.equals(scratch1); + assert !src1.equals(scratch2); + assert !src2.equals(scratch1); + // But src2 can be scratch2 exceptionOffset = masm.position(); new Udivx(asLongReg(src1), crb.asIntConst(src2), asLongReg(scratch1)).emit(masm); new Mulx(asLongReg(scratch1), crb.asIntConst(src2), asLongReg(scratch2)).emit(masm); @@ -608,6 +632,9 @@ new Setx(crb.asLongConst(src1), asLongReg(scratch2), false).emit(masm); srcLeft = scratch2; } + assert !asLongReg(srcLeft).equals(asLongReg(scratch1)); + assert !asLongReg(src2).equals(asLongReg(scratch1)); + // But src2 can be scratch2 exceptionOffset = masm.position(); new Sdivx(asLongReg(srcLeft), asLongReg(src2), asLongReg(scratch1)).emit(masm); new Mulx(asLongReg(scratch1), asLongReg(src2), asLongReg(scratch1)).emit(masm); @@ -618,6 +645,8 @@ new Setx(crb.asLongConst(src1), asLongReg(scratch2), false).emit(masm); srcLeft = scratch2; } + assert !asLongReg(srcLeft).equals(asLongReg(scratch1)); + assert !asLongReg(src2).equals(asLongReg(scratch1)); exceptionOffset = masm.position(); new Udivx(asLongReg(srcLeft), asLongReg(src2), asLongReg(scratch1)).emit(masm); new Mulx(asLongReg(scratch1), asLongReg(src2), asLongReg(scratch1)).emit(masm); @@ -628,17 +657,22 @@ new Setx(crb.asIntConst(src1), asIntReg(scratch2), false).emit(masm); srcLeft = scratch2; } + assert !asIntReg(srcLeft).equals(asIntReg(scratch1)); + assert !asIntReg(src2).equals(asIntReg(scratch1)); exceptionOffset = masm.position(); new Sdivx(asIntReg(srcLeft), asIntReg(src2), asIntReg(scratch1)).emit(masm); new Mulx(asIntReg(scratch1), asIntReg(src2), asIntReg(scratch1)).emit(masm); new Sub(asIntReg(srcLeft), asIntReg(scratch1), asIntReg(dst)).emit(masm); break; case IUREM: - new Sra(asIntReg(src1), 0, asIntReg(scratch1)).emit(masm); + assert !asIntReg(dst).equals(asIntReg(scratch1)); + assert !asIntReg(dst).equals(asIntReg(scratch2)); + new Srl(asIntReg(src1), 0, asIntReg(scratch1)).emit(masm); + new Srl(asIntReg(src2), 0, asIntReg(dst)).emit(masm); exceptionOffset = masm.position(); - new Udivx(asIntReg(scratch1), asIntReg(src2), asIntReg(scratch1)).emit(masm); - new Mulx(asIntReg(scratch1), asIntReg(src2), asIntReg(scratch1)).emit(masm); - new Sub(asIntReg(src1), asIntReg(scratch1), asIntReg(dst)).emit(masm); + new Udivx(asIntReg(scratch1), asIntReg(dst), asIntReg(scratch2)).emit(masm); + new Mulx(asIntReg(scratch2), asIntReg(dst), asIntReg(dst)).emit(masm); + new Sub(asIntReg(scratch1), asIntReg(dst), asIntReg(dst)).emit(masm); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -653,6 +687,7 @@ public static void emit(CompilationResultBuilder crb, SPARCAssembler masm, SPARCArithmetic opcode, Value dst, Value src, LIRFrameState info) { int exceptionOffset = -1; + Label notOrdered = new Label(); if (isRegister(src)) { switch (opcode) { case INEG: @@ -716,18 +751,20 @@ new Fstod(asFloatReg(src), asDoubleReg(dst)).emit(masm); break; case F2L: - new Fcmp(CC.Fcc0, Opfs.Fcmps, asFloatReg(dst), asFloatReg(dst)).emit(masm); - new Fbe(false, 4 * 4).emit(masm); + new Fcmp(CC.Fcc0, Opfs.Fcmps, asFloatReg(src), asFloatReg(src)).emit(masm); + new Fbo(false, notOrdered).emit(masm); new Fstox(asFloatReg(src), asFloatReg(dst)).emit(masm); new Fitos(asFloatReg(dst), asFloatReg(dst)).emit(masm); new Fsubs(asFloatReg(dst), asFloatReg(dst), asFloatReg(dst)).emit(masm); + masm.bind(notOrdered); break; case F2I: - new Fcmp(CC.Fcc0, Opfs.Fcmps, asFloatReg(dst), asFloatReg(dst)).emit(masm); - new Fbo(false, 4 * 4).emit(masm); + new Fcmp(CC.Fcc0, Opfs.Fcmps, asFloatReg(src), asFloatReg(src)).emit(masm); + new Fbo(false, notOrdered).emit(masm); new Fstoi(asFloatReg(src), asFloatReg(dst)).emit(masm); new Fitos(asFloatReg(dst), asFloatReg(dst)).emit(masm); new Fsubs(asFloatReg(dst), asFloatReg(dst), asFloatReg(dst)).emit(masm); + masm.bind(notOrdered); break; case MOV_D2L: new Movdtox(asDoubleReg(src), asLongReg(dst)).emit(masm); @@ -742,18 +779,20 @@ new Movwtos(asIntReg(src), asFloatReg(dst)).emit(masm); break; case D2L: - new Fcmp(CC.Fcc0, Opfs.Fcmpd, asDoubleReg(dst), asDoubleReg(dst)).emit(masm); - new Fbo(false, 4 * 4).emit(masm); + new Fcmp(CC.Fcc0, Opfs.Fcmpd, asDoubleReg(src), asDoubleReg(src)).emit(masm); + new Fbo(false, notOrdered).emit(masm); new Fdtox(asDoubleReg(src), asDoubleReg(dst)).emit(masm); new Fxtod(asDoubleReg(dst), asDoubleReg(dst)).emit(masm); new Fsubd(asDoubleReg(dst), asDoubleReg(dst), asDoubleReg(dst)).emit(masm); + masm.bind(notOrdered); break; case D2I: - new Fcmp(CC.Fcc0, Opfs.Fcmpd, asDoubleReg(dst), asDoubleReg(dst)).emit(masm); - new Fbo(false, 4 * 4).emit(masm); + new Fcmp(CC.Fcc0, Opfs.Fcmpd, asDoubleReg(src), asDoubleReg(src)).emit(masm); + new Fbo(false, notOrdered).emit(masm); new Fdtoi(asDoubleReg(src), asDoubleReg(dst)).emit(masm); new Fitod(asDoubleReg(dst), asDoubleReg(dst)).emit(masm); new Fsubd(asDoubleReg(dst), asDoubleReg(dst), asDoubleReg(dst)).emit(masm); + masm.bind(notOrdered); break; case FNEG: new Fnegs(asFloatReg(src), asFloatReg(dst)).emit(masm); @@ -803,10 +842,14 @@ case IUSHR: case IUDIV: case IUREM: - rk = result.getKind(); + rk = result.getKind().getStackKind(); xsk = x.getKind().getStackKind(); ysk = y.getKind().getStackKind(); - assert rk == Kind.Int && xsk == Kind.Int && ysk == Kind.Int; + boolean valid = false; + for (Kind k : new Kind[]{Kind.Int, Kind.Short, Kind.Byte, Kind.Char}) { + valid |= rk == k && xsk == k && ysk == k; + } + assert valid : "rk: " + rk + " xsk: " + xsk + " ysk: " + ysk; break; case LADD: case LSUB: @@ -839,7 +882,7 @@ rk = result.getKind(); xk = x.getKind(); yk = y.getKind(); - assert rk == Kind.Float && xk == Kind.Float && yk == Kind.Float; + assert (rk == Kind.Float || rk == Kind.Double) && xk == Kind.Float && yk == Kind.Float; break; case DAND: case DADD: @@ -856,4 +899,56 @@ throw GraalInternalError.shouldNotReachHere("missing: " + opcode); } } + + public static class MulHighOp extends SPARCLIRInstruction { + + @Opcode private final SPARCArithmetic opcode; + @Def({REG}) public AllocatableValue result; + @Alive({REG}) public AllocatableValue x; + @Alive({REG}) public AllocatableValue y; + @Temp({REG}) public AllocatableValue scratch; + + public MulHighOp(SPARCArithmetic opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) { + 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: + new Mulx(asIntReg(x), asIntReg(y), asIntReg(result)).emit(masm); + new Srax(asIntReg(result), 32, asIntReg(result)).emit(masm); + break; + case IUMUL: + assert !asIntReg(scratch).equals(asIntReg(result)); + new Srl(asIntReg(x), 0, asIntReg(scratch)).emit(masm); + new Srl(asIntReg(y), 0, asIntReg(result)).emit(masm); + new Mulx(asIntReg(result), asIntReg(scratch), asIntReg(result)).emit(masm); + new Srlx(asIntReg(result), 32, asIntReg(result)).emit(masm); + break; + case LMUL: + assert !asLongReg(scratch).equals(asLongReg(result)); + new Umulxhi(asLongReg(x), asLongReg(y), asLongReg(result)).emit(masm); + + new Srlx(asLongReg(x), 63, asLongReg(scratch)).emit(masm); + new Mulx(asLongReg(scratch), asLongReg(y), asLongReg(scratch)).emit(masm); + new Sub(asLongReg(result), asLongReg(scratch), asLongReg(result)).emit(masm); + + new Srlx(asLongReg(y), 63, asLongReg(scratch)).emit(masm); + new Mulx(asLongReg(scratch), asLongReg(x), asLongReg(scratch)).emit(masm); + new Sub(asLongReg(result), asLongReg(scratch), asLongReg(result)).emit(masm); + break; + case LUMUL: + new Umulxhi(asLongReg(x), asLongReg(y), asLongReg(result)).emit(masm); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java Tue Aug 26 09:35:08 2014 -0700 @@ -96,9 +96,10 @@ Kind ikind = input.getKind(); assert ikind == Kind.Int; Register tmp = asRegister(scratch); + assert !tmp.equals(dst); new Srl(src, 1, tmp).emit(masm); new Srl(src, 0, dst).emit(masm); - new Or(src, tmp, dst).emit(masm); + new Or(dst, tmp, dst).emit(masm); new Srl(dst, 2, tmp).emit(masm); new Or(dst, tmp, dst).emit(masm); new Srl(dst, 4, tmp).emit(masm); @@ -115,6 +116,7 @@ Kind lkind = input.getKind(); assert lkind == Kind.Long; Register tmp = asRegister(scratch); + assert !tmp.equals(dst); new Srlx(src, 1, tmp).emit(masm); new Or(src, tmp, dst).emit(masm); new Srlx(dst, 2, tmp).emit(masm); diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Tue Aug 26 09:35:08 2014 -0700 @@ -25,12 +25,12 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import static com.oracle.graal.sparc.SPARC.*; +import static com.oracle.graal.asm.sparc.SPARCAssembler.*; 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.SPARCAssembler.*; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; @@ -62,30 +62,44 @@ } public static class BranchOp extends SPARCLIRInstruction implements StandardOp.BranchOp { - + // TODO: Conditioncode/flag handling needs to be improved; protected final Condition condition; + protected final ConditionFlag conditionFlag; protected final LabelRef trueDestination; protected final LabelRef falseDestination; protected final Kind kind; + public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, Kind kind) { + this.conditionFlag = condition; + this.trueDestination = trueDestination; + this.falseDestination = falseDestination; + this.kind = kind; + this.condition = null; + } + public BranchOp(Condition condition, LabelRef trueDestination, LabelRef falseDestination, Kind kind) { this.condition = condition; this.trueDestination = trueDestination; this.falseDestination = falseDestination; this.kind = kind; + this.conditionFlag = null; } @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + assert condition == null && conditionFlag != null || condition != null && conditionFlag == null; Label actualTarget; Condition actualCondition; + ConditionFlag actualConditionFlag; boolean needJump; if (crb.isSuccessorEdge(trueDestination)) { - actualCondition = condition.negate(); + actualCondition = condition != null ? condition.negate() : null; + actualConditionFlag = conditionFlag != null ? conditionFlag.negate() : null; actualTarget = falseDestination.label(); needJump = false; } else { actualCondition = condition; + actualConditionFlag = conditionFlag; actualTarget = trueDestination.label(); needJump = !crb.isSuccessorEdge(falseDestination); } @@ -94,7 +108,13 @@ emitFloatCompare(masm, actualTarget, actualCondition); } else { CC cc = kind == Kind.Int ? CC.Icc : CC.Xcc; - emitCompare(masm, actualTarget, actualCondition, cc); + if (actualCondition != null) { + emitCompare(masm, actualTarget, actualCondition, cc); + } else if (actualConditionFlag != null) { + emitCompare(masm, actualTarget, actualConditionFlag); + } else { + GraalInternalError.shouldNotReachHere(); + } new Nop().emit(masm); // delay slot } if (needJump) { @@ -104,7 +124,7 @@ } private static void emitFloatCompare(SPARCMacroAssembler masm, Label target, Condition actualCondition) { - switch (actualCondition.mirror()) { + switch (actualCondition) { case EQ: new Fbe(false, target).emit(masm); break; @@ -134,6 +154,10 @@ new Nop().emit(masm); } + private static void emitCompare(SPARCMacroAssembler masm, Label target, ConditionFlag actualCondition) { + new Fmt00b(false, actualCondition, Op2s.Br, target).emit(masm); + } + private static void emitCompare(SPARCMacroAssembler masm, Label target, Condition actualCondition, CC cc) { switch (actualCondition) { case EQ: @@ -176,7 +200,7 @@ private final LabelRef[] keyTargets; private LabelRef defaultTarget; @Alive({REG}) protected Value key; - @Temp({REG, ILLEGAL}) protected Value scratch; + @Temp({REG}) protected Value scratch; private final SwitchStrategy strategy; public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { @@ -188,7 +212,6 @@ this.scratch = scratch; assert keyConstants.length == keyTargets.length; assert keyConstants.length == strategy.keyProbabilities.length; - assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int); } @Override @@ -204,8 +227,13 @@ crb.recordInlineDataInCode(keyConstants[index]); } long lc = keyConstants[index].asLong(); - assert NumUtil.isInt(lc); - new Cmp(keyRegister, (int) lc).emit(masm); + if (SPARCAssembler.isSimm13(lc)) { + assert NumUtil.isInt(lc); + new Cmp(keyRegister, (int) lc).emit(masm); + } else { + new Setx(lc, asIntReg(scratch)).emit(masm); + new Cmp(keyRegister, asIntReg(scratch)).emit(masm); + } emitCompare(masm, target, condition, CC.Icc); break; case Long: { @@ -253,12 +281,20 @@ // Compare index against jump table bounds int highKey = lowKey + targets.length - 1; - if (lowKey != 0) { - // subtract the low value from the switch value - new Sub(value, lowKey, value).emit(masm); - new Cmp(value, highKey - lowKey).emit(masm); + + // subtract the low value from the switch value + if (isSimm13(lowKey)) { + new Sub(value, lowKey, scratchReg).emit(masm); } else { - new Cmp(value, highKey).emit(masm); + new Setx(lowKey, g3).emit(masm); + new Sub(value, g3, scratchReg).emit(masm); + } + int upperLimit = highKey - lowKey; + if (isSimm13(upperLimit)) { + new Cmp(scratchReg, upperLimit).emit(masm); + } else { + new Setx(upperLimit, g3).emit(masm); + new Cmp(scratchReg, upperLimit).emit(masm); } // Jump to default target if index is not within the jump table @@ -268,19 +304,20 @@ } // Load jump table entry into scratch and jump to it - new Sll(value, 3, value).emit(masm); // Multiply by 8 - new Rdpc(scratchReg).emit(masm); + new Sll(scratchReg, 3, scratchReg).emit(masm); // Multiply by 8 + // Zero the left bits sll with shcnt>0 does not mask upper 32 bits + new Srl(scratchReg, 0, scratchReg).emit(masm); + new Rdpc(g3).emit(masm); // The jump table follows four instructions after rdpc new Add(scratchReg, 4 * 4, scratchReg).emit(masm); - new Jmpl(value, scratchReg, g0).emit(masm); - new Sra(value, 3, value).emit(masm); // delay slot, correct the value (division by 8) + new Jmpl(g3, scratchReg, g0).emit(masm); + new Nop().emit(masm); + // new Sra(value, 3, value).emit(masm); // delay slot, correct the value (division by 8) // Emit jump table entries for (LabelRef target : targets) { - Label label = target.label(); - label.addPatchAt(masm.position()); - new Bpa(0).emit(masm); + new Bpa(target.label()).emit(masm); new Nop().emit(masm); // delay slot } } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue Aug 26 09:35:08 2014 -0700 @@ -25,16 +25,18 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import static com.oracle.graal.sparc.SPARC.*; +import static com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.api.code.CompilationResult.RawData; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.StandardOp.NullCheck; import com.oracle.graal.lir.asm.*; public class SPARCMove { @@ -135,7 +137,7 @@ @Override public void emitMemAccess(SPARCMacroAssembler masm) { - final SPARCAddress addr = address.toAddress(); + final SPARCAddress addr = guaranueeLoadable(address.toAddress(), masm); final Register dst = asRegister(result); switch (kind) { case Boolean: @@ -172,21 +174,17 @@ public static class LoadAddressOp extends SPARCLIRInstruction { @Def({REG}) protected AllocatableValue result; - @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue address; + @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue addressValue; public LoadAddressOp(AllocatableValue result, SPARCAddressValue address) { this.result = result; - this.address = address; + this.addressValue = address; } @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - SPARCAddress addr = address.toAddress(); - if (addr.hasIndex()) { - new Add(addr.getBase(), addr.getIndex(), asLongReg(result)).emit(masm); - } else { - new Add(addr.getBase(), addr.getDisplacement(), asLongReg(result)).emit(masm); - } + SPARCAddress address = addressValue.toAddress(); + loadEffectiveAddress(address, asLongReg(result), masm); } } @@ -283,7 +281,21 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { SPARCAddress address = (SPARCAddress) crb.asAddress(slot); - new Add(address.getBase(), address.getDisplacement(), asLongReg(result)).emit(masm); + loadEffectiveAddress(address, asLongReg(result), masm); + } + } + + private static void loadEffectiveAddress(SPARCAddress address, Register result, SPARCMacroAssembler masm) { + if (address.getIndex().equals(Register.None)) { + if (isSimm13(address.getDisplacement())) { + new Add(address.getBase(), address.getDisplacement(), result).emit(masm); + } else { + assert result.encoding() != address.getBase().encoding(); + new Setx(address.getDisplacement(), result).emit(masm); + new Add(address.getBase(), result, result).emit(masm); + } + } else { + new Add(address.getBase(), address.getIndex(), result).emit(masm); } } @@ -299,7 +311,7 @@ @Override public void emitMemAccess(SPARCMacroAssembler masm) { assert isRegister(input); - SPARCAddress addr = address.toAddress(); + SPARCAddress addr = guaranueeLoadable(address.toAddress(), masm); switch (kind) { case Boolean: case Byte: @@ -344,21 +356,22 @@ @Override public void emitMemAccess(SPARCMacroAssembler masm) { + SPARCAddress addr = guaranueeLoadable(address.toAddress(), masm); switch (kind) { case Boolean: case Byte: - new Stb(g0, address.toAddress()).emit(masm); + new Stb(g0, addr).emit(masm); break; case Short: case Char: - new Sth(g0, address.toAddress()).emit(masm); + new Sth(g0, addr).emit(masm); break; case Int: - new Stw(g0, address.toAddress()).emit(masm); + new Stw(g0, addr).emit(masm); break; case Long: case Object: - new Stx(g0, address.toAddress()).emit(masm); + new Stx(g0, addr).emit(masm); break; case Float: case Double: @@ -451,8 +464,29 @@ } } + /** + * Guarantees that the given SPARCAddress given before is loadable by subsequent call. If the + * displacement exceeds the imm13 value, the value is put into a scratch register o7, which must + * be used as soon as possible. + * + * @param addr Address to modify + * @param masm assembler to output the prior stx command + * @return a loadable SPARCAddress + */ + public static SPARCAddress guaranueeLoadable(SPARCAddress addr, SPARCMacroAssembler masm) { + boolean displacementOutOfBound = addr.getIndex().equals(Register.None) && !SPARCAssembler.isSimm13(addr.getDisplacement()); + if (displacementOutOfBound) { + Register scratch = g3; + new Setx(addr.getDisplacement(), scratch, false).emit(masm); + return new SPARCAddress(addr.getBase(), scratch); + } else { + return addr; + } + } + private static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input) { SPARCAddress dst = (SPARCAddress) crb.asAddress(result); + dst = guaranueeLoadable(dst, masm); Register src = asRegister(input); switch (input.getKind()) { case Byte: @@ -483,6 +517,7 @@ private static void stack2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input) { SPARCAddress src = (SPARCAddress) crb.asAddress(input); + src = guaranueeLoadable(src, masm); Register dst = asRegister(result); switch (input.getKind()) { case Boolean: @@ -517,28 +552,10 @@ Register scratch = g5; switch (input.getKind().getStackKind()) { case Int: - if (crb.codeCache.needsDataPatch(input)) { - crb.recordInlineDataInCode(input); - new Setuw(input.asInt(), asRegister(result)).emit(masm); - } else { - if (input.isDefaultForKind()) { - new Clr(asRegister(result)).emit(masm); - } else { - new Setuw(input.asInt(), asRegister(result)).emit(masm); - } - } + new Setx(input.asLong(), asIntReg(result)).emit(masm); break; case Long: - if (crb.codeCache.needsDataPatch(input)) { - crb.recordInlineDataInCode(input); - new Setx(input.asLong(), asRegister(result), true).emit(masm); - } else { - if (input.isDefaultForKind()) { - new Clr(asRegister(result)).emit(masm); - } else { - new Setx(input.asLong(), asRegister(result)).emit(masm); - } - } + new Setx(input.asLong(), asLongReg(result)).emit(masm); break; case Float: // TODO: Handle it the same way, as in the double case with Movwtos diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java Tue Aug 26 09:35:08 2014 -0700 @@ -27,10 +27,12 @@ import java.util.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.sparc.SPARCAssembler.Movxtod; import com.oracle.graal.asm.sparc.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.asm.*; +import com.oracle.graal.sparc.*; /** * Saves registers to stack slots. @@ -78,6 +80,7 @@ saveRegister(crb, masm, slots[i], savedRegisters[i]); } } + new Movxtod(SPARC.i0, SPARC.f31).emit(masm); } public StackSlot[] getSlots() { diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Tue Aug 26 09:35:08 2014 -0700 @@ -204,7 +204,8 @@ // @formatter:off assert (!slot.getRawAddFrameSize() && slot.getRawOffset() < outgoingSize) || ( slot.getRawAddFrameSize() && slot.getRawOffset() < 0 && -slot.getRawOffset() <= spillSize) || - ( slot.getRawAddFrameSize() && slot.getRawOffset() >= 0); + ( slot.getRawAddFrameSize() && slot.getRawOffset() >= 0) : + String.format("RawAddFrameSize: %b RawOffset: 0x%x spillSize: 0x%x outgoingSize: 0x%x", slot.getRawAddFrameSize(), slot.getRawOffset(), spillSize, outgoingSize); // @formatter:on if (slot.isInCallerFrame()) { accessesCallerFrame = true; diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2014, 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.constopt; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.constopt.ConstantTree.Flags; +import com.oracle.graal.lir.constopt.ConstantTree.NodeCost; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.options.*; + +/** + * This optimization tries to improve the handling of constants by replacing a single definition of + * a constant, which is potentially scheduled into a block with high probability, with one or more + * definitions in blocks with a lower probability. + */ +public class ConstantLoadOptimization { + + public static class Options { + // @formatter:off + @Option(help = "Enable constant load optimization.") + public static final OptionValue ConstantLoadOptimization = new OptionValue<>(true); + // @formatter:on + } + + public static void optimize(LIR lir, LIRGeneratorTool lirGen) { + new ConstantLoadOptimization(lir, lirGen).apply(); + } + + private LIR lir; + private LIRGeneratorTool lirGen; + private VariableMap map; + private BitSet phiConstants; + private BitSet defined; + private BlockMap> blockMap; + private BlockMap insertionBuffers; + + private static DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]"); + private static DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]"); + private static DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]"); + private static DebugMetric usageAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[UsageAtDefinitionSkipped]"); + private static DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]"); + private static DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]"); + + private ConstantLoadOptimization(LIR lir, LIRGeneratorTool lirGen) { + this.lir = lir; + this.lirGen = lirGen; + this.map = new VariableMap<>(); + this.phiConstants = new BitSet(); + this.defined = new BitSet(); + this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph()); + this.blockMap = new BlockMap<>(lir.getControlFlowGraph()); + } + + private void apply() { + try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) { + try (Scope s = Debug.scope("BuildDefUseTree")) { + // build DefUseTree + lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock); + // remove all with only one use + map.filter(t -> { + if (t.usageCount() > 1) { + return true; + } else { + singleUsageConstantsSkipped.increment(); + return false; + } + }); + // collect block map + map.forEach(tree -> tree.forEach(this::addUsageToBlockMap)); + } catch (Throwable e) { + throw Debug.handle(e); + } + + try (Scope s = Debug.scope("BuildConstantTree")) { + // create ConstantTree + map.forEach(this::createConstantTree); + + // insert moves, delete null instructions and reset instruction ids + lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + } + + private static boolean isConstantLoad(LIRInstruction inst) { + if (!(inst instanceof MoveOp)) { + return false; + } + MoveOp move = (MoveOp) inst; + return isConstant(move.getInput()) && isVariable(move.getResult()); + } + + private void addUsageToBlockMap(UseEntry entry) { + AbstractBlock block = entry.getBlock(); + List list = blockMap.get(block); + if (list == null) { + list = new ArrayList<>(); + blockMap.put(block, list); + } + list.add(entry); + } + + /** + * Collects def-use information for a {@code block}. + */ + private void analyzeBlock(AbstractBlock block) { + try (Indent indent = Debug.logAndIndent("Block: %s", block)) { + + InstructionValueConsumer loadConsumer = new InstructionValueConsumer() { + @Override + public void visitValue(LIRInstruction instruction, Value value) { + if (isVariable(value)) { + Variable var = (Variable) value; + + if (!phiConstants.get(var.index)) { + if (!defined.get(var.index)) { + defined.set(var.index); + if (isConstantLoad(instruction)) { + Debug.log("constant load: %s", instruction); + map.put(var, new DefUseTree(instruction, block)); + constantsTotal.increment(); + } + } else { + // Variable is redefined, this only happens for constant loads + // introduced by phi resolution -> ignore. + DefUseTree removed = map.remove(var); + if (removed != null) { + phiConstantsSkipped.increment(); + } + phiConstants.set(var.index); + Debug.log(3, "Removing phi variable: %s", var); + } + } else { + assert defined.get(var.index) : "phi but not defined? " + var; + } + + } + } + + }; + + ValuePositionProcedure useProcedure = new ValuePositionProcedure() { + @Override + public void doValue(LIRInstruction instruction, ValuePosition position) { + Value value = position.get(instruction); + if (isVariable(value)) { + Variable var = (Variable) value; + if (!phiConstants.get(var.index)) { + DefUseTree tree = map.get(var); + if (tree != null) { + tree.addUsage(block, instruction, position); + Debug.log("usage of %s : %s", var, instruction); + } + } + } + } + + }; + + int opId = 0; + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + // set instruction id to the index in the lir instruction list + inst.setId(opId++); + inst.visitEachOutput(loadConsumer); + inst.forEachInput(useProcedure); + inst.forEachAlive(useProcedure); + + } + } + } + + /** + * Creates the dominator tree and searches for an solution. + */ + private void createConstantTree(DefUseTree tree) { + ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree); + constTree.set(Flags.SUBTREE, tree.getBlock()); + tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock())); + + if (constTree.get(Flags.USAGE, tree.getBlock())) { + // usage in the definition block -> no optimization + usageAtDefinitionSkipped.increment(); + return; + } + + constTree.markBlocks(); + + NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock()); + int usageCount = cost.getUsages().size(); + assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount(); + + if (Debug.isLogEnabled()) { + try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) { + Debug.log("Usages result: %s", cost); + } + + } + + if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) { + try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) { + // mark original load for removal + deleteInstruction(tree); + constantsOptimized.increment(); + + // collect result + createLoads(tree, constTree, tree.getBlock()); + + } catch (Throwable e) { + throw Debug.handle(e); + } + } else { + // no better solution found + materializeAtDefinitionSkipped.increment(); + } + Debug.dump(constTree, "ConstantTree for " + tree.getVariable()); + } + + private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock startBlock) { + Deque> worklist = new ArrayDeque<>(); + worklist.add(startBlock); + while (!worklist.isEmpty()) { + AbstractBlock block = worklist.pollLast(); + if (constTree.get(Flags.CANDIDATE, block)) { + constTree.set(Flags.MATERIALIZE, block); + // create and insert load + insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages()); + } else { + for (AbstractBlock dominated : block.getDominated()) { + if (constTree.isMarked(dominated)) { + worklist.addLast(dominated); + } + } + } + } + } + + private void insertLoad(Constant constant, LIRKind kind, AbstractBlock block, List usages) { + assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages); + // create variable + Variable variable = lirGen.newVariable(kind); + // create move + LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant); + // insert instruction + getInsertionBuffer(block).append(1, move); + Debug.log("new move (%s) and inserted in block %s", move, block); + // update usages + for (UseEntry u : usages) { + u.getPosition().set(u.getInstruction(), variable); + Debug.log("patched instruction %s", u.getInstruction()); + } + } + + /** + * Inserts the constant loads created in {@link #createConstantTree} and deletes the original + * definition. + */ + private void rewriteBlock(AbstractBlock block) { + // insert moves + LIRInsertionBuffer buffer = insertionBuffers.get(block); + if (buffer != null) { + assert buffer.initialized() : "not initialized?"; + buffer.finish(); + } + + // delete instructions + List instructions = lir.getLIRforBlock(block); + boolean hasDead = false; + for (LIRInstruction inst : instructions) { + if (inst == null) { + hasDead = true; + } else { + inst.setId(-1); + } + } + if (hasDead) { + // Remove null values from the list. + instructions.removeAll(Collections.singleton(null)); + } + } + + private void deleteInstruction(DefUseTree tree) { + AbstractBlock block = tree.getBlock(); + LIRInstruction instruction = tree.getInstruction(); + Debug.log("deleting instruction %s from block %s", instruction, block); + lir.getLIRforBlock(block).set(instruction.id(), null); + } + + private LIRInsertionBuffer getInsertionBuffer(AbstractBlock block) { + LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block); + if (insertionBuffer == null) { + insertionBuffer = new LIRInsertionBuffer(); + insertionBuffers.put(block, insertionBuffer); + assert !insertionBuffer.initialized() : "already initialized?"; + List instructions = lir.getLIRforBlock(block); + insertionBuffer.init(instructions); + } + return insertionBuffer; + } +} diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2014, 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.constopt; + +import java.util.*; +import java.util.function.*; + +import com.oracle.graal.compiler.common.cfg.*; + +/** + * Represents a dominator (sub-)tree for a constant definition. + */ +public class ConstantTree extends PrintableDominatorOptimizationProblem { + + public enum Flags { + SUBTREE, + USAGE, + MATERIALIZE, + CANDIDATE, + } + + /** + * Costs associated with a block. + */ + public static class NodeCost implements PropertyConsumable { + private List usages; + private double bestCost; + private int numMat; + + public NodeCost(double bestCost, List usages, int numMat) { + this.bestCost = bestCost; + this.usages = usages; + this.numMat = numMat; + } + + public void forEachProperty(BiConsumer action) { + action.accept("bestCost", Double.toString(getBestCost())); + action.accept("numMat", Integer.toString(getNumMaterializations())); + action.accept("numUsages", Integer.toString(usages.size())); + } + + public void addUsage(UseEntry usage) { + if (usages == null) { + usages = new ArrayList<>(); + } + usages.add(usage); + } + + public List getUsages() { + if (usages == null) { + Collections.emptyList(); + } + return usages; + } + + public double getBestCost() { + return bestCost; + } + + public int getNumMaterializations() { + return numMat; + } + + public void setBestCost(double cost) { + bestCost = cost; + } + + @Override + public String toString() { + return "NodeCost [bestCost=" + bestCost + ", numUsages=" + usages.size() + ", numMat=" + numMat + "]"; + } + } + + private final BlockMap> blockMap; + + public ConstantTree(AbstractControlFlowGraph cfg, DefUseTree tree) { + super(Flags.class, cfg); + this.blockMap = new BlockMap<>(cfg); + tree.forEach(u -> getOrInitList(u.getBlock()).add(u)); + } + + private List getOrInitList(AbstractBlock block) { + List list = blockMap.get(block); + if (list == null) { + list = new ArrayList<>(); + blockMap.put(block, list); + } + return list; + } + + public List getUsages(AbstractBlock block) { + List list = blockMap.get(block); + if (list == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(list); + } + + /** + * Returns the cost object associated with {@code block}. If there is none, a new cost object is + * created. + */ + NodeCost getOrInitCost(AbstractBlock block) { + NodeCost cost = getCost(block); + if (cost == null) { + cost = new NodeCost(block.probability(), blockMap.get(block), 1); + setCost(block, cost); + } + return cost; + } + + @Override + public String getName(Flags type) { + switch (type) { + case USAGE: + return "hasUsage"; + case SUBTREE: + return "inSubtree"; + case MATERIALIZE: + return "materialize"; + case CANDIDATE: + return "candidate"; + } + return super.getName(type); + } + + @Override + public void forEachPropertyPair(AbstractBlock block, BiConsumer action) { + if (get(Flags.SUBTREE, block) && (block.getDominator() == null || !get(Flags.SUBTREE, block.getDominator()))) { + action.accept("hasDefinition", "true"); + } + super.forEachPropertyPair(block, action); + } + + public long subTreeSize() { + return stream(Flags.SUBTREE).count(); + } + + public AbstractBlock getStartBlock() { + return stream(Flags.SUBTREE).findFirst().get(); + } + + public void markBlocks() { + stream(Flags.USAGE).forEach(block -> setDominatorPath(Flags.SUBTREE, block)); + } + + public boolean isMarked(AbstractBlock block) { + return get(Flags.SUBTREE, block); + } + + public boolean isLeafBlock(AbstractBlock block) { + return block.getDominated().stream().noneMatch(this::isMarked); + } + + public void setSolution(AbstractBlock block) { + set(Flags.MATERIALIZE, block); + } + + public int size() { + return getBlocks().size(); + } + + public void traverseTreeWhileTrue(AbstractBlock block, Predicate> action) { + assert block != null : "block must not be null!"; + if (action.test(block)) { + block.getDominated().stream().filter(this::isMarked).forEach(dominated -> traverseTreeWhileTrue(dominated, action)); + } + } + +} diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTreeAnalyzer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTreeAnalyzer.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014, 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.constopt; + +import java.util.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.constopt.ConstantTree.Flags; +import com.oracle.graal.lir.constopt.ConstantTree.NodeCost; + +/** + * Analyzes a {@link ConstantTree} and marks potential materialization positions. + */ +public class ConstantTreeAnalyzer { + private final ConstantTree tree; + private final BitSet visited; + + public static NodeCost analyze(ConstantTree tree, AbstractBlock startBlock) { + try (Scope s = Debug.scope("ConstantTreeAnalyzer")) { + ConstantTreeAnalyzer analyzer = new ConstantTreeAnalyzer(tree); + analyzer.analyzeBlocks(startBlock); + return tree.getCost(startBlock); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private ConstantTreeAnalyzer(ConstantTree tree) { + this.tree = tree; + this.visited = new BitSet(tree.size()); + } + + /** + * Queues all relevant blocks for {@linkplain #process processing}. + * + * This is a worklist-style algorithm because a (more elegant) recursive implementation may + * cause {@linkplain StackOverflowError stack overflows} on larger graphs. + * + * @param startBlock The start block of the dominator subtree. + */ + private void analyzeBlocks(AbstractBlock startBlock) { + Deque> worklist = new ArrayDeque<>(); + worklist.offerLast(startBlock); + while (!worklist.isEmpty()) { + AbstractBlock block = worklist.pollLast(); + try (Indent i = Debug.logAndIndent(3, "analyze: %s", block)) { + assert block != null : "worklist is empty!"; + assert isMarked(block) : "Block not part of the dominator tree: " + block; + + if (isLeafBlock(block)) { + Debug.log(3, "leaf block"); + leafCost(block); + continue; + } + + if (!visited.get(block.getId())) { + // if not yet visited (and not a leaf block) process all children first! + Debug.log(3, "not marked"); + worklist.offerLast(block); + List> children = block.getDominated(); + children.forEach(child -> filteredPush(worklist, child)); + visited.set(block.getId()); + } else { + Debug.log(3, "marked"); + // otherwise, process block + process(block); + } + } + } + } + + /** + * Calculates the cost of a {@code block}. It is assumed that all {@code children} have already + * been {@linkplain #process processed} + * + * @param block The block to be processed. + */ + private void process(AbstractBlock block) { + List usages = new ArrayList<>(); + double bestCost = 0; + int numMat = 0; + List> children = block.getDominated(); + assert children.stream().anyMatch(this::isMarked) : "no children? should have called leafCost(): " + block; + + // collect children costs + for (AbstractBlock child : children) { + if (isMarked(child)) { + NodeCost childCost = tree.getCost(child); + assert childCost != null : "Child with null cost? block: " + child; + usages.addAll(childCost.getUsages()); + numMat += childCost.getNumMaterializations(); + bestCost += childCost.getBestCost(); + } + } + assert numMat > 0 : "No materialization? " + numMat; + + // choose block + List usagesBlock = tree.getUsages(block); + double probabilityBlock = block.probability(); + + if (!usagesBlock.isEmpty() || shouldMaterializerInCurrentBlock(probabilityBlock, bestCost, numMat)) { + // mark current block as potential materialization position + usages.addAll(usagesBlock); + bestCost = probabilityBlock; + numMat = 1; + tree.set(Flags.CANDIDATE, block); + } else { + // stick with the current solution + } + + assert (new HashSet<>(usages)).size() == usages.size() : "doulbe entries? " + usages; + NodeCost nodeCost = new NodeCost(bestCost, usages, numMat); + tree.setCost(block, nodeCost); + } + + /** + * This is the cost function that decides whether a materialization should be inserted in the + * current block. + *

+ * Note that this function does not take into account if a materialization is required despite + * the probabilities (e.g. there are usages in the current block). + * + * @param probabilityBlock Probability of the current block. + * @param probabilityChildren Accumulated probability of the children. + * @param numMat Number of materializations along the subtrees. We use {@code numMat - 1} to + * insert materializations as late as possible if the probabilities are the same. + */ + private static boolean shouldMaterializerInCurrentBlock(double probabilityBlock, double probabilityChildren, int numMat) { + return probabilityBlock * Math.pow(0.9, numMat - 1) < probabilityChildren; + } + + private void filteredPush(Deque> worklist, AbstractBlock block) { + if (isMarked(block)) { + Debug.log(3, "adding %s to the worklist", block); + worklist.offerLast(block); + } + } + + private void leafCost(AbstractBlock block) { + tree.set(Flags.CANDIDATE, block); + tree.getOrInitCost(block); + } + + private boolean isMarked(AbstractBlock block) { + return tree.isMarked(block); + } + + private boolean isLeafBlock(AbstractBlock block) { + return tree.isLeafBlock(block); + } + +} diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/DefUseTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/DefUseTree.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, 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.constopt; + +import java.util.*; +import java.util.function.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.MoveOp; + +/** + * Represents def-use tree of a constant. + */ +class DefUseTree { + private final LIRInstruction instruction; + private final AbstractBlock block; + private final List uses; + + public DefUseTree(LIRInstruction instruction, AbstractBlock block) { + assert instruction instanceof MoveOp : "Not a MoveOp: " + instruction; + this.instruction = instruction; + this.block = block; + this.uses = new ArrayList<>(); + } + + public Variable getVariable() { + return (Variable) ((MoveOp) instruction).getResult(); + } + + public Constant getConstant() { + return (Constant) ((MoveOp) instruction).getInput(); + } + + public LIRInstruction getInstruction() { + return instruction; + } + + public AbstractBlock getBlock() { + return block; + } + + @Override + public String toString() { + return "DefUseTree [" + instruction + "|" + block + "," + uses + "]"; + } + + public void addUsage(AbstractBlock b, LIRInstruction inst, ValuePosition position) { + uses.add(new UseEntry(b, inst, position)); + } + + public int usageCount() { + return uses.size(); + } + + public void forEach(Consumer action) { + uses.forEach(action); + } + +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/UseEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/UseEntry.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, 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.constopt; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; + +/** + * Represents a usage of a constant. + */ +class UseEntry { + + private final AbstractBlock block; + private final LIRInstruction instruction; + private final ValuePosition position; + + public UseEntry(AbstractBlock block, LIRInstruction instruction, ValuePosition position) { + this.block = block; + this.instruction = instruction; + this.position = position; + } + + public LIRInstruction getInstruction() { + return instruction; + } + + public AbstractBlock getBlock() { + return block; + } + + public ValuePosition getPosition() { + return position; + } + + public Value getValue() { + return position.get(instruction); + } + + @Override + public String toString() { + return "Use[" + getValue() + ":" + instruction + ":" + block + "]"; + } +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/VariableMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/VariableMap.java Tue Aug 26 09:35:08 2014 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014, 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.constopt; + +import java.util.*; +import java.util.function.*; + +import com.oracle.graal.lir.*; + +/** + * Maps variables to a generic type. + * + * TODO (je) evaluate data structure + */ +class VariableMap { + + private final ArrayList content; + + public VariableMap() { + content = new ArrayList<>(); + } + + public T get(Variable key) { + if (key == null || key.index >= content.size()) { + return null; + } + return content.get(key.index); + } + + public T put(Variable key, T value) { + assert key != null : "Key cannot be null"; + assert value != null : "Value cannot be null"; + while (key.index >= content.size()) { + content.add(null); + } + return content.set(key.index, value); + } + + public T remove(Variable key) { + assert key != null : "Key cannot be null"; + if (key.index >= content.size()) { + return null; + } + return content.set(key.index, null); + } + + public void forEach(Consumer action) { + for (T e : content) { + if (e != null) { + action.accept(e); + } + } + } + + /** + * Keeps only keys which match the given predicate. + */ + public void filter(Predicate predicate) { + for (int i = 0; i < content.size(); i++) { + T e = content.get(i); + if (e != null && !predicate.test(e)) { + content.set(i, null); + } + } + } + +} \ No newline at end of file diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Aug 26 09:35:08 2014 -0700 @@ -273,24 +273,20 @@ } } - // Currently no node printing for lir - if (lir == null) { - Node cur = block.getBeginNode(); - while (true) { - printNode(cur, false); + Node cur = block.getBeginNode(); + while (true) { + printNode(cur, false); - if (cur == block.getEndNode()) { - for (Map.Entry entry : latestScheduling.entries()) { - if (entry.getValue() == block && !inFixedSchedule(entry.getKey()) && !printedNodes.isMarked(entry.getKey())) { - printNode(entry.getKey(), true); - } + if (cur == block.getEndNode()) { + for (Map.Entry entry : latestScheduling.entries()) { + if (entry.getValue() == block && !inFixedSchedule(entry.getKey()) && !printedNodes.isMarked(entry.getKey())) { + printNode(entry.getKey(), true); } - break; } - assert cur.successors().count() == 1; - cur = cur.successors().first(); + break; } - + assert cur.successors().count() == 1; + cur = cur.successors().first(); } out.enableIndentation(); diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Tue Aug 26 09:35:08 2014 -0700 @@ -50,7 +50,6 @@ private JavaMethod curMethod; private List curDecorators = Collections.emptyList(); private final boolean dumpFrontend; - private Object previousObject; public CFGPrinterObserver(boolean dumpFrontend) { this.dumpFrontend = dumpFrontend; @@ -162,10 +161,8 @@ } } else if (object instanceof LIR) { - // No need to print the HIR nodes again if this is not the first - // time dumping the same LIR since the HIR will not have changed. - boolean printNodes = previousObject != object && cfgPrinter.cfg != null; - cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), printNodes); + // Currently no node printing for lir + cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), false); } else if (object instanceof SchedulePhase) { cfgPrinter.printSchedule(message, (SchedulePhase) object); @@ -193,7 +190,6 @@ cfgPrinter.cfg = null; cfgPrinter.flush(); - previousObject = object; } private static boolean isCompilationResultAndInstalledCode(Object object) { diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java Tue Aug 26 09:35:08 2014 -0700 @@ -108,7 +108,7 @@ public void test7() { char[] src = "1234567890".toCharArray(); char[] dst = new char[src.length]; - int n = Runtime.getRuntime().availableProcessors(); + int n = Math.min(32, Runtime.getRuntime().availableProcessors()); testN(n, "copyArr", src, dst, 100); } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Tue Aug 26 09:35:08 2014 -0700 @@ -72,7 +72,11 @@ public void testMulHighUnsigned() { test("mulHighUnsigned", 7, 15); test("mulHighUnsigned", Integer.MAX_VALUE, 15); + test("mulHighUnsigned", 15, Integer.MAX_VALUE); + test("mulHighUnsigned", Integer.MAX_VALUE, Integer.MAX_VALUE); + test("mulHighUnsigned", 15, Integer.MIN_VALUE); test("mulHighUnsigned", Integer.MIN_VALUE, 15); + test("mulHighUnsigned", Integer.MIN_VALUE, Integer.MIN_VALUE); } @Test @@ -98,7 +102,11 @@ public void testLongMulHigh() { test("longMulHigh", 7L, 15L); test("longMulHigh", Long.MAX_VALUE, 15L); + test("longMulHigh", 15L, Long.MAX_VALUE); + test("longMulHigh", Long.MAX_VALUE, Long.MAX_VALUE); test("longMulHigh", Long.MIN_VALUE, 15L); + test("longMulHigh", 15L, Long.MIN_VALUE); + test("longMulHigh", Long.MIN_VALUE, Long.MIN_VALUE); } @Test diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Tue Aug 26 09:35:08 2014 -0700 @@ -34,6 +34,7 @@ import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.model.*; import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.DeclaredCodeTypeMirror; +import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.WildcardTypeMirror; /** * THIS IS NOT PUBLIC API. @@ -1034,4 +1035,35 @@ return actualType.getKind() == TypeKind.DECLARED && getQualifiedName(actualType).equals("java.lang.Object"); } + public static TypeMirror fillInGenericWildcards(TypeMirror type) { + if (type.getKind() != TypeKind.DECLARED) { + return type; + } + DeclaredType declaredType = (DeclaredType) type; + TypeElement element = (TypeElement) declaredType.asElement(); + if (element == null) { + return type; + } + int typeParameters = element.getTypeParameters().size(); + if (typeParameters > 0 && declaredType.getTypeArguments().size() != typeParameters) { + List genericTypes = new ArrayList<>(); + for (int i = 0; i < typeParameters; i++) { + genericTypes.add(new WildcardTypeMirror(null, null)); + } + return new DeclaredCodeTypeMirror(element, genericTypes); + } + return type; + } + + public static TypeMirror eraseGenericTypes(TypeMirror type) { + if (type.getKind() != TypeKind.DECLARED) { + return type; + } + DeclaredType declaredType = (DeclaredType) type; + if (declaredType.getTypeArguments().size() == 0) { + return type; + } + return new DeclaredCodeTypeMirror((TypeElement) declaredType.asElement()); + } + } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Tue Aug 26 09:35:08 2014 -0700 @@ -592,7 +592,7 @@ } public CodeTreeBuilder typeLiteral(TypeMirror type) { - return startGroup().type(type).string(".class").end(); + return startGroup().type(ElementUtils.eraseGenericTypes(type)).string(".class").end(); } private void assertRoot() { diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeMirror.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeMirror.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeMirror.java Tue Aug 26 09:35:08 2014 -0700 @@ -46,6 +46,27 @@ throw new UnsupportedOperationException(); } + public static class WildcardTypeMirror extends CodeTypeMirror implements WildcardType { + + private final TypeMirror extendsBounds; + private final TypeMirror superBounds; + + public WildcardTypeMirror(TypeMirror extendsBounds, TypeMirror superBounds) { + super(TypeKind.WILDCARD); + this.extendsBounds = extendsBounds; + this.superBounds = superBounds; + } + + public TypeMirror getExtendsBound() { + return extendsBounds; + } + + public TypeMirror getSuperBound() { + return superBounds; + } + + } + public static class ArrayCodeTypeMirror extends CodeTypeMirror implements ArrayType { private final TypeMirror component; @@ -65,13 +86,13 @@ public static class DeclaredCodeTypeMirror extends CodeTypeMirror implements DeclaredType { private final TypeElement clazz; - private final List typeArguments; + private final List typeArguments; public DeclaredCodeTypeMirror(TypeElement clazz) { this(clazz, Collections. emptyList()); } - public DeclaredCodeTypeMirror(TypeElement clazz, List typeArguments) { + public DeclaredCodeTypeMirror(TypeElement clazz, List typeArguments) { super(TypeKind.DECLARED); this.clazz = clazz; this.typeArguments = typeArguments; @@ -88,7 +109,7 @@ } @Override - public List getTypeArguments() { + public List getTypeArguments() { return typeArguments; } diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java Tue Aug 26 09:35:08 2014 -0700 @@ -107,6 +107,8 @@ b.append("? extends ").append(createTypeReference(enclosedElement, type.getExtendsBound())); } else if (type.getSuperBound() != null) { b.append("? super ").append(createTypeReference(enclosedElement, type.getExtendsBound())); + } else { + b.append("?"); } return b.toString(); } @@ -122,18 +124,23 @@ } } - if (type.getTypeArguments().size() == 0) { + List genericTypes = type.getTypeArguments(); + if (genericTypes.size() == 0) { return name; } StringBuilder b = new StringBuilder(name); b.append("<"); - if (type.getTypeArguments().size() > 0) { - for (int i = 0; i < type.getTypeArguments().size(); i++) { - b.append(createTypeReference(enclosedElement, type.getTypeArguments().get(i))); - if (i < type.getTypeArguments().size() - 1) { - b.append(", "); - } + for (int i = 0; i < genericTypes.size(); i++) { + TypeMirror genericType = i < genericTypes.size() ? genericTypes.get(i) : null; + if (genericType != null) { + b.append(createTypeReference(enclosedElement, genericType)); + } else { + b.append("?"); + } + + if (i < genericTypes.size() - 1) { + b.append(", "); } } b.append(">"); diff -r 5ed920f3aa18 -r 7ef0a2355540 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Mon Aug 25 11:44:45 2014 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Tue Aug 26 09:35:08 2014 -0700 @@ -183,10 +183,12 @@ int index = 0; for (TypeMirror primitiveType : typeMirrors) { - TypeMirror boxedType = ElementUtils.boxType(context, primitiveType); - TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitiveType, boxedType); + TypeMirror primitive = ElementUtils.fillInGenericWildcards(primitiveType); - if (isPrimitiveWrapper(primitiveType)) { + TypeMirror boxedType = ElementUtils.boxType(context, primitive); + TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitive, boxedType); + + if (isPrimitiveWrapper(primitive)) { typeData.addError("Types must not contain primitive wrapper types."); } diff -r 5ed920f3aa18 -r 7ef0a2355540 mx/projects --- a/mx/projects Mon Aug 25 11:44:45 2014 -0700 +++ b/mx/projects Tue Aug 26 09:35:08 2014 -0700 @@ -390,7 +390,7 @@ # graal.lir project@com.oracle.graal.lir@subDir=graal project@com.oracle.graal.lir@sourceDirs=src -project@com.oracle.graal.lir@dependencies=com.oracle.graal.debug,com.oracle.graal.compiler.common,com.oracle.graal.asm +project@com.oracle.graal.lir@dependencies=com.oracle.graal.compiler.common,com.oracle.graal.asm,com.oracle.graal.debug project@com.oracle.graal.lir@checkstyle=com.oracle.graal.graph project@com.oracle.graal.lir@javaCompliance=1.8 project@com.oracle.graal.lir@workingSets=Graal,LIR diff -r 5ed920f3aa18 -r 7ef0a2355540 mxtool/mx.py --- a/mxtool/mx.py Mon Aug 25 11:44:45 2014 -0700 +++ b/mxtool/mx.py Tue Aug 26 09:35:08 2014 -0700 @@ -1247,11 +1247,11 @@ """ Get the list of all loaded projects limited by --suite option if opt_limit_to_suite == True """ - + sortedProjects = sorted(_projects.values(), key=lambda p: p.name) if opt_limit_to_suite: - return _projects_opt_limit_to_suites(_projects.values()) + return _projects_opt_limit_to_suites(sortedProjects) else: - return _projects.values() + return sortedProjects def projects_opt_limit_to_suites(): """ @@ -2231,8 +2231,13 @@ self.proj.definedAnnotationProcessorsDist.make_archive() finally: - for n in toBeDeleted: - os.remove(n) + # Do not clean up temp files if verbose as there's + # a good chance the user wants to copy and paste the + # Java compiler command directly + if not _opts.verbose: + for n in toBeDeleted: + os.remove(n) + self.done = True def build(args, parser=None): @@ -2413,6 +2418,8 @@ logv('[no Java sources for {0} - skipping]'.format(p.name)) continue + javafilelist = sorted(javafilelist) + task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, jdtJar, taskDeps) if p.definedAnnotationProcessorsDist: updatedAnnotationProcessorDists.add(p.definedAnnotationProcessorsDist) diff -r 5ed920f3aa18 -r 7ef0a2355540 src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Mon Aug 25 11:44:45 2014 -0700 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue Aug 26 09:35:08 2014 -0700 @@ -3433,6 +3433,9 @@ if (UseStackBanging) { pad += StackShadowPages*16 + 32; } +#ifdef GRAAL + pad += 32; // Increase the buffer size when compiling for GRAAL +#endif #ifdef _LP64 CodeBuffer buffer("deopt_blob", 2100+pad, 512); #else @@ -3567,6 +3570,33 @@ // Restore G2_thread __ get_thread(); +#ifdef GRAAL + // load throwing pc from JavaThread and patch it as the return address + // of the current frame. Then clear the field in JavaThread + __ block_comment("load throwing pc and patch return"); + Address exception_pc(G2_thread, JavaThread::exception_pc_offset()); + Label has_no_pc; + // TODO: Remove this weird check if we should patch the return pc + // This is because when graal decides to deoptimize and the ExceptionHandlerStub.java + // jumps back to this code and the I7 register contains the pc pointing to the begin + // of this code. If this is the case (PC within a certain range) then we need to patch + // the return pc. + // THIS NEEDS REWORK! (sa) + __ rdpc(L0); + __ sub(L0, I7, L0); + __ cmp(L0, 0xFFF); + __ br(Assembler::greater, false, Assembler::pt, has_no_pc); + __ delayed() -> nop(); + __ cmp(L0, -0xFFF); + __ br(Assembler::less, false, Assembler::pt, has_no_pc); + __ delayed() -> nop(); + __ ld_ptr(exception_pc, I7); + __ sub(I7, 8, I7); + __ st_ptr(G0, exception_pc); + __ bind(has_no_pc); + __ block_comment("/load throwing pc and patch return"); +#endif // GAAL + #ifdef ASSERT { // verify that there is really an exception oop in exception_oop diff -r 5ed920f3aa18 -r 7ef0a2355540 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Mon Aug 25 11:44:45 2014 -0700 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Tue Aug 26 09:35:08 2014 -0700 @@ -199,6 +199,22 @@ address InterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); __ get_constant_pool_cache(LcpoolCache); // load LcpoolCache +#ifdef GRAAL + // Check if we need to take lock at entry of synchronized method. + { + Label L; + + //__ cmp(, 0); + Address pending_monitor_enter_addr(G2_thread, Thread::pending_monitorenter_offset()); + __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter + __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L); + // Clear flag. + __ stbool(G0, pending_monitor_enter_addr); + // Take lock. + lock_method(); + __ bind(L); + } +#endif { Label L; Address exception_addr(G2_thread, Thread::pending_exception_offset()); __ ld_ptr(exception_addr, Gtemp); // Load pending exception. @@ -1689,8 +1705,13 @@ // make sure I5_savedSP and the entry frames notion of saved SP // agree. This assertion duplicate a check in entry frame code // but catches the failure earlier. - assert(*caller->register_addr(Lscratch) == *interpreter_frame->register_addr(I5_savedSP), + /* + * Sanzinger: This does not make sense to me, since when we call stub_call -> i2c, the i2c may change the + * sp, which then is not in sync with Lscratch anymore. + */ + /**assert(*caller->register_addr(Lscratch) == *interpreter_frame->register_addr(I5_savedSP), "would change callers SP"); + */ } if (caller->is_entry_frame()) { tty->print("entry "); diff -r 5ed920f3aa18 -r 7ef0a2355540 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Mon Aug 25 11:44:45 2014 -0700 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Tue Aug 26 09:35:08 2014 -0700 @@ -231,6 +231,8 @@ Location::Type locationType; if (type == T_INT) { locationType = reference ? Location::narrowoop : Location::int_in_long; + } else if(type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN) { + locationType = Location::int_in_long; } else if (type == T_FLOAT) { locationType = Location::int_in_long; } else if (type == T_LONG) { @@ -264,7 +266,7 @@ #ifdef TARGET_ARCH_sparc ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, as_FloatRegister(encoding)->as_VMReg())); if (type == T_DOUBLE) { - second = new ConstantIntValue(0); + second = value; } return value; #else @@ -278,6 +280,8 @@ locationType = reference ? Location::oop : Location::lng; } else if (type == T_INT) { locationType = reference ? Location::narrowoop : Location::normal; + } else if(type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN) { + locationType = Location::normal; } else if (type == T_FLOAT) { assert(!reference, "unexpected type in stack slot"); locationType = Location::normal; @@ -289,6 +293,11 @@ locationType = Location::oop; } jint offset = StackSlot::offset(value); +#ifdef TARGET_ARCH_sparc + if(offset >= 0) { + offset += 128; + } +#endif if (StackSlot::addFrameSize(value)) { offset += total_frame_size; }