mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-27 07:21:31 +00:00
asm: minor cleanups
This commit is contained in:
@@ -2358,13 +2358,14 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
|
||||
entity->type = type;
|
||||
|
||||
bool is_volatile = false;
|
||||
bool is_align_stack = false;
|
||||
bool is_pure_annotated = false;
|
||||
auto *clobber_registers_set = &entity->AsmTemplate.clobber_registers_set;
|
||||
|
||||
check_asm_specs(asm_ctx, ctx, ate->param_scope, at->specs, &ate->decls);
|
||||
|
||||
bool is_pure_annotated = false;
|
||||
{ // check clobbers
|
||||
bool is_volatile = false;
|
||||
bool is_align_stack = false;
|
||||
auto *clobber_registers_set = &entity->AsmTemplate.clobber_registers_set;
|
||||
|
||||
bool clobber_flags = false;
|
||||
bool clobber_memory = false;
|
||||
|
||||
@@ -2432,17 +2433,18 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
entity->AsmTemplate.clobber_memory = clobber_memory;
|
||||
entity->AsmTemplate.is_volatile = is_volatile;
|
||||
entity->AsmTemplate.is_align_stack = is_align_stack;
|
||||
}
|
||||
|
||||
// add normalizations for the reigsters too
|
||||
for (String const ® : *clobber_registers_set) {
|
||||
u16 bit = asm_ctx->clobber_bit_for_reg_name(reg);
|
||||
String rname = make_string_c(asm_ctx->clobber_reg_bit_name(bit));
|
||||
if (rname != reg) {
|
||||
string_set_update(clobber_registers_set, rname);
|
||||
// add normalizations for the registers too
|
||||
for (String const ® : *clobber_registers_set) {
|
||||
u16 bit = asm_ctx->clobber_bit_for_reg_name(reg);
|
||||
String rname = make_string_c(asm_ctx->clobber_reg_bit_name(bit));
|
||||
if (rname != reg) {
|
||||
string_set_update(clobber_registers_set, rname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Two distinct operands pinned to the same physical register only makes sense when
|
||||
// they are tied (they intentionally share one register). Compared by bit so %eax
|
||||
// and %rax collide. Flag pins ("flags") yield bit 0 and are skipped.
|
||||
@@ -2471,16 +2473,6 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill, 2026-08-24): Construct a control-flow graph (CFG) from the instructions
|
||||
// to do further analysis which is not possible with an conservative straight-line approximation
|
||||
// Using a CFG is a much sounder approach for calculating:
|
||||
// * reads before writes
|
||||
// * divergence
|
||||
// * unreachable code
|
||||
|
||||
AsmCfg cfg = {};
|
||||
asm_cfg_init(&cfg);
|
||||
defer (asm_cfg_destroy(&cfg));
|
||||
|
||||
// collect label decls
|
||||
for (Ast *instruction_ : at->instructions) {
|
||||
@@ -2507,6 +2499,24 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill, 2026-08-24): Construct a control-flow graph (CFG) from the instructions
|
||||
// to do further analysis which is not possible with an conservative straight-line approximation
|
||||
// Using a CFG is a much sounder approach for calculating:
|
||||
// * read-before-writes
|
||||
// * sub-register width checks
|
||||
// * `%flags` checks
|
||||
// * divergence
|
||||
// * unreachable code
|
||||
// * liveness checks (forward and backwards)
|
||||
|
||||
// NOTE(bill): the AsmCfg structure also hold information which is used to in the linear pass
|
||||
// mainly because it will be used later on by it, so it makes sense to keep them together as
|
||||
// one unit rather than two separate structures.
|
||||
|
||||
AsmCfg cfg = {};
|
||||
asm_cfg_init(&cfg);
|
||||
defer (asm_cfg_destroy(&cfg));
|
||||
|
||||
Array<Operand> operands = {};
|
||||
operands.allocator = heap_allocator();
|
||||
array_reserve(&operands, 16);
|
||||
@@ -2679,10 +2689,14 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
error(previous_prefix_instr, "A prefix must be immediately followed by an instruction, but the template ended");
|
||||
}
|
||||
|
||||
// NOTE(bill): After the linear collection pass of the mnemonics,
|
||||
// now do the CFG building, analysis, and liveness checks (only if everything was correct)
|
||||
|
||||
check_asm_cfg_build(asm_ctx, &cfg, d->init_expr, entity);
|
||||
check_asm_cfg_analyse(asm_ctx, &cfg, ctx, entity);
|
||||
check_asm_cfg_liveness(asm_ctx, &cfg, entity, /*emit_dead_writes*/all_instructions_good);
|
||||
|
||||
|
||||
bool vet_unused = false;
|
||||
{
|
||||
AstFile *file = ctx->file;
|
||||
@@ -2740,7 +2754,7 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ed.tie > 0) {
|
||||
if (ed.tie >= 0) {
|
||||
// TODO(bill): Handle this edge case?
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -463,9 +463,9 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
}
|
||||
|
||||
for_array(bi, cfg->blocks) {
|
||||
u16 gr = 0;
|
||||
u16 gf = 0;
|
||||
u64 gp = 0;
|
||||
u16 gr = 0;
|
||||
u16 gf = 0;
|
||||
u64 gp = 0;
|
||||
AsmRegW gw = {};
|
||||
|
||||
AsmBlock const &b = cfg->blocks[bi];
|
||||
@@ -486,10 +486,10 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
}
|
||||
}
|
||||
}
|
||||
gen_regs[bi] = gr;
|
||||
gen_regs [bi] = gr;
|
||||
gen_flags[bi] = gf;
|
||||
gen_pm[bi] = gp;
|
||||
gen_w[bi] = gw;
|
||||
gen_pm [bi] = gp;
|
||||
gen_w [bi] = gw;
|
||||
}
|
||||
|
||||
// NOTE(bill): initialize the blocks
|
||||
@@ -499,16 +499,16 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
continue;
|
||||
}
|
||||
if (bi == 0) {
|
||||
in_regs[bi] = seed_regs;
|
||||
in_pm[bi] = seed_pm;
|
||||
in_regs [bi] = seed_regs;
|
||||
in_pm [bi] = seed_pm;
|
||||
in_flags[bi] = 0; // no flag is defined at the template entry point
|
||||
} else {
|
||||
in_regs[bi] = REG_TOP;
|
||||
in_pm[bi] = universe_pm;
|
||||
in_regs [bi] = REG_TOP;
|
||||
in_pm [bi] = universe_pm;
|
||||
in_flags[bi] = FLAG_TOP;
|
||||
}
|
||||
out_regs[bi] = in_regs[bi] | gen_regs[bi];
|
||||
out_pm[bi] = in_pm[bi] | gen_pm[bi];
|
||||
out_regs [bi] = in_regs [bi] | gen_regs [bi];
|
||||
out_pm [bi] = in_pm [bi] | gen_pm [bi];
|
||||
out_flags[bi] = in_flags[bi] | gen_flags[bi];
|
||||
}
|
||||
|
||||
@@ -538,17 +538,17 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
u64 nout_p = nin_p | gen_pm[bi];
|
||||
u16 nout_f = nin_f | gen_flags[bi];
|
||||
|
||||
if (nin_r != in_regs[bi] ||
|
||||
nin_p != in_pm[bi] ||
|
||||
nin_f != in_flags[bi] ||
|
||||
nout_r != out_regs[bi] ||
|
||||
nout_p != out_pm[bi] ||
|
||||
if (nin_r != in_regs [bi] ||
|
||||
nin_p != in_pm [bi] ||
|
||||
nin_f != in_flags [bi] ||
|
||||
nout_r != out_regs [bi] ||
|
||||
nout_p != out_pm [bi] ||
|
||||
nout_f != out_flags[bi]) {
|
||||
in_regs[bi] = nin_r;
|
||||
in_pm[bi] = nin_p;
|
||||
in_flags[bi] = nin_f;
|
||||
out_regs[bi] = nout_r;
|
||||
out_pm[bi] = nout_p;
|
||||
in_regs [bi] = nin_r;
|
||||
in_pm [bi] = nin_p;
|
||||
in_flags [bi] = nin_f;
|
||||
out_regs [bi] = nout_r;
|
||||
out_pm [bi] = nout_p;
|
||||
out_flags[bi] = nout_f;
|
||||
changed = true;
|
||||
}
|
||||
@@ -606,9 +606,9 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
// NOTE(bill): publish the register masks and materialise the parameter sets onto the blocks
|
||||
for_array(bi, cfg->blocks) {
|
||||
AsmBlock *b = &cfg->blocks[bi];
|
||||
b->in_defs = in_regs[bi];
|
||||
b->out_defs = out_regs[bi];
|
||||
b->in_flags = in_flags[bi];
|
||||
b->in_defs = in_regs [bi];
|
||||
b->out_defs = out_regs [bi];
|
||||
b->in_flags = in_flags [bi];
|
||||
b->out_flags = out_flags[bi];
|
||||
if (!b->reachable) {
|
||||
continue;
|
||||
@@ -670,10 +670,10 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
continue;
|
||||
}
|
||||
|
||||
u16 run_regs = in_regs[bi];
|
||||
u16 run_regs = in_regs [bi];
|
||||
u16 run_flags = in_flags[bi];
|
||||
u64 run_pm = in_pm[bi];
|
||||
AsmRegW run_w = in_w[bi];
|
||||
u64 run_pm = in_pm [bi];
|
||||
AsmRegW run_w = in_w [bi];
|
||||
|
||||
|
||||
for (i32 ii = b.first; ii <= b.last; ii++) {
|
||||
@@ -790,8 +790,8 @@ gb_internal void check_asm_cfg_analyse(AsmCtx *asm_ctx, AsmCfg *cfg, CheckerCont
|
||||
continue;
|
||||
}
|
||||
any_exit = true;
|
||||
exit_regs &= out_regs[bi];
|
||||
exit_pm &= out_pm[bi];
|
||||
exit_regs &= out_regs [bi];
|
||||
exit_pm &= out_pm [bi];
|
||||
exit_flags &= out_flags[bi];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user