authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-11 18:33:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-11 18:33:04-07:00
log2dc4ac0e21939c440135131212ac564197c61e30
tree8e34d358b152bb82fed363609a49711070d930ea
parent08eb19456b319cc5b0c287773d52850f12f2bcb5

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


7 files changed, 150 insertions(+), 18 deletions(-)

src/all_types.hpp+4
...@@ -1108,6 +1108,8 @@ struct CodeGen {...@@ -1108,6 +1108,8 @@ struct CodeGen {
1108 TypeTableEntry *entry_num_lit_float;1108 TypeTableEntry *entry_num_lit_float;
1109 TypeTableEntry *entry_undef;1109 TypeTableEntry *entry_undef;
1110 TypeTableEntry *entry_pure_error;1110 TypeTableEntry *entry_pure_error;
1111 TypeTableEntry *entry_os_enum;
1112 TypeTableEntry *entry_arch_enum;
1111 } builtin_types;1113 } builtin_types;
11121114
1113 ZigTarget zig_target;1115 ZigTarget zig_target;
...@@ -1126,6 +1128,8 @@ struct CodeGen {...@@ -1126,6 +1128,8 @@ struct CodeGen {
1126 Buf triple_str;1128 Buf triple_str;
1127 bool is_release_build;1129 bool is_release_build;
1128 bool is_test_build;1130 bool is_test_build;
1131 uint32_t target_os_index;
1132 uint32_t target_arch_index;
1129 LLVMTargetMachineRef target_machine;1133 LLVMTargetMachineRef target_machine;
1130 LLVMZigDIFile *dummy_di_file;1134 LLVMZigDIFile *dummy_di_file;
1131 bool is_native_target;1135 bool is_native_target;
src/analyze.cpp+71-5
...@@ -3526,6 +3526,8 @@ static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockCon...@@ -3526,6 +3526,8 @@ static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockCon
35263526
3527 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;3527 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
3528 *const_val = *other_const_val;3528 *const_val = *other_const_val;
3529 // the condition depends on a compile var, so the entire if statement does too
3530 const_val->depends_on_compile_var = true;
3529 return result_type;3531 return result_type;
3530}3532}
35313533
...@@ -4233,6 +4235,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -4233,6 +4235,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
4233 }4235 }
42344236
4235 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;4237 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
4238 const_val->ok = true;
4236 const_val->depends_on_compile_var = true;4239 const_val->depends_on_compile_var = true;
42374240
4238 if (buf_eql_str(&var_name, "is_big_endian")) {4241 if (buf_eql_str(&var_name, "is_big_endian")) {
...@@ -4242,7 +4245,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -4242,7 +4245,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
4242 } else if (buf_eql_str(&var_name, "is_test")) {4245 } else if (buf_eql_str(&var_name, "is_test")) {
4243 return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);4246 return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
4244 } else if (buf_eql_str(&var_name, "os")) {4247 } else if (buf_eql_str(&var_name, "os")) {
4245 zig_panic("TODO");4248 const_val->data.x_enum.tag = g->target_os_index;
4249 return g->builtin_types.entry_os_enum;
4250 } else if (buf_eql_str(&var_name, "arch")) {
4251 const_val->data.x_enum.tag = g->target_arch_index;
4252 return g->builtin_types.entry_arch_enum;
4246 } else {4253 } else {
4247 add_node_error(g, *str_node,4254 add_node_error(g, *str_node,
4248 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));4255 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));
...@@ -4638,17 +4645,18 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -4638,17 +4645,18 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
4638static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,4645static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
4639 TypeTableEntry *expected_type, AstNode *node)4646 TypeTableEntry *expected_type, AstNode *node)
4640{4647{
4641 AstNode *expr_node = node->data.switch_expr.expr;4648 AstNode **expr_node = &node->data.switch_expr.expr;
4642 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, expr_node);4649 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
46434650
4644 int prong_count = node->data.switch_expr.prongs.length;4651 int prong_count = node->data.switch_expr.prongs.length;
4645 AstNode **peer_nodes = allocate<AstNode*>(prong_count);4652 AstNode **peer_nodes = allocate<AstNode*>(prong_count);
4646 TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);4653 TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
46474654
4655 bool any_errors = false;
4648 if (expr_type->id == TypeTableEntryIdInvalid) {4656 if (expr_type->id == TypeTableEntryIdInvalid) {
4649 return expr_type;4657 return expr_type;
4650 } else if (expr_type->id == TypeTableEntryIdUnreachable) {4658 } else if (expr_type->id == TypeTableEntryIdUnreachable) {
4651 add_node_error(g, first_executing_node(expr_node),4659 add_node_error(g, first_executing_node(*expr_node),
4652 buf_sprintf("switch on unreachable expression not allowed"));4660 buf_sprintf("switch on unreachable expression not allowed"));
4653 return g->builtin_types.entry_invalid;4661 return g->builtin_types.entry_invalid;
4654 } else {4662 } else {
...@@ -4666,6 +4674,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4666,6 +4674,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4666 if (prong_node->data.switch_prong.items.length == 0) {4674 if (prong_node->data.switch_prong.items.length == 0) {
4667 if (else_prong) {4675 if (else_prong) {
4668 add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));4676 add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
4677 any_errors = true;
4669 } else {4678 } else {
4670 else_prong = prong_node;4679 else_prong = prong_node;
4671 }4680 }
...@@ -4700,14 +4709,17 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4700,14 +4709,17 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4700 add_node_error(g, item_node,4709 add_node_error(g, item_node,
4701 buf_sprintf("duplicate switch value: '%s'",4710 buf_sprintf("duplicate switch value: '%s'",
4702 buf_ptr(type_enum_field->name)));4711 buf_ptr(type_enum_field->name)));
4712 any_errors = true;
4703 }4713 }
4704 } else {4714 } else {
4705 add_node_error(g, item_node,4715 add_node_error(g, item_node,
4706 buf_sprintf("enum '%s' has no field '%s'",4716 buf_sprintf("enum '%s' has no field '%s'",
4707 buf_ptr(&expr_type->name), buf_ptr(field_name)));4717 buf_ptr(&expr_type->name), buf_ptr(field_name)));
4718 any_errors = true;
4708 }4719 }
4709 } else {4720 } else {
4710 add_node_error(g, item_node, buf_sprintf("expected enum tag name"));4721 add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
4722 any_errors = true;
4711 }4723 }
4712 } else {4724 } else {
4713 TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);4725 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,...@@ -4716,6 +4728,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4716 if (!const_val->ok) {4728 if (!const_val->ok) {
4717 add_node_error(g, item_node,4729 add_node_error(g, item_node,
4718 buf_sprintf("unable to resolve constant expression"));4730 buf_sprintf("unable to resolve constant expression"));
4731 any_errors = true;
4719 }4732 }
4720 }4733 }
4721 }4734 }
...@@ -4751,11 +4764,64 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4751,11 +4764,64 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4751 add_node_error(g, node,4764 add_node_error(g, node,
4752 buf_sprintf("enumeration value '%s' not handled in switch",4765 buf_sprintf("enumeration value '%s' not handled in switch",
4753 buf_ptr(expr_type->data.enumeration.fields[i].name)));4766 buf_ptr(expr_type->data.enumeration.fields[i].name)));
4767 any_errors = true;
4768 }
4769 }
4770 }
4771 }
4772
4773 if (any_errors) {
4774 return g->builtin_types.entry_invalid;
4775 }
4776
4777 if (prong_count == 0) {
4778 add_node_error(g, node, buf_sprintf("switch statement has no prongs"));
4779 return g->builtin_types.entry_invalid;
4780 }
4781
4782 TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
4783 peer_nodes, peer_types, prong_count);
4784
4785 if (resolved_type->id == TypeTableEntryIdInvalid) {
4786 return resolved_type;
4787 }
4788
4789 ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
4790 if (!expr_val->ok) {
4791 return resolved_type;
4792 }
4793
4794 if (expr_val->ok && !expr_val->depends_on_compile_var) {
4795 add_node_error(g, first_executing_node(*expr_node),
4796 buf_sprintf("value is constant; unnecessary switch statement"));
4797 }
4798
4799 if (!expr_val->ok) {
4800 return resolved_type;
4801 }
4802
4803 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
4804
4805 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4806 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4807 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
4808 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
4809 if (expr_type->id == TypeTableEntryIdEnum) {
4810 TypeEnumField *type_enum_field = item_node->data.symbol_expr.enum_field;
4811 if (expr_val->data.x_enum.tag == type_enum_field->value) {
4812 *const_val = get_resolved_expr(peer_nodes[prong_i])->const_val;
4813 const_val->ok = true;
4814 // the target expr depends on a compile var, so the entire if statement does too
4815 const_val->depends_on_compile_var = true;
4816 return resolved_type;
4754 }4817 }
4818 } else {
4819 zig_panic("TODO determine if const exprs are equal");
4755 }4820 }
4756 }4821 }
4757 }4822 }
4758 return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count);4823
4824 zig_unreachable();
4759}4825}
47604826
4761static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,4827static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
src/codegen.cpp+58-1
...@@ -352,10 +352,11 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -352,10 +352,11 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
352 case BuiltinFnIdMinValue:352 case BuiltinFnIdMinValue:
353 case BuiltinFnIdMaxValue:353 case BuiltinFnIdMaxValue:
354 case BuiltinFnIdMemberCount:354 case BuiltinFnIdMemberCount:
355 case BuiltinFnIdCompileVar:
356 case BuiltinFnIdConstEval:355 case BuiltinFnIdConstEval:
357 // caught by constant expression eval codegen356 // caught by constant expression eval codegen
358 zig_unreachable();357 zig_unreachable();
358 case BuiltinFnIdCompileVar:
359 return nullptr;
359 }360 }
360 zig_unreachable();361 zig_unreachable();
361}362}
...@@ -3443,6 +3444,62 @@ static void define_builtin_types(CodeGen *g) {...@@ -3443,6 +3444,62 @@ static void define_builtin_types(CodeGen *g) {
3443 g->builtin_types.entry_i16 = get_int_type(g, true, 16);3444 g->builtin_types.entry_i16 = get_int_type(g, true, 16);
3444 g->builtin_types.entry_i32 = get_int_type(g, true, 32);3445 g->builtin_types.entry_i32 = get_int_type(g, true, 32);
3445 g->builtin_types.entry_i64 = get_int_type(g, true, 64);3446 g->builtin_types.entry_i64 = get_int_type(g, true, 64);
3447
3448 {
3449 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3450 entry->zero_bits = true; // only allowed at compile time
3451 buf_init_from_str(&entry->name, "@OS");
3452 uint32_t field_count = target_os_count();
3453 entry->data.enumeration.field_count = field_count;
3454 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
3455 for (uint32_t i = 0; i < field_count; i += 1) {
3456 TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
3457 ZigLLVM_OSType os_type = get_target_os(i);
3458 type_enum_field->name = buf_create_from_str(get_target_os_name(os_type));
3459 type_enum_field->value = i;
3460
3461 if (os_type == g->zig_target.os) {
3462 g->target_os_index = i;
3463 }
3464 }
3465 entry->data.enumeration.complete = true;
3466
3467 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
3468 entry->data.enumeration.tag_type = tag_type_entry;
3469
3470 g->builtin_types.entry_os_enum = entry;
3471 }
3472
3473 {
3474 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3475 entry->zero_bits = true; // only allowed at compile time
3476 buf_init_from_str(&entry->name, "@Arch");
3477 uint32_t field_count = target_arch_count();
3478 entry->data.enumeration.field_count = field_count;
3479 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
3480 for (uint32_t i = 0; i < field_count; i += 1) {
3481 TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
3482 const ArchType *arch_type = get_target_arch(i);
3483 type_enum_field->name = buf_alloc();
3484 buf_resize(type_enum_field->name, 50);
3485 get_arch_name(buf_ptr(type_enum_field->name), arch_type);
3486 buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name)));
3487
3488 type_enum_field->value = i;
3489
3490 if (arch_type->arch == g->zig_target.arch.arch &&
3491 arch_type->sub_arch == g->zig_target.arch.sub_arch)
3492 {
3493 g->target_arch_index = i;
3494 }
3495 }
3496 entry->data.enumeration.complete = true;
3497
3498 TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
3499 entry->data.enumeration.tag_type = tag_type_entry;
3500
3501 g->builtin_types.entry_arch_enum = entry;
3502 }
3446}3503}
34473504
34483505
src/main.cpp+3-3
...@@ -58,11 +58,11 @@ static int print_target_list(FILE *f) {...@@ -58,11 +58,11 @@ static int print_target_list(FILE *f) {
58 int arch_count = target_arch_count();58 int arch_count = target_arch_count();
59 for (int arch_i = 0; arch_i < arch_count; arch_i += 1) {59 for (int arch_i = 0; arch_i < arch_count; arch_i += 1) {
60 const ArchType *arch = get_target_arch(arch_i);60 const ArchType *arch = get_target_arch(arch_i);
61 const char *sub_arch_str = (arch->sub_arch == ZigLLVM_NoSubArch) ?61 char arch_name[50];
62 "" : ZigLLVMGetSubArchTypeName(arch->sub_arch);62 get_arch_name(arch_name, arch);
63 const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?63 const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
64 " (native)" : "";64 " (native)" : "";
65 fprintf(f, " %s%s%s\n", ZigLLVMGetArchTypeName(arch->arch), sub_arch_str, native_str);65 fprintf(f, " %s%s\n", arch_name, native_str);
66 }66 }
6767
68 fprintf(f, "\nOperating Systems:\n");68 fprintf(f, "\nOperating Systems:\n");
src/target.cpp+10-3
...@@ -181,13 +181,20 @@ void get_unknown_target(ZigTarget *target) {...@@ -181,13 +181,20 @@ void get_unknown_target(ZigTarget *target) {
181 target->oformat = ZigLLVM_UnknownObjectFormat;181 target->oformat = ZigLLVM_UnknownObjectFormat;
182}182}
183183
184static void get_arch_name_raw(char *out_str, ZigLLVM_ArchType arch, ZigLLVM_SubArchType sub_arch) {
185 const char *sub_str = (sub_arch == ZigLLVM_NoSubArch) ? "" : ZigLLVMGetSubArchTypeName(sub_arch);
186 sprintf(out_str, "%s%s", ZigLLVMGetArchTypeName(arch), sub_str);
187}
188
189void get_arch_name(char *out_str, const ArchType *arch) {
190 return get_arch_name_raw(out_str, arch->arch, arch->sub_arch);
191}
192
184int parse_target_arch(const char *str, ArchType *out_arch) {193int parse_target_arch(const char *str, ArchType *out_arch) {
185 for (int i = 0; i < array_length(arch_list); i += 1) {194 for (int i = 0; i < array_length(arch_list); i += 1) {
186 const ArchType *arch = &arch_list[i];195 const ArchType *arch = &arch_list[i];
187 char arch_name[50];196 char arch_name[50];
188 const char *sub_str = (arch->sub_arch == ZigLLVM_NoSubArch) ?197 get_arch_name_raw(arch_name, arch->arch, arch->sub_arch);
189 "" : ZigLLVMGetSubArchTypeName(arch->sub_arch);
190 sprintf(arch_name, "%s%s", ZigLLVMGetArchTypeName(arch->arch), sub_str);
191 if (strcmp(arch_name, str) == 0) {198 if (strcmp(arch_name, str) == 0) {
192 *out_arch = *arch;199 *out_arch = *arch;
193 return 0;200 return 0;
src/target.hpp+1
...@@ -27,6 +27,7 @@ struct ZigTarget {...@@ -27,6 +27,7 @@ struct ZigTarget {
2727
28int target_arch_count(void);28int target_arch_count(void);
29const ArchType *get_target_arch(int index);29const ArchType *get_target_arch(int index);
30void get_arch_name(char *out_str, const ArchType *arch);
3031
31int target_vendor_count(void);32int target_vendor_count(void);
32ZigLLVM_VendorType get_target_vendor(int index);33ZigLLVM_VendorType get_target_vendor(int index);
test/self_hosted.zig+3-6
...@@ -308,11 +308,6 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) {...@@ -308,11 +308,6 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) {
308#attribute("test")308#attribute("test")
309fn switch_on_enum() {309fn switch_on_enum() {
310 const fruit = Fruit.Orange;310 const fruit = Fruit.Orange;
311 switch (fruit) {
312 Apple => unreachable{},
313 Orange => {},
314 Banana => unreachable{},
315 }
316 non_const_switch_on_enum(fruit);311 non_const_switch_on_enum(fruit);
317}312}
318enum Fruit {313enum Fruit {
...@@ -330,7 +325,9 @@ fn non_const_switch_on_enum(fruit: Fruit) {...@@ -330,7 +325,9 @@ fn non_const_switch_on_enum(fruit: Fruit) {
330325
331#attribute("test")326#attribute("test")
332fn switch_statement() {327fn switch_statement() {
333 const foo = SwitchStatmentFoo.C;328 non_const_switch(SwitchStatmentFoo.C);
329}
330fn non_const_switch(foo: SwitchStatmentFoo) {
334 const val: i32 = switch (foo) {331 const val: i32 = switch (foo) {
335 A => 1,332 A => 1,
336 B => 2,333 B => 2,