From 12c89ee2bfa2664f583bc008ca4049568000e20a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Aug 2026 14:11:01 +0100 Subject: [PATCH] Allow for `[base - disp]` --- src/check_asm.cpp | 23 +++++++++++++++++++++++ src/llvm_backend_asm.cpp | 29 ++++++++++++++++++++++++++--- src/parser.cpp | 15 ++++++++++++--- src/parser.hpp | 2 ++ 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/check_asm.cpp b/src/check_asm.cpp index ce15e2cd1..ee79c240d 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -1107,6 +1107,29 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext * check_asm_instruction_operand(asm_ctx, ctx, entity, &scale, mem_op->scale, false); check_asm_instruction_operand(asm_ctx, ctx, entity, &disp, mem_op->disp, false); + // NOTE(bill): if the index is actually an immediate and there is no scale nor disp, + // then treat it as a disp, and modify the AST too + if (index.expr != nullptr && scale.expr == nullptr && disp.expr == nullptr) { + bool do_swap = index.mode == Addressing_Constant; + if (!do_swap) { + Entity *param_entity = entity_of_node(index.expr); + if (param_entity != nullptr && param_entity->kind == Entity_Variable) { + auto kind = check_asm_find_kind(param_entity, ate->decls); + do_swap = kind == AsmTemplateEntityDecl_Immediate; + } + } + if (do_swap) { + disp = index; + index = {}; + + mem_op->disp = mem_op->index; + mem_op->index = nullptr; + + mem_op->disp_op = mem_op->index_op; + mem_op->index_op = {}; + } + } + i32 base_w = 0; i32 index_w = 0; bool have_base = false; diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 4016ad839..b77cf83ae 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -8,6 +8,9 @@ struct lbAsmGenerate { WriteOperandFlag_IsScale = 1<<1, WriteOperandFlag_IsScaleLog2 = 1<<2, + WriteOperandFlag_Negate = 1<<3, + + WriteOperandFlag_NONE = 0, WriteOperandFlag_DEFAULT = WriteOperandFlag_PrintPrefixes, }; @@ -77,6 +80,10 @@ struct lbAsmGenerate { asm_string = gb_string_appendc(asm_string, "$$"); } + if (flags & WriteOperandFlag_Negate) { + val = -val; + } + asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)val); break; } @@ -97,6 +104,11 @@ struct lbAsmGenerate { return write_constant_operand(asm_string, op, flags); } + if (flags & WriteOperandFlag_Negate) { + flags &= ~WriteOperandFlag_Negate; + asm_string = gb_string_appendc(asm_string, "-"); + } + switch (op->kind) { case_ast_node(i, Ident, op); Entity *e = entity_of_node(op); @@ -276,14 +288,25 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { gbString write_memory_operand(gbString asm_string, Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { if (mem_op->disp) { - asm_string = this->write_operand(asm_string, op_number, mem_op->disp, flags&~WriteOperandFlag_PrintPrefixes); + u32 disp_flags = flags; + disp_flags &= ~WriteOperandFlag_PrintPrefixes; + if (mem_op->disp_op.kind == Token_Sub) { + disp_flags |= WriteOperandFlag_Negate; + } + + asm_string = this->write_operand(asm_string, op_number, mem_op->disp, disp_flags); } asm_string = gb_string_appendc(asm_string, "("); GB_ASSERT(mem_op->base != nullptr); asm_string = this->write_operand(asm_string, op_number, mem_op->base, flags); if (mem_op->index) { + u32 index_flags = flags; + if (mem_op->index_op.kind == Token_Sub) { + index_flags |= WriteOperandFlag_Negate; + } asm_string = gb_string_appendc(asm_string, ","); - asm_string = this->write_operand(asm_string, op_number, mem_op->index, flags); + asm_string = this->write_operand(asm_string, op_number, mem_op->index, index_flags); + if (mem_op->scale) { asm_string = gb_string_appendc(asm_string, ","); switch (mem_op->scale_op.kind) { @@ -634,7 +657,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!!! diff --git a/src/parser.cpp b/src/parser.cpp index 99175c3fa..cb84d7e10 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2489,16 +2489,21 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) { Ast *disp = nullptr; Ast *type = nullptr; + Token index_op = {}; Token scale_op = {}; + Token disp_op = {}; base = parse_asm_operand(f, false); // [base] // [base + index] + // [base - index] // [base + index + disp] // [base + index*scale] // *, <<, >> // [base + index*scale + disp] - if (allow_token(f, Token_Add)) { + if (allow_token(f, Token_Add) || + allow_token(f, Token_Sub)) { + index_op = f->prev_token; index = parse_asm_operand(f, false); if (allow_token(f, Token_Mul) || allow_token(f, Token_Shl) || @@ -2506,7 +2511,9 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) { scale_op = f->prev_token; scale = parse_asm_operand(f, false); } - if (allow_token(f, Token_Add)) { + if (allow_token(f, Token_Add) || + allow_token(f, Token_Sub)) { + disp_op = f->prev_token; disp = parse_asm_operand(f, false); } } @@ -2521,9 +2528,11 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) { Ast *mem = alloc_ast_node(f, Ast_AsmMemoryOperand); mem->AsmMemoryOperand.open = open; mem->AsmMemoryOperand.base = base; + mem->AsmMemoryOperand.index_op = index_op; mem->AsmMemoryOperand.index = index; - mem->AsmMemoryOperand.scale = scale; mem->AsmMemoryOperand.scale_op = scale_op; + mem->AsmMemoryOperand.scale = scale; + mem->AsmMemoryOperand.disp_op = disp_op; mem->AsmMemoryOperand.disp = disp; mem->AsmMemoryOperand.close = close; mem->AsmMemoryOperand.type = type; diff --git a/src/parser.hpp b/src/parser.hpp index e945cadc3..8b6b72278 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -511,9 +511,11 @@ struct AstSplitArgs { AST_KIND(AsmMemoryOperand, "asm memory operand", struct { \ Token open; \ Ast * base; \ + Token index_op; \ Ast * index; \ Token scale_op; \ Ast * scale; \ + Token disp_op; \ Ast * disp; \ Ast * type; \ Token close; \