Added bitrev instruction for 32 and 64 bit integers (#486)

This commit is contained in:
Aaron Power
2018-09-05 00:23:50 +01:00
committed by Dan Gohman
parent 7e571f4a49
commit 17bb62c16c
4 changed files with 293 additions and 4 deletions

View File

@@ -0,0 +1,149 @@
test legalizer
target x86_64
function %reverse_bits_8(i8) -> i8 {
ebb0(v0: i8):
v1 = bitrev.i8 v0
return v1
}
; check: v2 = band_imm v0, 170
; check: v3 = ushr_imm v2, 1
; check: v4 = band_imm v0, 85
; check: v5 = ishl_imm v4, 1
; check: v16 = uextend.i32 v3
; check: v17 = uextend.i32 v5
; check: v18 = bor v16, v17
; check: v6 = ireduce.i8 v18
; check: v7 = band_imm v6, 204
; check: v8 = ushr_imm v7, 2
; check: v9 = band_imm v6, 51
; check: v10 = ushr_imm v9, 2
; check: v19 = uextend.i32 v8
; check: v20 = uextend.i32 v10
; check: v21 = bor v19, v20
; check: v11 = ireduce.i8 v21
; check: v12 = band_imm v11, 240
; check: v13 = ushr_imm v12, 4
; check: v14 = band_imm v11, 15
; check: v15 = ishl_imm v14, 4
; check: v22 = uextend.i32 v13
; check: v23 = uextend.i32 v15
; check: v24 = bor v22, v23
; check: v1 = ireduce.i8 v24
function %reverse_bits_16(i16) -> i16 {
ebb0(v0: i16):
v1 = bitrev.i16 v0
return v1
}
; check: v2 = band_imm v0, 0xaaaa
; check: v3 = ushr_imm v2, 1
; check: v4 = band_imm v0, 0x5555
; check: v5 = ishl_imm v4, 1
; check: v21 = uextend.i32 v3
; check: v22 = uextend.i32 v5
; check: v23 = bor v21, v22
; check: v6 = ireduce.i16 v23
; check: v7 = band_imm v6, 0xcccc
; check: v8 = ushr_imm v7, 2
; check: v9 = band_imm v6, 0x3333
; check: v10 = ushr_imm v9, 2
; check: v24 = uextend.i32 v8
; check: v25 = uextend.i32 v10
; check: v26 = bor v24, v25
; check: v11 = ireduce.i16 v26
; check: v12 = band_imm v11, 0xf0f0
; check: v13 = ushr_imm v12, 4
; check: v14 = band_imm v11, 3855
; check: v15 = ishl_imm v14, 4
; check: v27 = uextend.i32 v13
; check: v28 = uextend.i32 v15
; check: v29 = bor v27, v28
; check: v16 = ireduce.i16 v29
; check: v17 = band_imm v16, 0xff00
; check: v18 = ushr_imm v17, 8
; check: v19 = band_imm v16, 255
; check: v20 = ishl_imm v19, 8
; check: v30 = uextend.i32 v18
; check: v31 = uextend.i32 v20
; check: v32 = bor v30, v31
; check: v1 = ireduce.i16 v32
; check: return v1
function %reverse_bits_32(i32) -> i32 {
ebb0(v0: i32):
v1 = bitrev.i32 v0
return v1
}
; check: v24 = iconst.i32 0xaaaa_aaaa
; check: v2 = band v0, v24
; check: v3 = ushr_imm v2, 1
; check: v4 = band_imm v0, 0x5555_5555
; check: v5 = ishl_imm v4, 1
; check: v6 = bor v3, v5
; check: v25 = iconst.i32 0xcccc_cccc
; check: v7 = band v6, v25
; check: v8 = ushr_imm v7, 2
; check: v9 = band_imm v6, 0x3333_3333
; check: v10 = ushr_imm v9, 2
; check: v11 = bor v8, v10
; check: v26 = iconst.i32 0xf0f0_f0f0
; check: v12 = band v11, v26
; check: v13 = ushr_imm v12, 4
; check: v14 = band_imm v11, 0x0f0f_0f0f
; check: v15 = ishl_imm v14, 4
; check: v16 = bor v13, v15
; check: v27 = iconst.i32 0xff00_ff00
; check: v17 = band v16, v27
; check: v18 = ushr_imm v17, 8
; check: v19 = band_imm v16, 0x00ff_00ff
; check: v20 = ishl_imm v19, 8
; check: v21 = bor v18, v20
; check: v22 = ushr_imm v21, 16
; check: v23 = ishl_imm v21, 16
; check: v1 = bor v22, v23
function %reverse_bits_64(i64) -> i64 {
ebb0(v0: i64):
v1 = bitrev.i64 v0
return v1
}
; check: v29 = iconst.i64 0xaaaa_aaaa_aaaa_aaaa
; check: v2 = band v0, v29
; check: v3 = ushr_imm v2, 1
; check: v30 = iconst.i64 0x5555_5555_5555_5555
; check: v4 = band v0, v30
; check: v5 = ishl_imm v4, 1
; check: v6 = bor v3, v5
; check: v31 = iconst.i64 0xcccc_cccc_cccc_cccc
; check: v7 = band v6, v31
; check: v8 = ushr_imm v7, 2
; check: v32 = iconst.i64 0x3333_3333_3333_3333
; check: v9 = band v6, v32
; check: v10 = ushr_imm v9, 2
; check: v11 = bor v8, v10
; check: v33 = iconst.i64 0xf0f0_f0f0_f0f0_f0f0
; check: v12 = band v11, v33
; check: v13 = ushr_imm v12, 4
; check: v34 = iconst.i64 0x0f0f_0f0f_0f0f_0f0f
; check: v14 = band v11, v34
; check: v15 = ishl_imm v14, 4
; check: v16 = bor v13, v15
; check: v35 = iconst.i64 0xff00_ff00_ff00_ff00
; check: v17 = band v16, v35
; check: v18 = ushr_imm v17, 8
; check: v36 = iconst.i64 0x00ff_00ff_00ff_00ff
; check: v19 = band v16, v36
; check: v20 = ishl_imm v19, 8
; check: v21 = bor v18, v20
; check: v37 = iconst.i64 0xffff_0000_ffff_0000
; check: v22 = band v21, v37
; check: v23 = ushr_imm v22, 16
; check: v38 = iconst.i64 0xffff_0000_ffff
; check: v24 = band v21, v38
; check: v25 = ishl_imm v24, 16
; check: v26 = bor v23, v25
; check: v27 = ushr_imm v26, 32
; check: v28 = ishl_imm v26, 32
; check: v1 = bor v27, v28

View File

@@ -1409,6 +1409,14 @@ sshr_imm = Instruction(
x = Operand('x', iB) x = Operand('x', iB)
a = Operand('a', iB) a = Operand('a', iB)
bitrev = Instruction(
'bitrev', r"""
Reverse the bits of a integer.
Reverses the bits in ``x``.
""",
ins=x, outs=a)
clz = Instruction( clz = Instruction(
'clz', r""" 'clz', r"""
Count leading zero bits. Count leading zero bits.

View File

@@ -26,6 +26,7 @@ from .instructions import rotl, rotl_imm, rotr, rotr_imm
from .instructions import f32const, f64const from .instructions import f32const, f64const
from .instructions import store, load from .instructions import store, load
from .instructions import br_table from .instructions import br_table
from .instructions import bitrev
from cdsl.ast import Var from cdsl.ast import Var
from cdsl.xform import Rtl, XFormGroup from cdsl.xform import Rtl, XFormGroup
@@ -91,17 +92,35 @@ y = Var('y')
a = Var('a') a = Var('a')
a1 = Var('a1') a1 = Var('a1')
a2 = Var('a2') a2 = Var('a2')
a3 = Var('a3')
a4 = Var('a4')
b = Var('b') b = Var('b')
b1 = Var('b1') b1 = Var('b1')
b2 = Var('b2') b2 = Var('b2')
b3 = Var('b3')
b4 = Var('b4')
b_in = Var('b_in') b_in = Var('b_in')
b_int = Var('b_int') b_int = Var('b_int')
c = Var('c') c = Var('c')
c1 = Var('c1') c1 = Var('c1')
c2 = Var('c2') c2 = Var('c2')
c3 = Var('c3')
c4 = Var('c4')
c_in = Var('c_in') c_in = Var('c_in')
c_int = Var('c_int') c_int = Var('c_int')
d = Var('d') d = Var('d')
d1 = Var('d1')
d2 = Var('d2')
d3 = Var('d3')
d4 = Var('d4')
e = Var('e')
e1 = Var('e1')
e2 = Var('e2')
e3 = Var('e3')
e4 = Var('e4')
f = Var('f')
f1 = Var('f1')
f2 = Var('f2')
xl = Var('xl') xl = Var('xl')
xh = Var('xh') xh = Var('xh')
yl = Var('yl') yl = Var('yl')
@@ -382,6 +401,115 @@ expand.legalize(
a << bxor(x, y) a << bxor(x, y)
)) ))
# Expand bitrev
# Adapted from Stack Overflow.
# https://stackoverflow.com/questions/746171/most-efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
widen.legalize(
a << bitrev.i8(x),
Rtl(
a1 << band_imm(x, imm64(0xaa)),
a2 << ushr_imm(a1, imm64(1)),
a3 << band_imm(x, imm64(0x55)),
a4 << ishl_imm(a3, imm64(1)),
b << bor(a2, a4),
b1 << band_imm(b, imm64(0xcc)),
b2 << ushr_imm(b1, imm64(2)),
b3 << band_imm(b, imm64(0x33)),
b4 << ushr_imm(b3, imm64(2)),
c << bor(b2, b4),
c1 << band_imm(c, imm64(0xf0)),
c2 << ushr_imm(c1, imm64(4)),
c3 << band_imm(c, imm64(0x0f)),
c4 << ishl_imm(c3, imm64(4)),
a << bor(c2, c4),
))
widen.legalize(
a << bitrev.i16(x),
Rtl(
a1 << band_imm(x, imm64(0xaaaa)),
a2 << ushr_imm(a1, imm64(1)),
a3 << band_imm(x, imm64(0x5555)),
a4 << ishl_imm(a3, imm64(1)),
b << bor(a2, a4),
b1 << band_imm(b, imm64(0xcccc)),
b2 << ushr_imm(b1, imm64(2)),
b3 << band_imm(b, imm64(0x3333)),
b4 << ushr_imm(b3, imm64(2)),
c << bor(b2, b4),
c1 << band_imm(c, imm64(0xf0f0)),
c2 << ushr_imm(c1, imm64(4)),
c3 << band_imm(c, imm64(0x0f0f)),
c4 << ishl_imm(c3, imm64(4)),
d << bor(c2, c4),
d1 << band_imm(d, imm64(0xff00)),
d2 << ushr_imm(d1, imm64(8)),
d3 << band_imm(d, imm64(0x00ff)),
d4 << ishl_imm(d3, imm64(8)),
a << bor(d2, d4),
))
expand.legalize(
a << bitrev.i32(x),
Rtl(
a1 << band_imm(x, imm64(0xaaaaaaaa)),
a2 << ushr_imm(a1, imm64(1)),
a3 << band_imm(x, imm64(0x55555555)),
a4 << ishl_imm(a3, imm64(1)),
b << bor(a2, a4),
b1 << band_imm(b, imm64(0xcccccccc)),
b2 << ushr_imm(b1, imm64(2)),
b3 << band_imm(b, imm64(0x33333333)),
b4 << ushr_imm(b3, imm64(2)),
c << bor(b2, b4),
c1 << band_imm(c, imm64(0xf0f0f0f0)),
c2 << ushr_imm(c1, imm64(4)),
c3 << band_imm(c, imm64(0x0f0f0f0f)),
c4 << ishl_imm(c3, imm64(4)),
d << bor(c2, c4),
d1 << band_imm(d, imm64(0xff00ff00)),
d2 << ushr_imm(d1, imm64(8)),
d3 << band_imm(d, imm64(0x00ff00ff)),
d4 << ishl_imm(d3, imm64(8)),
e << bor(d2, d4),
e1 << ushr_imm(e, imm64(16)),
e2 << ishl_imm(e, imm64(16)),
a << bor(e1, e2),
))
expand.legalize(
a << bitrev.i64(x),
Rtl(
a1 << band_imm(x, imm64(0xaaaaaaaaaaaaaaaa)),
a2 << ushr_imm(a1, imm64(1)),
a3 << band_imm(x, imm64(0x5555555555555555)),
a4 << ishl_imm(a3, imm64(1)),
b << bor(a2, a4),
b1 << band_imm(b, imm64(0xcccccccccccccccc)),
b2 << ushr_imm(b1, imm64(2)),
b3 << band_imm(b, imm64(0x3333333333333333)),
b4 << ushr_imm(b3, imm64(2)),
c << bor(b2, b4),
c1 << band_imm(c, imm64(0xf0f0f0f0f0f0f0f0)),
c2 << ushr_imm(c1, imm64(4)),
c3 << band_imm(c, imm64(0x0f0f0f0f0f0f0f0f)),
c4 << ishl_imm(c3, imm64(4)),
d << bor(c2, c4),
d1 << band_imm(d, imm64(0xff00ff00ff00ff00)),
d2 << ushr_imm(d1, imm64(8)),
d3 << band_imm(d, imm64(0x00ff00ff00ff00ff)),
d4 << ishl_imm(d3, imm64(8)),
e << bor(d2, d4),
e1 << band_imm(e, imm64(0xffff0000ffff0000)),
e2 << ushr_imm(e1, imm64(16)),
e3 << band_imm(e, imm64(0x0000ffff0000ffff)),
e4 << ishl_imm(e3, imm64(16)),
f << bor(e2, e4),
f1 << ushr_imm(f, imm64(32)),
f2 << ishl_imm(f, imm64(32)),
a << bor(f1, f2),
))
# Floating-point sign manipulations. # Floating-point sign manipulations.
for ty, minus_zero in [ for ty, minus_zero in [
(types.f32, f32const(ieee32.bits(0x80000000))), (types.f32, f32const(ieee32.bits(0x80000000))),

View File

@@ -523,10 +523,14 @@ class ConstantInt(Literal):
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str
""" # If the value is in the signed imm64 range, print it as-is.
Get the Rust expression form of this constant. if self.value >= -(2**63) and self.value < (2**63):
"""
return str(self.value) return str(self.value)
# Otherwise if the value is in the unsigned imm64 range, print its
# bitwise counterpart in the signed imm64 range.
if self.value >= (2**63) and self.value < (2**64):
return str(self.value - (2**64))
assert False, "immediate value not in signed or unsigned imm64 range"
class ConstantBits(Literal): class ConstantBits(Literal):