authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-25 23:21:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-25 23:21:13-07:00
loga37bb4a4dafa8e3e3b1e9e3bbd07e5cf4eee129b
treed396fefae07b6f48f97990c2cf3c389a4b40025c
parent01428d4a72c8013e1fe8cfc69eedeb843b1d75c8

add the C integer types


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

doc/langref.md-1
...@@ -187,7 +187,6 @@ u64 uint64_t unsigned 64-bit integer...@@ -187,7 +187,6 @@ u64 uint64_t unsigned 64-bit integer
187187
188f32 float 32-bit IEE754 floating point188f32 float 32-bit IEE754 floating point
189f64 double 64-bit IEE754 floating point189f64 double 64-bit IEE754 floating point
190f128 long double 128-bit IEE754 floating point
191190
192isize intptr_t signed pointer sized integer191isize intptr_t signed pointer sized integer
193usize uintptr_t unsigned pointer sized integer192usize uintptr_t unsigned pointer sized integer
doc/targets.md+2
...@@ -9,3 +9,5 @@ target-specific. Add logic for how to do function prototypes and function calls...@@ -9,3 +9,5 @@ target-specific. Add logic for how to do function prototypes and function calls
9for the target when an exported or external function has a byvalue struct.9for the target when an exported or external function has a byvalue struct.
1010
11Write the target-specific code in std.zig.11Write the target-specific code in std.zig.
12
13Update the C integer types to be the correct size for the target.
doc/vim/syntax/zig.vim+2-1
...@@ -15,7 +15,8 @@ syn keyword zigRepeat while for...@@ -15,7 +15,8 @@ syn keyword zigRepeat while for
1515
16syn keyword zigConstant null undefined16syn keyword zigConstant null undefined
17syn keyword zigKeyword fn import17syn keyword zigKeyword fn import
18syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void unreachable type error18syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 void unreachable type error
19syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong
1920
20syn keyword zigBoolean true false21syn keyword zigBoolean true false
2122
example/hello_world/hello_libc.zig+2-2
...@@ -2,10 +2,10 @@ export executable "hello";...@@ -2,10 +2,10 @@ export executable "hello";
22
3#link("c")3#link("c")
4extern {4extern {
5 fn printf(__format: &const u8, ...) -> i32;5 fn printf(__format: &const u8, ...) -> c_int;
6}6}
77
8export fn main(argc: i32, argv: &&u8) -> i32 {8export fn main(argc: c_int, argv: &&u8) -> c_int {
9 printf(c"Hello, world!\n");9 printf(c"Hello, world!\n");
10 return 0;10 return 0;
11}11}
src/all_types.hpp+1-3
...@@ -752,9 +752,6 @@ struct TypeTableEntryPointer {...@@ -752,9 +752,6 @@ struct TypeTableEntryPointer {
752752
753struct TypeTableEntryInt {753struct TypeTableEntryInt {
754 bool is_signed;754 bool is_signed;
755 LLVMValueRef add_with_overflow_fn;
756 LLVMValueRef sub_with_overflow_fn;
757 LLVMValueRef mul_with_overflow_fn;
758};755};
759756
760struct TypeTableEntryArray {757struct TypeTableEntryArray {
...@@ -1025,6 +1022,7 @@ struct CodeGen {...@@ -1025,6 +1022,7 @@ struct CodeGen {
1025 uint32_t next_error_index;1022 uint32_t next_error_index;
1026 uint32_t error_value_count;1023 uint32_t error_value_count;
1027 TypeTableEntry *err_tag_type;1024 TypeTableEntry *err_tag_type;
1025 LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
1028};1026};
10291027
1030struct VariableTableEntry {1028struct VariableTableEntry {
src/codegen.cpp+139-45
...@@ -100,6 +100,74 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no...@@ -100,6 +100,74 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no
100 }100 }
101}101}
102102
103enum AddSubMul {
104 AddSubMulAdd = 0,
105 AddSubMulSub = 1,
106 AddSubMulMul = 2,
107};
108
109static int bits_index(int size_in_bits) {
110 switch (size_in_bits) {
111 case 8:
112 return 0;
113 case 16:
114 return 1;
115 case 32:
116 return 2;
117 case 64:
118 return 3;
119 default:
120 zig_unreachable();
121 }
122}
123
124static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
125 const char *signed_name, const char *unsigned_name)
126{
127 const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;
128 Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
129
130 LLVMTypeRef return_elem_types[] = {
131 type_entry->type_ref,
132 LLVMInt1Type(),
133 };
134 LLVMTypeRef param_types[] = {
135 type_entry->type_ref,
136 type_entry->type_ref,
137 };
138 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
139 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
140 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
141 assert(LLVMGetIntrinsicID(fn_val));
142 return fn_val;
143}
144
145static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul add_sub_mul) {
146 assert(type_entry->id == TypeTableEntryIdInt);
147 // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
148 int index0 = type_entry->data.integral.is_signed ? 0 : 1;
149 int index1 = add_sub_mul;
150 int index2 = bits_index(type_entry->size_in_bits);
151 LLVMValueRef *fn = &g->int_overflow_fns[index0][index1][index2];
152 if (*fn) {
153 return *fn;
154 }
155 switch (add_sub_mul) {
156 case AddSubMulAdd:
157 *fn = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd");
158 break;
159 case AddSubMulSub:
160 *fn = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub");
161 break;
162 case AddSubMulMul:
163 *fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");
164 break;
165
166 }
167 return *fn;
168}
169
170
103static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {171static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
104 assert(node->type == NodeTypeFnCallExpr);172 assert(node->type == NodeTypeFnCallExpr);
105 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;173 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
...@@ -118,16 +186,17 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -118,16 +186,17 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
118 assert(fn_call_param_count == 4);186 assert(fn_call_param_count == 4);
119187
120 TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));188 TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
121 LLVMValueRef fn_val;189 AddSubMul add_sub_mul;
122 if (builtin_fn->id == BuiltinFnIdAddWithOverflow) {190 if (builtin_fn->id == BuiltinFnIdAddWithOverflow) {
123 fn_val = int_type->data.integral.add_with_overflow_fn;191 add_sub_mul = AddSubMulAdd;
124 } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) {192 } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) {
125 fn_val = int_type->data.integral.sub_with_overflow_fn;193 add_sub_mul = AddSubMulSub;
126 } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) {194 } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) {
127 fn_val = int_type->data.integral.mul_with_overflow_fn;195 add_sub_mul = AddSubMulMul;
128 } else {196 } else {
129 zig_unreachable();197 zig_unreachable();
130 }198 }
199 LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul);
131200
132 LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1));201 LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
133 LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2));202 LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
...@@ -2559,35 +2628,6 @@ static void do_code_gen(CodeGen *g) {...@@ -2559,35 +2628,6 @@ static void do_code_gen(CodeGen *g) {
2559#endif2628#endif
2560}2629}
25612630
2562static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
2563 const char *signed_name, const char *unsigned_name)
2564{
2565 const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;
2566 Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
2567
2568 LLVMTypeRef return_elem_types[] = {
2569 type_entry->type_ref,
2570 LLVMInt1Type(),
2571 };
2572 LLVMTypeRef param_types[] = {
2573 type_entry->type_ref,
2574 type_entry->type_ref,
2575 };
2576 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
2577 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
2578 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
2579 assert(LLVMGetIntrinsicID(fn_val));
2580 return fn_val;
2581}
2582
2583static void add_int_overflow_fns(CodeGen *g, TypeTableEntry *type_entry) {
2584 assert(type_entry->id == TypeTableEntryIdInt);
2585
2586 type_entry->data.integral.add_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd");
2587 type_entry->data.integral.sub_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub");
2588 type_entry->data.integral.mul_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");
2589}
2590
2591static const int int_sizes_in_bits[] = {2631static const int int_sizes_in_bits[] = {
2592 8,2632 8,
2593 16,2633 16,
...@@ -2595,6 +2635,52 @@ static const int int_sizes_in_bits[] = {...@@ -2595,6 +2635,52 @@ static const int int_sizes_in_bits[] = {
2595 64,2635 64,
2596};2636};
25972637
2638enum CIntType {
2639 CIntTypeShort,
2640 CIntTypeUShort,
2641 CIntTypeInt,
2642 CIntTypeUInt,
2643 CIntTypeLong,
2644 CIntTypeULong,
2645 CIntTypeLongLong,
2646 CIntTypeULongLong,
2647};
2648
2649struct CIntTypeInfo {
2650 CIntType id;
2651 const char *name;
2652 bool is_signed;
2653};
2654
2655static const CIntTypeInfo c_int_type_infos[] = {
2656 {CIntTypeShort, "c_short", true},
2657 {CIntTypeUShort, "c_ushort", false},
2658 {CIntTypeInt, "c_int", true},
2659 {CIntTypeUInt, "c_uint", false},
2660 {CIntTypeLong, "c_long", true},
2661 {CIntTypeULong, "c_ulong", false},
2662 {CIntTypeLongLong, "c_longlong", true},
2663 {CIntTypeULongLong, "c_ulonglong", false},
2664};
2665
2666static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {
2667 // TODO other architectures besides x86_64
2668 switch (id) {
2669 case CIntTypeShort:
2670 case CIntTypeUShort:
2671 return 16;
2672 case CIntTypeInt:
2673 case CIntTypeUInt:
2674 return 32;
2675 case CIntTypeLong:
2676 case CIntTypeULong:
2677 case CIntTypeLongLong:
2678 case CIntTypeULongLong:
2679 return 64;
2680 }
2681 zig_unreachable();
2682}
2683
2598static void define_builtin_types(CodeGen *g) {2684static void define_builtin_types(CodeGen *g) {
2599 {2685 {
2600 // if this type is anywhere in the AST, we should never hit codegen.2686 // if this type is anywhere in the AST, we should never hit codegen.
...@@ -2639,8 +2725,6 @@ static void define_builtin_types(CodeGen *g) {...@@ -2639,8 +2725,6 @@ static void define_builtin_types(CodeGen *g) {
26392725
2640 get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;2726 get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
26412727
2642 add_int_overflow_fns(g, entry);
2643
2644 if (!is_signed) {2728 if (!is_signed) {
2645 break;2729 break;
2646 } else {2730 } else {
...@@ -2649,6 +2733,26 @@ static void define_builtin_types(CodeGen *g) {...@@ -2649,6 +2733,26 @@ static void define_builtin_types(CodeGen *g) {
2649 }2733 }
2650 }2734 }
26512735
2736 for (int i = 0; i < array_length(c_int_type_infos); i += 1) {
2737 const CIntTypeInfo *info = &c_int_type_infos[i];
2738 uint64_t size_in_bits = get_c_type_size_in_bits(g, info->id);
2739 bool is_signed = info->is_signed;
2740
2741 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2742 entry->type_ref = LLVMIntType(size_in_bits);
2743
2744 buf_init_from_str(&entry->name, info->name);
2745
2746 entry->size_in_bits = size_in_bits;
2747 entry->align_in_bits = size_in_bits;
2748
2749 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2750 entry->size_in_bits, entry->align_in_bits,
2751 is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
2752 entry->data.integral.is_signed = is_signed;
2753 g->primitive_type_table.put(&entry->name, entry);
2754 }
2755
2652 {2756 {
2653 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);2757 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
2654 entry->type_ref = LLVMInt1Type();2758 entry->type_ref = LLVMInt1Type();
...@@ -2669,11 +2773,6 @@ static void define_builtin_types(CodeGen *g) {...@@ -2669,11 +2773,6 @@ static void define_builtin_types(CodeGen *g) {
2669 entry->align_in_bits = g->pointer_size_bytes * 8;2773 entry->align_in_bits = g->pointer_size_bytes * 8;
2670 entry->data.integral.is_signed = true;2774 entry->data.integral.is_signed = true;
26712775
2672 TypeTableEntry *fixed_width_entry = get_int_type(g, entry->data.integral.is_signed, entry->size_in_bits);
2673 entry->data.integral.add_with_overflow_fn = fixed_width_entry->data.integral.add_with_overflow_fn;
2674 entry->data.integral.sub_with_overflow_fn = fixed_width_entry->data.integral.sub_with_overflow_fn;
2675 entry->data.integral.mul_with_overflow_fn = fixed_width_entry->data.integral.mul_with_overflow_fn;
2676
2677 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),2776 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2678 entry->size_in_bits, entry->align_in_bits,2777 entry->size_in_bits, entry->align_in_bits,
2679 LLVMZigEncoding_DW_ATE_signed());2778 LLVMZigEncoding_DW_ATE_signed());
...@@ -2688,11 +2787,6 @@ static void define_builtin_types(CodeGen *g) {...@@ -2688,11 +2787,6 @@ static void define_builtin_types(CodeGen *g) {
2688 entry->align_in_bits = g->pointer_size_bytes * 8;2787 entry->align_in_bits = g->pointer_size_bytes * 8;
2689 entry->data.integral.is_signed = false;2788 entry->data.integral.is_signed = false;
26902789
2691 TypeTableEntry *fixed_width_entry = get_int_type(g, entry->data.integral.is_signed, entry->size_in_bits);
2692 entry->data.integral.add_with_overflow_fn = fixed_width_entry->data.integral.add_with_overflow_fn;
2693 entry->data.integral.sub_with_overflow_fn = fixed_width_entry->data.integral.sub_with_overflow_fn;
2694 entry->data.integral.mul_with_overflow_fn = fixed_width_entry->data.integral.mul_with_overflow_fn;
2695
2696 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),2790 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2697 entry->size_in_bits, entry->align_in_bits,2791 entry->size_in_bits, entry->align_in_bits,
2698 LLVMZigEncoding_DW_ATE_unsigned());2792 LLVMZigEncoding_DW_ATE_unsigned());
test/run_tests.cpp+4-4
...@@ -98,10 +98,10 @@ static void add_compiling_test_cases(void) {...@@ -98,10 +98,10 @@ static void add_compiling_test_cases(void) {
98 add_simple_case("hello world with libc", R"SOURCE(98 add_simple_case("hello world with libc", R"SOURCE(
99#link("c")99#link("c")
100extern {100extern {
101 fn puts(s: &const u8) -> i32;101 fn puts(s: &const u8) -> c_int;
102}102}
103103
104export fn main(argc: i32, argv: &&u8) -> i32 {104export fn main(argc: c_int, argv: &&u8) -> c_int {
105 puts(c"Hello, world!");105 puts(c"Hello, world!");
106 return 0;106 return 0;
107}107}
...@@ -483,10 +483,10 @@ pub fn main(args: [][]u8) -> %void {...@@ -483,10 +483,10 @@ pub fn main(args: [][]u8) -> %void {
483 add_simple_case("number literals", R"SOURCE(483 add_simple_case("number literals", R"SOURCE(
484#link("c")484#link("c")
485extern {485extern {
486 fn printf(__format: &const u8, ...) -> i32;486 fn printf(__format: &const u8, ...) -> c_int;
487}487}
488488
489export fn main(argc: i32, argv: &&u8) -> i32 {489export fn main(argc: c_int, argv: &&u8) -> c_int {
490 printf(c"\n");490 printf(c"\n");
491491
492 printf(c"0: %llu\n",492 printf(c"0: %llu\n",