mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-27 23:41:31 +00:00
Add read-before-write for flags, and fix bugs caused by typos
This commit is contained in:
@@ -1630,8 +1630,9 @@ gb_internal bool check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm
|
||||
explicit_writes |= synth;
|
||||
}
|
||||
|
||||
facts->gen_regs = produced | pinned_param_writes;
|
||||
facts->gen_flags = cast(u16)clobber.flags_wr;
|
||||
facts->gen_regs = produced | pinned_param_writes;
|
||||
facts->gen_flags = cast(u16)clobber.flags_wr;
|
||||
facts->read_flags = cast(u16)clobber.flags_rd;
|
||||
|
||||
// NOTE(bill): mnemonics such as `xor r, r` / `sub r, r` act as zeroing the destination
|
||||
// independent of its prior value: the read is architecturally dead, so it must not count as a use.
|
||||
|
||||
@@ -24,6 +24,7 @@ struct AsmInstructionFacts {
|
||||
String name;
|
||||
|
||||
u16 gen_flags; // flag bits this instruction defines
|
||||
u16 read_flags;
|
||||
u16 gen_regs;
|
||||
u16 read_regs;
|
||||
|
||||
@@ -463,7 +464,7 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
nin_p = universe_pm;
|
||||
for (i32 p : preds[bi]) {
|
||||
nin_r &= out_regs[p];
|
||||
nin_r &= out_flags[p];
|
||||
nin_f &= out_flags[p];
|
||||
nin_p &= out_pm[p];
|
||||
}
|
||||
}
|
||||
@@ -546,7 +547,8 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
PtrSet<Entity *> reported_params = {};
|
||||
defer (ptr_set_destroy(&reported_params));
|
||||
|
||||
u16 reported_regs = 0;
|
||||
u16 reported_regs = 0;
|
||||
u16 reported_flags = 0;
|
||||
|
||||
for_array(bi, cfg->blocks) {
|
||||
AsmBlock const &b = cfg->blocks[bi];
|
||||
@@ -554,8 +556,9 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
continue;
|
||||
}
|
||||
|
||||
u16 run_regs = in_regs[bi];
|
||||
u64 run_pm = in_pm[bi];
|
||||
u16 run_regs = in_regs[bi];
|
||||
u16 run_flags = in_flags[bi];
|
||||
u64 run_pm = in_pm[bi];
|
||||
|
||||
for (i32 ii = b.first; ii <= b.last; ii++) {
|
||||
AstAsmInstruction *instr = cfg->insts[ii];
|
||||
@@ -573,6 +576,15 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
reported_regs |= bit;
|
||||
}
|
||||
|
||||
u16 undef_flags = f->read_flags & ~run_flags & ~reported_flags;
|
||||
if (undef_flags != 0) {
|
||||
error(instr->name,
|
||||
"'%.*s' reads a status flag that is not set on all paths reaching here; "
|
||||
"a flag-setting instruction (e.g. 'cmp', 'test') must precede it on every path",
|
||||
LIT(f->name));
|
||||
reported_flags |= undef_flags;
|
||||
}
|
||||
|
||||
for (Entity *pe : f->read_params) {
|
||||
i32 *ix = map_get(&cfg->entity_to_index, pe);
|
||||
if (ix == nullptr) {
|
||||
@@ -591,7 +603,8 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
}
|
||||
}
|
||||
|
||||
run_regs |= f->gen_regs;
|
||||
run_regs |= f->gen_regs;
|
||||
run_flags |= f->gen_flags;
|
||||
for (Entity *pe : f->gen_params) {
|
||||
run_pm |= bit_of(pe);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user