mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-18 03:12:10 +00:00
Allow (parent scope) constants within asm templates
This commit is contained in:
@@ -447,14 +447,14 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc
|
||||
|
||||
GB_ASSERT(spec->name->kind == Ast_Ident);
|
||||
|
||||
Entity *input = scope_lookup(scope, spec->name->Ident.interned, spec->name->Ident.hash);
|
||||
Entity *input = scope_lookup_current(scope, spec->name->Ident.interned, spec->name->Ident.hash);
|
||||
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);
|
||||
other_scratch = scope_lookup_current(scope, spec->value->Ident.interned, spec->value->Ident.hash);
|
||||
if (other_scratch) {
|
||||
auto group = check_asm_find_group(other_scratch, *asm_template_entity_decls, nullptr);
|
||||
if (!group) {
|
||||
@@ -621,7 +621,7 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc
|
||||
error(spec->name, "Undefined parameter declaration '%.*s'", LIT(spec->name->Ident.token.string));
|
||||
continue;
|
||||
}
|
||||
Entity *output = scope_lookup(scope, spec->tied_name->Ident.interned, spec->tied_name->Ident.hash);
|
||||
Entity *output = scope_lookup_current(scope, spec->tied_name->Ident.interned, spec->tied_name->Ident.hash);
|
||||
if (output == nullptr) {
|
||||
error(spec->name, "Undefined parameter declaration '%.*s'", LIT(spec->name->Ident.token.string));
|
||||
continue;
|
||||
@@ -1038,14 +1038,28 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext *
|
||||
|
||||
switch (expr->kind) {
|
||||
case_ast_node(i, Ident, expr);
|
||||
Entity *found = scope_lookup(param_scope, i->interned, i->hash);
|
||||
if (found == nullptr) {
|
||||
error(expr, "Undeclared asm parameter '%.*s'", LIT(i->token.string));
|
||||
Entity *found = scope_lookup_current(param_scope, i->interned, i->hash);
|
||||
if (found != nullptr) {
|
||||
i->entity = found;
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = found->type;
|
||||
return;
|
||||
}
|
||||
i->entity = found;
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = found->type;
|
||||
found = scope_lookup(param_scope->parent, i->interned, i->hash);
|
||||
if (found != nullptr) {
|
||||
if (found->kind == Entity_Constant) {
|
||||
i->entity = found;
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = found->Constant.value;
|
||||
operand->type = found->type;
|
||||
|
||||
add_type_and_value(ctx, expr, operand->mode, operand->type, operand->value);
|
||||
} else {
|
||||
error(expr, "Only asm parameters or constants are allowed to be used within an 'asm' template");
|
||||
}
|
||||
} else {
|
||||
error(expr, "Undeclared asm parameter or constant '%.*s'", LIT(i->token.string));
|
||||
}
|
||||
return;
|
||||
case_end;
|
||||
case_ast_node(bl, BasicLit, expr);
|
||||
@@ -1286,11 +1300,13 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext *
|
||||
case_end;
|
||||
case_ast_node(label, AsmLabelDecl, expr);
|
||||
ast_node(name, Ident, label->name);
|
||||
Entity *found = scope_lookup(label_scope, name->interned, name->hash);
|
||||
Entity *found = scope_lookup_current(label_scope, name->interned, name->hash);
|
||||
if (found == nullptr) {
|
||||
error(expr, "Undeclared asm label '.%.*s'", LIT(name->token.string));
|
||||
}
|
||||
name->entity = found;
|
||||
|
||||
add_type_and_value(ctx, expr, Addressing_Value, found->type, {});
|
||||
return;
|
||||
case_end;
|
||||
}
|
||||
@@ -1321,8 +1337,8 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
}
|
||||
AstProcType *pt = &at->signature->ProcType;
|
||||
|
||||
ate->param_scope = create_scope(nullptr, nullptr);
|
||||
ate->label_scope = create_scope(nullptr, nullptr);
|
||||
ate->param_scope = create_scope(ctx->info, ctx->scope);
|
||||
ate->label_scope = create_scope(ctx->info, ctx->scope);
|
||||
|
||||
ate->decls.allocator = heap_allocator();
|
||||
|
||||
|
||||
@@ -39,11 +39,64 @@ struct lbAsmGenerate {
|
||||
return &op;
|
||||
}
|
||||
}
|
||||
GB_PANIC("Could not find asm entity %s", LIT(parameter->token.string));
|
||||
GB_PANIC("Could not find asm entity %.*s", LIT(parameter->token.string));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gbString write_constant_operand(gbString asm_string, Ast *op, u32 flags) {
|
||||
GB_ASSERT(op->tav.mode == Addressing_Constant);
|
||||
|
||||
op->tav.value = exact_value_to_integer(op->tav.value);
|
||||
ExactValue ev = op->tav.value;
|
||||
GB_ASSERT(ev.kind != ExactValue_Invalid);
|
||||
switch (ev.kind) {
|
||||
case ExactValue_Integer: {
|
||||
i64 val = exact_value_to_i64(ev);
|
||||
if (flags & WriteOperandFlag_IsScale) {
|
||||
switch (val) {
|
||||
case 1: case 2: case 4: case 8:
|
||||
// okay
|
||||
break;
|
||||
default:
|
||||
error(op, "A scale must be a constant integer or an immediate with the value 1, 2, 4, or 8, got %lld", cast(long long)val);
|
||||
break;
|
||||
}
|
||||
} else if (flags & WriteOperandFlag_IsScaleLog2) {
|
||||
switch (val) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
// NOTE(bill): AMD64 only supports full scales
|
||||
val = (cast(i64)1)<<val;
|
||||
break;
|
||||
default:
|
||||
error(op, "A shifting scale must be a constant integer or an immediate with the value 0, 1, 2, or 3, got %lld", cast(long long)val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & WriteOperandFlag_PrintPrefixes) {
|
||||
asm_string = gb_string_appendc(asm_string, "$$");
|
||||
}
|
||||
|
||||
asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)val);
|
||||
break;
|
||||
}
|
||||
case ExactValue_Float:
|
||||
error(op, "Floating-point literals that cannot be represented as an integer are not supported within asm operands");
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Unsupported asm immediate literal %s", expr_to_string(op));
|
||||
break;
|
||||
}
|
||||
|
||||
return asm_string;
|
||||
}
|
||||
|
||||
|
||||
gbString write_operand(gbString asm_string, Array<i32> op_number, Ast *op, u32 flags) {
|
||||
if (op->tav.mode == Addressing_Constant) {
|
||||
return write_constant_operand(asm_string, op, flags);
|
||||
}
|
||||
|
||||
switch (op->kind) {
|
||||
case_ast_node(i, Ident, op);
|
||||
Entity *e = entity_of_node(op);
|
||||
@@ -75,47 +128,7 @@ struct lbAsmGenerate {
|
||||
case_end;
|
||||
|
||||
case_ast_node(bl, BasicLit, op);
|
||||
op->tav.value = exact_value_to_integer(op->tav.value);
|
||||
ExactValue ev = op->tav.value;
|
||||
GB_ASSERT(ev.kind != ExactValue_Invalid);
|
||||
switch (ev.kind) {
|
||||
case ExactValue_Integer: {
|
||||
i64 val = exact_value_to_i64(ev);
|
||||
if (flags & WriteOperandFlag_IsScale) {
|
||||
switch (val) {
|
||||
case 1: case 2: case 4: case 8:
|
||||
// okay
|
||||
break;
|
||||
default:
|
||||
error(op, "A scale must be a constant integer or an immediate with the value 1, 2, 4, or 8, got %lld", cast(long long)val);
|
||||
break;
|
||||
}
|
||||
} else if (flags & WriteOperandFlag_IsScaleLog2) {
|
||||
switch (val) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
// NOTE(bill): AMD64 only supports full scales
|
||||
val = (cast(i64)1)<<val;
|
||||
break;
|
||||
default:
|
||||
error(op, "A shifting scale must be a constant integer or an immediate with the value 0, 1, 2, or 3, got %lld", cast(long long)val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & WriteOperandFlag_PrintPrefixes) {
|
||||
asm_string = gb_string_appendc(asm_string, "$$");
|
||||
}
|
||||
|
||||
asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)val);
|
||||
break;
|
||||
}
|
||||
case ExactValue_Float:
|
||||
error(op, "Floating-point literals that cannot be represented as an integer are not supported within asm operands");
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Unsupported asm immediate literal %s", expr_to_string(op));
|
||||
break;
|
||||
}
|
||||
GB_PANIC("NOTE(bill): this should have been handled above");
|
||||
case_end;
|
||||
|
||||
case_ast_node(label, AsmLabelDecl, op);
|
||||
@@ -207,6 +220,9 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
|
||||
GB_ASSERT(instr->valid_form_index >= 0);
|
||||
// Otherwise derive from the matched form's operand widths.
|
||||
auto forms = g_asm_amd64.encoding_forms(instr->mnemonic);
|
||||
if (forms.count <= 1) {
|
||||
return 0;
|
||||
}
|
||||
auto &form = forms[instr->valid_form_index];
|
||||
|
||||
i32 width = 0;
|
||||
@@ -224,6 +240,18 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
|
||||
any_vector = true;
|
||||
continue; // xmm/ymm/zmm/k forms take no b/w/l/q suffix
|
||||
}
|
||||
|
||||
// Only register and memory operands contribute an operand-size suffix.
|
||||
// Relative branch targets (OP_REL8/REL32), immediates (OP_IMM*), and
|
||||
// labels are NOT operand sizes -- jl/jmp/call/setcc must never get a
|
||||
// b/w/l/q suffix from their displacement/immediate.
|
||||
AsmOperandKind kind = g_asm_amd64.kind_from_operand_type(ot);
|
||||
if (kind != AsmOperand_Register &&
|
||||
kind != AsmOperand_Memory &&
|
||||
kind != AsmOperand_Register_Or_Memory) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i32 w = g_asm_amd64.operand_type_bit_width(ot);
|
||||
if (w == 8 || w == 16 || w == 32 || w == 64) {
|
||||
width = gb_max(width, w); // GP/memory width
|
||||
|
||||
Reference in New Issue
Block a user