From: <mic...@us...> - 2007-08-07 22:28:52
|
Revision: 161 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=161&view=rev Author: michael_baer Date: 2007-08-07 15:28:53 -0700 (Tue, 07 Aug 2007) Log Message: ----------- - Added support for interchangeable flag behaviour and flag laziness on ARM - Improved usage of profiling data for conditional instructions on ARM Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/vmInterface/DBT_Trace.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/DBT_Options.java 2007-08-07 22:28:53 UTC (rev 161) @@ -93,9 +93,12 @@ /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ public static int minTraceValue = 20; - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information.. */ + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information. */ public static boolean optimizeTranslationByProfiling = false; + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using lazy evaluation.*/ + public static boolean optimizeTranslationByLazyEvaluation = true; + /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -179,6 +182,8 @@ debugSyscall = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugSyscallMore")) { debugSyscallMore = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugTranslation")) { + debugTranslation = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); } else if (key.equalsIgnoreCase("instrOpt1")) { @@ -201,9 +206,12 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); - } else if (key.equalsIgnoreCase("optimizeTranslation")) { + } else if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("optimizeByLazy")) { + optimizeTranslationByLazyEvaluation = Boolean.parseBoolean(value); } + else { throw new Error("Unknown DBT option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:28:53 UTC (rev 161) @@ -3,6 +3,9 @@ import java.util.ArrayList; import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.arch.arm.decoder.ARM_Laziness.Flag; +import org.binarytranslator.arch.arm.decoder.ARM_Laziness.Operation; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; @@ -77,6 +80,9 @@ /** The class performing the actual translation of the bytecode. */ private final ARM_Translator translator; + /** Determines how flags are resolved and if laziness is used.*/ + private final ARM_FlagBehavior flagBehavior; + static { psTref = VM_TypeReference.findOrCreate(ARM_ProcessSpace.class); @@ -136,8 +142,274 @@ public ARM2IR(OPT_GenerationContext context, DBT_Trace trace) { super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); + + if (DBT_Options.optimizeTranslationByLazyEvaluation) + flagBehavior = new ARM_LazyFlagBehavior(); + else + flagBehavior = new ARM_ImmediateFlagBehavior(); } + + /** ARM has an interchangeable flag behavior. Flags can either be evaluated immediately or on demand using + * lazy evaluation. This interface encapsulates the differences. */ + public abstract class ARM_FlagBehavior { + + /** + * Interface helper function. If a flag behaviour wants to set a value of a flag, it shall set + * the {@link OPT_RegisterOperand} returned by this function. + */ + protected final OPT_RegisterOperand getFlag(Flag flag) { + switch (flag) { + case Zero: + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + + case Carry: + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + + case Negative: + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + + case Overflow: + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + + default: + throw new RuntimeException("Unexpected flag type: " + flag); + } + } + /** Called before a flag is written to directly. */ + public abstract void onFlagWrite(Flag flag, ARM_Laziness lazy); + + /** Called before a flag is read. */ + public abstract void onFlagRead(Flag flag, ARM_Laziness lazy); + + /** Called when the ARM flags shall be set by a logical operation. This sets the zero and negative flag. */ + public abstract void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result); + + /** Called when the ARM flags shall be set by a ADD operation. This sets all ARM flags. */ + public abstract void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + + /** Called when the ARM flags shall be set by a SUB operation. This sets all ARM flags. */ + public abstract void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + } + + /** Implements a flag behavior that will immediately evaluate all flag values. */ + public final class ARM_ImmediateFlagBehavior extends ARM_FlagBehavior { + @Override + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + } + + @Override + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + + } + + @Override + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + } + + @Override + public void onFlagRead(Flag flag, ARM_Laziness lazy) { + //nothing to do here, because the flags are already resolved + } + + @Override + public void onFlagWrite(Flag flag, ARM_Laziness lazy) { + //nothing to do here, because the flags are already resolved + } + } + + /** Implements a flag behavior that will use lazy evaluation to only determine a flag value + * when it is necessary. */ + public final class ARM_LazyFlagBehavior extends ARM_FlagBehavior { + + /** Operands for lazy evaluation of condition codes. */ + private OPT_Register lazyOperand1; + private OPT_Register lazyOperand2; + private OPT_Register lazyLogicalOperand; + + public ARM_LazyFlagBehavior() { + //prepare the laziness registers + lazyOperand1 = makeTemp(VM_TypeReference.Int).register; + lazyOperand2 = makeTemp(VM_TypeReference.Int).register; + lazyLogicalOperand = makeTemp(VM_TypeReference.Int).register; + } + + @Override + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int), op1.copy())); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int), op2.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + lazy.setValid(Flag.Carry, false); + lazy.setValid(Flag.Overflow, false); + lazy.setOperation(Operation.Add); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyLogicalOperand, VM_TypeReference.Int), result.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + + switch (lazy.getOperation()) { + case Add: + lazy.setOperation(Operation.LogicalOpAfterAdd); + break; + + case Sub: + lazy.setOperation(Operation.LogicalOpAfterSub); + break; + + case LogicalOpAfterAdd: + case LogicalOpAfterSub: + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int), op1.copy())); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int), op2.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + lazy.setValid(Flag.Carry, false); + lazy.setValid(Flag.Overflow, false); + lazy.setOperation(Operation.Sub); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + private void resolveFlag(ARM_Laziness.Flag flag, ARM_Laziness lazy) { + + if (lazy.isValid(flag)) + return; + + if (DBT_Options.debugTranslation) { + System.out.println("Resolving " + flag + " flag."); + } + + OPT_RegisterOperand flagRegister = getFlag(flag); + OPT_RegisterOperand op1 = new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int); + OPT_RegisterOperand op2 = new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int); + OPT_RegisterOperand result; + + switch (lazy.getOperation()) { + case Add: + result = gc.temps.makeTempInt(); + appendInstruction(Binary.create(INT_ADD, result, op1, op2)); + break; + + case Sub: + result = gc.temps.makeTempInt(); + appendInstruction(Binary.create(INT_SUB, result, op1, op2)); + break; + + case LogicalOpAfterAdd: + case LogicalOpAfterSub: + result = new OPT_RegisterOperand(lazyLogicalOperand, VM_TypeReference.Int); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + switch (flag) { + case Zero: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + break; + + case Carry: + switch (lazy.getOperation()) { + case LogicalOpAfterAdd: + case Add: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); + break; + + case LogicalOpAfterSub: + case Sub: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + break; + + case Negative: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + break; + + case Overflow: + switch (lazy.getOperation()) { + case Add: + case LogicalOpAfterAdd: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + break; + + case Sub: + case LogicalOpAfterSub: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + break; + + default: + throw new RuntimeException("Unhandled flag type: " + flag); + } + + lazy.setValid(flag, true); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void onFlagRead(Flag flag, ARM_Laziness lazy) { + resolveFlag(flag, lazy); + + } + + @Override + public void onFlagWrite(Flag flag, ARM_Laziness lazy) { + lazy.setValid(flag, true); + } + } + @Override protected Laziness createInitialLaziness() { return new ARM_Laziness(); @@ -319,26 +591,67 @@ return new OPT_RegisterOperand(regMap[r], VM_TypeReference.Int); } - public OPT_RegisterOperand getCarryFlag() { + public OPT_Operand readCarryFlag(ARM_Laziness lazy) { carryUsed = true; + flagBehavior.onFlagRead(Flag.Carry, lazy); return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getZeroFlag() { + public OPT_Operand readZeroFlag(ARM_Laziness lazy) { zeroUsed = true; + flagBehavior.onFlagRead(Flag.Zero, lazy); return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getNegativeFlag() { + public OPT_Operand readNegativeFlag(ARM_Laziness lazy) { negativeUsed = true; + flagBehavior.onFlagRead(Flag.Negative, lazy); return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getOverflowFlag() { + public OPT_Operand readOverflowFlag(ARM_Laziness lazy) { overflowUsed = true; + flagBehavior.onFlagRead(Flag.Overflow, lazy); return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); } + public OPT_RegisterOperand writeCarryFlag(ARM_Laziness lazy) { + carryUsed = true; + flagBehavior.onFlagWrite(Flag.Carry, lazy); + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeZeroFlag(ARM_Laziness lazy) { + zeroUsed = true; + flagBehavior.onFlagWrite(Flag.Zero, lazy); + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeNegativeFlag(ARM_Laziness lazy) { + negativeUsed = true; + flagBehavior.onFlagWrite(Flag.Negative, lazy); + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeOverflowFlag(ARM_Laziness lazy) { + overflowUsed = true; + flagBehavior.onFlagWrite(Flag.Overflow, lazy); + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + } + + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + flagBehavior.appendLogicalFlags(lazy, result); + } + + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + flagBehavior.appendSubFlags(lazy, result, op1, op2); + } + + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + flagBehavior.appendAddFlags(lazy, result, op1, op2); + } + + @Override protected OPT_Register[] getUnusedRegisters() { @@ -372,7 +685,19 @@ @Override public void resolveLaziness(Laziness laziness) { - //NO-OP, as we're not using laziness at the moment + ARM_Laziness lazy = (ARM_Laziness)laziness; + + if (carryUsed) + flagBehavior.onFlagRead(Flag.Carry, lazy); + + if (negativeUsed) + flagBehavior.onFlagRead(Flag.Negative, lazy); + + if (overflowUsed) + flagBehavior.onFlagRead(Flag.Overflow, lazy); + + if (zeroUsed) + flagBehavior.onFlagRead(Flag.Zero, lazy); } @Override Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-07 22:28:53 UTC (rev 161) @@ -46,13 +46,18 @@ Instruction decodedInstruction; - if ((address & 0x1) == 1) { - short binaryInstruction = (short)ps.memory.loadInstruction16(address & 0xFFFFFFFE); - decodedInstruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction); + try { + if ((address & 0x1) == 1) { + short binaryInstruction = (short)ps.memory.loadInstruction16(address & 0xFFFFFFFE); + decodedInstruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction); + } + else { + int binaryInstruction = ps.memory.loadInstruction32(address); + decodedInstruction = ARM_InstructionDecoder.ARM32.decode(binaryInstruction); + } } - else { - int binaryInstruction = ps.memory.loadInstruction32(address); - decodedInstruction = ARM_InstructionDecoder.ARM32.decode(binaryInstruction); + catch (Exception e) { + return new ARM_DisassembledInstruction("Exception (" + e + ") while reading instruction at 0x" + Integer.toHexString(address)); } DisassemblingVisitor disassembler = new DisassemblingVisitor(); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:28:53 UTC (rev 161) @@ -2,41 +2,115 @@ import org.binarytranslator.generic.decoder.Laziness; -public class ARM_Laziness extends Laziness { +public final class ARM_Laziness extends Laziness { + public enum Operation { + Add, Sub, LogicalOpAfterAdd, LogicalOpAfterSub + } + + public enum Flag { + Carry, Zero, Negative, Overflow + } + + /** The state of the different ARM flags, compressed as bit fields within an integer. */ + private int flagValid; + + /** The operation that has to be performed to evaluate the remaining registers */ + private Operation lazinessOperation; + final class ARM_LazinessKey extends Key { private final int pc; + private final byte flagState; public int hashCode() { - return pc; + return pc | flagState; } public boolean equals(Object o) { - return ((o instanceof ARM_LazinessKey) && ((ARM_LazinessKey) o).pc == pc); + if (!(o instanceof ARM_LazinessKey)) + return false; + + ARM_LazinessKey otherKey = (ARM_LazinessKey)o; + return otherKey.pc == pc && otherKey.flagState == flagState; } - ARM_LazinessKey(int pc) { + ARM_LazinessKey(int pc, ARM_Laziness lazy) { this.pc = pc; + int tmpFlagState = lazy.flagValid & 0xF; + tmpFlagState |= (lazinessOperation.ordinal() + 1) << 4; + + this.flagState = (byte)tmpFlagState; } public String toString() { - return "0x" + Integer.toHexString(pc); + return String.format("0x%x (%d)", pc, flagState); } } + public ARM_Laziness() { + flagValid = 0xF; //all flags are valid + lazinessOperation = Operation.Add; + } + + private ARM_Laziness(ARM_Laziness other) { + set(other); + } + + public void setValid(Flag flag, boolean valid) { + flagValid |= 1 << flag.ordinal(); + } + + public boolean isValid(Flag flag) { + return (flagValid & (1 << flag.ordinal())) != 0; + } + + public void setAddOperation() { + flagValid = 0; // all flags are invalid + lazinessOperation = Operation.Add; + } + + public void setSubOperation() { + flagValid = 0; // all flags are invalid + lazinessOperation = Operation.Sub; + } + + public Operation getOperation() { + return lazinessOperation; + } + + public void setOperation(Operation lazinessOperation) { + this.lazinessOperation = lazinessOperation; + } + + public void set(ARM_Laziness other) { + flagValid = other.flagValid; + lazinessOperation = other.lazinessOperation; + } + @Override public Object clone() { - return new ARM_Laziness(); + return new ARM_Laziness(this); } @Override - public boolean equivalent(Laziness other) { - return other instanceof ARM_Laziness; + public boolean equivalent(Laziness o) { + if (!(o instanceof ARM_Laziness)) + return false; + + ARM_Laziness other = (ARM_Laziness)o; + return flagValid == other.flagValid && lazinessOperation == other.lazinessOperation; } @Override public Key makeKey(int pc) { - return new ARM_LazinessKey(pc); + return new ARM_LazinessKey(pc, this); } + @Override + public String toString() { + return "Operation: " + lazinessOperation + ", C:" + (isValid(Flag.Carry) ? "1" : "0") + + ", Z:" + (isValid(Flag.Zero) ? "1" : "0") + + ", N:" + (isValid(Flag.Negative) ? "1" : "0") + + ", O:" + (isValid(Flag.Overflow) ? "1" : "0"); + } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:28:53 UTC (rev 161) @@ -377,8 +377,9 @@ curBlock.deleteNormalOut(); curBlock.insertOut(nextBlock); curBlock.insertOut(block1); + OPT_Operand carryFlag = translator.arm2ir.readCarryFlag(translator.lazy); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -414,7 +415,7 @@ value = new OPT_IntConstantOperand(operand.getImmediate()); if (operand.getShiftAmount() != 0) { - OPT_RegisterOperand carryFlag = translator.arm2ir.getCarryFlag(); + OPT_RegisterOperand carryFlag = translator.arm2ir.writeCarryFlag(translator.lazy); OPT_Operand shifterCarryOut = new OPT_IntConstantOperand(((operand.getImmediate() & 0x80000000) != 0) ? 1 : 0); //otherwise there is no shifter carry out @@ -451,7 +452,7 @@ /** Returns the register that receives the shifte carry out*/ private OPT_RegisterOperand getShifterCarryOutTarget() { - return translator.arm2ir.getCarryFlag(); + return translator.arm2ir.writeCarryFlag(translator.lazy); } /** @@ -685,7 +686,7 @@ curBlock.insertOut(block1); curBlock.insertOut(nextBlock); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.readCarryFlag(translator.lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -720,7 +721,7 @@ /** Return the instruction following this one or -1, if that is not yet known. */ int getSuccessor(int pc); } - + /** All ARM instructions that are supposed to be executed conditionally * are decorated with this decorator. * The decorator takes care of checking the individual condition and depending on it, executing the @@ -729,7 +730,7 @@ protected final ARM_Instruction conditionalInstruction; protected final Condition condition; - + /** Decorates an ARM interpreter instruction, by making it execute conditionally. */ protected ConditionalDecorator(ARM_Instruction i) { conditionalInstruction = i; @@ -738,132 +739,213 @@ public int getSuccessor(int pc) { - boolean thumbMode = (pc & 0x1) == 1; - return pc + (thumbMode ? 2 : 4); + if (assumeInstructionWillBeSkipped()) { + boolean thumbMode = (pc & 0x1) == 1; + return pc + (thumbMode ? 2 : 4); + } + else { + return conditionalInstruction.getSuccessor(pc); + } } public Condition getCondition() { return condition; } + /** + * Returns the probability that this conditional instruction will be skipped. + * + * @return + * The probability that this conditional instruction will be skipped. Returns -1, if this probability + * cannot be estimated. + */ + private float getSkipProbability() { + + if (DBT_Options.optimizeTranslationByProfiling) + return -1f; + + return ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + } + + /** + * During the processing of this conditional instruction, shall we assume that it will be skipped? + * This is helpful to optimize the trace. + * + * @return + * True if it is likely that this instruction will be skipped. False otherwise. + */ + private boolean assumeInstructionWillBeSkipped() { + float skipProbability = getSkipProbability(); + + return (skipProbability == -1f || skipProbability > 0.5f); + } + + /** + conditionals are implemented easily: if the condition does not hold, then just + jump to the block following the conditional instruction. To do this, the following structure of + block is built: + + -------------------------------------------------------- + 1. block that checks the condition + -------------------------------------------------------- + 2. conditional instruction + -------------------------------------------------------- + 3. next instruction, when the instruction was not skipped + -------------------------------------------------------- + 4. next instruction, when it was skipped <- next block + -------------------------------------------------------- + + Note that the two last blocks are only necessary when laziness is used. Otherwise, the first of + them will remain empty. + */ public void translate() { - //conditionals are implemented easily: if the condition does not hold, then just - //jump to the block following the conditional instruction - OPT_BasicBlock nextInstruction = arm2ir.getNextBlock(); - OPT_BasicBlock condBlock = arm2ir.createBlockAfterCurrent(); - arm2ir.getCurrentBlock().deleteNormalOut(); - arm2ir.getCurrentBlock().insertOut(nextInstruction); - arm2ir.getCurrentBlock().insertOut(condBlock); + + OPT_BasicBlock blockThatChecksCondition = arm2ir.getCurrentBlock(); + OPT_BasicBlock nextInstruction_InstructionSkipped = arm2ir.getNextBlock(); + OPT_BasicBlock nextInstruction_InstructionNotSkipped = arm2ir.createBlockAfterCurrent(); + OPT_BasicBlock condInstructionBlock = arm2ir.createBlockAfterCurrent(); + + //prepare to translate the actual condition + arm2ir.setCurrentBlock(blockThatChecksCondition); + blockThatChecksCondition.deleteNormalOut(); + blockThatChecksCondition.insertOut(nextInstruction_InstructionSkipped); + blockThatChecksCondition.insertOut(condInstructionBlock); //Query the branch profile to get the probability that this instruction is going to get executed OPT_BranchProfileOperand profileOperand; - if (DBT_Options.optimizeTranslationByProfiling) { - float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + float skipProbability = getSkipProbability(); - if (skipProbability == -1 || skipProbability == 0.5f) { - profileOperand = new OPT_BranchProfileOperand(); - } - else if (skipProbability > 0.8f) { - profileOperand = OPT_BranchProfileOperand.always(); - condBlock.setInfrequent(); - } - else if (skipProbability > 0.5f) { - profileOperand = OPT_BranchProfileOperand.likely(); - condBlock.setInfrequent(); - } - else if (skipProbability < 0.2f) { - profileOperand = OPT_BranchProfileOperand.never(); - } - else { - profileOperand = OPT_BranchProfileOperand.unlikely(); - } + if (skipProbability == -1 || skipProbability == 0.5f) { + profileOperand = new OPT_BranchProfileOperand(); } + else if (skipProbability > 0.8f) { + profileOperand = OPT_BranchProfileOperand.always(); + condInstructionBlock.setInfrequent(); + } + else if (skipProbability > 0.5f) { + profileOperand = OPT_BranchProfileOperand.likely(); + condInstructionBlock.setInfrequent(); + } + else if (skipProbability < 0.2f) { + profileOperand = OPT_BranchProfileOperand.never(); + } else { - profileOperand = new OPT_BranchProfileOperand(); + profileOperand = OPT_BranchProfileOperand.unlikely(); } switch (condition) { case AL: - throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); + throw new RuntimeException("Unconditional instructions should not be decorated with a ConditionalDecorator."); case CC: //return !regs.isCarrySet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case CS: //return regs.isCarrySet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case EQ: //return regs.isZeroSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case GE: //return regs.isNegativeSet() == regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL(), arm2ir.readOverflowFlag(lazy)); break; case GT: - translateCondition_GT(nextInstruction, profileOperand); + translateCondition_GT(nextInstruction_InstructionSkipped, profileOperand); break; case HI: - translateCondition_HI(nextInstruction, profileOperand); + translateCondition_HI(nextInstruction_InstructionSkipped, profileOperand); break; case LE: - translateCondition_LE(nextInstruction, profileOperand); + translateCondition_LE(nextInstruction_InstructionSkipped, profileOperand); break; case LS: - translateCondition_LS(nextInstruction, profileOperand, condBlock); + translateCondition_LS(nextInstruction_InstructionSkipped, profileOperand, condInstructionBlock); break; case LT: //return regs.isNegativeSet() != regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.readOverflowFlag(lazy)); break; case MI: //return regs.isNegativeSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case NE: //return !regs.isZeroSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case NV: //never execute this instruction - translateCondition(nextInstruction, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); break; case PL: //return !regs.isNegativeSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case VC: //return !regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case VS: //return regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.EQUAL()); break; default: throw new RuntimeException("Unexpected condition code: " + condition); - } + } + + //Translate the conditional instruction first to see if the lazy state is changed by the + //conditional instruction + ARM_Laziness lazinessWhenInstructionSkipped = (ARM_Laziness)lazy.clone(); - arm2ir.setCurrentBlock(condBlock); + arm2ir.setCurrentBlock(condInstructionBlock); + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); conditionalInstruction.translate(); + + int followingInstructionAddress = pc + (inThumb() ? 2 : 4); + + //yes it did, so we may need to translate the successor instruction twice + if (assumeInstructionWillBeSkipped()) { + + //Did the laziness change during the translation? + if (!lazy.equivalent(lazinessWhenInstructionSkipped)) { + //Modify block 3 so that it resolves the different laziness correctly + arm2ir.setCurrentBlock(nextInstruction_InstructionNotSkipped); + nextInstruction_InstructionNotSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazy); + lazy.set(lazinessWhenInstructionSkipped); + } + + arm2ir.setNextBlock(nextInstruction_InstructionSkipped); + + } + else { + //Modify block 4 so that it resolves the different laziness correctly + arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); + nextInstruction_InstructionSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); + + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + } } private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand operand, OPT_ConditionOperand condition) { @@ -878,8 +960,8 @@ private void translateCondition_HI(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isCarrySet() && !regs.isZeroSet(); - OPT_Operand carry = arm2ir.getCarryFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, @@ -890,33 +972,20 @@ private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_BasicBlock actualInstruction) { //return !regs.isCarrySet() || regs.isZeroSet(); - OPT_Operand carry = arm2ir.getCarryFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getTempInt(0); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); - -/* cond1.deleteNormalOut(); - cond1.insertOut(cond2); - cond1.insertOut(actualInstruction); - - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); - - arm2ir.setCurrentBlock(cond2); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(Goto.create(GOTO, nextInstruction.makeJumpTarget())); - cond2.deleteNormalOut(); - cond2.insertOut(nextInstruction); - cond2.insertOut(actualInstruction);*/ } private void translateCondition_GT(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); - OPT_Operand negative = arm2ir.getNegativeFlag(); - OPT_Operand overflow = arm2ir.getOverflowFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, @@ -927,9 +996,9 @@ private void translateCondition_LE(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); - OPT_Operand negative = arm2ir.getNegativeFlag(); - OPT_Operand overflow = arm2ir.getOverflowFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, @@ -1021,21 +1090,8 @@ * The add's right-hand-side operator. */ protected final void setAddFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - //set the carry flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), result.copy(), lhs.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); - //set the overflow flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); - - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendAddFlags(lazy, result, lhs, rhs); } /** Sets the processor flags according to the result of subtracting <code>rhs</code> from <code>lhs</code>.*/ @@ -1077,22 +1133,8 @@ * The sub's right-hand-side operator. */ protected final void setSubFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - //set the carry flag to not(Borrow) - OPT_ConditionOperand notBorrowFromSub = OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(); - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs.copy(), rhs.copy(), notBorrowFromSub, new OPT_BranchProfileOperand())); - //set the overflow flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); - - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendSubFlags(lazy, result, lhs, rhs); } public Condition getCondition() { @@ -1165,13 +1207,8 @@ protected final void setLogicalFlags(OPT_Operand result) { //the shifter carry out has already been set during the resolve-phase - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + //set the negative & zero flag + arm2ir.appendLogicalFlags(lazy, result); } } @@ -1287,7 +1324,7 @@ //Is the carry set at all? if not, just jump to addWithoutCarry arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(addWithCarry); //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. @@ -1318,7 +1355,7 @@ //Is the carry set? if yes, just jump to subWithoutCarry arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(subWithCarry); //No, the carry flag is not set. That means, we have to use the carry within the subtraction (weird arm logic). @@ -1674,41 +1711,7 @@ //first translate the register write back translateWriteback(startAddress.copyRO(), nextAddress.copyRO()); - - //shall we switch to thumb mode? - /*OPT_BasicBlock finishInstruction = arm2ir.createBlockAfterCurrentNotInCFG(); - OPT_BasicBlock switchToARMBlock = arm2ir.createBlockAfterCurrentNotInCFG(); - OPT_BasicBlock switchToThumbBlock = arm2ir.createBlockAfterCurrentNotInCFG(); - - //Current block - OPT_BasicBlock currentBlock = arm2ir.getCurrentBlock(); - currentBlock.deleteNormalOut(); - currentBlock.insertOut(switchToARMBlock); - currentBlock.insertOut(switchToThumbBlock); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), regPC.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.BIT_TEST(), switchToThumbBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); - arm2ir.appendInstruction(Goto.create(GOTO, switchToARMBlock.makeJumpTarget())); - - //Yes, switch to thumb mode - arm2ir.setCurrentBlock(switchToThumbBlock); - switchToThumbBlock.insertOut(finishInstruction); - OPT_Instruction call_setThumbMode = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(call_setThumbMode, 1, new OPT_IntConstantOperand(1)); - arm2ir.appendCustomCall(call_setThumbMode); - arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); - //No, don't switch to thumb mode - arm2ir.setCurrentBlock(switchToARMBlock); - switchToARMBlock.insertOut(finishInstruction); - arm2ir.appendInstruction(Binary.create(INT_AND, regPC.copyRO(), regPC.copy(), new OPT_IntConstantOperand(0xFFFFFFFE))); - OPT_Instruction call_setArmMode = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(call_setArmMode, 1, new OPT_IntConstantOperand(0)); - arm2ir.appendCustomCall(call_setArmMode); - arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); - - //according to the APCS, these types of instructions are usually function returns - arm2ir.setCurrentBlock(finishInstruction); - arm2ir.appendBranch(regPC, lazy, BranchType.RETURN);*/ - arm2ir.appendBranch(regPC, lazy, BranchType.RETURN); return; } @@ -1940,13 +1943,8 @@ } if (i.updateConditionCodes) { - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + //set the negative & zero flag + arm2ir.appendLogicalFlags(lazy, result); } } @@ -2006,13 +2004,13 @@ } if (i.updateConditionCodes) { - //set the negative flag + //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.writeNegativeFlag(lazy), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.writeZeroFlag(lazy), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -2223,6 +2221,7 @@ //do we actually have to perform the rotation? arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), rotation.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), rotationBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); arm2ir.appendInstruction(Goto.create(GOTO, remainderBlock.makeJumpTarget())); + arm2ir.getCurrentBlock().insertOut(remainderBlock); //in case we are performing the rotation... arm2ir.setCurrentBlock(rotationBlock); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:28:53 UTC (rev 161) @@ -247,7 +247,7 @@ * dependencies (unknown branch targets etc.) have been resolved. This function is useful for * debug purposes. */ - protected void printTraceAfterCompletion() { + public void printTraceAfterCompletion() { printTraceAfterCompletionRequested = true; } @@ -283,18 +283,9 @@ printTraceAfterCompletionRequested = false; printNextBlocks(preFillBlock, 50); } + + ((DBT_Trace) gc.method).setNumberOfInstructions(numberOfInstructions); } - /* - protected final void maximizeBasicBlocks(OPT_IR ir) { - for (OPT_BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) { - if (currBB.mergeFallThrough(ir)) { - // don't advance currBB; it may have a new trivial fallthrough to - // swallow - } else { - currBB = currBB.nextBasicBlockInCodeOrder(); - } - } - }*/ /** @@ -759,8 +750,11 @@ * within the code cache c) The trace is already too long d) the branch is * supposedly a CALL or RETURN */ + + DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); + return DBT_Options.singleInstrTranslation == false - && ps.codeCache.tryGet(targetPc) == null && !shallTraceStop() + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 20) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; } @@ -789,7 +783,7 @@ if (targetBB != null) return targetBB; - if (inlineBranchInstruction(targetPc, jump)) { + if (!inlineBranchInstruction(targetPc, jump)) { // Just exit the trace and continue at the target address in a new trace if (currentBlock.getNumberOfRealInstructions() != 0) { @@ -903,7 +897,7 @@ // Copy the value into the register specified by gc.resultReg. appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand( gc.resultReg, VM_TypeReference.Int), nextPc.copy())); - resolveLaziness(laziness); + resolveLaziness((Laziness)laziness.clone()); appendInstruction(Goto.create(GOTO, finishBlock.makeJumpTarget())); currentBlock.deleteNormalOut(); currentBlock.insertOut(finishBlock); @@ -1305,9 +1299,7 @@ */ public void appendInterpretedInstruction(int pc, Laziness lazy) { - if (lazy != null) - resolveLaziness(lazy); - + resolveLaziness(lazy); spillAllRegisters(); // Prepare a local variable of type Interpreter Modified: src/org/binarytranslator/vmInterface/DBT_Trace.java =================================================================== --- src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-07 22:28:53 UTC (rev 161) @@ -97,6 +97,9 @@ */ public final int pc; + /** The number of guest instructions that have been compiled into this trace. */ + private int numberOfInstructions; + /** * In order to allow arbitrary calls within a trace, we have to store at which bytecode index * a method is called in which way. This class stores the necessary information. */ @@ -321,4 +324,12 @@ public int getBytecodeLength() { return 256; } + + public int getNumberOfInstructions() { + return numberOfInstructions; + } + + public void setNumberOfInstructions(int numberOfInstructions) { + this.numberOfInstructions = numberOfInstructions; + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |