authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-30 14:45:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-30 14:45:03-07:00
logfb81ba87620467de11db6b904741b4aafc7cb756
treef67ac23cd5c4136521e4f16854a9a207b1673688
parent1e21876de25f5725dd093f2243bcfdb3f6c6c44e

LLVM: fix extern functions missing attributes

Extern functions were missing attributes such as "readonly" on non-optional pointers, and "byval" which is required to match C ABI. Follow-up from bf28765a975355c27558eaa86cf00ccb29b663a7. closes #12683

2 files changed, 92 insertions(+), 36 deletions(-)

src/codegen/llvm.zig+91-35
...@@ -910,10 +910,11 @@ pub const Object = struct {...@@ -910,10 +910,11 @@ pub const Object = struct {
910 while (it.next()) |lowering| switch (lowering) {910 while (it.next()) |lowering| switch (lowering) {
911 .no_bits => continue,911 .no_bits => continue,
912 .byval => {912 .byval => {
913 const param_ty = fn_info.param_types[it.zig_index - 1];913 assert(!it.byval_attr);
914 const param_index = it.zig_index - 1;
915 const param_ty = fn_info.param_types[param_index];
914 const param = llvm_func.getParam(llvm_arg_i);916 const param = llvm_func.getParam(llvm_arg_i);
915 try args.ensureUnusedCapacity(1);917 try args.ensureUnusedCapacity(1);
916 assert(!it.byval_attr);
917918
918 if (isByRef(param_ty)) {919 if (isByRef(param_ty)) {
919 const alignment = param_ty.abiAlignment(target);920 const alignment = param_ty.abiAlignment(target);
...@@ -926,32 +927,7 @@ pub const Object = struct {...@@ -926,32 +927,7 @@ pub const Object = struct {
926 } else {927 } else {
927 args.appendAssumeCapacity(param);928 args.appendAssumeCapacity(param);
928929
929 if (param_ty.isPtrAtRuntime()) {930 dg.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
930 const ptr_info = param_ty.ptrInfo().data;
931 if (math.cast(u5, it.zig_index - 1)) |i| {
932 if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
933 dg.addArgAttr(llvm_func, llvm_arg_i, "noalias");
934 }
935 }
936 if (!param_ty.isPtrLikeOptional() and !ptr_info.@"allowzero") {
937 dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
938 }
939 if (!ptr_info.mutable) {
940 dg.addArgAttr(llvm_func, llvm_arg_i, "readonly");
941 }
942 if (ptr_info.@"align" != 0) {
943 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align");
944 } else {
945 const elem_align = @maximum(
946 ptr_info.pointee_type.abiAlignment(target),
947 1,
948 );
949 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
950 }
951 } else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) {
952 .signed => dg.addArgAttr(llvm_func, llvm_arg_i, "signext"),
953 .unsigned => dg.addArgAttr(llvm_func, llvm_arg_i, "zeroext"),
954 };
955 }931 }
956 llvm_arg_i += 1;932 llvm_arg_i += 1;
957 },933 },
...@@ -961,13 +937,7 @@ pub const Object = struct {...@@ -961,13 +937,7 @@ pub const Object = struct {
961 const param = llvm_func.getParam(llvm_arg_i);937 const param = llvm_func.getParam(llvm_arg_i);
962 const alignment = param_ty.abiAlignment(target);938 const alignment = param_ty.abiAlignment(target);
963939
964 dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");940 dg.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
965 dg.addArgAttr(llvm_func, llvm_arg_i, "readonly");
966 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", alignment);
967 if (it.byval_attr) {
968 llvm_func.addByValAttr(llvm_arg_i, param_llvm_ty);
969 }
970
971 llvm_arg_i += 1;941 llvm_arg_i += 1;
972942
973 try args.ensureUnusedCapacity(1);943 try args.ensureUnusedCapacity(1);
...@@ -2531,6 +2501,39 @@ pub const DeclGen = struct {...@@ -2531,6 +2501,39 @@ pub const DeclGen = struct {
2531 dg.addFnAttr(llvm_fn, "noreturn");2501 dg.addFnAttr(llvm_fn, "noreturn");
2532 }2502 }
25332503
2504 // Add parameter attributes. We handle only the case of extern functions (no body)
2505 // because functions with bodies are handled in `updateFunc`.
2506 if (is_extern) {
2507 var it = iterateParamTypes(dg, fn_info);
2508 it.llvm_index += @boolToInt(sret);
2509 it.llvm_index += @boolToInt(err_return_tracing);
2510 while (it.next()) |lowering| switch (lowering) {
2511 .byval => {
2512 const param_index = it.zig_index - 1;
2513 const param_ty = fn_info.param_types[param_index];
2514 if (!isByRef(param_ty)) {
2515 dg.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
2516 }
2517 },
2518 .byref => {
2519 const param_ty = fn_info.param_types[it.zig_index - 1];
2520 const param_llvm_ty = try dg.lowerType(param_ty);
2521 const alignment = param_ty.abiAlignment(target);
2522 dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
2523 },
2524 // No attributes needed for these.
2525 .no_bits,
2526 .abi_sized_int,
2527 .multiple_llvm_ints,
2528 .multiple_llvm_float,
2529 .as_u16,
2530 => continue,
2531
2532 .slice => unreachable, // extern functions do not support slice types.
2533
2534 };
2535 }
2536
2534 return llvm_fn;2537 return llvm_fn;
2535 }2538 }
25362539
...@@ -4141,6 +4144,59 @@ pub const DeclGen = struct {...@@ -4141,6 +4144,59 @@ pub const DeclGen = struct {
4141 return null;4144 return null;
4142 }4145 }
4143 }4146 }
4147
4148 fn addByValParamAttrs(
4149 dg: DeclGen,
4150 llvm_fn: *const llvm.Value,
4151 param_ty: Type,
4152 param_index: u32,
4153 fn_info: Type.Payload.Function.Data,
4154 llvm_arg_i: u32,
4155 ) void {
4156 const target = dg.module.getTarget();
4157 if (param_ty.isPtrAtRuntime()) {
4158 const ptr_info = param_ty.ptrInfo().data;
4159 if (math.cast(u5, param_index)) |i| {
4160 if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
4161 dg.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
4162 }
4163 }
4164 if (!param_ty.isPtrLikeOptional() and !ptr_info.@"allowzero") {
4165 dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4166 }
4167 if (!ptr_info.mutable) {
4168 dg.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4169 }
4170 if (ptr_info.@"align" != 0) {
4171 dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", ptr_info.@"align");
4172 } else {
4173 const elem_align = @maximum(
4174 ptr_info.pointee_type.abiAlignment(target),
4175 1,
4176 );
4177 dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align);
4178 }
4179 } else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) {
4180 .signed => dg.addArgAttr(llvm_fn, llvm_arg_i, "signext"),
4181 .unsigned => dg.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"),
4182 };
4183 }
4184
4185 fn addByRefParamAttrs(
4186 dg: DeclGen,
4187 llvm_fn: *const llvm.Value,
4188 llvm_arg_i: u32,
4189 alignment: u32,
4190 byval_attr: bool,
4191 param_llvm_ty: *const llvm.Type,
4192 ) void {
4193 dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4194 dg.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4195 dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
4196 if (byval_attr) {
4197 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty);
4198 }
4199 }
4144};4200};
41454201
4146pub const FuncGen = struct {4202pub const FuncGen = struct {
test/standalone.zig+1-1
...@@ -44,7 +44,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -44,7 +44,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
44 }44 }
45 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/148145 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481
46 if (builtin.cpu.arch == .x86_64) {46 if (builtin.cpu.arch == .x86_64) {
47 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/1222247 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) {
48 cases.addBuildFile("test/c_abi/build.zig", .{});48 cases.addBuildFile("test/c_abi/build.zig", .{});
49 }49 }
50 }50 }