| ... | @@ -62,6 +62,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { | ... | @@ -62,6 +62,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { |
| 62 | g->fn_type_table.init(32); | 62 | g->fn_type_table.init(32); |
| 63 | g->error_table.init(16); | 63 | g->error_table.init(16); |
| 64 | g->generic_table.init(16); | 64 | g->generic_table.init(16); |
| | 65 | g->llvm_fn_table.init(16); |
| 65 | g->memoized_fn_eval_table.init(16); | 66 | g->memoized_fn_eval_table.init(16); |
| 66 | g->is_release_build = false; | 67 | g->is_release_build = false; |
| 67 | g->is_test_build = false; | 68 | g->is_test_build = false; |
| ... | @@ -352,33 +353,14 @@ static void clear_debug_source_node(CodeGen *g) { | ... | @@ -352,33 +353,14 @@ static void clear_debug_source_node(CodeGen *g) { |
| 352 | ZigLLVMClearCurrentDebugLocation(g->builder); | 353 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 353 | } | 354 | } |
| 354 | | 355 | |
| 355 | enum AddSubMul { | | |
| 356 | AddSubMulAdd = 0, | | |
| 357 | AddSubMulSub = 1, | | |
| 358 | AddSubMulMul = 2, | | |
| 359 | }; | | |
| 360 | | | |
| 361 | static size_t bits_index(size_t size_in_bits) { | | |
| 362 | switch (size_in_bits) { | | |
| 363 | case 8: | | |
| 364 | return 0; | | |
| 365 | case 16: | | |
| 366 | return 1; | | |
| 367 | case 32: | | |
| 368 | return 2; | | |
| 369 | case 64: | | |
| 370 | return 3; | | |
| 371 | default: | | |
| 372 | zig_unreachable(); | | |
| 373 | } | | |
| 374 | } | | |
| 375 | | | |
| 376 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, | 356 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, |
| 377 | const char *signed_name, const char *unsigned_name) | 357 | const char *signed_name, const char *unsigned_name) |
| 378 | { | 358 | { |
| | 359 | char fn_name[64]; |
| | 360 | |
| 379 | assert(type_entry->id == TypeTableEntryIdInt); | 361 | assert(type_entry->id == TypeTableEntryIdInt); |
| 380 | const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name; | 362 | const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name; |
| 381 | Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%zu", signed_str, type_entry->data.integral.bit_count); | 363 | sprintf(fn_name, "llvm.%s.with.overflow.i%zu", signed_str, type_entry->data.integral.bit_count); |
| 382 | | 364 | |
| 383 | LLVMTypeRef return_elem_types[] = { | 365 | LLVMTypeRef return_elem_types[] = { |
| 384 | type_entry->type_ref, | 366 | type_entry->type_ref, |
| ... | @@ -390,34 +372,39 @@ static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_ | ... | @@ -390,34 +372,39 @@ static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_ |
| 390 | }; | 372 | }; |
| 391 | LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); | 373 | LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); |
| 392 | LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); | 374 | LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); |
| 393 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type); | 375 | LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); |
| 394 | assert(LLVMGetIntrinsicID(fn_val)); | 376 | assert(LLVMGetIntrinsicID(fn_val)); |
| 395 | return fn_val; | 377 | return fn_val; |
| 396 | } | 378 | } |
| 397 | | 379 | |
| 398 | static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul add_sub_mul) { | 380 | static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul add_sub_mul) { |
| 399 | assert(type_entry->id == TypeTableEntryIdInt); | 381 | assert(type_entry->id == TypeTableEntryIdInt); |
| 400 | // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64] | 382 | |
| 401 | size_t index0 = type_entry->data.integral.is_signed ? 0 : 1; | 383 | ZigLLVMFnKey key = {}; |
| 402 | size_t index1 = add_sub_mul; | 384 | key.id = ZigLLVMFnIdOverflowArithmetic; |
| 403 | size_t index2 = bits_index(type_entry->data.integral.bit_count); | 385 | key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed; |
| 404 | LLVMValueRef *fn = &g->int_overflow_fns[index0][index1][index2]; | 386 | key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; |
| 405 | if (*fn) { | 387 | key.data.overflow_arithmetic.bit_count = type_entry->data.integral.bit_count; |
| 406 | return *fn; | 388 | |
| 407 | } | 389 | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| | 390 | if (existing_entry) |
| | 391 | return existing_entry->value; |
| | 392 | |
| | 393 | LLVMValueRef fn_val; |
| 408 | switch (add_sub_mul) { | 394 | switch (add_sub_mul) { |
| 409 | case AddSubMulAdd: | 395 | case AddSubMulAdd: |
| 410 | *fn = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd"); | 396 | fn_val = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd"); |
| 411 | break; | 397 | break; |
| 412 | case AddSubMulSub: | 398 | case AddSubMulSub: |
| 413 | *fn = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub"); | 399 | fn_val = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub"); |
| 414 | break; | 400 | break; |
| 415 | case AddSubMulMul: | 401 | case AddSubMulMul: |
| 416 | *fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul"); | 402 | fn_val = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul"); |
| 417 | break; | 403 | break; |
| 418 | | | |
| 419 | } | 404 | } |
| 420 | return *fn; | 405 | |
| | 406 | g->llvm_fn_table.put(key, fn_val); |
| | 407 | return fn_val; |
| 421 | } | 408 | } |
| 422 | | 409 | |
| 423 | static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type, bool is_volatile) { | 410 | static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type, bool is_volatile) { |
| ... | @@ -1388,13 +1375,22 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -1388,13 +1375,22 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 1388 | bool is_volatile = ptr_type->data.pointer.is_volatile; | 1375 | bool is_volatile = ptr_type->data.pointer.is_volatile; |
| 1389 | | 1376 | |
| 1390 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; | 1377 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; |
| 1391 | if (bit_offset == 0) | 1378 | LLVMValueRef containing_int; |
| 1392 | return get_handle_value(g, ptr, child_type, is_volatile); | 1379 | if (bit_offset == 0) { |
| 1393 | | 1380 | LLVMValueRef result_val = get_handle_value(g, ptr, child_type, is_volatile); |
| 1394 | assert(!handle_is_ptr(child_type)); | 1381 | if (LLVMGetTypeKind(LLVMTypeOf(result_val)) == LLVMIntegerTypeKind && |
| 1395 | | 1382 | LLVMGetTypeKind(child_type->type_ref) == LLVMIntegerTypeKind && |
| 1396 | LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, ""); | 1383 | LLVMGetIntTypeWidth(child_type->type_ref) < LLVMGetIntTypeWidth(LLVMTypeOf(result_val))) |
| 1397 | LLVMSetVolatile(containing_int, is_volatile); | 1384 | { |
| | 1385 | containing_int = result_val; |
| | 1386 | } else { |
| | 1387 | return result_val; |
| | 1388 | } |
| | 1389 | } else { |
| | 1390 | assert(!handle_is_ptr(child_type)); |
| | 1391 | containing_int = LLVMBuildLoad(g->builder, ptr, ""); |
| | 1392 | LLVMSetVolatile(containing_int, is_volatile); |
| | 1393 | } |
| 1398 | | 1394 | |
| 1399 | uint32_t child_bit_count = type_size_bits(g, child_type); | 1395 | uint32_t child_bit_count = type_size_bits(g, child_type); |
| 1400 | uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); | 1396 | uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); |
| ... | @@ -1748,21 +1744,34 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, | ... | @@ -1748,21 +1744,34 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, |
| 1748 | } | 1744 | } |
| 1749 | | 1745 | |
| 1750 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) { | 1746 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) { |
| 1751 | // [0-ctz,1-clz][0-8,1-16,2-32,3-64] | 1747 | ZigLLVMFnKey key = {}; |
| 1752 | size_t index0 = (fn_id == BuiltinFnIdCtz) ? 0 : 1; | 1748 | const char *fn_name; |
| 1753 | size_t index1 = bits_index(int_type->data.integral.bit_count); | 1749 | if (fn_id == BuiltinFnIdCtz) { |
| 1754 | LLVMValueRef *fn = &g->int_builtin_fns[index0][index1]; | 1750 | fn_name = "cttz"; |
| 1755 | if (!*fn) { | 1751 | key.id = ZigLLVMFnIdCtz; |
| 1756 | const char *fn_name = (fn_id == BuiltinFnIdCtz) ? "cttz" : "ctlz"; | 1752 | key.data.ctz.bit_count = int_type->data.integral.bit_count; |
| 1757 | Buf *llvm_name = buf_sprintf("llvm.%s.i%zu", fn_name, int_type->data.integral.bit_count); | 1753 | } else { |
| 1758 | LLVMTypeRef param_types[] = { | 1754 | fn_name = "ctlz"; |
| 1759 | int_type->type_ref, | 1755 | key.id = ZigLLVMFnIdClz; |
| 1760 | LLVMInt1Type(), | 1756 | key.data.clz.bit_count = int_type->data.integral.bit_count; |
| 1761 | }; | | |
| 1762 | LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false); | | |
| 1763 | *fn = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type); | | |
| 1764 | } | 1757 | } |
| 1765 | return *fn; | 1758 | |
| | 1759 | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| | 1760 | if (existing_entry) |
| | 1761 | return existing_entry->value; |
| | 1762 | |
| | 1763 | char llvm_name[64]; |
| | 1764 | sprintf(llvm_name, "llvm.%s.i%zu", fn_name, int_type->data.integral.bit_count); |
| | 1765 | LLVMTypeRef param_types[] = { |
| | 1766 | int_type->type_ref, |
| | 1767 | LLVMInt1Type(), |
| | 1768 | }; |
| | 1769 | LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false); |
| | 1770 | LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type); |
| | 1771 | |
| | 1772 | g->llvm_fn_table.put(key, fn_val); |
| | 1773 | |
| | 1774 | return fn_val; |
| 1766 | } | 1775 | } |
| 1767 | | 1776 | |
| 1768 | static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) { | 1777 | static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) { |