Exemplo n.º 1
0
    def test_bint(self):
        # type: () -> None
        x = Var('x')
        y = Var('y')
        z = Var('z')
        w = Var('w')
        v = Var('v')
        u = Var('u')

        r = Rtl(
            z << iadd(x, y),
            w << bint(v),
            u << iadd(z, w)
        )
        r1 = r.copy({})
        s = r.substitution(r1, {})

        s[x].set_typevar(TypeVar.singleton(i32.by(8)))
        s[z].set_typevar(TypeVar.singleton(i32.by(8)))
        # TODO: Relax this to simd=True
        s[v].set_typevar(TypeVar('v', '', bools=(1, 1), simd=(8, 8)))
        r1.cleanup_concrete_rtl()

        assert s is not None
        assert s[x].get_typevar().singleton_type() == i32.by(8)
        assert s[y].get_typevar().singleton_type() == i32.by(8)
        assert s[z].get_typevar().singleton_type() == i32.by(8)
        assert s[w].get_typevar().singleton_type() == i32.by(8)
        assert s[u].get_typevar().singleton_type() == i32.by(8)
        assert s[v].get_typevar().singleton_type() == b1.by(8)
Exemplo n.º 2
0
    def test_vselect_icmpimm(self):
        # type: () -> None
        x = Var('x')
        y = Var('y')
        z = Var('z')
        w = Var('w')
        v = Var('v')
        zeroes = Var('zeroes')
        imm0 = Var("imm0")

        r = Rtl(
                zeroes << iconst(imm0),
                y << icmp(intcc.eq, x, zeroes),
                v << vselect(y, z, w),
        )
        r1 = r.copy({})

        s = r.substitution(r1, {})
        s[zeroes].set_typevar(TypeVar.singleton(i32.by(4)))
        s[z].set_typevar(TypeVar.singleton(f32.by(4)))

        r1.cleanup_concrete_rtl()

        assert s is not None
        assert s[zeroes].get_typevar().singleton_type() == i32.by(4)
        assert s[x].get_typevar().singleton_type() == i32.by(4)
        assert s[y].get_typevar().singleton_type() == b32.by(4)
        assert s[z].get_typevar().singleton_type() == f32.by(4)
        assert s[w].get_typevar().singleton_type() == f32.by(4)
        assert s[v].get_typevar().singleton_type() == f32.by(4)
Exemplo n.º 3
0
    def test_width_check(self):
        # type: () -> None
        x = XForm(
            Rtl(self.v0 << copy(self.v1)),
            Rtl((self.v2, self.v3) << isplit(self.v1),
                self.v0 << iconcat(self.v2, self.v3)))

        WideInt = TypeSet(lanes=(1, 256), ints=(16, 64))
        self.check_yo_check(x, typeset_check(self.v1, WideInt))
Exemplo n.º 4
0
    def test_cleanup_concrete_rtl_ireduce_bad(self):
        # type: () -> None
        x = Var('x')
        y = Var('y')
        x.set_typevar(TypeVar.singleton(i16.by(1)))
        r = Rtl(
                y << ireduce(x),
        )

        with self.assertRaises(AssertionError):
            r.cleanup_concrete_rtl()
Exemplo n.º 5
0
    def test_cleanup_concrete_rtl_fail(self):
        # type: () -> None
        x = Var('x')
        lo = Var('lo')
        hi = Var('hi')
        r = Rtl(
                (lo, hi) << vsplit(x),
        )

        with self.assertRaises(AssertionError):
            r.cleanup_concrete_rtl()
Exemplo n.º 6
0
    def test_lanes_check(self):
        # type: () -> None
        x = XForm(
            Rtl(self.v0 << copy(self.v1)),
            Rtl((self.v2, self.v3) << vsplit(self.v1),
                self.v0 << vconcat(self.v2, self.v3)))

        WideVec = TypeSet(lanes=(2, 256),
                          ints=(8, 64),
                          floats=(32, 64),
                          bools=(1, 64))
        self.check_yo_check(x, typeset_check(self.v1, WideVec))
Exemplo n.º 7
0
def widen_imm(signed, op):
    # type: (bool, Instruction) -> None
    for int_ty in [types.i8, types.i16]:
        if signed:
            widen.legalize(
                a << op.bind(int_ty)(b, c),
                Rtl(x << sextend.i32(b), z << op.i32(x, c),
                    a << ireduce.bind(int_ty)(z)))
        else:
            widen.legalize(
                a << op.bind(int_ty)(b, c),
                Rtl(x << uextend.i32(b), z << op.i32(x, c),
                    a << ireduce.bind(int_ty)(z)))
Exemplo n.º 8
0
    def test_elaborate_vsplit(self):
        # type: () -> None
        i32.by(4)  # Make sure i32x4 exists.
        i32.by(2)  # Make sure i32x2 exists.
        r = Rtl(
                (self.v0, self.v1) << vsplit.i32x4(self.v2),
        )
        r.cleanup_concrete_rtl()
        sem = elaborate(r)
        bvx = Var('bvx')
        bvlo = Var('bvlo')
        bvhi = Var('bvhi')
        x = Var('x')
        lo = Var('lo')
        hi = Var('hi')

        exp = Rtl(
            bvx << prim_to_bv.i32x4(x),
            (bvlo, bvhi) << bvsplit.bv128(bvx),
            lo << prim_from_bv.i32x2(bvlo),
            hi << prim_from_bv.i32x2(bvhi)
        )
        exp.cleanup_concrete_rtl()

        assert concrete_rtls_eq(sem, exp)
Exemplo n.º 9
0
    def test_elaborate_iadd_elaborate_1(self):
        # type: () -> None
        i32.by(2)  # Make sure i32x2 exists.
        r = Rtl(
                self.v0 << iadd.i32x2(self.v1, self.v2),
        )
        r.cleanup_concrete_rtl()
        sem = elaborate(r)
        x = Var('x')
        y = Var('y')
        a = Var('a')
        bvx_1 = Var('bvx_1')
        bvx_2 = Var('bvx_2')
        bvx_5 = Var('bvx_5')
        bvlo_1 = Var('bvlo_1')
        bvlo_2 = Var('bvlo_2')
        bvhi_1 = Var('bvhi_1')
        bvhi_2 = Var('bvhi_2')

        bva_3 = Var('bva_3')
        bva_4 = Var('bva_4')

        exp = Rtl(
            bvx_1 << prim_to_bv.i32x2(x),
            (bvlo_1, bvhi_1) << bvsplit.bv64(bvx_1),
            bvx_2 << prim_to_bv.i32x2(y),
            (bvlo_2, bvhi_2) << bvsplit.bv64(bvx_2),
            bva_3 << bvadd.bv32(bvlo_1, bvlo_2),
            bva_4 << bvadd.bv32(bvhi_1, bvhi_2),
            bvx_5 << bvconcat.bv32(bva_3, bva_4),
            a << prim_from_bv.i32x2(bvx_5)
        )
        exp.cleanup_concrete_rtl()

        assert concrete_rtls_eq(sem, exp)
Exemplo n.º 10
0
 def test_elaborate_iadd_cout_simple(self):
     # type: () -> None
     x = Var('x')
     y = Var('y')
     a = Var('a')
     c_out = Var('c_out')
     bvc_out = Var('bvc_out')
     bc_out = Var('bc_out')
     bvx = Var('bvx')
     bvy = Var('bvy')
     bva = Var('bva')
     bvone = Var('bvone')
     bvzero = Var('bvzero')
     r = Rtl(
             (a, c_out) << iadd_cout.i32(x, y),
     )
     r.cleanup_concrete_rtl()
     sem = elaborate(r)
     exp = Rtl(
         bvx << prim_to_bv.i32(x),
         bvy << prim_to_bv.i32(y),
         bva << bvadd.bv32(bvx, bvy),
         bc_out << bvult.bv32(bva, bvx),
         bvone << bv_from_imm64(imm64(1)),
         bvzero << bv_from_imm64(imm64(0)),
         bvc_out << bvite(bc_out, bvone, bvzero),
         a << prim_from_bv.i32(bva),
         c_out << prim_from_bv.b1(bvc_out)
     )
     exp.cleanup_concrete_rtl()
     assert concrete_rtls_eq(sem, exp)
Exemplo n.º 11
0
    def test_elaborate_vconcat(self):
        # type: () -> None
        i32.by(4)  # Make sure i32x4 exists.
        i32.by(2)  # Make sure i32x2 exists.
        r = Rtl(
                self.v0 << vconcat.i32x2(self.v1, self.v2),
        )
        r.cleanup_concrete_rtl()
        sem = elaborate(r)
        bvx = Var('bvx')
        bvlo = Var('bvlo')
        bvhi = Var('bvhi')
        x = Var('x')
        lo = Var('lo')
        hi = Var('hi')

        exp = Rtl(
            bvlo << prim_to_bv.i32x2(lo),
            bvhi << prim_to_bv.i32x2(hi),
            bvx << bvconcat.bv64(bvlo, bvhi),
            x << prim_from_bv.i32x4(bvx)
        )
        exp.cleanup_concrete_rtl()

        assert concrete_rtls_eq(sem, exp)
Exemplo n.º 12
0
    def test_cleanup_concrete_rtl_ireduce(self):
        # type: () -> None
        x = Var('x')
        y = Var('y')
        r = Rtl(
                y << ireduce(x),
        )
        r1 = r.copy({})
        s = r.substitution(r1, {})
        s[x].set_typevar(TypeVar.singleton(i8.by(2)))
        r1.cleanup_concrete_rtl()

        assert s is not None
        assert s[x].get_typevar().singleton_type() == i8.by(2)
        assert s[y].get_typevar().singleton_type() == i8.by(2)
Exemplo n.º 13
0
    def test_elaborate_iadd_elaborate_2(self):
        # type: () -> None
        i8.by(4)  # Make sure i32x2 exists.
        r = Rtl(
                self.v0 << iadd.i8x4(self.v1, self.v2),
        )
        r.cleanup_concrete_rtl()

        sem = elaborate(r)
        x = Var('x')
        y = Var('y')
        a = Var('a')
        bvx_1 = Var('bvx_1')
        bvx_2 = Var('bvx_2')
        bvx_5 = Var('bvx_5')
        bvx_10 = Var('bvx_10')
        bvx_15 = Var('bvx_15')

        bvlo_1 = Var('bvlo_1')
        bvlo_2 = Var('bvlo_2')
        bvlo_6 = Var('bvlo_6')
        bvlo_7 = Var('bvlo_7')
        bvlo_11 = Var('bvlo_11')
        bvlo_12 = Var('bvlo_12')

        bvhi_1 = Var('bvhi_1')
        bvhi_2 = Var('bvhi_2')
        bvhi_6 = Var('bvhi_6')
        bvhi_7 = Var('bvhi_7')
        bvhi_11 = Var('bvhi_11')
        bvhi_12 = Var('bvhi_12')

        bva_8 = Var('bva_8')
        bva_9 = Var('bva_9')
        bva_13 = Var('bva_13')
        bva_14 = Var('bva_14')

        exp = Rtl(
            bvx_1 << prim_to_bv.i8x4(x),
            (bvlo_1, bvhi_1) << bvsplit.bv32(bvx_1),
            bvx_2 << prim_to_bv.i8x4(y),
            (bvlo_2, bvhi_2) << bvsplit.bv32(bvx_2),
            (bvlo_6, bvhi_6) << bvsplit.bv16(bvlo_1),
            (bvlo_7, bvhi_7) << bvsplit.bv16(bvlo_2),
            bva_8 << bvadd.bv8(bvlo_6, bvlo_7),
            bva_9 << bvadd.bv8(bvhi_6, bvhi_7),
            bvx_10 << bvconcat.bv8(bva_8, bva_9),
            (bvlo_11, bvhi_11) << bvsplit.bv16(bvhi_1),
            (bvlo_12, bvhi_12) << bvsplit.bv16(bvhi_2),
            bva_13 << bvadd.bv8(bvlo_11, bvlo_12),
            bva_14 << bvadd.bv8(bvhi_11, bvhi_12),
            bvx_15 << bvconcat.bv8(bva_13, bva_14),
            bvx_5 << bvconcat.bv16(bvx_10, bvx_15),
            a << prim_from_bv.i8x4(bvx_5)
        )
        exp.cleanup_concrete_rtl()
        assert concrete_rtls_eq(sem, exp)
Exemplo n.º 14
0
    def test_cleanup_concrete_rtl(self):
        # type: () -> None
        typ = i64.by(4)
        x = Var('x')
        lo = Var('lo')
        hi = Var('hi')

        r = Rtl(
                (lo, hi) << vsplit(x),
        )
        r1 = r.copy({})
        s = r.substitution(r1, {})

        s[x].set_typevar(TypeVar.singleton(typ))
        r1.cleanup_concrete_rtl()
        assert s is not None
        assert s[x].get_typevar().singleton_type() == typ
        assert s[lo].get_typevar().singleton_type() == i64.by(2)
        assert s[hi].get_typevar().singleton_type() == i64.by(2)
def elaborate(r):
    # type: (Rtl) -> Rtl
    """
    Given a concrete Rtl r, return a semantically equivalent Rtl r1 containing
    only primitive instructions.
    """
    fp = False
    primitives = set(PRIMITIVES.instructions)
    idx = 0

    res = Rtl(*r.rtl)
    outputs = res.definitions()

    while not fp:
        assert res.is_concrete()
        new_defs = []  # type: List[Def]
        fp = True

        for d in res.rtl:
            inst = d.expr.inst

            if (inst not in primitives):
                t = find_matching_xform(d)
                transformed = t.apply(Rtl(d), str(idx))
                idx += 1
                new_defs.extend(transformed.rtl)
                fp = False
            else:
                new_defs.append(d)

        res.rtl = tuple(new_defs)

    return cleanup_semantics(res, outputs)
Exemplo n.º 16
0
    def test_vselect_imm(self):
        # type: () -> None
        ts = TypeSet(lanes=(2, 256), ints=True, floats=True, bools=(8, 64))
        r = Rtl(
            self.v0 << iconst(self.imm0),
            self.v1 << icmp(intcc.eq, self.v2, self.v0),
            self.v5 << vselect(self.v1, self.v3, self.v4),
        )
        x = XForm(r, r)
        tv2_exp = 'Some({}).map(|t: crate::ir::Type| t.as_bool())'\
            .format(self.v2.get_typevar().name)
        tv3_exp = 'Some({}).map(|t: crate::ir::Type| t.as_bool())'\
            .format(self.v3.get_typevar().name)

        self.check_yo_check(
            x,
            sequence(typeset_check(self.v3, ts), equiv_check(tv2_exp,
                                                             tv3_exp)))
Exemplo n.º 17
0
    def test_demote_promote(self):
        # type: () -> None
        r = Rtl(
            self.v1 << fpromote(self.v0),
            self.v2 << fdemote(self.v1),
            self.v3 << fpromote(self.v2),
        )
        x = XForm(r, r)

        tv0_exp = 'Some({})'.format(self.v0.get_typevar().name)
        tv1_exp = 'Some({})'.format(self.v1.get_typevar().name)
        tv2_exp = 'Some({})'.format(self.v2.get_typevar().name)
        tv3_exp = 'Some({})'.format(self.v3.get_typevar().name)

        self.check_yo_check(
            x,
            sequence(wider_check(tv1_exp, tv0_exp),
                     wider_check(tv1_exp, tv2_exp),
                     wider_check(tv3_exp, tv2_exp)))
Exemplo n.º 18
0
    def test_elaborate_iadd_simple(self):
        # type: () -> None
        i32.by(2)  # Make sure i32x2 exists.
        x = Var('x')
        y = Var('y')
        a = Var('a')
        bvx = Var('bvx')
        bvy = Var('bvy')
        bva = Var('bva')
        r = Rtl(
                a << iadd.i32(x, y),
        )
        r.cleanup_concrete_rtl()
        sem = elaborate(r)
        exp = Rtl(
            bvx << prim_to_bv.i32(x),
            bvy << prim_to_bv.i32(y),
            bva << bvadd.bv32(bvx, bvy),
            a << prim_from_bv.i32(bva)
        )
        exp.cleanup_concrete_rtl()

        assert concrete_rtls_eq(sem, exp)
Exemplo n.º 19
0
xl = Var('xl')
xh = Var('xh')
yl = Var('yl')
yh = Var('yh')
al = Var('al')
ah = Var('ah')
cc = Var('cc')
ptr = Var('ptr')
flags = Var('flags')
offset = Var('off')
ss = Var('ss')

narrow.legalize(
    a << iadd(x, y),
    Rtl((xl, xh) << isplit(x), (yl, yh) << isplit(y),
        (al, c) << iadd_cout(xl, yl), ah << iadd_cin(xh, yh, c),
        a << iconcat(al, ah)))

narrow.legalize(
    a << isub(x, y),
    Rtl((xl, xh) << isplit(x), (yl, yh) << isplit(y),
        (al, b) << isub_bout(xl, yl), ah << isub_bin(xh, yh, b),
        a << iconcat(al, ah)))

for bitop in [band, bor, bxor]:
    narrow.legalize(
        a << bitop(x, y),
        Rtl((xl, xh) << isplit(x), (yl, yh) << isplit(y), al << bitop(xl, yl),
            ah << bitop(xh, yh), a << iconcat(al, ah)))

narrow.legalize(
Exemplo n.º 20
0
                          chain=shared.expand)

a = Var('a')
dead = Var('dead')
x = Var('x')
xhi = Var('xhi')
y = Var('y')
a1 = Var('a1')
a2 = Var('a2')

#
# Division and remainder.
#
intel_expand.legalize(
    a << insts.udiv(x, y),
    Rtl(xhi << insts.iconst(imm64(0)), (a, dead) << x86.udivmodx(x, xhi, y)))

intel_expand.legalize(
    a << insts.urem(x, y),
    Rtl(xhi << insts.iconst(imm64(0)), (dead, a) << x86.udivmodx(x, xhi, y)))

for ty in [i32, i64]:
    intel_expand.legalize(
        a << insts.sdiv.bind(ty)(x, y),
        Rtl(xhi << insts.sshr_imm(x, imm64(ty.lane_bits() - 1)),
            (a, dead) << x86.sdivmodx(x, xhi, y)))

# The srem expansion requires custom code because srem INT_MIN, -1 is not
# allowed to trap.
intel_expand.custom_legalize(insts.srem, 'expand_srem')
Exemplo n.º 21
0
yl = Var('yl')
yh = Var('yh')
al = Var('al')
ah = Var('ah')
cc = Var('cc')
ptr = Var('ptr')
flags = Var('flags')
offset = Var('off')
ss = Var('ss')

narrow.legalize(
        a << iadd(x, y),
        Rtl(
            (xl, xh) << isplit(x),
            (yl, yh) << isplit(y),
            (al, c) << iadd_cout(xl, yl),
            ah << iadd_cin(xh, yh, c),
            a << iconcat(al, ah)
        ))

narrow.legalize(
        a << isub(x, y),
        Rtl(
            (xl, xh) << isplit(x),
            (yl, yh) << isplit(y),
            (al, b) << isub_bout(xl, yl),
            ah << isub_bin(xh, yh, b),
            a << iconcat(al, ah)
        ))

for bitop in [band, bor, bxor]:
Exemplo n.º 22
0
c1 = Var('c1')
c2 = Var('c2')
c_in = Var('c_in')
c_int = Var('c_int')
xl = Var('xl')
xh = Var('xh')
yl = Var('yl')
yh = Var('yh')
al = Var('al')
ah = Var('ah')
cc = Var('cc')

narrow.legalize(
    a << iadd(x, y),
    Rtl((xl, xh) << isplit(x), (yl, yh) << isplit(y),
        (al, c) << iadd_cout(xl, yl), ah << iadd_cin(xh, yh, c),
        a << iconcat(al, ah)))

narrow.legalize(
    a << isub(x, y),
    Rtl((xl, xh) << isplit(x), (yl, yh) << isplit(y),
        (al, b) << isub_bout(xl, yl), ah << isub_bin(xh, yh, b),
        a << iconcat(al, ah)))

for bitop in [band, bor, bxor]:
    narrow.legalize(
        a << bitop(x, y),
        Rtl((xl, xh) << isplit(x), (yl, yh) << isplit(y), al << bitop(xl, yl),
            ah << bitop(xh, yh), a << iconcat(al, ah)))

narrow.legalize(
import base.formats  # noqa

GROUP = InstructionGroup("primitive_macros", "Semantic macros instruction set")
AnyBV = TypeVar('AnyBV', bitvecs=True, doc="")
x = Var('x')
y = Var('y')
imm = Var('imm')
a = Var('a')

#
# Bool-to-bv1
#
BV1 = TypeVar("BV1", bitvecs=(1, 1), doc="")
bv1_op = Operand('bv1_op', BV1, doc="")
cond_op = Operand("cond", b1, doc="")
bool2bv = Instruction('bool2bv',
                      r"""Convert a b1 value to a 1-bit BV""",
                      ins=cond_op,
                      outs=bv1_op)

v1 = Var('v1')
v2 = Var('v2')
bvone = Var('bvone')
bvzero = Var('bvzero')
bool2bv.set_semantics(
    v1 << bool2bv(v2),
    Rtl(bvone << bv_from_imm64(imm64(1)), bvzero << bv_from_imm64(imm64(0)),
        v1 << bvite(v2, bvone, bvzero)))

GROUP.close()
Exemplo n.º 24
0
c1 = Var('c1')
c2 = Var('c2')
c_in = Var('c_in')
xl = Var('xl')
xh = Var('xh')
yl = Var('yl')
yh = Var('yh')
al = Var('al')
ah = Var('ah')

narrow.legalize(
        a << iadd(x, y),
        Rtl(
            (xl, xh) << isplit(x),
            (yl, yh) << isplit(y),
            (al, c) << iadd_cout(xl, yl),
            ah << iadd_cin(xh, yh, c),
            a << iconcat(al, ah)
        ))

narrow.legalize(
        a << isub(x, y),
        Rtl(
            (xl, xh) << isplit(x),
            (yl, yh) << isplit(y),
            (al, b) << isub_bout(xl, yl),
            ah << isub_bin(xh, yh, b),
            a << iconcat(al, ah)
        ))

for bitop in [band, bor, bxor]:
# Division and remainder.
#
# The srem expansion requires custom code because srem INT_MIN, -1 is not
# allowed to trap. The other ops need to check avoid_div_traps.
x86_expand.custom_legalize(insts.sdiv, 'expand_sdivrem')
x86_expand.custom_legalize(insts.srem, 'expand_sdivrem')
x86_expand.custom_legalize(insts.udiv, 'expand_udivrem')
x86_expand.custom_legalize(insts.urem, 'expand_udivrem')

#
# Double length (widening) multiplication
#
resLo = Var('resLo')
resHi = Var('resHi')
x86_expand.legalize(resHi << insts.umulhi(x, y),
                    Rtl((resLo, resHi) << x86.umulx(x, y)))

x86_expand.legalize(resHi << insts.smulhi(x, y),
                    Rtl((resLo, resHi) << x86.smulx(x, y)))

# Floating point condition codes.
#
# The 8 condition codes in `supported_floatccs` are directly supported by a
# `ucomiss` or `ucomisd` instruction. The remaining codes need legalization
# patterns.

# Equality needs an explicit `ord` test which checks the parity bit.
x86_expand.legalize(
    a << insts.fcmp(floatcc.eq, x, y),
    Rtl(a1 << insts.fcmp(floatcc.ord, x, y),
        a2 << insts.fcmp(floatcc.ueq, x, y), a << insts.band(a1, a2)))
def cleanup_semantics(r, outputs):
    # type: (Rtl, Set[Var]) -> Rtl
    """
    The elaboration process creates a lot of redundant prim_to_bv conversions.
    Cleanup the following cases:

    1) prim_to_bv/prim_from_bv pair:
        a.0 << prim_from_bv(bva.0)
        ...
        bva.1 << prim_to_bv(a.0)  <-- redundant, replace by bva.0
        ...

    2) prim_to_bv/prim_to-bv pair:
        bva.0 << prim_to_bv(a)
        ...
        bva.1 << prim_to_bv(a) <-- redundant, replace by bva.0
        ...
    """
    new_defs = []  # type: List[Def]
    subst_m = {v: v for v in r.vars()}  # type: VarAtomMap
    definition = {}  # type: Dict[Var, Def]
    prim_to_bv_map = {}  # type: Dict[Var, Def]

    # Pass 1: Remove redundant prim_to_bv
    for d in r.rtl:
        inst = d.expr.inst

        if (inst == prim_to_bv):
            arg = d.expr.args[0]
            df = d.defs[0]
            assert isinstance(arg, Var)

            if arg in definition:
                def_loc = definition[arg]
                if def_loc.expr.inst == prim_from_bv:
                    assert isinstance(def_loc.expr.args[0], Var)
                    subst_m[df] = def_loc.expr.args[0]
                    continue

            if arg in prim_to_bv_map:
                subst_m[df] = prim_to_bv_map[arg].defs[0]
                continue

            prim_to_bv_map[arg] = d

        new_def = d.copy(subst_m)

        for v in new_def.defs:
            assert v not in definition  # Guaranteed by SSA
            definition[v] = new_def

        new_defs.append(new_def)

    # Pass 2: Remove dead prim_from_bv
    live = set(outputs)  # type: Set[Var]
    for d in new_defs:
        live = live.union(d.uses())

    new_defs = [
        d for d in new_defs
        if not (d.expr.inst == prim_from_bv and d.defs[0] not in live)
    ]

    return Rtl(*new_defs)