| ... | ... | @@ -62,6 +62,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { |
| 62 | 62 | g->fn_type_table.init(32); |
| 63 | 63 | g->error_table.init(16); |
| 64 | 64 | g->generic_table.init(16); |
| 65 | g->llvm_fn_table.init(16); |
| 65 | 66 | g->memoized_fn_eval_table.init(16); |
| 66 | 67 | g->is_release_build = false; |
| 67 | 68 | g->is_test_build = false; |
| ... | ... | @@ -352,33 +353,14 @@ static void clear_debug_source_node(CodeGen *g) { |
| 352 | 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 | 356 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, |
| 377 | 357 | const char *signed_name, const char *unsigned_name) |
| 378 | 358 | { |
| 359 | char fn_name[64]; |
| 360 | |
| 379 | 361 | assert(type_entry->id == TypeTableEntryIdInt); |
| 380 | 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 | 365 | LLVMTypeRef return_elem_types[] = { |
| 384 | 366 | type_entry->type_ref, |
| ... | ... | @@ -390,34 +372,39 @@ static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_ |
| 390 | 372 | }; |
| 391 | 373 | LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); |
| 392 | 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 | 376 | assert(LLVMGetIntrinsicID(fn_val)); |
| 395 | 377 | return fn_val; |
| 396 | 378 | } |
| 397 | 379 | |
| 398 | 380 | static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul add_sub_mul) { |
| 399 | 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] |
| 401 | | size_t index0 = type_entry->data.integral.is_signed ? 0 : 1; |
| 402 | | size_t index1 = add_sub_mul; |
| 403 | | size_t index2 = bits_index(type_entry->data.integral.bit_count); |
| 404 | | LLVMValueRef *fn = &g->int_overflow_fns[index0][index1][index2]; |
| 405 | | if (*fn) { |
| 406 | | return *fn; |
| 407 | | } |
| 382 | |
| 383 | ZigLLVMFnKey key = {}; |
| 384 | key.id = ZigLLVMFnIdOverflowArithmetic; |
| 385 | key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed; |
| 386 | key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; |
| 387 | key.data.overflow_arithmetic.bit_count = type_entry->data.integral.bit_count; |
| 388 | |
| 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 | 394 | switch (add_sub_mul) { |
| 409 | 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 | 397 | break; |
| 412 | 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 | 400 | break; |
| 415 | 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 | 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 | 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 | 1375 | bool is_volatile = ptr_type->data.pointer.is_volatile; |
| 1389 | 1376 | |
| 1390 | 1377 | uint32_t bit_offset = ptr_type->data.pointer.bit_offset; |
| 1391 | | if (bit_offset == 0) |
| 1392 | | return get_handle_value(g, ptr, child_type, is_volatile); |
| 1393 | | |
| 1394 | | assert(!handle_is_ptr(child_type)); |
| 1395 | | |
| 1396 | | LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, ""); |
| 1397 | | LLVMSetVolatile(containing_int, is_volatile); |
| 1378 | LLVMValueRef containing_int; |
| 1379 | if (bit_offset == 0) { |
| 1380 | LLVMValueRef result_val = get_handle_value(g, ptr, child_type, is_volatile); |
| 1381 | if (LLVMGetTypeKind(LLVMTypeOf(result_val)) == LLVMIntegerTypeKind && |
| 1382 | LLVMGetTypeKind(child_type->type_ref) == LLVMIntegerTypeKind && |
| 1383 | LLVMGetIntTypeWidth(child_type->type_ref) < LLVMGetIntTypeWidth(LLVMTypeOf(result_val))) |
| 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 | 1395 | uint32_t child_bit_count = type_size_bits(g, child_type); |
| 1400 | 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 | 1744 | } |
| 1749 | 1745 | |
| 1750 | 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] |
| 1752 | | size_t index0 = (fn_id == BuiltinFnIdCtz) ? 0 : 1; |
| 1753 | | size_t index1 = bits_index(int_type->data.integral.bit_count); |
| 1754 | | LLVMValueRef *fn = &g->int_builtin_fns[index0][index1]; |
| 1755 | | if (!*fn) { |
| 1756 | | const char *fn_name = (fn_id == BuiltinFnIdCtz) ? "cttz" : "ctlz"; |
| 1757 | | Buf *llvm_name = buf_sprintf("llvm.%s.i%zu", fn_name, int_type->data.integral.bit_count); |
| 1758 | | LLVMTypeRef param_types[] = { |
| 1759 | | int_type->type_ref, |
| 1760 | | LLVMInt1Type(), |
| 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); |
| 1747 | ZigLLVMFnKey key = {}; |
| 1748 | const char *fn_name; |
| 1749 | if (fn_id == BuiltinFnIdCtz) { |
| 1750 | fn_name = "cttz"; |
| 1751 | key.id = ZigLLVMFnIdCtz; |
| 1752 | key.data.ctz.bit_count = int_type->data.integral.bit_count; |
| 1753 | } else { |
| 1754 | fn_name = "ctlz"; |
| 1755 | key.id = ZigLLVMFnIdClz; |
| 1756 | key.data.clz.bit_count = int_type->data.integral.bit_count; |
| 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 | 1777 | static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) { |