authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-02-23 00:51:40+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-23 00:51:40+01:00
log5e203e157b0188a57ce43b876ab4d1877f1dfea1
tree17440ee9d22fb5e83edcbd846a471e76c1a92ac6
parent813312f0e871d436581c5d0be8700ee04aa2fb97
parent21eb75749722668632da55499831eedc62120d61
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22903 from alexrp/llvm-nobuiltin-memcpy-inline

`llvm`: Use inline variants of `memcpy`/`memset` intrinsics when using `-fno-builtin`

2 files changed, 83 insertions(+), 18 deletions(-)

src/codegen/llvm.zig+64-10
...@@ -5771,6 +5771,7 @@ pub const FuncGen = struct {...@@ -5771,6 +5771,7 @@ pub const FuncGen = struct {
5771 try o.builder.intValue(.i8, 0xaa),5771 try o.builder.intValue(.i8, 0xaa),
5772 len,5772 len,
5773 if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,5773 if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,
5774 self.ng.ownerModule().no_builtin,
5774 );5775 );
5775 const owner_mod = self.ng.ownerModule();5776 const owner_mod = self.ng.ownerModule();
5776 if (owner_mod.valgrind) {5777 if (owner_mod.valgrind) {
...@@ -5821,6 +5822,7 @@ pub const FuncGen = struct {...@@ -5821,6 +5822,7 @@ pub const FuncGen = struct {
5821 try o.builder.intValue(.i8, 0xaa),5822 try o.builder.intValue(.i8, 0xaa),
5822 len,5823 len,
5823 .normal,5824 .normal,
5825 self.ng.ownerModule().no_builtin,
5824 );5826 );
5825 const owner_mod = self.ng.ownerModule();5827 const owner_mod = self.ng.ownerModule();
5826 if (owner_mod.valgrind) {5828 if (owner_mod.valgrind) {
...@@ -5902,7 +5904,7 @@ pub const FuncGen = struct {...@@ -5902,7 +5904,7 @@ pub const FuncGen = struct {
5902 const result_alignment = va_list_ty.abiAlignment(pt.zcu).toLlvm();5904 const result_alignment = va_list_ty.abiAlignment(pt.zcu).toLlvm();
5903 const dest_list = try self.buildAllocaWorkaround(va_list_ty, result_alignment);5905 const dest_list = try self.buildAllocaWorkaround(va_list_ty, result_alignment);
59045906
5905 _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, "");5907 _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{dest_list.typeOfWip(&self.wip)}, &.{ dest_list, src_list }, "");
5906 return if (isByRef(va_list_ty, zcu))5908 return if (isByRef(va_list_ty, zcu))
5907 dest_list5909 dest_list
5908 else5910 else
...@@ -5913,7 +5915,7 @@ pub const FuncGen = struct {...@@ -5913,7 +5915,7 @@ pub const FuncGen = struct {
5913 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5915 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5914 const src_list = try self.resolveInst(un_op);5916 const src_list = try self.resolveInst(un_op);
59155917
5916 _ = try self.wip.callIntrinsic(.normal, .none, .va_end, &.{}, &.{src_list}, "");5918 _ = try self.wip.callIntrinsic(.normal, .none, .va_end, &.{src_list.typeOfWip(&self.wip)}, &.{src_list}, "");
5917 return .none;5919 return .none;
5918 }5920 }
59195921
...@@ -5927,7 +5929,7 @@ pub const FuncGen = struct {...@@ -5927,7 +5929,7 @@ pub const FuncGen = struct {
5927 const result_alignment = va_list_ty.abiAlignment(pt.zcu).toLlvm();5929 const result_alignment = va_list_ty.abiAlignment(pt.zcu).toLlvm();
5928 const dest_list = try self.buildAllocaWorkaround(va_list_ty, result_alignment);5930 const dest_list = try self.buildAllocaWorkaround(va_list_ty, result_alignment);
59295931
5930 _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, "");5932 _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{dest_list.typeOfWip(&self.wip)}, &.{dest_list}, "");
5931 return if (isByRef(va_list_ty, zcu))5933 return if (isByRef(va_list_ty, zcu))
5932 dest_list5934 dest_list
5933 else5935 else
...@@ -9734,6 +9736,7 @@ pub const FuncGen = struct {...@@ -9734,6 +9736,7 @@ pub const FuncGen = struct {
9734 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),9736 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),
9735 len,9737 len,
9736 if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,9738 if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,
9739 self.ng.ownerModule().no_builtin,
9737 );9740 );
9738 if (safety and owner_mod.valgrind) {9741 if (safety and owner_mod.valgrind) {
9739 try self.valgrindMarkUndef(dest_ptr, len);9742 try self.valgrindMarkUndef(dest_ptr, len);
...@@ -10041,9 +10044,22 @@ pub const FuncGen = struct {...@@ -10041,9 +10044,22 @@ pub const FuncGen = struct {
10041 try o.builder.undefValue(.i8);10044 try o.builder.undefValue(.i8);
10042 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);10045 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
10043 if (intrinsic_len0_traps) {10046 if (intrinsic_len0_traps) {
10044 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind);10047 try self.safeWasmMemset(
10048 dest_ptr,
10049 fill_byte,
10050 len,
10051 dest_ptr_align,
10052 access_kind,
10053 );
10045 } else {10054 } else {
10046 _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);10055 _ = try self.wip.callMemSet(
10056 dest_ptr,
10057 dest_ptr_align,
10058 fill_byte,
10059 len,
10060 access_kind,
10061 self.ng.ownerModule().no_builtin,
10062 );
10047 }10063 }
10048 const owner_mod = self.ng.ownerModule();10064 const owner_mod = self.ng.ownerModule();
10049 if (safety and owner_mod.valgrind) {10065 if (safety and owner_mod.valgrind) {
...@@ -10060,9 +10076,22 @@ pub const FuncGen = struct {...@@ -10060,9 +10076,22 @@ pub const FuncGen = struct {
10060 const fill_byte = try o.builder.intValue(.i8, byte_val);10076 const fill_byte = try o.builder.intValue(.i8, byte_val);
10061 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);10077 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
10062 if (intrinsic_len0_traps) {10078 if (intrinsic_len0_traps) {
10063 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind);10079 try self.safeWasmMemset(
10080 dest_ptr,
10081 fill_byte,
10082 len,
10083 dest_ptr_align,
10084 access_kind,
10085 );
10064 } else {10086 } else {
10065 _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);10087 _ = try self.wip.callMemSet(
10088 dest_ptr,
10089 dest_ptr_align,
10090 fill_byte,
10091 len,
10092 access_kind,
10093 self.ng.ownerModule().no_builtin,
10094 );
10066 }10095 }
10067 return .none;10096 return .none;
10068 }10097 }
...@@ -10077,9 +10106,22 @@ pub const FuncGen = struct {...@@ -10077,9 +10106,22 @@ pub const FuncGen = struct {
10077 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);10106 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
1007810107
10079 if (intrinsic_len0_traps) {10108 if (intrinsic_len0_traps) {
10080 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind);10109 try self.safeWasmMemset(
10110 dest_ptr,
10111 fill_byte,
10112 len,
10113 dest_ptr_align,
10114 access_kind,
10115 );
10081 } else {10116 } else {
10082 _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);10117 _ = try self.wip.callMemSet(
10118 dest_ptr,
10119 dest_ptr_align,
10120 fill_byte,
10121 len,
10122 access_kind,
10123 self.ng.ownerModule().no_builtin,
10124 );
10083 }10125 }
10084 return .none;10126 return .none;
10085 }10127 }
...@@ -10131,6 +10173,7 @@ pub const FuncGen = struct {...@@ -10131,6 +10173,7 @@ pub const FuncGen = struct {
10131 elem_abi_align.toLlvm(),10173 elem_abi_align.toLlvm(),
10132 try o.builder.intValue(llvm_usize_ty, elem_abi_size),10174 try o.builder.intValue(llvm_usize_ty, elem_abi_size),
10133 access_kind,10175 access_kind,
10176 self.ng.ownerModule().no_builtin,
10134 );10177 );
10135 } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align);10178 } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align);
10136 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{10179 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
...@@ -10158,7 +10201,14 @@ pub const FuncGen = struct {...@@ -10158,7 +10201,14 @@ pub const FuncGen = struct {
10158 const end_block = try self.wip.block(2, "MemsetTrapEnd");10201 const end_block = try self.wip.block(2, "MemsetTrapEnd");
10159 _ = try self.wip.brCond(cond, memset_block, end_block, .none);10202 _ = try self.wip.brCond(cond, memset_block, end_block, .none);
10160 self.wip.cursor = .{ .block = memset_block };10203 self.wip.cursor = .{ .block = memset_block };
10161 _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);10204 _ = try self.wip.callMemSet(
10205 dest_ptr,
10206 dest_ptr_align,
10207 fill_byte,
10208 len,
10209 access_kind,
10210 self.ng.ownerModule().no_builtin,
10211 );
10162 _ = try self.wip.br(end_block);10212 _ = try self.wip.br(end_block);
10163 self.wip.cursor = .{ .block = end_block };10213 self.wip.cursor = .{ .block = end_block };
10164 }10214 }
...@@ -10200,6 +10250,7 @@ pub const FuncGen = struct {...@@ -10200,6 +10250,7 @@ pub const FuncGen = struct {
10200 src_ptr_ty.ptrAlignment(zcu).toLlvm(),10250 src_ptr_ty.ptrAlignment(zcu).toLlvm(),
10201 len,10251 len,
10202 access_kind,10252 access_kind,
10253 self.ng.ownerModule().no_builtin,
10203 );10254 );
10204 _ = try self.wip.br(end_block);10255 _ = try self.wip.br(end_block);
10205 self.wip.cursor = .{ .block = end_block };10256 self.wip.cursor = .{ .block = end_block };
...@@ -10213,6 +10264,7 @@ pub const FuncGen = struct {...@@ -10213,6 +10264,7 @@ pub const FuncGen = struct {
10213 src_ptr_ty.ptrAlignment(zcu).toLlvm(),10264 src_ptr_ty.ptrAlignment(zcu).toLlvm(),
10214 len,10265 len,
10215 access_kind,10266 access_kind,
10267 self.ng.ownerModule().no_builtin,
10216 );10268 );
10217 return .none;10269 return .none;
10218 }10270 }
...@@ -11346,6 +11398,7 @@ pub const FuncGen = struct {...@@ -11346,6 +11398,7 @@ pub const FuncGen = struct {
11346 ptr_alignment,11398 ptr_alignment,
11347 try o.builder.intValue(try o.lowerType(Type.usize), size_bytes),11399 try o.builder.intValue(try o.lowerType(Type.usize), size_bytes),
11348 access_kind,11400 access_kind,
11401 fg.ng.ownerModule().no_builtin,
11349 );11402 );
11350 return result_ptr;11403 return result_ptr;
11351 }11404 }
...@@ -11513,6 +11566,7 @@ pub const FuncGen = struct {...@@ -11513,6 +11566,7 @@ pub const FuncGen = struct {
11513 elem_ty.abiAlignment(zcu).toLlvm(),11566 elem_ty.abiAlignment(zcu).toLlvm(),
11514 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(zcu)),11567 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(zcu)),
11515 access_kind,11568 access_kind,
11569 self.ng.ownerModule().no_builtin,
11516 );11570 );
11517 }11571 }
1151811572
src/codegen/llvm/Builder.zig+19-8
...@@ -2634,6 +2634,7 @@ pub const Intrinsic = enum {...@@ -2634,6 +2634,7 @@ pub const Intrinsic = enum {
2634 cos,2634 cos,
2635 pow,2635 pow,
2636 exp,2636 exp,
2637 exp10,
2637 exp2,2638 exp2,
2638 ldexp,2639 ldexp,
2639 frexp,2640 frexp,
...@@ -2801,22 +2802,22 @@ pub const Intrinsic = enum {...@@ -2801,22 +2802,22 @@ pub const Intrinsic = enum {
2801 .va_start = .{2802 .va_start = .{
2802 .ret_len = 0,2803 .ret_len = 0,
2803 .params = &.{2804 .params = &.{
2804 .{ .kind = .{ .type = .ptr } },2805 .{ .kind = .overloaded },
2805 },2806 },
2806 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },2807 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2807 },2808 },
2808 .va_end = .{2809 .va_end = .{
2809 .ret_len = 0,2810 .ret_len = 0,
2810 .params = &.{2811 .params = &.{
2811 .{ .kind = .{ .type = .ptr } },2812 .{ .kind = .overloaded },
2812 },2813 },
2813 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },2814 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2814 },2815 },
2815 .va_copy = .{2816 .va_copy = .{
2816 .ret_len = 0,2817 .ret_len = 0,
2817 .params = &.{2818 .params = &.{
2818 .{ .kind = .{ .type = .ptr } },2819 .{ .kind = .overloaded },
2819 .{ .kind = .{ .type = .ptr } },2820 .{ .kind = .{ .matches = 0 } },
2820 },2821 },
2821 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },2822 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
2822 },2823 },
...@@ -2929,7 +2930,7 @@ pub const Intrinsic = enum {...@@ -2929,7 +2930,7 @@ pub const Intrinsic = enum {
2929 .params = &.{2930 .params = &.{
2930 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },2931 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
2931 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },2932 .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
2932 .{ .kind = .overloaded, .attrs = &.{.immarg} },2933 .{ .kind = .overloaded },
2933 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },2934 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2934 },2935 },
2935 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },2936 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
...@@ -2959,7 +2960,7 @@ pub const Intrinsic = enum {...@@ -2959,7 +2960,7 @@ pub const Intrinsic = enum {
2959 .params = &.{2960 .params = &.{
2960 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },2961 .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
2961 .{ .kind = .{ .type = .i8 } },2962 .{ .kind = .{ .type = .i8 } },
2962 .{ .kind = .overloaded, .attrs = &.{.immarg} },2963 .{ .kind = .overloaded },
2963 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },2964 .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
2964 },2965 },
2965 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },2966 .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
...@@ -3022,6 +3023,14 @@ pub const Intrinsic = enum {...@@ -3022,6 +3023,14 @@ pub const Intrinsic = enum {
3022 },3023 },
3023 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },3024 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3024 },3025 },
3026 .exp10 = .{
3027 .ret_len = 1,
3028 .params = &.{
3029 .{ .kind = .overloaded },
3030 .{ .kind = .{ .matches = 0 } },
3031 },
3032 .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
3033 },
3025 .ldexp = .{3034 .ldexp = .{
3026 .ret_len = 1,3035 .ret_len = 1,
3027 .params = &.{3036 .params = &.{
...@@ -6093,6 +6102,7 @@ pub const WipFunction = struct {...@@ -6093,6 +6102,7 @@ pub const WipFunction = struct {
6093 src_align: Alignment,6102 src_align: Alignment,
6094 len: Value,6103 len: Value,
6095 kind: MemoryAccessKind,6104 kind: MemoryAccessKind,
6105 @"inline": bool,
6096 ) Allocator.Error!Instruction.Index {6106 ) Allocator.Error!Instruction.Index {
6097 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};6107 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6098 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};6108 var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
...@@ -6104,7 +6114,7 @@ pub const WipFunction = struct {...@@ -6104,7 +6114,7 @@ pub const WipFunction = struct {
6104 try self.builder.attrs(&dst_attrs),6114 try self.builder.attrs(&dst_attrs),
6105 try self.builder.attrs(&src_attrs),6115 try self.builder.attrs(&src_attrs),
6106 }),6116 }),
6107 .memcpy,6117 if (@"inline") .@"memcpy.inline" else .memcpy,
6108 &.{ dst.typeOfWip(self), src.typeOfWip(self), len.typeOfWip(self) },6118 &.{ dst.typeOfWip(self), src.typeOfWip(self), len.typeOfWip(self) },
6109 &.{ dst, src, len, switch (kind) {6119 &.{ dst, src, len, switch (kind) {
6110 .normal => Value.false,6120 .normal => Value.false,
...@@ -6122,12 +6132,13 @@ pub const WipFunction = struct {...@@ -6122,12 +6132,13 @@ pub const WipFunction = struct {
6122 val: Value,6132 val: Value,
6123 len: Value,6133 len: Value,
6124 kind: MemoryAccessKind,6134 kind: MemoryAccessKind,
6135 @"inline": bool,
6125 ) Allocator.Error!Instruction.Index {6136 ) Allocator.Error!Instruction.Index {
6126 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};6137 var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
6127 const value = try self.callIntrinsic(6138 const value = try self.callIntrinsic(
6128 .normal,6139 .normal,
6129 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),6140 try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
6130 .memset,6141 if (@"inline") .@"memset.inline" else .memset,
6131 &.{ dst.typeOfWip(self), len.typeOfWip(self) },6142 &.{ dst.typeOfWip(self), len.typeOfWip(self) },
6132 &.{ dst, val, len, switch (kind) {6143 &.{ dst, val, len, switch (kind) {
6133 .normal => Value.false,6144 .normal => Value.false,