mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-23 13:31:35 +00:00
Support segment overrides on asm memory operands
This commit is contained in:
@@ -1098,6 +1098,26 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext *
|
||||
break;
|
||||
}
|
||||
|
||||
Operand segment_override = {};
|
||||
check_asm_instruction_operand(asm_ctx, ctx, entity, &segment_override, mem_op->segment_override, false);
|
||||
|
||||
if (segment_override.expr == nullptr) {
|
||||
// okay
|
||||
} else if (segment_override.expr->kind == Ast_AsmRegister) {
|
||||
String reg_name = segment_override.expr->AsmRegister.name.string;
|
||||
auto reg = asm_ctx->register_lookup(reg_name);
|
||||
auto reg_class = asm_ctx->reg_class(asm_ctx->register_codes[reg]);
|
||||
if (reg_class != asm_ctx->REG_CLASS_SEG) {
|
||||
gbString s = expr_to_string(segment_override.expr);
|
||||
error(segment_override.expr, "A segment override must be a selector register parameter, got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
} else {
|
||||
gbString s = expr_to_string(segment_override.expr);
|
||||
error(segment_override.expr, "A segment override must be a selector register parameter, got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
Operand base = {};
|
||||
Operand index = {};
|
||||
Operand scale = {};
|
||||
@@ -1107,7 +1127,7 @@ 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,
|
||||
// NOTE(bill): if the base/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;
|
||||
@@ -1129,6 +1149,23 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext *
|
||||
mem_op->index_op = {};
|
||||
}
|
||||
}
|
||||
if (base.expr != nullptr && index.expr == nullptr && scale.expr == nullptr && disp.expr == nullptr) {
|
||||
bool do_swap = base.mode == Addressing_Constant;
|
||||
if (!do_swap) {
|
||||
Entity *param_entity = entity_of_node(base.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 = base;
|
||||
base = {};
|
||||
|
||||
mem_op->disp = mem_op->base;
|
||||
mem_op->base = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
i32 base_w = 0;
|
||||
i32 index_w = 0;
|
||||
|
||||
@@ -146,6 +146,11 @@ struct lbAsmGenerate {
|
||||
case_ast_node(label, AsmLabelDecl, op);
|
||||
asm_string = write_label(asm_string, &label->name->Ident);
|
||||
case_end;
|
||||
|
||||
case_ast_node(reg, AsmRegister, op);
|
||||
asm_string = gb_string_appendc(asm_string, "%");
|
||||
asm_string = gb_string_append_length(asm_string, reg->name.string.text, reg->name.string.len);
|
||||
case_end;
|
||||
default:
|
||||
GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op));
|
||||
break;
|
||||
@@ -287,6 +292,11 @@ 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->segment_override != nullptr) {
|
||||
asm_string = this->write_operand(asm_string, op_number, mem_op->segment_override, flags);
|
||||
asm_string = gb_string_appendc(asm_string, ":");
|
||||
}
|
||||
|
||||
if (mem_op->disp) {
|
||||
u32 disp_flags = flags;
|
||||
disp_flags &= ~WriteOperandFlag_PrintPrefixes;
|
||||
@@ -297,8 +307,9 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
|
||||
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->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) {
|
||||
@@ -657,7 +668,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
|
||||
|
||||
LLVMValueRef call = LLVMBuildCall2(p->builder, fn_ty, ia, call_args.data, cast(unsigned)call_args.count, "");
|
||||
|
||||
if (true) {
|
||||
if (false) {
|
||||
// DEBUG PRINT!!!
|
||||
// DEBUG PRINT!!!
|
||||
// DEBUG PRINT!!!
|
||||
|
||||
@@ -548,6 +548,7 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
|
||||
n->AsmInstruction.operands = clone_ast_array(n->AsmInstruction.operands, f);
|
||||
break;
|
||||
case Ast_AsmMemoryOperand:
|
||||
n->AsmMemoryOperand.segment_override = clone_ast(n->AsmMemoryOperand.segment_override, f);
|
||||
n->AsmMemoryOperand.base = clone_ast(n->AsmMemoryOperand.base, f);
|
||||
n->AsmMemoryOperand.index = clone_ast(n->AsmMemoryOperand.index, f);
|
||||
n->AsmMemoryOperand.scale = clone_ast(n->AsmMemoryOperand.scale, f);
|
||||
@@ -2483,6 +2484,7 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) {
|
||||
case Token_OpenBracket:
|
||||
if (allow_memory_operand) {
|
||||
Token open = expect_token(f, Token_OpenBracket);
|
||||
Ast *segment_override = nullptr;
|
||||
Ast *base = nullptr;
|
||||
Ast *index = nullptr;
|
||||
Ast *scale = nullptr;
|
||||
@@ -2495,6 +2497,16 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) {
|
||||
|
||||
base = parse_asm_operand(f, false);
|
||||
|
||||
if (allow_token(f, Token_Colon)) {
|
||||
// [segment: ...]
|
||||
segment_override = base;
|
||||
if (segment_override != nullptr &&
|
||||
segment_override->kind != Ast_AsmRegister) {
|
||||
error(segment_override, "Expected an asm register as the segment override");
|
||||
}
|
||||
base = parse_asm_operand(f, false);
|
||||
}
|
||||
|
||||
// [base]
|
||||
// [base + index]
|
||||
// [base - index]
|
||||
@@ -2526,16 +2538,17 @@ 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_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;
|
||||
mem->AsmMemoryOperand.open = open;
|
||||
mem->AsmMemoryOperand.segment_override = segment_override;
|
||||
mem->AsmMemoryOperand.base = base;
|
||||
mem->AsmMemoryOperand.index_op = index_op;
|
||||
mem->AsmMemoryOperand.index = index;
|
||||
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;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
@@ -510,6 +510,7 @@ struct AstSplitArgs {
|
||||
}) \
|
||||
AST_KIND(AsmMemoryOperand, "asm memory operand", struct { \
|
||||
Token open; \
|
||||
Ast * segment_override; \
|
||||
Ast * base; \
|
||||
Token index_op; \
|
||||
Ast * index; \
|
||||
|
||||
Reference in New Issue
Block a user