@@ -1064,6 +1064,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
10641064 _(SSE_CEIL) \
10651065 _(SSE_TRUNC) \
10661066 _(SSE_NEARBYINT) \
1067+ _(OR_PWR2) \
10671068
10681069#define IR_RULE_ENUM(name) IR_ ## name,
10691070
@@ -1395,6 +1396,7 @@ op2_const:
13951396 case IR_DIV_PWR2:
13961397 case IR_OP_INT:
13971398 case IR_OP_FP:
1399+ case IR_OR_PWR2:
13981400 flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
13991401 break;
14001402 case IR_MOD_PWR2:
@@ -2262,6 +2264,9 @@ binop_fp:
22622264 // return IR_COPY_INT;
22632265 } else if (op2_insn->val.i64 == -1) {
22642266 // -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;
22652270 }
22662271 }
22672272 goto binop_int;
@@ -4280,6 +4285,26 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
42804285 uint32_t shift = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
42814286
42824287 | 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+ }
42834308 } else {
42844309 IR_ASSERT(insn->op == IR_MOD);
42854310 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)
1060810633 case IR_MUL_PWR2:
1060910634 case IR_DIV_PWR2:
1061010635 case IR_MOD_PWR2:
10636+ case IR_OR_PWR2:
1061110637 ir_emit_mul_div_mod_pwr2(ctx, i, insn);
1061210638 break;
1061310639 case IR_SDIV_PWR2:
0 commit comments