From db94c5a6cb46d0a0db341975ff72190be69be049 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Aug 2026 12:25:17 +0100 Subject: [PATCH] Begin work in `%flags.zf` et al --- .../x86/tablegen/cpp-compiler/cpp-gen.odin | 36 +++++++++++++++ src/asm_tables_amd64.cpp | 36 +++++++++++++++ src/check_asm.cpp | 46 +++++++++++++++++-- src/entity.cpp | 1 + src/llvm_backend_asm.cpp | 2 +- 5 files changed, 115 insertions(+), 6 deletions(-) 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 4d5228d92..2fa8f34d9 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -219,6 +219,42 @@ main :: proc() { return \"\"; } + i32 flag_bit_from_name(String const &name, i32 *width_) { + static const struct {String name; i32 bit; } table[] = { + {str_lit(\"cf\"), 0}, // Carry + {str_lit(\"pf\"), 2}, // Parity + {str_lit(\"af\"), 4}, // Auxiliary Carry + {str_lit(\"zf\"), 6}, // Zero + {str_lit(\"sf\"), 7}, // Sign + {str_lit(\"tf\"), 8}, // Trap + {str_lit(\"if\"), 9}, // Interrupt Enable + {str_lit(\"df\"), 10}, // Direction + {str_lit(\"of\"), 11}, // Overflow + {str_lit(\"iopl\"),12}, // I/O Privilege Level (2-bit field: bits 12-13, low bit) + {str_lit(\"nt\"), 14}, // Nested Task + {str_lit(\"rf\"), 16}, // Resume + {str_lit(\"vm\"), 17}, // Virtual-8086 Mode + {str_lit(\"ac\"), 18}, // Alignment Check / Access Control + {str_lit(\"vif\"), 19}, // Virtual Interrupt Flag + {str_lit(\"vip\"), 20}, // Virtual Interrupt Pending + {str_lit(\"id\"), 21}, // Identification + }; + + for (auto const &t : table) { + if (name == t.name) { + if (width_) { + if (t.name == \"iopl\") { + *width_ = 2; + } else { + *width_ = 1; + } + } + return t.bit; + } + } + return -1; + } + struct Clobber { OperandSet written; OperandSet read; diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index fd218e0e9..fda95ad24 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -219,6 +219,42 @@ struct Asm_amd64 { return ""; } + i32 flag_bit_from_name(String const &name, i32 *width_) { + static const struct {String name; i32 bit; } table[] = { + {str_lit("cf"), 0}, // Carry + {str_lit("pf"), 2}, // Parity + {str_lit("af"), 4}, // Auxiliary Carry + {str_lit("zf"), 6}, // Zero + {str_lit("sf"), 7}, // Sign + {str_lit("tf"), 8}, // Trap + {str_lit("if"), 9}, // Interrupt Enable + {str_lit("df"), 10}, // Direction + {str_lit("of"), 11}, // Overflow + {str_lit("iopl"),12}, // I/O Privilege Level (2-bit field: bits 12-13, low bit) + {str_lit("nt"), 14}, // Nested Task + {str_lit("rf"), 16}, // Resume + {str_lit("vm"), 17}, // Virtual-8086 Mode + {str_lit("ac"), 18}, // Alignment Check / Access Control + {str_lit("vif"), 19}, // Virtual Interrupt Flag + {str_lit("vip"), 20}, // Virtual Interrupt Pending + {str_lit("id"), 21}, // Identification + }; + + for (auto const &t : table) { + if (name == t.name) { + if (width_) { + if (t.name == "iopl") { + *width_ = 2; + } else { + *width_ = 1; + } + } + return t.bit; + } + } + return -1; + } + struct Clobber { OperandSet written; OperandSet read; diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 6e4914961..7f2d1298c 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -7,6 +7,9 @@ gb_internal i32 check_asm_operand_bit_width(Type *type) { if (is_type_untyped(type)) { return -1; } + if (is_type_boolean(type)) { + return 1; + } i64 sz = type_size_of(base_type(type)); if (sz <= 0) { return 0; @@ -432,6 +435,10 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc string_set_init(&pin_set, specs.count); defer (string_set_destroy(&pin_set)); + StringSet pin_flag_set = {}; + string_set_init(&pin_flag_set, specs.count); + defer (string_set_destroy(&pin_flag_set)); + for (Ast *spec_ : specs) { if (spec_->kind != Ast_AsmSpec) { continue; @@ -444,6 +451,7 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc Entity *other_scratch = nullptr; String pin = {}; + String pin_flag = {}; if (spec->value != nullptr) { if (spec->value->kind == Ast_Ident) { other_scratch = scope_lookup(scope, spec->value->Ident.interned, spec->value->Ident.hash); @@ -467,9 +475,17 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc pin = reg->name.string; if (pin.len != 0) { Operand op = {}; - check_register(asm_ctx, &op, reg); - if (string_set_update(&pin_set, pin)) { - error(spec->value, "Pinned register %%%.*s has already been assigned", LIT(pin)); + if (check_register(asm_ctx, &op, reg)) { + if (reg->flag.string.len) { + GB_ASSERT(pin == "flags"); + pin_flag = reg->flag.string; + if (string_set_update(&pin_flag_set, pin_flag)) { + error(spec->value, "Pinned register flag %%%.*s.%.*s has already been assigned", LIT(pin), LIT(pin_flag)); + } + } + if (string_set_update(&pin_set, pin)) { + error(spec->value, "Pinned register %%%.*s has already been assigned", LIT(pin)); + } } } } @@ -496,6 +512,7 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc ed.param_group = AsmTemplateEntityDeclParamGroup_Scratch; ed.total_index = cast(i32)asm_template_entity_decls->count; ed.pin = pin; + ed.pin_flag = pin_flag; if (other_scratch != nullptr) { // Width-view of another operand: `p0b: u8 = p0`. @@ -632,6 +649,9 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc i->pin = pin; o->pin = pin; + i->pin_flag = pin_flag; + o->pin_flag = pin_flag; + if (other_scratch != nullptr) { GB_ASSERT(spec->value != nullptr); error(spec->value, "Another parameter must be assigned/paired with a scratch parameter declaration, not a tie"); @@ -644,10 +664,26 @@ template gb_internal bool check_register(AsmCtx *asm_ctx, Operand *operand, AstAsmRegister *asm_reg) { String name = asm_reg->name.string; if (asm_reg->flag.kind == Token_Ident) { - // TODO(bill): has flags - if (name != "cc") { + bool ok = true; + i32 width = 0; + String flag = asm_reg->flag.string; + if (name != "flags") { + error(asm_reg->name, "Register flags can only be called on %%flags"); + ok = false; + } else { + i32 bit = asm_ctx->flag_bit_from_name(flag, &width); + if (bit < 0) { + error(asm_reg->flag, "Unknown register %%flags name: %.*s", LIT(flag)); + ok = false; + } } + + operand->type = t_bool; + if (width > 1) { + operand->type = t_u8; + } + return ok; } auto r = asm_ctx->register_lookup(name); diff --git a/src/entity.cpp b/src/entity.cpp index 3ec3860e2..ea5317447 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -186,6 +186,7 @@ struct AsmTemplateEntityDecl { AsmRegClass reg_class; String pin; + String pin_flag; // e.g. %flags.zf i32 total_index; diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 1e36459c8..ff502cf47 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -491,7 +491,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { LLVMValueRef call = LLVMBuildCall2(p->builder, fn_ty, ia, call_args.data, cast(unsigned)call_args.count, ""); - if (false) { + if (true) { // DEBUG PRINT!!! // DEBUG PRINT!!! // DEBUG PRINT!!!