mirror of
https://github.com/ziglang/zig.git
synced 2024-12-03 10:28:48 +00:00
add @compile_var("os") and @compile_var("arch")
This commit is contained in:
parent
08eb19456b
commit
2dc4ac0e21
@ -1108,6 +1108,8 @@ struct CodeGen {
|
||||
TypeTableEntry *entry_num_lit_float;
|
||||
TypeTableEntry *entry_undef;
|
||||
TypeTableEntry *entry_pure_error;
|
||||
TypeTableEntry *entry_os_enum;
|
||||
TypeTableEntry *entry_arch_enum;
|
||||
} builtin_types;
|
||||
|
||||
ZigTarget zig_target;
|
||||
@ -1126,6 +1128,8 @@ struct CodeGen {
|
||||
Buf triple_str;
|
||||
bool is_release_build;
|
||||
bool is_test_build;
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
LLVMZigDIFile *dummy_di_file;
|
||||
bool is_native_target;
|
||||
|
@ -3526,6 +3526,8 @@ static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockCon
|
||||
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
*const_val = *other_const_val;
|
||||
// the condition depends on a compile var, so the entire if statement does too
|
||||
const_val->depends_on_compile_var = true;
|
||||
return result_type;
|
||||
}
|
||||
|
||||
@ -4233,6 +4235,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
const_val->ok = true;
|
||||
const_val->depends_on_compile_var = true;
|
||||
|
||||
if (buf_eql_str(&var_name, "is_big_endian")) {
|
||||
@ -4242,7 +4245,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
||||
} else if (buf_eql_str(&var_name, "is_test")) {
|
||||
return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
|
||||
} else if (buf_eql_str(&var_name, "os")) {
|
||||
zig_panic("TODO");
|
||||
const_val->data.x_enum.tag = g->target_os_index;
|
||||
return g->builtin_types.entry_os_enum;
|
||||
} else if (buf_eql_str(&var_name, "arch")) {
|
||||
const_val->data.x_enum.tag = g->target_arch_index;
|
||||
return g->builtin_types.entry_arch_enum;
|
||||
} else {
|
||||
add_node_error(g, *str_node,
|
||||
buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));
|
||||
@ -4638,17 +4645,18 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
||||
static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
AstNode *expr_node = node->data.switch_expr.expr;
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, expr_node);
|
||||
AstNode **expr_node = &node->data.switch_expr.expr;
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
|
||||
|
||||
int prong_count = node->data.switch_expr.prongs.length;
|
||||
AstNode **peer_nodes = allocate<AstNode*>(prong_count);
|
||||
TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
|
||||
|
||||
bool any_errors = false;
|
||||
if (expr_type->id == TypeTableEntryIdInvalid) {
|
||||
return expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdUnreachable) {
|
||||
add_node_error(g, first_executing_node(expr_node),
|
||||
add_node_error(g, first_executing_node(*expr_node),
|
||||
buf_sprintf("switch on unreachable expression not allowed"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
@ -4666,6 +4674,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
||||
if (prong_node->data.switch_prong.items.length == 0) {
|
||||
if (else_prong) {
|
||||
add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
|
||||
any_errors = true;
|
||||
} else {
|
||||
else_prong = prong_node;
|
||||
}
|
||||
@ -4700,14 +4709,17 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
||||
add_node_error(g, item_node,
|
||||
buf_sprintf("duplicate switch value: '%s'",
|
||||
buf_ptr(type_enum_field->name)));
|
||||
any_errors = true;
|
||||
}
|
||||
} else {
|
||||
add_node_error(g, item_node,
|
||||
buf_sprintf("enum '%s' has no field '%s'",
|
||||
buf_ptr(&expr_type->name), buf_ptr(field_name)));
|
||||
any_errors = true;
|
||||
}
|
||||
} else {
|
||||
add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
|
||||
any_errors = true;
|
||||
}
|
||||
} else {
|
||||
TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);
|
||||
@ -4716,6 +4728,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
||||
if (!const_val->ok) {
|
||||
add_node_error(g, item_node,
|
||||
buf_sprintf("unable to resolve constant expression"));
|
||||
any_errors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4751,11 +4764,64 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("enumeration value '%s' not handled in switch",
|
||||
buf_ptr(expr_type->data.enumeration.fields[i].name)));
|
||||
any_errors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count);
|
||||
|
||||
if (any_errors) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (prong_count == 0) {
|
||||
add_node_error(g, node, buf_sprintf("switch statement has no prongs"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
|
||||
peer_nodes, peer_types, prong_count);
|
||||
|
||||
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
|
||||
if (!expr_val->ok) {
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
if (expr_val->ok && !expr_val->depends_on_compile_var) {
|
||||
add_node_error(g, first_executing_node(*expr_node),
|
||||
buf_sprintf("value is constant; unnecessary switch statement"));
|
||||
}
|
||||
|
||||
if (!expr_val->ok) {
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
|
||||
for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
|
||||
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
|
||||
for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
|
||||
AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
|
||||
if (expr_type->id == TypeTableEntryIdEnum) {
|
||||
TypeEnumField *type_enum_field = item_node->data.symbol_expr.enum_field;
|
||||
if (expr_val->data.x_enum.tag == type_enum_field->value) {
|
||||
*const_val = get_resolved_expr(peer_nodes[prong_i])->const_val;
|
||||
const_val->ok = true;
|
||||
// the target expr depends on a compile var, so the entire if statement does too
|
||||
const_val->depends_on_compile_var = true;
|
||||
return resolved_type;
|
||||
}
|
||||
} else {
|
||||
zig_panic("TODO determine if const exprs are equal");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
|
@ -352,10 +352,11 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
case BuiltinFnIdMinValue:
|
||||
case BuiltinFnIdMaxValue:
|
||||
case BuiltinFnIdMemberCount:
|
||||
case BuiltinFnIdCompileVar:
|
||||
case BuiltinFnIdConstEval:
|
||||
// caught by constant expression eval codegen
|
||||
zig_unreachable();
|
||||
case BuiltinFnIdCompileVar:
|
||||
return nullptr;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -3443,6 +3444,62 @@ static void define_builtin_types(CodeGen *g) {
|
||||
g->builtin_types.entry_i16 = get_int_type(g, true, 16);
|
||||
g->builtin_types.entry_i32 = get_int_type(g, true, 32);
|
||||
g->builtin_types.entry_i64 = get_int_type(g, true, 64);
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@OS");
|
||||
uint32_t field_count = target_os_count();
|
||||
entry->data.enumeration.field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||
TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
|
||||
ZigLLVM_OSType os_type = get_target_os(i);
|
||||
type_enum_field->name = buf_create_from_str(get_target_os_name(os_type));
|
||||
type_enum_field->value = i;
|
||||
|
||||
if (os_type == g->zig_target.os) {
|
||||
g->target_os_index = i;
|
||||
}
|
||||
}
|
||||
entry->data.enumeration.complete = true;
|
||||
|
||||
TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_os_enum = entry;
|
||||
}
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "@Arch");
|
||||
uint32_t field_count = target_arch_count();
|
||||
entry->data.enumeration.field_count = field_count;
|
||||
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||
TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
|
||||
const ArchType *arch_type = get_target_arch(i);
|
||||
type_enum_field->name = buf_alloc();
|
||||
buf_resize(type_enum_field->name, 50);
|
||||
get_arch_name(buf_ptr(type_enum_field->name), arch_type);
|
||||
buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name)));
|
||||
|
||||
type_enum_field->value = i;
|
||||
|
||||
if (arch_type->arch == g->zig_target.arch.arch &&
|
||||
arch_type->sub_arch == g->zig_target.arch.sub_arch)
|
||||
{
|
||||
g->target_arch_index = i;
|
||||
}
|
||||
}
|
||||
entry->data.enumeration.complete = true;
|
||||
|
||||
TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
|
||||
entry->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
g->builtin_types.entry_arch_enum = entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,11 +58,11 @@ static int print_target_list(FILE *f) {
|
||||
int arch_count = target_arch_count();
|
||||
for (int arch_i = 0; arch_i < arch_count; arch_i += 1) {
|
||||
const ArchType *arch = get_target_arch(arch_i);
|
||||
const char *sub_arch_str = (arch->sub_arch == ZigLLVM_NoSubArch) ?
|
||||
"" : ZigLLVMGetSubArchTypeName(arch->sub_arch);
|
||||
char arch_name[50];
|
||||
get_arch_name(arch_name, arch);
|
||||
const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
|
||||
" (native)" : "";
|
||||
fprintf(f, " %s%s%s\n", ZigLLVMGetArchTypeName(arch->arch), sub_arch_str, native_str);
|
||||
fprintf(f, " %s%s\n", arch_name, native_str);
|
||||
}
|
||||
|
||||
fprintf(f, "\nOperating Systems:\n");
|
||||
|
@ -181,13 +181,20 @@ void get_unknown_target(ZigTarget *target) {
|
||||
target->oformat = ZigLLVM_UnknownObjectFormat;
|
||||
}
|
||||
|
||||
static void get_arch_name_raw(char *out_str, ZigLLVM_ArchType arch, ZigLLVM_SubArchType sub_arch) {
|
||||
const char *sub_str = (sub_arch == ZigLLVM_NoSubArch) ? "" : ZigLLVMGetSubArchTypeName(sub_arch);
|
||||
sprintf(out_str, "%s%s", ZigLLVMGetArchTypeName(arch), sub_str);
|
||||
}
|
||||
|
||||
void get_arch_name(char *out_str, const ArchType *arch) {
|
||||
return get_arch_name_raw(out_str, arch->arch, arch->sub_arch);
|
||||
}
|
||||
|
||||
int parse_target_arch(const char *str, ArchType *out_arch) {
|
||||
for (int i = 0; i < array_length(arch_list); i += 1) {
|
||||
const ArchType *arch = &arch_list[i];
|
||||
char arch_name[50];
|
||||
const char *sub_str = (arch->sub_arch == ZigLLVM_NoSubArch) ?
|
||||
"" : ZigLLVMGetSubArchTypeName(arch->sub_arch);
|
||||
sprintf(arch_name, "%s%s", ZigLLVMGetArchTypeName(arch->arch), sub_str);
|
||||
get_arch_name_raw(arch_name, arch->arch, arch->sub_arch);
|
||||
if (strcmp(arch_name, str) == 0) {
|
||||
*out_arch = *arch;
|
||||
return 0;
|
||||
|
@ -27,6 +27,7 @@ struct ZigTarget {
|
||||
|
||||
int target_arch_count(void);
|
||||
const ArchType *get_target_arch(int index);
|
||||
void get_arch_name(char *out_str, const ArchType *arch);
|
||||
|
||||
int target_vendor_count(void);
|
||||
ZigLLVM_VendorType get_target_vendor(int index);
|
||||
|
@ -308,11 +308,6 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) {
|
||||
#attribute("test")
|
||||
fn switch_on_enum() {
|
||||
const fruit = Fruit.Orange;
|
||||
switch (fruit) {
|
||||
Apple => unreachable{},
|
||||
Orange => {},
|
||||
Banana => unreachable{},
|
||||
}
|
||||
non_const_switch_on_enum(fruit);
|
||||
}
|
||||
enum Fruit {
|
||||
@ -330,7 +325,9 @@ fn non_const_switch_on_enum(fruit: Fruit) {
|
||||
|
||||
#attribute("test")
|
||||
fn switch_statement() {
|
||||
const foo = SwitchStatmentFoo.C;
|
||||
non_const_switch(SwitchStatmentFoo.C);
|
||||
}
|
||||
fn non_const_switch(foo: SwitchStatmentFoo) {
|
||||
const val: i32 = switch (foo) {
|
||||
A => 1,
|
||||
B => 2,
|
||||
|
Loading…
Reference in New Issue
Block a user