| ... | @@ -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 | } |
| 191 | | 205 | |
| 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)); |
| 195 | | 209 | |
| 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 | }; |
| 200 | | 214 | |
| 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 | #endif | 2198 | #endif |
| 2185 | } | 2199 | } |
| 2186 | | 2200 | |
| | 2201 | static 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 | |
| | 2222 | static 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 | |
| 2187 | static const NumLit num_lit_kinds[] = { | 2230 | static 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 | }; |
| 2200 | | 2243 | |
| | 2244 | static const int int_sizes_in_bits[] = { |
| | 2245 | 8, |
| | 2246 | 16, |
| | 2247 | 32, |
| | 2248 | 64, |
| | 2249 | }; |
| | 2250 | |
| 2201 | static void define_builtin_types(CodeGen *g) { | 2251 | static 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 | } |
| 2221 | | 2271 | |
| | 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 | | | |
| 2408 | static 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); | | |
| 2432 | | 2395 | |
| | 2396 | g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, get_int_type(g, false, 8), true); |
| 2433 | | 2397 | |
| 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); |
| 2437 | | 2401 | 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 | } |
| 2454 | | 2407 | |
| | 2408 | |
| 2455 | static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) { | 2409 | static 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 | } |
| 2462 | | 2416 | |
| 2463 | static BuiltinFnEntry *create_one_arg_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) { | 2417 | static 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 later | 2419 | 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 | } |
| 2471 | | 2423 | |
| 2472 | static void define_builtin_fns(CodeGen *g) { | 2424 | static 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) { |
| 2524 | | 2468 | |
| 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 | } |
| 2533 | | 2480 | |
| 2534 | | 2481 | |