# HG changeset patch # User Thomas Wuerthinger # Date 1309537444 -7200 # Node ID 5cdaa94cd622ebde4392a717348a4eb8bc23e6ef # Parent 0affee9ff3a9923a3a70cebb5f817e6db4954ecd# Parent 3664989976e2aee48278b4928a43893e3df714a9 Merge. diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Fri Jul 01 18:24:04 2011 +0200 @@ -73,9 +73,13 @@ @Override public void verificationFailed(Node n, String message) { GraalCompiler.this.fireCompilationEvent(new CompilationEvent(currentCompilation, "Verification Error on Node " + n.id(), currentCompilation.graph, true, false, true)); + TTY.println(n.toString()); for (Node p : n.predecessors()) { TTY.println("predecessor: " + p); } + for (Node p : n.usages()) { + TTY.println("usage: " + p); + } assert false : "Verification of node " + n + " failed: " + message; } }); diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Fri Jul 01 18:24:04 2011 +0200 @@ -108,8 +108,10 @@ public static boolean TraceInlining = ____; public static boolean TraceDeadCodeElimination = ____; public static boolean TraceEscapeAnalysis = ____; + public static boolean TraceCanonicalizer = ____; public static boolean TraceMemoryMaps = ____; public static boolean TraceReadElimination = ____; + public static boolean TraceGVN = ____; public static int TraceBytecodeParserLevel = 0; public static boolean QuietBailout = ____; @@ -149,6 +151,7 @@ public static boolean CommentedAssembly = ____; public static boolean PrintLIRWithAssembly = ____; + public static boolean OptGVN = true; public static boolean OptCanonicalizer = true; public static boolean OptLoops = true; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java Fri Jul 01 18:24:04 2011 +0200 @@ -130,6 +130,8 @@ ((LIRBranch) instr).substitute(block, newTarget); } else if (instr instanceof LIRTableSwitch) { ((LIRTableSwitch) instr).substitute(block, newTarget); + } else if (instr instanceof LIRXirInstruction) { + ((LIRXirInstruction) instr).substitute(block, newTarget); } } } @@ -246,8 +248,8 @@ for (LIRInstruction instr : instructions) { if (instr instanceof LIRBranch) { LIRBranch opBranch = (LIRBranch) instr; - assert opBranch.block() == null || code.contains(opBranch.block()) : "missing successor branch from: " + block + " to: " + opBranch.block(); - assert opBranch.unorderedBlock() == null || code.contains(opBranch.unorderedBlock()) : "missing successor branch from: " + block + " to: " + opBranch.unorderedBlock(); + assert opBranch.block() == null || opBranch.block().blockID() == -1 || code.contains(opBranch.block()) : "missing successor branch from: " + block + " to: " + opBranch.block(); + assert opBranch.unorderedBlock() == null || opBranch.unorderedBlock().blockID() == -1 || code.contains(opBranch.unorderedBlock()) : "missing successor branch from: " + block + " to: " + opBranch.unorderedBlock(); } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java Fri Jul 01 18:24:04 2011 +0200 @@ -136,8 +136,12 @@ return; } + if (predInstructions.get(predInstructions.size() - 1).code == LIROpcode.Xir) { + return; + } + assert pred.suxAt(0) == block : "invalid control flow"; - assert predInstructions.get(predInstructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch"; + assert predInstructions.get(predInstructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch" + predInstructions.get(predInstructions.size() - 1); assert predInstructions.get(predInstructions.size() - 1) instanceof LIRBranch : "branch must be LIROpBranch"; assert ((LIRBranch) predInstructions.get(predInstructions.size() - 1)).cond() == Condition.TRUE : "block must end with unconditional branch"; @@ -191,6 +195,11 @@ assert numSux == 2 : "method should not be called otherwise"; + if (instructions.get(instructions.size() - 1).code == LIROpcode.Xir) { + // cannot optimize when last instruction is Xir. + return; + } + assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch block=B" + block.blockID(); assert instructions.get(instructions.size() - 1) instanceof LIRBranch : "branch must be LIROpBranch"; assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block must end with unconditional branch"; diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Fri Jul 01 18:24:04 2011 +0200 @@ -354,13 +354,6 @@ } @Override - public void visitInstanceOf(InstanceOf x) { - XirArgument obj = toXirArgument(x.object()); - XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass()); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override public void visitMonitorEnter(MonitorEnter x) { XirArgument obj = toXirArgument(x.object()); XirArgument lockAddress = toXirArgument(x.lockAddress()); @@ -461,12 +454,8 @@ @Override public void visitIf(If x) { - Condition cond = emitBooleanBranch(x.compare()); - emitBranch(x.compare(), cond, getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor())); - assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination above"; - LIRBlock block = getLIRBlock(x.defaultSuccessor()); - assert block != null : x; - lir.jump(block); + assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination"; + emitBooleanBranch(x.compare(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), null); } public void emitBranch(BooleanNode n, Condition cond, LIRBlock trueSuccessor, LIRBlock falseSucc) { @@ -484,18 +473,39 @@ lir.branch(cond, trueSuccessor); } - public Condition emitBooleanBranch(BooleanNode node) { + public void emitBooleanBranch(Node node, LIRBlock trueSuccessor, LIRBlock falseSuccessor, LIRDebugInfo info) { if (node instanceof Compare) { - return emitCompare((Compare) node); + emitCompare((Compare) node, trueSuccessor, falseSuccessor); + } else if (node instanceof InstanceOf) { + emitInstanceOf((TypeCheck) node, trueSuccessor, falseSuccessor, info); + } else if (node instanceof NotInstanceOf) { + emitInstanceOf((TypeCheck) node, falseSuccessor, trueSuccessor, info); } else { - throw Util.unimplemented(); + throw Util.unimplemented(node.toString()); } } - public Condition emitCompare(Compare compare) { + private void emitInstanceOf(TypeCheck x, LIRBlock trueSuccessor, LIRBlock falseSuccessor, LIRDebugInfo info) { + XirArgument obj = toXirArgument(x.object()); + XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass()); + emitXir(snippet, x, info, null, false); + LIRXirInstruction instr = (LIRXirInstruction) lir.instructionsList().get(lir.instructionsList().size() - 1); + instr.setTrueSuccessor(trueSuccessor); + instr.setFalseSuccessor(falseSuccessor); + } + + public void emitCompare(Compare compare, LIRBlock trueSuccessorBlock, LIRBlock falseSuccessorBlock) { CiKind kind = compare.x().kind; Condition cond = compare.condition(); + boolean unorderedIsTrue = compare.unorderedIsTrue(); + + if (trueSuccessorBlock == null) { + cond = cond.negate(); + unorderedIsTrue = !unorderedIsTrue; + trueSuccessorBlock = falseSuccessorBlock; + falseSuccessorBlock = null; + } LIRItem xitem = new LIRItem(compare.x(), this); LIRItem yitem = new LIRItem(compare.y(), this); @@ -523,7 +533,20 @@ CiValue left = xin.result(); CiValue right = yin.result(); lir.cmp(cond, left, right); - return cond; + + if (compare.x().kind.isFloat() || compare.x().kind.isDouble()) { + LIRBlock unorderedSuccBlock = falseSuccessorBlock; + if (unorderedIsTrue) { + unorderedSuccBlock = trueSuccessorBlock; + } + lir.branch(cond, trueSuccessorBlock, unorderedSuccBlock); + } else { + lir.branch(cond, trueSuccessorBlock); + } + + if (falseSuccessorBlock != null) { + lir.jump(falseSuccessorBlock); + } } @Override @@ -743,12 +766,10 @@ if (deoptimizationStubs == null) { deoptimizationStubs = new ArrayList(); } - DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state); deoptimizationStubs.add(stub); - Condition cond = emitBooleanBranch(comp); - lir.branch(cond.negate(), stub.label, stub.info); + emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info); } } @@ -1117,7 +1138,7 @@ * @param x an instruction that produces a result * @return the variable assigned to hold the result produced by {@code x} */ - protected CiVariable createResultVariable(Value x) { + public CiVariable createResultVariable(Value x) { CiVariable operand = newVariable(x.kind); setResult(x, operand); return operand; diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/CompilerGraph.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/CompilerGraph.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/CompilerGraph.java Fri Jul 01 18:24:04 2011 +0200 @@ -25,6 +25,7 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.graph.*; +import com.sun.cri.ri.*; public class CompilerGraph extends Graph { @@ -56,6 +57,9 @@ return unwindSingleton; } + public RiRuntime runtime() { + return compilation.runtime; + } public GraalCompilation getCompilation() { return compilation; diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Fri Jul 01 18:24:04 2011 +0200 @@ -107,6 +107,12 @@ new DeadCodeEliminationPhase().apply(graph); } + if (GraalOptions.OptGVN) { + new GlobalValueNumberingPhase().apply(graph); + } +// +// new EscapeAnalysisPhase().apply(graph); + if (GraalOptions.OptLoops) { new LoopPhase().apply(graph); } @@ -114,6 +120,9 @@ if (GraalOptions.Lower) { new LoweringPhase(compilation.runtime).apply(graph); new MemoryPhase().apply(graph); + if (GraalOptions.OptGVN) { + new GlobalValueNumberingPhase().apply(graph); + } new ReadEliminationPhase().apply(graph); } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BooleanNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BooleanNode.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BooleanNode.java Fri Jul 01 18:24:04 2011 +0200 @@ -32,4 +32,8 @@ super(kind, inputCount, successorCount, graph); } + + public BooleanNode negate() { + throw new IllegalStateException(); + } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java Fri Jul 01 18:24:04 2011 +0200 @@ -23,7 +23,6 @@ package com.oracle.max.graal.compiler.ir; import com.oracle.max.graal.compiler.debug.*; -import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; @@ -43,8 +42,8 @@ * @param object the instruction producing the object * @param graph */ - public CheckCast(RiType targetClass, Value targetClassInstruction, Value object, Graph graph) { - super(targetClass, targetClassInstruction, object, CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); + public CheckCast(Constant targetClassInstruction, Value object, Graph graph) { + super(targetClassInstruction, object, CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); } /** @@ -53,7 +52,7 @@ */ @Override public RiType declaredType() { - return targetClass; + return targetClass(); } /** @@ -62,7 +61,7 @@ */ @Override public RiType exactType() { - return targetClass.isResolved() ? targetClass.exactType() : null; + return targetClass().isResolved() ? targetClass().exactType() : null; } @Override @@ -70,19 +69,15 @@ v.visitCheckCast(this); } - @Override - public int valueNumber() { - return targetClass.isResolved() ? Util.hash1(Bytecodes.CHECKCAST, object()) : 0; - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof CheckCast) { - CheckCast o = (CheckCast) i; - return targetClass == o.targetClass && object() == o.object(); - } - return false; - } +// @Override +// public int valueNumber() { +// return targetClass().isResolved() ? Util.hash1(Bytecodes.CHECKCAST, object()) : 0; +// } +// +// @Override +// public boolean valueEqual(Node i) { +// return i instanceof CheckCast; +// } @Override public void print(LogStream out) { @@ -96,7 +91,7 @@ @Override public Node copy(Graph into) { - CheckCast x = new CheckCast(targetClass, null, null, into); + CheckCast x = new CheckCast(null, null, into); return x; } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Compare.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Compare.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Compare.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,7 +22,10 @@ */ package com.oracle.max.graal.compiler.ir; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.*; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -138,10 +141,71 @@ return "Comp " + condition.operator; } + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + @Override public Node copy(Graph into) { Compare x = new Compare(null, condition, null, into); x.unorderedIsTrue = unorderedIsTrue; return x; } + + @Override + public BooleanNode negate() { + return new Compare(x(), condition.negate(), y(), graph()); + } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + Compare compare = (Compare) node; + if (compare.x().isConstant() && compare.y().isConstant()) { + CiConstant constX = compare.x().asConstant(); + CiConstant constY = compare.y().asConstant(); + Boolean result = compare.condition().foldCondition(constX, constY, ((CompilerGraph) node.graph()).runtime()); + if (result != null) { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("folded condition " + constX + " " + compare.condition() + " " + constY); + } + return Constant.forBoolean(result, compare.graph()); + } else { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind); + } + } + } else if (compare.x().isConstant() && compare.y() instanceof MaterializeNode) { + return optimizeMaterialize(compare, compare.x().asConstant(), (MaterializeNode) compare.y()); + } else if (compare.y().isConstant() && compare.x() instanceof MaterializeNode) { + return optimizeMaterialize(compare, compare.y().asConstant(), (MaterializeNode) compare.x()); + } + return compare; + } + + private Node optimizeMaterialize(Compare compare, CiConstant constant, MaterializeNode materializeNode) { + if (constant.kind == CiKind.Int) { + boolean isFalseCheck = (constant.asInt() == 0); + if (compare.condition == Condition.EQ || compare.condition == Condition.NE) { + if (compare.condition == Condition.NE) { + isFalseCheck = !isFalseCheck; + } + BooleanNode result = materializeNode.value(); + if (isFalseCheck) { + result = result.negate(); + } + if (GraalOptions.TraceCanonicalizer) { + TTY.println("Removed materialize replacing with " + result); + } + return result; + } + } + return compare; + } + }; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Constant.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Constant.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Constant.java Fri Jul 01 18:24:04 2011 +0200 @@ -33,7 +33,7 @@ * The {@code Constant} instruction represents a constant such as an integer value, * long, float, object reference, address, etc. */ -public final class Constant extends FloatingNode { +public final class Constant extends BooleanNode { private static final int INPUT_COUNT = 0; private static final int SUCCESSOR_COUNT = 0; @@ -55,6 +55,14 @@ v.visitConstant(this); } + @Override + public BooleanNode negate() { + if (kind != CiKind.Boolean) { + throw new IllegalStateException(); + } + return Constant.forBoolean(!value.asBoolean(), graph()); + } + /** * Creates an instruction for a double constant. * @param d the double value for which to create the instruction @@ -193,7 +201,6 @@ @Override public Node copy(Graph into) { - Constant x = new Constant(value, into); - return x; + return new Constant(value, into); } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FixedGuard.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FixedGuard.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FixedGuard.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,7 +22,10 @@ */ package com.oracle.max.graal.compiler.ir; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -44,8 +47,9 @@ inputs().set(super.inputCount() + INPUT_NODE, n); } - public FixedGuard(Graph graph) { + public FixedGuard(BooleanNode node, Graph graph) { super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setNode(node); } @Override @@ -60,6 +64,37 @@ @Override public Node copy(Graph into) { - return new FixedGuard(into); + return new FixedGuard(null, into); + } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + FixedGuard fixedGuard = (FixedGuard) node; + if (fixedGuard.node() instanceof Constant) { + Constant c = (Constant) fixedGuard.node(); + if (c.asConstant().asBoolean()) { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("Removing redundant fixed guard " + fixedGuard); + } + return fixedGuard.next(); + } else { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("Replacing fixed guard " + fixedGuard + " with deoptimization node"); + } + return new Deoptimize(DeoptAction.InvalidateRecompile, fixedGuard.graph()); + } + } + return fixedGuard; + } + }; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/GuardNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/GuardNode.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/GuardNode.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,7 +22,9 @@ */ package com.oracle.max.graal.compiler.ir; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -64,11 +66,37 @@ @Override public void print(LogStream out) { - out.print("clip node ").print(node()); + out.print("guard node ").print(node()); } @Override public Node copy(Graph into) { return new GuardNode(into); } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + GuardNode guard = (GuardNode) node; + if (guard.node() instanceof Constant) { + Constant c = (Constant) guard.node(); + if (c.asConstant().asBoolean()) { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("Removing redundant floating guard " + guard); + } + return Node.Null; + } + } + return guard; + } + }; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,7 +22,9 @@ */ package com.oracle.max.graal.compiler.ir; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -112,4 +114,35 @@ public Node copy(Graph into) { return new If(null, into); } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + If ifNode = (If) node; + if (ifNode.compare() instanceof Constant) { + Constant c = (Constant) ifNode.compare(); + if (c.asConstant().asBoolean()) { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("Replacing if " + ifNode + " with true branch"); + } + return ifNode.trueSuccessor(); + } else { + if (GraalOptions.TraceCanonicalizer) { + TTY.println("Replacing if " + ifNode + " with false branch"); + } + return ifNode.falseSuccessor(); + } + } + return ifNode; + } + }; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java Fri Jul 01 18:24:04 2011 +0200 @@ -27,7 +27,6 @@ import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; -import com.sun.cri.ri.*; /** * The {@code InstanceOf} instruction represents an instanceof test. @@ -43,13 +42,12 @@ * @param object the instruction producing the object input to this instruction * @param graph */ - public InstanceOf(RiType targetClass, Value targetClassInstruction, Value object, Graph graph) { - super(targetClass, targetClassInstruction, object, CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); + public InstanceOf(Constant targetClassInstruction, Value object, Graph graph) { + super(targetClassInstruction, object, CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); } @Override public void accept(ValueVisitor v) { - v.visitInstanceOf(this); } @Override @@ -59,11 +57,7 @@ @Override public boolean valueEqual(Node i) { - if (i instanceof InstanceOf) { - InstanceOf o = (InstanceOf) i; - return targetClass == o.targetClass && object() == o.object(); - } - return false; + return i instanceof InstanceOf; } @Override @@ -72,8 +66,12 @@ } @Override + public BooleanNode negate() { + return new NotInstanceOf(targetClassInstruction(), object(), graph()); + } + + @Override public Node copy(Graph into) { - InstanceOf x = new InstanceOf(targetClass, null, null, into); - return x; + return new InstanceOf(null, null, into); } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java Fri Jul 01 18:24:04 2011 +0200 @@ -83,11 +83,7 @@ @Override public boolean valueEqual(Node i) { - if (i instanceof IsNonNull) { - IsNonNull o = (IsNonNull) i; - return object() == o.object(); - } - return false; + return i instanceof IsNonNull; } @Override diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java Fri Jul 01 18:24:04 2011 +0200 @@ -95,7 +95,7 @@ public boolean valueEqual(Node i) { if (i instanceof IsType) { IsType o = (IsType) i; - return type == o.type() && object() == o.object(); + return type == o.type(); } return false; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LocationNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LocationNode.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LocationNode.java Fri Jul 01 18:24:04 2011 +0200 @@ -36,7 +36,12 @@ private CiKind valueKind; private Object locationIdentity; - public LocationNode(Object identity, CiKind kind, int displacement, Graph graph) { + public static LocationNode create(Object identity, CiKind kind, int displacement, Graph graph) { + LocationNode result = new LocationNode(identity, kind, displacement, graph); + return graph.ideal(result); + } + + private LocationNode(Object identity, CiKind kind, int displacement, Graph graph) { super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); this.displacement = displacement; this.valueKind = kind; @@ -73,7 +78,17 @@ return locationIdentity; } - public boolean same(LocationNode location) { - return valueKind == location.valueKind && displacement == location.displacement; + @Override + public boolean valueEqual(Node i) { + if (i instanceof LocationNode) { + LocationNode locationNode = (LocationNode) i; + return locationNode.locationIdentity == locationIdentity && locationNode.displacement == displacement; + } + return false; + } + + @Override + public int valueNumber() { + return locationIdentity.hashCode() + displacement; } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java Fri Jul 01 18:24:04 2011 +0200 @@ -42,7 +42,6 @@ } } } - assert false : "LoopBegin should always have a LoopEnd"; return null; } @@ -63,8 +62,7 @@ @Override public Node copy(Graph into) { - LoopBegin x = new LoopBegin(into); - return x; + return new LoopBegin(into); } @Override diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MaterializeNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MaterializeNode.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2009, 2011, 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.max.graal.compiler.ir; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code Convert} class represents a conversion between primitive types. + */ +public final class MaterializeNode extends FloatingNode { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_VALUE = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction which produces the input value to this instruction. + */ + public BooleanNode value() { + return (BooleanNode) inputs().get(super.inputCount() + INPUT_VALUE); + } + + public void setValue(BooleanNode n) { + inputs().set(super.inputCount() + INPUT_VALUE, n); + } + + /** + * Constructs a new Convert instance. + * @param opcode the bytecode representing the operation + * @param value the instruction producing the input value + * @param kind the result type of this instruction + * @param graph + */ + public MaterializeNode(BooleanNode value, Graph graph) { + super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setValue(value); + } + + @Override + public void accept(ValueVisitor v) { + } + + @Override + public boolean valueEqual(Node i) { + return (i instanceof MaterializeNode); + } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == LIRGenerator.LIRGeneratorOp.class) { + return (T) LIR_GENERATOR_OP; + } + return super.lookup(clazz); + } + + public static final LIRGenerator.LIRGeneratorOp LIR_GENERATOR_OP = new LIRGenerator.LIRGeneratorOp() { + + @Override + public void generate(Node n, LIRGenerator generator) { + LIRBlock trueSuccessor = new LIRBlock(new Label(), null); + generator.emitBooleanBranch(((MaterializeNode) n).value(), trueSuccessor, null, null); + CiValue result = generator.createResultVariable((Value) n); + LIRList lir = generator.lir(); + lir.move(CiConstant.FALSE, result); + Label label = new Label(); + lir.branch(Condition.TRUE, label); + lir.branchDestination(trueSuccessor.label); + lir.move(CiConstant.TRUE, result); + lir.branchDestination(label); + } + }; + + @Override + public void print(LogStream out) { + out.print("materialize(").print(value().toString()).print(')'); + } + + @Override + public Node copy(Graph into) { + return new MaterializeNode(null, into); + } +} diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NotInstanceOf.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NotInstanceOf.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009, 2011, 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.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code InstanceOf} instruction represents an instanceof test. + */ +public final class NotInstanceOf extends TypeCheck { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Constructs a new InstanceOf instruction. + * @param targetClass the target class of the instanceof check + * @param object the instruction producing the object input to this instruction + * @param graph + */ + public NotInstanceOf(Constant targetClassInstruction, Value object, Graph graph) { + super(targetClassInstruction, object, CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + } + + @Override + public int valueNumber() { + return Util.hash1(Bytecodes.INSTANCEOF, object()); + } + + @Override + public boolean valueEqual(Node i) { + return i instanceof NotInstanceOf; + } + + @Override + public void print(LogStream out) { + out.print("instanceof(").print(object()).print(") ").print(CiUtil.toJavaName(targetClass())); + } + + @Override + public BooleanNode negate() { + return new InstanceOf(targetClassInstruction(), object(), graph()); + } + + @Override + public Node copy(Graph into) { + return new NotInstanceOf(null, null, into); + } +} diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ReadNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ReadNode.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ReadNode.java Fri Jul 01 18:24:04 2011 +0200 @@ -47,6 +47,11 @@ } @Override + public boolean valueEqual(Node i) { + return i instanceof ReadNode; + } + + @Override public Node copy(Graph into) { return new ReadNode(super.kind, null, null, into); } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java Fri Jul 01 18:24:04 2011 +0200 @@ -29,7 +29,7 @@ /** * The {@code TypeCheck} instruction is the base class of casts and instanceof tests. */ -public abstract class TypeCheck extends FloatingNode { +public abstract class TypeCheck extends BooleanNode { private static final int INPUT_COUNT = 2; private static final int INPUT_OBJECT = 0; @@ -61,16 +61,23 @@ /** * The instruction that loads the target class object that is used by this checkcast. */ - public Value targetClassInstruction() { - return (Value) inputs().get(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION); + public Constant targetClassInstruction() { + return (Constant) inputs().get(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION); + } + + private void setTargetClassInstruction(Constant n) { + inputs().set(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION, n); } - public Value setTargetClassInstruction(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION, n); + + /** + * Gets the target class, i.e. the class being cast to, or the class being tested against. + * @return the target class + */ + public RiType targetClass() { + return (RiType) targetClassInstruction().asConstant().asObject(); } - final RiType targetClass; - /** * Creates a new TypeCheck instruction. * @param targetClass the class which is being casted to or checked against @@ -80,27 +87,9 @@ * @param successorCount * @param graph */ - public TypeCheck(RiType targetClass, Value targetClassInstruction, Value object, CiKind kind, int inputCount, int successorCount, Graph graph) { + public TypeCheck(Constant targetClassInstruction, Value object, CiKind kind, int inputCount, int successorCount, Graph graph) { super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - this.targetClass = targetClass; setObject(object); setTargetClassInstruction(targetClassInstruction); } - - /** - * Gets the target class, i.e. the class being cast to, or the class being tested against. - * @return the target class - */ - public RiType targetClass() { - return targetClass; - } - - /** - * Checks whether the target class of this instruction is loaded. - * @return {@code true} if the target class is loaded - */ - public boolean isLoaded() { - return targetClass != null; - } - } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueVisitor.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueVisitor.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueVisitor.java Fri Jul 01 18:24:04 2011 +0200 @@ -44,7 +44,6 @@ public abstract void visitAnchor(Anchor i); public abstract void visitIf(If i); public abstract void visitIfOp(Conditional i); - public abstract void visitInstanceOf(InstanceOf i); public abstract void visitInvoke(Invoke i); public abstract void visitLoadField(LoadField i); public abstract void visitLoadIndexed(LoadIndexed i); diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRAssembler.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRAssembler.java Fri Jul 01 18:24:04 2011 +0200 @@ -49,7 +49,6 @@ public int registerRestoreEpilogueOffset = -1; protected final List xirSlowPath; - protected final List branchTargetBlocks; private int lastDecodeStart; @@ -70,7 +69,6 @@ this.tasm = compilation.assembler(); this.asm = tasm.asm; this.frameMap = compilation.frameMap(); - this.branchTargetBlocks = new ArrayList(); this.xirSlowPath = new ArrayList(); } @@ -164,12 +162,12 @@ } boolean checkNoUnboundLabels() { - for (int i = 0; i < branchTargetBlocks.size() - 1; i++) { - if (!branchTargetBlocks.get(i).label().isBound()) { - TTY.println(String.format("label of block B%d is not bound", branchTargetBlocks.get(i).blockID())); - assert false : "unbound label"; - } - } +// for (int i = 0; i < branchTargetBlocks.size() - 1; i++) { +// if (!branchTargetBlocks.get(i).label().isBound()) { +// TTY.println(String.format("label of block B%d is not bound", branchTargetBlocks.get(i).blockID())); +// assert false : "unbound label"; +// } +// } return true; } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBlock.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBlock.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBlock.java Fri Jul 01 18:24:04 2011 +0200 @@ -36,13 +36,14 @@ */ public final class LIRBlock { - public final Label label = new Label(); + public final Label label; private LIRList lir; private final int blockID; private FrameState lastState; private List instructions = new ArrayList(4); private List predecessors = new ArrayList(4); private List successors = new ArrayList(4); + private LIRDebugInfo debugInfo; /** * Bit map specifying which {@linkplain OperandPool operands} are live upon entry to this block. @@ -77,10 +78,24 @@ private int lastLirInstructionID; public int blockEntryPco; + public LIRBlock(Label label, LIRDebugInfo debugInfo) { + this.label = label; + blockID = -1; + this.debugInfo = debugInfo; + } + + public LIRDebugInfo debugInfo() { + return this.debugInfo; + } + public LIRBlock(int blockID) { this.blockID = blockID; + label = new Label(); loopIndex = -1; linearScanNumber = blockID; + instructions = new ArrayList(4); + predecessors = new ArrayList(4); + successors = new ArrayList(4); } public List getInstructions() { @@ -261,7 +276,12 @@ if (instructionsList.size() == 0) { return false; } - LIROpcode code = instructionsList.get(instructionsList.size() - 1).code; + LIRInstruction lirInstruction = instructionsList.get(instructionsList.size() - 1); + if (lirInstruction instanceof LIRXirInstruction) { + LIRXirInstruction lirXirInstruction = (LIRXirInstruction) lirInstruction; + return (lirXirInstruction.falseSuccessor() != null) && (lirXirInstruction.trueSuccessor() != null); + } + LIROpcode code = lirInstruction.code; return code == LIROpcode.Branch || code == LIROpcode.TableSwitch; } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBranch.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBranch.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBranch.java Fri Jul 01 18:24:04 2011 +0200 @@ -73,7 +73,7 @@ * */ public LIRBranch(Condition cond, LIRBlock block) { - super(LIROpcode.Branch, CiValue.IllegalValue, null, false); + super(LIROpcode.Branch, CiValue.IllegalValue, block.debugInfo(), false); this.cond = cond; this.label = block.label(); this.block = block; @@ -81,7 +81,7 @@ } public LIRBranch(Condition cond, LIRBlock block, LIRBlock ublock) { - super(LIROpcode.CondFloatBranch, CiValue.IllegalValue, null, false); + super(LIROpcode.CondFloatBranch, CiValue.IllegalValue, (block.debugInfo() != null ? block.debugInfo() : (ublock != null ? ublock.debugInfo() : null)), false); this.cond = cond; this.label = block.label(); this.block = block; @@ -116,11 +116,6 @@ this.label = b.label(); } - public void changeUblock(LIRBlock b) { - assert unorderedBlock != null : "must have old block"; - this.unorderedBlock = b; - } - public void negateCondition() { cond = cond.negate(); } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java Fri Jul 01 18:24:04 2011 +0200 @@ -42,6 +42,8 @@ public final int inputCount; public final List pointerSlots; public final LIRDebugInfo infoAfter; + private LIRBlock trueSuccessor; + private LIRBlock falseSuccessor; public LIRXirInstruction(XirSnippet snippet, CiValue[] originalOperands, @@ -71,6 +73,24 @@ GraalMetrics.LIRXIRInstructions++; } + + public void setFalseSuccessor(LIRBlock falseSuccessor) { + this.falseSuccessor = falseSuccessor; + } + + + public void setTrueSuccessor(LIRBlock trueSuccessor) { + this.trueSuccessor = trueSuccessor; + } + + public LIRBlock falseSuccessor() { + return falseSuccessor; + } + + public LIRBlock trueSuccessor() { + return trueSuccessor; + } + public CiValue[] getOperands() { for (int i = 0; i < operandIndices.length; i++) { originalOperands[operandIndices[i]] = operand(i); @@ -163,4 +183,15 @@ return sb.toString(); } + + + public void substitute(LIRBlock block, LIRBlock newTarget) { + if (trueSuccessor == block) { + trueSuccessor = newTarget; + } + + if (falseSuccessor == block) { + falseSuccessor = newTarget; + } + } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -29,70 +29,37 @@ import com.oracle.max.graal.compiler.gen.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.graph.*; -import com.sun.cri.ci.*; public class DeadCodeEliminationPhase extends Phase { private NodeFlood flood; private Graph graph; - private ArrayList brokenLoops; @Override protected void run(Graph graph) { this.graph = graph; this.flood = graph.createNodeFlood(); - this.brokenLoops = new ArrayList(); - - // remove chained Merges - for (Merge merge : graph.getNodes(Merge.class)) { - if (merge.endCount() == 1 && merge.usages().size() == 0 && !(merge instanceof LoopBegin)) { - FixedNode next = merge.next(); - EndNode endNode = merge.endAt(0); - merge.delete(); - endNode.replaceAndDelete(next); - } - } - // remove if nodes with constant-value comparison - for (If ifNode : graph.getNodes(If.class)) { - BooleanNode bool = ifNode.compare(); - if (bool instanceof Compare) { - Compare compare = (Compare) bool; - if (compare.x().isConstant() && compare.y().isConstant()) { - CiConstant constX = compare.x().asConstant(); - CiConstant constY = compare.y().asConstant(); - Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime); - if (result != null) { - Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor(); - ifNode.replaceAndDelete(actualSuccessor); - } else { - TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind); - } - } - } - } - // remove unnecessary FixedGuards - for (FixedGuard guard : graph.getNodes(FixedGuard.class)) { - if (guard.node() instanceof IsNonNull && ((IsNonNull) guard.node()).object() instanceof NewInstance) { - guard.replaceAndDelete(guard.next()); - } - } flood.add(graph.start()); - iterateSuccessors(); disconnectCFGNodes(); iterateInputs(); disconnectNodes(); deleteNodes(); - deleteBrokenLoops(); + // remove chained Merges + for (Merge merge : graph.getNodes(Merge.class)) { + if (merge.endCount() == 1 && !(merge instanceof LoopBegin)) { + replacePhis(merge); + EndNode endNode = merge.endAt(0); + FixedNode next = merge.next(); + merge.delete(); + endNode.replaceAndDelete(next); + } + } new PhiSimplifier(graph); - - if (GraalOptions.TraceDeadCodeElimination) { - TTY.println("dead code elimination finished"); - } } private void iterateSuccessors() { @@ -118,20 +85,28 @@ // We are a dead end node leading to a live merge. merge.removeEnd(end); } + } else if (node instanceof LoopEnd) { + LoopBegin loop = ((LoopEnd) node).loopBegin(); + if (flood.isMarked(loop)) { + if (GraalOptions.TraceDeadCodeElimination) { + TTY.println("Building loop begin node back: " + loop); + } + ((LoopEnd) node).setLoopBegin(null); + EndNode endNode = loop.endAt(0); + assert endNode.predecessors().size() == 1 : endNode.predecessors().size(); + replacePhis(loop); + endNode.replaceAndDelete(loop.next()); + loop.delete(); + } } } } } - private void deleteBrokenLoops() { - for (LoopBegin loop : brokenLoops) { - assert loop.predecessors().size() == 1; - for (Node usage : new ArrayList(loop.usages())) { - assert usage instanceof Phi; - usage.replaceAndDelete(((Phi) usage).valueAt(0)); - } - - loop.replaceAndDelete(loop.next()); + private void replacePhis(Merge merge) { + for (Node usage : new ArrayList(merge.usages())) { + assert usage instanceof Phi; + usage.replaceAndDelete(((Phi) usage).valueAt(0)); } } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GlobalValueNumberingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GlobalValueNumberingPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, 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.max.graal.compiler.phases; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + +/** + * Duplicates every node in the graph to test the implementation of the {@link com.oracle.max.graal.graph.Node#copy()} method in node subclasses. + */ +public class GlobalValueNumberingPhase extends Phase { + + @Override + protected void run(Graph graph) { + NodeBitMap visited = graph.createNodeBitMap(); + for (Node n : graph.getNodes()) { + apply(n, visited); + } + } + + private void apply(Node n, NodeBitMap visited) { + if (n != null && !visited.isMarked(n)) { + visited.mark(n); + for (Node input : n.inputs()) { + apply(input, visited); + } + Node newNode = n.graph().ideal(n); + if (GraalOptions.TraceGVN && newNode != n) { + TTY.println("GVN applied and new node is " + newNode); + } + } + } +} diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -725,8 +725,7 @@ private void genThrow(int bci) { Value exception = frameState.apop(); - FixedGuard node = new FixedGuard(graph); - node.setNode(new IsNonNull(exception, graph)); + FixedGuard node = new FixedGuard(new IsNonNull(exception, graph), graph); append(node); FixedNode entry = handleException(exception, bci); @@ -743,10 +742,12 @@ int cpi = stream().readCPI(); RiType type = constantPool.lookupType(cpi, CHECKCAST); boolean isInitialized = type.isResolved(); - Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); + Constant typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); Value object = frameState.apop(); if (typeInstruction != null) { - frameState.apush(append(new CheckCast(type, typeInstruction, object, graph))); +// append(new FixedGuard(new InstanceOf(typeInstruction, object, graph), graph)); +// frameState.apush(object); + frameState.apush(new CheckCast(typeInstruction, object, graph)); } else { frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); } @@ -756,10 +757,10 @@ int cpi = stream().readCPI(); RiType type = constantPool.lookupType(cpi, INSTANCEOF); boolean isInitialized = type.isResolved(); - Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); + Constant typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); Value object = frameState.apop(); if (typeInstruction != null) { - frameState.ipush(append(new InstanceOf(type, typeInstruction, object, graph))); + frameState.ipush(append(new MaterializeNode(new InstanceOf(typeInstruction, object, graph), graph))); } else { frameState.ipush(appendConstant(CiConstant.INT_0)); } @@ -874,7 +875,7 @@ } } - private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { + private Constant genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { if (initialized) { return appendConstant(holder.getEncoding(representation)); } else { @@ -1124,11 +1125,44 @@ append(lookupSwitch); } - private Value appendConstant(CiConstant constant) { - return append(new Constant(constant, graph)); + private Constant appendConstant(CiConstant constant) { + return new Constant(constant, graph); } private Value append(FixedNode fixed) { + if (fixed instanceof Deoptimize && lastInstr.predecessors().size() > 0) { + Node cur = lastInstr; + Node prev = cur; + while (cur != cur.graph().start() && !(cur instanceof ControlSplit)) { + assert cur.predecessors().size() == 1; + prev = cur; + cur = cur.predecessors().get(0); + if (cur.predecessors().size() == 0) { + break; + } + + if (cur instanceof ExceptionObject) { + break; + } + } + + if (cur instanceof If) { + If ifNode = (If) cur; + if (ifNode.falseSuccessor() == prev) { + FixedNode successor = ifNode.trueSuccessor(); + BooleanNode condition = ifNode.compare(); + FixedGuard fixedGuard = new FixedGuard(condition, graph); + fixedGuard.setNext(successor); + ifNode.replaceAndDelete(fixedGuard); + lastInstr = null; + return fixed; + } + } else if (prev != cur) { + prev.replaceAtPredecessors(fixed); + lastInstr = null; + return fixed; + } + } lastInstr.setNext(fixed); lastInstr = null; return fixed; diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/ReadEliminationPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/ReadEliminationPhase.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/ReadEliminationPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -38,7 +38,7 @@ Node memoryInput = n.inputs().variablePart().get(0); if (memoryInput instanceof WriteNode) { WriteNode other = (WriteNode) memoryInput; - if (other.object() == n.object() && other.location().same(n.location())) { + if (other.object() == n.object() && other.location() == n.location()) { if (GraalOptions.TraceReadElimination) { TTY.println("Eliminated memory read " + n + "and replaced with node " + other.value()); } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java Fri Jul 01 18:24:04 2011 +0200 @@ -439,22 +439,11 @@ private boolean assertEmitBranch(LIRBranch op) { assert op.block() == null || op.block().label() == op.label() : "wrong label"; - if (op.block() != null) { - branchTargetBlocks.add(op.block()); - } - if (op.unorderedBlock() != null) { - branchTargetBlocks.add(op.unorderedBlock()); - } return true; } private boolean assertEmitTableSwitch(LIRTableSwitch op) { assert op.defaultTarget != null; - branchTargetBlocks.add(op.defaultTarget); - for (LIRBlock target : op.targets) { - assert target != null; - branchTargetBlocks.add(target); - } return true; } @@ -537,9 +526,14 @@ masm.jmp(op.label()); } else { ConditionFlag acond = ConditionFlag.zero; + Label unorderedLabel = null; if (op.code == LIROpcode.CondFloatBranch) { - assert op.unorderedBlock() != null : "must have unordered successor"; - masm.jcc(ConditionFlag.parity, op.unorderedBlock().label()); + if (op.unorderedBlock() == null) { + unorderedLabel = new Label(); + } else { + unorderedLabel = op.unorderedBlock().label; + } + masm.jcc(ConditionFlag.parity, unorderedLabel); // Checkstyle: off switch (op.cond()) { case EQ : acond = ConditionFlag.equal; break; @@ -565,6 +559,9 @@ // Checkstyle: on } masm.jcc(acond, op.label()); + if (unorderedLabel != null) { + masm.bind(unorderedLabel); + } } } @@ -1597,11 +1594,34 @@ protected void emitXir(LIRXirInstruction instruction) { XirSnippet snippet = instruction.snippet; + + Label endLabel = null; Label[] labels = new Label[snippet.template.labels.length]; for (int i = 0; i < labels.length; i++) { labels[i] = new Label(); + if (snippet.template.labels[i].name == XirLabel.TrueSuccessor) { + if (instruction.trueSuccessor() == null) { + assert endLabel == null; + endLabel = new Label(); + labels[i] = endLabel; + } else { + labels[i] = instruction.trueSuccessor().label; + } + } else if (snippet.template.labels[i].name == XirLabel.FalseSuccessor) { + if (instruction.falseSuccessor() == null) { + assert endLabel == null; + endLabel = new Label(); + labels[i] = endLabel; + } else { + labels[i] = instruction.falseSuccessor().label; + } + } } emitXirInstructions(instruction, snippet.template.fastPath, labels, instruction.getOperands(), snippet.marks); + if (endLabel != null) { + masm.bind(endLabel); + } + if (snippet.template.slowPath != null) { addSlowPath(new SlowPath(instruction, labels, snippet.marks)); } @@ -2090,6 +2110,9 @@ default: throw Util.shouldNotReachHere(); } + if (code == 0) { + throw new RuntimeException(); + } masm.movq(rscratch1, code); directCall(CiRuntimeCall.Deoptimize, stub.info); shouldNotReachHere(); diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Fri Jul 01 18:24:04 2011 +0200 @@ -475,11 +475,10 @@ XirArgument obj = toXirArgument(x.exception()); XirArgument clazz = toXirArgument(riType.getEncoding(Representation.ObjectHub)); XirSnippet snippet = xir.genInstanceOf(site(x), obj, clazz, riType); - CiValue result = emitXir(snippet, x, stateFor(x), null, true); + emitXir(snippet, x, stateFor(x), null, false); - lir.cmp(Condition.EQ, result, CiConstant.TRUE); - lir.branch(Condition.EQ, getLIRBlock(x.catchSuccessor())); - + LIRXirInstruction instr = (LIRXirInstruction) lir.instructionsList().get(lir.instructionsList().size() - 1); + instr.setTrueSuccessor(getLIRBlock(x.catchSuccessor())); lir.jump(getLIRBlock(x.otherSuccessor())); } diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirAssembler.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirAssembler.java Fri Jul 01 18:24:04 2011 +0200 @@ -200,7 +200,7 @@ } } for (XirLabel label : labels) { - assert boundLabels.contains(label) : "label " + label.name + " is not bound!"; + assert label.name == XirLabel.TrueSuccessor || label.name == XirLabel.FalseSuccessor || boundLabels.contains(label) : "label " + label.name + " is not bound!"; } XirInstruction[] fp = fastPath.toArray(new XirInstruction[fastPath.size()]); XirInstruction[] sp = slowPath.size() > 0 ? slowPath.toArray(new XirInstruction[slowPath.size()]) : null; diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java Fri Jul 01 18:24:04 2011 +0200 @@ -251,7 +251,7 @@ Graph graph = field.graph(); int displacement = ((HotSpotField) field.field()).offset(); assert field.kind != CiKind.Illegal; - ReadNode memoryRead = new ReadNode(field.field().kind().stackKind(), field.object(), new LocationNode(field.field(), field.field().kind(), displacement, graph), graph); + ReadNode memoryRead = new ReadNode(field.field().kind().stackKind(), field.object(), LocationNode.create(field.field(), field.field().kind(), displacement, graph), graph); memoryRead.setGuard((GuardNode) tool.createGuard(new IsNonNull(field.object(), graph))); memoryRead.setNext(field.next()); field.replaceAndDelete(memoryRead); @@ -262,7 +262,7 @@ } Graph graph = field.graph(); int displacement = ((HotSpotField) field.field()).offset(); - WriteNode memoryWrite = new WriteNode(CiKind.Illegal, field.object(), field.value(), new LocationNode(field.field(), field.field().kind(), displacement, graph), graph); + WriteNode memoryWrite = new WriteNode(CiKind.Illegal, field.object(), field.value(), LocationNode.create(field.field(), field.field().kind(), displacement, graph), graph); memoryWrite.setGuard((GuardNode) tool.createGuard(new IsNonNull(field.object(), graph))); memoryWrite.setStateAfter(field.stateAfter()); memoryWrite.setNext(field.next()); diff -r 3664989976e2 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Fri Jul 01 12:57:10 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Fri Jul 01 18:24:04 2011 +0200 @@ -636,32 +636,32 @@ @Override protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Boolean); + asm.restart(CiKind.Void); XirParameter object = asm.createInputParameter("object", CiKind.Object); final XirOperand hub; hub = asm.createConstantInputParameter("hub", CiKind.Object); XirOperand objHub = asm.createTemp("objHub", CiKind.Object); - XirLabel end = asm.createInlineLabel("end"); XirLabel slowPath = asm.createOutOfLineLabel("slow path"); + XirLabel trueSucc = asm.createInlineLabel(XirLabel.TrueSuccessor); + XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor); if (is(NULL_CHECK, flags)) { // null isn't "instanceof" anything - asm.mov(result, asm.b(false)); - asm.jeq(end, object, asm.o(null)); + asm.jeq(falseSucc, object, asm.o(null)); } asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); // if we get an exact match: succeed immediately - asm.mov(result, asm.b(true)); - asm.jneq(slowPath, objHub, hub); - asm.bindInline(end); + asm.jeq(trueSucc, objHub, hub); + asm.jmp(slowPath); // -- out of line ------------------------------------------------------- asm.bindOutOfLine(slowPath); - checkSubtype(asm, result, objHub, hub); - asm.jmp(end); + checkSubtype(asm, objHub, objHub, hub); + asm.jeq(falseSucc, objHub, asm.o(null)); + asm.jmp(trueSucc); return asm.finishTemplate("instanceof"); } diff -r 3664989976e2 -r 5cdaa94cd622 runfop.sh --- a/runfop.sh Fri Jul 01 12:57:10 2011 +0200 +++ b/runfop.sh Fri Jul 01 18:24:04 2011 +0200 @@ -15,4 +15,4 @@ echo "DACAPO is not defined. It must point to a Dacapo benchmark directory." exit 1; fi -${JDK7}/bin/java -client -d64 -graal -Xms1g -Xmx2g -esa -classpath ${DACAPO}/dacapo-9.12-bach.jar -XX:-GraalBailoutIsFatal $* Harness --preserve -n 5 fop +${JDK7}/bin/java -client -d64 -graal -Xms1g -Xmx2g -esa -classpath ${DACAPO}/dacapo-9.12-bach.jar -XX:-GraalBailoutIsFatal $* Harness --preserve -n 10 fop