@@ -650,6 +650,26 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_
650
650
|| }
651
651
|.endmacro
652
652
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
+
653
673
|.macro ASM_MEM_REG_OP, op, type, op1, op2
654
674
| ASM_EXPAND_OP1_MEM ASM_EXPAND_TYPE_MEM_REG, op, type, op1, op2
655
675
|.endmacro
@@ -1066,6 +1086,7 @@ const char *ir_reg_name(int8_t reg, ir_type type)
1066
1086
_(SSE_CEIL) \
1067
1087
_(SSE_TRUNC) \
1068
1088
_(SSE_NEARBYINT) \
1089
+ _(BIT_OP) \
1069
1090
1070
1091
#define IR_LEA_FIRST IR_LEA_OB
1071
1092
#define IR_LEA_LAST IR_LEA_O_SYM
@@ -1400,6 +1421,7 @@ op2_const:
1400
1421
case IR_DIV_PWR2:
1401
1422
case IR_OP_INT:
1402
1423
case IR_OP_FP:
1424
+ case IR_BIT_OP:
1403
1425
flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG;
1404
1426
break;
1405
1427
case IR_MOD_PWR2:
@@ -2280,6 +2302,9 @@ binop_fp:
2280
2302
// return IR_COPY_INT;
2281
2303
} else if (op2_insn->val.i64 == -1) {
2282
2304
// -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;
2283
2308
}
2284
2309
}
2285
2310
goto binop_int;
@@ -2294,6 +2319,9 @@ binop_fp:
2294
2319
// 0
2295
2320
} else if (op2_insn->val.i64 == -1) {
2296
2321
// 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;
2297
2325
}
2298
2326
}
2299
2327
goto binop_int;
@@ -4341,6 +4369,45 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
4341
4369
}
4342
4370
}
4343
4371
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
+
4344
4411
static void ir_emit_sdiv_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn)
4345
4412
{
4346
4413
ir_backend_data *data = ctx->data;
@@ -10668,6 +10735,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
10668
10735
case IR_MOD_PWR2:
10669
10736
ir_emit_mul_div_mod_pwr2(ctx, i, insn);
10670
10737
break;
10738
+ case IR_BIT_OP:
10739
+ ir_emit_bit_op(ctx, i, insn);
10740
+ break;
10671
10741
case IR_SDIV_PWR2:
10672
10742
ir_emit_sdiv_pwr2(ctx, i, insn);
10673
10743
break;
0 commit comments