Cosmos/source2/IL2CPU/Cosmos.IL2CPU.X86/IL/Branch.cs
Trivalik_cp dfbf5f4f00 fix all branches for 64bit,
add comment in fatstream to array copy
2011-06-17 07:45:00 +00:00

193 lines
No EOL
10 KiB
C#

using System;
using Cosmos.IL2CPU.X86;
using CPU = Cosmos.Compiler.Assembler.X86;
using Cosmos.Compiler.Assembler.X86;
using Label = Cosmos.Compiler.Assembler.Label;
namespace Cosmos.IL2CPU.X86.IL {
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Beq)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bge)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bgt)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Ble)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Blt)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bne_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bge_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bgt_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Ble_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Blt_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Brfalse)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Brtrue)]
public class Branch: ILOp {
public Branch(Cosmos.Compiler.Assembler.Assembler aAsmblr)
: base(aAsmblr) {
}
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) {
var xStackContent = Assembler.Stack.Pop();
var xIsSingleCompare = true;
switch (aOpCode.OpCode) {
case ILOpCode.Code.Beq:
case ILOpCode.Code.Bge:
case ILOpCode.Code.Bgt:
case ILOpCode.Code.Bge_Un:
case ILOpCode.Code.Bgt_Un:
case ILOpCode.Code.Ble:
case ILOpCode.Code.Ble_Un:
case ILOpCode.Code.Bne_Un:
case ILOpCode.Code.Blt:
case ILOpCode.Code.Blt_Un:
Assembler.Stack.Pop();
xIsSingleCompare = false;
break;
}
if (xStackContent.Size > 8) {
throw new Exception("StackSize > 8 not supported");
}
CPU.ConditionalTestEnum xTestOp;
// all conditions are inverted here?
switch (aOpCode.OpCode) {
case ILOpCode.Code.Beq:
xTestOp = CPU.ConditionalTestEnum.Zero;
break;
case ILOpCode.Code.Bge:
xTestOp = CPU.ConditionalTestEnum.GreaterThanOrEqualTo;
break;
case ILOpCode.Code.Bgt:
xTestOp = CPU.ConditionalTestEnum.GreaterThan;
break;
case ILOpCode.Code.Ble:
xTestOp = CPU.ConditionalTestEnum.LessThanOrEqualTo;
break;
case ILOpCode.Code.Blt:
xTestOp = CPU.ConditionalTestEnum.LessThan;
break;
case ILOpCode.Code.Bne_Un:
xTestOp = CPU.ConditionalTestEnum.NotEqual;
break;
case ILOpCode.Code.Bge_Un:
xTestOp = CPU.ConditionalTestEnum.AboveOrEqual;
break;
case ILOpCode.Code.Bgt_Un:
xTestOp = CPU.ConditionalTestEnum.Above;
break;
case ILOpCode.Code.Ble_Un:
xTestOp = CPU.ConditionalTestEnum.BelowOrEqual;
break;
case ILOpCode.Code.Blt_Un:
xTestOp = CPU.ConditionalTestEnum.Below;
break;
case ILOpCode.Code.Brfalse:
xTestOp = CPU.ConditionalTestEnum.Zero;
break;
case ILOpCode.Code.Brtrue:
xTestOp = CPU.ConditionalTestEnum.NotZero;
break;
default:
throw new Exception("Unknown OpCode for conditional branch.");
}
if (!xIsSingleCompare) {
if (xStackContent.Size <= 4) {
new CPU.Pop { DestinationReg = CPU.Registers.EAX };
new CPU.Pop { DestinationReg = CPU.Registers.EBX };
new CPU.Compare { DestinationReg = CPU.Registers.EBX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
} else {
var xNoJump = GetLabel(aMethod, aOpCode) + "__NoBranch";
// value 2 EBX:EAX
new CPU.Pop { DestinationReg = CPU.Registers.EAX };
new CPU.Pop { DestinationReg = CPU.Registers.EBX };
// value 1 EDX:ECX
new CPU.Pop { DestinationReg = CPU.Registers.ECX };
new CPU.Pop { DestinationReg = CPU.Registers.EDX };
switch (xTestOp)
{
case ConditionalTestEnum.Zero: // Equal
case ConditionalTestEnum.NotEqual: // NotZero
new CPU.Xor { DestinationReg = CPU.Registers.EAX, SourceReg = CPU.Registers.ECX };
new CPU.ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.Xor { DestinationReg = CPU.Registers.EBX, SourceReg = CPU.Registers.EDX };
new CPU.ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
break;
case ConditionalTestEnum.GreaterThanOrEqualTo:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.LessThan, DestinationLabel = xNoJump };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.GreaterThan, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Below, DestinationLabel = xNoJump };
break;
case ConditionalTestEnum.GreaterThan:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.LessThan, DestinationLabel = xNoJump };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.GreaterThan, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.BelowOrEqual, DestinationLabel = xNoJump };
break;
case ConditionalTestEnum.LessThanOrEqualTo:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.LessThan, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.GreaterThan, DestinationLabel = xNoJump };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.BelowOrEqual, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
break;
case ConditionalTestEnum.LessThan:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.LessThan, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.GreaterThan, DestinationLabel = xNoJump };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Below, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
break;
// from here all unsigned
case ConditionalTestEnum.AboveOrEqual:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Above, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Below, DestinationLabel = xNoJump };
break;
case ConditionalTestEnum.Above:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Above, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.BelowOrEqual, DestinationLabel = xNoJump };
break;
case ConditionalTestEnum.BelowOrEqual:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Above, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Below, DestinationLabel = xNoJump };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Above, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
break;
case ConditionalTestEnum.Below:
new CPU.Compare { DestinationReg = CPU.Registers.EDX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Above, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Below, DestinationLabel = xNoJump };
new CPU.Compare { DestinationReg = CPU.Registers.ECX, SourceReg = CPU.Registers.EAX };
new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.AboveOrEqual, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
break;
default:
throw new Exception("Unknown OpCode for conditional branch in 64-bit.");
}
new Label(xNoJump);
}
} else {
// todo: improve code clarity
if (xStackContent.Size > 4) {
throw new Exception("Simple branches are not supported yet on operands > 4 bytes!");
}
new CPU.Pop { DestinationReg = CPU.Registers.EAX };
if (xTestOp == ConditionalTestEnum.Zero) {
new CPU.Compare { DestinationReg = CPU.Registers.EAX, SourceValue = 0 };
new CPU.ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
} else if (xTestOp == ConditionalTestEnum.NotZero) {
new CPU.Compare { DestinationReg = CPU.Registers.EAX, SourceValue = 0 };
new CPU.ConditionalJump { Condition = ConditionalTestEnum.NotEqual, DestinationLabel = AppAssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
} else {
throw new NotSupportedException("Situation not supported yet!");
}
}
}
}
}