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)
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)
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))
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()
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()
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))
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)))
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)
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)
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)
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)
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)
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)
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)
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)))
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)))
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)
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(
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')
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]:
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()
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)