public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { ASMOps.BranchOp branchOp = ASMOps.BranchOp.Branch; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Br: case OpCodes.Br_S: break; case OpCodes.Brtrue: branchOp = ASMOps.BranchOp.BranchNotZero; break; case OpCodes.Brtrue_S: branchOp = ASMOps.BranchOp.BranchNotZero; break; case OpCodes.Brfalse: branchOp = ASMOps.BranchOp.BranchZero; break; case OpCodes.Brfalse_S: branchOp = ASMOps.BranchOp.BranchZero; break; case OpCodes.Beq: branchOp = ASMOps.BranchOp.BranchEqual; break; case OpCodes.Beq_S: branchOp = ASMOps.BranchOp.BranchEqual; break; case OpCodes.Bne_Un: branchOp = ASMOps.BranchOp.BranchNotEqual; break; case OpCodes.Bne_Un_S: branchOp = ASMOps.BranchOp.BranchNotEqual; break; case OpCodes.Bge: branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; break; case OpCodes.Bge_S: branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; break; case OpCodes.Bge_Un: branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; break; case OpCodes.Bge_Un_S: branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; break; case OpCodes.Ble: branchOp = ASMOps.BranchOp.BranchLessThanEqual; break; case OpCodes.Ble_S: branchOp = ASMOps.BranchOp.BranchLessThanEqual; break; case OpCodes.Ble_Un: branchOp = ASMOps.BranchOp.BranchLessThanEqual; break; case OpCodes.Ble_Un_S: branchOp = ASMOps.BranchOp.BranchLessThanEqual; break; case OpCodes.Blt: branchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Blt_S: branchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Blt_Un: branchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Blt_Un_S: branchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Bgt: branchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Bgt_S: branchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Bgt_Un: branchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Bgt_Un_S: branchOp = ASMOps.BranchOp.BranchGreaterThan; break; } if (branchOp == ASMOps.BranchOp.BranchZero || branchOp == ASMOps.BranchOp.BranchNotZero) { //Pop from our stack the test item to use in the condition StackItem testItem = conversionState.CurrentStackFrame.Stack.Pop(); } else if (branchOp == ASMOps.BranchOp.BranchEqual || branchOp == ASMOps.BranchOp.BranchNotEqual || branchOp == ASMOps.BranchOp.BranchGreaterThanEqual || branchOp == ASMOps.BranchOp.BranchLessThanEqual || branchOp == ASMOps.BranchOp.BranchLessThan || branchOp == ASMOps.BranchOp.BranchGreaterThan) { //Pop from our stack the test items to use in the condition StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if branch test operand value is a floating point value. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //This will store the offset from the current next op's position //to the IL op to branch to. int ILOffset = 0; //This will store the branch operation - by default, the basic branch op ASMOps.BranchOp branchOp = ASMOps.BranchOp.Branch; bool UnsignedTest = false; ASMOps.BranchOp inverseBranchOp = ASMOps.BranchOp.None; bool isNegativeTest = false; //The value for the branch op to test against - currently always "0" since on jnz and jz ops are used. string testVal = "0"; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Br: //Load the IL offset as signed Int 32 from the value bytes. ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); break; case OpCodes.Br_S: //Load the IL offset as signed Int 8 from the value bytes. ILOffset = (int)(sbyte)theOp.ValueBytes[0]; break; case OpCodes.Brtrue: //See above. ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-true means we want to do the branch if the operand is not equal to 0 //i.e. not false //Set the branch op to jnz - Branch if Not Zero branchOp = ASMOps.BranchOp.BranchNotZero; break; case OpCodes.Brtrue_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchNotZero; break; case OpCodes.Brfalse: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-true means we want to do the branch if the operand is equal to 0 //i.e. is false //Set the branch op to jz - Branch if Zero branchOp = ASMOps.BranchOp.BranchZero; break; case OpCodes.Brfalse_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchZero; break; case OpCodes.Beq: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-equal means we want to do the branch if the operand is equal to the other operand //i.e. A == B //Set the branch op to je - Branch if equal branchOp = ASMOps.BranchOp.BranchEqual; inverseBranchOp = ASMOps.BranchOp.BranchNotEqual; break; case OpCodes.Beq_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchEqual; inverseBranchOp = ASMOps.BranchOp.BranchNotEqual; break; case OpCodes.Bne_Un: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-equal means we want to do the branch if the operand is equal to the other operand //i.e. A == B //Set the branch op to je - Branch if not equal branchOp = ASMOps.BranchOp.BranchNotEqual; isNegativeTest = true; break; case OpCodes.Bne_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchNotEqual; isNegativeTest = true; break; case OpCodes.Bge: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-greater-than-or-equal means we want to do the branch if the operand is greater than equal to //the other operand //i.e. A >= B //Set the branch op to jge - Branch if greater than or equal branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Bge_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Bge_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Bge_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchGreaterThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchLessThan; break; case OpCodes.Ble: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-less-than-or-equal means we want to do the branch if the operand is less than equal to //the other operand //i.e. A <= B //Set the branch op to jle - Branch if less than or equal branchOp = ASMOps.BranchOp.BranchLessThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Ble_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchLessThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Ble_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchLessThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Ble_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchLessThanEqual; inverseBranchOp = ASMOps.BranchOp.BranchGreaterThan; break; case OpCodes.Blt: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-less-than means we want to do the branch if the operand is less than //the other operand //i.e. A < B //Set the branch op to jl - Branch if less than branchOp = ASMOps.BranchOp.BranchLessThan; isNegativeTest = true; break; case OpCodes.Blt_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchLessThan; isNegativeTest = true; break; case OpCodes.Blt_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchLessThan; isNegativeTest = true; break; case OpCodes.Blt_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchLessThan; isNegativeTest = true; break; case OpCodes.Bgt: //See above ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); //Branch-if-greater-than means we want to do the branch if the operand is greater than //the other operand //i.e. A > B //Set the branch op to jg - Branch if greater than branchOp = ASMOps.BranchOp.BranchGreaterThan; isNegativeTest = true; break; case OpCodes.Bgt_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; //See above branchOp = ASMOps.BranchOp.BranchGreaterThan; isNegativeTest = true; break; case OpCodes.Bgt_Un: //See above : This is unsigned variant ILOffset = Utilities.ReadInt32(theOp.ValueBytes, 0); UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchGreaterThan; isNegativeTest = true; break; case OpCodes.Bgt_Un_S: //See above ILOffset = (int)(sbyte)theOp.ValueBytes[0]; UnsignedTest = true; //See above branchOp = ASMOps.BranchOp.BranchGreaterThan; isNegativeTest = true; break; } if (ILOffset == 0) { //Err..why bother jumping at all if the offset is 0? conversionState.Append(new ASMOps.Comment("No jump insert - pointless 0 distance jump")); } else { //Get the IL number of the next op int startILNum = theOp.NextOffset; //Add the offset to get the IL op num to jump to int ILNumToGoTo = startILNum + ILOffset; //Find the IL op to jump to ILOp opToGoTo = conversionState.Input.At(ILNumToGoTo); int opToGoToPosition = conversionState.PositionOf(opToGoTo); int currOpPosition = conversionState.PositionOf(theOp); //If the jump op is not a straightforward jump i.e. has one or more conditions if (branchOp == ASMOps.BranchOp.BranchZero || branchOp == ASMOps.BranchOp.BranchNotZero) { //Pop from our stack the test item to use in the condition StackItem testItem = conversionState.CurrentStackFrame.Stack.Pop(); if (testItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Branch test based on float not supported!"); } //If the test item is Int64 or UInt64 else if (testItem.sizeOnStackInBytes == 8) { //Compare first 32 bits (low bits) //Then (if necessary) compare second 32 bits (high bits) //Pop the low bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Pop the high bits conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //If we are testing for not equal to zero: if (branchOp == ASMOps.BranchOp.BranchNotZero) { //If the low bits are not zero, do the jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src2 = testVal, Src1 = "$t0", DestILPosition = opToGoToPosition }); //If the high bits are not zero, do the jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t1", Src2 = testVal, DestILPosition = opToGoToPosition }); } //If we are testing for equal to zero: else if (branchOp == ASMOps.BranchOp.BranchZero) { //If the low bits are not zero, jump to the end of these tests as condition has not been met conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t0", DestILPosition = opToGoToPosition, Extension = "End" }); //If the high bits are zero, do the jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t1", DestILPosition = opToGoToPosition }); //Insert the end label to be jumped to if condition is not met (see above) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); } else { //Check that no extra ops have been added in the switch block above! throw new NotSupportedException("Unsupported 64-bit branch op!"); } } //If the test item is Int32 or UInt32 else if (testItem.sizeOnStackInBytes == 4) { //Pop the test item conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Do the specified jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t0", Src2 = testVal, DestILPosition = opToGoToPosition }); } else { throw new InvalidOperationException("Invalid stack operand sizes!"); } } else if (branchOp == ASMOps.BranchOp.BranchEqual || branchOp == ASMOps.BranchOp.BranchNotEqual || branchOp == ASMOps.BranchOp.BranchGreaterThanEqual || branchOp == ASMOps.BranchOp.BranchLessThanEqual || branchOp == ASMOps.BranchOp.BranchLessThan || branchOp == ASMOps.BranchOp.BranchGreaterThan) { //Pop from our stack the test items to use in the condition StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.isFloat || itemB.isFloat) { //SUPPORT - floats throw new NotSupportedException("Branch test based on float not supported!"); } else if (itemA.sizeOnStackInBytes != itemB.sizeOnStackInBytes) { throw new InvalidOperationException("Branch test operands must be same size!"); } else if (itemA.sizeOnStackInBytes == 8) { //Pop the test item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); //Pop the test item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); if (!isNegativeTest) { //Compare test item A high bits to test item B high bits //If they are not equal, abort the testing conversionState.Append(new ASMOps.Branch() { BranchType = inverseBranchOp, Src1 = "$t3", Src2 = "$t2", DestILPosition = currOpPosition, Extension = "End", UnsignedTest = UnsignedTest }); //Else the igh bits are equal so test low bits //Compare test item A low bits to test item B low bits //Do the specified jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t1", Src2 = "$t0", DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); //Insert the end label to be jumped to if condition is not met (see above) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); } else { //Compare test item A high bits to test item B high bits //Do the specified jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t3", Src2 = "$t2", DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); //Compare test item A low bits to test item B low bits //Do the specified jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t1", Src2 = "$t0", DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); } } else if (itemA.sizeOnStackInBytes == 4) { //Pop the test item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop the test item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Compare test item A to test item B //Do the specified jump conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, Src1 = "$t0", Src2 = "$t1", DestILPosition = opToGoToPosition, UnsignedTest = UnsignedTest }); } else { throw new NotSupportedException("Branch test based on supplied stack item sizes not supported!"); } } else { //Do the straightforward jump... conversionState.Append(new ASMOps.Branch() { BranchType = branchOp, DestILPosition = opToGoToPosition }); } } }