add @compile_var("os") and @compile_var("arch")

This commit is contained in:
Andrew Kelley 2016-02-11 18:33:04 -07:00
parent 08eb19456b
commit 2dc4ac0e21
7 changed files with 150 additions and 18 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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