authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-21 00:51:50-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-23 23:48:18-04:00
logaa44f8f0fd1a4af9df65a9b9bfc5fe6fa0d31b9f
tree0f57991e2e463e963e117e0046f87efcf2aa6be5
parent23a806102a5a3d5b28b2e5ab5ec30e191daea6f4

llvm: convert attributes and non-intrinsic calls


4 files changed, 1880 insertions(+), 332 deletions(-)

src/codegen/llvm.zig+449-268
......@@ -359,7 +359,7 @@ const DataLayoutBuilder = struct {
359359 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
360360 // Other symbols get a `_` prefix.
361361 .coff => switch (self.target.os.tag) {
362 .windows => switch (self.target.cpu.arch) {
362 .uefi, .windows => switch (self.target.cpu.arch) {
363363 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
364364 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
365365 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
......@@ -794,7 +794,7 @@ pub const Object = struct {
794794 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
795795 DW.LANG.C99,
796796 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
797 producer.toSlice(&builder).?,
797 producer.slice(&builder).?,
798798 options.optimize_mode != .Debug,
799799 "", // flags
800800 0, // runtime version
......@@ -830,7 +830,7 @@ pub const Object = struct {
830830
831831 target_machine = llvm.TargetMachine.create(
832832 builder.llvm.target.?,
833 builder.target_triple.toSlice(&builder).?,
833 builder.target_triple.slice(&builder).?,
834834 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
835835 options.llvm_cpu_features,
836836 opt_level,
......@@ -861,7 +861,7 @@ pub const Object = struct {
861861 defer llvm.disposeMessage(rep);
862862 std.testing.expectEqualStrings(
863863 std.mem.span(rep),
864 builder.data_layout.toSlice(&builder).?,
864 builder.data_layout.slice(&builder).?,
865865 ) catch unreachable;
866866 }
867867 }
......@@ -963,7 +963,7 @@ pub const Object = struct {
963963
964964 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
965965 global_index.toConst(),
966 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),
966 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len),
967967 });
968968 }
969969
......@@ -1223,6 +1223,7 @@ pub const Object = struct {
12231223 const func = mod.funcInfo(func_index);
12241224 const decl_index = func.owner_decl;
12251225 const decl = mod.declPtr(decl_index);
1226 const fn_info = mod.typeToFunc(decl.ty).?;
12261227 const target = mod.getTarget();
12271228 const ip = &mod.intern_pool;
12281229
......@@ -1237,28 +1238,43 @@ pub const Object = struct {
12371238 const global = function.ptrConst(&o.builder).global;
12381239 const llvm_func = global.toLlvm(&o.builder);
12391240
1241 var attributes = try function.ptrConst(&o.builder).attributes.toWip(&o.builder);
1242 defer attributes.deinit(&o.builder);
1243
12401244 if (func.analysis(ip).is_noinline) {
1245 try attributes.addFnAttr(.@"noinline", &o.builder);
12411246 o.addFnAttr(llvm_func, "noinline");
12421247 } else {
1248 _ = try attributes.removeFnAttr(.@"noinline");
12431249 Object.removeFnAttr(llvm_func, "noinline");
12441250 }
12451251
12461252 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {
1253 try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);
1254 try attributes.addFnAttr(.@"noinline", &o.builder);
12471255 o.addFnAttrInt(llvm_func, "alignstack", alignment);
12481256 o.addFnAttr(llvm_func, "noinline");
12491257 } else {
1258 _ = try attributes.removeFnAttr(.alignstack);
12501259 Object.removeFnAttr(llvm_func, "alignstack");
12511260 }
12521261
12531262 if (func.analysis(ip).is_cold) {
1263 try attributes.addFnAttr(.cold, &o.builder);
12541264 o.addFnAttr(llvm_func, "cold");
12551265 } else {
1266 _ = try attributes.removeFnAttr(.cold);
12561267 Object.removeFnAttr(llvm_func, "cold");
12571268 }
12581269
12591270 // TODO: disable this if safety is off for the function scope
12601271 const ssp_buf_size = mod.comp.bin_file.options.stack_protector;
12611272 if (ssp_buf_size != 0) {
1273 try attributes.addFnAttr(.sspstrong, &o.builder);
1274 try attributes.addFnAttr(.{ .string = .{
1275 .kind = try o.builder.string("stack-protector-buffer-size"),
1276 .value = try o.builder.fmt("{d}", .{ssp_buf_size}),
1277 } }, &o.builder);
12621278 var buf: [12]u8 = undefined;
12631279 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
12641280 o.addFnAttr(llvm_func, "sspstrong");
......@@ -1267,8 +1283,16 @@ pub const Object = struct {
12671283
12681284 // TODO: disable this if safety is off for the function scope
12691285 if (mod.comp.bin_file.options.stack_check) {
1286 try attributes.addFnAttr(.{ .string = .{
1287 .kind = try o.builder.string("probe-stack"),
1288 .value = try o.builder.string("__zig_probe_stack"),
1289 } }, &o.builder);
12701290 o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");
12711291 } else if (target.os.tag == .uefi) {
1292 try attributes.addFnAttr(.{ .string = .{
1293 .kind = try o.builder.string("no-stack-arg-probe"),
1294 .value = .empty,
1295 } }, &o.builder);
12721296 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
12731297 }
12741298
......@@ -1286,18 +1310,22 @@ pub const Object = struct {
12861310 var llvm_arg_i: u32 = 0;
12871311
12881312 // This gets the LLVM values from the function and stores them in `dg.args`.
1289 const fn_info = mod.typeToFunc(decl.ty).?;
12901313 const sret = firstParamSRet(fn_info, mod);
12911314 const ret_ptr: Builder.Value = if (sret) param: {
12921315 const param = wip.arg(llvm_arg_i);
12931316 llvm_arg_i += 1;
12941317 break :param param;
12951318 } else .none;
1296 const gpa = o.gpa;
12971319
12981320 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
1299 .signed => o.addAttr(llvm_func, 0, "signext"),
1300 .unsigned => o.addAttr(llvm_func, 0, "zeroext"),
1321 .signed => {
1322 try attributes.addRetAttr(.signext, &o.builder);
1323 o.addAttr(llvm_func, 0, "signext");
1324 },
1325 .unsigned => {
1326 try attributes.addRetAttr(.zeroext, &o.builder);
1327 o.addAttr(llvm_func, 0, "zeroext");
1328 },
13011329 };
13021330
13031331 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
......@@ -1312,6 +1340,7 @@ pub const Object = struct {
13121340 // This is the list of args we will use that correspond directly to the AIR arg
13131341 // instructions. Depending on the calling convention, this list is not necessarily
13141342 // a bijection with the actual LLVM parameters of the function.
1343 const gpa = o.gpa;
13151344 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
13161345 defer args.deinit(gpa);
13171346
......@@ -1337,7 +1366,7 @@ pub const Object = struct {
13371366 } else {
13381367 args.appendAssumeCapacity(param);
13391368
1340 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
1369 try o.addByValParamAttrsOld(&attributes, llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
13411370 }
13421371 llvm_arg_i += 1;
13431372 },
......@@ -1347,7 +1376,7 @@ pub const Object = struct {
13471376 const param = wip.arg(llvm_arg_i);
13481377 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
13491378
1350 o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);
1379 try o.addByRefParamAttrsOld(&attributes, llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
13511380 llvm_arg_i += 1;
13521381
13531382 if (isByRef(param_ty, mod)) {
......@@ -1362,7 +1391,8 @@ pub const Object = struct {
13621391 const param = wip.arg(llvm_arg_i);
13631392 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
13641393
1365 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
1394 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
1395 o.addArgAttr(llvm_func, llvm_arg_i, "noundef");
13661396 llvm_arg_i += 1;
13671397
13681398 if (isByRef(param_ty, mod)) {
......@@ -1398,21 +1428,28 @@ pub const Object = struct {
13981428
13991429 if (math.cast(u5, it.zig_index - 1)) |i| {
14001430 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1401 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noalias");
1431 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
1432 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
14021433 }
14031434 }
14041435 if (param_ty.zigTypeTag(mod) != .Optional) {
1405 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "nonnull");
1436 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
1437 o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
14061438 }
14071439 if (ptr_info.flags.is_const) {
1408 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "readonly");
1440 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
1441 o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
14091442 }
1410 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
1411 @max(ptr_info.child.toType().abiAlignment(mod), 1);
1412 o.addArgAttrInt(llvm_func, @intCast(llvm_arg_i), "align", elem_align);
1413 const ptr_param = wip.arg(llvm_arg_i + 0);
1414 const len_param = wip.arg(llvm_arg_i + 1);
1415 llvm_arg_i += 2;
1443 const elem_align = Builder.Alignment.fromByteUnits(
1444 ptr_info.flags.alignment.toByteUnitsOptional() orelse
1445 @max(ptr_info.child.toType().abiAlignment(mod), 1),
1446 );
1447 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1448 o.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
1449 const ptr_param = wip.arg(llvm_arg_i);
1450 llvm_arg_i += 1;
1451 const len_param = wip.arg(llvm_arg_i);
1452 llvm_arg_i += 1;
14161453
14171454 const slice_llvm_ty = try o.lowerType(param_ty);
14181455 args.appendAssumeCapacity(
......@@ -1482,6 +1519,8 @@ pub const Object = struct {
14821519 }
14831520 }
14841521
1522 function.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
1523
14851524 var di_file: ?*llvm.DIFile = null;
14861525 var di_scope: ?*llvm.DIScope = null;
14871526
......@@ -1618,7 +1657,7 @@ pub const Object = struct {
16181657 llvm_global.setDLLStorageClass(.Default);
16191658 }
16201659 if (self.di_map.get(decl)) |di_node| {
1621 const decl_name_slice = decl_name.toSlice(&self.builder).?;
1660 const decl_name_slice = decl_name.slice(&self.builder).?;
16221661 if (try decl.isFunction(mod)) {
16231662 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
16241663 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
......@@ -1655,7 +1694,7 @@ pub const Object = struct {
16551694 llvm_global.setDLLStorageClass(.DLLExport);
16561695 }
16571696 if (self.di_map.get(decl)) |di_node| {
1658 const exp_name_slice = exp_name.toSlice(&self.builder).?;
1697 const exp_name_slice = exp_name.slice(&self.builder).?;
16591698 if (try decl.isFunction(mod)) {
16601699 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
16611700 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
......@@ -2816,7 +2855,7 @@ pub const Object = struct {
28162855 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
28172856
28182857 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2819 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
2858 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.slice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
28202859
28212860 var global = Builder.Global{
28222861 .type = fn_type,
......@@ -2826,6 +2865,9 @@ pub const Object = struct {
28262865 .global = @enumFromInt(o.builder.globals.count()),
28272866 };
28282867
2868 var attributes: Builder.FunctionAttributes.Wip = .{};
2869 defer attributes.deinit(&o.builder);
2870
28292871 const is_extern = decl.isExtern(mod);
28302872 if (!is_extern) {
28312873 global.linkage = .internal;
......@@ -2834,43 +2876,64 @@ pub const Object = struct {
28342876 llvm_fn.setUnnamedAddr(.True);
28352877 } else {
28362878 if (target.isWasm()) {
2879 try attributes.addFnAttr(.{ .string = .{
2880 .kind = try o.builder.string("wasm-import-name"),
2881 .value = try o.builder.string(ip.stringToSlice(decl.name)),
2882 } }, &o.builder);
28372883 o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));
28382884 if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
28392885 if (!std.mem.eql(u8, lib_name, "c")) {
2886 try attributes.addFnAttr(.{ .string = .{
2887 .kind = try o.builder.string("wasm-import-module"),
2888 .value = try o.builder.string(lib_name),
2889 } }, &o.builder);
28402890 o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);
28412891 }
28422892 }
28432893 }
28442894 }
28452895
2896 var llvm_arg_i: u32 = 0;
28462897 if (sret) {
2847 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
2848 o.addArgAttr(llvm_fn, 0, "noalias");
2898 // Sret pointers must not be address 0
2899 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2900 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
2901 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); // Sret pointers must not be address 0
2902 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
2903
2904 const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
2905 try attributes.addParamAttr(llvm_arg_i, .{ .sret = raw_llvm_ret_ty }, &o.builder);
2906 llvm_fn.addSretAttr(raw_llvm_ret_ty.toLlvm(&o.builder));
28492907
2850 const raw_llvm_ret_ty = (try o.lowerType(fn_info.return_type.toType())).toLlvm(&o.builder);
2851 llvm_fn.addSretAttr(raw_llvm_ret_ty);
2908 llvm_arg_i += 1;
28522909 }
28532910
28542911 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
28552912 mod.comp.bin_file.options.error_return_tracing;
28562913
28572914 if (err_return_tracing) {
2858 o.addArgAttr(llvm_fn, @intFromBool(sret), "nonnull");
2915 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2916 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
2917 llvm_arg_i += 1;
28592918 }
28602919
28612920 switch (fn_info.cc) {
28622921 .Unspecified, .Inline => {
2922 function.call_conv = .fastcc;
28632923 llvm_fn.setFunctionCallConv(.Fast);
28642924 },
28652925 .Naked => {
2926 try attributes.addFnAttr(.naked, &o.builder);
28662927 o.addFnAttr(llvm_fn, "naked");
28672928 },
28682929 .Async => {
2930 function.call_conv = .fastcc;
28692931 llvm_fn.setFunctionCallConv(.Fast);
28702932 @panic("TODO: LLVM backend lower async function");
28712933 },
28722934 else => {
2873 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
2935 function.call_conv = toLlvmCallConv(fn_info.cc, target);
2936 llvm_fn.setFunctionCallConv(@enumFromInt(@intFromEnum(function.call_conv)));
28742937 },
28752938 }
28762939
......@@ -2880,9 +2943,10 @@ pub const Object = struct {
28802943 }
28812944
28822945 // Function attributes that are independent of analysis results of the function body.
2883 o.addCommonFnAttributes(llvm_fn);
2946 try o.addCommonFnAttributes(&attributes, llvm_fn);
28842947
28852948 if (fn_info.return_type == .noreturn_type) {
2949 try attributes.addFnAttr(.noreturn, &o.builder);
28862950 o.addFnAttr(llvm_fn, "noreturn");
28872951 }
28882952
......@@ -2890,23 +2954,24 @@ pub const Object = struct {
28902954 // because functions with bodies are handled in `updateFunc`.
28912955 if (is_extern) {
28922956 var it = iterateParamTypes(o, fn_info);
2893 it.llvm_index += @intFromBool(sret);
2894 it.llvm_index += @intFromBool(err_return_tracing);
2957 it.llvm_index = llvm_arg_i;
28952958 while (try it.next()) |lowering| switch (lowering) {
28962959 .byval => {
28972960 const param_index = it.zig_index - 1;
28982961 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
28992962 if (!isByRef(param_ty, mod)) {
2900 o.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
2963 try o.addByValParamAttrsOld(&attributes, llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
29012964 }
29022965 },
29032966 .byref => {
29042967 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
29052968 const param_llvm_ty = try o.lowerType(param_ty.toType());
2906 const alignment = param_ty.toType().abiAlignment(mod);
2907 o.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
2969 const alignment =
2970 Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod));
2971 try o.addByRefParamAttrsOld(&attributes, llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
29082972 },
29092973 .byref_mut => {
2974 try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder);
29102975 o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
29112976 },
29122977 // No attributes needed for these.
......@@ -2924,25 +2989,42 @@ pub const Object = struct {
29242989 };
29252990 }
29262991
2992 function.attributes = try attributes.finish(&o.builder);
2993
29272994 try o.builder.llvm.globals.append(o.gpa, llvm_fn);
29282995 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);
29292996 try o.builder.functions.append(o.gpa, function);
29302997 return global.kind.function;
29312998 }
29322999
2933 fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {
3000 fn addCommonFnAttributes(
3001 o: *Object,
3002 attributes: *Builder.FunctionAttributes.Wip,
3003 llvm_fn: *llvm.Value,
3004 ) Allocator.Error!void {
29343005 const comp = o.module.comp;
29353006
29363007 if (!comp.bin_file.options.red_zone) {
3008 try attributes.addFnAttr(.noredzone, &o.builder);
29373009 o.addFnAttr(llvm_fn, "noredzone");
29383010 }
29393011 if (comp.bin_file.options.omit_frame_pointer) {
3012 try attributes.addFnAttr(.{ .string = .{
3013 .kind = try o.builder.string("frame-pointer"),
3014 .value = try o.builder.string("none"),
3015 } }, &o.builder);
29403016 o.addFnAttrString(llvm_fn, "frame-pointer", "none");
29413017 } else {
3018 try attributes.addFnAttr(.{ .string = .{
3019 .kind = try o.builder.string("frame-pointer"),
3020 .value = try o.builder.string("all"),
3021 } }, &o.builder);
29423022 o.addFnAttrString(llvm_fn, "frame-pointer", "all");
29433023 }
3024 try attributes.addFnAttr(.nounwind, &o.builder);
29443025 o.addFnAttr(llvm_fn, "nounwind");
29453026 if (comp.unwind_tables) {
3027 try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
29463028 o.addFnAttrInt(llvm_fn, "uwtable", 2);
29473029 }
29483030 if (comp.bin_file.options.skip_linker_dependencies or
......@@ -2953,22 +3035,38 @@ pub const Object = struct {
29533035 // and llvm detects that the body is equivalent to memcpy, it may replace the
29543036 // body of memcpy with a call to memcpy, which would then cause a stack
29553037 // overflow instead of performing memcpy.
3038 try attributes.addFnAttr(.nobuiltin, &o.builder);
29563039 o.addFnAttr(llvm_fn, "nobuiltin");
29573040 }
29583041 if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
3042 try attributes.addFnAttr(.minsize, &o.builder);
3043 try attributes.addFnAttr(.optsize, &o.builder);
29593044 o.addFnAttr(llvm_fn, "minsize");
29603045 o.addFnAttr(llvm_fn, "optsize");
29613046 }
29623047 if (comp.bin_file.options.tsan) {
3048 try attributes.addFnAttr(.sanitize_thread, &o.builder);
29633049 o.addFnAttr(llvm_fn, "sanitize_thread");
29643050 }
29653051 if (comp.getTarget().cpu.model.llvm_name) |s| {
3052 try attributes.addFnAttr(.{ .string = .{
3053 .kind = try o.builder.string("target-cpu"),
3054 .value = try o.builder.string(s),
3055 } }, &o.builder);
29663056 llvm_fn.addFunctionAttr("target-cpu", s);
29673057 }
29683058 if (comp.bin_file.options.llvm_cpu_features) |s| {
3059 try attributes.addFnAttr(.{ .string = .{
3060 .kind = try o.builder.string("target-features"),
3061 .value = try o.builder.string(std.mem.span(s)),
3062 } }, &o.builder);
29693063 llvm_fn.addFunctionAttr("target-features", s);
29703064 }
29713065 if (comp.getTarget().cpu.arch.isBpf()) {
3066 try attributes.addFnAttr(.{ .string = .{
3067 .kind = try o.builder.string("no-builtins"),
3068 .value = .empty,
3069 } }, &o.builder);
29723070 llvm_fn.addFunctionAttr("no-builtins", "");
29733071 }
29743072 }
......@@ -3002,7 +3100,7 @@ pub const Object = struct {
30023100 fqn;
30033101 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
30043102 global.type.toLlvm(&o.builder),
3005 fqn.toSlice(&o.builder).?,
3103 fqn.slice(&o.builder).?,
30063104 @intFromEnum(global.addr_space),
30073105 );
30083106
......@@ -4403,47 +4501,114 @@ pub const Object = struct {
44034501
44044502 fn addByValParamAttrs(
44054503 o: *Object,
4504 attributes: *Builder.FunctionAttributes.Wip,
4505 param_ty: Type,
4506 param_index: u32,
4507 fn_info: InternPool.Key.FuncType,
4508 llvm_arg_i: u32,
4509 ) Allocator.Error!void {
4510 const mod = o.module;
4511 if (param_ty.isPtrAtRuntime(mod)) {
4512 const ptr_info = param_ty.ptrInfo(mod);
4513 if (math.cast(u5, param_index)) |i| {
4514 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4515 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
4516 }
4517 }
4518 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4519 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4520 }
4521 if (ptr_info.flags.is_const) {
4522 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4523 }
4524 const elem_align = Builder.Alignment.fromByteUnits(
4525 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4526 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4527 );
4528 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4529 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4530 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
4531 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
4532 };
4533 }
4534
4535 fn addByRefParamAttrs(
4536 o: *Object,
4537 attributes: *Builder.FunctionAttributes.Wip,
4538 llvm_arg_i: u32,
4539 alignment: Builder.Alignment,
4540 byval_attr: bool,
4541 param_llvm_ty: Builder.Type,
4542 ) Allocator.Error!void {
4543 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4544 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4545 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
4546 if (byval_attr) {
4547 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
4548 }
4549 }
4550
4551 fn addByValParamAttrsOld(
4552 o: *Object,
4553 attributes: *Builder.FunctionAttributes.Wip,
44064554 llvm_fn: *llvm.Value,
44074555 param_ty: Type,
44084556 param_index: u32,
44094557 fn_info: InternPool.Key.FuncType,
44104558 llvm_arg_i: u32,
4411 ) void {
4559 ) Allocator.Error!void {
44124560 const mod = o.module;
44134561 if (param_ty.isPtrAtRuntime(mod)) {
44144562 const ptr_info = param_ty.ptrInfo(mod);
44154563 if (math.cast(u5, param_index)) |i| {
44164564 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4565 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
44174566 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
44184567 }
44194568 }
44204569 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4570 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
44214571 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
44224572 }
44234573 if (ptr_info.flags.is_const) {
4574 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
44244575 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
44254576 }
4426 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
4427 @max(ptr_info.child.toType().abiAlignment(mod), 1);
4428 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align);
4577 const elem_align = Builder.Alignment.fromByteUnits(
4578 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4579 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4580 );
4581 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4582 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
44294583 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4430 .signed => o.addArgAttr(llvm_fn, llvm_arg_i, "signext"),
4431 .unsigned => o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"),
4584 .signed => {
4585 try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder);
4586 o.addArgAttr(llvm_fn, llvm_arg_i, "signext");
4587 },
4588 .unsigned => {
4589 try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder);
4590 o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext");
4591 },
44324592 };
44334593 }
44344594
4435 fn addByRefParamAttrs(
4595 fn addByRefParamAttrsOld(
44364596 o: *Object,
4597 attributes: *Builder.FunctionAttributes.Wip,
44374598 llvm_fn: *llvm.Value,
44384599 llvm_arg_i: u32,
4439 alignment: u32,
4600 alignment: Builder.Alignment,
44404601 byval_attr: bool,
44414602 param_llvm_ty: Builder.Type,
4442 ) void {
4603 ) Allocator.Error!void {
4604 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4605 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4606 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
44434607 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
44444608 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4445 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
4609 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment.toByteUnits() orelse 0);
44464610 if (byval_attr) {
4611 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
44474612 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
44484613 }
44494614 }
......@@ -4841,10 +5006,10 @@ pub const FuncGen = struct {
48415006 .slice_ptr => try self.airSliceField(inst, 0),
48425007 .slice_len => try self.airSliceField(inst, 1),
48435008
4844 .call => try self.airCall(inst, .Auto),
4845 .call_always_tail => try self.airCall(inst, .AlwaysTail),
4846 .call_never_tail => try self.airCall(inst, .NeverTail),
4847 .call_never_inline => try self.airCall(inst, .NeverInline),
5009 .call => try self.airCall(inst, .auto),
5010 .call_always_tail => try self.airCall(inst, .always_tail),
5011 .call_never_tail => try self.airCall(inst, .never_tail),
5012 .call_never_inline => try self.airCall(inst, .never_inline),
48485013
48495014 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
48505015 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
......@@ -4953,7 +5118,15 @@ pub const FuncGen = struct {
49535118 }
49545119 }
49555120
4956 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !Builder.Value {
5121 pub const CallAttr = enum {
5122 Auto,
5123 NeverTail,
5124 NeverInline,
5125 AlwaysTail,
5126 AlwaysInline,
5127 };
5128
5129 fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !Builder.Value {
49575130 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
49585131 const extra = self.air.extraData(Air.Call, pl_op.payload);
49595132 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
......@@ -4972,14 +5145,25 @@ pub const FuncGen = struct {
49725145 const target = mod.getTarget();
49735146 const sret = firstParamSRet(fn_info, mod);
49745147
4975 var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa);
5148 var llvm_args = std.ArrayList(Builder.Value).init(self.gpa);
49765149 defer llvm_args.deinit();
49775150
5151 var attributes: Builder.FunctionAttributes.Wip = .{};
5152 defer attributes.deinit(&o.builder);
5153
5154 switch (modifier) {
5155 .auto, .never_tail, .always_tail => {},
5156 .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder),
5157 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5158 }
5159
49785160 const ret_ptr = if (!sret) null else blk: {
49795161 const llvm_ret_ty = try o.lowerType(return_type);
5162 try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
5163
49805164 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
49815165 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4982 try llvm_args.append(ret_ptr.toLlvm(&self.wip));
5166 try llvm_args.append(ret_ptr);
49835167 break :blk ret_ptr;
49845168 };
49855169
......@@ -4987,7 +5171,7 @@ pub const FuncGen = struct {
49875171 o.module.comp.bin_file.options.error_return_tracing;
49885172 if (err_return_tracing) {
49895173 assert(self.err_ret_trace != .none);
4990 try llvm_args.append(self.err_ret_trace.toLlvm(&self.wip));
5174 try llvm_args.append(self.err_ret_trace);
49915175 }
49925176
49935177 var it = iterateParamTypes(o, fn_info);
......@@ -5001,9 +5185,9 @@ pub const FuncGen = struct {
50015185 if (isByRef(param_ty, mod)) {
50025186 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
50035187 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
5004 try llvm_args.append(loaded.toLlvm(&self.wip));
5188 try llvm_args.append(loaded);
50055189 } else {
5006 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
5190 try llvm_args.append(llvm_arg);
50075191 }
50085192 },
50095193 .byref => {
......@@ -5011,13 +5195,13 @@ pub const FuncGen = struct {
50115195 const param_ty = self.typeOf(arg);
50125196 const llvm_arg = try self.resolveInst(arg);
50135197 if (isByRef(param_ty, mod)) {
5014 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
5198 try llvm_args.append(llvm_arg);
50155199 } else {
50165200 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
50175201 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
50185202 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
50195203 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
5020 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
5204 try llvm_args.append(arg_ptr);
50215205 }
50225206 },
50235207 .byref_mut => {
......@@ -5034,7 +5218,7 @@ pub const FuncGen = struct {
50345218 } else {
50355219 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
50365220 }
5037 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
5221 try llvm_args.append(arg_ptr);
50385222 },
50395223 .abi_sized_int => {
50405224 const arg = args[it.zig_index - 1];
......@@ -5045,7 +5229,7 @@ pub const FuncGen = struct {
50455229 if (isByRef(param_ty, mod)) {
50465230 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
50475231 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
5048 try llvm_args.append(loaded.toLlvm(&self.wip));
5232 try llvm_args.append(loaded);
50495233 } else {
50505234 // LLVM does not allow bitcasting structs so we must allocate
50515235 // a local, store as one type, and then load as another type.
......@@ -5056,7 +5240,7 @@ pub const FuncGen = struct {
50565240 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
50575241 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
50585242 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
5059 try llvm_args.append(loaded.toLlvm(&self.wip));
5243 try llvm_args.append(loaded);
50605244 }
50615245 },
50625246 .slice => {
......@@ -5064,7 +5248,7 @@ pub const FuncGen = struct {
50645248 const llvm_arg = try self.resolveInst(arg);
50655249 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
50665250 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
5067 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
5251 try llvm_args.appendSlice(&.{ ptr, len });
50685252 },
50695253 .multiple_llvm_types => {
50705254 const arg = args[it.zig_index - 1];
......@@ -5086,14 +5270,14 @@ pub const FuncGen = struct {
50865270 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
50875271 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
50885272 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
5089 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
5273 llvm_args.appendAssumeCapacity(loaded);
50905274 }
50915275 },
50925276 .as_u16 => {
50935277 const arg = args[it.zig_index - 1];
50945278 const llvm_arg = try self.resolveInst(arg);
50955279 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
5096 try llvm_args.append(casted.toLlvm(&self.wip));
5280 try llvm_args.append(casted);
50975281 },
50985282 .float_array => |count| {
50995283 const arg = args[it.zig_index - 1];
......@@ -5110,7 +5294,7 @@ pub const FuncGen = struct {
51105294 const array_ty = try o.builder.arrayType(count, float_ty);
51115295
51125296 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5113 try llvm_args.append(loaded.toLlvm(&self.wip));
5297 try llvm_args.append(loaded);
51145298 },
51155299 .i32_array, .i64_array => |arr_len| {
51165300 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
......@@ -5127,24 +5311,10 @@ pub const FuncGen = struct {
51275311 const array_ty =
51285312 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
51295313 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5130 try llvm_args.append(loaded.toLlvm(&self.wip));
5314 try llvm_args.append(loaded);
51315315 },
51325316 };
51335317
5134 const llvm_fn_ty = try o.lowerType(zig_fn_ty);
5135 const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
5136 self.builder.buildCall(
5137 llvm_fn_ty.toLlvm(&o.builder),
5138 llvm_fn.toLlvm(&self.wip),
5139 llvm_args.items.ptr,
5140 @intCast(llvm_args.items.len),
5141 toLlvmCallConv(fn_info.cc, target),
5142 attr,
5143 "",
5144 ),
5145 &self.wip,
5146 );
5147
51485318 if (callee_ty.zigTypeTag(mod) == .Pointer) {
51495319 // Add argument attributes for function pointer calls.
51505320 it = iterateParamTypes(o, fn_info);
......@@ -5155,19 +5325,17 @@ pub const FuncGen = struct {
51555325 const param_index = it.zig_index - 1;
51565326 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
51575327 if (!isByRef(param_ty, mod)) {
5158 o.addByValParamAttrs(call.toLlvm(&self.wip), param_ty, param_index, fn_info, it.llvm_index - 1);
5328 try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
51595329 }
51605330 },
51615331 .byref => {
51625332 const param_index = it.zig_index - 1;
51635333 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
51645334 const param_llvm_ty = try o.lowerType(param_ty);
5165 const alignment = param_ty.abiAlignment(mod);
5166 o.addByRefParamAttrs(call.toLlvm(&self.wip), it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
5167 },
5168 .byref_mut => {
5169 o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
5335 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5336 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
51705337 },
5338 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
51715339 // No attributes needed for these.
51725340 .no_bits,
51735341 .abi_sized_int,
......@@ -5186,23 +5354,40 @@ pub const FuncGen = struct {
51865354
51875355 if (math.cast(u5, it.zig_index - 1)) |i| {
51885356 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
5189 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "noalias");
5357 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
51905358 }
51915359 }
51925360 if (param_ty.zigTypeTag(mod) != .Optional) {
5193 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "nonnull");
5361 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
51945362 }
51955363 if (ptr_info.flags.is_const) {
5196 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "readonly");
5364 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
51975365 }
5198 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
5199 @max(ptr_info.child.toType().abiAlignment(mod), 1);
5200 o.addArgAttrInt(call.toLlvm(&self.wip), llvm_arg_i, "align", elem_align);
5366 const elem_align = Builder.Alignment.fromByteUnits(
5367 ptr_info.flags.alignment.toByteUnitsOptional() orelse
5368 @max(ptr_info.child.toType().abiAlignment(mod), 1),
5369 );
5370 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
52015371 },
52025372 };
52035373 }
52045374
5205 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
5375 const call = try self.wip.call(
5376 switch (modifier) {
5377 .auto, .never_inline => .normal,
5378 .never_tail => .notail,
5379 .always_tail => .musttail,
5380 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5381 },
5382 toLlvmCallConv(fn_info.cc, target),
5383 try attributes.finish(&o.builder),
5384 try o.lowerType(zig_fn_ty),
5385 llvm_fn,
5386 llvm_args.items,
5387 "",
5388 );
5389
5390 if (fn_info.return_type == .noreturn_type and modifier != .always_tail) {
52065391 return .none;
52075392 }
52085393
......@@ -5211,9 +5396,7 @@ pub const FuncGen = struct {
52115396 }
52125397
52135398 const llvm_ret_ty = try o.lowerType(return_type);
5214
52155399 if (ret_ptr) |rp| {
5216 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
52175400 if (isByRef(return_type, mod)) {
52185401 return rp;
52195402 } else {
......@@ -5269,25 +5452,24 @@ pub const FuncGen = struct {
52695452 // ptr null, ; stack trace
52705453 // ptr @2, ; addr (null ?usize)
52715454 // )
5272 const args = [4]*llvm.Value{
5273 msg_ptr.toLlvm(&o.builder),
5274 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
5275 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
5276 null_opt_addr_global.toLlvm(&o.builder),
5277 };
52785455 const panic_func = mod.funcInfo(mod.panic_func_index);
52795456 const panic_decl = mod.declPtr(panic_func.owner_decl);
52805457 const fn_info = mod.typeToFunc(panic_decl.ty).?;
52815458 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
5282 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(
5283 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),
5284 panic_global.toLlvm(&o.builder),
5285 &args,
5286 args.len,
5459 _ = try fg.wip.call(
5460 .normal,
52875461 toLlvmCallConv(fn_info.cc, target),
5288 .Auto,
5462 .none,
5463 panic_global.typeOf(&o.builder),
5464 panic_global.toValue(&o.builder),
5465 &.{
5466 msg_ptr.toValue(),
5467 try o.builder.intValue(llvm_usize, msg_len),
5468 try o.builder.nullValue(.ptr),
5469 null_opt_addr_global.toValue(),
5470 },
52895471 "",
5290 ), &fg.wip);
5472 );
52915473 _ = try fg.wip.@"unreachable"();
52925474 }
52935475
......@@ -5395,7 +5577,7 @@ pub const FuncGen = struct {
53955577 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
53965578
53975579 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
5398 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5580 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
53995581 llvm_fn_ty.toLlvm(&o.builder),
54005582 llvm_fn,
54015583 &args,
......@@ -5422,7 +5604,7 @@ pub const FuncGen = struct {
54225604 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54235605
54245606 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5425 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5607 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
54265608 llvm_fn_ty.toLlvm(&o.builder),
54275609 llvm_fn,
54285610 &args,
......@@ -5449,7 +5631,7 @@ pub const FuncGen = struct {
54495631 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54505632
54515633 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5452 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5634 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
54535635 llvm_fn_ty.toLlvm(&o.builder),
54545636 llvm_fn,
54555637 &args,
......@@ -5495,16 +5677,15 @@ pub const FuncGen = struct {
54955677 const un_op = self.air.instructions.items(.data)[inst].un_op;
54965678 const operand = try self.resolveInst(un_op);
54975679 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5498 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};
5499 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
5500 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
5501 llvm_fn.toLlvm(&o.builder),
5502 &args,
5503 args.len,
5504 .Fast,
5505 .Auto,
5680 return self.wip.call(
5681 .normal,
5682 .fastcc,
5683 .none,
5684 llvm_fn.typeOf(&o.builder),
5685 llvm_fn.toValue(&o.builder),
5686 &.{operand},
55065687 "",
5507 ), &self.wip);
5688 );
55085689 }
55095690
55105691 fn cmp(
......@@ -5953,16 +6134,15 @@ pub const FuncGen = struct {
59536134 }
59546135
59556136 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5956 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};
5957 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
5958 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
5959 libc_fn.toLlvm(&o.builder),
5960 &params,
5961 params.len,
5962 .C,
5963 .Auto,
6137 return self.wip.call(
6138 .normal,
6139 .ccc,
6140 .none,
6141 libc_fn.typeOf(&o.builder),
6142 libc_fn.toValue(&o.builder),
6143 &.{extended},
59646144 "",
5965 ), &self.wip);
6145 );
59666146 }
59676147
59686148 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
......@@ -6013,16 +6193,15 @@ pub const FuncGen = struct {
60136193
60146194 const operand_llvm_ty = try o.lowerType(operand_ty);
60156195 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
6016 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
6017 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(
6018 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
6019 libc_fn.toLlvm(&o.builder),
6020 &params,
6021 params.len,
6022 .C,
6023 .Auto,
6196 var result = try self.wip.call(
6197 .normal,
6198 .ccc,
6199 .none,
6200 libc_fn.typeOf(&o.builder),
6201 libc_fn.toValue(&o.builder),
6202 &.{operand},
60246203 "",
6025 ), &self.wip);
6204 );
60266205
60276206 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
60286207 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
......@@ -6843,6 +7022,9 @@ pub const FuncGen = struct {
68437022 }
68447023 }
68457024
7025 var attributes: Builder.FunctionAttributes.Wip = .{};
7026 defer attributes.deinit(&o.builder);
7027
68467028 const ret_llvm_ty = switch (return_count) {
68477029 0 => .void,
68487030 1 => llvm_ret_types[0],
......@@ -6861,7 +7043,7 @@ pub const FuncGen = struct {
68617043 .ATT,
68627044 .False,
68637045 );
6864 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
7046 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCallOld(
68657047 llvm_fn_ty.toLlvm(&o.builder),
68667048 asm_fn,
68677049 llvm_param_values.ptr,
......@@ -6872,6 +7054,7 @@ pub const FuncGen = struct {
68727054 ), &self.wip);
68737055 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
68747056 if (llvm_elem_ty != .none) {
7057 try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
68757058 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
68767059 }
68777060 }
......@@ -7287,7 +7470,7 @@ pub const FuncGen = struct {
72877470 const args: [1]*llvm.Value = .{
72887471 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
72897472 };
7290 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7473 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
72917474 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
72927475 llvm_fn,
72937476 &args,
......@@ -7308,7 +7491,7 @@ pub const FuncGen = struct {
73087491 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
73097492 operand.toLlvm(&self.wip),
73107493 };
7311 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7494 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
73127495 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
73137496 llvm_fn,
73147497 &args,
......@@ -7425,7 +7608,7 @@ pub const FuncGen = struct {
74257608 });
74267609 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);
74277610 const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});
7428 const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCall(
7611 const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCallOld(
74297612 llvm_fn_ty.toLlvm(&o.builder),
74307613 llvm_fn,
74317614 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
......@@ -7768,7 +7951,7 @@ pub const FuncGen = struct {
77687951 );
77697952 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);
77707953 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
7771 self.builder.buildCall(
7954 self.builder.buildCallOld(
77727955 llvm_fn_ty.toLlvm(&o.builder),
77737956 llvm_fn,
77747957 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
......@@ -7818,29 +8001,23 @@ pub const FuncGen = struct {
78188001 const o = self.dg.object;
78198002 assert(args_vectors.len <= 3);
78208003
7821 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
7822 const llvm_scalar_ty = llvm_fn_ty.functionReturn(&o.builder);
7823
78248004 var i: usize = 0;
78258005 var result = result_vector;
78268006 while (i < vector_len) : (i += 1) {
78278007 const index_i32 = try o.builder.intValue(.i32, i);
78288008
7829 var args: [3]*llvm.Value = undefined;
8009 var args: [3]Builder.Value = undefined;
78308010 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
7831 arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);
8011 arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, "");
78328012 }
7833 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
7834 self.builder.buildCall(
7835 llvm_fn_ty.toLlvm(&o.builder),
7836 llvm_fn.toLlvm(&o.builder),
7837 &args,
7838 @intCast(args_vectors.len),
7839 .C,
7840 .Auto,
7841 "",
7842 ),
7843 &self.wip,
8013 const result_elem = try self.wip.call(
8014 .normal,
8015 .ccc,
8016 .none,
8017 llvm_fn.typeOf(&o.builder),
8018 llvm_fn.toValue(&o.builder),
8019 args[0..args_vectors.len],
8020 "",
78448021 );
78458022 result = try self.wip.insertElement(result, result_elem, index_i32, "");
78468023 }
......@@ -7861,7 +8038,7 @@ pub const FuncGen = struct {
78618038 };
78628039
78638040 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7864 const f = o.llvm_module.addFunction(fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
8041 const f = o.llvm_module.addFunction(fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
78658042
78668043 var global = Builder.Global{
78678044 .type = fn_type,
......@@ -7942,20 +8119,15 @@ pub const FuncGen = struct {
79428119 return self.wip.icmp(int_cond, result, zero_vector, "");
79438120 }
79448121
7945 const llvm_fn_ty = libc_fn.typeOf(&o.builder);
7946 const llvm_params = [2]*llvm.Value{ params[0].toLlvm(&self.wip), params[1].toLlvm(&self.wip) };
7947 const result = (try self.wip.unimplemented(
7948 llvm_fn_ty.functionReturn(&o.builder),
7949 "",
7950 )).finish(self.builder.buildCall(
7951 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
7952 libc_fn.toLlvm(&o.builder),
7953 &llvm_params,
7954 llvm_params.len,
7955 .C,
7956 .Auto,
8122 const result = try self.wip.call(
8123 .normal,
8124 .ccc,
8125 .none,
8126 libc_fn.typeOf(&o.builder),
8127 libc_fn.toValue(&o.builder),
8128 &params,
79578129 "",
7958 ), &self.wip);
8130 );
79598131 return self.wip.icmp(int_cond, result, zero.toValue(), "");
79608132 }
79618133
......@@ -8085,7 +8257,7 @@ pub const FuncGen = struct {
80858257 );
80868258 var llvm_params: [params_len]*llvm.Value = undefined;
80878259 for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);
8088 return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCall(
8260 return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCallOld(
80898261 llvm_fn_ty.toLlvm(&o.builder),
80908262 llvm_fn,
80918263 &llvm_params,
......@@ -8311,17 +8483,16 @@ pub const FuncGen = struct {
83118483 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
83128484 });
83138485
8314 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8315 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8316 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
8317 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
8318 llvm_fn.toLlvm(&o.builder),
8319 &params,
8320 params.len,
8321 .C,
8322 .Auto,
8486 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8487 return self.wip.call(
8488 .normal,
8489 .ccc,
8490 .none,
8491 libc_fn.typeOf(&o.builder),
8492 libc_fn.toValue(&o.builder),
8493 &.{operand},
83238494 "",
8324 ), &self.wip);
8495 );
83258496 }
83268497 }
83278498
......@@ -8346,17 +8517,16 @@ pub const FuncGen = struct {
83468517 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
83478518 });
83488519
8349 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8350 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8351 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
8352 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
8353 llvm_fn.toLlvm(&o.builder),
8354 &params,
8355 params.len,
8356 .C,
8357 .Auto,
8520 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8521 return self.wip.call(
8522 .normal,
8523 .ccc,
8524 .none,
8525 libc_fn.typeOf(&o.builder),
8526 libc_fn.toValue(&o.builder),
8527 &.{operand},
83588528 "",
8359 ), &self.wip);
8529 );
83608530 }
83618531 }
83628532
......@@ -8657,7 +8827,7 @@ pub const FuncGen = struct {
86578827 _ = inst;
86588828 const o = self.dg.object;
86598829 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8660 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8830 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
86618831 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
86628832 llvm_fn,
86638833 undefined,
......@@ -8674,7 +8844,7 @@ pub const FuncGen = struct {
86748844 _ = inst;
86758845 const o = self.dg.object;
86768846 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8677 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8847 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
86788848 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
86798849 llvm_fn,
86808850 undefined,
......@@ -8701,7 +8871,7 @@ pub const FuncGen = struct {
87018871 const params = [_]*llvm.Value{
87028872 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
87038873 };
8704 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(
8874 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCallOld(
87058875 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
87068876 llvm_fn,
87078877 &params,
......@@ -8727,7 +8897,7 @@ pub const FuncGen = struct {
87278897 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
87288898 };
87298899 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8730 self.builder.buildCall(
8900 self.builder.buildCallOld(
87318901 llvm_fn_ty.toLlvm(&o.builder),
87328902 llvm_fn,
87338903 &params,
......@@ -9256,7 +9426,7 @@ pub const FuncGen = struct {
92569426 Builder.Constant.false.toLlvm(&o.builder),
92579427 };
92589428 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9259 self.builder.buildCall(
9429 self.builder.buildCallOld(
92609430 llvm_fn_ty.toLlvm(&o.builder),
92619431 fn_val,
92629432 &params,
......@@ -9283,7 +9453,7 @@ pub const FuncGen = struct {
92839453
92849454 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
92859455 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9286 self.builder.buildCall(
9456 self.builder.buildCallOld(
92879457 llvm_fn_ty.toLlvm(&o.builder),
92889458 fn_val,
92899459 &params,
......@@ -9331,7 +9501,7 @@ pub const FuncGen = struct {
93319501
93329502 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
93339503 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9334 self.builder.buildCall(
9504 self.builder.buildCallOld(
93359505 llvm_fn_ty.toLlvm(&o.builder),
93369506 fn_val,
93379507 &params,
......@@ -9389,16 +9559,15 @@ pub const FuncGen = struct {
93899559 const enum_ty = self.typeOf(un_op);
93909560
93919561 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
9392 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9393 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
9394 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
9395 llvm_fn.toLlvm(&o.builder),
9396 &params,
9397 params.len,
9398 .Fast,
9399 .Auto,
9562 return self.wip.call(
9563 .normal,
9564 .fastcc,
9565 .none,
9566 llvm_fn.typeOf(&o.builder),
9567 llvm_fn.toValue(&o.builder),
9568 &.{operand},
94009569 "",
9401 ), &self.wip);
9570 );
94029571 }
94039572
94049573 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
......@@ -9416,13 +9585,16 @@ pub const FuncGen = struct {
94169585 fqn.fmt(&mod.intern_pool),
94179586 });
94189587
9588 var attributes: Builder.FunctionAttributes.Wip = .{};
9589 defer attributes.deinit(&o.builder);
9590
94199591 const fn_type = try o.builder.fnType(.i1, &.{
94209592 try o.lowerType(enum_type.tag_ty.toType()),
94219593 }, .normal);
9422 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9594 const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
94239595 fn_val.setLinkage(.Internal);
94249596 fn_val.setFunctionCallConv(.Fast);
9425 o.addCommonFnAttributes(fn_val);
9597 try o.addCommonFnAttributes(&attributes, fn_val);
94269598
94279599 var global = Builder.Global{
94289600 .linkage = .internal,
......@@ -9431,6 +9603,8 @@ pub const FuncGen = struct {
94319603 };
94329604 var function = Builder.Function{
94339605 .global = @enumFromInt(o.builder.globals.count()),
9606 .call_conv = .fastcc,
9607 .attributes = try attributes.finish(&o.builder),
94349608 };
94359609 try o.builder.llvm.globals.append(self.gpa, fn_val);
94369610 _ = try o.builder.addGlobal(llvm_fn_name, global);
......@@ -9470,19 +9644,14 @@ pub const FuncGen = struct {
94709644 const enum_ty = self.typeOf(un_op);
94719645
94729646 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9473 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
9474 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9475 return (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
9476 self.builder.buildCall(
9477 llvm_fn_ty.toLlvm(&o.builder),
9478 llvm_fn.toLlvm(&o.builder),
9479 &params,
9480 params.len,
9481 .Fast,
9482 .Auto,
9483 "",
9484 ),
9485 &self.wip,
9647 return self.wip.call(
9648 .normal,
9649 .fastcc,
9650 .none,
9651 llvm_fn.typeOf(&o.builder),
9652 llvm_fn.toValue(&o.builder),
9653 &.{operand},
9654 "",
94869655 );
94879656 }
94889657
......@@ -9499,16 +9668,19 @@ pub const FuncGen = struct {
94999668 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
95009669 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
95019670
9671 var attributes: Builder.FunctionAttributes.Wip = .{};
9672 defer attributes.deinit(&o.builder);
9673
95029674 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
95039675 const usize_ty = try o.lowerType(Type.usize);
95049676
95059677 const fn_type = try o.builder.fnType(ret_ty, &.{
95069678 try o.lowerType(enum_type.tag_ty.toType()),
95079679 }, .normal);
9508 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9680 const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
95099681 fn_val.setLinkage(.Internal);
95109682 fn_val.setFunctionCallConv(.Fast);
9511 o.addCommonFnAttributes(fn_val);
9683 try o.addCommonFnAttributes(&attributes, fn_val);
95129684
95139685 var global = Builder.Global{
95149686 .linkage = .internal,
......@@ -9517,6 +9689,8 @@ pub const FuncGen = struct {
95179689 };
95189690 var function = Builder.Function{
95199691 .global = @enumFromInt(o.builder.globals.count()),
9692 .call_conv = .fastcc,
9693 .attributes = try attributes.finish(&o.builder),
95209694 };
95219695 try o.builder.llvm.globals.append(self.gpa, fn_val);
95229696 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
......@@ -9561,7 +9735,7 @@ pub const FuncGen = struct {
95619735
95629736 const slice_val = try o.builder.structValue(ret_ty, &.{
95639737 global_index.toConst(),
9564 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
9738 try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
95659739 });
95669740
95679741 const return_block = try wip.block(1, "Name");
......@@ -9590,11 +9764,14 @@ pub const FuncGen = struct {
95909764 // Function signature: fn (anyerror) bool
95919765
95929766 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);
9593 const llvm_fn = o.llvm_module.addFunction(name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9767 const llvm_fn = o.llvm_module.addFunction(name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
9768
9769 var attributes: Builder.FunctionAttributes.Wip = .{};
9770 defer attributes.deinit(&o.builder);
95949771
95959772 llvm_fn.setLinkage(.Internal);
95969773 llvm_fn.setFunctionCallConv(.Fast);
9597 o.addCommonFnAttributes(llvm_fn);
9774 try o.addCommonFnAttributes(&attributes, llvm_fn);
95989775
95999776 var global = Builder.Global{
96009777 .linkage = .internal,
......@@ -9603,6 +9780,8 @@ pub const FuncGen = struct {
96039780 };
96049781 var function = Builder.Function{
96059782 .global = @enumFromInt(o.builder.globals.count()),
9783 .call_conv = .fastcc,
9784 .attributes = try attributes.finish(&o.builder),
96069785 };
96079786
96089787 try o.builder.llvm.globals.append(self.gpa, llvm_fn);
......@@ -9731,18 +9910,14 @@ pub const FuncGen = struct {
97319910 // accum = f(accum, vec[i]);
97329911 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
97339912 const element = try self.wip.extractElement(operand_vector, i, "");
9734 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };
9735 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
9736 self.builder.buildCall(
9737 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
9738 llvm_fn.toLlvm(&o.builder),
9739 &params,
9740 params.len,
9741 .C,
9742 .Auto,
9743 "",
9744 ),
9745 &self.wip,
9913 const new_accum = try self.wip.call(
9914 .normal,
9915 .ccc,
9916 .none,
9917 llvm_fn.typeOf(&o.builder),
9918 llvm_fn.toValue(&o.builder),
9919 &.{ accum, element },
9920 "",
97469921 );
97479922 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
97489923
......@@ -10190,7 +10365,7 @@ pub const FuncGen = struct {
1019010365 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
1019110366 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
1019210367 };
10193 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
10368 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
1019410369 llvm_fn_ty.toLlvm(&o.builder),
1019510370 fn_val,
1019610371 &params,
......@@ -10222,7 +10397,7 @@ pub const FuncGen = struct {
1022210397
1022310398 const args: [0]*llvm.Value = .{};
1022410399 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
10225 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
10400 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
1022610401 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
1022710402 llvm_fn,
1022810403 &args,
......@@ -10252,12 +10427,15 @@ pub const FuncGen = struct {
1025210427 const dimension = pl_op.payload;
1025310428 if (dimension >= 3) return o.builder.intValue(.i32, 1);
1025410429
10430 var attributes: Builder.FunctionAttributes.Wip = .{};
10431 defer attributes.deinit(&o.builder);
10432
1025510433 // Fetch the dispatch pointer, which points to this structure:
1025610434 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
1025710435 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
1025810436 const args: [0]*llvm.Value = .{};
1025910437 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
10260 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCall(
10438 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCallOld(
1026110439 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
1026210440 llvm_fn,
1026310441 &args,
......@@ -10266,6 +10444,9 @@ pub const FuncGen = struct {
1026610444 .Auto,
1026710445 "",
1026810446 ), &self.wip);
10447 try attributes.addRetAttr(.{
10448 .@"align" = comptime Builder.Alignment.fromByteUnits(4),
10449 }, &o.builder);
1026910450 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
1027010451
1027110452 // Load the work_group_* member from the struct as u16.
......@@ -10298,7 +10479,7 @@ pub const FuncGen = struct {
1029810479 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
1029910480
1030010481 const name = try o.builder.string("__zig_err_name_table");
10301 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.toSlice(&o.builder).?);
10482 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.slice(&o.builder).?);
1030210483 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
1030310484 error_name_table_global.setLinkage(.Private);
1030410485 error_name_table_global.setGlobalConstant(.True);
......@@ -10751,7 +10932,7 @@ pub const FuncGen = struct {
1075110932 );
1075210933
1075310934 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10754 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10935 fg.builder.buildCallOld(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
1075510936 &fg.wip,
1075610937 );
1075710938 return call;
......@@ -10991,33 +11172,33 @@ fn toLlvmAtomicRmwBinOp(
1099111172 };
1099211173}
1099311174
10994fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {
11175fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {
1099511176 return switch (cc) {
10996 .Unspecified, .Inline, .Async => .Fast,
10997 .C, .Naked => .C,
10998 .Stdcall => .X86_StdCall,
10999 .Fastcall => .X86_FastCall,
11177 .Unspecified, .Inline, .Async => .fastcc,
11178 .C, .Naked => .ccc,
11179 .Stdcall => .x86_stdcallcc,
11180 .Fastcall => .x86_fastcallcc,
1100011181 .Vectorcall => return switch (target.cpu.arch) {
11001 .x86, .x86_64 => .X86_VectorCall,
11002 .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,
11182 .x86, .x86_64 => .x86_vectorcallcc,
11183 .aarch64, .aarch64_be, .aarch64_32 => .aarch64_vector_pcs,
1100311184 else => unreachable,
1100411185 },
11005 .Thiscall => .X86_ThisCall,
11006 .APCS => .ARM_APCS,
11007 .AAPCS => .ARM_AAPCS,
11008 .AAPCSVFP => .ARM_AAPCS_VFP,
11186 .Thiscall => .x86_thiscallcc,
11187 .APCS => .arm_apcscc,
11188 .AAPCS => .arm_aapcscc,
11189 .AAPCSVFP => .arm_aapcs_vfpcc,
1100911190 .Interrupt => return switch (target.cpu.arch) {
11010 .x86, .x86_64 => .X86_INTR,
11011 .avr => .AVR_INTR,
11012 .msp430 => .MSP430_INTR,
11191 .x86, .x86_64 => .x86_intrcc,
11192 .avr => .avr_intrcc,
11193 .msp430 => .msp430_intrcc,
1101311194 else => unreachable,
1101411195 },
11015 .Signal => .AVR_SIGNAL,
11016 .SysV => .X86_64_SysV,
11017 .Win64 => .Win64,
11196 .Signal => .avr_signalcc,
11197 .SysV => .x86_64_sysvcc,
11198 .Win64 => .win64cc,
1101811199 .Kernel => return switch (target.cpu.arch) {
11019 .nvptx, .nvptx64 => .PTX_Kernel,
11020 .amdgcn => .AMDGPU_KERNEL,
11200 .nvptx, .nvptx64 => .ptx_kernel,
11201 .amdgcn => .amdgpu_kernel,
1102111202 else => unreachable,
1102211203 },
1102311204 };
src/codegen/llvm/Builder.zig+1395-52
......@@ -4,13 +4,15 @@ strip: bool,
44
55llvm: if (build_options.have_llvm) struct {
66 context: *llvm.Context,
7 module: ?*llvm.Module = null,
8 target: ?*llvm.Target = null,
9 di_builder: ?*llvm.DIBuilder = null,
10 di_compile_unit: ?*llvm.DICompileUnit = null,
11 types: std.ArrayListUnmanaged(*llvm.Type) = .{},
12 globals: std.ArrayListUnmanaged(*llvm.Value) = .{},
13 constants: std.ArrayListUnmanaged(*llvm.Value) = .{},
7 module: ?*llvm.Module,
8 target: ?*llvm.Target,
9 di_builder: ?*llvm.DIBuilder,
10 di_compile_unit: ?*llvm.DICompileUnit,
11 attribute_kind_ids: ?*[Attribute.Kind.len]c_uint,
12 attributes: std.ArrayListUnmanaged(*llvm.Attribute),
13 types: std.ArrayListUnmanaged(*llvm.Type),
14 globals: std.ArrayListUnmanaged(*llvm.Value),
15 constants: std.ArrayListUnmanaged(*llvm.Value),
1416} else void,
1517
1618source_filename: String,
......@@ -18,8 +20,8 @@ data_layout: String,
1820target_triple: String,
1921
2022string_map: std.AutoArrayHashMapUnmanaged(void, void),
21string_bytes: std.ArrayListUnmanaged(u8),
2223string_indices: std.ArrayListUnmanaged(u32),
24string_bytes: std.ArrayListUnmanaged(u8),
2325
2426types: std.AutoArrayHashMapUnmanaged(String, Type),
2527next_unnamed_type: String,
......@@ -28,6 +30,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void),
2830type_items: std.ArrayListUnmanaged(Type.Item),
2931type_extra: std.ArrayListUnmanaged(u32),
3032
33attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void),
34attributes_map: std.AutoArrayHashMapUnmanaged(void, void),
35attributes_indices: std.ArrayListUnmanaged(u32),
36attributes_extra: std.ArrayListUnmanaged(u32),
37
3138globals: std.AutoArrayHashMapUnmanaged(String, Global),
3239next_unnamed_global: String,
3340next_replaced_global: String,
......@@ -41,6 +48,7 @@ constant_items: std.MultiArrayList(Constant.Item),
4148constant_extra: std.ArrayListUnmanaged(u32),
4249constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
4350
51pub const expected_args_len = 16;
4452pub const expected_fields_len = 32;
4553pub const expected_gep_indices_len = 8;
4654pub const expected_cases_len = 8;
......@@ -65,7 +73,7 @@ pub const String = enum(u32) {
6573 return self.toIndex() == null;
6674 }
6775
68 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
76 pub fn slice(self: String, b: *const Builder) ?[:0]const u8 {
6977 const index = self.toIndex() orelse return null;
7078 const start = b.string_indices.items[index];
7179 const end = b.string_indices.items[index + 1];
......@@ -85,9 +93,9 @@ pub const String = enum(u32) {
8593 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
8694 @compileError("invalid format string: '" ++ fmt_str ++ "'");
8795 assert(data.string != .none);
88 const slice = data.string.toSlice(data.builder) orelse
96 const sentinel_slice = data.string.slice(data.builder) orelse
8997 return writer.print("{d}", .{@intFromEnum(data.string)});
90 const full_slice = slice[0 .. slice.len + comptime @intFromBool(
98 const full_slice = sentinel_slice[0 .. sentinel_slice.len + comptime @intFromBool(
9199 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
92100 )];
93101 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or
......@@ -108,6 +116,7 @@ pub const String = enum(u32) {
108116 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
109117 @intFromEnum(String.empty))));
110118 }
119
111120 fn toIndex(self: String) ?usize {
112121 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
113122 }
......@@ -118,7 +127,7 @@ pub const String = enum(u32) {
118127 return @truncate(std.hash.Wyhash.hash(0, key));
119128 }
120129 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
121 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).toSlice(ctx.builder).?);
130 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).slice(ctx.builder).?);
122131 }
123132 };
124133};
......@@ -290,6 +299,17 @@ pub const Type = enum(u32) {
290299 };
291300 }
292301
302 pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace {
303 switch (self) {
304 .ptr => return .default,
305 else => {
306 const item = builder.type_items.items[@intFromEnum(self)];
307 assert(item.tag == .pointer);
308 return @enumFromInt(item.data);
309 },
310 }
311 }
312
293313 pub fn isFunction(self: Type, builder: *const Builder) bool {
294314 return switch (self.tag(builder)) {
295315 .function, .vararg_function => true,
......@@ -606,7 +626,7 @@ pub const Type = enum(u32) {
606626 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
607627 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
608628 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
609 try writer.print("t{s}", .{extra.data.name.toSlice(data.builder).?});
629 try writer.print("t{s}", .{extra.data.name.slice(data.builder).?});
610630 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
611631 for (ints) |int| try writer.print("_{d}", .{int});
612632 try writer.writeByte('t');
......@@ -641,7 +661,7 @@ pub const Type = enum(u32) {
641661 .named_structure => {
642662 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
643663 try writer.writeAll("s_");
644 if (extra.id.toSlice(data.builder)) |id| try writer.writeAll(id);
664 if (extra.id.slice(data.builder)) |id| try writer.writeAll(id);
645665 },
646666 }
647667 return;
......@@ -823,6 +843,789 @@ pub const Type = enum(u32) {
823843 }
824844};
825845
846pub const Attribute = union(Kind) {
847 // Parameter Attributes
848 zeroext,
849 signext,
850 inreg,
851 byval: Type,
852 byref: Type,
853 preallocated: Type,
854 inalloca: Type,
855 sret: Type,
856 elementtype: Type,
857 @"align": Alignment,
858 @"noalias",
859 nocapture,
860 nofree,
861 nest,
862 returned,
863 nonnull,
864 dereferenceable: u32,
865 dereferenceable_or_null: u32,
866 swiftself,
867 swiftasync,
868 swifterror,
869 immarg,
870 noundef,
871 nofpclass: FpClass,
872 alignstack: Alignment,
873 allocalign,
874 allocptr,
875 readnone,
876 readonly,
877 writeonly,
878
879 // Function Attributes
880 //alignstack: Alignment,
881 allockind: AllocKind,
882 allocsize: AllocSize,
883 alwaysinline,
884 builtin,
885 cold,
886 convergent,
887 disable_sanitizer_information,
888 fn_ret_thunk_extern,
889 hot,
890 inlinehint,
891 jumptable,
892 memory: Memory,
893 minsize,
894 naked,
895 nobuiltin,
896 nocallback,
897 noduplicate,
898 //nofree,
899 noimplicitfloat,
900 @"noinline",
901 nomerge,
902 nonlazybind,
903 noprofile,
904 skipprofile,
905 noredzone,
906 noreturn,
907 norecurse,
908 willreturn,
909 nosync,
910 nounwind,
911 nosanitize_bounds,
912 nosanitize_coverage,
913 null_pointer_is_valid,
914 optforfuzzing,
915 optnone,
916 optsize,
917 //preallocated: Type,
918 returns_twice,
919 safestack,
920 sanitize_address,
921 sanitize_memory,
922 sanitize_thread,
923 sanitize_hwaddress,
924 sanitize_memtag,
925 speculative_load_hardening,
926 speculatable,
927 ssp,
928 sspstrong,
929 sspreq,
930 strictfp,
931 uwtable: UwTable,
932 nocf_check,
933 shadowcallstack,
934 mustprogress,
935 vscale_range: VScaleRange,
936
937 // Global Attributes
938 no_sanitize_address,
939 no_sanitize_hwaddress,
940 //sanitize_memtag,
941 sanitize_address_dyninit,
942
943 string: struct { kind: String, value: String },
944 none: noreturn,
945
946 pub const Index = enum(u32) {
947 _,
948
949 pub fn getKind(self: Index, builder: *const Builder) Kind {
950 return self.toStorage(builder).kind;
951 }
952
953 pub fn toAttribute(self: Index, builder: *const Builder) Attribute {
954 @setEvalBranchQuota(2_000);
955 const storage = self.toStorage(builder);
956 if (storage.kind.toString()) |kind| return .{ .string = .{
957 .kind = kind,
958 .value = @enumFromInt(storage.value),
959 } } else return switch (storage.kind) {
960 inline .zeroext,
961 .signext,
962 .inreg,
963 .byval,
964 .byref,
965 .preallocated,
966 .inalloca,
967 .sret,
968 .elementtype,
969 .@"align",
970 .@"noalias",
971 .nocapture,
972 .nofree,
973 .nest,
974 .returned,
975 .nonnull,
976 .dereferenceable,
977 .dereferenceable_or_null,
978 .swiftself,
979 .swiftasync,
980 .swifterror,
981 .immarg,
982 .noundef,
983 .nofpclass,
984 .alignstack,
985 .allocalign,
986 .allocptr,
987 .readnone,
988 .readonly,
989 .writeonly,
990 //.alignstack,
991 .allockind,
992 .allocsize,
993 .alwaysinline,
994 .builtin,
995 .cold,
996 .convergent,
997 .disable_sanitizer_information,
998 .fn_ret_thunk_extern,
999 .hot,
1000 .inlinehint,
1001 .jumptable,
1002 .memory,
1003 .minsize,
1004 .naked,
1005 .nobuiltin,
1006 .nocallback,
1007 .noduplicate,
1008 //.nofree,
1009 .noimplicitfloat,
1010 .@"noinline",
1011 .nomerge,
1012 .nonlazybind,
1013 .noprofile,
1014 .skipprofile,
1015 .noredzone,
1016 .noreturn,
1017 .norecurse,
1018 .willreturn,
1019 .nosync,
1020 .nounwind,
1021 .nosanitize_bounds,
1022 .nosanitize_coverage,
1023 .null_pointer_is_valid,
1024 .optforfuzzing,
1025 .optnone,
1026 .optsize,
1027 //.preallocated,
1028 .returns_twice,
1029 .safestack,
1030 .sanitize_address,
1031 .sanitize_memory,
1032 .sanitize_thread,
1033 .sanitize_hwaddress,
1034 .sanitize_memtag,
1035 .speculative_load_hardening,
1036 .speculatable,
1037 .ssp,
1038 .sspstrong,
1039 .sspreq,
1040 .strictfp,
1041 .uwtable,
1042 .nocf_check,
1043 .shadowcallstack,
1044 .mustprogress,
1045 .vscale_range,
1046 .no_sanitize_address,
1047 .no_sanitize_hwaddress,
1048 .sanitize_address_dyninit,
1049 => |kind| {
1050 const field = @typeInfo(Attribute).Union.fields[@intFromEnum(kind)];
1051 comptime assert(std.mem.eql(u8, @tagName(kind), field.name));
1052 return @unionInit(Attribute, field.name, switch (field.type) {
1053 void => {},
1054 u32 => storage.value,
1055 Alignment, String, Type, UwTable => @enumFromInt(storage.value),
1056 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
1057 else => @compileError("bad payload type: " ++ @typeName(field.type)),
1058 });
1059 },
1060 .string, .none => unreachable,
1061 _ => unreachable,
1062 };
1063 }
1064
1065 const FormatData = struct {
1066 attribute_index: Index,
1067 builder: *const Builder,
1068 };
1069 fn format(
1070 data: FormatData,
1071 comptime fmt_str: []const u8,
1072 _: std.fmt.FormatOptions,
1073 writer: anytype,
1074 ) @TypeOf(writer).Error!void {
1075 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"")) |_|
1076 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1077 const attribute = data.attribute_index.toAttribute(data.builder);
1078 switch (attribute) {
1079 .zeroext,
1080 .signext,
1081 .inreg,
1082 .@"noalias",
1083 .nocapture,
1084 .nofree,
1085 .nest,
1086 .returned,
1087 .nonnull,
1088 .swiftself,
1089 .swiftasync,
1090 .swifterror,
1091 .immarg,
1092 .noundef,
1093 .allocalign,
1094 .allocptr,
1095 .readnone,
1096 .readonly,
1097 .writeonly,
1098 .alwaysinline,
1099 .builtin,
1100 .cold,
1101 .convergent,
1102 .disable_sanitizer_information,
1103 .fn_ret_thunk_extern,
1104 .hot,
1105 .inlinehint,
1106 .jumptable,
1107 .minsize,
1108 .naked,
1109 .nobuiltin,
1110 .nocallback,
1111 .noduplicate,
1112 .noimplicitfloat,
1113 .@"noinline",
1114 .nomerge,
1115 .nonlazybind,
1116 .noprofile,
1117 .skipprofile,
1118 .noredzone,
1119 .noreturn,
1120 .norecurse,
1121 .willreturn,
1122 .nosync,
1123 .nounwind,
1124 .nosanitize_bounds,
1125 .nosanitize_coverage,
1126 .null_pointer_is_valid,
1127 .optforfuzzing,
1128 .optnone,
1129 .optsize,
1130 .returns_twice,
1131 .safestack,
1132 .sanitize_address,
1133 .sanitize_memory,
1134 .sanitize_thread,
1135 .sanitize_hwaddress,
1136 .sanitize_memtag,
1137 .speculative_load_hardening,
1138 .speculatable,
1139 .ssp,
1140 .sspstrong,
1141 .sspreq,
1142 .strictfp,
1143 .nocf_check,
1144 .shadowcallstack,
1145 .mustprogress,
1146 .no_sanitize_address,
1147 .no_sanitize_hwaddress,
1148 .sanitize_address_dyninit,
1149 => try writer.print(" {s}", .{@tagName(attribute)}),
1150 .byval,
1151 .byref,
1152 .preallocated,
1153 .inalloca,
1154 .sret,
1155 .elementtype,
1156 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1157 .@"align" => @panic("todo"),
1158 .dereferenceable,
1159 .dereferenceable_or_null,
1160 => @panic("todo"),
1161 .nofpclass => @panic("todo"),
1162 .alignstack => @panic("todo"),
1163 .allockind => @panic("todo"),
1164 .allocsize => @panic("todo"),
1165 .memory => @panic("todo"),
1166 .uwtable => @panic("todo"),
1167 .vscale_range => @panic("todo"),
1168 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1169 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1170 if (string_attr.value != .empty)
1171 try writer.print("={\"}", .{string_attr.value.fmt(data.builder)});
1172 },
1173 .none => unreachable,
1174 }
1175 }
1176 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1177 return .{ .data = .{ .attribute_index = self, .builder = builder } };
1178 }
1179
1180 fn toStorage(self: Index, builder: *const Builder) Storage {
1181 return builder.attributes.keys()[@intFromEnum(self)];
1182 }
1183
1184 fn toLlvm(self: Index, builder: *const Builder) *llvm.Attribute {
1185 assert(builder.useLibLlvm());
1186 return builder.llvm.attributes.items[@intFromEnum(self)];
1187 }
1188 };
1189
1190 pub const Kind = enum(u32) {
1191 // Parameter Attributes
1192 zeroext,
1193 signext,
1194 inreg,
1195 byval,
1196 byref,
1197 preallocated,
1198 inalloca,
1199 sret,
1200 elementtype,
1201 @"align",
1202 @"noalias",
1203 nocapture,
1204 nofree,
1205 nest,
1206 returned,
1207 nonnull,
1208 dereferenceable,
1209 dereferenceable_or_null,
1210 swiftself,
1211 swiftasync,
1212 swifterror,
1213 immarg,
1214 noundef,
1215 nofpclass,
1216 alignstack,
1217 allocalign,
1218 allocptr,
1219 readnone,
1220 readonly,
1221 writeonly,
1222
1223 // Function Attributes
1224 //alignstack,
1225 allockind,
1226 allocsize,
1227 alwaysinline,
1228 builtin,
1229 cold,
1230 convergent,
1231 disable_sanitizer_information,
1232 fn_ret_thunk_extern,
1233 hot,
1234 inlinehint,
1235 jumptable,
1236 memory,
1237 minsize,
1238 naked,
1239 nobuiltin,
1240 nocallback,
1241 noduplicate,
1242 //nofree,
1243 noimplicitfloat,
1244 @"noinline",
1245 nomerge,
1246 nonlazybind,
1247 noprofile,
1248 skipprofile,
1249 noredzone,
1250 noreturn,
1251 norecurse,
1252 willreturn,
1253 nosync,
1254 nounwind,
1255 nosanitize_bounds,
1256 nosanitize_coverage,
1257 null_pointer_is_valid,
1258 optforfuzzing,
1259 optnone,
1260 optsize,
1261 //preallocated,
1262 returns_twice,
1263 safestack,
1264 sanitize_address,
1265 sanitize_memory,
1266 sanitize_thread,
1267 sanitize_hwaddress,
1268 sanitize_memtag,
1269 speculative_load_hardening,
1270 speculatable,
1271 ssp,
1272 sspstrong,
1273 sspreq,
1274 strictfp,
1275 uwtable,
1276 nocf_check,
1277 shadowcallstack,
1278 mustprogress,
1279 vscale_range,
1280
1281 // Global Attributes
1282 no_sanitize_address,
1283 no_sanitize_hwaddress,
1284 //sanitize_memtag,
1285 sanitize_address_dyninit,
1286
1287 string = std.math.maxInt(u31) - 1,
1288 none = std.math.maxInt(u31),
1289 _,
1290
1291 pub const len = @typeInfo(Kind).Enum.fields.len - 2;
1292
1293 pub fn fromString(str: String) Kind {
1294 assert(!str.isAnon());
1295 return @enumFromInt(@intFromEnum(str));
1296 }
1297
1298 fn toString(self: Kind) ?String {
1299 const str: String = @enumFromInt(@intFromEnum(self));
1300 return if (str.isAnon()) null else str;
1301 }
1302 };
1303
1304 pub const FpClass = packed struct(u32) {
1305 signaling_nan: bool = false,
1306 quiet_nan: bool = false,
1307 negative_infinity: bool = false,
1308 negative_normal: bool = false,
1309 negative_subnormal: bool = false,
1310 negative_zero: bool = false,
1311 positive_zero: bool = false,
1312 positive_subnormal: bool = false,
1313 positive_normal: bool = false,
1314 positive_infinity: bool = false,
1315 _: u22 = 0,
1316
1317 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1318 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1319 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1320 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1321 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1322 pub const all = FpClass{
1323 .signaling_nan = true,
1324 .quiet_nan = true,
1325 .negative_infinity = true,
1326 .negative_normal = true,
1327 .negative_subnormal = true,
1328 .negative_zero = true,
1329 .positive_zero = true,
1330 .positive_subnormal = true,
1331 .positive_normal = true,
1332 .positive_infinity = true,
1333 };
1334 pub const snan = FpClass{ .signaling_nan = true };
1335 pub const qnan = FpClass{ .quiet_nan = true };
1336 pub const ninf = FpClass{ .negative_infinity = true };
1337 pub const nnorm = FpClass{ .negative_normal = true };
1338 pub const nsub = FpClass{ .negative_subnormal = true };
1339 pub const nzero = FpClass{ .negative_zero = true };
1340 pub const pzero = FpClass{ .positive_zero = true };
1341 pub const psub = FpClass{ .positive_subnormal = true };
1342 pub const pnorm = FpClass{ .positive_normal = true };
1343 pub const pinf = FpClass{ .positive_infinity = true };
1344 };
1345
1346 pub const AllocKind = packed struct(u32) {
1347 alloc: bool,
1348 realloc: bool,
1349 free: bool,
1350 uninitialized: bool,
1351 zeroed: bool,
1352 aligned: bool,
1353 _: u26 = 0,
1354 };
1355
1356 pub const AllocSize = packed struct(u32) {
1357 elem_size: u16,
1358 num_elems: u16,
1359
1360 pub const none = std.math.maxInt(u16);
1361
1362 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
1363 return .{ .num_elems = switch (self.num_elems) {
1364 else => self.num_elems,
1365 none => std.math.maxInt(u32),
1366 }, .elem_size = self.elem_size };
1367 }
1368 };
1369
1370 pub const Memory = packed struct(u32) {
1371 argmem: Effect,
1372 inaccessiblemem: Effect,
1373 other: Effect,
1374 _: u26 = 0,
1375
1376 pub const Effect = enum(u2) { none, read, write, readwrite };
1377 };
1378
1379 pub const UwTable = enum(u32) {
1380 none,
1381 sync,
1382 @"async",
1383
1384 pub const default = UwTable.@"async";
1385 };
1386
1387 pub const VScaleRange = packed struct(u32) {
1388 min: Alignment,
1389 max: Alignment,
1390 _: u20 = 0,
1391
1392 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
1393 return .{
1394 .max = @intCast(self.max.toByteUnits() orelse 0),
1395 .min = @intCast(self.min.toByteUnits().?),
1396 };
1397 }
1398 };
1399
1400 pub fn getKind(self: Attribute) Kind {
1401 return switch (self) {
1402 else => self,
1403 .string => |string_attr| Kind.fromString(string_attr.kind),
1404 };
1405 }
1406
1407 const Storage = extern struct {
1408 kind: Kind,
1409 value: u32,
1410 };
1411
1412 fn toStorage(self: Attribute) Storage {
1413 return switch (self) {
1414 inline else => |value| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
1415 void => 0,
1416 u32 => value,
1417 Alignment, String, Type, UwTable => @intFromEnum(value),
1418 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
1419 else => @compileError("bad payload type: " ++ @typeName(@TypeOf(value))),
1420 } },
1421 .string => |string_attr| .{
1422 .kind = Kind.fromString(string_attr.kind),
1423 .value = @intFromEnum(string_attr.value),
1424 },
1425 .none => unreachable,
1426 };
1427 }
1428};
1429
1430pub const Attributes = enum(u32) {
1431 none,
1432 _,
1433
1434 pub fn slice(self: Attributes, builder: *const Builder) []const Attribute.Index {
1435 const start = builder.attributes_indices.items[@intFromEnum(self)];
1436 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1437 return @ptrCast(builder.attributes_extra.items[start..end]);
1438 }
1439
1440 const FormatData = struct {
1441 attributes: Attributes,
1442 builder: *const Builder,
1443 };
1444 fn format(
1445 data: FormatData,
1446 comptime fmt_str: []const u8,
1447 fmt_opts: std.fmt.FormatOptions,
1448 writer: anytype,
1449 ) @TypeOf(writer).Error!void {
1450 for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{
1451 .attribute_index = attribute_index,
1452 .builder = data.builder,
1453 }, fmt_str, fmt_opts, writer);
1454 }
1455 pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) {
1456 return .{ .data = .{ .attributes = self, .builder = builder } };
1457 }
1458};
1459
1460pub const FunctionAttributes = enum(u32) {
1461 none,
1462 _,
1463
1464 const function_index = 0;
1465 const return_index = 1;
1466 const params_index = 2;
1467
1468 pub const Wip = struct {
1469 maps: Maps = .{},
1470
1471 const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index);
1472 const Maps = std.ArrayListUnmanaged(Map);
1473
1474 pub fn deinit(self: *Wip, builder: *const Builder) void {
1475 for (self.maps.items) |*map| map.deinit(builder.gpa);
1476 self.maps.deinit(builder.gpa);
1477 self.* = undefined;
1478 }
1479
1480 pub fn addFnAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1481 try self.addAttr(function_index, attribute, builder);
1482 }
1483
1484 pub fn addFnAttrIndex(
1485 self: *Wip,
1486 attribute_index: Attribute.Index,
1487 builder: *const Builder,
1488 ) Allocator.Error!void {
1489 try self.addAttrIndex(function_index, attribute_index, builder);
1490 }
1491
1492 pub fn removeFnAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1493 return self.removeAttr(function_index, attribute_kind);
1494 }
1495
1496 pub fn addRetAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1497 try self.addAttr(return_index, attribute, builder);
1498 }
1499
1500 pub fn addRetAttrIndex(
1501 self: *Wip,
1502 attribute_index: Attribute.Index,
1503 builder: *const Builder,
1504 ) Allocator.Error!void {
1505 try self.addAttrIndex(return_index, attribute_index, builder);
1506 }
1507
1508 pub fn removeRetAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1509 return self.removeAttr(return_index, attribute_kind);
1510 }
1511
1512 pub fn addParamAttr(
1513 self: *Wip,
1514 param_index: usize,
1515 attribute: Attribute,
1516 builder: *Builder,
1517 ) Allocator.Error!void {
1518 try self.addAttr(params_index + param_index, attribute, builder);
1519 }
1520
1521 pub fn addParamAttrIndex(
1522 self: *Wip,
1523 param_index: usize,
1524 attribute_index: Attribute.Index,
1525 builder: *const Builder,
1526 ) Allocator.Error!void {
1527 try self.addAttrIndex(params_index + param_index, attribute_index, builder);
1528 }
1529
1530 pub fn removeParamAttr(
1531 self: *Wip,
1532 param_index: usize,
1533 attribute_kind: Attribute.Kind,
1534 ) Allocator.Error!bool {
1535 return self.removeAttr(params_index + param_index, attribute_kind);
1536 }
1537
1538 pub fn finish(self: *const Wip, builder: *Builder) Allocator.Error!FunctionAttributes {
1539 const attributes = try builder.gpa.alloc(Attributes, self.maps.items.len);
1540 defer builder.gpa.free(attributes);
1541 for (attributes, self.maps.items) |*attribute, map|
1542 attribute.* = try builder.attrs(map.values());
1543 return builder.fnAttrs(attributes);
1544 }
1545
1546 fn addAttr(
1547 self: *Wip,
1548 index: usize,
1549 attribute: Attribute,
1550 builder: *Builder,
1551 ) Allocator.Error!void {
1552 const map = try self.getOrPutMap(builder.gpa, index);
1553 try map.put(builder.gpa, attribute.getKind(), try builder.attr(attribute));
1554 }
1555
1556 fn addAttrIndex(
1557 self: *Wip,
1558 index: usize,
1559 attribute_index: Attribute.Index,
1560 builder: *const Builder,
1561 ) Allocator.Error!void {
1562 const map = try self.getOrPutMap(builder.gpa, index);
1563 try map.put(builder.gpa, attribute_index.getKind(builder), attribute_index);
1564 }
1565
1566 fn removeAttr(self: *Wip, index: usize, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1567 const map = self.getMap(index) orelse return false;
1568 return map.swapRemove(attribute_kind);
1569 }
1570
1571 fn getOrPutMap(self: *Wip, allocator: Allocator, index: usize) Allocator.Error!*Map {
1572 if (index >= self.maps.items.len)
1573 try self.maps.appendNTimes(allocator, .{}, index + 1 - self.maps.items.len);
1574 return &self.maps.items[index];
1575 }
1576
1577 fn getMap(self: *Wip, index: usize) ?*Map {
1578 return if (index >= self.maps.items.len) null else &self.maps.items[index];
1579 }
1580
1581 fn ensureTotalLength(self: *Wip, new_len: usize) Allocator.Error!void {
1582 try self.maps.appendNTimes(
1583 .{},
1584 std.math.sub(usize, new_len, self.maps.items.len) catch return,
1585 );
1586 }
1587 };
1588
1589 pub fn func(self: FunctionAttributes, builder: *const Builder) Attributes {
1590 return self.get(function_index, builder);
1591 }
1592
1593 pub fn ret(self: FunctionAttributes, builder: *const Builder) Attributes {
1594 return self.get(return_index, builder);
1595 }
1596
1597 pub fn param(self: FunctionAttributes, param_index: usize, builder: *const Builder) Attributes {
1598 return self.get(params_index + param_index, builder);
1599 }
1600
1601 pub fn toWip(self: FunctionAttributes, builder: *const Builder) Allocator.Error!Wip {
1602 var wip: Wip = .{};
1603 errdefer wip.deinit(builder);
1604 const attributes_slice = self.slice(builder);
1605 try wip.maps.ensureTotalCapacityPrecise(builder.gpa, attributes_slice.len);
1606 for (attributes_slice) |attributes| {
1607 const map = wip.maps.addOneAssumeCapacity();
1608 map.* = .{};
1609 const attribute_slice = attributes.slice(builder);
1610 try map.ensureTotalCapacity(builder.gpa, attribute_slice.len);
1611 for (attributes.slice(builder)) |attribute|
1612 map.putAssumeCapacityNoClobber(attribute.getKind(builder), attribute);
1613 }
1614 return wip;
1615 }
1616
1617 fn get(self: FunctionAttributes, index: usize, builder: *const Builder) Attributes {
1618 const attribute_slice = self.slice(builder);
1619 return if (index < attribute_slice.len) attribute_slice[index] else .none;
1620 }
1621
1622 fn slice(self: FunctionAttributes, builder: *const Builder) []const Attributes {
1623 const start = builder.attributes_indices.items[@intFromEnum(self)];
1624 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1625 return @ptrCast(builder.attributes_extra.items[start..end]);
1626 }
1627};
1628
8261629pub const Linkage = enum {
8271630 external,
8281631 private,
......@@ -1053,6 +1856,127 @@ pub const Alignment = enum(u6) {
10531856 }
10541857};
10551858
1859pub const CallConv = enum(u10) {
1860 ccc,
1861
1862 fastcc = 8,
1863 coldcc,
1864 ghccc,
1865
1866 webkit_jscc = 12,
1867 anyregcc,
1868 preserve_mostcc,
1869 preserve_allcc,
1870 swiftcc,
1871 cxx_fast_tlscc,
1872 tailcc,
1873 cfguard_checkcc,
1874 swifttailcc,
1875
1876 x86_stdcallcc = 64,
1877 x86_fastcallcc,
1878 arm_apcscc,
1879 arm_aapcscc,
1880 arm_aapcs_vfpcc,
1881 msp430_intrcc,
1882 x86_thiscallcc,
1883 ptx_kernel,
1884 ptx_device,
1885
1886 spir_func = 75,
1887 spir_kernel,
1888 intel_ocl_bicc,
1889 x86_64_sysvcc,
1890 win64cc,
1891 x86_vectorcallcc,
1892 hhvmcc,
1893 hhvm_ccc,
1894 x86_intrcc,
1895 avr_intrcc,
1896 avr_signalcc,
1897
1898 amdgpu_vs = 87,
1899 amdgpu_gs,
1900 amdgpu_ps,
1901 amdgpu_cs,
1902 amdgpu_kernel,
1903 x86_regcallcc,
1904 amdgpu_hs,
1905
1906 amdgpu_ls = 95,
1907 amdgpu_es,
1908 aarch64_vector_pcs,
1909 aarch64_sve_vector_pcs,
1910
1911 amdgpu_gfx = 100,
1912
1913 aarch64_sme_preservemost_from_x0 = 102,
1914 aarch64_sme_preservemost_from_x2,
1915
1916 _,
1917
1918 pub const default = CallConv.ccc;
1919
1920 pub fn format(
1921 self: CallConv,
1922 comptime _: []const u8,
1923 _: std.fmt.FormatOptions,
1924 writer: anytype,
1925 ) @TypeOf(writer).Error!void {
1926 switch (self) {
1927 .ccc => {},
1928 .fastcc,
1929 .coldcc,
1930 .ghccc,
1931 .webkit_jscc,
1932 .anyregcc,
1933 .preserve_mostcc,
1934 .preserve_allcc,
1935 .swiftcc,
1936 .cxx_fast_tlscc,
1937 .tailcc,
1938 .cfguard_checkcc,
1939 .swifttailcc,
1940 .x86_stdcallcc,
1941 .x86_fastcallcc,
1942 .arm_apcscc,
1943 .arm_aapcscc,
1944 .arm_aapcs_vfpcc,
1945 .msp430_intrcc,
1946 .x86_thiscallcc,
1947 .ptx_kernel,
1948 .ptx_device,
1949 .spir_func,
1950 .spir_kernel,
1951 .intel_ocl_bicc,
1952 .x86_64_sysvcc,
1953 .win64cc,
1954 .x86_vectorcallcc,
1955 .hhvmcc,
1956 .hhvm_ccc,
1957 .x86_intrcc,
1958 .avr_intrcc,
1959 .avr_signalcc,
1960 .amdgpu_vs,
1961 .amdgpu_gs,
1962 .amdgpu_ps,
1963 .amdgpu_cs,
1964 .amdgpu_kernel,
1965 .x86_regcallcc,
1966 .amdgpu_hs,
1967 .amdgpu_ls,
1968 .amdgpu_es,
1969 .aarch64_vector_pcs,
1970 .aarch64_sve_vector_pcs,
1971 .amdgpu_gfx,
1972 .aarch64_sme_preservemost_from_x0,
1973 .aarch64_sme_preservemost_from_x2,
1974 => try writer.print(" {s}", .{@tagName(self)}),
1975 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
1976 }
1977 }
1978};
1979
10561980pub const Global = struct {
10571981 linkage: Linkage = .external,
10581982 preemption: Preemption = .dso_preemptable,
......@@ -1170,7 +2094,7 @@ pub const Global = struct {
11702094 fn updateName(self: Index, builder: *const Builder) void {
11712095 if (!builder.useLibLlvm()) return;
11722096 const index = @intFromEnum(self.unwrap(builder));
1173 const name_slice = self.name(builder).toSlice(builder) orelse "";
2097 const name_slice = self.name(builder).slice(builder) orelse "";
11742098 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
11752099 }
11762100
......@@ -1301,6 +2225,8 @@ pub const Variable = struct {
13012225
13022226pub const Function = struct {
13032227 global: Global.Index,
2228 call_conv: CallConv = CallConv.default,
2229 attributes: FunctionAttributes = .none,
13042230 section: String = .none,
13052231 alignment: Alignment = .default,
13062232 blocks: []const Block = &.{},
......@@ -1364,6 +2290,8 @@ pub const Function = struct {
13642290 block,
13652291 br,
13662292 br_cond,
2293 call,
2294 @"call fast",
13672295 extractelement,
13682296 extractvalue,
13692297 fadd,
......@@ -1454,6 +2382,10 @@ pub const Function = struct {
14542382 @"mul nsw",
14552383 @"mul nuw",
14562384 @"mul nuw nsw",
2385 @"musttail call",
2386 @"musttail call fast",
2387 @"notail call",
2388 @"notail call fast",
14572389 @"or",
14582390 phi,
14592391 @"phi fast",
......@@ -1481,6 +2413,8 @@ pub const Function = struct {
14812413 @"sub nuw",
14822414 @"sub nuw nsw",
14832415 @"switch",
2416 @"tail call",
2417 @"tail call fast",
14842418 trunc,
14852419 udiv,
14862420 @"udiv exact",
......@@ -1530,6 +2464,15 @@ pub const Function = struct {
15302464 .@"store volatile",
15312465 .@"unreachable",
15322466 => false,
2467 .call,
2468 .@"call fast",
2469 .@"musttail call",
2470 .@"musttail call fast",
2471 .@"notail call",
2472 .@"notail call fast",
2473 .@"tail call",
2474 .@"tail call fast",
2475 => self.typeOfWip(wip) != .void,
15332476 else => true,
15342477 };
15352478 }
......@@ -1625,6 +2568,15 @@ pub const Function = struct {
16252568 .@"switch",
16262569 .@"unreachable",
16272570 => .none,
2571 .call,
2572 .@"call fast",
2573 .@"musttail call",
2574 .@"musttail call fast",
2575 .@"notail call",
2576 .@"notail call fast",
2577 .@"tail call",
2578 .@"tail call fast",
2579 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
16282580 .extractelement => wip.extraData(ExtractElement, instruction.data)
16292581 .val.typeOfWip(wip).childType(wip.builder),
16302582 .extractvalue => {
......@@ -1813,6 +2765,15 @@ pub const Function = struct {
18132765 .@"switch",
18142766 .@"unreachable",
18152767 => .none,
2768 .call,
2769 .@"call fast",
2770 .@"musttail call",
2771 .@"musttail call fast",
2772 .@"notail call",
2773 .@"notail call fast",
2774 .@"tail call",
2775 .@"tail call fast",
2776 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
18162777 .extractelement => function.extraData(ExtractElement, instruction.data)
18172778 .val.typeOf(function_index, builder).childType(builder),
18182779 .extractvalue => {
......@@ -1955,7 +2916,7 @@ pub const Function = struct {
19552916 return if (wip.builder.strip)
19562917 ""
19572918 else
1958 wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?;
2919 wip.names.items[@intFromEnum(self)].slice(wip.builder).?;
19592920 }
19602921 };
19612922
......@@ -2063,6 +3024,30 @@ pub const Function = struct {
20633024 rhs: Value,
20643025 };
20653026
3027 pub const Call = struct {
3028 info: Info,
3029 attributes: FunctionAttributes,
3030 ty: Type,
3031 callee: Value,
3032 args_len: u32,
3033 //args: [args_len]Value,
3034
3035 pub const Kind = enum {
3036 normal,
3037 fast,
3038 musttail,
3039 musttail_fast,
3040 notail,
3041 notail_fast,
3042 tail,
3043 tail_fast,
3044 };
3045 pub const Info = packed struct(u32) {
3046 call_conv: CallConv,
3047 _: u22 = undefined,
3048 };
3049 };
3050
20663051 pub const VaArg = struct {
20673052 list: Value,
20683053 type: Type,
......@@ -2117,8 +3102,17 @@ pub const Function = struct {
21173102 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
21183103 @field(result, field.name) = switch (field.type) {
21193104 u32 => value,
2120 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
2121 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3105 Alignment,
3106 AtomicOrdering,
3107 Block.Index,
3108 FunctionAttributes,
3109 Type,
3110 Value,
3111 => @enumFromInt(value),
3112 MemoryAccessInfo,
3113 Instruction.Alloca.Info,
3114 Instruction.Call.Info,
3115 => @bitCast(value),
21223116 else => @compileError("bad field type: " ++ @typeName(field.type)),
21233117 };
21243118 return .{
......@@ -2243,7 +3237,7 @@ pub const WipFunction = struct {
22433237 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
22443238 self.builder.llvm.context.appendBasicBlock(
22453239 self.function.toLlvm(self.builder),
2246 final_name.toSlice(self.builder).?,
3240 final_name.slice(self.builder).?,
22473241 ),
22483242 );
22493243 return index;
......@@ -3162,6 +4156,88 @@ pub const WipFunction = struct {
31624156 return self.selectTag(.@"select fast", cond, lhs, rhs, name);
31634157 }
31644158
4159 pub fn call(
4160 self: *WipFunction,
4161 kind: Instruction.Call.Kind,
4162 call_conv: CallConv,
4163 function_attributes: FunctionAttributes,
4164 ty: Type,
4165 callee: Value,
4166 args: []const Value,
4167 name: []const u8,
4168 ) if (build_options.have_llvm) Allocator.Error!Value else Value {
4169 const ret_ty = ty.functionReturn(self.builder);
4170 assert(ty.isFunction(self.builder));
4171 assert(callee.typeOfWip(self).isPointer(self.builder));
4172 const params = ty.functionParameters(self.builder);
4173 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));
4174
4175 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len);
4176 const instruction = try self.addInst(switch (ret_ty) {
4177 .void => null,
4178 else => name,
4179 }, .{
4180 .tag = .call,
4181 .data = self.addExtraAssumeCapacity(Instruction.Call{
4182 .info = .{ .call_conv = call_conv },
4183 .attributes = function_attributes,
4184 .ty = ty,
4185 .callee = callee,
4186 .args_len = @intCast(args.len),
4187 }),
4188 });
4189 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
4190 if (self.builder.useLibLlvm()) {
4191 const ExpectedContents = [expected_args_len]*llvm.Value;
4192 var stack align(@alignOf(ExpectedContents)) =
4193 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
4194 const allocator = stack.get();
4195
4196 const llvm_args = try allocator.alloc(*llvm.Value, args.len);
4197 defer allocator.free(llvm_args);
4198 for (llvm_args, args) |*llvm_arg, arg_val| llvm_arg.* = arg_val.toLlvm(self);
4199
4200 switch (kind) {
4201 .normal,
4202 .musttail,
4203 .notail,
4204 .tail,
4205 => self.llvm.builder.setFastMath(false),
4206 .fast,
4207 .musttail_fast,
4208 .notail_fast,
4209 .tail_fast,
4210 => self.llvm.builder.setFastMath(true),
4211 }
4212 const llvm_instruction = self.llvm.builder.buildCall(
4213 ty.toLlvm(self.builder),
4214 callee.toLlvm(self),
4215 llvm_args.ptr,
4216 @intCast(llvm_args.len),
4217 switch (ret_ty) {
4218 .void => "",
4219 else => instruction.llvmName(self),
4220 },
4221 );
4222 llvm_instruction.setInstructionCallConv(@enumFromInt(@intFromEnum(call_conv)));
4223 llvm_instruction.setTailCallKind(switch (kind) {
4224 .normal, .fast => .None,
4225 .musttail, .musttail_fast => .MustTail,
4226 .notail, .notail_fast => .NoTail,
4227 .tail, .tail_fast => .Tail,
4228 });
4229 for (0.., function_attributes.slice(self.builder)) |index, attributes| {
4230 const attribute_index = @as(llvm.AttributeIndex, @intCast(index)) -% 1;
4231 for (attributes.slice(self.builder)) |attribute| llvm_instruction.addCallSiteAttribute(
4232 attribute_index,
4233 attribute.toLlvm(self.builder),
4234 );
4235 }
4236 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
4237 }
4238 return instruction.toValue();
4239 }
4240
31654241 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
31664242 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
31674243 const instruction = try self.addInst(name, .{
......@@ -3246,8 +4322,17 @@ pub const WipFunction = struct {
32464322 const value = @field(extra, field.name);
32474323 wip_extra.items[wip_extra.index] = switch (field.type) {
32484324 u32 => value,
3249 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3250 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
4325 Alignment,
4326 AtomicOrdering,
4327 Block.Index,
4328 FunctionAttributes,
4329 Type,
4330 Value,
4331 => @intFromEnum(value),
4332 MemoryAccessInfo,
4333 Instruction.Alloca.Info,
4334 Instruction.Call.Info,
4335 => @bitCast(value),
32514336 else => @compileError("bad field type: " ++ @typeName(field.type)),
32524337 };
32534338 wip_extra.index += 1;
......@@ -3256,13 +4341,14 @@ pub const WipFunction = struct {
32564341 }
32574342
32584343 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
3259 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) @compileError("use appendValues");
4344 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value)
4345 @compileError("use appendMappedValues");
32604346 const data: []const u32 = @ptrCast(slice);
32614347 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
32624348 wip_extra.index += @intCast(data.len);
32634349 }
32644350
3265 fn appendValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
4351 fn appendMappedValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
32664352 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
32674353 extra.* = @intFromEnum(ctx.map(val));
32684354 wip_extra.index += @intCast(vals.len);
......@@ -3494,6 +4580,26 @@ pub const WipFunction = struct {
34944580 .@"else" = extra.@"else",
34954581 });
34964582 },
4583 .call,
4584 .@"call fast",
4585 .@"musttail call",
4586 .@"musttail call fast",
4587 .@"notail call",
4588 .@"notail call fast",
4589 .@"tail call",
4590 .@"tail call fast",
4591 => {
4592 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
4593 const args = extra.trail.next(extra.data.args_len, Value, self);
4594 instruction.data = wip_extra.addExtra(Instruction.Call{
4595 .info = extra.data.info,
4596 .attributes = extra.data.attributes,
4597 .ty = extra.data.ty,
4598 .callee = instructions.map(extra.data.callee),
4599 .args_len = extra.data.args_len,
4600 });
4601 wip_extra.appendMappedValues(args, instructions);
4602 },
34974603 .extractvalue => {
34984604 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
34994605 const indices = extra.trail.next(extra.data.indices_len, u32, self);
......@@ -3517,7 +4623,7 @@ pub const WipFunction = struct {
35174623 .base = instructions.map(extra.data.base),
35184624 .indices_len = extra.data.indices_len,
35194625 });
3520 wip_extra.appendValues(indices, instructions);
4626 wip_extra.appendMappedValues(indices, instructions);
35214627 },
35224628 .insertelement => {
35234629 const extra = self.extraData(Instruction.InsertElement, instruction.data);
......@@ -3559,7 +4665,7 @@ pub const WipFunction = struct {
35594665 instruction.data = wip_extra.addExtra(Instruction.Phi{
35604666 .type = extra.data.type,
35614667 });
3562 wip_extra.appendValues(incoming_vals, instructions);
4668 wip_extra.appendMappedValues(incoming_vals, instructions);
35634669 wip_extra.appendSlice(incoming_blocks);
35644670 },
35654671 .select,
......@@ -3932,8 +5038,17 @@ pub const WipFunction = struct {
39325038 const value = @field(extra, field.name);
39335039 self.extra.appendAssumeCapacity(switch (field.type) {
39345040 u32 => value,
3935 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3936 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
5041 Alignment,
5042 AtomicOrdering,
5043 Block.Index,
5044 FunctionAttributes,
5045 Type,
5046 Value,
5047 => @intFromEnum(value),
5048 MemoryAccessInfo,
5049 Instruction.Alloca.Info,
5050 Instruction.Call.Info,
5051 => @bitCast(value),
39375052 else => @compileError("bad field type: " ++ @typeName(field.type)),
39385053 });
39395054 }
......@@ -3971,8 +5086,17 @@ pub const WipFunction = struct {
39715086 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
39725087 @field(result, field.name) = switch (field.type) {
39735088 u32 => value,
3974 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
3975 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
5089 Alignment,
5090 AtomicOrdering,
5091 Block.Index,
5092 FunctionAttributes,
5093 Type,
5094 Value,
5095 => @enumFromInt(value),
5096 MemoryAccessInfo,
5097 Instruction.Alloca.Info,
5098 Instruction.Call.Info,
5099 => @bitCast(value),
39765100 else => @compileError("bad field type: " ++ @typeName(field.type)),
39775101 };
39785102 return .{
......@@ -4294,7 +5418,7 @@ pub const Constant = enum(u32) {
42945418 .string,
42955419 .string_null,
42965420 => builder.arrayTypeAssumeCapacity(
4297 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +
5421 @as(String, @enumFromInt(item.data)).slice(builder).?.len +
42985422 @intFromBool(item.tag == .string_null),
42995423 .i8,
43005424 ),
......@@ -4821,8 +5945,8 @@ pub fn init(options: Options) InitError!Builder {
48215945 .target_triple = .none,
48225946
48235947 .string_map = .{},
4824 .string_bytes = .{},
48255948 .string_indices = .{},
5949 .string_bytes = .{},
48265950
48275951 .types = .{},
48285952 .next_unnamed_type = @enumFromInt(0),
......@@ -4831,6 +5955,11 @@ pub fn init(options: Options) InitError!Builder {
48315955 .type_items = .{},
48325956 .type_extra = .{},
48335957
5958 .attributes = .{},
5959 .attributes_map = .{},
5960 .attributes_indices = .{},
5961 .attributes_extra = .{},
5962
48345963 .globals = .{},
48355964 .next_unnamed_global = @enumFromInt(0),
48365965 .next_replaced_global = .none,
......@@ -4844,7 +5973,18 @@ pub fn init(options: Options) InitError!Builder {
48445973 .constant_extra = .{},
48455974 .constant_limbs = .{},
48465975 };
4847 if (self.useLibLlvm()) self.llvm = .{ .context = llvm.Context.create() };
5976 if (self.useLibLlvm()) self.llvm = .{
5977 .context = llvm.Context.create(),
5978 .module = null,
5979 .target = null,
5980 .di_builder = null,
5981 .di_compile_unit = null,
5982 .attribute_kind_ids = null,
5983 .attributes = .{},
5984 .types = .{},
5985 .globals = .{},
5986 .constants = .{},
5987 };
48485988 errdefer self.deinit();
48495989
48505990 try self.string_indices.append(self.gpa, 0);
......@@ -4853,7 +5993,7 @@ pub fn init(options: Options) InitError!Builder {
48535993 if (options.name.len > 0) self.source_filename = try self.string(options.name);
48545994 self.initializeLLVMTarget(options.target.cpu.arch);
48555995 if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(
4856 (self.source_filename.toSlice(&self) orelse "").ptr,
5996 (self.source_filename.slice(&self) orelse "").ptr,
48575997 self.llvm.context,
48585998 );
48595999
......@@ -4864,20 +6004,20 @@ pub fn init(options: Options) InitError!Builder {
48646004 var error_message: [*:0]const u8 = undefined;
48656005 var target: *llvm.Target = undefined;
48666006 if (llvm.Target.getFromTriple(
4867 self.target_triple.toSlice(&self).?,
6007 self.target_triple.slice(&self).?,
48686008 &target,
48696009 &error_message,
48706010 ).toBool()) {
48716011 defer llvm.disposeMessage(error_message);
48726012
48736013 log.err("LLVM failed to parse '{s}': {s}", .{
4874 self.target_triple.toSlice(&self).?,
6014 self.target_triple.slice(&self).?,
48756015 error_message,
48766016 });
48776017 return InitError.InvalidLlvmTriple;
48786018 }
48796019 self.llvm.target = target;
4880 self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?);
6020 self.llvm.module.?.setTarget(self.target_triple.slice(&self).?);
48816021 }
48826022 }
48836023
......@@ -4902,6 +6042,16 @@ pub fn init(options: Options) InitError!Builder {
49026042 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
49036043 }
49046044
6045 {
6046 if (self.useLibLlvm()) {
6047 self.llvm.attribute_kind_ids = try self.gpa.create([Attribute.Kind.len]c_uint);
6048 @memset(self.llvm.attribute_kind_ids.?, 0);
6049 }
6050 try self.attributes_indices.append(self.gpa, 0);
6051 assert(try self.attrs(&.{}) == .none);
6052 assert(try self.fnAttrs(&.{}) == .none);
6053 }
6054
49056055 assert(try self.intConst(.i1, 0) == .false);
49066056 assert(try self.intConst(.i1, 1) == .true);
49076057 assert(try self.noneConst(.token) == .none);
......@@ -4911,8 +6061,8 @@ pub fn init(options: Options) InitError!Builder {
49116061
49126062pub fn deinit(self: *Builder) void {
49136063 self.string_map.deinit(self.gpa);
4914 self.string_bytes.deinit(self.gpa);
49156064 self.string_indices.deinit(self.gpa);
6065 self.string_bytes.deinit(self.gpa);
49166066
49176067 self.types.deinit(self.gpa);
49186068 self.next_unique_type_id.deinit(self.gpa);
......@@ -4920,6 +6070,11 @@ pub fn deinit(self: *Builder) void {
49206070 self.type_items.deinit(self.gpa);
49216071 self.type_extra.deinit(self.gpa);
49226072
6073 self.attributes.deinit(self.gpa);
6074 self.attributes_map.deinit(self.gpa);
6075 self.attributes_indices.deinit(self.gpa);
6076 self.attributes_extra.deinit(self.gpa);
6077
49236078 self.globals.deinit(self.gpa);
49246079 self.next_unique_global_id.deinit(self.gpa);
49256080 self.aliases.deinit(self.gpa);
......@@ -4936,6 +6091,8 @@ pub fn deinit(self: *Builder) void {
49366091 self.llvm.constants.deinit(self.gpa);
49376092 self.llvm.globals.deinit(self.gpa);
49386093 self.llvm.types.deinit(self.gpa);
6094 self.llvm.attributes.deinit(self.gpa);
6095 if (self.llvm.attribute_kind_ids) |attribute_kind_ids| self.gpa.destroy(attribute_kind_ids);
49396096 if (self.llvm.di_builder) |di_builder| di_builder.dispose();
49406097 if (self.llvm.module) |module| module.dispose();
49416098 self.llvm.context.dispose();
......@@ -5230,7 +6387,7 @@ pub fn structType(
52306387
52316388pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
52326389 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5233 if (name.toSlice(self)) |id| {
6390 if (name.slice(self)) |id| {
52346391 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
52356392 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
52366393 }
......@@ -5268,6 +6425,99 @@ pub fn namedTypeSetBody(
52686425 }
52696426}
52706427
6428pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Index {
6429 try self.attributes.ensureUnusedCapacity(self.gpa, 1);
6430 if (self.useLibLlvm()) try self.llvm.attributes.ensureUnusedCapacity(self.gpa, 1);
6431
6432 const gop = self.attributes.getOrPutAssumeCapacity(attribute.toStorage());
6433 if (!gop.found_existing) {
6434 gop.value_ptr.* = {};
6435 if (self.useLibLlvm()) self.llvm.attributes.appendAssumeCapacity(switch (attribute) {
6436 else => llvm_attr: {
6437 const kind_id = &self.llvm.attribute_kind_ids.?[@intFromEnum(attribute)];
6438 if (kind_id.* == 0) {
6439 const name = @tagName(attribute);
6440 kind_id.* = llvm.getEnumAttributeKindForName(name.ptr, name.len);
6441 assert(kind_id.* != 0);
6442 }
6443 break :llvm_attr switch (attribute) {
6444 else => switch (attribute) {
6445 inline else => |value| self.llvm.context.createEnumAttribute(
6446 kind_id.*,
6447 switch (@TypeOf(value)) {
6448 void => 0,
6449 u32 => value,
6450 Attribute.FpClass,
6451 Attribute.AllocKind,
6452 Attribute.Memory,
6453 => @as(u32, @bitCast(value)),
6454 Alignment => value.toByteUnits() orelse 0,
6455 Attribute.AllocSize,
6456 Attribute.VScaleRange,
6457 => @bitCast(value.toLlvm()),
6458 Attribute.UwTable => @intFromEnum(value),
6459 else => @compileError(
6460 "bad payload type: " ++ @typeName(@TypeOf(value)),
6461 ),
6462 },
6463 ),
6464 .byval,
6465 .byref,
6466 .preallocated,
6467 .inalloca,
6468 .sret,
6469 .elementtype,
6470 .string,
6471 .none,
6472 => unreachable,
6473 },
6474 .byval,
6475 .byref,
6476 .preallocated,
6477 .inalloca,
6478 .sret,
6479 .elementtype,
6480 => |ty| self.llvm.context.createTypeAttribute(kind_id.*, ty.toLlvm(self)),
6481 .string, .none => unreachable,
6482 };
6483 },
6484 .string => |string_attr| llvm_attr: {
6485 const kind = string_attr.kind.slice(self).?;
6486 const value = string_attr.value.slice(self).?;
6487 break :llvm_attr self.llvm.context.createStringAttribute(
6488 kind.ptr,
6489 @intCast(kind.len),
6490 value.ptr,
6491 @intCast(value.len),
6492 );
6493 },
6494 .none => unreachable,
6495 });
6496 }
6497 return @enumFromInt(gop.index);
6498}
6499
6500pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attributes {
6501 std.sort.heap(Attribute.Index, attributes, self, struct {
6502 pub fn lessThan(builder: *const Builder, lhs: Attribute.Index, rhs: Attribute.Index) bool {
6503 const lhs_kind = lhs.getKind(builder);
6504 const rhs_kind = rhs.getKind(builder);
6505 assert(lhs_kind != rhs_kind);
6506 return @intFromEnum(lhs_kind) < @intFromEnum(rhs_kind);
6507 }
6508 }.lessThan);
6509 return @enumFromInt(try self.attrGeneric(@ptrCast(attributes)));
6510}
6511
6512pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes {
6513 return @enumFromInt(try self.attrGeneric(@ptrCast(
6514 fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last|
6515 last + 1
6516 else
6517 0],
6518 )));
6519}
6520
52716521pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
52726522 assert(!name.isAnon());
52736523 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
......@@ -5295,7 +6545,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
52956545
52966546 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
52976547 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
5298 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
6548 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
52996549 unique_gop.value_ptr.* += 1;
53006550 }
53016551}
......@@ -5309,8 +6559,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta
53096559 switch (@typeInfo(@TypeOf(value))) {
53106560 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
53116561 .ComptimeInt => std.math.big.int.calcLimbLen(value),
5312 else => @compileError("intConst expected an integral value, got " ++
5313 @typeName(@TypeOf(value))),
6562 else => @compileError(
6563 "intConst expected an integral value, got " ++ @typeName(@TypeOf(value)),
6564 ),
53146565 }
53156566 ]std.math.big.Limb = undefined;
53166567 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
......@@ -5770,7 +7021,7 @@ pub fn printUnbuffered(
57707021 \\; ModuleID = '{s}'
57717022 \\source_filename = {"}
57727023 \\
5773 , .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) });
7024 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
57747025 if (self.data_layout != .none) try writer.print(
57757026 \\target datalayout = {"}
57767027 \\
......@@ -5780,11 +7031,13 @@ pub fn printUnbuffered(
57807031 \\
57817032 , .{self.target_triple.fmt(self)});
57827033 try writer.writeByte('\n');
7034
57837035 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
57847036 \\%{} = type {}
57857037 \\
57867038 , .{ id.fmt(self), ty.fmt(self) });
57877039 try writer.writeByte('\n');
7040
57887041 for (self.variables.items) |variable| {
57897042 if (variable.global.getReplacement(self) != .none) continue;
57907043 const global = variable.global.ptrConst(self);
......@@ -5808,28 +7061,42 @@ pub fn printUnbuffered(
58087061 });
58097062 }
58107063 try writer.writeByte('\n');
7064
7065 var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{};
7066 defer attribute_groups.deinit(self.gpa);
58117067 for (0.., self.functions.items) |function_i, function| {
58127068 const function_index: Function.Index = @enumFromInt(function_i);
58137069 if (function.global.getReplacement(self) != .none) continue;
58147070 const global = function.global.ptrConst(self);
58157071 const params_len = global.type.functionParameters(self).len;
7072 const function_attributes = function.attributes.func(self);
7073 if (function_attributes != .none) try writer.print(
7074 \\; Function Attrs:{}
7075 \\
7076 , .{function_attributes.fmt(self)});
58167077 try writer.print(
5817 \\{s}{}{}{}{} {} {}(
7078 \\{s}{}{}{}{}{}{"} {} {}(
58187079 , .{
58197080 if (function.instructions.len > 0) "define" else "declare",
58207081 global.linkage,
58217082 global.preemption,
58227083 global.visibility,
58237084 global.dll_storage_class,
7085 function.call_conv,
7086 function.attributes.ret(self).fmt(self),
58247087 global.type.functionReturn(self).fmt(self),
58257088 function.global.fmt(self),
58267089 });
58277090 for (0..params_len) |arg| {
58287091 if (arg > 0) try writer.writeAll(", ");
7092 try writer.print(
7093 \\{%}{"}
7094 , .{
7095 global.type.functionParameters(self)[arg].fmt(self),
7096 function.attributes.param(arg, self).fmt(self),
7097 });
58297098 if (function.instructions.len > 0)
5830 try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
5831 else
5832 try writer.print("{%}", .{global.type.functionParameters(self)[arg].fmt(self)});
7099 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
58337100 }
58347101 switch (global.type.functionKind(self)) {
58357102 .normal => {},
......@@ -5838,7 +7105,11 @@ pub fn printUnbuffered(
58387105 try writer.writeAll("...");
58397106 },
58407107 }
5841 try writer.print("){}{}", .{ global.unnamed_addr, function.alignment });
7108 try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space });
7109 if (function_attributes != .none) try writer.print(" #{d}", .{
7110 (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
7111 });
7112 try writer.print("{}", .{function.alignment});
58427113 if (function.instructions.len > 0) {
58437114 var block_incoming_len: u32 = undefined;
58447115 try writer.writeAll(" {\n");
......@@ -5992,6 +7263,48 @@ pub fn printUnbuffered(
59927263 extra.@"else".toInst(&function).fmt(function_index, self),
59937264 });
59947265 },
7266 .call,
7267 .@"call fast",
7268 .@"musttail call",
7269 .@"musttail call fast",
7270 .@"notail call",
7271 .@"notail call fast",
7272 .@"tail call",
7273 .@"tail call fast",
7274 => |tag| {
7275 var extra =
7276 function.extraDataTrail(Function.Instruction.Call, instruction.data);
7277 const args = extra.trail.next(extra.data.args_len, Value, &function);
7278 try writer.writeAll(" ");
7279 const ret_ty = extra.data.ty.functionReturn(self);
7280 switch (ret_ty) {
7281 .void => {},
7282 else => try writer.print("%{} = ", .{
7283 instruction_index.name(&function).fmt(self),
7284 }),
7285 .none => unreachable,
7286 }
7287 try writer.print("{s}{}{}{} {%} {}(", .{
7288 @tagName(tag),
7289 extra.data.info.call_conv,
7290 extra.data.attributes.ret(self).fmt(self),
7291 extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
7292 switch (extra.data.ty.functionKind(self)) {
7293 .normal => ret_ty,
7294 .vararg => extra.data.ty,
7295 }.fmt(self),
7296 extra.data.callee.fmt(function_index, self),
7297 });
7298 for (0.., args) |arg_index, arg| {
7299 if (arg_index > 0) try writer.writeAll(", ");
7300 try writer.print("{%}{} {}", .{
7301 arg.typeOf(function_index, self).fmt(self),
7302 extra.data.attributes.param(arg_index, self).fmt(self),
7303 arg.fmt(function_index, self),
7304 });
7305 }
7306 try writer.print("){}\n", .{extra.data.attributes.func(self).fmt(self)});
7307 },
59957308 .extractelement => |tag| {
59967309 const extra =
59977310 function.extraData(Function.Instruction.ExtractElement, instruction.data);
......@@ -6218,6 +7531,12 @@ pub fn printUnbuffered(
62187531 }
62197532 try writer.writeAll("\n\n");
62207533 }
7534
7535 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
7536 try writer.print(
7537 \\attribute #{d} = {{{"} }}
7538 \\
7539 , .{ attribute_group_index, attribute_group.fmt(self) });
62217540}
62227541
62237542pub inline fn useLibLlvm(self: *const Builder) bool {
......@@ -6238,7 +7557,7 @@ fn isValidIdentifier(id: []const u8) bool {
62387557fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {
62397558 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);
62407559 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
6241 if (name.toSlice(self)) |id| {
7560 if (name.slice(self)) |id| {
62427561 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
62437562 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
62447563 }
......@@ -6528,14 +7847,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
65287847 const result: Type = @enumFromInt(gop.index);
65297848 type_gop.value_ptr.* = result;
65307849 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
6531 self.llvm.context.structCreateNamed(id.toSlice(self) orelse ""),
7850 self.llvm.context.structCreateNamed(id.slice(self) orelse ""),
65327851 );
65337852 return result;
65347853 }
65357854
65367855 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
65377856 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
6538 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
7857 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
65397858 unique_gop.value_ptr.* += 1;
65407859 }
65417860}
......@@ -6636,6 +7955,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI
66367955 return self.typeExtraDataTrail(T, index).data;
66377956}
66387957
7958fn attrGeneric(self: *Builder, data: []const u32) Allocator.Error!u32 {
7959 try self.attributes_map.ensureUnusedCapacity(self.gpa, 1);
7960 try self.attributes_indices.ensureUnusedCapacity(self.gpa, 1);
7961 try self.attributes_extra.ensureUnusedCapacity(self.gpa, data.len);
7962
7963 const Adapter = struct {
7964 builder: *const Builder,
7965 pub fn hash(_: @This(), key: []const u32) u32 {
7966 return @truncate(std.hash.Wyhash.hash(1, std.mem.sliceAsBytes(key)));
7967 }
7968 pub fn eql(ctx: @This(), lhs_key: []const u32, _: void, rhs_index: usize) bool {
7969 const start = ctx.builder.attributes_indices.items[rhs_index];
7970 const end = ctx.builder.attributes_indices.items[rhs_index + 1];
7971 return std.mem.eql(u32, lhs_key, ctx.builder.attributes_extra.items[start..end]);
7972 }
7973 };
7974 const gop = self.attributes_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
7975 if (!gop.found_existing) {
7976 self.attributes_extra.appendSliceAssumeCapacity(data);
7977 self.attributes_indices.appendAssumeCapacity(@intCast(self.attributes_extra.items.len));
7978 }
7979 return @intCast(gop.index);
7980}
7981
66397982fn bigIntConstAssumeCapacity(
66407983 self: *Builder,
66417984 ty: Type,
......@@ -7073,7 +8416,7 @@ fn arrayConstAssumeCapacity(
70738416}
70748417
70758418fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7076 const slice = val.toSlice(self).?;
8419 const slice = val.slice(self).?;
70778420 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
70788421 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
70798422 const result = self.getOrPutConstantNoExtraAssumeCapacity(
......@@ -7086,7 +8429,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
70868429}
70878430
70888431fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
7089 const slice = val.toSlice(self).?;
8432 const slice = val.slice(self).?;
70908433 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
70918434 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
70928435 const result = self.getOrPutConstantNoExtraAssumeCapacity(
src/codegen/llvm/bindings.zig+32-6
......@@ -26,10 +26,13 @@ pub const Context = opaque {
2626 extern fn LLVMContextDispose(C: *Context) void;
2727
2828 pub const createEnumAttribute = LLVMCreateEnumAttribute;
29 extern fn LLVMCreateEnumAttribute(*Context, KindID: c_uint, Val: u64) *Attribute;
29 extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) *Attribute;
30
31 pub const createTypeAttribute = LLVMCreateTypeAttribute;
32 extern fn LLVMCreateTypeAttribute(C: *Context, KindID: c_uint, Type: *Type) *Attribute;
3033
3134 pub const createStringAttribute = LLVMCreateStringAttribute;
32 extern fn LLVMCreateStringAttribute(*Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *Attribute;
35 extern fn LLVMCreateStringAttribute(C: *Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *Attribute;
3336
3437 pub const pointerType = LLVMPointerTypeInContext;
3538 extern fn LLVMPointerTypeInContext(C: *Context, AddressSpace: c_uint) *Type;
......@@ -309,12 +312,18 @@ pub const Value = opaque {
309312 pub const setAlignment = LLVMSetAlignment;
310313 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
311314
312 pub const getFunctionCallConv = LLVMGetFunctionCallConv;
313 extern fn LLVMGetFunctionCallConv(Fn: *Value) CallConv;
314
315315 pub const setFunctionCallConv = LLVMSetFunctionCallConv;
316316 extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void;
317317
318 pub const setInstructionCallConv = LLVMSetInstructionCallConv;
319 extern fn LLVMSetInstructionCallConv(Instr: *Value, CC: CallConv) void;
320
321 pub const setTailCallKind = ZigLLVMSetTailCallKind;
322 extern fn ZigLLVMSetTailCallKind(CallInst: *Value, TailCallKind: TailCallKind) void;
323
324 pub const addCallSiteAttribute = LLVMAddCallSiteAttribute;
325 extern fn LLVMAddCallSiteAttribute(C: *Value, Idx: AttributeIndex, A: *Attribute) void;
326
318327 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;
319328 extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;
320329
......@@ -642,7 +651,17 @@ pub const Builder = opaque {
642651 Name: [*:0]const u8,
643652 ) *Value;
644653
645 pub const buildCall = ZigLLVMBuildCall;
654 pub const buildCall = LLVMBuildCall2;
655 extern fn LLVMBuildCall2(
656 *Builder,
657 *Type,
658 Fn: *Value,
659 Args: [*]const *Value,
660 NumArgs: c_uint,
661 Name: [*:0]const u8,
662 ) *Value;
663
664 pub const buildCallOld = ZigLLVMBuildCall;
646665 extern fn ZigLLVMBuildCall(
647666 *Builder,
648667 *Type,
......@@ -1605,6 +1624,13 @@ pub const CallAttr = enum(c_int) {
16051624 AlwaysInline,
16061625};
16071626
1627pub const TailCallKind = enum(c_uint) {
1628 None,
1629 Tail,
1630 MustTail,
1631 NoTail,
1632};
1633
16081634pub const DLLStorageClass = enum(c_uint) {
16091635 Default,
16101636 DLLImport,
src/zig_llvm.cpp+4-6
......@@ -453,6 +453,10 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
453453 return wrap(call_inst);
454454}
455455
456ZIG_EXTERN_C void ZigLLVMSetTailCallKind(LLVMValueRef Call, CallInst::TailCallKind TailCallKind) {
457 unwrap<CallInst>(Call)->setTailCallKind(TailCallKind);
458}
459
456460void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
457461 if (isa<Function>(unwrap(Val))) {
458462 unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
......@@ -461,7 +465,6 @@ void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef
461465 }
462466}
463467
464
465468LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
466469 LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
467470{
......@@ -1116,11 +1119,6 @@ void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const ch
11161119 func->addFnAttr(attr_name, attr_value);
11171120}
11181121
1119void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) {
1120 Function *func = unwrap<Function>(fn_ref);
1121 func->addFnAttr(Attribute::Cold);
1122}
1123
11241122void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
11251123 cl::ParseCommandLineOptions(argc, argv);
11261124}