Allow for [base - disp]

This commit is contained in:
gingerBill
2026-08-18 14:11:01 +01:00
parent 6e17e7a2de
commit 12c89ee2bf
4 changed files with 63 additions and 6 deletions

View File

@@ -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;

View File

@@ -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<i32> 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!!!

View File

@@ -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;

View File

@@ -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; \