authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-14 17:04:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-14 17:04:35-07:00
log0c9afede9e6216aa59cd69dd9ed1ca544e24df30
treead59785a0c4c2d7d0a4c53cc48d5bf98a1498352
parent68c4f617edc2afd4f9b201b6b67248d6cb80e69d

overflow intrinsics take type as first argument


6 files changed, 182 insertions(+), 198 deletions(-)

src/all_types.hpp+7-1
...@@ -630,6 +630,9 @@ struct TypeTableEntryPointer {...@@ -630,6 +630,9 @@ struct TypeTableEntryPointer {
630630
631struct TypeTableEntryInt {631struct TypeTableEntryInt {
632 bool is_signed;632 bool is_signed;
633 LLVMValueRef add_with_overflow_fn;
634 LLVMValueRef sub_with_overflow_fn;
635 LLVMValueRef mul_with_overflow_fn;
633};636};
634637
635struct TypeTableEntryArray {638struct TypeTableEntryArray {
...@@ -791,7 +794,6 @@ struct FnTableEntry {...@@ -791,7 +794,6 @@ struct FnTableEntry {
791794
792enum BuiltinFnId {795enum BuiltinFnId {
793 BuiltinFnIdInvalid,796 BuiltinFnIdInvalid,
794 BuiltinFnIdArithmeticWithOverflow,
795 BuiltinFnIdMemcpy,797 BuiltinFnIdMemcpy,
796 BuiltinFnIdMemset,798 BuiltinFnIdMemset,
797 BuiltinFnIdSizeof,799 BuiltinFnIdSizeof,
...@@ -799,6 +801,9 @@ enum BuiltinFnId {...@@ -799,6 +801,9 @@ enum BuiltinFnId {
799 BuiltinFnIdMinValue,801 BuiltinFnIdMinValue,
800 BuiltinFnIdValueCount,802 BuiltinFnIdValueCount,
801 BuiltinFnIdTypeof,803 BuiltinFnIdTypeof,
804 BuiltinFnIdAddWithOverflow,
805 BuiltinFnIdSubWithOverflow,
806 BuiltinFnIdMulWithOverflow,
802};807};
803808
804struct BuiltinFnEntry {809struct BuiltinFnEntry {
...@@ -831,6 +836,7 @@ struct CodeGen {...@@ -831,6 +836,7 @@ struct CodeGen {
831836
832 struct {837 struct {
833 TypeTableEntry *entry_bool;838 TypeTableEntry *entry_bool;
839 TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
834 TypeTableEntry *entry_u8;840 TypeTableEntry *entry_u8;
835 TypeTableEntry *entry_u16;841 TypeTableEntry *entry_u16;
836 TypeTableEntry *entry_u32;842 TypeTableEntry *entry_u32;
src/analyze.cpp+49-20
...@@ -155,18 +155,7 @@ static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x)...@@ -155,18 +155,7 @@ static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x)
155}155}
156156
157static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) {157static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) {
158 switch (get_number_literal_kind_unsigned(x)) {158 return get_int_type(g, false, num_lit_bit_count(get_number_literal_kind_unsigned(x)));
159 case NumLitU8:
160 return g->builtin_types.entry_u8;
161 case NumLitU16:
162 return g->builtin_types.entry_u16;
163 case NumLitU32:
164 return g->builtin_types.entry_u32;
165 case NumLitU64:
166 return g->builtin_types.entry_u64;
167 default:
168 zig_unreachable();
169 }
170}159}
171160
172static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) {161static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) {
...@@ -464,7 +453,9 @@ static void eval_const_expr_builtin(CodeGen *g, BlockContext *context, AstNode *...@@ -464,7 +453,9 @@ static void eval_const_expr_builtin(CodeGen *g, BlockContext *context, AstNode *
464 switch (node->data.fn_call_expr.builtin_fn->id) {453 switch (node->data.fn_call_expr.builtin_fn->id) {
465 case BuiltinFnIdInvalid:454 case BuiltinFnIdInvalid:
466 zig_unreachable();455 zig_unreachable();
467 case BuiltinFnIdArithmeticWithOverflow:456 case BuiltinFnIdAddWithOverflow:
457 case BuiltinFnIdSubWithOverflow:
458 case BuiltinFnIdMulWithOverflow:
468 case BuiltinFnIdMemcpy:459 case BuiltinFnIdMemcpy:
469 case BuiltinFnIdMemset:460 case BuiltinFnIdMemset:
470 break;461 break;
...@@ -2476,18 +2467,36 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -2476,18 +2467,36 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
2476 add_node_error(g, node,2467 add_node_error(g, node,
2477 buf_sprintf("expected %d arguments, got %d",2468 buf_sprintf("expected %d arguments, got %d",
2478 builtin_fn->param_count, actual_param_count));2469 builtin_fn->param_count, actual_param_count));
2470 return g->builtin_types.entry_invalid;
2479 }2471 }
24802472
2481 switch (builtin_fn->id) {2473 switch (builtin_fn->id) {
2482 case BuiltinFnIdInvalid:2474 case BuiltinFnIdInvalid:
2483 zig_unreachable();2475 zig_unreachable();
2484 case BuiltinFnIdArithmeticWithOverflow:2476 case BuiltinFnIdAddWithOverflow:
2485 for (int i = 0; i < actual_param_count; i += 1) {2477 case BuiltinFnIdSubWithOverflow:
2486 AstNode *child = node->data.fn_call_expr.params.at(i);2478 case BuiltinFnIdMulWithOverflow:
2487 TypeTableEntry *expected_param_type = builtin_fn->param_types[i];2479 {
2488 analyze_expression(g, import, context, expected_param_type, child);2480 AstNode *type_node = node->data.fn_call_expr.params.at(0);
2481 TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node);
2482 if (int_type->id == TypeTableEntryIdInvalid) {
2483 return g->builtin_types.entry_bool;
2484 } else if (int_type->id == TypeTableEntryIdInt) {
2485 AstNode *op1_node = node->data.fn_call_expr.params.at(1);
2486 AstNode *op2_node = node->data.fn_call_expr.params.at(2);
2487 AstNode *result_node = node->data.fn_call_expr.params.at(3);
2488
2489 analyze_expression(g, import, context, int_type, op1_node);
2490 analyze_expression(g, import, context, int_type, op2_node);
2491 analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false),
2492 result_node);
2493 } else {
2494 add_node_error(g, type_node,
2495 buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name)));
2496 }
2497
2498 return g->builtin_types.entry_bool;
2489 }2499 }
2490 return builtin_fn->return_type;
2491 case BuiltinFnIdMemcpy:2500 case BuiltinFnIdMemcpy:
2492 {2501 {
2493 AstNode *dest_node = node->data.fn_call_expr.params.at(0);2502 AstNode *dest_node = node->data.fn_call_expr.params.at(0);
...@@ -2796,7 +2805,8 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -2796,7 +2805,8 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
2796 } else if (expr_type->id == TypeTableEntryIdNumberLiteral) {2805 } else if (expr_type->id == TypeTableEntryIdNumberLiteral) {
2797 return expr_type;2806 return expr_type;
2798 } else {2807 } else {
2799 add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'",2808 BREAKPOINT;
2809 add_node_error(g, node, buf_sprintf("invalid negation type: '%s'",
2800 buf_ptr(&expr_type->name)));2810 buf_ptr(&expr_type->name)));
2801 return g->builtin_types.entry_invalid;2811 return g->builtin_types.entry_invalid;
2802 }2812 }
...@@ -3842,3 +3852,22 @@ bool is_node_void_expr(AstNode *node) {...@@ -3842,3 +3852,22 @@ bool is_node_void_expr(AstNode *node) {
3842 return false;3852 return false;
3843}3853}
38443854
3855TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits) {
3856 int index;
3857 if (size_in_bits == 8) {
3858 index = 0;
3859 } else if (size_in_bits == 16) {
3860 index = 1;
3861 } else if (size_in_bits == 32) {
3862 index = 2;
3863 } else if (size_in_bits == 64) {
3864 index = 3;
3865 } else {
3866 zig_unreachable();
3867 }
3868 return &g->builtin_types.entry_int[is_signed ? 0 : 1][index];
3869}
3870
3871TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {
3872 return *get_int_type_ptr(g, is_signed, size_in_bits);
3873}
src/analyze.hpp+2
...@@ -21,5 +21,7 @@ Expr *get_resolved_expr(AstNode *node);...@@ -21,5 +21,7 @@ Expr *get_resolved_expr(AstNode *node);
21NumLitCodeGen *get_resolved_num_lit(AstNode *node);21NumLitCodeGen *get_resolved_num_lit(AstNode *node);
22TopLevelDecl *get_resolved_top_level_decl(AstNode *node);22TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
23bool is_node_void_expr(AstNode *node);23bool is_node_void_expr(AstNode *node);
24TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
25TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
2426
25#endif27#endif
src/codegen.cpp+120-173
...@@ -184,14 +184,28 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -184,14 +184,28 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
184 case BuiltinFnIdInvalid:184 case BuiltinFnIdInvalid:
185 case BuiltinFnIdTypeof:185 case BuiltinFnIdTypeof:
186 zig_unreachable();186 zig_unreachable();
187 case BuiltinFnIdArithmeticWithOverflow:187 case BuiltinFnIdAddWithOverflow:
188 case BuiltinFnIdSubWithOverflow:
189 case BuiltinFnIdMulWithOverflow:
188 {190 {
189 int fn_call_param_count = node->data.fn_call_expr.params.length;191 int fn_call_param_count = node->data.fn_call_expr.params.length;
190 assert(fn_call_param_count == 3);192 assert(fn_call_param_count == 4);
193
194 TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0));
195 LLVMValueRef fn_val;
196 if (builtin_fn->id == BuiltinFnIdAddWithOverflow) {
197 fn_val = int_type->data.integral.add_with_overflow_fn;
198 } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) {
199 fn_val = int_type->data.integral.sub_with_overflow_fn;
200 } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) {
201 fn_val = int_type->data.integral.mul_with_overflow_fn;
202 } else {
203 zig_unreachable();
204 }
191205
192 LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(0));206 LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1));
193 LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(1));207 LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2));
194 LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(2));208 LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3));
195209
196 LLVMValueRef params[] = {210 LLVMValueRef params[] = {
197 op1,211 op1,
...@@ -199,7 +213,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -199,7 +213,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
199 };213 };
200214
201 add_debug_source_node(g, node);215 add_debug_source_node(g, node);
202 LLVMValueRef result_struct = LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 2, "");216 LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
203 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");217 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
204 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");218 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
205 LLVMBuildStore(g->builder, result, ptr_result);219 LLVMBuildStore(g->builder, result, ptr_result);
...@@ -2184,6 +2198,35 @@ static void do_code_gen(CodeGen *g) {...@@ -2184,6 +2198,35 @@ static void do_code_gen(CodeGen *g) {
2184#endif2198#endif
2185}2199}
21862200
2201static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
2202 const char *signed_name, const char *unsigned_name)
2203{
2204 const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;
2205 Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
2206
2207 LLVMTypeRef return_elem_types[] = {
2208 type_entry->type_ref,
2209 LLVMInt1Type(),
2210 };
2211 LLVMTypeRef param_types[] = {
2212 type_entry->type_ref,
2213 type_entry->type_ref,
2214 };
2215 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
2216 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
2217 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
2218 assert(LLVMGetIntrinsicID(fn_val));
2219 return fn_val;
2220}
2221
2222static void add_int_overflow_fns(CodeGen *g, TypeTableEntry *type_entry) {
2223 assert(type_entry->id == TypeTableEntryIdInt);
2224
2225 type_entry->data.integral.add_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd");
2226 type_entry->data.integral.sub_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub");
2227 type_entry->data.integral.mul_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");
2228}
2229
2187static const NumLit num_lit_kinds[] = {2230static const NumLit num_lit_kinds[] = {
2188 NumLitF32,2231 NumLitF32,
2189 NumLitF64,2232 NumLitF64,
...@@ -2198,6 +2241,13 @@ static const NumLit num_lit_kinds[] = {...@@ -2198,6 +2241,13 @@ static const NumLit num_lit_kinds[] = {
2198 NumLitI64,2241 NumLitI64,
2199};2242};
22002243
2244static const int int_sizes_in_bits[] = {
2245 8,
2246 16,
2247 32,
2248 64,
2249};
2250
2201static void define_builtin_types(CodeGen *g) {2251static void define_builtin_types(CodeGen *g) {
2202 {2252 {
2203 // if this type is anywhere in the AST, we should never hit codegen.2253 // if this type is anywhere in the AST, we should never hit codegen.
...@@ -2219,6 +2269,37 @@ static void define_builtin_types(CodeGen *g) {...@@ -2219,6 +2269,37 @@ static void define_builtin_types(CodeGen *g) {
2219 g->num_lit_types[i] = entry;2269 g->num_lit_types[i] = entry;
2220 }2270 }
22212271
2272 for (int i = 0; i < array_length(int_sizes_in_bits); i += 1) {
2273 int size_in_bits = int_sizes_in_bits[i];
2274 bool is_signed = true;
2275 for (;;) {
2276 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2277 entry->type_ref = LLVMIntType(size_in_bits);
2278
2279 const char u_or_i = is_signed ? 'i' : 'u';
2280 buf_resize(&entry->name, 0);
2281 buf_appendf(&entry->name, "%c%d", u_or_i, size_in_bits);
2282
2283 entry->size_in_bits = size_in_bits;
2284 entry->align_in_bits = size_in_bits;
2285 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2286 entry->size_in_bits, entry->align_in_bits,
2287 is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
2288 entry->data.integral.is_signed = is_signed;
2289 g->primitive_type_table.put(&entry->name, entry);
2290
2291 get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
2292
2293 add_int_overflow_fns(g, entry);
2294
2295 if (!is_signed) {
2296 break;
2297 } else {
2298 is_signed = false;
2299 }
2300 }
2301 }
2302
2222 {2303 {
2223 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);2304 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
2224 entry->type_ref = LLVMInt1Type();2305 entry->type_ref = LLVMInt1Type();
...@@ -2231,110 +2312,6 @@ static void define_builtin_types(CodeGen *g) {...@@ -2231,110 +2312,6 @@ static void define_builtin_types(CodeGen *g) {
2231 g->builtin_types.entry_bool = entry;2312 g->builtin_types.entry_bool = entry;
2232 g->primitive_type_table.put(&entry->name, entry);2313 g->primitive_type_table.put(&entry->name, entry);
2233 }2314 }
2234 {
2235 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2236 entry->type_ref = LLVMInt8Type();
2237 buf_init_from_str(&entry->name, "u8");
2238 entry->size_in_bits = 8;
2239 entry->align_in_bits = 8;
2240 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2241 entry->size_in_bits, entry->align_in_bits,
2242 LLVMZigEncoding_DW_ATE_unsigned());
2243 g->builtin_types.entry_u8 = entry;
2244 g->primitive_type_table.put(&entry->name, entry);
2245 }
2246 {
2247 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2248 entry->type_ref = LLVMInt16Type();
2249 buf_init_from_str(&entry->name, "u16");
2250 entry->size_in_bits = 16;
2251 entry->align_in_bits = 16;
2252 entry->data.integral.is_signed = false;
2253 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2254 entry->size_in_bits, entry->align_in_bits,
2255 LLVMZigEncoding_DW_ATE_unsigned());
2256 g->builtin_types.entry_u16 = entry;
2257 g->primitive_type_table.put(&entry->name, entry);
2258 }
2259 {
2260 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2261 entry->type_ref = LLVMInt32Type();
2262 buf_init_from_str(&entry->name, "u32");
2263 entry->size_in_bits = 32;
2264 entry->align_in_bits = 32;
2265 entry->data.integral.is_signed = false;
2266 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2267 entry->size_in_bits, entry->align_in_bits,
2268 LLVMZigEncoding_DW_ATE_unsigned());
2269 g->builtin_types.entry_u32 = entry;
2270 g->primitive_type_table.put(&entry->name, entry);
2271 }
2272 {
2273 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2274 entry->type_ref = LLVMInt64Type();
2275 buf_init_from_str(&entry->name, "u64");
2276 entry->size_in_bits = 64;
2277 entry->align_in_bits = 64;
2278 entry->data.integral.is_signed = false;
2279 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2280 entry->size_in_bits, entry->align_in_bits,
2281 LLVMZigEncoding_DW_ATE_unsigned());
2282 g->builtin_types.entry_u64 = entry;
2283 g->primitive_type_table.put(&entry->name, entry);
2284 }
2285 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
2286 {
2287 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2288 entry->type_ref = LLVMInt8Type();
2289 buf_init_from_str(&entry->name, "i8");
2290 entry->size_in_bits = 8;
2291 entry->align_in_bits = 8;
2292 entry->data.integral.is_signed = true;
2293 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2294 entry->size_in_bits, entry->align_in_bits,
2295 LLVMZigEncoding_DW_ATE_signed());
2296 g->builtin_types.entry_i8 = entry;
2297 g->primitive_type_table.put(&entry->name, entry);
2298 }
2299 {
2300 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2301 entry->type_ref = LLVMInt16Type();
2302 buf_init_from_str(&entry->name, "i16");
2303 entry->size_in_bits = 16;
2304 entry->align_in_bits = 16;
2305 entry->data.integral.is_signed = true;
2306 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2307 entry->size_in_bits, entry->align_in_bits,
2308 LLVMZigEncoding_DW_ATE_signed());
2309 g->builtin_types.entry_i16 = entry;
2310 g->primitive_type_table.put(&entry->name, entry);
2311 }
2312 {
2313 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2314 entry->type_ref = LLVMInt32Type();
2315 buf_init_from_str(&entry->name, "i32");
2316 entry->size_in_bits = 32;
2317 entry->align_in_bits = 32;
2318 entry->data.integral.is_signed = true;
2319 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2320 entry->size_in_bits, entry->align_in_bits,
2321 LLVMZigEncoding_DW_ATE_signed());
2322 g->builtin_types.entry_i32 = entry;
2323 g->primitive_type_table.put(&entry->name, entry);
2324 }
2325 {
2326 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2327 entry->type_ref = LLVMInt64Type();
2328 buf_init_from_str(&entry->name, "i64");
2329 entry->size_in_bits = 64;
2330 entry->align_in_bits = 64;
2331 entry->data.integral.is_signed = true;
2332 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2333 entry->size_in_bits, entry->align_in_bits,
2334 LLVMZigEncoding_DW_ATE_signed());
2335 g->builtin_types.entry_i64 = entry;
2336 g->primitive_type_table.put(&entry->name, entry);
2337 }
2338 {2315 {
2339 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);2316 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2340 entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);2317 entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
...@@ -2342,6 +2319,12 @@ static void define_builtin_types(CodeGen *g) {...@@ -2342,6 +2319,12 @@ static void define_builtin_types(CodeGen *g) {
2342 entry->size_in_bits = g->pointer_size_bytes * 8;2319 entry->size_in_bits = g->pointer_size_bytes * 8;
2343 entry->align_in_bits = g->pointer_size_bytes * 8;2320 entry->align_in_bits = g->pointer_size_bytes * 8;
2344 entry->data.integral.is_signed = true;2321 entry->data.integral.is_signed = true;
2322
2323 TypeTableEntry *fixed_width_entry = get_int_type(g, entry->data.integral.is_signed, entry->size_in_bits);
2324 entry->data.integral.add_with_overflow_fn = fixed_width_entry->data.integral.add_with_overflow_fn;
2325 entry->data.integral.sub_with_overflow_fn = fixed_width_entry->data.integral.sub_with_overflow_fn;
2326 entry->data.integral.mul_with_overflow_fn = fixed_width_entry->data.integral.mul_with_overflow_fn;
2327
2345 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),2328 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2346 entry->size_in_bits, entry->align_in_bits,2329 entry->size_in_bits, entry->align_in_bits,
2347 LLVMZigEncoding_DW_ATE_signed());2330 LLVMZigEncoding_DW_ATE_signed());
...@@ -2355,6 +2338,12 @@ static void define_builtin_types(CodeGen *g) {...@@ -2355,6 +2338,12 @@ static void define_builtin_types(CodeGen *g) {
2355 entry->size_in_bits = g->pointer_size_bytes * 8;2338 entry->size_in_bits = g->pointer_size_bytes * 8;
2356 entry->align_in_bits = g->pointer_size_bytes * 8;2339 entry->align_in_bits = g->pointer_size_bytes * 8;
2357 entry->data.integral.is_signed = false;2340 entry->data.integral.is_signed = false;
2341
2342 TypeTableEntry *fixed_width_entry = get_int_type(g, entry->data.integral.is_signed, entry->size_in_bits);
2343 entry->data.integral.add_with_overflow_fn = fixed_width_entry->data.integral.add_with_overflow_fn;
2344 entry->data.integral.sub_with_overflow_fn = fixed_width_entry->data.integral.sub_with_overflow_fn;
2345 entry->data.integral.mul_with_overflow_fn = fixed_width_entry->data.integral.mul_with_overflow_fn;
2346
2358 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),2347 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
2359 entry->size_in_bits, entry->align_in_bits,2348 entry->size_in_bits, entry->align_in_bits,
2360 LLVMZigEncoding_DW_ATE_unsigned());2349 LLVMZigEncoding_DW_ATE_unsigned());
...@@ -2403,55 +2392,20 @@ static void define_builtin_types(CodeGen *g) {...@@ -2403,55 +2392,20 @@ static void define_builtin_types(CodeGen *g) {
2403 g->builtin_types.entry_unreachable = entry;2392 g->builtin_types.entry_unreachable = entry;
2404 g->primitive_type_table.put(&entry->name, entry);2393 g->primitive_type_table.put(&entry->name, entry);
2405 }2394 }
2406}
2407
2408static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
2409 assert(type_entry->id == TypeTableEntryIdInt);
2410 struct OverflowFn {
2411 const char *bare_name;
2412 const char *signed_name;
2413 const char *unsigned_name;
2414 };
2415 OverflowFn overflow_fns[] = {
2416 {"add", "sadd", "uadd"},
2417 {"sub", "ssub", "usub"},
2418 {"mul", "smul", "umul"},
2419 };
2420 for (size_t i = 0; i < sizeof(overflow_fns)/sizeof(overflow_fns[0]); i += 1) {
2421 OverflowFn *overflow_fn = &overflow_fns[i];
2422 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
2423 buf_resize(&builtin_fn->name, 0);
2424 buf_appendf(&builtin_fn->name, "%s_with_overflow_%s", overflow_fn->bare_name, buf_ptr(&type_entry->name));
2425 builtin_fn->id = BuiltinFnIdArithmeticWithOverflow;
2426 builtin_fn->return_type = g->builtin_types.entry_bool;
2427 builtin_fn->param_count = 3;
2428 builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
2429 builtin_fn->param_types[0] = type_entry;
2430 builtin_fn->param_types[1] = type_entry;
2431 builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false);
24322395
2396 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, get_int_type(g, false, 8), true);
24332397
2434 const char *signed_str = type_entry->data.integral.is_signed ?2398 g->builtin_types.entry_u8 = get_int_type(g, false, 8);
2435 overflow_fn->signed_name : overflow_fn->unsigned_name;2399 g->builtin_types.entry_u16 = get_int_type(g, false, 16);
2436 Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);2400 g->builtin_types.entry_u32 = get_int_type(g, false, 32);
24372401 g->builtin_types.entry_u64 = get_int_type(g, false, 64);
2438 LLVMTypeRef return_elem_types[] = {2402 g->builtin_types.entry_i8 = get_int_type(g, true, 8);
2439 type_entry->type_ref,2403 g->builtin_types.entry_i16 = get_int_type(g, true, 16);
2440 LLVMInt1Type(),2404 g->builtin_types.entry_i32 = get_int_type(g, true, 32);
2441 };2405 g->builtin_types.entry_i64 = get_int_type(g, true, 64);
2442 LLVMTypeRef param_types[] = {
2443 type_entry->type_ref,
2444 type_entry->type_ref,
2445 };
2446 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
2447 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
2448 builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
2449 assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
2450
2451 g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
2452 }
2453}2406}
24542407
2408
2455static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {2409static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
2456 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);2410 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
2457 buf_init_from_str(&builtin_fn->name, name);2411 buf_init_from_str(&builtin_fn->name, name);
...@@ -2460,24 +2414,14 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char...@@ -2460,24 +2414,14 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char
2460 return builtin_fn;2414 return builtin_fn;
2461}2415}
24622416
2463static BuiltinFnEntry *create_one_arg_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {2417static BuiltinFnEntry *create_builtin_fn_with_arg_count(CodeGen *g, BuiltinFnId id, const char *name, int count) {
2464 BuiltinFnEntry *builtin_fn = create_builtin_fn(g, id, name);2418 BuiltinFnEntry *builtin_fn = create_builtin_fn(g, id, name);
2465 builtin_fn->return_type = nullptr; // manually determined later2419 builtin_fn->param_count = count;
2466 builtin_fn->param_count = 1;2420 builtin_fn->param_types = allocate<TypeTableEntry *>(count);
2467 builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
2468 builtin_fn->param_types[0] = nullptr; // manually checked later
2469 return builtin_fn;2421 return builtin_fn;
2470}2422}
24712423
2472static void define_builtin_fns(CodeGen *g) {2424static void define_builtin_fns(CodeGen *g) {
2473 define_builtin_fns_int(g, g->builtin_types.entry_u8);
2474 define_builtin_fns_int(g, g->builtin_types.entry_u16);
2475 define_builtin_fns_int(g, g->builtin_types.entry_u32);
2476 define_builtin_fns_int(g, g->builtin_types.entry_u64);
2477 define_builtin_fns_int(g, g->builtin_types.entry_i8);
2478 define_builtin_fns_int(g, g->builtin_types.entry_i16);
2479 define_builtin_fns_int(g, g->builtin_types.entry_i32);
2480 define_builtin_fns_int(g, g->builtin_types.entry_i64);
2481 {2425 {
2482 BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy");2426 BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy");
2483 builtin_fn->return_type = g->builtin_types.entry_void;2427 builtin_fn->return_type = g->builtin_types.entry_void;
...@@ -2524,11 +2468,14 @@ static void define_builtin_fns(CodeGen *g) {...@@ -2524,11 +2468,14 @@ static void define_builtin_fns(CodeGen *g) {
25242468
2525 g->memset_fn_val = builtin_fn->fn_val;2469 g->memset_fn_val = builtin_fn->fn_val;
2526 }2470 }
2527 create_one_arg_builtin_fn(g, BuiltinFnIdSizeof, "sizeof");2471 create_builtin_fn_with_arg_count(g, BuiltinFnIdSizeof, "sizeof", 1);
2528 create_one_arg_builtin_fn(g, BuiltinFnIdMaxValue, "max_value");2472 create_builtin_fn_with_arg_count(g, BuiltinFnIdMaxValue, "max_value", 1);
2529 create_one_arg_builtin_fn(g, BuiltinFnIdMinValue, "min_value");2473 create_builtin_fn_with_arg_count(g, BuiltinFnIdMinValue, "min_value", 1);
2530 create_one_arg_builtin_fn(g, BuiltinFnIdValueCount, "value_count");2474 create_builtin_fn_with_arg_count(g, BuiltinFnIdValueCount, "value_count", 1);
2531 create_one_arg_builtin_fn(g, BuiltinFnIdTypeof, "typeof");2475 create_builtin_fn_with_arg_count(g, BuiltinFnIdTypeof, "typeof", 1);
2476 create_builtin_fn_with_arg_count(g, BuiltinFnIdAddWithOverflow, "add_with_overflow", 4);
2477 create_builtin_fn_with_arg_count(g, BuiltinFnIdSubWithOverflow, "sub_with_overflow", 4);
2478 create_builtin_fn_with_arg_count(g, BuiltinFnIdMulWithOverflow, "mul_with_overflow", 4);
2532}2479}
25332480
25342481
std/std.zig+2-2
...@@ -61,12 +61,12 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {...@@ -61,12 +61,12 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
61 }61 }
6262
63 // x *= radix63 // x *= radix
64 if (@mul_with_overflow_u64(x, radix, &x)) {64 if (@mul_with_overflow(u64, x, radix, &x)) {
65 return true;65 return true;
66 }66 }
6767
68 // x += digit68 // x += digit
69 if (@add_with_overflow_u64(x, digit, &x)) {69 if (@add_with_overflow(u64, x, digit, &x)) {
70 return true;70 return true;
71 }71 }
7272
test/run_tests.cpp+2-2
...@@ -986,10 +986,10 @@ fn f(c: u8) u8 => {...@@ -986,10 +986,10 @@ fn f(c: u8) u8 => {
986use "std.zig";986use "std.zig";
987pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {987pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
988 var result: u8;988 var result: u8;
989 if (!@add_with_overflow_u8(250, 100, &result)) {989 if (!@add_with_overflow(u8, 250, 100, &result)) {
990 print_str("BAD\n");990 print_str("BAD\n");
991 }991 }
992 if (@add_with_overflow_u8(100, 150, &result)) {992 if (@add_with_overflow(u8, 100, 150, &result)) {
993 print_str("BAD\n");993 print_str("BAD\n");
994 }994 }
995 if (result != 250) {995 if (result != 250) {