Esempio n. 1
0
def MakeGenericCpuRegs(num_gpr_not_lac,
                       num_gpr_lac=0,
                       num_flt_not_lac=0,
                       num_flt_lac=0):
    return (
        [ir.CpuReg(f"gn{i}", i, GPR_NOT_LAC) for i in range(num_gpr_not_lac)] +
        [ir.CpuReg(f"gl{i}", i, GPR_LAC) for i in range(num_gpr_lac)] +
        [ir.CpuReg(f"sn{i}", i, FLT_NOT_LAC) for i in range(num_flt_not_lac)] +
        [ir.CpuReg(f"sl{i}", i, FLT_LAC) for i in range(num_flt_lac)])
Esempio n. 2
0
    def testD(self):
        code = io.StringIO(r"""
.fun arm_syscall_write SIGNATURE [S32] = [S32 A32 U32]

.fun putchar NORMAL [] = [U32]

.fun writeln NORMAL [] = [A32 U32]
# live_out: ['r0', 'r1']
.reg S32 [$r0_S32 dummy]
.reg U32 [$r0_U32 $r1_U32 $r2_U32 len]
.reg A32 [$r0_A32 $r1_A32 buf]
.bbl start
    mov buf $r0_A32@r0                     # 0
    mov len $r1_U32@r1                     # 1
    mov $r2_U32@r2 len                     # 2
    mov $r1_A32@r1 buf                     # 3
    mov $r0_S32@r0 1                       # 4
    syscall arm_syscall_write 4:U32        # 5
    mov dummy $r0_S32@r0                   # 6
    mov $r0_U32@r0 10                      # 7
    bsr putchar                            # 8
    ret                                    # 9
""")
        cpu_regs = {"r0": ir.CpuReg("r0", 0), "r1": ir.CpuReg("r1", 1), "r2": ir.CpuReg("r2", 2)}
        unit = serialize.UnitParseFromAsm(code, cpu_regs=cpu_regs)

        fun = unit.fun_syms["arm_syscall_write"]
        fun.cpu_live_out = {cpu_regs["r0"]}
        fun.cpu_live_in = {cpu_regs["r0"], cpu_regs["r1"], cpu_regs["r2"]}

        fun = unit.fun_syms["putchar"]
        fun.cpu_live_in = {cpu_regs["r0"]}

        fun = unit.fun_syms["writeln"]
        cfg.FunSplitBbls(fun)
        cfg.FunInitCFG(fun)
        cfg.FunRemoveUnconditionalBranches(fun)
        cfg.FunRemoveEmptyBbls(fun)
        liveness.FunComputeLivenessInfo(fun)
        ranges = liveness.BblGetLiveRanges(fun.bbls[0], fun, fun.bbls[0].live_out, False)
        ranges.sort()
        print("TestD")
        for lr in ranges:
            print(lr)
        self.assertEqual(ranges, [
            liveness.LiveRange(liveness.BEFORE_BBL, 0, fun.reg_syms["$r0_A32"], 1),
            liveness.LiveRange(liveness.BEFORE_BBL, 1, fun.reg_syms["$r1_U32"], 1),
            liveness.LiveRange(0, 3, fun.reg_syms["buf"], 1),
            liveness.LiveRange(1, 2, fun.reg_syms["len"], 1),
            liveness.LiveRange(2, 5, fun.reg_syms["$r2_U32"], 0),
            liveness.LiveRange(3, 5, fun.reg_syms["$r1_A32"], 0),
            liveness.LiveRange(4, 5, fun.reg_syms["$r0_S32"], 0),
            liveness.LiveRange(5, 6, fun.reg_syms["$r0_S32"], 1),
            liveness.LiveRange(6, liveness.NO_USE, fun.reg_syms["dummy"], 0),
            liveness.LiveRange(7, 8, fun.reg_syms["$r0_U32"], 0),
        ])
Esempio n. 3
0
 def get_available_reg(self, lr: liveness.LiveRange) -> ir.CpuReg:
     key: REG_KIND_LAC = self._get_reg_class(lr)
     available = self._available.get(key)
     if available:
         return available.pop(-1)
     else:
         # manufacture a new register
         self.counter += 1
         return ir.CpuReg(f"z{self.counter}", key[1], key[0].value)
Esempio n. 4
0
    def testE(self):
        code = io.StringIO(r"""


.fun test NORMAL [F32 F32 F32 F32] = [F32 F32]
.reg F32 [a b add sub mul div  $s0_F32  $s1_F32  $s2_F32  $s3_F32]
.bbl start
    mov a $s0_F32@s0
    mov b $s1_F32@s1
    add add a b
    sub sub a b
    mul mul a b
    div div a b
    mov $s3_F32@s3 div
    mov $s2_F32@s2 mul
    mov $s1_F32@s1 sub
    mov $s0_F32@s0 add
    ret
""")
        cpu_regs = {
            "s0": ir.CpuReg("s0", 0),
            "s1": ir.CpuReg("s1", 1),
            "s2": ir.CpuReg("s2", 2),
            "s3": ir.CpuReg("s3", 2)
        }
        unit = serialize.UnitParseFromAsm(code, cpu_regs=cpu_regs)
        fun = unit.fun_syms["test"]
        fun.cpu_live_out = {
            cpu_regs["s0"], cpu_regs["s1"], cpu_regs["s2"], cpu_regs["s3"]
        }
        fun.cpu_live_in = {cpu_regs["s0"], cpu_regs["s1"]}
        cfg.FunSplitBblsAtTerminators(fun)
        cfg.FunInitCFG(fun)
        cfg.FunRemoveUnconditionalBranches(fun)
        cfg.FunRemoveEmptyBbls(fun)
        liveness.FunComputeLivenessInfo(fun)
        ranges = liveness.BblGetLiveRanges(fun.bbls[0], fun,
                                           fun.bbls[0].live_out)
        ranges.sort()
        print("TestE")
        for lr in ranges:
            print(lr)
Esempio n. 5
0
 def get_available_reg(self, lr: liveness.LiveRange) -> ir.CpuReg:
     key: REG_KIND_LAC = self._get_reg_class(lr)
     available = self._available.get(key)
     if available:
         cpu_reg = available.pop(-1)
     else:
         # manufacture a new register
         self.counter += 1
         cpu_reg = ir.CpuReg(f"z{self.counter}", key[1], key[0])
     if TRACE_REG_ALLOC:
         print(f"{cpu_reg.name} {key} <- {lr}")
     return cpu_reg
Esempio n. 6
0
from Base import ir
from Base.liveness import LiveRange, BblGetLiveRanges, BEFORE_BBL, AFTER_BBL, LiveRangeFlag
from Base import opcode_tab as o
from Base import serialize
from Base import reg_alloc

O = o.Opcode.Lookup

LAC = 16
GPR_NOT_LAC = 1
GPR_LAC = LAC + GPR_NOT_LAC
FLT_NOT_LAC = 2
FLT_LAC = LAC + FLT_NOT_LAC

A32_REGS = (
    [ir.CpuReg(f"r{i}", i, GPR_NOT_LAC) for i in range(6)] +
    [ir.CpuReg(f"r12", 12, GPR_NOT_LAC),
     ir.CpuReg(f"r14", 14, GPR_NOT_LAC)] +
    [ir.CpuReg(f"r{i}", i, GPR_LAC) for i in range(6, 12)] +
    [ir.CpuReg(f"s{i}", i, FLT_NOT_LAC) for i in range(16)] +
    [ir.CpuReg(f"s{i}", i, FLT_LAC) for i in range(16, 32)])


def DumpBbl(bbl):
    lines = serialize.BblRenderToAsm(bbl)
    print(lines.pop(0))
    for n, l in enumerate(lines):
        print(f"{n:2d}", l)


def extract_lsb(x):
Esempio n. 7
0
from Base import serialize

import dataclasses
from typing import List, Optional, Tuple
import enum


# This must mimic the DK enum (0: invalid, no more than 255 entries)
@enum.unique
class CpuRegKind(enum.Enum):
    INVALID = 0
    GPR = 1
    FLT = 2


_GPR_REGS = [ir.CpuReg(f"x{i}" if i != 31 else "sp", i, CpuRegKind.GPR)
             for i in range(32)]

_FLT_REGS = [ir.CpuReg(f"d{i}", i, CpuRegKind.FLT) for i in range(32)]

# used to map function parameters to CpuRegs and for non-lac regs
# note: our calling convention does not completely match the official one
_GPR_PARAMETER_REGS = _GPR_REGS[0:16]
_FLT_PARAMETER_REGS = _FLT_REGS[0:8] + _FLT_REGS[16:32]

CPU_REGS_MAP = {**{r.name: r for r in _GPR_REGS},
                **{r.name: r for r in _FLT_REGS}}

REG_KIND_TO_CPU_REG_FAMILY = {
    o.DK.S8: CpuRegKind.GPR,
    o.DK.S16: CpuRegKind.GPR,
Esempio n. 8
0
from typing import List, Optional, Tuple
import enum

_GPR_REG_NAMES = ["r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
                  "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"]


@enum.unique
class A32RegKind(enum.IntEnum):
    INVALID = 0
    GPR = 1
    FLT = 2
    DBL = 2 + 16


_GPR_REGS = [ir.CpuReg(name, i, A32RegKind.GPR) for i, name in
             enumerate(_GPR_REG_NAMES)]
_FLT_REGS = [ir.CpuReg(f"s{i}", i, A32RegKind.FLT) for i in range(32)]
DBL_REGS = [ir.CpuReg(f"d{i}", i, A32RegKind.DBL) for i in range(16)]

CPU_REGS = {**{r.name: r for r in _GPR_REGS},
            **{r.name: r for r in _FLT_REGS},
            **{r.name: r for r in DBL_REGS}}


def A32RegToAllocMask(reg: ir.CpuReg) -> int:
    """ Note that for DBL and FLT this matches the architectural overlap

    For GPR this produces the right mask for ldm/stm
    """
    if reg.kind is A32RegKind.DBL:
Esempio n. 9
0

# This must mimic the DK enum (0: invalid, no more than 255 entries)
@enum.unique
class CpuRegKind(enum.IntEnum):
    INVALID = 0
    GPR = 1
    FLT = 2
    DBL = 2 + 16


GPR_FAMILY = 1
FLT_FAMILY = 2  # (includes FLT + DBL )

GPR_REGS = [
    ir.CpuReg(name, i, CpuRegKind.GPR) for i, name in enumerate(_GPR_REG_NAMES)
]
FLT_REGS = [ir.CpuReg(f"s{i}", i, CpuRegKind.FLT) for i in range(32)]
DBL_REGS = [ir.CpuReg(f"d{i}", i, CpuRegKind.DBL) for i in range(16)]

CPU_REGS_MAP = {
    **{r.name: r
       for r in GPR_REGS},
    **{r.name: r
       for r in FLT_REGS},
    **{r.name: r
       for r in DBL_REGS}
}


def A32RegToAllocMask(reg: ir.CpuReg) -> int:
Esempio n. 10
0
    o.DK.U16: GPR_FAMILY,
    o.DK.U32: GPR_FAMILY,
    o.DK.U64: GPR_FAMILY,
    #
    o.DK.A64: GPR_FAMILY,
    o.DK.C64: GPR_FAMILY,
    #
    o.DK.F32: FLT_FAMILY,
    o.DK.F64: FLT_FAMILY,
}

# We use the 64 bit reg names regardless of the operand width
_REG_NAMES = ["rax", "rcx", "rdx", "rbx", "sp", "rbp", "rsi", "rdi",
              "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"]

_GPR_REGS = [ir.CpuReg(name, i, CpuRegKind.GPR) for i, name in enumerate(_REG_NAMES)]

_FLT_REGS = [ir.CpuReg(f"xmm{i}", i, CpuRegKind.FLT) for i in range(16)]

CPU_REGS_MAP = {**{r.name: r for r in _GPR_REGS},
                **{r.name: r for r in _FLT_REGS}}

GPR_RESERVED_MASK = 0x0011  # rax/sp is not available for allocation
GPR_REGS_MASK = 0xffee
GPR_LAC_REGS_MASK = 0xf028  # rbx, rbp, r12-r15

GPR_REG_IMPLICIT_MASK = 0x0007  # rax/rcx/rdx must not be used for globals
FLT_RESERVED_MASK = 0x0001  # xmm0 is not available for allocation
FLT_REGS_MASK = 0xfffe
FLT_LAC_REGS_MASK = 0xff00  # xmm8 - xmm15
Esempio n. 11
0
    def testD(self):
        code = io.StringIO(r"""
.fun arm_syscall_write SIGNATURE [S32] = [S32 A32 U32]

.fun putchar NORMAL [] = [U32]

.fun writeln NORMAL [] = [A32 U32]
# live_out: ['r0', 'r1']
.reg S32 [$r0_S32 dummy]
.reg U32 [$r0_U32 $r1_U32 $r2_U32 len]
.reg A32 [$r0_A32 $r1_A32 buf]
.bbl start
    mov buf $r0_A32@r0                     # 0
    mov len $r1_U32@r1                     # 1
    mov $r2_U32@r2 len                     # 2
    mov $r1_A32@r1 buf                     # 3
    mov $r0_S32@r0 1                       # 4
    syscall arm_syscall_write 4:U32        # 5
    mov dummy $r0_S32@r0                   # 6
    mov $r0_U32@r0 10                      # 7
    bsr putchar                            # 8
    ret                                    # 9
""")
        cpu_regs = {
            "r0": ir.CpuReg("r0", 0),
            "r1": ir.CpuReg("r1", 1),
            "r2": ir.CpuReg("r2", 2)
        }
        unit = serialize.UnitParseFromAsm(code, cpu_regs=cpu_regs)

        fun = unit.fun_syms["arm_syscall_write"]
        fun.cpu_live_out = {cpu_regs["r0"]}
        fun.cpu_live_in = {cpu_regs["r0"], cpu_regs["r1"], cpu_regs["r2"]}

        fun = unit.fun_syms["putchar"]
        fun.cpu_live_in = {cpu_regs["r0"]}

        fun = unit.fun_syms["writeln"]
        cfg.FunSplitBblsAtTerminators(fun)
        cfg.FunInitCFG(fun)
        cfg.FunRemoveUnconditionalBranches(fun)
        cfg.FunRemoveEmptyBbls(fun)
        liveness.FunComputeLivenessInfo(fun)
        ranges = liveness.BblGetLiveRanges(fun.bbls[0], fun,
                                           fun.bbls[0].live_out)
        ranges.sort()
        print("TestD")
        for lr in ranges:
            print(lr)

        lr_r0 = liveness.LiveRange(liveness.BEFORE_BBL, 0,
                                   fun.reg_syms["$r0_A32"], 1)
        lr_r1 = liveness.LiveRange(liveness.BEFORE_BBL, 1,
                                   fun.reg_syms["$r1_U32"], 1)
        lr_buf = liveness.LiveRange(0, 3, fun.reg_syms["buf"], 1)
        lr_len = liveness.LiveRange(1, 2, fun.reg_syms["len"], 1)
        lr_r0_2 = liveness.LiveRange(5, 6, fun.reg_syms["$r0_S32"], 1)

        expected = [
            lr_r0,
            lr_r1,
            liveness.LiveRange(0,
                               0,
                               reg=ir.REG_INVALID,
                               num_uses=1,
                               uses=[lr_r0]),
            lr_buf,
            liveness.LiveRange(1,
                               1,
                               reg=ir.REG_INVALID,
                               num_uses=1,
                               uses=[lr_r1]),
            lr_len,
            liveness.LiveRange(2,
                               2,
                               reg=ir.REG_INVALID,
                               num_uses=1,
                               uses=[lr_len]),
            liveness.LiveRange(2, 5, fun.reg_syms["$r2_U32"], 0),
            liveness.LiveRange(3,
                               3,
                               reg=ir.REG_INVALID,
                               num_uses=1,
                               uses=[lr_buf]),
            liveness.LiveRange(3, 5, fun.reg_syms["$r1_A32"], 0),
            liveness.LiveRange(4, 5, fun.reg_syms["$r0_S32"], 0),
            lr_r0_2,
            liveness.LiveRange(6,
                               6,
                               reg=ir.REG_INVALID,
                               num_uses=1,
                               uses=[lr_r0_2]),
            liveness.LiveRange(6, liveness.NO_USE, fun.reg_syms["dummy"], 0),
            liveness.LiveRange(7, 8, fun.reg_syms["$r0_U32"], 0),
        ]
        # self.assertSequenceEqual(ranges, expected) # this does not work because of the uses field
        self.assertEqual(len(ranges), len(expected))
        for a, b in zip():
            self.assertEqual(a, b)