mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-18 03:12:10 +00:00
Begin work in %flags.zf et al
This commit is contained in:
@@ -219,6 +219,42 @@ main :: proc() {
|
||||
return \"<reg>\";
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -219,6 +219,42 @@ struct Asm_amd64 {
|
||||
return "<reg>";
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 <typename AsmCtx>
|
||||
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);
|
||||
|
||||
@@ -186,6 +186,7 @@ struct AsmTemplateEntityDecl {
|
||||
AsmRegClass reg_class;
|
||||
|
||||
String pin;
|
||||
String pin_flag; // e.g. %flags.zf
|
||||
|
||||
i32 total_index;
|
||||
|
||||
|
||||
@@ -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!!!
|
||||
|
||||
Reference in New Issue
Block a user