mplemented code-generation for bit counting instructions

This commit is contained in:
Dmitry Stogov 2023-11-16 22:48:05 +03:00
parent 92ef948caf
commit 688f876928
10 changed files with 551 additions and 24 deletions

1
ir.h
View File

@ -840,6 +840,7 @@ int ir_patch(const void *code, size_t size, uint32_t jmp_table_size, const void
# define IR_X86_SSE42 (1<<4)
# define IR_X86_AVX (1<<5)
# define IR_X86_AVX2 (1<<6)
# define IR_X86_BMI1 (1<<7)
#endif
uint32_t ir_cpuinfo(void);

View File

@ -655,6 +655,8 @@ binop_fp:
return IR_BINOP_INT;
case IR_BSWAP:
case IR_NOT:
case IR_CTLZ:
case IR_CTTZ:
IR_ASSERT(IR_IS_TYPE_INT(insn->type));
return IR_OP_INT;
case IR_NEG:
@ -1880,6 +1882,21 @@ static void ir_emit_op_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
| cmp Rw(op1_reg), #0
| cneg Rw(def_reg), Rw(op1_reg), lt
}
} else if (insn->op == IR_CTLZ) {
if (ir_type_size[type] == 1) {
| and Rw(def_reg), Rw(op1_reg), #0xff
| clz Rw(def_reg), Rw(def_reg)
| sub Rw(def_reg), Rw(def_reg), #24
} else if (ir_type_size[type] == 2) {
| and Rw(def_reg), Rw(op1_reg), #0xffff
| clz Rw(def_reg), Rw(def_reg)
| sub Rw(def_reg), Rw(def_reg), #16
} else {
| ASM_REG_REG_OP clz, type, def_reg, op1_reg
}
} else if (insn->op == IR_CTTZ) {
| ASM_REG_REG_OP rbit, insn->type, def_reg, op1_reg
| ASM_REG_REG_OP clz, insn->type, def_reg, def_reg
} else {
IR_ASSERT(insn->op == IR_BSWAP);
| ASM_REG_REG_OP rev, insn->type, def_reg, op1_reg
@ -1911,14 +1928,14 @@ static void ir_emit_ctpop(ir_ctx *ctx, ir_ref def, ir_insn *insn)
default:
IR_ASSERT(0);
case 1:
| and Rw(def_reg-IR_REG_FP_FIRST), Rw(op1_reg), #0xff
| and Rw(def_reg), Rw(op1_reg), #0xff
| fmov Rs(tmp_reg-IR_REG_FP_FIRST), Rw(def_reg)
| .long code1 // cnt v0.8b, v0.8b
| .long code2 // addv b0, v0.8b
| fmov Rw(def_reg), Rs(tmp_reg-IR_REG_FP_FIRST)
break;
case 2:
| and Rw(def_reg-IR_REG_FP_FIRST), Rw(op1_reg), #0xffff
| and Rw(def_reg), Rw(op1_reg), #0xffff
| fmov Rs(tmp_reg-IR_REG_FP_FIRST), Rw(def_reg)
| .long code1 // cnt v0.8b, v0.8b
| .long code2 // addv b0, v0.8b

View File

@ -46,6 +46,7 @@ uint32_t ir_cpuinfo(void)
ir_cpuid_ex(info_0x7_0, 0x7, 0);
if (bit(info_0x7_0[1], 5U)) ret |= IR_X86_AVX2;
if (bit(info_0x7_0[1], 3U)) ret |= IR_X86_BMI1;
#undef bit

View File

@ -27,7 +27,7 @@ static void help(const char *cmd)
" -S - dump final target assembler code\n"
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
" -mavx - use AVX instruction set\n"
" -mno-sse41 - disable SSE 4.1 instruction set\n"
" -mno-bmi1 - disable BMI1 instruction set\n"
#endif
" -muse-fp - use base frame pointer register\n"
" --emit-c [file-name] - convert to C source\n"
@ -740,8 +740,8 @@ int main(int argc, char **argv)
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
} else if (strcmp(argv[i], "-mavx") == 0) {
mflags |= IR_X86_AVX;
} else if (strcmp(argv[i], "-mno-sse41") == 0) {
mflags_disabled |= IR_X86_SSE41;
} else if (strcmp(argv[i], "-mno-bmi1") == 0) {
mflags_disabled |= IR_X86_BMI1;
#endif
} else if (strcmp(argv[i], "-muse-fp") == 0) {
flags |= IR_USE_FRAME_POINTER;
@ -819,8 +819,8 @@ int main(int argc, char **argv)
fprintf(stderr, "ERROR: -mavx is not compatible with CPU (AVX is not supported)\n");
return 1;
}
if ((cpuinfo & IR_X86_SSE41) && !(mflags_disabled & IR_X86_SSE41)) {
mflags |= IR_X86_SSE41;
if ((cpuinfo & IR_X86_BMI1) && !(mflags_disabled & IR_X86_BMI1)) {
mflags |= IR_X86_BMI1;
}
#endif

View File

@ -547,7 +547,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
_(RETURN_VOID) \
_(RETURN_INT) \
_(RETURN_FP) \
_(CTPOP_POPCNT) \
_(BIT_COUNT) \
#define IR_RULE_ENUM(name) IR_ ## name,
@ -804,7 +804,7 @@ op2_const:
case IR_OP_FP:
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
break;
case IR_CTPOP_POPCNT:
case IR_BIT_COUNT:
insn = &ctx->ir_base[ref];
if (ir_type_size[insn->type] == 1) {
flags = IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG;
@ -1913,9 +1913,13 @@ store_int:
case IR_FP2FP:
ir_match_fuse_load(ctx, insn->op1, ref);
return insn->op;
case IR_CTLZ:
case IR_CTTZ:
ir_match_fuse_load(ctx, insn->op1, ref);
return IR_BIT_COUNT;
case IR_CTPOP:
ir_match_fuse_load(ctx, insn->op1, ref);
return (ctx->mflags & IR_X86_SSE41) ? IR_CTPOP_POPCNT : IR_CTPOP;
return (ctx->mflags & IR_X86_BMI1) ? IR_BIT_COUNT : IR_CTPOP;
default:
break;
}
@ -3181,7 +3185,7 @@ static void ir_emit_op_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
}
}
static void ir_emit_ctpop_popcnt(ir_ctx *ctx, ir_ref def, ir_insn *insn)
static void ir_emit_bit_count(ir_ctx *ctx, ir_ref def, ir_insn *insn)
{
ir_backend_data *data = ctx->data;
dasm_State **Dst = &data->dasm_state;
@ -3201,17 +3205,75 @@ static void ir_emit_ctpop_popcnt(ir_ctx *ctx, ir_ref def, ir_insn *insn)
default:
IR_ASSERT(0);
case 2:
| popcnt Rw(def_reg), Rw(op1_reg)
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rw(def_reg), Rw(op1_reg)
} else {
| bsr Rw(def_reg), Rw(op1_reg)
| xor Rw(def_reg), 0xf
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rw(def_reg), Rw(op1_reg)
} else {
| bsf Rw(def_reg), Rw(op1_reg)
}
} else {
IR_ASSERT(insn->op == IR_CTPOP);
| popcnt Rw(def_reg), Rw(op1_reg)
}
break;
case 1:
| movzx Rd(op1_reg), Rb(op1_reg)
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rd(def_reg), Rd(op1_reg)
| sub Rd(def_reg), 24
} else {
| bsr Rd(def_reg), Rd(op1_reg)
| xor Rw(def_reg), 0x7
}
break;
}
IR_FALLTHROUGH;
case 4:
| popcnt Rd(def_reg), Rd(op1_reg)
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rd(def_reg), Rd(op1_reg)
} else {
| bsr Rd(def_reg), Rd(op1_reg)
| xor Rw(def_reg), 0x1f
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rd(def_reg), Rd(op1_reg)
} else {
| bsf Rd(def_reg), Rd(op1_reg)
}
} else {
IR_ASSERT(insn->op == IR_CTPOP);
| popcnt Rd(def_reg), Rd(op1_reg)
}
break;
|.if X64
case 8:
| popcnt Rq(def_reg), Rq(op1_reg)
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rq(def_reg), Rq(op1_reg)
} else {
| bsr Rq(def_reg), Rq(op1_reg)
| xor Rw(def_reg), 0x3f
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rq(def_reg), Rq(op1_reg)
} else {
| bsf Rq(def_reg), Rq(op1_reg)
}
} else {
IR_ASSERT(insn->op == IR_CTPOP);
| popcnt Rq(def_reg), Rq(op1_reg)
}
break;
|.endif
}
@ -3228,14 +3290,59 @@ static void ir_emit_ctpop_popcnt(ir_ctx *ctx, ir_ref def, ir_insn *insn)
default:
IR_ASSERT(0);
case 2:
| popcnt Rw(def_reg), word [Ra(op1_reg)+offset]
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rw(def_reg), word [Ra(op1_reg)+offset]
} else {
| bsr Rw(def_reg), word [Ra(op1_reg)+offset]
| xor Rw(def_reg), 0xf
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rw(def_reg), word [Ra(op1_reg)+offset]
} else {
| bsf Rw(def_reg), word [Ra(op1_reg)+offset]
}
} else {
| popcnt Rw(def_reg), word [Ra(op1_reg)+offset]
}
break;
case 4:
| popcnt Rd(def_reg), dword [Ra(op1_reg)+offset]
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rd(def_reg), dword [Ra(op1_reg)+offset]
} else {
| bsr Rd(def_reg), dword [Ra(op1_reg)+offset]
| xor Rw(def_reg), 0x1f
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rd(def_reg), dword [Ra(op1_reg)+offset]
} else {
| bsf Rd(def_reg), dword [Ra(op1_reg)+offset]
}
} else {
| popcnt Rd(def_reg), dword [Ra(op1_reg)+offset]
}
break;
|.if X64
case 8:
| popcnt Rq(def_reg), qword [Ra(op1_reg)+offset]
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rq(def_reg), qword [Ra(op1_reg)+offset]
} else {
| bsr Rq(def_reg), qword [Ra(op1_reg)+offset]
| xor Rw(def_reg), 0x3f
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rq(def_reg), qword [Ra(op1_reg)+offset]
} else {
| bsf Rq(def_reg), qword [Ra(op1_reg)+offset]
}
} else {
| popcnt Rq(def_reg), qword [Ra(op1_reg)+offset]
}
break;
|.endif
}
@ -3244,14 +3351,59 @@ static void ir_emit_ctpop_popcnt(ir_ctx *ctx, ir_ref def, ir_insn *insn)
default:
IR_ASSERT(0);
case 2:
| popcnt Rw(def_reg), word [offset]
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rw(def_reg), word [offset]
} else {
| bsr Rw(def_reg), word [offset]
| xor Rw(def_reg), 0xf
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rw(def_reg), word [offset]
} else {
| bsf Rw(def_reg), word [offset]
}
} else {
| popcnt Rw(def_reg), word [offset]
}
break;
case 4:
| popcnt Rd(def_reg), dword [offset]
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rd(def_reg), dword [offset]
} else {
| bsr Rw(def_reg), word [offset]
| xor Rw(def_reg), 0x1f
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rd(def_reg), dword [offset]
} else {
| bsf Rd(def_reg), dword [offset]
}
} else {
| popcnt Rd(def_reg), dword [offset]
}
break;
|.if X64
case 8:
| popcnt Rq(def_reg), qword [offset]
if (insn->op == IR_CTLZ) {
if (ctx->mflags & IR_X86_BMI1) {
| lzcnt Rq(def_reg), qword [offset]
} else {
| bsr Rw(def_reg), word [offset]
| xor Rw(def_reg), 0x1f
}
} else if (insn->op == IR_CTTZ) {
if (ctx->mflags & IR_X86_BMI1) {
| tzcnt Rq(def_reg), qword [offset]
} else {
| bsf Rq(def_reg), qword [offset]
}
} else {
| popcnt Rq(def_reg), qword [offset]
}
break;
|.endif
}
@ -8764,8 +8916,8 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
case IR_SHIFT_CONST:
ir_emit_shift_const(ctx, i, insn);
break;
case IR_CTPOP_POPCNT:
ir_emit_ctpop_popcnt(ctx, i, insn);
case IR_BIT_COUNT:
ir_emit_bit_count(ctx, i, insn);
break;
case IR_CTPOP:
ir_emit_ctpop(ctx, i, insn);

88
tests/run/ctlz_001.irt Normal file
View File

@ -0,0 +1,88 @@
--TEST--
CTLZ 001:
--ARGS--
--run
--CODE--
extern func printf(uintptr_t, ...): int32_t;
func ctlz8(int8_t): int32_t
{
l_1 = START(l_5);
int8_t d_2 = PARAM(l_1, "arg_1", 1);
int8_t d_3 = CTLZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func ctlz16(int16_t): int32_t
{
l_1 = START(l_5);
int16_t d_2 = PARAM(l_1, "arg_1", 1);
int16_t d_3 = CTLZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func ctlz32(int32_t): int32_t
{
l_1 = START(l_4);
int32_t d_2 = PARAM(l_1, "arg_1", 1);
int32_t d_3 = CTLZ(d_2);
l_4 = RETURN(l_1, d_3);
}
#func ctlz64(int64_t): int32_t
#{
# l_1 = START(l_5);
# int64_t d_2 = PARAM(l_1, "arg_1", 1);
# int64_t d_3 = CTLZ(d_2);
# int32_t d_4 = TRUNC(d_3);
# l_5 = RETURN(l_1, d_4);
#}
func main(void): int32_t
{
uintptr_t c_1 = 0;
bool c_2 = 0;
bool c_3 = 1;
int8_t c_4 = 1;
uintptr_t c_5 = func(ctlz8);
int8_t c_6 = 96;
int8_t c_7 = -128;
uintptr_t c_8 = "u8 : %2d %2d %2d\n";
uintptr_t c_9 = func(printf);
int16_t c_10 = 1;
uintptr_t c_11 = func(ctlz16);
int16_t c_12 = 1536;
int16_t c_13 = -32768;
uintptr_t c_14 = "u16: %2d %2d %2d\n";
int32_t c_15 = 1;
uintptr_t c_16 = func(ctlz32);
int32_t c_17 = 393216;
int32_t c_18 = -2147483648;
uintptr_t c_19 = "u32: %2d %2d %2d\n";
int64_t c_20 = 1;
uintptr_t c_21 = func(ctlz64);
int64_t c_22 = 25769803776;
int64_t c_23 = -9223372036854775808;
uintptr_t c_24 = "u64: %2d %2d %2d\n";
int32_t c_25 = 0;
l_1 = START(l_22);
int32_t d_2, l_2 = CALL/1(l_1, c_5, c_4);
int32_t d_3, l_3 = CALL/1(l_2, c_5, c_6);
int32_t d_4, l_4 = CALL/1(l_3, c_5, c_7);
int32_t d_5, l_5 = CALL/4(l_4, c_9, c_8, d_2, d_3, d_4);
int32_t d_7, l_7 = CALL/1(l_5, c_11, c_10);
int32_t d_8, l_8 = CALL/1(l_7, c_11, c_12);
int32_t d_9, l_9 = CALL/1(l_8, c_11, c_13);
int32_t d_10, l_10 = CALL/4(l_9, c_9, c_14, d_7, d_8, d_9);
int32_t d_12, l_12 = CALL/1(l_10, c_16, c_15);
int32_t d_13, l_13 = CALL/1(l_12, c_16, c_17);
int32_t d_14, l_14 = CALL/1(l_13, c_16, c_18);
int32_t d_15, l_15 = CALL/4(l_14, c_9, c_19, d_12, d_13, d_14);
# int32_t d_17, l_17 = CALL/1(l_15, c_21, c_20);
# int32_t d_18, l_18 = CALL/1(l_17, c_21, c_22);
# int32_t d_19, l_19 = CALL/1(l_18, c_21, c_23);
# int32_t d_20, l_20 = CALL/4(l_19, c_9, c_24, d_17, d_18, d_19);
# l_22 = RETURN(l_20, c_25);
l_22 = RETURN(l_15, c_25);
}
--EXPECT--
u8 : 7 1 0
u16: 15 5 0
u32: 31 13 0

90
tests/run/ctlz_002.irt Normal file
View File

@ -0,0 +1,90 @@
--TEST--
CTLZ 002: -mno-bmi1
--TARGET--
x86_64
--ARGS--
-mno-bmi1 --run
--CODE--
extern func printf(uintptr_t, ...): int32_t;
func ctlz8(int8_t): int32_t
{
l_1 = START(l_5);
int8_t d_2 = PARAM(l_1, "arg_1", 1);
int8_t d_3 = CTLZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func ctlz16(int16_t): int32_t
{
l_1 = START(l_5);
int16_t d_2 = PARAM(l_1, "arg_1", 1);
int16_t d_3 = CTLZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func ctlz32(int32_t): int32_t
{
l_1 = START(l_4);
int32_t d_2 = PARAM(l_1, "arg_1", 1);
int32_t d_3 = CTLZ(d_2);
l_4 = RETURN(l_1, d_3);
}
func ctlz64(int64_t): int32_t
{
l_1 = START(l_5);
int64_t d_2 = PARAM(l_1, "arg_1", 1);
int64_t d_3 = CTLZ(d_2);
int32_t d_4 = TRUNC(d_3);
l_5 = RETURN(l_1, d_4);
}
func main(void): int32_t
{
uintptr_t c_1 = 0;
bool c_2 = 0;
bool c_3 = 1;
int8_t c_4 = 1;
uintptr_t c_5 = func(ctlz8);
int8_t c_6 = 96;
int8_t c_7 = -128;
uintptr_t c_8 = "u8 : %2d %2d %2d\n";
uintptr_t c_9 = func(printf);
int16_t c_10 = 1;
uintptr_t c_11 = func(ctlz16);
int16_t c_12 = 1536;
int16_t c_13 = -32768;
uintptr_t c_14 = "u16: %2d %2d %2d\n";
int32_t c_15 = 1;
uintptr_t c_16 = func(ctlz32);
int32_t c_17 = 393216;
int32_t c_18 = -2147483648;
uintptr_t c_19 = "u32: %2d %2d %2d\n";
int64_t c_20 = 1;
uintptr_t c_21 = func(ctlz64);
int64_t c_22 = 25769803776;
int64_t c_23 = -9223372036854775808;
uintptr_t c_24 = "u64: %2d %2d %2d\n";
int32_t c_25 = 0;
l_1 = START(l_22);
int32_t d_2, l_2 = CALL/1(l_1, c_5, c_4);
int32_t d_3, l_3 = CALL/1(l_2, c_5, c_6);
int32_t d_4, l_4 = CALL/1(l_3, c_5, c_7);
int32_t d_5, l_5 = CALL/4(l_4, c_9, c_8, d_2, d_3, d_4);
int32_t d_7, l_7 = CALL/1(l_5, c_11, c_10);
int32_t d_8, l_8 = CALL/1(l_7, c_11, c_12);
int32_t d_9, l_9 = CALL/1(l_8, c_11, c_13);
int32_t d_10, l_10 = CALL/4(l_9, c_9, c_14, d_7, d_8, d_9);
int32_t d_12, l_12 = CALL/1(l_10, c_16, c_15);
int32_t d_13, l_13 = CALL/1(l_12, c_16, c_17);
int32_t d_14, l_14 = CALL/1(l_13, c_16, c_18);
int32_t d_15, l_15 = CALL/4(l_14, c_9, c_19, d_12, d_13, d_14);
int32_t d_17, l_17 = CALL/1(l_15, c_21, c_20);
int32_t d_18, l_18 = CALL/1(l_17, c_21, c_22);
int32_t d_19, l_19 = CALL/1(l_18, c_21, c_23);
int32_t d_20, l_20 = CALL/4(l_19, c_9, c_24, d_17, d_18, d_19);
l_22 = RETURN(l_20, c_25);
}
--EXPECT--
u8 : 7 1 0
u16: 15 5 0
u32: 31 13 0
u64: 63 29 0

View File

@ -1,9 +1,9 @@
--TEST--
CTPOP 002:
CTPOP 002: -mno-bmi1
--TARGET--
x86_64
--ARGS--
-mno-sse41 --run
-mno-bmi1 --run
--CODE--
extern func printf(uintptr_t, ...): int32_t;
func ctpop8(int8_t): int32_t

88
tests/run/cttz_001.irt Normal file
View File

@ -0,0 +1,88 @@
--TEST--
CTTZ 001:
--ARGS--
--run
--CODE--
extern func printf(uintptr_t, ...): int32_t;
func cttz8(int8_t): int32_t
{
l_1 = START(l_5);
int8_t d_2 = PARAM(l_1, "arg_1", 1);
int8_t d_3 = CTTZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func cttz16(int16_t): int32_t
{
l_1 = START(l_5);
int16_t d_2 = PARAM(l_1, "arg_1", 1);
int16_t d_3 = CTTZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func cttz32(int32_t): int32_t
{
l_1 = START(l_4);
int32_t d_2 = PARAM(l_1, "arg_1", 1);
int32_t d_3 = CTTZ(d_2);
l_4 = RETURN(l_1, d_3);
}
#func cttz64(int64_t): int32_t
#{
# l_1 = START(l_5);
# int64_t d_2 = PARAM(l_1, "arg_1", 1);
# int64_t d_3 = CTTZ(d_2);
# int32_t d_4 = TRUNC(d_3);
# l_5 = RETURN(l_1, d_4);
#}
func main(void): int32_t
{
uintptr_t c_1 = 0;
bool c_2 = 0;
bool c_3 = 1;
int8_t c_4 = 1;
uintptr_t c_5 = func(cttz8);
int8_t c_6 = 96;
int8_t c_7 = -128;
uintptr_t c_8 = "u8 : %2d %2d %2d\n";
uintptr_t c_9 = func(printf);
int16_t c_10 = 1;
uintptr_t c_11 = func(cttz16);
int16_t c_12 = 1536;
int16_t c_13 = -32768;
uintptr_t c_14 = "u16: %2d %2d %2d\n";
int32_t c_15 = 1;
uintptr_t c_16 = func(cttz32);
int32_t c_17 = 393216;
int32_t c_18 = -2147483648;
uintptr_t c_19 = "u32: %2d %2d %2d\n";
int64_t c_20 = 1;
uintptr_t c_21 = func(cttz64);
int64_t c_22 = 25769803776;
int64_t c_23 = -9223372036854775808;
uintptr_t c_24 = "u64: %2d %2d %2d\n";
int32_t c_25 = 0;
l_1 = START(l_22);
int32_t d_2, l_2 = CALL/1(l_1, c_5, c_4);
int32_t d_3, l_3 = CALL/1(l_2, c_5, c_6);
int32_t d_4, l_4 = CALL/1(l_3, c_5, c_7);
int32_t d_5, l_5 = CALL/4(l_4, c_9, c_8, d_2, d_3, d_4);
int32_t d_7, l_7 = CALL/1(l_5, c_11, c_10);
int32_t d_8, l_8 = CALL/1(l_7, c_11, c_12);
int32_t d_9, l_9 = CALL/1(l_8, c_11, c_13);
int32_t d_10, l_10 = CALL/4(l_9, c_9, c_14, d_7, d_8, d_9);
int32_t d_12, l_12 = CALL/1(l_10, c_16, c_15);
int32_t d_13, l_13 = CALL/1(l_12, c_16, c_17);
int32_t d_14, l_14 = CALL/1(l_13, c_16, c_18);
int32_t d_15, l_15 = CALL/4(l_14, c_9, c_19, d_12, d_13, d_14);
# int32_t d_17, l_17 = CALL/1(l_15, c_21, c_20);
# int32_t d_18, l_18 = CALL/1(l_17, c_21, c_22);
# int32_t d_19, l_19 = CALL/1(l_18, c_21, c_23);
# int32_t d_20, l_20 = CALL/4(l_19, c_9, c_24, d_17, d_18, d_19);
# l_22 = RETURN(l_20, c_25);
l_22 = RETURN(l_15, c_25);
}
--EXPECT--
u8 : 0 5 7
u16: 0 9 15
u32: 0 17 31

90
tests/run/cttz_002.irt Normal file
View File

@ -0,0 +1,90 @@
--TEST--
CTTZ 002: -mno-bmi1
--TARGET--
x86_64
--ARGS--
-mno-bmi1 --run
--CODE--
extern func printf(uintptr_t, ...): int32_t;
func cttz8(int8_t): int32_t
{
l_1 = START(l_5);
int8_t d_2 = PARAM(l_1, "arg_1", 1);
int8_t d_3 = CTTZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func cttz16(int16_t): int32_t
{
l_1 = START(l_5);
int16_t d_2 = PARAM(l_1, "arg_1", 1);
int16_t d_3 = CTTZ(d_2);
int32_t d_4 = ZEXT(d_3);
l_5 = RETURN(l_1, d_4);
}
func cttz32(int32_t): int32_t
{
l_1 = START(l_4);
int32_t d_2 = PARAM(l_1, "arg_1", 1);
int32_t d_3 = CTTZ(d_2);
l_4 = RETURN(l_1, d_3);
}
func cttz64(int64_t): int32_t
{
l_1 = START(l_5);
int64_t d_2 = PARAM(l_1, "arg_1", 1);
int64_t d_3 = CTTZ(d_2);
int32_t d_4 = TRUNC(d_3);
l_5 = RETURN(l_1, d_4);
}
func main(void): int32_t
{
uintptr_t c_1 = 0;
bool c_2 = 0;
bool c_3 = 1;
int8_t c_4 = 1;
uintptr_t c_5 = func(cttz8);
int8_t c_6 = 96;
int8_t c_7 = -128;
uintptr_t c_8 = "u8 : %2d %2d %2d\n";
uintptr_t c_9 = func(printf);
int16_t c_10 = 1;
uintptr_t c_11 = func(cttz16);
int16_t c_12 = 1536;
int16_t c_13 = -32768;
uintptr_t c_14 = "u16: %2d %2d %2d\n";
int32_t c_15 = 1;
uintptr_t c_16 = func(cttz32);
int32_t c_17 = 393216;
int32_t c_18 = -2147483648;
uintptr_t c_19 = "u32: %2d %2d %2d\n";
int64_t c_20 = 1;
uintptr_t c_21 = func(cttz64);
int64_t c_22 = 25769803776;
int64_t c_23 = -9223372036854775808;
uintptr_t c_24 = "u64: %2d %2d %2d\n";
int32_t c_25 = 0;
l_1 = START(l_22);
int32_t d_2, l_2 = CALL/1(l_1, c_5, c_4);
int32_t d_3, l_3 = CALL/1(l_2, c_5, c_6);
int32_t d_4, l_4 = CALL/1(l_3, c_5, c_7);
int32_t d_5, l_5 = CALL/4(l_4, c_9, c_8, d_2, d_3, d_4);
int32_t d_7, l_7 = CALL/1(l_5, c_11, c_10);
int32_t d_8, l_8 = CALL/1(l_7, c_11, c_12);
int32_t d_9, l_9 = CALL/1(l_8, c_11, c_13);
int32_t d_10, l_10 = CALL/4(l_9, c_9, c_14, d_7, d_8, d_9);
int32_t d_12, l_12 = CALL/1(l_10, c_16, c_15);
int32_t d_13, l_13 = CALL/1(l_12, c_16, c_17);
int32_t d_14, l_14 = CALL/1(l_13, c_16, c_18);
int32_t d_15, l_15 = CALL/4(l_14, c_9, c_19, d_12, d_13, d_14);
int32_t d_17, l_17 = CALL/1(l_15, c_21, c_20);
int32_t d_18, l_18 = CALL/1(l_17, c_21, c_22);
int32_t d_19, l_19 = CALL/1(l_18, c_21, c_23);
int32_t d_20, l_20 = CALL/4(l_19, c_9, c_24, d_17, d_18, d_19);
l_22 = RETURN(l_20, c_25);
}
--EXPECT--
u8 : 0 5 7
u16: 0 9 15
u32: 0 17 31
u64: 0 33 63