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 {
11081108 TypeTableEntry *entry_num_lit_float;
11091109 TypeTableEntry *entry_undef;
11101110 TypeTableEntry *entry_pure_error;
1111 TypeTableEntry *entry_os_enum;
1112 TypeTableEntry *entry_arch_enum;
11111113 } builtin_types;
11121114
11131115 ZigTarget zig_target;
......@@ -1126,6 +1128,8 @@ struct CodeGen {
11261128 Buf triple_str;
11271129 bool is_release_build;
11281130 bool is_test_build;
1131 uint32_t target_os_index;
1132 uint32_t target_arch_index;
11291133 LLVMTargetMachineRef target_machine;
11301134 LLVMZigDIFile *dummy_di_file;
11311135 bool is_native_target;
src/analyze.cpp+71-5
......@@ -3526,6 +3526,8 @@ static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockCon
35263526
35273527 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
35283528 *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;
35293531 return result_type;
35303532}
35313533
......@@ -4233,6 +4235,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
42334235 }
42344236
42354237 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
4238 const_val->ok = true;
42364239 const_val->depends_on_compile_var = true;
42374240
42384241 if (buf_eql_str(&var_name, "is_big_endian")) {
......@@ -4242,7 +4245,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
42424245 } else if (buf_eql_str(&var_name, "is_test")) {
42434246 return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
42444247 } 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;
42464253 } else {
42474254 add_node_error(g, *str_node,
42484255 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));
......@@ -4638,17 +4645,18 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
46384645static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
46394646 TypeTableEntry *expected_type, AstNode *node)
46404647{
4641 AstNode *expr_node = node->data.switch_expr.expr;
4642 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, expr_node);
4648 AstNode **expr_node = &node->data.switch_expr.expr;
4649 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
46434650
46444651 int prong_count = node->data.switch_expr.prongs.length;
46454652 AstNode **peer_nodes = allocate<AstNode*>(prong_count);
46464653 TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
46474654
4655 bool any_errors = false;
46484656 if (expr_type->id == TypeTableEntryIdInvalid) {
46494657 return expr_type;
46504658 } 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),
46524660 buf_sprintf("switch on unreachable expression not allowed"));
46534661 return g->builtin_types.entry_invalid;
46544662 } else {
......@@ -4666,6 +4674,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
46664674 if (prong_node->data.switch_prong.items.length == 0) {
46674675 if (else_prong) {
46684676 add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
4677 any_errors = true;
46694678 } else {
46704679 else_prong = prong_node;
46714680 }
......@@ -4700,14 +4709,17 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
47004709 add_node_error(g, item_node,
47014710 buf_sprintf("duplicate switch value: '%s'",
47024711 buf_ptr(type_enum_field->name)));
4712 any_errors = true;
47034713 }
47044714 } else {
47054715 add_node_error(g, item_node,
47064716 buf_sprintf("enum '%s' has no field '%s'",
47074717 buf_ptr(&expr_type->name), buf_ptr(field_name)));
4718 any_errors = true;
47084719 }
47094720 } else {
47104721 add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
4722 any_errors = true;
47114723 }
47124724 } else {
47134725 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,
47164728 if (!const_val->ok) {
47174729 add_node_error(g, item_node,
47184730 buf_sprintf("unable to resolve constant expression"));
4731 any_errors = true;
47194732 }
47204733 }
47214734 }
......@@ -4751,11 +4764,64 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
47514764 add_node_error(g, node,
47524765 buf_sprintf("enumeration value '%s' not handled in switch",
47534766 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;
47544817 }
4818 } else {
4819 zig_panic("TODO determine if const exprs are equal");
47554820 }
47564821 }
47574822 }
4758 return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count);
4823
4824 zig_unreachable();
47594825}
47604826
47614827static 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) {
352352 case BuiltinFnIdMinValue:
353353 case BuiltinFnIdMaxValue:
354354 case BuiltinFnIdMemberCount:
355 case BuiltinFnIdCompileVar:
356355 case BuiltinFnIdConstEval:
357356 // caught by constant expression eval codegen
358357 zig_unreachable();
358 case BuiltinFnIdCompileVar:
359 return nullptr;
359360 }
360361 zig_unreachable();
361362}
......@@ -3443,6 +3444,62 @@ static void define_builtin_types(CodeGen *g) {
34433444 g->builtin_types.entry_i16 = get_int_type(g, true, 16);
34443445 g->builtin_types.entry_i32 = get_int_type(g, true, 32);
34453446 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 }
34463503}
34473504
34483505
src/main.cpp+3-3
......@@ -58,11 +58,11 @@ static int print_target_list(FILE *f) {
5858 int arch_count = target_arch_count();
5959 for (int arch_i = 0; arch_i < arch_count; arch_i += 1) {
6060 const ArchType *arch = get_target_arch(arch_i);
61 const char *sub_arch_str = (arch->sub_arch == ZigLLVM_NoSubArch) ?
62 "" : ZigLLVMGetSubArchTypeName(arch->sub_arch);
61 char arch_name[50];
62 get_arch_name(arch_name, arch);
6363 const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
6464 " (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);
6666 }
6767
6868 fprintf(f, "\nOperating Systems:\n");
src/target.cpp+10-3
......@@ -181,13 +181,20 @@ void get_unknown_target(ZigTarget *target) {
181181 target->oformat = ZigLLVM_UnknownObjectFormat;
182182}
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
184193int parse_target_arch(const char *str, ArchType *out_arch) {
185194 for (int i = 0; i < array_length(arch_list); i += 1) {
186195 const ArchType *arch = &arch_list[i];
187196 char arch_name[50];
188 const char *sub_str = (arch->sub_arch == ZigLLVM_NoSubArch) ?
189 "" : ZigLLVMGetSubArchTypeName(arch->sub_arch);
190 sprintf(arch_name, "%s%s", ZigLLVMGetArchTypeName(arch->arch), sub_str);
197 get_arch_name_raw(arch_name, arch->arch, arch->sub_arch);
191198 if (strcmp(arch_name, str) == 0) {
192199 *out_arch = *arch;
193200 return 0;
src/target.hpp+1
......@@ -27,6 +27,7 @@ struct ZigTarget {
2727
2828int target_arch_count(void);
2929const ArchType *get_target_arch(int index);
30void get_arch_name(char *out_str, const ArchType *arch);
3031
3132int target_vendor_count(void);
3233ZigLLVM_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) {
308308#attribute("test")
309309fn switch_on_enum() {
310310 const fruit = Fruit.Orange;
311 switch (fruit) {
312 Apple => unreachable{},
313 Orange => {},
314 Banana => unreachable{},
315 }
316311 non_const_switch_on_enum(fruit);
317312}
318313enum Fruit {
......@@ -330,7 +325,9 @@ fn non_const_switch_on_enum(fruit: Fruit) {
330325
331326#attribute("test")
332327fn switch_statement() {
333 const foo = SwitchStatmentFoo.C;
328 non_const_switch(SwitchStatmentFoo.C);
329}
330fn non_const_switch(foo: SwitchStatmentFoo) {
334331 const val: i32 = switch (foo) {
335332 A => 1,
336333 B => 2,