mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-14 01:34:35 +00:00
Infer #clobber memory and #clobber cc from the mnemonics directly
This commit is contained in:
@@ -187,6 +187,18 @@ main :: proc() {
|
||||
strings.write_string(&sb, "\t\tbool writes_mem;\n")
|
||||
strings.write_string(&sb, "\t\tbool reads_mem;\n")
|
||||
strings.write_string(&sb, "\t\tSideEffectFlags side_effects;\n")
|
||||
strings.write_string(&sb, "\n")
|
||||
strings.write_string(&sb, "\t\tbool implies_clobber_cc() {\n")
|
||||
strings.write_string(&sb, "\t\t\tu16 const CC_MASK = ClobberFlag_CF|ClobberFlag_PF|ClobberFlag_AF|\n")
|
||||
strings.write_string(&sb, "\t\t\t ClobberFlag_ZF|ClobberFlag_SF|ClobberFlag_OF;\n")
|
||||
strings.write_string(&sb, "\t\t\treturn ((flags_wr | flags_undef) & CC_MASK) != 0;\n")
|
||||
strings.write_string(&sb, "\t\t}\n")
|
||||
strings.write_string(&sb, "\t\tbool implies_clobber_memory() {\n")
|
||||
strings.write_string(&sb, "\t\t\treturn writes_mem || reads_mem ||\n")
|
||||
strings.write_string(&sb, "\t\t\t\t(side_effects & (SideEffectFlag_FENCE |\n")
|
||||
strings.write_string(&sb, "\t\t\t\t SideEffectFlag_CACHE |\n")
|
||||
strings.write_string(&sb, "\t\t\t\t SideEffectFlag_SERIALIZING)) != 0;\n")
|
||||
strings.write_string(&sb, "\t\t}\n")
|
||||
strings.write_string(&sb, "\t};\n")
|
||||
}
|
||||
strings.write_string(&sb, "\n");
|
||||
|
||||
@@ -192,6 +192,18 @@ struct Asm_amd64 {
|
||||
bool writes_mem;
|
||||
bool reads_mem;
|
||||
SideEffectFlags side_effects;
|
||||
|
||||
bool implies_clobber_cc() {
|
||||
u16 const CC_MASK = ClobberFlag_CF|ClobberFlag_PF|ClobberFlag_AF|
|
||||
ClobberFlag_ZF|ClobberFlag_SF|ClobberFlag_OF;
|
||||
return ((flags_wr | flags_undef) & CC_MASK) != 0;
|
||||
}
|
||||
bool implies_clobber_memory() {
|
||||
return writes_mem || reads_mem ||
|
||||
(side_effects & (SideEffectFlag_FENCE |
|
||||
SideEffectFlag_CACHE |
|
||||
SideEffectFlag_SERIALIZING)) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
static u16 const register_codes[REG_COUNT];
|
||||
|
||||
@@ -734,7 +734,9 @@ gb_internal AsmOperandKind determine_asm_operand_kind(Operand const *operand) {
|
||||
|
||||
|
||||
template <typename AsmCtx>
|
||||
gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, AstAsmInstruction *instr, u16 mnemonic, Slice<Operand> const &operands, u8 previous_prefix, Ast *previous_prefix_instr) {
|
||||
gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tmpl_entity, AstAsmInstruction *instr,
|
||||
u16 mnemonic, Slice<Operand> const &operands,
|
||||
u8 previous_prefix, Ast *previous_prefix_instr) {
|
||||
GB_ASSERT(mnemonic > 0);
|
||||
auto forms = asm_ctx->encoding_forms(mnemonic);
|
||||
String name = asm_ctx->mnemonic_strings[mnemonic];
|
||||
@@ -860,6 +862,15 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, AstAsmInst
|
||||
error(instr->name, "Asm prefix cannot be applied to '%.*s'", LIT(name));
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT(tmpl_entity->kind == Entity_AsmTemplate);
|
||||
|
||||
// Handle clobbering from mnemonic
|
||||
auto clobber = asm_ctx->clobber(mnemonic);
|
||||
|
||||
tmpl_entity->AsmTemplate.clobber_cc |= clobber.implies_clobber_cc();
|
||||
tmpl_entity->AsmTemplate.clobber_memory |= clobber.implies_clobber_memory();
|
||||
tmpl_entity->AsmTemplate.has_side_effects |= clobber.side_effects != 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1260,12 +1271,10 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
|
||||
entity->type = type;
|
||||
|
||||
auto *clobber_registers_set = &entity->AsmTemplate.clobber_registers_set;
|
||||
|
||||
check_asm_specs(ctx, ate->param_scope, at->specs, &ate->decls);
|
||||
{ // check clobbers
|
||||
StringSet reg_set = {};
|
||||
string_set_init(®_set, 16);
|
||||
defer (string_set_destroy(®_set));
|
||||
|
||||
bool clobber_cc = false;
|
||||
bool clobber_memory = false;
|
||||
|
||||
@@ -1276,7 +1285,7 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
String reg = asm_reg->name.string;
|
||||
Operand operand = {};
|
||||
if (check_register(asm_ctx, &operand, asm_reg)) {
|
||||
if (string_set_update(®_set, reg)) {
|
||||
if (string_set_update(clobber_registers_set, reg)) {
|
||||
error(clobber->value, "#clobber %%%.*s has already been defined", LIT(reg));
|
||||
}
|
||||
}
|
||||
@@ -1302,6 +1311,9 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
entity->AsmTemplate.clobber_cc = clobber_cc;
|
||||
entity->AsmTemplate.clobber_memory = clobber_memory;
|
||||
}
|
||||
|
||||
// collect label decls
|
||||
@@ -1363,7 +1375,7 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
previous_prefix = cast(u8)mnemonic;
|
||||
previous_prefix_instr = instruction_;
|
||||
} else if (res == CheckMnemomic_Mnemonic) {
|
||||
check_mnemonic(asm_ctx, ctx, instr, mnemonic, slice_from_array(operands), previous_prefix, previous_prefix_instr);
|
||||
check_mnemonic(asm_ctx, ctx, entity, instr, mnemonic, slice_from_array(operands), previous_prefix, previous_prefix_instr);
|
||||
previous_prefix = 0;
|
||||
previous_prefix_instr = nullptr;
|
||||
} else {
|
||||
|
||||
@@ -345,7 +345,7 @@ struct Entity {
|
||||
|
||||
bool clobber_cc;
|
||||
bool clobber_memory;
|
||||
Array<String> clobber_registers;
|
||||
StringSet clobber_registers_set;
|
||||
|
||||
Scope *param_scope;
|
||||
Scope *label_scope;
|
||||
|
||||
@@ -403,6 +403,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
|
||||
}
|
||||
}
|
||||
|
||||
bool memory_clobbered_already = false;
|
||||
// Pass 3: clobbers
|
||||
// Only the Scratch group. Unpinned register scratch was already emitted as an
|
||||
// output in Pass 1, so it is skipped here.
|
||||
@@ -427,12 +428,27 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
|
||||
break;
|
||||
case AsmTemplateEntityDecl_Memory: // general memory clobber
|
||||
raw("~{memory}");
|
||||
memory_clobbered_already = true;
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("asm: invalid scratch operand kind");
|
||||
}
|
||||
}
|
||||
|
||||
// Template-level clobbers derived from #clobber cc / #clobber memory.
|
||||
if (tmpl_entity->AsmTemplate.clobber_cc) {
|
||||
sep();
|
||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||
raw("~{flags}"); // x86 EFLAGS condition codes
|
||||
} else {
|
||||
raw("~{cc}"); // AArch64 uses ~{cc}
|
||||
}
|
||||
}
|
||||
if (tmpl_entity->AsmTemplate.clobber_memory && memory_clobbered_already) {
|
||||
sep();
|
||||
raw("~{memory}");
|
||||
}
|
||||
|
||||
// Build the callee type
|
||||
// NOTE(bill): Even though the user has given a signature, this might not actually match what
|
||||
// LLVM requires it to be due to the scratch parameters and more, so many of the results might
|
||||
|
||||
Reference in New Issue
Block a user