示例#1
0
 public LowInstruction(LowOp op, int dest, int left, int right, ulong data)
 {
     Op    = op;
     Dest  = dest;
     Left  = left;
     Right = right;
     Data  = data;
 }
示例#2
0
        public void Noncommutative_arithmetic_destination_is_not_same_as_right(LowOp op)
        {
            var method = new LowMethod <X64Register>();

            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32, X64Register.Rax));
            method.Blocks.Add(new LowBlock
            {
                Instructions =
                {
                    new LowInstruction(LowOp.LoadInt, 0, 0, 0, 1), // Load 1 -> #0
                    new LowInstruction(LowOp.LoadInt, 1, 0, 0, 1), // Load 1 -> #1

                    new LowInstruction(op,            2, 0, 1, 0), // Subtract/Shift #0 - #1 -> #2

                    new LowInstruction(LowOp.Test,    0, 0, 0, 0), // Use #0
                    new LowInstruction(LowOp.Move,    3, 2, 0, 0), // Use #2
                    new LowInstruction(LowOp.Return,  0, 3, 0, 0)
                },
                Predecessors = Array.Empty <int>(),
                Successors   = Array.Empty <int>()
            });

            var(rewritten, allocationMap) = X64RegisterAllocator.Allocate(method);

            AssertDump(rewritten, $@"
LB_0:
    LoadInt 0 0 1 -> 0
    LoadInt 0 0 1 -> 1
    {op} 0 1 0 -> 2
    Test 0 0 0 -> 0
    Move 2 0 0 -> 3
    Return 3 0 0 -> 0");

            Assert.That(allocationMap.Get(0).localIndex, Is.EqualTo(0));
            Assert.That(allocationMap.Get(1).localIndex, Is.EqualTo(1));
            Assert.That(allocationMap.Get(2).localIndex, Is.EqualTo(2));

            // It would be tempting to assign #1 and #2 the same register, but that
            // is not good for x64: we would have to emit "mov r1, r0; sub r1, r1" where
            // local #1 is stored in r1 but local #2 lives there up until the last instruction.
            Assert.That(allocationMap.Get(1).location.Register,
                        Is.Not.EqualTo(allocationMap.Get(2).location.Register));
        }
示例#3
0
        public void Load_right_and_arithmetic_are_folded(LowOp arithmeticOp, long constant)
        {
            // The right operand of shift has special location on x64
            var isShift       = arithmeticOp == LowOp.ShiftLeft || arithmeticOp == LowOp.ShiftArithmeticRight;
            var rightLocation = isShift ? X64Register.Rdx : X64Register.Invalid;

            var method = new LowMethod <X64Register>();

            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32, requiredLocation: X64Register.Rcx));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32, requiredLocation: rightLocation));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32));
            method.Blocks.Add(new LowBlock
            {
                Instructions =
                {
                    new LowInstruction(LowOp.LoadInt, 1, 0, 0, (ulong)constant), // Load constant -> #1
                    new LowInstruction(arithmeticOp,  2, 0, 1, 0)                // #0 op #1 -> #2
                }
            });

            var expected = @$ "
; #0 int32 [rcx]
示例#4
0
        public void Division_reserves_rdx(LowOp op)
        {
            var method = new LowMethod <X64Register>();

            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32, X64Register.Rax));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Int32, X64Register.Rax));
            method.Blocks.Add(new LowBlock
            {
                Instructions =
                {
                    new LowInstruction(LowOp.LoadInt, 0, 0, 0, 1), // Load 1 -> #0
                    new LowInstruction(LowOp.LoadInt, 1, 0, 0, 1), // Load 1 -> #1
                    new LowInstruction(LowOp.LoadInt, 2, 0, 0, 1), // Load 1 -> #2

                    new LowInstruction(op,            3, 2, 2, 0), // Divide #2 / #2 -> #3

                    new LowInstruction(LowOp.Test,    0, 0, 0, 0), // Use #0
                    new LowInstruction(LowOp.Move,    0, 1, 0, 0), // Use #1
                    new LowInstruction(LowOp.Return,  0, 3, 0, 0)
                },
                Predecessors = Array.Empty <int>(),
                Successors   = Array.Empty <int>()
            });

            var(_, allocationMap) = X64RegisterAllocator.Allocate(method);

            // RDX holds the upper part of dividend and therefore must be reserved
            for (var i = 0; i < allocationMap.IntervalCount; i++)
            {
                var(location, localIndex) = allocationMap.Get(i);
                if (localIndex >= 0)
                {
                    Assert.That(location.Register, Is.Not.EqualTo(X64Register.Rdx));
                }
            }
        }
示例#5
0
        public void Call_instruction_reserves_registers(LowOp callOp)
        {
            var method = new LowMethod <X64Register>();

            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Bool));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Bool));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Bool));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Bool));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Bool));
            method.Locals.Add(new LowLocal <X64Register>(SimpleType.Void, X64Register.Rax));
            method.Blocks.Add(new LowBlock
            {
                Instructions =
                {
                    new LowInstruction(LowOp.LoadInt, 0, 0, 0, 1),    // Load 1 -> #0
                    new LowInstruction(LowOp.LoadInt, 1, 0, 0, 1),    // Load 1 -> #1
                    new LowInstruction(LowOp.LoadInt, 2, 0, 0, 1),    // Load 1 -> #2
                    new LowInstruction(LowOp.LoadInt, 3, 0, 0, 1),    // Load 1 -> #3
                    new LowInstruction(LowOp.LoadInt, 4, 0, 0, 1),    // Load 1 -> #4

                    new LowInstruction(callOp,        5, 0, 0, 1234), // Call - this trashes rax, rcx, rdx, r8 and r9

                    new LowInstruction(LowOp.Test,    0, 0, 0, 0),    // Test #0
                    new LowInstruction(LowOp.Test,    0, 1, 0, 0),    // Test #1
                    new LowInstruction(LowOp.Test,    0, 2, 0, 0),    // Test #2
                    new LowInstruction(LowOp.Test,    0, 3, 0, 0),    // Test #3
                    new LowInstruction(LowOp.Test,    0, 4, 0, 0),    // Test #4
                    new LowInstruction(LowOp.Return,  5, 0, 0, 0)
                },
                Predecessors = Array.Empty <int>(),
                Successors   = Array.Empty <int>()
            });

            var(_, allocationMap) = X64RegisterAllocator.Allocate(method);

            // No local variable should be assigned to a blocked register
            for (var i = 0; i < allocationMap.IntervalCount; i++)
            {
                var(location, localIndex) = allocationMap.Get(i);

                if (localIndex == -1)
                {
                    continue;
                }

                if (localIndex == 5)
                {
                    Assert.That(location.Register, Is.EqualTo(X64Register.Rax));
                    continue;
                }

                Assert.That(location.IsSet, Is.True);
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.Rax));
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.Rcx));
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.Rdx));
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.R8));
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.R9));
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.R10));
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.R11));

                // ..and as a general sanity check, do not allocate the stack pointer!
                Assert.That(location.Register, Is.Not.EqualTo(X64Register.Rsp));
            }
        }