@@ -650,6 +650,26 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_
650650|| }
651651|.endmacro
652652
653+ /* Like ASM_REG_IMM_OP, but op1 accepts r16,r32,r64 (not r8) */
654+ |.macro ASM_REG16_IMM_OP, op, type, op1, op2
655+ || switch (ir_type_size[type]) {
656+ || default:
657+ || IR_ASSERT(0);
658+ || case 1:
659+ || case 2:
660+ | op Rw(op1), (op2 & 0xffff)
661+ || break;
662+ || case 4:
663+ | op Rd(op1), op2
664+ || break;
665+ |.if X64
666+ || case 8:
667+ | op Rq(op1), op2
668+ || break;
669+ |.endif
670+ || }
671+ |.endmacro
672+
653673|.macro ASM_MEM_REG_OP, op, type, op1, op2
654674| ASM_EXPAND_OP1_MEM ASM_EXPAND_TYPE_MEM_REG, op, type, op1, op2
655675|.endmacro
@@ -1066,6 +1086,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
10661086 _(SSE_CEIL) \
10671087 _(SSE_TRUNC) \
10681088 _(SSE_NEARBYINT) \
1089+ _(BIT_OP) \
10691090
10701091#define IR_LEA_FIRST IR_LEA_OB
10711092#define IR_LEA_LAST IR_LEA_O_SYM
@@ -1400,6 +1421,7 @@ op2_const:
14001421 case IR_DIV_PWR2:
14011422 case IR_OP_INT:
14021423 case IR_OP_FP:
1424+ case IR_BIT_OP:
14031425 flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
14041426 break;
14051427 case IR_MOD_PWR2:
@@ -2280,6 +2302,9 @@ binop_fp:
22802302 // return IR_COPY_INT;
22812303 } else if (op2_insn->val.i64 == -1) {
22822304 // -1
2305+ } else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64) && !IR_IS_SIGNED_32BIT(op2_insn->val.i64)) {
2306+ /* OR(X, PWR2) => BTS */
2307+ return IR_BIT_OP;
22832308 }
22842309 }
22852310 goto binop_int;
@@ -2294,6 +2319,9 @@ binop_fp:
22942319 // 0
22952320 } else if (op2_insn->val.i64 == -1) {
22962321 // return IR_COPY_INT;
2322+ } else if (IR_IS_POWER_OF_TWO(~op2_insn->val.u64) && !IR_IS_SIGNED_32BIT(op2_insn->val.i64)) {
2323+ /* AND(X, ~PWR2) => BTR */
2324+ return IR_BIT_OP;
22972325 }
22982326 }
22992327 goto binop_int;
@@ -4341,6 +4369,45 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
43414369 }
43424370}
43434371
4372+ static void ir_emit_bit_op(ir_ctx *ctx, ir_ref def, ir_insn *insn)
4373+ {
4374+ ir_backend_data *data = ctx->data;
4375+ dasm_State **Dst = &data->dasm_state;
4376+ ir_type type = insn->type;
4377+ ir_ref op1 = insn->op1;
4378+ ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]);
4379+ ir_reg op1_reg = ctx->regs[def][1];
4380+
4381+ IR_ASSERT(IR_IS_CONST_REF(insn->op2));
4382+ IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op));
4383+ IR_ASSERT(def_reg != IR_REG_NONE);
4384+
4385+ if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) {
4386+ op1_reg = IR_REG_NUM(op1_reg);
4387+ ir_emit_load(ctx, type, op1_reg, op1);
4388+ }
4389+ if (def_reg != op1_reg) {
4390+ if (op1_reg != IR_REG_NONE) {
4391+ ir_emit_mov(ctx, type, def_reg, op1_reg);
4392+ } else {
4393+ ir_emit_load(ctx, type, def_reg, op1);
4394+ }
4395+ }
4396+ if (insn->op == IR_OR) {
4397+ uint32_t bit = IR_LOG2(ctx->ir_base[insn->op2].val.u64);
4398+
4399+ | ASM_REG16_IMM_OP, bts, type, def_reg, bit
4400+ } else {
4401+ IR_ASSERT(insn->op == IR_AND);
4402+ uint32_t bit = IR_LOG2(~ctx->ir_base[insn->op2].val.u64);
4403+
4404+ | ASM_REG16_IMM_OP, btr, type, def_reg, bit
4405+ }
4406+ if (IR_REG_SPILLED(ctx->regs[def][0])) {
4407+ ir_emit_store(ctx, type, def, def_reg);
4408+ }
4409+ }
4410+
43444411static void ir_emit_sdiv_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
43454412{
43464413 ir_backend_data *data = ctx->data;
@@ -10668,6 +10735,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
1066810735 case IR_MOD_PWR2:
1066910736 ir_emit_mul_div_mod_pwr2(ctx, i, insn);
1067010737 break;
10738+ case IR_BIT_OP:
10739+ ir_emit_bit_op(ctx, i, insn);
10740+ break;
1067110741 case IR_SDIV_PWR2:
1067210742 ir_emit_sdiv_pwr2(ctx, i, insn);
1067310743 break;
0 commit comments