From d0fb380c2087b0d2aaa0554ed54f0c461ca92958 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 01:05:47 +0100 Subject: [PATCH] Support riscv `_aq` `_rl` `_aqrl` suffixes for mnemonics --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 48 +++++++++++++++++++ .../x86/tablegen/cpp-compiler/cpp-gen.odin | 15 ++++++ src/asm_tables_amd64.cpp | 15 ++++++ src/asm_tables_riscv.cpp | 48 +++++++++++++++++++ src/check_asm.cpp | 18 +++++-- src/parser.hpp | 1 + 6 files changed, 142 insertions(+), 3 deletions(-) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index 8bc1026b3..f357e6700 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -437,6 +437,54 @@ main :: proc() { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + MnemonicSuffix_AQ = 1<<0, // Acquire + MnemonicSuffix_RL = 1<<1, // Release + }; + + bool mnemonic_accepts_suffix(u16 m) const { + auto forms = encoding_forms(m); + for (auto const &form : forms) { + for (auto const &enc : form.enc) { + if (enc == ENC_AQRL) { + return true; + } + } + } + auto clobbers = clobber_forms(m); + for (auto const &c : clobbers) { + if ((cast(u16)c.side_effects & (SideEffectFlag_ATOMIC | SideEffectFlag_RESERVATION)) != 0) { + return true; + } + } + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + u8 suffixes = 0; + String base = {}; + if (string_ends_with(name, str_lit(\"_aqrl\"))) { + suffixes = MnemonicSuffix_AQ | MnemonicSuffix_RL; + base = substring(name, 0, name.len - 5); + } else if (string_ends_with(name, str_lit(\"_aq\"))) { + suffixes = MnemonicSuffix_AQ; + base = substring(name, 0, name.len - 3); + } else if (string_ends_with(name, str_lit(\"_rl\"))) { + suffixes = MnemonicSuffix_RL; + base = substring(name, 0, name.len - 3); + } else { + return M_INVALID; + } + Mnemonic m = mnemonic_lookup(base); + if (m == M_INVALID || !mnemonic_accepts_suffix(cast(u16)m)) { + return M_INVALID; + } + if (suffixes_) *suffixes_ = suffixes; + return m; + } + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index b665d97dd..a6052c650 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -480,6 +480,21 @@ main :: proc() { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + }; + + bool mnemonic_accepts_suffix(u16 m) const { + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + // NOTE(bill): Do any instructions need a suffix idea? + return M_INVALID; + } + + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index c2f013049..d175ec0f5 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -508,6 +508,21 @@ struct Asm_amd64 { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + }; + + bool mnemonic_accepts_suffix(u16 m) const { + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + // NOTE(bill): Do any instructions need a suffix idea? + return M_INVALID; + } + + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index e5045f622..fbafea854 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -407,6 +407,54 @@ struct Asm_riscv { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + MnemonicSuffix_AQ = 1<<0, // Acquire + MnemonicSuffix_RL = 1<<1, // Release + }; + + bool mnemonic_accepts_suffix(u16 m) const { + auto forms = encoding_forms(m); + for (auto const &form : forms) { + for (auto const &enc : form.enc) { + if (enc == ENC_AQRL) { + return true; + } + } + } + auto clobbers = clobber_forms(m); + for (auto const &c : clobbers) { + if ((cast(u16)c.side_effects & (SideEffectFlag_ATOMIC | SideEffectFlag_RESERVATION)) != 0) { + return true; + } + } + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + u8 suffixes = 0; + String base = {}; + if (string_ends_with(name, str_lit("_aqrl"))) { + suffixes = MnemonicSuffix_AQ | MnemonicSuffix_RL; + base = substring(name, 0, name.len - 5); + } else if (string_ends_with(name, str_lit("_aq"))) { + suffixes = MnemonicSuffix_AQ; + base = substring(name, 0, name.len - 3); + } else if (string_ends_with(name, str_lit("_rl"))) { + suffixes = MnemonicSuffix_RL; + base = substring(name, 0, name.len - 3); + } else { + return M_INVALID; + } + Mnemonic m = mnemonic_lookup(base); + if (m == M_INVALID || !mnemonic_accepts_suffix(cast(u16)m)) { + return M_INVALID; + } + if (suffixes_) *suffixes_ = suffixes; + return m; + } + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/check_asm.cpp b/src/check_asm.cpp index a05eeb17a..899565876 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -855,7 +855,7 @@ enum CheckMnemomicResult { }; template -gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstruction *instr, u16 *mnemonic_) { +gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstruction *instr, u16 *mnemonic_, u8 *suffix_flags_) { Token token = instr->name->Ident.token; GB_ASSERT_MSG(token.kind == Token_Ident || token_is_keyword(token.kind), "got %.*s of kind %.*s", LIT(token.string), LIT(token_strings[token.kind])); String name = token.string; @@ -875,6 +875,14 @@ gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstr return CheckMnemomic_PseudoMnemonic; } + u8 suffix_flags = 0; + auto om = asm_ctx->mnemonic_lookup_ordered(name, &suffix_flags); + if (om) { + if (mnemonic_) *mnemonic_ = cast(u16)om; + if (suffix_flags_) *suffix_flags_ = suffix_flags; + return CheckMnemomic_Mnemonic; + } + ERROR_BLOCK(); if (instr->operands.count == 0) { @@ -1924,8 +1932,9 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity case_ast_node(instr, AsmInstruction, instruction_); GB_ASSERT(instr->name->kind == Ast_Ident); - u16 mnemonic = 0; - CheckMnemomicResult res = check_mnemonic_name(asm_ctx, instr, &mnemonic); + u16 mnemonic = 0; + u8 suffix_flags = 0; + CheckMnemomicResult res = check_mnemonic_name(asm_ctx, instr, &mnemonic, &suffix_flags); array_clear(&operands); for (Ast *expr : instr->operands) { @@ -1944,6 +1953,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) { + instr->suffix_flags = suffix_flags; check_mnemonic(asm_ctx, ctx, entity, instr, mnemonic, 0, slice_from_array(operands), previous_prefix, previous_prefix_instr, &asm_acc); @@ -1953,6 +1963,8 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity previous_prefix = 0; previous_prefix_instr = nullptr; } else if (res == CheckMnemomic_PseudoMnemonic) { + instr->suffix_flags = suffix_flags; + u16 pseudo_mnemonic = cast(u16)mnemonic; auto alias = asm_ctx->pseudo_alias(cast(u16)pseudo_mnemonic); u16 target_mnemonic = cast(u16)alias.target; diff --git a/src/parser.hpp b/src/parser.hpp index 4779e09a8..efc8be219 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -507,6 +507,7 @@ struct AstSplitArgs { Ast * name; \ Slice operands; \ u16 mnemonic; \ + u8 suffix_flags; \ i32 valid_form_index; \ }) \ AST_KIND(AsmMemoryOperand, "asm memory operand", struct { \