| ... | @@ -682,25 +682,141 @@ pub const Object = struct { | ... | @@ -682,25 +682,141 @@ pub const Object = struct { |
| 682 | else | 682 | else |
| 683 | null; | 683 | null; |
| 684 | | 684 | |
| | 685 | // This is the list of args we will use that correspond directly to the AIR arg |
| | 686 | // instructions. Depending on the calling convention, this list is not necessarily |
| | 687 | // a bijection with the actual LLVM parameters of the function. |
| 685 | var args = std.ArrayList(*const llvm.Value).init(gpa); | 688 | var args = std.ArrayList(*const llvm.Value).init(gpa); |
| 686 | defer args.deinit(); | 689 | defer args.deinit(); |
| 687 | | 690 | |
| 688 | const param_offset = @as(c_uint, @boolToInt(ret_ptr != null)) + @boolToInt(err_return_tracing); | 691 | { |
| 689 | for (fn_info.param_types) |param_ty| { | 692 | var llvm_arg_i = @as(c_uint, @boolToInt(ret_ptr != null)) + @boolToInt(err_return_tracing); |
| 690 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 693 | var it = iterateParamTypes(&dg, fn_info); |
| | 694 | while (it.next()) |lowering| switch (lowering) { |
| | 695 | .no_bits => continue, |
| | 696 | .byval => { |
| | 697 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 698 | const param = llvm_func.getParam(llvm_arg_i); |
| | 699 | llvm_arg_i += 1; |
| | 700 | |
| | 701 | if (isByRef(param_ty)) { |
| | 702 | const alignment = param_ty.abiAlignment(target); |
| | 703 | const param_llvm_ty = param.typeOf(); |
| | 704 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| | 705 | arg_ptr.setAlignment(alignment); |
| | 706 | const store_inst = builder.buildStore(param, arg_ptr); |
| | 707 | store_inst.setAlignment(alignment); |
| | 708 | try args.append(arg_ptr); |
| | 709 | } else { |
| | 710 | try args.append(param); |
| | 711 | } |
| | 712 | }, |
| | 713 | .byref => { |
| | 714 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 715 | const param = llvm_func.getParam(llvm_arg_i); |
| | 716 | llvm_arg_i += 1; |
| 691 | | 717 | |
| 692 | const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset; | 718 | if (isByRef(param_ty)) { |
| 693 | const param = llvm_func.getParam(llvm_arg_i); | 719 | try args.append(param); |
| 694 | // It is possible for the calling convention to make the argument's by-reference nature | 720 | } else { |
| 695 | // disagree with our canonical value for it, in which case we must dereference here. | 721 | const alignment = param_ty.abiAlignment(target); |
| 696 | const need_deref = !param_ty.isPtrAtRuntime() and !isByRef(param_ty) and | 722 | const load_inst = builder.buildLoad(param, ""); |
| 697 | (param.typeOf().getTypeKind() == .Pointer); | 723 | load_inst.setAlignment(alignment); |
| 698 | const loaded_param = if (!need_deref) param else l: { | 724 | try args.append(load_inst); |
| 699 | const load_inst = builder.buildLoad(param, ""); | 725 | } |
| 700 | load_inst.setAlignment(param_ty.abiAlignment(target)); | 726 | }, |
| 701 | break :l load_inst; | 727 | .abi_sized_int => { |
| | 728 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 729 | const param = llvm_func.getParam(llvm_arg_i); |
| | 730 | llvm_arg_i += 1; |
| | 731 | |
| | 732 | const param_llvm_ty = try dg.llvmType(param_ty); |
| | 733 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); |
| | 734 | const int_llvm_ty = dg.context.intType(abi_size * 8); |
| | 735 | const int_ptr_llvm_ty = int_llvm_ty.pointerType(0); |
| | 736 | const alignment = @maximum( |
| | 737 | param_ty.abiAlignment(target), |
| | 738 | dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| | 739 | ); |
| | 740 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| | 741 | arg_ptr.setAlignment(alignment); |
| | 742 | const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, ""); |
| | 743 | const store_inst = builder.buildStore(param, casted_ptr); |
| | 744 | store_inst.setAlignment(alignment); |
| | 745 | |
| | 746 | if (isByRef(param_ty)) { |
| | 747 | try args.append(arg_ptr); |
| | 748 | } else { |
| | 749 | const load_inst = builder.buildLoad(arg_ptr, ""); |
| | 750 | load_inst.setAlignment(alignment); |
| | 751 | try args.append(load_inst); |
| | 752 | } |
| | 753 | }, |
| | 754 | .multiple_llvm_ints => { |
| | 755 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 756 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| | 757 | const is_by_ref = isByRef(param_ty); |
| | 758 | switch (param_ty.zigTypeTag()) { |
| | 759 | .Struct => { |
| | 760 | const fields = param_ty.structFields().values(); |
| | 761 | if (is_by_ref) { |
| | 762 | const param_llvm_ty = try dg.llvmType(param_ty); |
| | 763 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| | 764 | arg_ptr.setAlignment(param_ty.abiAlignment(target)); |
| | 765 | |
| | 766 | var field_i: u32 = 0; |
| | 767 | var field_offset: u32 = 0; |
| | 768 | for (llvm_ints) |int_bits| { |
| | 769 | const param = llvm_func.getParam(llvm_arg_i); |
| | 770 | llvm_arg_i += 1; |
| | 771 | |
| | 772 | const big_int_ty = dg.context.intType(int_bits); |
| | 773 | var bits_used: u32 = 0; |
| | 774 | while (bits_used < int_bits) { |
| | 775 | const field = fields[field_i]; |
| | 776 | const field_alignment = field.normalAlignment(target); |
| | 777 | const prev_offset = field_offset; |
| | 778 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| | 779 | if (field_offset > prev_offset) { |
| | 780 | // Padding counts as bits used. |
| | 781 | bits_used += (field_offset - prev_offset) * 8; |
| | 782 | if (bits_used >= int_bits) break; |
| | 783 | } |
| | 784 | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| | 785 | const field_abi_bits = field_size * 8; |
| | 786 | const field_int_ty = dg.context.intType(field_abi_bits); |
| | 787 | const shifted = if (bits_used == 0) param else s: { |
| | 788 | const shift_amt = big_int_ty.constInt(bits_used, .False); |
| | 789 | break :s builder.buildLShr(param, shift_amt, ""); |
| | 790 | }; |
| | 791 | const field_as_int = builder.buildTrunc(shifted, field_int_ty, ""); |
| | 792 | var ty_buf: Type.Payload.Pointer = undefined; |
| | 793 | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| | 794 | const field_ptr = builder.buildStructGEP(arg_ptr, llvm_i, ""); |
| | 795 | const casted_ptr = builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| | 796 | const store_inst = builder.buildStore(field_as_int, casted_ptr); |
| | 797 | store_inst.setAlignment(field_alignment); |
| | 798 | |
| | 799 | field_i += 1; |
| | 800 | if (field_i >= fields.len) break; |
| | 801 | |
| | 802 | bits_used += field_abi_bits; |
| | 803 | field_offset += field_size; |
| | 804 | } |
| | 805 | if (field_i >= fields.len) break; |
| | 806 | } |
| | 807 | |
| | 808 | try args.append(arg_ptr); |
| | 809 | } else { |
| | 810 | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with byval struct parameter"); |
| | 811 | } |
| | 812 | }, |
| | 813 | .Union => { |
| | 814 | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with union parameter"); |
| | 815 | }, |
| | 816 | else => unreachable, |
| | 817 | } |
| | 818 | }, |
| 702 | }; | 819 | }; |
| 703 | try args.append(loaded_param); | | |
| 704 | } | 820 | } |
| 705 | | 821 | |
| 706 | var di_file: ?*llvm.DIFile = null; | 822 | var di_file: ?*llvm.DIFile = null; |
| ... | @@ -2072,22 +2188,31 @@ pub const DeclGen = struct { | ... | @@ -2072,22 +2188,31 @@ pub const DeclGen = struct { |
| 2072 | } | 2188 | } |
| 2073 | | 2189 | |
| 2074 | // Set parameter attributes. | 2190 | // Set parameter attributes. |
| 2075 | var llvm_param_i: c_uint = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing); | | |
| 2076 | for (fn_info.param_types) |param_ty| { | | |
| 2077 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | | |
| 2078 | | | |
| 2079 | if (isByRef(param_ty)) { | | |
| 2080 | dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); | | |
| 2081 | // TODO readonly, noalias, align | | |
| 2082 | } | | |
| 2083 | llvm_param_i += 1; | | |
| 2084 | } | | |
| 2085 | | | |
| 2086 | // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`. | 2191 | // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`. |
| 2087 | if (fn_info.cc == .Naked) { | 2192 | switch (fn_info.cc) { |
| 2088 | dg.addFnAttr(llvm_fn, "naked"); | 2193 | .Unspecified, .Inline => { |
| 2089 | } else { | 2194 | var llvm_param_i: c_uint = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing); |
| 2090 | llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target)); | 2195 | for (fn_info.param_types) |param_ty| { |
| | 2196 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| | 2197 | |
| | 2198 | if (isByRef(param_ty)) { |
| | 2199 | dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); |
| | 2200 | // TODO readonly, noalias, align |
| | 2201 | } |
| | 2202 | llvm_param_i += 1; |
| | 2203 | } |
| | 2204 | llvm_fn.setFunctionCallConv(.Fast); |
| | 2205 | }, |
| | 2206 | .Naked => { |
| | 2207 | dg.addFnAttr(llvm_fn, "naked"); |
| | 2208 | }, |
| | 2209 | .Async => { |
| | 2210 | llvm_fn.setFunctionCallConv(.Fast); |
| | 2211 | @panic("TODO: LLVM backend lower async function"); |
| | 2212 | }, |
| | 2213 | else => { |
| | 2214 | llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target)); |
| | 2215 | }, |
| 2091 | } | 2216 | } |
| 2092 | | 2217 | |
| 2093 | if (fn_info.alignment != 0) { | 2218 | if (fn_info.alignment != 0) { |
| ... | @@ -2518,42 +2643,7 @@ pub const DeclGen = struct { | ... | @@ -2518,42 +2643,7 @@ pub const DeclGen = struct { |
| 2518 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); | 2643 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); |
| 2519 | return llvm_union_ty; | 2644 | return llvm_union_ty; |
| 2520 | }, | 2645 | }, |
| 2521 | .Fn => { | 2646 | .Fn => return llvmTypeFn(dg, t), |
| 2522 | const fn_info = t.fnInfo(); | | |
| 2523 | const llvm_ret_ty = try lowerFnRetTy(dg, fn_info); | | |
| 2524 | | | |
| 2525 | var llvm_params = std.ArrayList(*const llvm.Type).init(dg.gpa); | | |
| 2526 | defer llvm_params.deinit(); | | |
| 2527 | | | |
| 2528 | if (firstParamSRet(fn_info, target)) { | | |
| 2529 | const llvm_sret_ty = try dg.llvmType(fn_info.return_type); | | |
| 2530 | try llvm_params.append(llvm_sret_ty.pointerType(0)); | | |
| 2531 | } | | |
| 2532 | | | |
| 2533 | if (fn_info.return_type.isError() and | | |
| 2534 | dg.module.comp.bin_file.options.error_return_tracing) | | |
| 2535 | { | | |
| 2536 | var ptr_ty_payload: Type.Payload.ElemType = .{ | | |
| 2537 | .base = .{ .tag = .single_mut_pointer }, | | |
| 2538 | .data = dg.object.getStackTraceType(), | | |
| 2539 | }; | | |
| 2540 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | | |
| 2541 | try llvm_params.append(try lowerFnParamTy(dg, fn_info.cc, ptr_ty)); | | |
| 2542 | } | | |
| 2543 | | | |
| 2544 | for (fn_info.param_types) |param_ty| { | | |
| 2545 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | | |
| 2546 | | | |
| 2547 | try llvm_params.append(try lowerFnParamTy(dg, fn_info.cc, param_ty)); | | |
| 2548 | } | | |
| 2549 | | | |
| 2550 | return llvm.functionType( | | |
| 2551 | llvm_ret_ty, | | |
| 2552 | llvm_params.items.ptr, | | |
| 2553 | @intCast(c_uint, llvm_params.items.len), | | |
| 2554 | llvm.Bool.fromBool(fn_info.is_var_args), | | |
| 2555 | ); | | |
| 2556 | }, | | |
| 2557 | .ComptimeInt => unreachable, | 2647 | .ComptimeInt => unreachable, |
| 2558 | .ComptimeFloat => unreachable, | 2648 | .ComptimeFloat => unreachable, |
| 2559 | .Type => unreachable, | 2649 | .Type => unreachable, |
| ... | @@ -2568,6 +2658,119 @@ pub const DeclGen = struct { | ... | @@ -2568,6 +2658,119 @@ pub const DeclGen = struct { |
| 2568 | } | 2658 | } |
| 2569 | } | 2659 | } |
| 2570 | | 2660 | |
| | 2661 | fn llvmTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*const llvm.Type { |
| | 2662 | const target = dg.module.getTarget(); |
| | 2663 | const fn_info = fn_ty.fnInfo(); |
| | 2664 | const llvm_ret_ty = try lowerFnRetTy(dg, fn_info); |
| | 2665 | |
| | 2666 | var llvm_params = std.ArrayList(*const llvm.Type).init(dg.gpa); |
| | 2667 | defer llvm_params.deinit(); |
| | 2668 | |
| | 2669 | if (firstParamSRet(fn_info, target)) { |
| | 2670 | const llvm_sret_ty = try dg.llvmType(fn_info.return_type); |
| | 2671 | try llvm_params.append(llvm_sret_ty.pointerType(0)); |
| | 2672 | } |
| | 2673 | |
| | 2674 | if (fn_info.return_type.isError() and |
| | 2675 | dg.module.comp.bin_file.options.error_return_tracing) |
| | 2676 | { |
| | 2677 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| | 2678 | .base = .{ .tag = .single_mut_pointer }, |
| | 2679 | .data = dg.object.getStackTraceType(), |
| | 2680 | }; |
| | 2681 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| | 2682 | try llvm_params.append(try dg.llvmType(ptr_ty)); |
| | 2683 | } |
| | 2684 | |
| | 2685 | var it = iterateParamTypes(dg, fn_info); |
| | 2686 | while (it.next()) |lowering| switch (lowering) { |
| | 2687 | .no_bits => continue, |
| | 2688 | .byval => { |
| | 2689 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 2690 | try llvm_params.append(try dg.llvmType(param_ty)); |
| | 2691 | }, |
| | 2692 | .byref => { |
| | 2693 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 2694 | const raw_llvm_ty = try dg.llvmType(param_ty); |
| | 2695 | try llvm_params.append(raw_llvm_ty.pointerType(0)); |
| | 2696 | }, |
| | 2697 | .abi_sized_int => { |
| | 2698 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 2699 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); |
| | 2700 | try llvm_params.append(dg.context.intType(abi_size * 8)); |
| | 2701 | }, |
| | 2702 | .multiple_llvm_ints => { |
| | 2703 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 2704 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| | 2705 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); |
| | 2706 | |
| | 2707 | // The reason we have all this logic instead of simply appending |
| | 2708 | // big_int_ty is for the special case of a pointer type; |
| | 2709 | // we want to use a pointer type instead of inttoptr at the callsites, |
| | 2710 | // which may prevent optimization. |
| | 2711 | switch (param_ty.zigTypeTag()) { |
| | 2712 | .Struct => { |
| | 2713 | const fields = param_ty.structFields().values(); |
| | 2714 | var field_i: u32 = 0; |
| | 2715 | var field_offset: u32 = 0; |
| | 2716 | llvm_arg: for (llvm_ints) |int_bits| { |
| | 2717 | const big_int_ty = dg.context.intType(int_bits); |
| | 2718 | var bits_used: u32 = 0; |
| | 2719 | while (bits_used < int_bits) { |
| | 2720 | const field = fields[field_i]; |
| | 2721 | const field_alignment = field.normalAlignment(target); |
| | 2722 | const prev_offset = field_offset; |
| | 2723 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| | 2724 | if (field_offset > prev_offset) { |
| | 2725 | // Padding counts as bits used. |
| | 2726 | bits_used += (field_offset - prev_offset) * 8; |
| | 2727 | if (bits_used >= int_bits) break; |
| | 2728 | } |
| | 2729 | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| | 2730 | const field_abi_bits = field_size * 8; |
| | 2731 | |
| | 2732 | // Special case for when the entire LLVM integer represents |
| | 2733 | // one field; in this case keep the type information |
| | 2734 | // to avoid the potentially costly ptrtoint/bitcast. |
| | 2735 | if (bits_used == 0 and field_abi_bits == int_bits) { |
| | 2736 | const llvm_field_ty = try dg.llvmType(field.ty); |
| | 2737 | llvm_params.appendAssumeCapacity(llvm_field_ty); |
| | 2738 | field_i += 1; |
| | 2739 | if (field_i >= fields.len) { |
| | 2740 | break :llvm_arg; |
| | 2741 | } else { |
| | 2742 | continue :llvm_arg; |
| | 2743 | } |
| | 2744 | } |
| | 2745 | |
| | 2746 | field_i += 1; |
| | 2747 | if (field_i >= fields.len) break; |
| | 2748 | |
| | 2749 | bits_used += field_abi_bits; |
| | 2750 | field_offset += field_size; |
| | 2751 | } |
| | 2752 | llvm_params.appendAssumeCapacity(big_int_ty); |
| | 2753 | if (field_i >= fields.len) break; |
| | 2754 | } |
| | 2755 | }, |
| | 2756 | else => { |
| | 2757 | for (llvm_ints) |int_bits| { |
| | 2758 | const big_int_ty = dg.context.intType(int_bits); |
| | 2759 | llvm_params.appendAssumeCapacity(big_int_ty); |
| | 2760 | } |
| | 2761 | }, |
| | 2762 | } |
| | 2763 | }, |
| | 2764 | }; |
| | 2765 | |
| | 2766 | return llvm.functionType( |
| | 2767 | llvm_ret_ty, |
| | 2768 | llvm_params.items.ptr, |
| | 2769 | @intCast(c_uint, llvm_params.items.len), |
| | 2770 | llvm.Bool.fromBool(fn_info.is_var_args), |
| | 2771 | ); |
| | 2772 | } |
| | 2773 | |
| 2571 | fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value { | 2774 | fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value { |
| 2572 | if (tv.val.isUndef()) { | 2775 | if (tv.val.isUndef()) { |
| 2573 | const llvm_type = try dg.llvmType(tv.ty); | 2776 | const llvm_type = try dg.llvmType(tv.ty); |
| ... | @@ -3848,52 +4051,164 @@ pub const FuncGen = struct { | ... | @@ -3848,52 +4051,164 @@ pub const FuncGen = struct { |
| 3848 | try llvm_args.append(self.err_ret_trace.?); | 4051 | try llvm_args.append(self.err_ret_trace.?); |
| 3849 | } | 4052 | } |
| 3850 | | 4053 | |
| 3851 | for (args) |arg| { | 4054 | var it = iterateParamTypes(self.dg, fn_info); |
| 3852 | const param_ty = self.air.typeOf(arg); | 4055 | while (it.next()) |lowering| switch (lowering) { |
| 3853 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 4056 | .no_bits => continue, |
| 3854 | | 4057 | .byval => { |
| 3855 | const llvm_arg = try self.resolveInst(arg); | 4058 | const arg = args[it.zig_index - 1]; |
| 3856 | const abi_llvm_ty = try lowerFnParamTy(self.dg, fn_info.cc, param_ty); | 4059 | const param_ty = self.air.typeOf(arg); |
| 3857 | const param_llvm_ty = llvm_arg.typeOf(); | 4060 | const llvm_arg = try self.resolveInst(arg); |
| 3858 | if (abi_llvm_ty == param_llvm_ty) { | 4061 | if (isByRef(param_ty)) { |
| 3859 | try llvm_args.append(llvm_arg); | 4062 | const alignment = param_ty.abiAlignment(target); |
| 3860 | continue; | 4063 | const load_inst = self.builder.buildLoad(llvm_arg, ""); |
| 3861 | } | 4064 | load_inst.setAlignment(alignment); |
| 3862 | | 4065 | try llvm_args.append(load_inst); |
| 3863 | // In this case the function param type is honoring the calling convention | 4066 | } else { |
| 3864 | // by having a different LLVM type than the usual one. We solve this here | 4067 | if (param_ty.zigTypeTag() == .Pointer) { |
| 3865 | // at the callsite by bitcasting a pointer to our canonical type, then | 4068 | // We need a bitcast in case of two possibilities: |
| 3866 | // loading it if necessary. | 4069 | // 1. The parameter type is a pointer to zero-sized type, |
| 3867 | const alignment = param_ty.abiAlignment(target); | 4070 | // which is always lowered to an LLVM type of `*i8`. |
| 3868 | const ptr_abi_ty = abi_llvm_ty.pointerType(0); | 4071 | // 2. The argument is a global which does act as a pointer, however |
| 3869 | | 4072 | // a bitcast is needed in order for the LLVM types to match. |
| 3870 | const casted_ptr = if (isByRef(param_ty)) | 4073 | const llvm_param_ty = try self.dg.llvmType(param_ty); |
| 3871 | self.builder.buildBitCast(llvm_arg, ptr_abi_ty, "") | 4074 | const casted_ptr = self.builder.buildBitCast(llvm_arg, llvm_param_ty, ""); |
| 3872 | else p: { | 4075 | try llvm_args.append(casted_ptr); |
| 3873 | const arg_ptr = self.buildAlloca(param_llvm_ty); | 4076 | } else { |
| 3874 | arg_ptr.setAlignment(alignment); | 4077 | try llvm_args.append(llvm_arg); |
| 3875 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); | | |
| 3876 | store_inst.setAlignment(alignment); | | |
| 3877 | | | |
| 3878 | if (abi_llvm_ty.getTypeKind() == .Pointer) { | | |
| 3879 | // In this case, the calling convention wants a pointer, but | | |
| 3880 | // we have a value. | | |
| 3881 | if (arg_ptr.typeOf() == abi_llvm_ty) { | | |
| 3882 | try llvm_args.append(arg_ptr); | | |
| 3883 | continue; | | |
| 3884 | } | 4078 | } |
| 3885 | const casted_ptr = self.builder.buildBitCast(arg_ptr, abi_llvm_ty, ""); | | |
| 3886 | try llvm_args.append(casted_ptr); | | |
| 3887 | continue; | | |
| 3888 | } | 4079 | } |
| 3889 | | 4080 | }, |
| 3890 | break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, ""); | 4081 | .byref => { |
| 3891 | }; | 4082 | const arg = args[it.zig_index - 1]; |
| 3892 | | 4083 | const param_ty = self.air.typeOf(arg); |
| 3893 | const load_inst = self.builder.buildLoad(casted_ptr, ""); | 4084 | const llvm_arg = try self.resolveInst(arg); |
| 3894 | load_inst.setAlignment(alignment); | 4085 | if (isByRef(param_ty)) { |
| 3895 | try llvm_args.append(load_inst); | 4086 | try llvm_args.append(llvm_arg); |
| 3896 | } | 4087 | } else { |
| | 4088 | const alignment = param_ty.abiAlignment(target); |
| | 4089 | const param_llvm_ty = llvm_arg.typeOf(); |
| | 4090 | const arg_ptr = self.buildAlloca(param_llvm_ty); |
| | 4091 | arg_ptr.setAlignment(alignment); |
| | 4092 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); |
| | 4093 | store_inst.setAlignment(alignment); |
| | 4094 | try llvm_args.append(arg_ptr); |
| | 4095 | } |
| | 4096 | }, |
| | 4097 | .abi_sized_int => { |
| | 4098 | const arg = args[it.zig_index - 1]; |
| | 4099 | const param_ty = self.air.typeOf(arg); |
| | 4100 | const llvm_arg = try self.resolveInst(arg); |
| | 4101 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); |
| | 4102 | const int_llvm_ty = self.dg.context.intType(abi_size * 8); |
| | 4103 | const int_ptr_llvm_ty = int_llvm_ty.pointerType(0); |
| | 4104 | |
| | 4105 | if (isByRef(param_ty)) { |
| | 4106 | const alignment = param_ty.abiAlignment(target); |
| | 4107 | const casted_ptr = self.builder.buildBitCast(llvm_arg, int_ptr_llvm_ty, ""); |
| | 4108 | const load_inst = self.builder.buildLoad(casted_ptr, ""); |
| | 4109 | load_inst.setAlignment(alignment); |
| | 4110 | try llvm_args.append(load_inst); |
| | 4111 | } else { |
| | 4112 | // LLVM does not allow bitcasting structs so we must allocate |
| | 4113 | // a local, bitcast its pointer, store, and then load. |
| | 4114 | const alignment = @maximum( |
| | 4115 | param_ty.abiAlignment(target), |
| | 4116 | self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| | 4117 | ); |
| | 4118 | const int_ptr = self.buildAlloca(int_llvm_ty); |
| | 4119 | int_ptr.setAlignment(alignment); |
| | 4120 | const param_llvm_ty = try self.dg.llvmType(param_ty); |
| | 4121 | const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), ""); |
| | 4122 | const store_inst = self.builder.buildStore(llvm_arg, casted_ptr); |
| | 4123 | store_inst.setAlignment(alignment); |
| | 4124 | const load_inst = self.builder.buildLoad(int_ptr, ""); |
| | 4125 | load_inst.setAlignment(alignment); |
| | 4126 | try llvm_args.append(load_inst); |
| | 4127 | } |
| | 4128 | }, |
| | 4129 | .multiple_llvm_ints => { |
| | 4130 | const arg = args[it.zig_index - 1]; |
| | 4131 | const param_ty = self.air.typeOf(arg); |
| | 4132 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| | 4133 | const llvm_arg = try self.resolveInst(arg); |
| | 4134 | const is_by_ref = isByRef(param_ty); |
| | 4135 | try llvm_args.ensureUnusedCapacity(it.llvm_types_len); |
| | 4136 | switch (param_ty.zigTypeTag()) { |
| | 4137 | .Struct => { |
| | 4138 | const fields = param_ty.structFields().values(); |
| | 4139 | var field_i: u32 = 0; |
| | 4140 | var field_offset: u32 = 0; |
| | 4141 | for (llvm_ints) |int_bits| { |
| | 4142 | const big_int_ty = self.dg.context.intType(int_bits); |
| | 4143 | var int_arg: *const llvm.Value = undefined; |
| | 4144 | var bits_used: u32 = 0; |
| | 4145 | while (bits_used < int_bits) { |
| | 4146 | const field = fields[field_i]; |
| | 4147 | const field_alignment = field.normalAlignment(target); |
| | 4148 | const prev_offset = field_offset; |
| | 4149 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| | 4150 | if (field_offset > prev_offset) { |
| | 4151 | // Padding counts as bits used. |
| | 4152 | bits_used += (field_offset - prev_offset) * 8; |
| | 4153 | if (bits_used >= int_bits) break; |
| | 4154 | } |
| | 4155 | var ty_buf: Type.Payload.Pointer = undefined; |
| | 4156 | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| | 4157 | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| | 4158 | const field_abi_bits = field_size * 8; |
| | 4159 | |
| | 4160 | // Special case for when the entire LLVM integer represents |
| | 4161 | // one field; in this case keep the type information |
| | 4162 | // to avoid the potentially costly ptrtoint/bitcast. |
| | 4163 | if (bits_used == 0 and field_abi_bits == int_bits) { |
| | 4164 | int_arg = if (is_by_ref) f: { |
| | 4165 | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); |
| | 4166 | const load_inst = self.builder.buildLoad(field_ptr, ""); |
| | 4167 | load_inst.setAlignment(field_alignment); |
| | 4168 | break :f load_inst; |
| | 4169 | } else self.builder.buildExtractValue(llvm_arg, llvm_i, ""); |
| | 4170 | field_i += 1; |
| | 4171 | break; |
| | 4172 | } |
| | 4173 | |
| | 4174 | const field_int_ty = self.dg.context.intType(field_abi_bits); |
| | 4175 | const llvm_field = if (is_by_ref) f: { |
| | 4176 | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); |
| | 4177 | const casted_ptr = self.builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| | 4178 | const load_inst = self.builder.buildLoad(casted_ptr, ""); |
| | 4179 | load_inst.setAlignment(field_alignment); |
| | 4180 | break :f load_inst; |
| | 4181 | } else f: { |
| | 4182 | const llvm_field = self.builder.buildExtractValue(llvm_arg, llvm_i, ""); |
| | 4183 | break :f self.builder.buildBitCast(llvm_field, field_int_ty, ""); |
| | 4184 | }; |
| | 4185 | |
| | 4186 | const extended = self.builder.buildZExt(llvm_field, big_int_ty, ""); |
| | 4187 | if (bits_used == 0) { |
| | 4188 | int_arg = extended; |
| | 4189 | } else { |
| | 4190 | const shift_amt = big_int_ty.constInt(bits_used, .False); |
| | 4191 | const shifted = self.builder.buildShl(extended, shift_amt, ""); |
| | 4192 | int_arg = self.builder.buildOr(int_arg, shifted, ""); |
| | 4193 | } |
| | 4194 | |
| | 4195 | field_i += 1; |
| | 4196 | if (field_i >= fields.len) break; |
| | 4197 | |
| | 4198 | bits_used += field_abi_bits; |
| | 4199 | field_offset += field_size; |
| | 4200 | } |
| | 4201 | llvm_args.appendAssumeCapacity(int_arg); |
| | 4202 | if (field_i >= fields.len) break; |
| | 4203 | } |
| | 4204 | }, |
| | 4205 | .Union => { |
| | 4206 | return self.todo("airCall C calling convention on x86_64 with union argument ", .{}); |
| | 4207 | }, |
| | 4208 | else => unreachable, |
| | 4209 | } |
| | 4210 | }, |
| | 4211 | }; |
| 3897 | | 4212 | |
| 3898 | const call = self.builder.buildCall( | 4213 | const call = self.builder.buildCall( |
| 3899 | llvm_fn, | 4214 | llvm_fn, |
| ... | @@ -6489,24 +6804,7 @@ pub const FuncGen = struct { | ... | @@ -6489,24 +6804,7 @@ pub const FuncGen = struct { |
| 6489 | /// Use this instead of builder.buildAlloca, because this function makes sure to | 6804 | /// Use this instead of builder.buildAlloca, because this function makes sure to |
| 6490 | /// put the alloca instruction at the top of the function! | 6805 | /// put the alloca instruction at the top of the function! |
| 6491 | fn buildAlloca(self: *FuncGen, llvm_ty: *const llvm.Type) *const llvm.Value { | 6806 | fn buildAlloca(self: *FuncGen, llvm_ty: *const llvm.Type) *const llvm.Value { |
| 6492 | const prev_block = self.builder.getInsertBlock(); | 6807 | return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty); |
| 6493 | const prev_debug_location = self.builder.getCurrentDebugLocation2(); | | |
| 6494 | defer { | | |
| 6495 | self.builder.positionBuilderAtEnd(prev_block); | | |
| 6496 | if (self.di_scope != null) { | | |
| 6497 | self.builder.setCurrentDebugLocation2(prev_debug_location); | | |
| 6498 | } | | |
| 6499 | } | | |
| 6500 | | | |
| 6501 | const entry_block = self.llvm_func.getFirstBasicBlock().?; | | |
| 6502 | if (entry_block.getFirstInstruction()) |first_inst| { | | |
| 6503 | self.builder.positionBuilder(entry_block, first_inst); | | |
| 6504 | } else { | | |
| 6505 | self.builder.positionBuilderAtEnd(entry_block); | | |
| 6506 | } | | |
| 6507 | self.builder.clearCurrentDebugLocation(); | | |
| 6508 | | | |
| 6509 | return self.builder.buildAlloca(llvm_ty, ""); | | |
| 6510 | } | 6808 | } |
| 6511 | | 6809 | |
| 6512 | fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 6810 | fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -8296,99 +8594,171 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. | ... | @@ -8296,99 +8594,171 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 8296 | } | 8594 | } |
| 8297 | } | 8595 | } |
| 8298 | | 8596 | |
| 8299 | fn lowerFnParamTy(dg: *DeclGen, cc: std.builtin.CallingConvention, ty: Type) !*const llvm.Type { | 8597 | const ParamTypeIterator = struct { |
| 8300 | assert(ty.hasRuntimeBitsIgnoreComptime()); | 8598 | dg: *DeclGen, |
| 8301 | const target = dg.module.getTarget(); | 8599 | fn_info: Type.Payload.Function.Data, |
| 8302 | switch (cc) { | 8600 | zig_index: u32, |
| 8303 | .Unspecified, .Inline => { | 8601 | llvm_index: u32, |
| 8304 | const raw_llvm_ty = try dg.llvmType(ty); | 8602 | target: std.Target, |
| 8305 | if (isByRef(ty)) { | 8603 | llvm_types_len: u32, |
| 8306 | return raw_llvm_ty.pointerType(0); | 8604 | llvm_types_buffer: [8]u16, |
| 8307 | } else { | 8605 | |
| 8308 | return raw_llvm_ty; | 8606 | const Lowering = enum { |
| 8309 | } | 8607 | no_bits, |
| 8310 | }, | 8608 | byval, |
| 8311 | .C => { | 8609 | byref, |
| 8312 | const is_scalar = switch (ty.zigTypeTag()) { | 8610 | abi_sized_int, |
| 8313 | .Void, | 8611 | multiple_llvm_ints, |
| 8314 | .Bool, | 8612 | }; |
| 8315 | .NoReturn, | | |
| 8316 | .Int, | | |
| 8317 | .Float, | | |
| 8318 | .Pointer, | | |
| 8319 | .Optional, | | |
| 8320 | .ErrorSet, | | |
| 8321 | .Enum, | | |
| 8322 | .AnyFrame, | | |
| 8323 | .Vector, | | |
| 8324 | => true, | | |
| 8325 | | 8613 | |
| 8326 | else => false, | 8614 | fn next(it: *ParamTypeIterator) ?Lowering { |
| 8327 | }; | 8615 | if (it.zig_index >= it.fn_info.param_types.len) return null; |
| 8328 | switch (target.cpu.arch) { | 8616 | |
| 8329 | .mips, .mipsel => return dg.llvmType(ty), | 8617 | const ty = it.fn_info.param_types[it.zig_index]; |
| 8330 | .x86_64 => switch (target.os.tag) { | 8618 | if (!ty.hasRuntimeBitsIgnoreComptime()) { |
| 8331 | .windows => switch (x86_64_abi.classifyWindows(ty, target)) { | 8619 | it.zig_index += 1; |
| 8332 | .integer => { | 8620 | return .no_bits; |
| | 8621 | } |
| | 8622 | |
| | 8623 | switch (it.fn_info.cc) { |
| | 8624 | .Unspecified, .Inline => { |
| | 8625 | it.zig_index += 1; |
| | 8626 | it.llvm_index += 1; |
| | 8627 | if (isByRef(ty)) { |
| | 8628 | return .byref; |
| | 8629 | } else { |
| | 8630 | return .byval; |
| | 8631 | } |
| | 8632 | }, |
| | 8633 | .Async => { |
| | 8634 | @panic("TODO implement async function lowering in the LLVM backend"); |
| | 8635 | }, |
| | 8636 | .C => { |
| | 8637 | const is_scalar = switch (ty.zigTypeTag()) { |
| | 8638 | .Void, |
| | 8639 | .Bool, |
| | 8640 | .NoReturn, |
| | 8641 | .Int, |
| | 8642 | .Float, |
| | 8643 | .Pointer, |
| | 8644 | .Optional, |
| | 8645 | .ErrorSet, |
| | 8646 | .Enum, |
| | 8647 | .AnyFrame, |
| | 8648 | .Vector, |
| | 8649 | => true, |
| | 8650 | |
| | 8651 | else => false, |
| | 8652 | }; |
| | 8653 | switch (it.target.cpu.arch) { |
| | 8654 | .mips, .mipsel => { |
| | 8655 | it.zig_index += 1; |
| | 8656 | it.llvm_index += 1; |
| | 8657 | return .byval; |
| | 8658 | }, |
| | 8659 | .x86_64 => switch (it.target.os.tag) { |
| | 8660 | .windows => switch (x86_64_abi.classifyWindows(ty, it.target)) { |
| | 8661 | .integer => { |
| | 8662 | if (is_scalar) { |
| | 8663 | it.zig_index += 1; |
| | 8664 | it.llvm_index += 1; |
| | 8665 | return .byval; |
| | 8666 | } else { |
| | 8667 | it.zig_index += 1; |
| | 8668 | it.llvm_index += 1; |
| | 8669 | return .abi_sized_int; |
| | 8670 | } |
| | 8671 | }, |
| | 8672 | .memory => { |
| | 8673 | it.zig_index += 1; |
| | 8674 | it.llvm_index += 1; |
| | 8675 | return .byref; |
| | 8676 | }, |
| | 8677 | .sse => { |
| | 8678 | it.zig_index += 1; |
| | 8679 | it.llvm_index += 1; |
| | 8680 | return .byval; |
| | 8681 | }, |
| | 8682 | else => unreachable, |
| | 8683 | }, |
| | 8684 | else => { |
| 8333 | if (is_scalar) { | 8685 | if (is_scalar) { |
| 8334 | return dg.llvmType(ty); | 8686 | it.zig_index += 1; |
| 8335 | } else { | 8687 | it.llvm_index += 1; |
| 8336 | const abi_size = ty.abiSize(target); | 8688 | return .byval; |
| 8337 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); | 8689 | } |
| | 8690 | const classes = x86_64_abi.classifySystemV(ty, it.target); |
| | 8691 | if (classes[0] == .memory) { |
| | 8692 | it.zig_index += 1; |
| | 8693 | it.llvm_index += 1; |
| | 8694 | return .byref; |
| | 8695 | } |
| | 8696 | var llvm_types_buffer: [8]u16 = undefined; |
| | 8697 | var llvm_types_index: u32 = 0; |
| | 8698 | for (classes) |class| { |
| | 8699 | switch (class) { |
| | 8700 | .integer => { |
| | 8701 | llvm_types_buffer[llvm_types_index] = 64; |
| | 8702 | llvm_types_index += 1; |
| | 8703 | }, |
| | 8704 | .sse => { |
| | 8705 | @panic("TODO"); |
| | 8706 | }, |
| | 8707 | .sseup => { |
| | 8708 | @panic("TODO"); |
| | 8709 | }, |
| | 8710 | .x87 => { |
| | 8711 | @panic("TODO"); |
| | 8712 | }, |
| | 8713 | .x87up => { |
| | 8714 | @panic("TODO"); |
| | 8715 | }, |
| | 8716 | .complex_x87 => { |
| | 8717 | @panic("TODO"); |
| | 8718 | }, |
| | 8719 | .memory => unreachable, // handled above |
| | 8720 | .none => break, |
| | 8721 | } |
| 8338 | } | 8722 | } |
| | 8723 | if (classes[0] == .integer and classes[1] == .none) { |
| | 8724 | it.zig_index += 1; |
| | 8725 | it.llvm_index += 1; |
| | 8726 | return .abi_sized_int; |
| | 8727 | } |
| | 8728 | it.llvm_types_buffer = llvm_types_buffer; |
| | 8729 | it.llvm_types_len = llvm_types_index; |
| | 8730 | it.llvm_index += llvm_types_index; |
| | 8731 | it.zig_index += 1; |
| | 8732 | return .multiple_llvm_ints; |
| 8339 | }, | 8733 | }, |
| 8340 | .memory => return (try dg.llvmType(ty)).pointerType(0), | | |
| 8341 | .sse => return dg.llvmType(ty), | | |
| 8342 | else => unreachable, | | |
| 8343 | }, | 8734 | }, |
| | 8735 | // TODO investigate C ABI for other architectures |
| 8344 | else => { | 8736 | else => { |
| 8345 | if (is_scalar) { | 8737 | it.zig_index += 1; |
| 8346 | return dg.llvmType(ty); | 8738 | it.llvm_index += 1; |
| 8347 | } | 8739 | return .byval; |
| 8348 | const classes = x86_64_abi.classifySystemV(ty, target); | | |
| 8349 | if (classes[0] == .memory) { | | |
| 8350 | return (try dg.llvmType(ty)).pointerType(0); | | |
| 8351 | } | | |
| 8352 | var llvm_types_buffer: [8]*const llvm.Type = undefined; | | |
| 8353 | var llvm_types_index: u32 = 0; | | |
| 8354 | for (classes) |class| { | | |
| 8355 | switch (class) { | | |
| 8356 | .integer => { | | |
| 8357 | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); | | |
| 8358 | llvm_types_index += 1; | | |
| 8359 | }, | | |
| 8360 | .sse => { | | |
| 8361 | @panic("TODO"); | | |
| 8362 | }, | | |
| 8363 | .sseup => { | | |
| 8364 | @panic("TODO"); | | |
| 8365 | }, | | |
| 8366 | .x87 => { | | |
| 8367 | @panic("TODO"); | | |
| 8368 | }, | | |
| 8369 | .x87up => { | | |
| 8370 | @panic("TODO"); | | |
| 8371 | }, | | |
| 8372 | .complex_x87 => { | | |
| 8373 | @panic("TODO"); | | |
| 8374 | }, | | |
| 8375 | .memory => unreachable, // handled above | | |
| 8376 | .none => break, | | |
| 8377 | } | | |
| 8378 | } | | |
| 8379 | if (classes[0] == .integer and classes[1] == .none) { | | |
| 8380 | const abi_size = ty.abiSize(target); | | |
| 8381 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); | | |
| 8382 | } | | |
| 8383 | return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False); | | |
| 8384 | }, | 8740 | }, |
| 8385 | }, | 8741 | } |
| 8386 | // TODO investigate C ABI for other architectures | 8742 | }, |
| 8387 | else => return dg.llvmType(ty), | 8743 | else => { |
| 8388 | } | 8744 | it.zig_index += 1; |
| 8389 | }, | 8745 | it.llvm_index += 1; |
| 8390 | else => return dg.llvmType(ty), | 8746 | return .byval; |
| | 8747 | }, |
| | 8748 | } |
| 8391 | } | 8749 | } |
| | 8750 | }; |
| | 8751 | |
| | 8752 | fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTypeIterator { |
| | 8753 | return .{ |
| | 8754 | .dg = dg, |
| | 8755 | .fn_info = fn_info, |
| | 8756 | .zig_index = 0, |
| | 8757 | .llvm_index = 0, |
| | 8758 | .target = dg.module.getTarget(), |
| | 8759 | .llvm_types_buffer = undefined, |
| | 8760 | .llvm_types_len = 0, |
| | 8761 | }; |
| 8392 | } | 8762 | } |
| 8393 | | 8763 | |
| 8394 | fn isByRef(ty: Type) bool { | 8764 | fn isByRef(ty: Type) bool { |
| ... | @@ -8549,3 +8919,29 @@ fn compilerRtIntBits(bits: u16) u16 { | ... | @@ -8549,3 +8919,29 @@ fn compilerRtIntBits(bits: u16) u16 { |
| 8549 | } | 8919 | } |
| 8550 | return bits; | 8920 | return bits; |
| 8551 | } | 8921 | } |
| | 8922 | |
| | 8923 | fn buildAllocaInner( |
| | 8924 | builder: *const llvm.Builder, |
| | 8925 | llvm_func: *const llvm.Value, |
| | 8926 | di_scope_non_null: bool, |
| | 8927 | llvm_ty: *const llvm.Type, |
| | 8928 | ) *const llvm.Value { |
| | 8929 | const prev_block = builder.getInsertBlock(); |
| | 8930 | const prev_debug_location = builder.getCurrentDebugLocation2(); |
| | 8931 | defer { |
| | 8932 | builder.positionBuilderAtEnd(prev_block); |
| | 8933 | if (di_scope_non_null) { |
| | 8934 | builder.setCurrentDebugLocation2(prev_debug_location); |
| | 8935 | } |
| | 8936 | } |
| | 8937 | |
| | 8938 | const entry_block = llvm_func.getFirstBasicBlock().?; |
| | 8939 | if (entry_block.getFirstInstruction()) |first_inst| { |
| | 8940 | builder.positionBuilder(entry_block, first_inst); |
| | 8941 | } else { |
| | 8942 | builder.positionBuilderAtEnd(entry_block); |
| | 8943 | } |
| | 8944 | builder.clearCurrentDebugLocation(); |
| | 8945 | |
| | 8946 | return builder.buildAlloca(llvm_ty, ""); |
| | 8947 | } |