@@ -1064,6 +1064,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
1064
1064
_(SSE_CEIL) \
1065
1065
_(SSE_TRUNC) \
1066
1066
_(SSE_NEARBYINT) \
1067
+ _(OR_PWR2) \
1067
1068
1068
1069
#define IR_RULE_ENUM(name) IR_ ## name,
1069
1070
@@ -1395,6 +1396,7 @@ op2_const:
1395
1396
case IR_DIV_PWR2:
1396
1397
case IR_OP_INT:
1397
1398
case IR_OP_FP:
1399
+ case IR_OR_PWR2:
1398
1400
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
1399
1401
break;
1400
1402
case IR_MOD_PWR2:
@@ -2262,6 +2264,9 @@ binop_fp:
2262
2264
// return IR_COPY_INT;
2263
2265
} else if (op2_insn->val.i64 == -1) {
2264
2266
// -1
2267
+ } else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64) && op2_insn->val.u64 > (1ULL<<30)) {
2268
+ /* OR(X, PWR2) => BTS */
2269
+ return IR_OR_PWR2;
2265
2270
}
2266
2271
}
2267
2272
goto binop_int;
@@ -4280,6 +4285,26 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
4280
4285
uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
4281
4286
4282
4287
| ASM_REG_IMM_OP shr, type, def_reg, shift
4288
+ } else if (insn->op == IR_OR) {
4289
+ uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
4290
+
4291
+ /* bts doesn't support r/m8 first operand */
4292
+ switch (ir_type_size[type]) {
4293
+ default:
4294
+ IR_ASSERT(0);
4295
+ case 1:
4296
+ case 2:
4297
+ | bts Rw(def_reg), (shift & 0xffff)
4298
+ break;
4299
+ case 4:
4300
+ | bts Rd(def_reg), shift
4301
+ break;
4302
+ |.if X64
4303
+ || case 8:
4304
+ | bts Rq(def_reg), shift
4305
+ || break;
4306
+ |.endif
4307
+ }
4283
4308
} else {
4284
4309
IR_ASSERT(insn->op == IR_MOD);
4285
4310
uint64_t mask = ctx->ir_base[insn->op2].val.u64 - 1;
@@ -10608,6 +10633,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
10608
10633
case IR_MUL_PWR2:
10609
10634
case IR_DIV_PWR2:
10610
10635
case IR_MOD_PWR2:
10636
+ case IR_OR_PWR2:
10611
10637
ir_emit_mul_div_mod_pwr2(ctx, i, insn);
10612
10638
break;
10613
10639
case IR_SDIV_PWR2:
0 commit comments