Avoid code generation for useless loads and stores

This commit is contained in:
Dmitry Stogov 2023-06-07 14:43:16 +03:00
parent eaaf487600
commit 3de6c5126a
2 changed files with 96 additions and 28 deletions

View File

@ -2920,6 +2920,12 @@ static void ir_emit_load_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg); int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg);
if (op2_reg == IR_REG_NONE) { if (op2_reg == IR_REG_NONE) {
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, def, &fp) == offset && op1_reg == fp) {
return;
}
}
ir_emit_load_mem_int(ctx, type, def_reg, op1_reg, offset); ir_emit_load_mem_int(ctx, type, def_reg, op1_reg, offset);
} else { } else {
switch (ir_type_size[type]) { switch (ir_type_size[type]) {
@ -2981,6 +2987,12 @@ static void ir_emit_load_fp(ir_ctx *ctx, ir_ref def, ir_insn *insn)
int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg); int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg);
if (op2_reg == IR_REG_NONE) { if (op2_reg == IR_REG_NONE) {
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, def, &fp) == offset && op1_reg == fp) {
return;
}
}
ir_emit_load_mem_fp(ctx, type, def_reg, op1_reg, offset); ir_emit_load_mem_fp(ctx, type, def_reg, op1_reg, offset);
} else { } else {
if (type == IR_DOUBLE) { if (type == IR_DOUBLE) {
@ -3016,20 +3028,33 @@ static void ir_emit_store_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
ir_reg op2_reg = ctx->regs[ref][2]; ir_reg op2_reg = ctx->regs[ref][2];
ir_reg op3_reg = ctx->regs[ref][3]; ir_reg op3_reg = ctx->regs[ref][3];
if (op3_reg == IR_REG_NONE) {
IR_ASSERT(IR_IS_CONST_REF(insn->op3) && ctx->ir_base[insn->op3].val.i64 == 0);
op3_reg = IR_REG_ZR;
} else if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
if (!IR_IS_CONST_REF(insn->op2) && (ir_rule(ctx, insn->op2) & IR_FUSED)) { if (!IR_IS_CONST_REF(insn->op2) && (ir_rule(ctx, insn->op2) & IR_FUSED)) {
ir_reg op1_reg; ir_reg op1_reg;
int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg); int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg);
if (op2_reg == IR_REG_NONE) { if (op2_reg == IR_REG_NONE) {
if (!IR_IS_CONST_REF(insn->op3) && (op3_reg & IR_REG_SPILL_LOAD)) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, insn->op3, &fp) == offset && op1_reg == fp) {
return;
}
}
if (op3_reg == IR_REG_NONE) {
IR_ASSERT(IR_IS_CONST_REF(insn->op3) && ctx->ir_base[insn->op3].val.i64 == 0);
op3_reg = IR_REG_ZR;
} else if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
ir_emit_store_mem_int(ctx, type, op1_reg, offset, op3_reg); ir_emit_store_mem_int(ctx, type, op1_reg, offset, op3_reg);
} else { } else {
if (op3_reg == IR_REG_NONE) {
IR_ASSERT(IR_IS_CONST_REF(insn->op3) && ctx->ir_base[insn->op3].val.i64 == 0);
op3_reg = IR_REG_ZR;
} else if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
switch (ir_type_size[type]) { switch (ir_type_size[type]) {
case 8: case 8:
| str Rx(op3_reg), [Rx(op1_reg), Rx(op2_reg)] | str Rx(op3_reg), [Rx(op1_reg), Rx(op2_reg)]
@ -3054,6 +3079,13 @@ static void ir_emit_store_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR); IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR);
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
if (op3_reg == IR_REG_NONE) {
IR_ASSERT(IR_IS_CONST_REF(insn->op3) && ctx->ir_base[insn->op3].val.i64 == 0);
op3_reg = IR_REG_ZR;
} else if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
ir_emit_store_mem_int(ctx, type, op2_reg, 0, op3_reg); ir_emit_store_mem_int(ctx, type, op2_reg, 0, op3_reg);
} }
} }
@ -3067,17 +3099,27 @@ static void ir_emit_store_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
ir_reg op3_reg = ctx->regs[ref][3]; ir_reg op3_reg = ctx->regs[ref][3];
IR_ASSERT(op3_reg != IR_REG_NONE); IR_ASSERT(op3_reg != IR_REG_NONE);
if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
if (!IR_IS_CONST_REF(insn->op2) && (ir_rule(ctx, insn->op2) & IR_FUSED)) { if (!IR_IS_CONST_REF(insn->op2) && (ir_rule(ctx, insn->op2) & IR_FUSED)) {
ir_reg op1_reg; ir_reg op1_reg;
int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg); int32_t offset = ir_fuse_addr(ctx, insn->op2, &op1_reg, &op2_reg);
if (op2_reg == IR_REG_NONE) { if (op2_reg == IR_REG_NONE) {
if (!IR_IS_CONST_REF(insn->op3) && (op3_reg & IR_REG_SPILL_LOAD)) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, insn->op3, &fp) == offset && op1_reg == fp) {
return;
}
}
if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
ir_emit_store_mem_fp(ctx, type, op1_reg, offset, op3_reg); ir_emit_store_mem_fp(ctx, type, op1_reg, offset, op3_reg);
} else { } else {
if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
if (type == IR_DOUBLE) { if (type == IR_DOUBLE) {
| str Rd(op3_reg-IR_REG_FP_FIRST), [Rx(op1_reg), Rx(op2_reg)] | str Rd(op3_reg-IR_REG_FP_FIRST), [Rx(op1_reg), Rx(op2_reg)]
} else { } else {
@ -3091,6 +3133,10 @@ static void ir_emit_store_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR); IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR);
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
ir_emit_store_mem_fp(ctx, type, op2_reg, 0, op3_reg); ir_emit_store_mem_fp(ctx, type, op2_reg, 0, op3_reg);
} }
} }

View File

@ -5269,6 +5269,9 @@ static void ir_emit_load_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
if (sizeof(void*) == 4 || IR_IS_SIGNED_32BIT(addr)) { if (sizeof(void*) == 4 || IR_IS_SIGNED_32BIT(addr)) {
int32_t addr32 = (int32_t)(intptr_t)addr; int32_t addr32 = (int32_t)(intptr_t)addr;
| ASM_REG_MEM_OP mov, type, def_reg, [addr32] | ASM_REG_MEM_OP mov, type, def_reg, [addr32]
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_emit_store(ctx, type, def, def_reg);
}
return; return;
} }
} }
@ -5277,18 +5280,18 @@ static void ir_emit_load_int(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} }
if (!IR_IS_CONST_REF(insn->op2) && (ir_rule(ctx, insn->op2) & IR_FUSED)) { if (!IR_IS_CONST_REF(insn->op2) && (ir_rule(ctx, insn->op2) & IR_FUSED)) {
offset = ir_fuse_addr(ctx, insn->op2, &op2_reg); offset = ir_fuse_addr(ctx, insn->op2, &op2_reg);
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, def, &fp) == offset && op2_reg == fp) {
return;
}
}
} else if ((op2_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op2)) { } else if ((op2_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op2)) {
op2_reg &= ~IR_REG_SPILL_LOAD; op2_reg &= ~IR_REG_SPILL_LOAD;
IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR); IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR);
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, def, &fp) == offset && op2_reg == fp) {
return;
}
}
ir_emit_load_mem_int(ctx, type, def_reg, op2_reg, offset); ir_emit_load_mem_int(ctx, type, def_reg, op2_reg, offset);
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) { if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_emit_store(ctx, type, def, def_reg); ir_emit_store(ctx, type, def, def_reg);
@ -5315,24 +5318,27 @@ static void ir_emit_load_fp(ir_ctx *ctx, ir_ref def, ir_insn *insn)
IR_ASSERT(sizeof(void*) == 4 || IR_IS_SIGNED_32BIT(ctx->ir_base[insn->op2].val.i64)); IR_ASSERT(sizeof(void*) == 4 || IR_IS_SIGNED_32BIT(ctx->ir_base[insn->op2].val.i64));
| ASM_FP_REG_MEM_OP movss, movsd, vmovss, vmovsd, type, def_reg, [addr32] | ASM_FP_REG_MEM_OP movss, movsd, vmovss, vmovsd, type, def_reg, [addr32]
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_emit_store(ctx, type, def, def_reg);
}
return; return;
} else { } else {
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
} else if (op2_reg == IR_REG_NONE) { } else if (op2_reg == IR_REG_NONE) {
offset = ir_fuse_addr(ctx, insn->op2, &op2_reg); offset = ir_fuse_addr(ctx, insn->op2, &op2_reg);
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, def, &fp) == offset && op2_reg == fp) {
return;
}
}
} else if (op2_reg & IR_REG_SPILL_LOAD) { } else if (op2_reg & IR_REG_SPILL_LOAD) {
op2_reg &= ~IR_REG_SPILL_LOAD; op2_reg &= ~IR_REG_SPILL_LOAD;
IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR); IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR);
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, def, &fp) == offset && op2_reg == fp) {
return;
}
}
ir_emit_load_mem_fp(ctx, type, def_reg, op2_reg, offset); ir_emit_load_mem_fp(ctx, type, def_reg, op2_reg, offset);
if (ctx->regs[def][0] & IR_REG_SPILL_STORE) { if (ctx->regs[def][0] & IR_REG_SPILL_STORE) {
ir_emit_store(ctx, type, def, def_reg); ir_emit_store(ctx, type, def, def_reg);
@ -5371,6 +5377,12 @@ static void ir_emit_store_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
} }
} else if (op2_reg == IR_REG_NONE) { } else if (op2_reg == IR_REG_NONE) {
offset = ir_fuse_addr(ctx, insn->op2, &op2_reg); offset = ir_fuse_addr(ctx, insn->op2, &op2_reg);
if (!IR_IS_CONST_REF(insn->op3) && (op3_reg & IR_REG_SPILL_LOAD)) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, insn->op3, &fp) == offset && op2_reg == fp) {
return;
}
}
} else if (op2_reg & IR_REG_SPILL_LOAD) { } else if (op2_reg & IR_REG_SPILL_LOAD) {
op2_reg &= ~IR_REG_SPILL_LOAD; op2_reg &= ~IR_REG_SPILL_LOAD;
IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR); IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR);
@ -5399,28 +5411,38 @@ static void ir_emit_store_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
int32_t offset = 0; int32_t offset = 0;
IR_ASSERT(op3_reg != IR_REG_NONE); IR_ASSERT(op3_reg != IR_REG_NONE);
if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
if (IR_IS_CONST_REF(insn->op2)) { if (IR_IS_CONST_REF(insn->op2)) {
if (op2_reg == IR_REG_NONE) { if (op2_reg == IR_REG_NONE) {
int32_t addr32 = ctx->ir_base[insn->op2].val.i32; int32_t addr32 = ctx->ir_base[insn->op2].val.i32;
IR_ASSERT(sizeof(void*) == 4 || IR_IS_SIGNED_32BIT(ctx->ir_base[insn->op2].val.i64)); IR_ASSERT(sizeof(void*) == 4 || IR_IS_SIGNED_32BIT(ctx->ir_base[insn->op2].val.i64));
| ASM_FP_MEM_REG_OP movss, movsd, vmovss, vmovsd, type, [addr32], op2_reg if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
| ASM_FP_MEM_REG_OP movss, movsd, vmovss, vmovsd, type, [addr32], op3_reg
return; return;
} else { } else {
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
} else if (op2_reg == IR_REG_NONE) { } else if (op2_reg == IR_REG_NONE) {
offset = ir_fuse_addr(ctx, insn->op2, &op2_reg); offset = ir_fuse_addr(ctx, insn->op2, &op2_reg);
if (!IR_IS_CONST_REF(insn->op3) && (op3_reg & IR_REG_SPILL_LOAD)) {
ir_reg fp;
if (ir_ref_spill_slot(ctx, insn->op3, &fp) == offset && op2_reg == fp) {
return;
}
}
} else if (op2_reg & IR_REG_SPILL_LOAD) { } else if (op2_reg & IR_REG_SPILL_LOAD) {
op2_reg &= ~IR_REG_SPILL_LOAD; op2_reg &= ~IR_REG_SPILL_LOAD;
IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR); IR_ASSERT(ctx->ir_base[insn->op2].type == IR_ADDR);
ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2);
} }
if ((op3_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op3)) {
op3_reg &= ~IR_REG_SPILL_LOAD;
ir_emit_load(ctx, type, op3_reg, insn->op3);
}
ir_emit_store_mem_fp(ctx, type, op2_reg, offset, op3_reg); ir_emit_store_mem_fp(ctx, type, op2_reg, offset, op3_reg);
} }