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 {...@@ -359,7 +359,7 @@ const DataLayoutBuilder = struct {
359 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.359 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
360 // Other symbols get a `_` prefix.360 // Other symbols get a `_` prefix.
361 .coff => switch (self.target.os.tag) {361 .coff => switch (self.target.os.tag) {
362 .windows => switch (self.target.cpu.arch) {362 .uefi, .windows => switch (self.target.cpu.arch) {
363 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual363 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
364 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,364 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
365 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`365 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
...@@ -794,7 +794,7 @@ pub const Object = struct {...@@ -794,7 +794,7 @@ pub const Object = struct {
794 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(794 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
795 DW.LANG.C99,795 DW.LANG.C99,
796 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),796 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
797 producer.toSlice(&builder).?,797 producer.slice(&builder).?,
798 options.optimize_mode != .Debug,798 options.optimize_mode != .Debug,
799 "", // flags799 "", // flags
800 0, // runtime version800 0, // runtime version
...@@ -830,7 +830,7 @@ pub const Object = struct {...@@ -830,7 +830,7 @@ pub const Object = struct {
830830
831 target_machine = llvm.TargetMachine.create(831 target_machine = llvm.TargetMachine.create(
832 builder.llvm.target.?,832 builder.llvm.target.?,
833 builder.target_triple.toSlice(&builder).?,833 builder.target_triple.slice(&builder).?,
834 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,834 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
835 options.llvm_cpu_features,835 options.llvm_cpu_features,
836 opt_level,836 opt_level,
...@@ -861,7 +861,7 @@ pub const Object = struct {...@@ -861,7 +861,7 @@ pub const Object = struct {
861 defer llvm.disposeMessage(rep);861 defer llvm.disposeMessage(rep);
862 std.testing.expectEqualStrings(862 std.testing.expectEqualStrings(
863 std.mem.span(rep),863 std.mem.span(rep),
864 builder.data_layout.toSlice(&builder).?,864 builder.data_layout.slice(&builder).?,
865 ) catch unreachable;865 ) catch unreachable;
866 }866 }
867 }867 }
...@@ -963,7 +963,7 @@ pub const Object = struct {...@@ -963,7 +963,7 @@ pub const Object = struct {
963963
964 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{964 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
965 global_index.toConst(),965 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),
967 });967 });
968 }968 }
969969
...@@ -1223,6 +1223,7 @@ pub const Object = struct {...@@ -1223,6 +1223,7 @@ pub const Object = struct {
1223 const func = mod.funcInfo(func_index);1223 const func = mod.funcInfo(func_index);
1224 const decl_index = func.owner_decl;1224 const decl_index = func.owner_decl;
1225 const decl = mod.declPtr(decl_index);1225 const decl = mod.declPtr(decl_index);
1226 const fn_info = mod.typeToFunc(decl.ty).?;
1226 const target = mod.getTarget();1227 const target = mod.getTarget();
1227 const ip = &mod.intern_pool;1228 const ip = &mod.intern_pool;
12281229
...@@ -1237,28 +1238,43 @@ pub const Object = struct {...@@ -1237,28 +1238,43 @@ pub const Object = struct {
1237 const global = function.ptrConst(&o.builder).global;1238 const global = function.ptrConst(&o.builder).global;
1238 const llvm_func = global.toLlvm(&o.builder);1239 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
1240 if (func.analysis(ip).is_noinline) {1244 if (func.analysis(ip).is_noinline) {
1245 try attributes.addFnAttr(.@"noinline", &o.builder);
1241 o.addFnAttr(llvm_func, "noinline");1246 o.addFnAttr(llvm_func, "noinline");
1242 } else {1247 } else {
1248 _ = try attributes.removeFnAttr(.@"noinline");
1243 Object.removeFnAttr(llvm_func, "noinline");1249 Object.removeFnAttr(llvm_func, "noinline");
1244 }1250 }
12451251
1246 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {1252 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);
1247 o.addFnAttrInt(llvm_func, "alignstack", alignment);1255 o.addFnAttrInt(llvm_func, "alignstack", alignment);
1248 o.addFnAttr(llvm_func, "noinline");1256 o.addFnAttr(llvm_func, "noinline");
1249 } else {1257 } else {
1258 _ = try attributes.removeFnAttr(.alignstack);
1250 Object.removeFnAttr(llvm_func, "alignstack");1259 Object.removeFnAttr(llvm_func, "alignstack");
1251 }1260 }
12521261
1253 if (func.analysis(ip).is_cold) {1262 if (func.analysis(ip).is_cold) {
1263 try attributes.addFnAttr(.cold, &o.builder);
1254 o.addFnAttr(llvm_func, "cold");1264 o.addFnAttr(llvm_func, "cold");
1255 } else {1265 } else {
1266 _ = try attributes.removeFnAttr(.cold);
1256 Object.removeFnAttr(llvm_func, "cold");1267 Object.removeFnAttr(llvm_func, "cold");
1257 }1268 }
12581269
1259 // TODO: disable this if safety is off for the function scope1270 // TODO: disable this if safety is off for the function scope
1260 const ssp_buf_size = mod.comp.bin_file.options.stack_protector;1271 const ssp_buf_size = mod.comp.bin_file.options.stack_protector;
1261 if (ssp_buf_size != 0) {1272 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);
1262 var buf: [12]u8 = undefined;1278 var buf: [12]u8 = undefined;
1263 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;1279 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
1264 o.addFnAttr(llvm_func, "sspstrong");1280 o.addFnAttr(llvm_func, "sspstrong");
...@@ -1267,8 +1283,16 @@ pub const Object = struct {...@@ -1267,8 +1283,16 @@ pub const Object = struct {
12671283
1268 // TODO: disable this if safety is off for the function scope1284 // TODO: disable this if safety is off for the function scope
1269 if (mod.comp.bin_file.options.stack_check) {1285 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);
1270 o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");1290 o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");
1271 } else if (target.os.tag == .uefi) {1291 } 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);
1272 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");1296 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
1273 }1297 }
12741298
...@@ -1286,18 +1310,22 @@ pub const Object = struct {...@@ -1286,18 +1310,22 @@ pub const Object = struct {
1286 var llvm_arg_i: u32 = 0;1310 var llvm_arg_i: u32 = 0;
12871311
1288 // This gets the LLVM values from the function and stores them in `dg.args`.1312 // This gets the LLVM values from the function and stores them in `dg.args`.
1289 const fn_info = mod.typeToFunc(decl.ty).?;
1290 const sret = firstParamSRet(fn_info, mod);1313 const sret = firstParamSRet(fn_info, mod);
1291 const ret_ptr: Builder.Value = if (sret) param: {1314 const ret_ptr: Builder.Value = if (sret) param: {
1292 const param = wip.arg(llvm_arg_i);1315 const param = wip.arg(llvm_arg_i);
1293 llvm_arg_i += 1;1316 llvm_arg_i += 1;
1294 break :param param;1317 break :param param;
1295 } else .none;1318 } else .none;
1296 const gpa = o.gpa;
12971319
1298 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {1320 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
1299 .signed => o.addAttr(llvm_func, 0, "signext"),1321 .signed => {
1300 .unsigned => o.addAttr(llvm_func, 0, "zeroext"),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 },
1301 };1329 };
13021330
1303 const err_return_tracing = fn_info.return_type.toType().isError(mod) and1331 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
...@@ -1312,6 +1340,7 @@ pub const Object = struct {...@@ -1312,6 +1340,7 @@ pub const Object = struct {
1312 // This is the list of args we will use that correspond directly to the AIR arg1340 // This is the list of args we will use that correspond directly to the AIR arg
1313 // instructions. Depending on the calling convention, this list is not necessarily1341 // instructions. Depending on the calling convention, this list is not necessarily
1314 // a bijection with the actual LLVM parameters of the function.1342 // a bijection with the actual LLVM parameters of the function.
1343 const gpa = o.gpa;
1315 var args: std.ArrayListUnmanaged(Builder.Value) = .{};1344 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
1316 defer args.deinit(gpa);1345 defer args.deinit(gpa);
13171346
...@@ -1337,7 +1366,7 @@ pub const Object = struct {...@@ -1337,7 +1366,7 @@ pub const Object = struct {
1337 } else {1366 } else {
1338 args.appendAssumeCapacity(param);1367 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);
1341 }1370 }
1342 llvm_arg_i += 1;1371 llvm_arg_i += 1;
1343 },1372 },
...@@ -1347,7 +1376,7 @@ pub const Object = struct {...@@ -1347,7 +1376,7 @@ pub const Object = struct {
1347 const param = wip.arg(llvm_arg_i);1376 const param = wip.arg(llvm_arg_i);
1348 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1377 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);
1351 llvm_arg_i += 1;1380 llvm_arg_i += 1;
13521381
1353 if (isByRef(param_ty, mod)) {1382 if (isByRef(param_ty, mod)) {
...@@ -1362,7 +1391,8 @@ pub const Object = struct {...@@ -1362,7 +1391,8 @@ pub const Object = struct {
1362 const param = wip.arg(llvm_arg_i);1391 const param = wip.arg(llvm_arg_i);
1363 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1392 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");
1366 llvm_arg_i += 1;1396 llvm_arg_i += 1;
13671397
1368 if (isByRef(param_ty, mod)) {1398 if (isByRef(param_ty, mod)) {
...@@ -1398,21 +1428,28 @@ pub const Object = struct {...@@ -1398,21 +1428,28 @@ pub const Object = struct {
13981428
1399 if (math.cast(u5, it.zig_index - 1)) |i| {1429 if (math.cast(u5, it.zig_index - 1)) |i| {
1400 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {1430 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");
1402 }1433 }
1403 }1434 }
1404 if (param_ty.zigTypeTag(mod) != .Optional) {1435 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");
1406 }1438 }
1407 if (ptr_info.flags.is_const) {1439 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");
1409 }1442 }
1410 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse1443 const elem_align = Builder.Alignment.fromByteUnits(
1411 @max(ptr_info.child.toType().abiAlignment(mod), 1);1444 ptr_info.flags.alignment.toByteUnitsOptional() orelse
1412 o.addArgAttrInt(llvm_func, @intCast(llvm_arg_i), "align", elem_align);1445 @max(ptr_info.child.toType().abiAlignment(mod), 1),
1413 const ptr_param = wip.arg(llvm_arg_i + 0);1446 );
1414 const len_param = wip.arg(llvm_arg_i + 1);1447 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1415 llvm_arg_i += 2;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
1417 const slice_llvm_ty = try o.lowerType(param_ty);1454 const slice_llvm_ty = try o.lowerType(param_ty);
1418 args.appendAssumeCapacity(1455 args.appendAssumeCapacity(
...@@ -1482,6 +1519,8 @@ pub const Object = struct {...@@ -1482,6 +1519,8 @@ pub const Object = struct {
1482 }1519 }
1483 }1520 }
14841521
1522 function.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
1523
1485 var di_file: ?*llvm.DIFile = null;1524 var di_file: ?*llvm.DIFile = null;
1486 var di_scope: ?*llvm.DIScope = null;1525 var di_scope: ?*llvm.DIScope = null;
14871526
...@@ -1618,7 +1657,7 @@ pub const Object = struct {...@@ -1618,7 +1657,7 @@ pub const Object = struct {
1618 llvm_global.setDLLStorageClass(.Default);1657 llvm_global.setDLLStorageClass(.Default);
1619 }1658 }
1620 if (self.di_map.get(decl)) |di_node| {1659 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).?;
1622 if (try decl.isFunction(mod)) {1661 if (try decl.isFunction(mod)) {
1623 const di_func: *llvm.DISubprogram = @ptrCast(di_node);1662 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1624 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);1663 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 {...@@ -1655,7 +1694,7 @@ pub const Object = struct {
1655 llvm_global.setDLLStorageClass(.DLLExport);1694 llvm_global.setDLLStorageClass(.DLLExport);
1656 }1695 }
1657 if (self.di_map.get(decl)) |di_node| {1696 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).?;
1659 if (try decl.isFunction(mod)) {1698 if (try decl.isFunction(mod)) {
1660 const di_func: *llvm.DISubprogram = @ptrCast(di_node);1699 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1661 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);1700 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 {...@@ -2816,7 +2855,7 @@ pub const Object = struct {
2816 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));2855 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
28172856
2818 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);2857 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
2821 var global = Builder.Global{2860 var global = Builder.Global{
2822 .type = fn_type,2861 .type = fn_type,
...@@ -2826,6 +2865,9 @@ pub const Object = struct {...@@ -2826,6 +2865,9 @@ pub const Object = struct {
2826 .global = @enumFromInt(o.builder.globals.count()),2865 .global = @enumFromInt(o.builder.globals.count()),
2827 };2866 };
28282867
2868 var attributes: Builder.FunctionAttributes.Wip = .{};
2869 defer attributes.deinit(&o.builder);
2870
2829 const is_extern = decl.isExtern(mod);2871 const is_extern = decl.isExtern(mod);
2830 if (!is_extern) {2872 if (!is_extern) {
2831 global.linkage = .internal;2873 global.linkage = .internal;
...@@ -2834,43 +2876,64 @@ pub const Object = struct {...@@ -2834,43 +2876,64 @@ pub const Object = struct {
2834 llvm_fn.setUnnamedAddr(.True);2876 llvm_fn.setUnnamedAddr(.True);
2835 } else {2877 } else {
2836 if (target.isWasm()) {2878 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);
2837 o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));2883 o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));
2838 if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {2884 if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
2839 if (!std.mem.eql(u8, lib_name, "c")) {2885 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);
2840 o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);2890 o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);
2841 }2891 }
2842 }2892 }
2843 }2893 }
2844 }2894 }
28452895
2896 var llvm_arg_i: u32 = 0;
2846 if (sret) {2897 if (sret) {
2847 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 02898 // Sret pointers must not be address 0
2848 o.addArgAttr(llvm_fn, 0, "noalias");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);2908 llvm_arg_i += 1;
2851 llvm_fn.addSretAttr(raw_llvm_ret_ty);
2852 }2909 }
28532910
2854 const err_return_tracing = fn_info.return_type.toType().isError(mod) and2911 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
2855 mod.comp.bin_file.options.error_return_tracing;2912 mod.comp.bin_file.options.error_return_tracing;
28562913
2857 if (err_return_tracing) {2914 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;
2859 }2918 }
28602919
2861 switch (fn_info.cc) {2920 switch (fn_info.cc) {
2862 .Unspecified, .Inline => {2921 .Unspecified, .Inline => {
2922 function.call_conv = .fastcc;
2863 llvm_fn.setFunctionCallConv(.Fast);2923 llvm_fn.setFunctionCallConv(.Fast);
2864 },2924 },
2865 .Naked => {2925 .Naked => {
2926 try attributes.addFnAttr(.naked, &o.builder);
2866 o.addFnAttr(llvm_fn, "naked");2927 o.addFnAttr(llvm_fn, "naked");
2867 },2928 },
2868 .Async => {2929 .Async => {
2930 function.call_conv = .fastcc;
2869 llvm_fn.setFunctionCallConv(.Fast);2931 llvm_fn.setFunctionCallConv(.Fast);
2870 @panic("TODO: LLVM backend lower async function");2932 @panic("TODO: LLVM backend lower async function");
2871 },2933 },
2872 else => {2934 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)));
2874 },2937 },
2875 }2938 }
28762939
...@@ -2880,9 +2943,10 @@ pub const Object = struct {...@@ -2880,9 +2943,10 @@ pub const Object = struct {
2880 }2943 }
28812944
2882 // Function attributes that are independent of analysis results of the function body.2945 // 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
2885 if (fn_info.return_type == .noreturn_type) {2948 if (fn_info.return_type == .noreturn_type) {
2949 try attributes.addFnAttr(.noreturn, &o.builder);
2886 o.addFnAttr(llvm_fn, "noreturn");2950 o.addFnAttr(llvm_fn, "noreturn");
2887 }2951 }
28882952
...@@ -2890,23 +2954,24 @@ pub const Object = struct {...@@ -2890,23 +2954,24 @@ pub const Object = struct {
2890 // because functions with bodies are handled in `updateFunc`.2954 // because functions with bodies are handled in `updateFunc`.
2891 if (is_extern) {2955 if (is_extern) {
2892 var it = iterateParamTypes(o, fn_info);2956 var it = iterateParamTypes(o, fn_info);
2893 it.llvm_index += @intFromBool(sret);2957 it.llvm_index = llvm_arg_i;
2894 it.llvm_index += @intFromBool(err_return_tracing);
2895 while (try it.next()) |lowering| switch (lowering) {2958 while (try it.next()) |lowering| switch (lowering) {
2896 .byval => {2959 .byval => {
2897 const param_index = it.zig_index - 1;2960 const param_index = it.zig_index - 1;
2898 const param_ty = fn_info.param_types.get(ip)[param_index].toType();2961 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
2899 if (!isByRef(param_ty, mod)) {2962 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);
2901 }2964 }
2902 },2965 },
2903 .byref => {2966 .byref => {
2904 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];2967 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
2905 const param_llvm_ty = try o.lowerType(param_ty.toType());2968 const param_llvm_ty = try o.lowerType(param_ty.toType());
2906 const alignment = param_ty.toType().abiAlignment(mod);2969 const alignment =
2907 o.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);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);
2908 },2972 },
2909 .byref_mut => {2973 .byref_mut => {
2974 try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder);
2910 o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");2975 o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
2911 },2976 },
2912 // No attributes needed for these.2977 // No attributes needed for these.
...@@ -2924,25 +2989,42 @@ pub const Object = struct {...@@ -2924,25 +2989,42 @@ pub const Object = struct {
2924 };2989 };
2925 }2990 }
29262991
2992 function.attributes = try attributes.finish(&o.builder);
2993
2927 try o.builder.llvm.globals.append(o.gpa, llvm_fn);2994 try o.builder.llvm.globals.append(o.gpa, llvm_fn);
2928 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);2995 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);
2929 try o.builder.functions.append(o.gpa, function);2996 try o.builder.functions.append(o.gpa, function);
2930 return global.kind.function;2997 return global.kind.function;
2931 }2998 }
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 {
2934 const comp = o.module.comp;3005 const comp = o.module.comp;
29353006
2936 if (!comp.bin_file.options.red_zone) {3007 if (!comp.bin_file.options.red_zone) {
3008 try attributes.addFnAttr(.noredzone, &o.builder);
2937 o.addFnAttr(llvm_fn, "noredzone");3009 o.addFnAttr(llvm_fn, "noredzone");
2938 }3010 }
2939 if (comp.bin_file.options.omit_frame_pointer) {3011 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);
2940 o.addFnAttrString(llvm_fn, "frame-pointer", "none");3016 o.addFnAttrString(llvm_fn, "frame-pointer", "none");
2941 } else {3017 } else {
3018 try attributes.addFnAttr(.{ .string = .{
3019 .kind = try o.builder.string("frame-pointer"),
3020 .value = try o.builder.string("all"),
3021 } }, &o.builder);
2942 o.addFnAttrString(llvm_fn, "frame-pointer", "all");3022 o.addFnAttrString(llvm_fn, "frame-pointer", "all");
2943 }3023 }
3024 try attributes.addFnAttr(.nounwind, &o.builder);
2944 o.addFnAttr(llvm_fn, "nounwind");3025 o.addFnAttr(llvm_fn, "nounwind");
2945 if (comp.unwind_tables) {3026 if (comp.unwind_tables) {
3027 try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
2946 o.addFnAttrInt(llvm_fn, "uwtable", 2);3028 o.addFnAttrInt(llvm_fn, "uwtable", 2);
2947 }3029 }
2948 if (comp.bin_file.options.skip_linker_dependencies or3030 if (comp.bin_file.options.skip_linker_dependencies or
...@@ -2953,22 +3035,38 @@ pub const Object = struct {...@@ -2953,22 +3035,38 @@ pub const Object = struct {
2953 // and llvm detects that the body is equivalent to memcpy, it may replace the3035 // and llvm detects that the body is equivalent to memcpy, it may replace the
2954 // body of memcpy with a call to memcpy, which would then cause a stack3036 // body of memcpy with a call to memcpy, which would then cause a stack
2955 // overflow instead of performing memcpy.3037 // overflow instead of performing memcpy.
3038 try attributes.addFnAttr(.nobuiltin, &o.builder);
2956 o.addFnAttr(llvm_fn, "nobuiltin");3039 o.addFnAttr(llvm_fn, "nobuiltin");
2957 }3040 }
2958 if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {3041 if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
3042 try attributes.addFnAttr(.minsize, &o.builder);
3043 try attributes.addFnAttr(.optsize, &o.builder);
2959 o.addFnAttr(llvm_fn, "minsize");3044 o.addFnAttr(llvm_fn, "minsize");
2960 o.addFnAttr(llvm_fn, "optsize");3045 o.addFnAttr(llvm_fn, "optsize");
2961 }3046 }
2962 if (comp.bin_file.options.tsan) {3047 if (comp.bin_file.options.tsan) {
3048 try attributes.addFnAttr(.sanitize_thread, &o.builder);
2963 o.addFnAttr(llvm_fn, "sanitize_thread");3049 o.addFnAttr(llvm_fn, "sanitize_thread");
2964 }3050 }
2965 if (comp.getTarget().cpu.model.llvm_name) |s| {3051 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);
2966 llvm_fn.addFunctionAttr("target-cpu", s);3056 llvm_fn.addFunctionAttr("target-cpu", s);
2967 }3057 }
2968 if (comp.bin_file.options.llvm_cpu_features) |s| {3058 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);
2969 llvm_fn.addFunctionAttr("target-features", s);3063 llvm_fn.addFunctionAttr("target-features", s);
2970 }3064 }
2971 if (comp.getTarget().cpu.arch.isBpf()) {3065 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);
2972 llvm_fn.addFunctionAttr("no-builtins", "");3070 llvm_fn.addFunctionAttr("no-builtins", "");
2973 }3071 }
2974 }3072 }
...@@ -3002,7 +3100,7 @@ pub const Object = struct {...@@ -3002,7 +3100,7 @@ pub const Object = struct {
3002 fqn;3100 fqn;
3003 const llvm_global = o.llvm_module.addGlobalInAddressSpace(3101 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
3004 global.type.toLlvm(&o.builder),3102 global.type.toLlvm(&o.builder),
3005 fqn.toSlice(&o.builder).?,3103 fqn.slice(&o.builder).?,
3006 @intFromEnum(global.addr_space),3104 @intFromEnum(global.addr_space),
3007 );3105 );
30083106
...@@ -4403,47 +4501,114 @@ pub const Object = struct {...@@ -4403,47 +4501,114 @@ pub const Object = struct {
44034501
4404 fn addByValParamAttrs(4502 fn addByValParamAttrs(
4405 o: *Object,4503 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,
4406 llvm_fn: *llvm.Value,4554 llvm_fn: *llvm.Value,
4407 param_ty: Type,4555 param_ty: Type,
4408 param_index: u32,4556 param_index: u32,
4409 fn_info: InternPool.Key.FuncType,4557 fn_info: InternPool.Key.FuncType,
4410 llvm_arg_i: u32,4558 llvm_arg_i: u32,
4411 ) void {4559 ) Allocator.Error!void {
4412 const mod = o.module;4560 const mod = o.module;
4413 if (param_ty.isPtrAtRuntime(mod)) {4561 if (param_ty.isPtrAtRuntime(mod)) {
4414 const ptr_info = param_ty.ptrInfo(mod);4562 const ptr_info = param_ty.ptrInfo(mod);
4415 if (math.cast(u5, param_index)) |i| {4563 if (math.cast(u5, param_index)) |i| {
4416 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {4564 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4565 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
4417 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");4566 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
4418 }4567 }
4419 }4568 }
4420 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {4569 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4570 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4421 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");4571 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4422 }4572 }
4423 if (ptr_info.flags.is_const) {4573 if (ptr_info.flags.is_const) {
4574 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4424 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");4575 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4425 }4576 }
4426 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse4577 const elem_align = Builder.Alignment.fromByteUnits(
4427 @max(ptr_info.child.toType().abiAlignment(mod), 1);4578 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4428 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align);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);
4429 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {4583 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4430 .signed => o.addArgAttr(llvm_fn, llvm_arg_i, "signext"),4584 .signed => {
4431 .unsigned => o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"),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 },
4432 };4592 };
4433 }4593 }
44344594
4435 fn addByRefParamAttrs(4595 fn addByRefParamAttrsOld(
4436 o: *Object,4596 o: *Object,
4597 attributes: *Builder.FunctionAttributes.Wip,
4437 llvm_fn: *llvm.Value,4598 llvm_fn: *llvm.Value,
4438 llvm_arg_i: u32,4599 llvm_arg_i: u32,
4439 alignment: u32,4600 alignment: Builder.Alignment,
4440 byval_attr: bool,4601 byval_attr: bool,
4441 param_llvm_ty: Builder.Type,4602 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);
4443 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");4607 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
4444 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");4608 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);
4446 if (byval_attr) {4610 if (byval_attr) {
4611 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
4447 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));4612 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
4448 }4613 }
4449 }4614 }
...@@ -4841,10 +5006,10 @@ pub const FuncGen = struct {...@@ -4841,10 +5006,10 @@ pub const FuncGen = struct {
4841 .slice_ptr => try self.airSliceField(inst, 0),5006 .slice_ptr => try self.airSliceField(inst, 0),
4842 .slice_len => try self.airSliceField(inst, 1),5007 .slice_len => try self.airSliceField(inst, 1),
48435008
4844 .call => try self.airCall(inst, .Auto),5009 .call => try self.airCall(inst, .auto),
4845 .call_always_tail => try self.airCall(inst, .AlwaysTail),5010 .call_always_tail => try self.airCall(inst, .always_tail),
4846 .call_never_tail => try self.airCall(inst, .NeverTail),5011 .call_never_tail => try self.airCall(inst, .never_tail),
4847 .call_never_inline => try self.airCall(inst, .NeverInline),5012 .call_never_inline => try self.airCall(inst, .never_inline),
48485013
4849 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),5014 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
4850 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),5015 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
...@@ -4953,7 +5118,15 @@ pub const FuncGen = struct {...@@ -4953,7 +5118,15 @@ pub const FuncGen = struct {
4953 }5118 }
4954 }5119 }
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 {
4957 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5130 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4958 const extra = self.air.extraData(Air.Call, pl_op.payload);5131 const extra = self.air.extraData(Air.Call, pl_op.payload);
4959 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);5132 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 {...@@ -4972,14 +5145,25 @@ pub const FuncGen = struct {
4972 const target = mod.getTarget();5145 const target = mod.getTarget();
4973 const sret = firstParamSRet(fn_info, mod);5146 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);
4976 defer llvm_args.deinit();5149 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
4978 const ret_ptr = if (!sret) null else blk: {5160 const ret_ptr = if (!sret) null else blk: {
4979 const llvm_ret_ty = try o.lowerType(return_type);5161 const llvm_ret_ty = try o.lowerType(return_type);
5162 try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
5163
4980 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));5164 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4981 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);5165 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);
4983 break :blk ret_ptr;5167 break :blk ret_ptr;
4984 };5168 };
49855169
...@@ -4987,7 +5171,7 @@ pub const FuncGen = struct {...@@ -4987,7 +5171,7 @@ pub const FuncGen = struct {
4987 o.module.comp.bin_file.options.error_return_tracing;5171 o.module.comp.bin_file.options.error_return_tracing;
4988 if (err_return_tracing) {5172 if (err_return_tracing) {
4989 assert(self.err_ret_trace != .none);5173 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);
4991 }5175 }
49925176
4993 var it = iterateParamTypes(o, fn_info);5177 var it = iterateParamTypes(o, fn_info);
...@@ -5001,9 +5185,9 @@ pub const FuncGen = struct {...@@ -5001,9 +5185,9 @@ pub const FuncGen = struct {
5001 if (isByRef(param_ty, mod)) {5185 if (isByRef(param_ty, mod)) {
5002 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5186 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5003 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");5187 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);
5005 } else {5189 } else {
5006 try llvm_args.append(llvm_arg.toLlvm(&self.wip));5190 try llvm_args.append(llvm_arg);
5007 }5191 }
5008 },5192 },
5009 .byref => {5193 .byref => {
...@@ -5011,13 +5195,13 @@ pub const FuncGen = struct {...@@ -5011,13 +5195,13 @@ pub const FuncGen = struct {
5011 const param_ty = self.typeOf(arg);5195 const param_ty = self.typeOf(arg);
5012 const llvm_arg = try self.resolveInst(arg);5196 const llvm_arg = try self.resolveInst(arg);
5013 if (isByRef(param_ty, mod)) {5197 if (isByRef(param_ty, mod)) {
5014 try llvm_args.append(llvm_arg.toLlvm(&self.wip));5198 try llvm_args.append(llvm_arg);
5015 } else {5199 } else {
5016 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5200 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5017 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);5201 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
5018 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);5202 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
5019 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);5203 _ = 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);
5021 }5205 }
5022 },5206 },
5023 .byref_mut => {5207 .byref_mut => {
...@@ -5034,7 +5218,7 @@ pub const FuncGen = struct {...@@ -5034,7 +5218,7 @@ pub const FuncGen = struct {
5034 } else {5218 } else {
5035 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);5219 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
5036 }5220 }
5037 try llvm_args.append(arg_ptr.toLlvm(&self.wip));5221 try llvm_args.append(arg_ptr);
5038 },5222 },
5039 .abi_sized_int => {5223 .abi_sized_int => {
5040 const arg = args[it.zig_index - 1];5224 const arg = args[it.zig_index - 1];
...@@ -5045,7 +5229,7 @@ pub const FuncGen = struct {...@@ -5045,7 +5229,7 @@ pub const FuncGen = struct {
5045 if (isByRef(param_ty, mod)) {5229 if (isByRef(param_ty, mod)) {
5046 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5230 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5047 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");5231 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);
5049 } else {5233 } else {
5050 // LLVM does not allow bitcasting structs so we must allocate5234 // LLVM does not allow bitcasting structs so we must allocate
5051 // a local, store as one type, and then load as another type.5235 // a local, store as one type, and then load as another type.
...@@ -5056,7 +5240,7 @@ pub const FuncGen = struct {...@@ -5056,7 +5240,7 @@ pub const FuncGen = struct {
5056 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);5240 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
5057 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);5241 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
5058 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");5242 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);
5060 }5244 }
5061 },5245 },
5062 .slice => {5246 .slice => {
...@@ -5064,7 +5248,7 @@ pub const FuncGen = struct {...@@ -5064,7 +5248,7 @@ pub const FuncGen = struct {
5064 const llvm_arg = try self.resolveInst(arg);5248 const llvm_arg = try self.resolveInst(arg);
5065 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");5249 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
5066 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");5250 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 });
5068 },5252 },
5069 .multiple_llvm_types => {5253 .multiple_llvm_types => {
5070 const arg = args[it.zig_index - 1];5254 const arg = args[it.zig_index - 1];
...@@ -5086,14 +5270,14 @@ pub const FuncGen = struct {...@@ -5086,14 +5270,14 @@ pub const FuncGen = struct {
5086 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));5270 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
5087 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");5271 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
5088 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");5272 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);
5090 }5274 }
5091 },5275 },
5092 .as_u16 => {5276 .as_u16 => {
5093 const arg = args[it.zig_index - 1];5277 const arg = args[it.zig_index - 1];
5094 const llvm_arg = try self.resolveInst(arg);5278 const llvm_arg = try self.resolveInst(arg);
5095 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");5279 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);
5097 },5281 },
5098 .float_array => |count| {5282 .float_array => |count| {
5099 const arg = args[it.zig_index - 1];5283 const arg = args[it.zig_index - 1];
...@@ -5110,7 +5294,7 @@ pub const FuncGen = struct {...@@ -5110,7 +5294,7 @@ pub const FuncGen = struct {
5110 const array_ty = try o.builder.arrayType(count, float_ty);5294 const array_ty = try o.builder.arrayType(count, float_ty);
51115295
5112 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");5296 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);
5114 },5298 },
5115 .i32_array, .i64_array => |arr_len| {5299 .i32_array, .i64_array => |arr_len| {
5116 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;5300 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
...@@ -5127,24 +5311,10 @@ pub const FuncGen = struct {...@@ -5127,24 +5311,10 @@ pub const FuncGen = struct {
5127 const array_ty =5311 const array_ty =
5128 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));5312 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
5129 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");5313 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);
5131 },5315 },
5132 };5316 };
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
5148 if (callee_ty.zigTypeTag(mod) == .Pointer) {5318 if (callee_ty.zigTypeTag(mod) == .Pointer) {
5149 // Add argument attributes for function pointer calls.5319 // Add argument attributes for function pointer calls.
5150 it = iterateParamTypes(o, fn_info);5320 it = iterateParamTypes(o, fn_info);
...@@ -5155,19 +5325,17 @@ pub const FuncGen = struct {...@@ -5155,19 +5325,17 @@ pub const FuncGen = struct {
5155 const param_index = it.zig_index - 1;5325 const param_index = it.zig_index - 1;
5156 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5326 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5157 if (!isByRef(param_ty, mod)) {5327 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);
5159 }5329 }
5160 },5330 },
5161 .byref => {5331 .byref => {
5162 const param_index = it.zig_index - 1;5332 const param_index = it.zig_index - 1;
5163 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5333 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5164 const param_llvm_ty = try o.lowerType(param_ty);5334 const param_llvm_ty = try o.lowerType(param_ty);
5165 const alignment = param_ty.abiAlignment(mod);5335 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5166 o.addByRefParamAttrs(call.toLlvm(&self.wip), it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);5336 try o.addByRefParamAttrs(&attributes, 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");
5170 },5337 },
5338 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
5171 // No attributes needed for these.5339 // No attributes needed for these.
5172 .no_bits,5340 .no_bits,
5173 .abi_sized_int,5341 .abi_sized_int,
...@@ -5186,23 +5354,40 @@ pub const FuncGen = struct {...@@ -5186,23 +5354,40 @@ pub const FuncGen = struct {
51865354
5187 if (math.cast(u5, it.zig_index - 1)) |i| {5355 if (math.cast(u5, it.zig_index - 1)) |i| {
5188 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {5356 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);
5190 }5358 }
5191 }5359 }
5192 if (param_ty.zigTypeTag(mod) != .Optional) {5360 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);
5194 }5362 }
5195 if (ptr_info.flags.is_const) {5363 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);
5197 }5365 }
5198 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse5366 const elem_align = Builder.Alignment.fromByteUnits(
5199 @max(ptr_info.child.toType().abiAlignment(mod), 1);5367 ptr_info.flags.alignment.toByteUnitsOptional() orelse
5200 o.addArgAttrInt(call.toLlvm(&self.wip), llvm_arg_i, "align", elem_align);5368 @max(ptr_info.child.toType().abiAlignment(mod), 1),
5369 );
5370 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
5201 },5371 },
5202 };5372 };
5203 }5373 }
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) {
5206 return .none;5391 return .none;
5207 }5392 }
52085393
...@@ -5211,9 +5396,7 @@ pub const FuncGen = struct {...@@ -5211,9 +5396,7 @@ pub const FuncGen = struct {
5211 }5396 }
52125397
5213 const llvm_ret_ty = try o.lowerType(return_type);5398 const llvm_ret_ty = try o.lowerType(return_type);
5214
5215 if (ret_ptr) |rp| {5399 if (ret_ptr) |rp| {
5216 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
5217 if (isByRef(return_type, mod)) {5400 if (isByRef(return_type, mod)) {
5218 return rp;5401 return rp;
5219 } else {5402 } else {
...@@ -5269,25 +5452,24 @@ pub const FuncGen = struct {...@@ -5269,25 +5452,24 @@ pub const FuncGen = struct {
5269 // ptr null, ; stack trace5452 // ptr null, ; stack trace
5270 // ptr @2, ; addr (null ?usize)5453 // ptr @2, ; addr (null ?usize)
5271 // )5454 // )
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 };
5278 const panic_func = mod.funcInfo(mod.panic_func_index);5455 const panic_func = mod.funcInfo(mod.panic_func_index);
5279 const panic_decl = mod.declPtr(panic_func.owner_decl);5456 const panic_decl = mod.declPtr(panic_func.owner_decl);
5280 const fn_info = mod.typeToFunc(panic_decl.ty).?;5457 const fn_info = mod.typeToFunc(panic_decl.ty).?;
5281 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);5458 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
5282 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(5459 _ = try fg.wip.call(
5283 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),5460 .normal,
5284 panic_global.toLlvm(&o.builder),
5285 &args,
5286 args.len,
5287 toLlvmCallConv(fn_info.cc, target),5461 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 },
5289 "",5471 "",
5290 ), &fg.wip);5472 );
5291 _ = try fg.wip.@"unreachable"();5473 _ = try fg.wip.@"unreachable"();
5292 }5474 }
52935475
...@@ -5395,7 +5577,7 @@ pub const FuncGen = struct {...@@ -5395,7 +5577,7 @@ pub const FuncGen = struct {
5395 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));5577 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
53965578
5397 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };5579 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(
5399 llvm_fn_ty.toLlvm(&o.builder),5581 llvm_fn_ty.toLlvm(&o.builder),
5400 llvm_fn,5582 llvm_fn,
5401 &args,5583 &args,
...@@ -5422,7 +5604,7 @@ pub const FuncGen = struct {...@@ -5422,7 +5604,7 @@ pub const FuncGen = struct {
5422 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));5604 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54235605
5424 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};5606 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(
5426 llvm_fn_ty.toLlvm(&o.builder),5608 llvm_fn_ty.toLlvm(&o.builder),
5427 llvm_fn,5609 llvm_fn,
5428 &args,5610 &args,
...@@ -5449,7 +5631,7 @@ pub const FuncGen = struct {...@@ -5449,7 +5631,7 @@ pub const FuncGen = struct {
5449 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));5631 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54505632
5451 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};5633 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(
5453 llvm_fn_ty.toLlvm(&o.builder),5635 llvm_fn_ty.toLlvm(&o.builder),
5454 llvm_fn,5636 llvm_fn,
5455 &args,5637 &args,
...@@ -5495,16 +5677,15 @@ pub const FuncGen = struct {...@@ -5495,16 +5677,15 @@ pub const FuncGen = struct {
5495 const un_op = self.air.instructions.items(.data)[inst].un_op;5677 const un_op = self.air.instructions.items(.data)[inst].un_op;
5496 const operand = try self.resolveInst(un_op);5678 const operand = try self.resolveInst(un_op);
5497 const llvm_fn = try self.getCmpLtErrorsLenFunction();5679 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5498 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};5680 return self.wip.call(
5499 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(5681 .normal,
5500 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),5682 .fastcc,
5501 llvm_fn.toLlvm(&o.builder),5683 .none,
5502 &args,5684 llvm_fn.typeOf(&o.builder),
5503 args.len,5685 llvm_fn.toValue(&o.builder),
5504 .Fast,5686 &.{operand},
5505 .Auto,
5506 "",5687 "",
5507 ), &self.wip);5688 );
5508 }5689 }
55095690
5510 fn cmp(5691 fn cmp(
...@@ -5953,16 +6134,15 @@ pub const FuncGen = struct {...@@ -5953,16 +6134,15 @@ pub const FuncGen = struct {
5953 }6134 }
59546135
5955 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);6136 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5956 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};6137 return self.wip.call(
5957 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(6138 .normal,
5958 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),6139 .ccc,
5959 libc_fn.toLlvm(&o.builder),6140 .none,
5960 &params,6141 libc_fn.typeOf(&o.builder),
5961 params.len,6142 libc_fn.toValue(&o.builder),
5962 .C,6143 &.{extended},
5963 .Auto,
5964 "",6144 "",
5965 ), &self.wip);6145 );
5966 }6146 }
59676147
5968 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {6148 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
...@@ -6013,16 +6193,15 @@ pub const FuncGen = struct {...@@ -6013,16 +6193,15 @@ pub const FuncGen = struct {
60136193
6014 const operand_llvm_ty = try o.lowerType(operand_ty);6194 const operand_llvm_ty = try o.lowerType(operand_ty);
6015 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);6195 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
6016 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};6196 var result = try self.wip.call(
6017 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(6197 .normal,
6018 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),6198 .ccc,
6019 libc_fn.toLlvm(&o.builder),6199 .none,
6020 &params,6200 libc_fn.typeOf(&o.builder),
6021 params.len,6201 libc_fn.toValue(&o.builder),
6022 .C,6202 &.{operand},
6023 .Auto,
6024 "",6203 "",
6025 ), &self.wip);6204 );
60266205
6027 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");6206 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
6028 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");6207 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
...@@ -6843,6 +7022,9 @@ pub const FuncGen = struct {...@@ -6843,6 +7022,9 @@ pub const FuncGen = struct {
6843 }7022 }
6844 }7023 }
68457024
7025 var attributes: Builder.FunctionAttributes.Wip = .{};
7026 defer attributes.deinit(&o.builder);
7027
6846 const ret_llvm_ty = switch (return_count) {7028 const ret_llvm_ty = switch (return_count) {
6847 0 => .void,7029 0 => .void,
6848 1 => llvm_ret_types[0],7030 1 => llvm_ret_types[0],
...@@ -6861,7 +7043,7 @@ pub const FuncGen = struct {...@@ -6861,7 +7043,7 @@ pub const FuncGen = struct {
6861 .ATT,7043 .ATT,
6862 .False,7044 .False,
6863 );7045 );
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(
6865 llvm_fn_ty.toLlvm(&o.builder),7047 llvm_fn_ty.toLlvm(&o.builder),
6866 asm_fn,7048 asm_fn,
6867 llvm_param_values.ptr,7049 llvm_param_values.ptr,
...@@ -6872,6 +7054,7 @@ pub const FuncGen = struct {...@@ -6872,6 +7054,7 @@ pub const FuncGen = struct {
6872 ), &self.wip);7054 ), &self.wip);
6873 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {7055 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6874 if (llvm_elem_ty != .none) {7056 if (llvm_elem_ty != .none) {
7057 try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
6875 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));7058 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
6876 }7059 }
6877 }7060 }
...@@ -7287,7 +7470,7 @@ pub const FuncGen = struct {...@@ -7287,7 +7470,7 @@ pub const FuncGen = struct {
7287 const args: [1]*llvm.Value = .{7470 const args: [1]*llvm.Value = .{
7288 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),7471 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7289 };7472 };
7290 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(7473 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
7291 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),7474 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
7292 llvm_fn,7475 llvm_fn,
7293 &args,7476 &args,
...@@ -7308,7 +7491,7 @@ pub const FuncGen = struct {...@@ -7308,7 +7491,7 @@ pub const FuncGen = struct {
7308 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),7491 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7309 operand.toLlvm(&self.wip),7492 operand.toLlvm(&self.wip),
7310 };7493 };
7311 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(7494 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
7312 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),7495 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
7313 llvm_fn,7496 llvm_fn,
7314 &args,7497 &args,
...@@ -7425,7 +7608,7 @@ pub const FuncGen = struct {...@@ -7425,7 +7608,7 @@ pub const FuncGen = struct {
7425 });7608 });
7426 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);7609 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);
7427 const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});7610 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(
7429 llvm_fn_ty.toLlvm(&o.builder),7612 llvm_fn_ty.toLlvm(&o.builder),
7430 llvm_fn,7613 llvm_fn,
7431 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },7614 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
...@@ -7768,7 +7951,7 @@ pub const FuncGen = struct {...@@ -7768,7 +7951,7 @@ pub const FuncGen = struct {
7768 );7951 );
7769 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);7952 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);
7770 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(7953 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
7771 self.builder.buildCall(7954 self.builder.buildCallOld(
7772 llvm_fn_ty.toLlvm(&o.builder),7955 llvm_fn_ty.toLlvm(&o.builder),
7773 llvm_fn,7956 llvm_fn,
7774 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },7957 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
...@@ -7818,29 +8001,23 @@ pub const FuncGen = struct {...@@ -7818,29 +8001,23 @@ pub const FuncGen = struct {
7818 const o = self.dg.object;8001 const o = self.dg.object;
7819 assert(args_vectors.len <= 3);8002 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
7824 var i: usize = 0;8004 var i: usize = 0;
7825 var result = result_vector;8005 var result = result_vector;
7826 while (i < vector_len) : (i += 1) {8006 while (i < vector_len) : (i += 1) {
7827 const index_i32 = try o.builder.intValue(.i32, i);8007 const index_i32 = try o.builder.intValue(.i32, i);
78288008
7829 var args: [3]*llvm.Value = undefined;8009 var args: [3]Builder.Value = undefined;
7830 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {8010 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, "");
7832 }8012 }
7833 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(8013 const result_elem = try self.wip.call(
7834 self.builder.buildCall(8014 .normal,
7835 llvm_fn_ty.toLlvm(&o.builder),8015 .ccc,
7836 llvm_fn.toLlvm(&o.builder),8016 .none,
7837 &args,8017 llvm_fn.typeOf(&o.builder),
7838 @intCast(args_vectors.len),8018 llvm_fn.toValue(&o.builder),
7839 .C,8019 args[0..args_vectors.len],
7840 .Auto,8020 "",
7841 "",
7842 ),
7843 &self.wip,
7844 );8021 );
7845 result = try self.wip.insertElement(result, result_elem, index_i32, "");8022 result = try self.wip.insertElement(result, result_elem, index_i32, "");
7846 }8023 }
...@@ -7861,7 +8038,7 @@ pub const FuncGen = struct {...@@ -7861,7 +8038,7 @@ pub const FuncGen = struct {
7861 };8038 };
78628039
7863 const fn_type = try o.builder.fnType(return_type, param_types, .normal);8040 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
7866 var global = Builder.Global{8043 var global = Builder.Global{
7867 .type = fn_type,8044 .type = fn_type,
...@@ -7942,20 +8119,15 @@ pub const FuncGen = struct {...@@ -7942,20 +8119,15 @@ pub const FuncGen = struct {
7942 return self.wip.icmp(int_cond, result, zero_vector, "");8119 return self.wip.icmp(int_cond, result, zero_vector, "");
7943 }8120 }
79448121
7945 const llvm_fn_ty = libc_fn.typeOf(&o.builder);8122 const result = try self.wip.call(
7946 const llvm_params = [2]*llvm.Value{ params[0].toLlvm(&self.wip), params[1].toLlvm(&self.wip) };8123 .normal,
7947 const result = (try self.wip.unimplemented(8124 .ccc,
7948 llvm_fn_ty.functionReturn(&o.builder),8125 .none,
7949 "",8126 libc_fn.typeOf(&o.builder),
7950 )).finish(self.builder.buildCall(8127 libc_fn.toValue(&o.builder),
7951 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),8128 &params,
7952 libc_fn.toLlvm(&o.builder),
7953 &llvm_params,
7954 llvm_params.len,
7955 .C,
7956 .Auto,
7957 "",8129 "",
7958 ), &self.wip);8130 );
7959 return self.wip.icmp(int_cond, result, zero.toValue(), "");8131 return self.wip.icmp(int_cond, result, zero.toValue(), "");
7960 }8132 }
79618133
...@@ -8085,7 +8257,7 @@ pub const FuncGen = struct {...@@ -8085,7 +8257,7 @@ pub const FuncGen = struct {
8085 );8257 );
8086 var llvm_params: [params_len]*llvm.Value = undefined;8258 var llvm_params: [params_len]*llvm.Value = undefined;
8087 for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);8259 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(
8089 llvm_fn_ty.toLlvm(&o.builder),8261 llvm_fn_ty.toLlvm(&o.builder),
8090 llvm_fn,8262 llvm_fn,
8091 &llvm_params,8263 &llvm_params,
...@@ -8311,17 +8483,16 @@ pub const FuncGen = struct {...@@ -8311,17 +8483,16 @@ pub const FuncGen = struct {
8311 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8483 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
8312 });8484 });
83138485
8314 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);8486 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8315 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};8487 return self.wip.call(
8316 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(8488 .normal,
8317 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),8489 .ccc,
8318 llvm_fn.toLlvm(&o.builder),8490 .none,
8319 &params,8491 libc_fn.typeOf(&o.builder),
8320 params.len,8492 libc_fn.toValue(&o.builder),
8321 .C,8493 &.{operand},
8322 .Auto,
8323 "",8494 "",
8324 ), &self.wip);8495 );
8325 }8496 }
8326 }8497 }
83278498
...@@ -8346,17 +8517,16 @@ pub const FuncGen = struct {...@@ -8346,17 +8517,16 @@ pub const FuncGen = struct {
8346 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8517 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
8347 });8518 });
83488519
8349 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);8520 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8350 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};8521 return self.wip.call(
8351 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(8522 .normal,
8352 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),8523 .ccc,
8353 llvm_fn.toLlvm(&o.builder),8524 .none,
8354 &params,8525 libc_fn.typeOf(&o.builder),
8355 params.len,8526 libc_fn.toValue(&o.builder),
8356 .C,8527 &.{operand},
8357 .Auto,
8358 "",8528 "",
8359 ), &self.wip);8529 );
8360 }8530 }
8361 }8531 }
83628532
...@@ -8657,7 +8827,7 @@ pub const FuncGen = struct {...@@ -8657,7 +8827,7 @@ pub const FuncGen = struct {
8657 _ = inst;8827 _ = inst;
8658 const o = self.dg.object;8828 const o = self.dg.object;
8659 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});8829 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(
8661 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),8831 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8662 llvm_fn,8832 llvm_fn,
8663 undefined,8833 undefined,
...@@ -8674,7 +8844,7 @@ pub const FuncGen = struct {...@@ -8674,7 +8844,7 @@ pub const FuncGen = struct {
8674 _ = inst;8844 _ = inst;
8675 const o = self.dg.object;8845 const o = self.dg.object;
8676 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});8846 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(
8678 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),8848 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8679 llvm_fn,8849 llvm_fn,
8680 undefined,8850 undefined,
...@@ -8701,7 +8871,7 @@ pub const FuncGen = struct {...@@ -8701,7 +8871,7 @@ pub const FuncGen = struct {
8701 const params = [_]*llvm.Value{8871 const params = [_]*llvm.Value{
8702 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),8872 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8703 };8873 };
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(
8705 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),8875 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
8706 llvm_fn,8876 llvm_fn,
8707 &params,8877 &params,
...@@ -8727,7 +8897,7 @@ pub const FuncGen = struct {...@@ -8727,7 +8897,7 @@ pub const FuncGen = struct {
8727 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),8897 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8728 };8898 };
8729 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(8899 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8730 self.builder.buildCall(8900 self.builder.buildCallOld(
8731 llvm_fn_ty.toLlvm(&o.builder),8901 llvm_fn_ty.toLlvm(&o.builder),
8732 llvm_fn,8902 llvm_fn,
8733 &params,8903 &params,
...@@ -9256,7 +9426,7 @@ pub const FuncGen = struct {...@@ -9256,7 +9426,7 @@ pub const FuncGen = struct {
9256 Builder.Constant.false.toLlvm(&o.builder),9426 Builder.Constant.false.toLlvm(&o.builder),
9257 };9427 };
9258 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(9428 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9259 self.builder.buildCall(9429 self.builder.buildCallOld(
9260 llvm_fn_ty.toLlvm(&o.builder),9430 llvm_fn_ty.toLlvm(&o.builder),
9261 fn_val,9431 fn_val,
9262 &params,9432 &params,
...@@ -9283,7 +9453,7 @@ pub const FuncGen = struct {...@@ -9283,7 +9453,7 @@ pub const FuncGen = struct {
92839453
9284 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9454 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9285 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(9455 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9286 self.builder.buildCall(9456 self.builder.buildCallOld(
9287 llvm_fn_ty.toLlvm(&o.builder),9457 llvm_fn_ty.toLlvm(&o.builder),
9288 fn_val,9458 fn_val,
9289 &params,9459 &params,
...@@ -9331,7 +9501,7 @@ pub const FuncGen = struct {...@@ -9331,7 +9501,7 @@ pub const FuncGen = struct {
93319501
9332 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9502 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9333 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(9503 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9334 self.builder.buildCall(9504 self.builder.buildCallOld(
9335 llvm_fn_ty.toLlvm(&o.builder),9505 llvm_fn_ty.toLlvm(&o.builder),
9336 fn_val,9506 fn_val,
9337 &params,9507 &params,
...@@ -9389,16 +9559,15 @@ pub const FuncGen = struct {...@@ -9389,16 +9559,15 @@ pub const FuncGen = struct {
9389 const enum_ty = self.typeOf(un_op);9559 const enum_ty = self.typeOf(un_op);
93909560
9391 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);9561 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
9392 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9562 return self.wip.call(
9393 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(9563 .normal,
9394 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),9564 .fastcc,
9395 llvm_fn.toLlvm(&o.builder),9565 .none,
9396 &params,9566 llvm_fn.typeOf(&o.builder),
9397 params.len,9567 llvm_fn.toValue(&o.builder),
9398 .Fast,9568 &.{operand},
9399 .Auto,
9400 "",9569 "",
9401 ), &self.wip);9570 );
9402 }9571 }
94039572
9404 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {9573 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
...@@ -9416,13 +9585,16 @@ pub const FuncGen = struct {...@@ -9416,13 +9585,16 @@ pub const FuncGen = struct {
9416 fqn.fmt(&mod.intern_pool),9585 fqn.fmt(&mod.intern_pool),
9417 });9586 });
94189587
9588 var attributes: Builder.FunctionAttributes.Wip = .{};
9589 defer attributes.deinit(&o.builder);
9590
9419 const fn_type = try o.builder.fnType(.i1, &.{9591 const fn_type = try o.builder.fnType(.i1, &.{
9420 try o.lowerType(enum_type.tag_ty.toType()),9592 try o.lowerType(enum_type.tag_ty.toType()),
9421 }, .normal);9593 }, .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));
9423 fn_val.setLinkage(.Internal);9595 fn_val.setLinkage(.Internal);
9424 fn_val.setFunctionCallConv(.Fast);9596 fn_val.setFunctionCallConv(.Fast);
9425 o.addCommonFnAttributes(fn_val);9597 try o.addCommonFnAttributes(&attributes, fn_val);
94269598
9427 var global = Builder.Global{9599 var global = Builder.Global{
9428 .linkage = .internal,9600 .linkage = .internal,
...@@ -9431,6 +9603,8 @@ pub const FuncGen = struct {...@@ -9431,6 +9603,8 @@ pub const FuncGen = struct {
9431 };9603 };
9432 var function = Builder.Function{9604 var function = Builder.Function{
9433 .global = @enumFromInt(o.builder.globals.count()),9605 .global = @enumFromInt(o.builder.globals.count()),
9606 .call_conv = .fastcc,
9607 .attributes = try attributes.finish(&o.builder),
9434 };9608 };
9435 try o.builder.llvm.globals.append(self.gpa, fn_val);9609 try o.builder.llvm.globals.append(self.gpa, fn_val);
9436 _ = try o.builder.addGlobal(llvm_fn_name, global);9610 _ = try o.builder.addGlobal(llvm_fn_name, global);
...@@ -9470,19 +9644,14 @@ pub const FuncGen = struct {...@@ -9470,19 +9644,14 @@ pub const FuncGen = struct {
9470 const enum_ty = self.typeOf(un_op);9644 const enum_ty = self.typeOf(un_op);
94719645
9472 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);9646 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9473 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);9647 return self.wip.call(
9474 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};9648 .normal,
9475 return (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(9649 .fastcc,
9476 self.builder.buildCall(9650 .none,
9477 llvm_fn_ty.toLlvm(&o.builder),9651 llvm_fn.typeOf(&o.builder),
9478 llvm_fn.toLlvm(&o.builder),9652 llvm_fn.toValue(&o.builder),
9479 &params,9653 &.{operand},
9480 params.len,9654 "",
9481 .Fast,
9482 .Auto,
9483 "",
9484 ),
9485 &self.wip,
9486 );9655 );
9487 }9656 }
94889657
...@@ -9499,16 +9668,19 @@ pub const FuncGen = struct {...@@ -9499,16 +9668,19 @@ pub const FuncGen = struct {
9499 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9668 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
9500 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});9669 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
9502 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);9674 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
9503 const usize_ty = try o.lowerType(Type.usize);9675 const usize_ty = try o.lowerType(Type.usize);
95049676
9505 const fn_type = try o.builder.fnType(ret_ty, &.{9677 const fn_type = try o.builder.fnType(ret_ty, &.{
9506 try o.lowerType(enum_type.tag_ty.toType()),9678 try o.lowerType(enum_type.tag_ty.toType()),
9507 }, .normal);9679 }, .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));
9509 fn_val.setLinkage(.Internal);9681 fn_val.setLinkage(.Internal);
9510 fn_val.setFunctionCallConv(.Fast);9682 fn_val.setFunctionCallConv(.Fast);
9511 o.addCommonFnAttributes(fn_val);9683 try o.addCommonFnAttributes(&attributes, fn_val);
95129684
9513 var global = Builder.Global{9685 var global = Builder.Global{
9514 .linkage = .internal,9686 .linkage = .internal,
...@@ -9517,6 +9689,8 @@ pub const FuncGen = struct {...@@ -9517,6 +9689,8 @@ pub const FuncGen = struct {
9517 };9689 };
9518 var function = Builder.Function{9690 var function = Builder.Function{
9519 .global = @enumFromInt(o.builder.globals.count()),9691 .global = @enumFromInt(o.builder.globals.count()),
9692 .call_conv = .fastcc,
9693 .attributes = try attributes.finish(&o.builder),
9520 };9694 };
9521 try o.builder.llvm.globals.append(self.gpa, fn_val);9695 try o.builder.llvm.globals.append(self.gpa, fn_val);
9522 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);9696 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
...@@ -9561,7 +9735,7 @@ pub const FuncGen = struct {...@@ -9561,7 +9735,7 @@ pub const FuncGen = struct {
95619735
9562 const slice_val = try o.builder.structValue(ret_ty, &.{9736 const slice_val = try o.builder.structValue(ret_ty, &.{
9563 global_index.toConst(),9737 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),
9565 });9739 });
95669740
9567 const return_block = try wip.block(1, "Name");9741 const return_block = try wip.block(1, "Name");
...@@ -9590,11 +9764,14 @@ pub const FuncGen = struct {...@@ -9590,11 +9764,14 @@ pub const FuncGen = struct {
9590 // Function signature: fn (anyerror) bool9764 // Function signature: fn (anyerror) bool
95919765
9592 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);9766 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
9595 llvm_fn.setLinkage(.Internal);9772 llvm_fn.setLinkage(.Internal);
9596 llvm_fn.setFunctionCallConv(.Fast);9773 llvm_fn.setFunctionCallConv(.Fast);
9597 o.addCommonFnAttributes(llvm_fn);9774 try o.addCommonFnAttributes(&attributes, llvm_fn);
95989775
9599 var global = Builder.Global{9776 var global = Builder.Global{
9600 .linkage = .internal,9777 .linkage = .internal,
...@@ -9603,6 +9780,8 @@ pub const FuncGen = struct {...@@ -9603,6 +9780,8 @@ pub const FuncGen = struct {
9603 };9780 };
9604 var function = Builder.Function{9781 var function = Builder.Function{
9605 .global = @enumFromInt(o.builder.globals.count()),9782 .global = @enumFromInt(o.builder.globals.count()),
9783 .call_conv = .fastcc,
9784 .attributes = try attributes.finish(&o.builder),
9606 };9785 };
96079786
9608 try o.builder.llvm.globals.append(self.gpa, llvm_fn);9787 try o.builder.llvm.globals.append(self.gpa, llvm_fn);
...@@ -9731,18 +9910,14 @@ pub const FuncGen = struct {...@@ -9731,18 +9910,14 @@ pub const FuncGen = struct {
9731 // accum = f(accum, vec[i]);9910 // accum = f(accum, vec[i]);
9732 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");9911 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9733 const element = try self.wip.extractElement(operand_vector, i, "");9912 const element = try self.wip.extractElement(operand_vector, i, "");
9734 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };9913 const new_accum = try self.wip.call(
9735 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(9914 .normal,
9736 self.builder.buildCall(9915 .ccc,
9737 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),9916 .none,
9738 llvm_fn.toLlvm(&o.builder),9917 llvm_fn.typeOf(&o.builder),
9739 &params,9918 llvm_fn.toValue(&o.builder),
9740 params.len,9919 &.{ accum, element },
9741 .C,9920 "",
9742 .Auto,
9743 "",
9744 ),
9745 &self.wip,
9746 );9921 );
9747 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);9922 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
97489923
...@@ -10190,7 +10365,7 @@ pub const FuncGen = struct {...@@ -10190,7 +10365,7 @@ pub const FuncGen = struct {
10190 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),10365 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
10191 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),10366 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
10192 };10367 };
10193 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(10368 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
10194 llvm_fn_ty.toLlvm(&o.builder),10369 llvm_fn_ty.toLlvm(&o.builder),
10195 fn_val,10370 fn_val,
10196 &params,10371 &params,
...@@ -10222,7 +10397,7 @@ pub const FuncGen = struct {...@@ -10222,7 +10397,7 @@ pub const FuncGen = struct {
1022210397
10223 const args: [0]*llvm.Value = .{};10398 const args: [0]*llvm.Value = .{};
10224 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});10399 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(
10226 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),10401 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
10227 llvm_fn,10402 llvm_fn,
10228 &args,10403 &args,
...@@ -10252,12 +10427,15 @@ pub const FuncGen = struct {...@@ -10252,12 +10427,15 @@ pub const FuncGen = struct {
10252 const dimension = pl_op.payload;10427 const dimension = pl_op.payload;
10253 if (dimension >= 3) return o.builder.intValue(.i32, 1);10428 if (dimension >= 3) return o.builder.intValue(.i32, 1);
1025410429
10430 var attributes: Builder.FunctionAttributes.Wip = .{};
10431 defer attributes.deinit(&o.builder);
10432
10255 // Fetch the dispatch pointer, which points to this structure:10433 // Fetch the dispatch pointer, which points to this structure:
10256 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L291310434 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
10257 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});10435 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
10258 const args: [0]*llvm.Value = .{};10436 const args: [0]*llvm.Value = .{};
10259 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);10437 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(
10261 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),10439 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
10262 llvm_fn,10440 llvm_fn,
10263 &args,10441 &args,
...@@ -10266,6 +10444,9 @@ pub const FuncGen = struct {...@@ -10266,6 +10444,9 @@ pub const FuncGen = struct {
10266 .Auto,10444 .Auto,
10267 "",10445 "",
10268 ), &self.wip);10446 ), &self.wip);
10447 try attributes.addRetAttr(.{
10448 .@"align" = comptime Builder.Alignment.fromByteUnits(4),
10449 }, &o.builder);
10269 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);10450 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
1027010451
10271 // Load the work_group_* member from the struct as u16.10452 // Load the work_group_* member from the struct as u16.
...@@ -10298,7 +10479,7 @@ pub const FuncGen = struct {...@@ -10298,7 +10479,7 @@ pub const FuncGen = struct {
10298 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space10479 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
1029910480
10300 const name = try o.builder.string("__zig_err_name_table");10481 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).?);
10302 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));10483 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
10303 error_name_table_global.setLinkage(.Private);10484 error_name_table_global.setLinkage(.Private);
10304 error_name_table_global.setGlobalConstant(.True);10485 error_name_table_global.setGlobalConstant(.True);
...@@ -10751,7 +10932,7 @@ pub const FuncGen = struct {...@@ -10751,7 +10932,7 @@ pub const FuncGen = struct {
10751 );10932 );
1075210933
10753 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(10934 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, ""),
10755 &fg.wip,10936 &fg.wip,
10756 );10937 );
10757 return call;10938 return call;
...@@ -10991,33 +11172,33 @@ fn toLlvmAtomicRmwBinOp(...@@ -10991,33 +11172,33 @@ fn toLlvmAtomicRmwBinOp(
10991 };11172 };
10992}11173}
1099311174
10994fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {11175fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {
10995 return switch (cc) {11176 return switch (cc) {
10996 .Unspecified, .Inline, .Async => .Fast,11177 .Unspecified, .Inline, .Async => .fastcc,
10997 .C, .Naked => .C,11178 .C, .Naked => .ccc,
10998 .Stdcall => .X86_StdCall,11179 .Stdcall => .x86_stdcallcc,
10999 .Fastcall => .X86_FastCall,11180 .Fastcall => .x86_fastcallcc,
11000 .Vectorcall => return switch (target.cpu.arch) {11181 .Vectorcall => return switch (target.cpu.arch) {
11001 .x86, .x86_64 => .X86_VectorCall,11182 .x86, .x86_64 => .x86_vectorcallcc,
11002 .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,11183 .aarch64, .aarch64_be, .aarch64_32 => .aarch64_vector_pcs,
11003 else => unreachable,11184 else => unreachable,
11004 },11185 },
11005 .Thiscall => .X86_ThisCall,11186 .Thiscall => .x86_thiscallcc,
11006 .APCS => .ARM_APCS,11187 .APCS => .arm_apcscc,
11007 .AAPCS => .ARM_AAPCS,11188 .AAPCS => .arm_aapcscc,
11008 .AAPCSVFP => .ARM_AAPCS_VFP,11189 .AAPCSVFP => .arm_aapcs_vfpcc,
11009 .Interrupt => return switch (target.cpu.arch) {11190 .Interrupt => return switch (target.cpu.arch) {
11010 .x86, .x86_64 => .X86_INTR,11191 .x86, .x86_64 => .x86_intrcc,
11011 .avr => .AVR_INTR,11192 .avr => .avr_intrcc,
11012 .msp430 => .MSP430_INTR,11193 .msp430 => .msp430_intrcc,
11013 else => unreachable,11194 else => unreachable,
11014 },11195 },
11015 .Signal => .AVR_SIGNAL,11196 .Signal => .avr_signalcc,
11016 .SysV => .X86_64_SysV,11197 .SysV => .x86_64_sysvcc,
11017 .Win64 => .Win64,11198 .Win64 => .win64cc,
11018 .Kernel => return switch (target.cpu.arch) {11199 .Kernel => return switch (target.cpu.arch) {
11019 .nvptx, .nvptx64 => .PTX_Kernel,11200 .nvptx, .nvptx64 => .ptx_kernel,
11020 .amdgcn => .AMDGPU_KERNEL,11201 .amdgcn => .amdgpu_kernel,
11021 else => unreachable,11202 else => unreachable,
11022 },11203 },
11023 };11204 };
src/codegen/llvm/Builder.zig+1395-52
...@@ -4,13 +4,15 @@ strip: bool,...@@ -4,13 +4,15 @@ strip: bool,
44
5llvm: if (build_options.have_llvm) struct {5llvm: if (build_options.have_llvm) struct {
6 context: *llvm.Context,6 context: *llvm.Context,
7 module: ?*llvm.Module = null,7 module: ?*llvm.Module,
8 target: ?*llvm.Target = null,8 target: ?*llvm.Target,
9 di_builder: ?*llvm.DIBuilder = null,9 di_builder: ?*llvm.DIBuilder,
10 di_compile_unit: ?*llvm.DICompileUnit = null,10 di_compile_unit: ?*llvm.DICompileUnit,
11 types: std.ArrayListUnmanaged(*llvm.Type) = .{},11 attribute_kind_ids: ?*[Attribute.Kind.len]c_uint,
12 globals: std.ArrayListUnmanaged(*llvm.Value) = .{},12 attributes: std.ArrayListUnmanaged(*llvm.Attribute),
13 constants: std.ArrayListUnmanaged(*llvm.Value) = .{},13 types: std.ArrayListUnmanaged(*llvm.Type),
14 globals: std.ArrayListUnmanaged(*llvm.Value),
15 constants: std.ArrayListUnmanaged(*llvm.Value),
14} else void,16} else void,
1517
16source_filename: String,18source_filename: String,
...@@ -18,8 +20,8 @@ data_layout: String,...@@ -18,8 +20,8 @@ data_layout: String,
18target_triple: String,20target_triple: String,
1921
20string_map: std.AutoArrayHashMapUnmanaged(void, void),22string_map: std.AutoArrayHashMapUnmanaged(void, void),
21string_bytes: std.ArrayListUnmanaged(u8),
22string_indices: std.ArrayListUnmanaged(u32),23string_indices: std.ArrayListUnmanaged(u32),
24string_bytes: std.ArrayListUnmanaged(u8),
2325
24types: std.AutoArrayHashMapUnmanaged(String, Type),26types: std.AutoArrayHashMapUnmanaged(String, Type),
25next_unnamed_type: String,27next_unnamed_type: String,
...@@ -28,6 +30,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void),...@@ -28,6 +30,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void),
28type_items: std.ArrayListUnmanaged(Type.Item),30type_items: std.ArrayListUnmanaged(Type.Item),
29type_extra: std.ArrayListUnmanaged(u32),31type_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
31globals: std.AutoArrayHashMapUnmanaged(String, Global),38globals: std.AutoArrayHashMapUnmanaged(String, Global),
32next_unnamed_global: String,39next_unnamed_global: String,
33next_replaced_global: String,40next_replaced_global: String,
...@@ -41,6 +48,7 @@ constant_items: std.MultiArrayList(Constant.Item),...@@ -41,6 +48,7 @@ constant_items: std.MultiArrayList(Constant.Item),
41constant_extra: std.ArrayListUnmanaged(u32),48constant_extra: std.ArrayListUnmanaged(u32),
42constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),49constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
4350
51pub const expected_args_len = 16;
44pub const expected_fields_len = 32;52pub const expected_fields_len = 32;
45pub const expected_gep_indices_len = 8;53pub const expected_gep_indices_len = 8;
46pub const expected_cases_len = 8;54pub const expected_cases_len = 8;
...@@ -65,7 +73,7 @@ pub const String = enum(u32) {...@@ -65,7 +73,7 @@ pub const String = enum(u32) {
65 return self.toIndex() == null;73 return self.toIndex() == null;
66 }74 }
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 {
69 const index = self.toIndex() orelse return null;77 const index = self.toIndex() orelse return null;
70 const start = b.string_indices.items[index];78 const start = b.string_indices.items[index];
71 const end = b.string_indices.items[index + 1];79 const end = b.string_indices.items[index + 1];
...@@ -85,9 +93,9 @@ pub const String = enum(u32) {...@@ -85,9 +93,9 @@ pub const String = enum(u32) {
85 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|93 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
86 @compileError("invalid format string: '" ++ fmt_str ++ "'");94 @compileError("invalid format string: '" ++ fmt_str ++ "'");
87 assert(data.string != .none);95 assert(data.string != .none);
88 const slice = data.string.toSlice(data.builder) orelse96 const sentinel_slice = data.string.slice(data.builder) orelse
89 return writer.print("{d}", .{@intFromEnum(data.string)});97 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(
91 std.mem.indexOfScalar(u8, fmt_str, '@') != null,99 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
92 )];100 )];
93 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or101 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or
...@@ -108,6 +116,7 @@ pub const String = enum(u32) {...@@ -108,6 +116,7 @@ pub const String = enum(u32) {
108 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +116 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
109 @intFromEnum(String.empty))));117 @intFromEnum(String.empty))));
110 }118 }
119
111 fn toIndex(self: String) ?usize {120 fn toIndex(self: String) ?usize {
112 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;121 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
113 }122 }
...@@ -118,7 +127,7 @@ pub const String = enum(u32) {...@@ -118,7 +127,7 @@ pub const String = enum(u32) {
118 return @truncate(std.hash.Wyhash.hash(0, key));127 return @truncate(std.hash.Wyhash.hash(0, key));
119 }128 }
120 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {129 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).?);
122 }131 }
123 };132 };
124};133};
...@@ -290,6 +299,17 @@ pub const Type = enum(u32) {...@@ -290,6 +299,17 @@ pub const Type = enum(u32) {
290 };299 };
291 }300 }
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
293 pub fn isFunction(self: Type, builder: *const Builder) bool {313 pub fn isFunction(self: Type, builder: *const Builder) bool {
294 return switch (self.tag(builder)) {314 return switch (self.tag(builder)) {
295 .function, .vararg_function => true,315 .function, .vararg_function => true,
...@@ -606,7 +626,7 @@ pub const Type = enum(u32) {...@@ -606,7 +626,7 @@ pub const Type = enum(u32) {
606 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);626 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
607 const types = extra.trail.next(extra.data.types_len, Type, data.builder);627 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
608 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);628 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).?});
610 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});630 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
611 for (ints) |int| try writer.print("_{d}", .{int});631 for (ints) |int| try writer.print("_{d}", .{int});
612 try writer.writeByte('t');632 try writer.writeByte('t');
...@@ -641,7 +661,7 @@ pub const Type = enum(u32) {...@@ -641,7 +661,7 @@ pub const Type = enum(u32) {
641 .named_structure => {661 .named_structure => {
642 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);662 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
643 try writer.writeAll("s_");663 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);
645 },665 },
646 }666 }
647 return;667 return;
...@@ -823,6 +843,789 @@ pub const Type = enum(u32) {...@@ -823,6 +843,789 @@ pub const Type = enum(u32) {
823 }843 }
824};844};
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
826pub const Linkage = enum {1629pub const Linkage = enum {
827 external,1630 external,
828 private,1631 private,
...@@ -1053,6 +1856,127 @@ pub const Alignment = enum(u6) {...@@ -1053,6 +1856,127 @@ pub const Alignment = enum(u6) {
1053 }1856 }
1054};1857};
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
1056pub const Global = struct {1980pub const Global = struct {
1057 linkage: Linkage = .external,1981 linkage: Linkage = .external,
1058 preemption: Preemption = .dso_preemptable,1982 preemption: Preemption = .dso_preemptable,
...@@ -1170,7 +2094,7 @@ pub const Global = struct {...@@ -1170,7 +2094,7 @@ pub const Global = struct {
1170 fn updateName(self: Index, builder: *const Builder) void {2094 fn updateName(self: Index, builder: *const Builder) void {
1171 if (!builder.useLibLlvm()) return;2095 if (!builder.useLibLlvm()) return;
1172 const index = @intFromEnum(self.unwrap(builder));2096 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 "";
1174 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);2098 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
1175 }2099 }
11762100
...@@ -1301,6 +2225,8 @@ pub const Variable = struct {...@@ -1301,6 +2225,8 @@ pub const Variable = struct {
13012225
1302pub const Function = struct {2226pub const Function = struct {
1303 global: Global.Index,2227 global: Global.Index,
2228 call_conv: CallConv = CallConv.default,
2229 attributes: FunctionAttributes = .none,
1304 section: String = .none,2230 section: String = .none,
1305 alignment: Alignment = .default,2231 alignment: Alignment = .default,
1306 blocks: []const Block = &.{},2232 blocks: []const Block = &.{},
...@@ -1364,6 +2290,8 @@ pub const Function = struct {...@@ -1364,6 +2290,8 @@ pub const Function = struct {
1364 block,2290 block,
1365 br,2291 br,
1366 br_cond,2292 br_cond,
2293 call,
2294 @"call fast",
1367 extractelement,2295 extractelement,
1368 extractvalue,2296 extractvalue,
1369 fadd,2297 fadd,
...@@ -1454,6 +2382,10 @@ pub const Function = struct {...@@ -1454,6 +2382,10 @@ pub const Function = struct {
1454 @"mul nsw",2382 @"mul nsw",
1455 @"mul nuw",2383 @"mul nuw",
1456 @"mul nuw nsw",2384 @"mul nuw nsw",
2385 @"musttail call",
2386 @"musttail call fast",
2387 @"notail call",
2388 @"notail call fast",
1457 @"or",2389 @"or",
1458 phi,2390 phi,
1459 @"phi fast",2391 @"phi fast",
...@@ -1481,6 +2413,8 @@ pub const Function = struct {...@@ -1481,6 +2413,8 @@ pub const Function = struct {
1481 @"sub nuw",2413 @"sub nuw",
1482 @"sub nuw nsw",2414 @"sub nuw nsw",
1483 @"switch",2415 @"switch",
2416 @"tail call",
2417 @"tail call fast",
1484 trunc,2418 trunc,
1485 udiv,2419 udiv,
1486 @"udiv exact",2420 @"udiv exact",
...@@ -1530,6 +2464,15 @@ pub const Function = struct {...@@ -1530,6 +2464,15 @@ pub const Function = struct {
1530 .@"store volatile",2464 .@"store volatile",
1531 .@"unreachable",2465 .@"unreachable",
1532 => false,2466 => 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,
1533 else => true,2476 else => true,
1534 };2477 };
1535 }2478 }
...@@ -1625,6 +2568,15 @@ pub const Function = struct {...@@ -1625,6 +2568,15 @@ pub const Function = struct {
1625 .@"switch",2568 .@"switch",
1626 .@"unreachable",2569 .@"unreachable",
1627 => .none,2570 => .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),
1628 .extractelement => wip.extraData(ExtractElement, instruction.data)2580 .extractelement => wip.extraData(ExtractElement, instruction.data)
1629 .val.typeOfWip(wip).childType(wip.builder),2581 .val.typeOfWip(wip).childType(wip.builder),
1630 .extractvalue => {2582 .extractvalue => {
...@@ -1813,6 +2765,15 @@ pub const Function = struct {...@@ -1813,6 +2765,15 @@ pub const Function = struct {
1813 .@"switch",2765 .@"switch",
1814 .@"unreachable",2766 .@"unreachable",
1815 => .none,2767 => .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),
1816 .extractelement => function.extraData(ExtractElement, instruction.data)2777 .extractelement => function.extraData(ExtractElement, instruction.data)
1817 .val.typeOf(function_index, builder).childType(builder),2778 .val.typeOf(function_index, builder).childType(builder),
1818 .extractvalue => {2779 .extractvalue => {
...@@ -1955,7 +2916,7 @@ pub const Function = struct {...@@ -1955,7 +2916,7 @@ pub const Function = struct {
1955 return if (wip.builder.strip)2916 return if (wip.builder.strip)
1956 ""2917 ""
1957 else2918 else
1958 wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?;2919 wip.names.items[@intFromEnum(self)].slice(wip.builder).?;
1959 }2920 }
1960 };2921 };
19612922
...@@ -2063,6 +3024,30 @@ pub const Function = struct {...@@ -2063,6 +3024,30 @@ pub const Function = struct {
2063 rhs: Value,3024 rhs: Value,
2064 };3025 };
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
2066 pub const VaArg = struct {3051 pub const VaArg = struct {
2067 list: Value,3052 list: Value,
2068 type: Type,3053 type: Type,
...@@ -2117,8 +3102,17 @@ pub const Function = struct {...@@ -2117,8 +3102,17 @@ pub const Function = struct {
2117 inline for (fields, self.extra[index..][0..fields.len]) |field, value|3102 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
2118 @field(result, field.name) = switch (field.type) {3103 @field(result, field.name) = switch (field.type) {
2119 u32 => value,3104 u32 => value,
2120 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),3105 Alignment,
2121 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),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),
2122 else => @compileError("bad field type: " ++ @typeName(field.type)),3116 else => @compileError("bad field type: " ++ @typeName(field.type)),
2123 };3117 };
2124 return .{3118 return .{
...@@ -2243,7 +3237,7 @@ pub const WipFunction = struct {...@@ -2243,7 +3237,7 @@ pub const WipFunction = struct {
2243 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(3237 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
2244 self.builder.llvm.context.appendBasicBlock(3238 self.builder.llvm.context.appendBasicBlock(
2245 self.function.toLlvm(self.builder),3239 self.function.toLlvm(self.builder),
2246 final_name.toSlice(self.builder).?,3240 final_name.slice(self.builder).?,
2247 ),3241 ),
2248 );3242 );
2249 return index;3243 return index;
...@@ -3162,6 +4156,88 @@ pub const WipFunction = struct {...@@ -3162,6 +4156,88 @@ pub const WipFunction = struct {
3162 return self.selectTag(.@"select fast", cond, lhs, rhs, name);4156 return self.selectTag(.@"select fast", cond, lhs, rhs, name);
3163 }4157 }
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
3165 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {4241 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
3166 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);4242 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
3167 const instruction = try self.addInst(name, .{4243 const instruction = try self.addInst(name, .{
...@@ -3246,8 +4322,17 @@ pub const WipFunction = struct {...@@ -3246,8 +4322,17 @@ pub const WipFunction = struct {
3246 const value = @field(extra, field.name);4322 const value = @field(extra, field.name);
3247 wip_extra.items[wip_extra.index] = switch (field.type) {4323 wip_extra.items[wip_extra.index] = switch (field.type) {
3248 u32 => value,4324 u32 => value,
3249 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),4325 Alignment,
3250 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),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),
3251 else => @compileError("bad field type: " ++ @typeName(field.type)),4336 else => @compileError("bad field type: " ++ @typeName(field.type)),
3252 };4337 };
3253 wip_extra.index += 1;4338 wip_extra.index += 1;
...@@ -3256,13 +4341,14 @@ pub const WipFunction = struct {...@@ -3256,13 +4341,14 @@ pub const WipFunction = struct {
3256 }4341 }
32574342
3258 fn appendSlice(wip_extra: *@This(), slice: anytype) void {4343 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");
3260 const data: []const u32 = @ptrCast(slice);4346 const data: []const u32 = @ptrCast(slice);
3261 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);4347 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
3262 wip_extra.index += @intCast(data.len);4348 wip_extra.index += @intCast(data.len);
3263 }4349 }
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 {
3266 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|4352 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
3267 extra.* = @intFromEnum(ctx.map(val));4353 extra.* = @intFromEnum(ctx.map(val));
3268 wip_extra.index += @intCast(vals.len);4354 wip_extra.index += @intCast(vals.len);
...@@ -3494,6 +4580,26 @@ pub const WipFunction = struct {...@@ -3494,6 +4580,26 @@ pub const WipFunction = struct {
3494 .@"else" = extra.@"else",4580 .@"else" = extra.@"else",
3495 });4581 });
3496 },4582 },
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 },
3497 .extractvalue => {4603 .extractvalue => {
3498 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);4604 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
3499 const indices = extra.trail.next(extra.data.indices_len, u32, self);4605 const indices = extra.trail.next(extra.data.indices_len, u32, self);
...@@ -3517,7 +4623,7 @@ pub const WipFunction = struct {...@@ -3517,7 +4623,7 @@ pub const WipFunction = struct {
3517 .base = instructions.map(extra.data.base),4623 .base = instructions.map(extra.data.base),
3518 .indices_len = extra.data.indices_len,4624 .indices_len = extra.data.indices_len,
3519 });4625 });
3520 wip_extra.appendValues(indices, instructions);4626 wip_extra.appendMappedValues(indices, instructions);
3521 },4627 },
3522 .insertelement => {4628 .insertelement => {
3523 const extra = self.extraData(Instruction.InsertElement, instruction.data);4629 const extra = self.extraData(Instruction.InsertElement, instruction.data);
...@@ -3559,7 +4665,7 @@ pub const WipFunction = struct {...@@ -3559,7 +4665,7 @@ pub const WipFunction = struct {
3559 instruction.data = wip_extra.addExtra(Instruction.Phi{4665 instruction.data = wip_extra.addExtra(Instruction.Phi{
3560 .type = extra.data.type,4666 .type = extra.data.type,
3561 });4667 });
3562 wip_extra.appendValues(incoming_vals, instructions);4668 wip_extra.appendMappedValues(incoming_vals, instructions);
3563 wip_extra.appendSlice(incoming_blocks);4669 wip_extra.appendSlice(incoming_blocks);
3564 },4670 },
3565 .select,4671 .select,
...@@ -3932,8 +5038,17 @@ pub const WipFunction = struct {...@@ -3932,8 +5038,17 @@ pub const WipFunction = struct {
3932 const value = @field(extra, field.name);5038 const value = @field(extra, field.name);
3933 self.extra.appendAssumeCapacity(switch (field.type) {5039 self.extra.appendAssumeCapacity(switch (field.type) {
3934 u32 => value,5040 u32 => value,
3935 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),5041 Alignment,
3936 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),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),
3937 else => @compileError("bad field type: " ++ @typeName(field.type)),5052 else => @compileError("bad field type: " ++ @typeName(field.type)),
3938 });5053 });
3939 }5054 }
...@@ -3971,8 +5086,17 @@ pub const WipFunction = struct {...@@ -3971,8 +5086,17 @@ pub const WipFunction = struct {
3971 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|5086 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
3972 @field(result, field.name) = switch (field.type) {5087 @field(result, field.name) = switch (field.type) {
3973 u32 => value,5088 u32 => value,
3974 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),5089 Alignment,
3975 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),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),
3976 else => @compileError("bad field type: " ++ @typeName(field.type)),5100 else => @compileError("bad field type: " ++ @typeName(field.type)),
3977 };5101 };
3978 return .{5102 return .{
...@@ -4294,7 +5418,7 @@ pub const Constant = enum(u32) {...@@ -4294,7 +5418,7 @@ pub const Constant = enum(u32) {
4294 .string,5418 .string,
4295 .string_null,5419 .string_null,
4296 => builder.arrayTypeAssumeCapacity(5420 => builder.arrayTypeAssumeCapacity(
4297 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +5421 @as(String, @enumFromInt(item.data)).slice(builder).?.len +
4298 @intFromBool(item.tag == .string_null),5422 @intFromBool(item.tag == .string_null),
4299 .i8,5423 .i8,
4300 ),5424 ),
...@@ -4821,8 +5945,8 @@ pub fn init(options: Options) InitError!Builder {...@@ -4821,8 +5945,8 @@ pub fn init(options: Options) InitError!Builder {
4821 .target_triple = .none,5945 .target_triple = .none,
48225946
4823 .string_map = .{},5947 .string_map = .{},
4824 .string_bytes = .{},
4825 .string_indices = .{},5948 .string_indices = .{},
5949 .string_bytes = .{},
48265950
4827 .types = .{},5951 .types = .{},
4828 .next_unnamed_type = @enumFromInt(0),5952 .next_unnamed_type = @enumFromInt(0),
...@@ -4831,6 +5955,11 @@ pub fn init(options: Options) InitError!Builder {...@@ -4831,6 +5955,11 @@ pub fn init(options: Options) InitError!Builder {
4831 .type_items = .{},5955 .type_items = .{},
4832 .type_extra = .{},5956 .type_extra = .{},
48335957
5958 .attributes = .{},
5959 .attributes_map = .{},
5960 .attributes_indices = .{},
5961 .attributes_extra = .{},
5962
4834 .globals = .{},5963 .globals = .{},
4835 .next_unnamed_global = @enumFromInt(0),5964 .next_unnamed_global = @enumFromInt(0),
4836 .next_replaced_global = .none,5965 .next_replaced_global = .none,
...@@ -4844,7 +5973,18 @@ pub fn init(options: Options) InitError!Builder {...@@ -4844,7 +5973,18 @@ pub fn init(options: Options) InitError!Builder {
4844 .constant_extra = .{},5973 .constant_extra = .{},
4845 .constant_limbs = .{},5974 .constant_limbs = .{},
4846 };5975 };
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 };
4848 errdefer self.deinit();5988 errdefer self.deinit();
48495989
4850 try self.string_indices.append(self.gpa, 0);5990 try self.string_indices.append(self.gpa, 0);
...@@ -4853,7 +5993,7 @@ pub fn init(options: Options) InitError!Builder {...@@ -4853,7 +5993,7 @@ pub fn init(options: Options) InitError!Builder {
4853 if (options.name.len > 0) self.source_filename = try self.string(options.name);5993 if (options.name.len > 0) self.source_filename = try self.string(options.name);
4854 self.initializeLLVMTarget(options.target.cpu.arch);5994 self.initializeLLVMTarget(options.target.cpu.arch);
4855 if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(5995 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,
4857 self.llvm.context,5997 self.llvm.context,
4858 );5998 );
48595999
...@@ -4864,20 +6004,20 @@ pub fn init(options: Options) InitError!Builder {...@@ -4864,20 +6004,20 @@ pub fn init(options: Options) InitError!Builder {
4864 var error_message: [*:0]const u8 = undefined;6004 var error_message: [*:0]const u8 = undefined;
4865 var target: *llvm.Target = undefined;6005 var target: *llvm.Target = undefined;
4866 if (llvm.Target.getFromTriple(6006 if (llvm.Target.getFromTriple(
4867 self.target_triple.toSlice(&self).?,6007 self.target_triple.slice(&self).?,
4868 &target,6008 &target,
4869 &error_message,6009 &error_message,
4870 ).toBool()) {6010 ).toBool()) {
4871 defer llvm.disposeMessage(error_message);6011 defer llvm.disposeMessage(error_message);
48726012
4873 log.err("LLVM failed to parse '{s}': {s}", .{6013 log.err("LLVM failed to parse '{s}': {s}", .{
4874 self.target_triple.toSlice(&self).?,6014 self.target_triple.slice(&self).?,
4875 error_message,6015 error_message,
4876 });6016 });
4877 return InitError.InvalidLlvmTriple;6017 return InitError.InvalidLlvmTriple;
4878 }6018 }
4879 self.llvm.target = target;6019 self.llvm.target = target;
4880 self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?);6020 self.llvm.module.?.setTarget(self.target_triple.slice(&self).?);
4881 }6021 }
4882 }6022 }
48836023
...@@ -4902,6 +6042,16 @@ pub fn init(options: Options) InitError!Builder {...@@ -4902,6 +6042,16 @@ pub fn init(options: Options) InitError!Builder {
4902 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);6042 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
4903 }6043 }
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
4905 assert(try self.intConst(.i1, 0) == .false);6055 assert(try self.intConst(.i1, 0) == .false);
4906 assert(try self.intConst(.i1, 1) == .true);6056 assert(try self.intConst(.i1, 1) == .true);
4907 assert(try self.noneConst(.token) == .none);6057 assert(try self.noneConst(.token) == .none);
...@@ -4911,8 +6061,8 @@ pub fn init(options: Options) InitError!Builder {...@@ -4911,8 +6061,8 @@ pub fn init(options: Options) InitError!Builder {
49116061
4912pub fn deinit(self: *Builder) void {6062pub fn deinit(self: *Builder) void {
4913 self.string_map.deinit(self.gpa);6063 self.string_map.deinit(self.gpa);
4914 self.string_bytes.deinit(self.gpa);
4915 self.string_indices.deinit(self.gpa);6064 self.string_indices.deinit(self.gpa);
6065 self.string_bytes.deinit(self.gpa);
49166066
4917 self.types.deinit(self.gpa);6067 self.types.deinit(self.gpa);
4918 self.next_unique_type_id.deinit(self.gpa);6068 self.next_unique_type_id.deinit(self.gpa);
...@@ -4920,6 +6070,11 @@ pub fn deinit(self: *Builder) void {...@@ -4920,6 +6070,11 @@ pub fn deinit(self: *Builder) void {
4920 self.type_items.deinit(self.gpa);6070 self.type_items.deinit(self.gpa);
4921 self.type_extra.deinit(self.gpa);6071 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
4923 self.globals.deinit(self.gpa);6078 self.globals.deinit(self.gpa);
4924 self.next_unique_global_id.deinit(self.gpa);6079 self.next_unique_global_id.deinit(self.gpa);
4925 self.aliases.deinit(self.gpa);6080 self.aliases.deinit(self.gpa);
...@@ -4936,6 +6091,8 @@ pub fn deinit(self: *Builder) void {...@@ -4936,6 +6091,8 @@ pub fn deinit(self: *Builder) void {
4936 self.llvm.constants.deinit(self.gpa);6091 self.llvm.constants.deinit(self.gpa);
4937 self.llvm.globals.deinit(self.gpa);6092 self.llvm.globals.deinit(self.gpa);
4938 self.llvm.types.deinit(self.gpa);6093 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);
4939 if (self.llvm.di_builder) |di_builder| di_builder.dispose();6096 if (self.llvm.di_builder) |di_builder| di_builder.dispose();
4940 if (self.llvm.module) |module| module.dispose();6097 if (self.llvm.module) |module| module.dispose();
4941 self.llvm.context.dispose();6098 self.llvm.context.dispose();
...@@ -5230,7 +6387,7 @@ pub fn structType(...@@ -5230,7 +6387,7 @@ pub fn structType(
52306387
5231pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {6388pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
5232 try self.string_map.ensureUnusedCapacity(self.gpa, 1);6389 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5233 if (name.toSlice(self)) |id| {6390 if (name.slice(self)) |id| {
5234 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});6391 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
5235 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);6392 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
5236 }6393 }
...@@ -5268,6 +6425,99 @@ pub fn namedTypeSetBody(...@@ -5268,6 +6425,99 @@ pub fn namedTypeSetBody(
5268 }6425 }
5269}6426}
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
5271pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {6521pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
5272 assert(!name.isAnon());6522 assert(!name.isAnon());
5273 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);6523 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
...@@ -5295,7 +6545,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo...@@ -5295,7 +6545,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
52956545
5296 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);6546 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
5297 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;6547 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.* });
5299 unique_gop.value_ptr.* += 1;6549 unique_gop.value_ptr.* += 1;
5300 }6550 }
5301}6551}
...@@ -5309,8 +6559,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta...@@ -5309,8 +6559,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta
5309 switch (@typeInfo(@TypeOf(value))) {6559 switch (@typeInfo(@TypeOf(value))) {
5310 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),6560 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
5311 .ComptimeInt => std.math.big.int.calcLimbLen(value),6561 .ComptimeInt => std.math.big.int.calcLimbLen(value),
5312 else => @compileError("intConst expected an integral value, got " ++6562 else => @compileError(
5313 @typeName(@TypeOf(value))),6563 "intConst expected an integral value, got " ++ @typeName(@TypeOf(value)),
6564 ),
5314 }6565 }
5315 ]std.math.big.Limb = undefined;6566 ]std.math.big.Limb = undefined;
5316 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());6567 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
...@@ -5770,7 +7021,7 @@ pub fn printUnbuffered(...@@ -5770,7 +7021,7 @@ pub fn printUnbuffered(
5770 \\; ModuleID = '{s}'7021 \\; ModuleID = '{s}'
5771 \\source_filename = {"}7022 \\source_filename = {"}
5772 \\7023 \\
5773 , .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) });7024 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
5774 if (self.data_layout != .none) try writer.print(7025 if (self.data_layout != .none) try writer.print(
5775 \\target datalayout = {"}7026 \\target datalayout = {"}
5776 \\7027 \\
...@@ -5780,11 +7031,13 @@ pub fn printUnbuffered(...@@ -5780,11 +7031,13 @@ pub fn printUnbuffered(
5780 \\7031 \\
5781 , .{self.target_triple.fmt(self)});7032 , .{self.target_triple.fmt(self)});
5782 try writer.writeByte('\n');7033 try writer.writeByte('\n');
7034
5783 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(7035 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
5784 \\%{} = type {}7036 \\%{} = type {}
5785 \\7037 \\
5786 , .{ id.fmt(self), ty.fmt(self) });7038 , .{ id.fmt(self), ty.fmt(self) });
5787 try writer.writeByte('\n');7039 try writer.writeByte('\n');
7040
5788 for (self.variables.items) |variable| {7041 for (self.variables.items) |variable| {
5789 if (variable.global.getReplacement(self) != .none) continue;7042 if (variable.global.getReplacement(self) != .none) continue;
5790 const global = variable.global.ptrConst(self);7043 const global = variable.global.ptrConst(self);
...@@ -5808,28 +7061,42 @@ pub fn printUnbuffered(...@@ -5808,28 +7061,42 @@ pub fn printUnbuffered(
5808 });7061 });
5809 }7062 }
5810 try writer.writeByte('\n');7063 try writer.writeByte('\n');
7064
7065 var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{};
7066 defer attribute_groups.deinit(self.gpa);
5811 for (0.., self.functions.items) |function_i, function| {7067 for (0.., self.functions.items) |function_i, function| {
5812 const function_index: Function.Index = @enumFromInt(function_i);7068 const function_index: Function.Index = @enumFromInt(function_i);
5813 if (function.global.getReplacement(self) != .none) continue;7069 if (function.global.getReplacement(self) != .none) continue;
5814 const global = function.global.ptrConst(self);7070 const global = function.global.ptrConst(self);
5815 const params_len = global.type.functionParameters(self).len;7071 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)});
5816 try writer.print(7077 try writer.print(
5817 \\{s}{}{}{}{} {} {}(7078 \\{s}{}{}{}{}{}{"} {} {}(
5818 , .{7079 , .{
5819 if (function.instructions.len > 0) "define" else "declare",7080 if (function.instructions.len > 0) "define" else "declare",
5820 global.linkage,7081 global.linkage,
5821 global.preemption,7082 global.preemption,
5822 global.visibility,7083 global.visibility,
5823 global.dll_storage_class,7084 global.dll_storage_class,
7085 function.call_conv,
7086 function.attributes.ret(self).fmt(self),
5824 global.type.functionReturn(self).fmt(self),7087 global.type.functionReturn(self).fmt(self),
5825 function.global.fmt(self),7088 function.global.fmt(self),
5826 });7089 });
5827 for (0..params_len) |arg| {7090 for (0..params_len) |arg| {
5828 if (arg > 0) try writer.writeAll(", ");7091 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 });
5829 if (function.instructions.len > 0)7098 if (function.instructions.len > 0)
5830 try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)})7099 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
5831 else
5832 try writer.print("{%}", .{global.type.functionParameters(self)[arg].fmt(self)});
5833 }7100 }
5834 switch (global.type.functionKind(self)) {7101 switch (global.type.functionKind(self)) {
5835 .normal => {},7102 .normal => {},
...@@ -5838,7 +7105,11 @@ pub fn printUnbuffered(...@@ -5838,7 +7105,11 @@ pub fn printUnbuffered(
5838 try writer.writeAll("...");7105 try writer.writeAll("...");
5839 },7106 },
5840 }7107 }
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});
5842 if (function.instructions.len > 0) {7113 if (function.instructions.len > 0) {
5843 var block_incoming_len: u32 = undefined;7114 var block_incoming_len: u32 = undefined;
5844 try writer.writeAll(" {\n");7115 try writer.writeAll(" {\n");
...@@ -5992,6 +7263,48 @@ pub fn printUnbuffered(...@@ -5992,6 +7263,48 @@ pub fn printUnbuffered(
5992 extra.@"else".toInst(&function).fmt(function_index, self),7263 extra.@"else".toInst(&function).fmt(function_index, self),
5993 });7264 });
5994 },7265 },
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 },
5995 .extractelement => |tag| {7308 .extractelement => |tag| {
5996 const extra =7309 const extra =
5997 function.extraData(Function.Instruction.ExtractElement, instruction.data);7310 function.extraData(Function.Instruction.ExtractElement, instruction.data);
...@@ -6218,6 +7531,12 @@ pub fn printUnbuffered(...@@ -6218,6 +7531,12 @@ pub fn printUnbuffered(
6218 }7531 }
6219 try writer.writeAll("\n\n");7532 try writer.writeAll("\n\n");
6220 }7533 }
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) });
6221}7540}
62227541
6223pub inline fn useLibLlvm(self: *const Builder) bool {7542pub inline fn useLibLlvm(self: *const Builder) bool {
...@@ -6238,7 +7557,7 @@ fn isValidIdentifier(id: []const u8) bool {...@@ -6238,7 +7557,7 @@ fn isValidIdentifier(id: []const u8) bool {
6238fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {7557fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {
6239 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);7558 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);
6240 try self.string_map.ensureUnusedCapacity(self.gpa, 1);7559 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
6241 if (name.toSlice(self)) |id| {7560 if (name.slice(self)) |id| {
6242 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});7561 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
6243 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);7562 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
6244 }7563 }
...@@ -6528,14 +7847,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {...@@ -6528,14 +7847,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
6528 const result: Type = @enumFromInt(gop.index);7847 const result: Type = @enumFromInt(gop.index);
6529 type_gop.value_ptr.* = result;7848 type_gop.value_ptr.* = result;
6530 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(7849 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 ""),
6532 );7851 );
6533 return result;7852 return result;
6534 }7853 }
65357854
6536 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);7855 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
6537 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;7856 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.* });
6539 unique_gop.value_ptr.* += 1;7858 unique_gop.value_ptr.* += 1;
6540 }7859 }
6541}7860}
...@@ -6636,6 +7955,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI...@@ -6636,6 +7955,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI
6636 return self.typeExtraDataTrail(T, index).data;7955 return self.typeExtraDataTrail(T, index).data;
6637}7956}
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
6639fn bigIntConstAssumeCapacity(7982fn bigIntConstAssumeCapacity(
6640 self: *Builder,7983 self: *Builder,
6641 ty: Type,7984 ty: Type,
...@@ -7073,7 +8416,7 @@ fn arrayConstAssumeCapacity(...@@ -7073,7 +8416,7 @@ fn arrayConstAssumeCapacity(
7073}8416}
70748417
7075fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {8418fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7076 const slice = val.toSlice(self).?;8419 const slice = val.slice(self).?;
7077 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);8420 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
7078 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);8421 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
7079 const result = self.getOrPutConstantNoExtraAssumeCapacity(8422 const result = self.getOrPutConstantNoExtraAssumeCapacity(
...@@ -7086,7 +8429,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {...@@ -7086,7 +8429,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7086}8429}
70878430
7088fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {8431fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
7089 const slice = val.toSlice(self).?;8432 const slice = val.slice(self).?;
7090 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);8433 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
7091 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);8434 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
7092 const result = self.getOrPutConstantNoExtraAssumeCapacity(8435 const result = self.getOrPutConstantNoExtraAssumeCapacity(
src/codegen/llvm/bindings.zig+32-6
...@@ -26,10 +26,13 @@ pub const Context = opaque {...@@ -26,10 +26,13 @@ pub const Context = opaque {
26 extern fn LLVMContextDispose(C: *Context) void;26 extern fn LLVMContextDispose(C: *Context) void;
2727
28 pub const createEnumAttribute = LLVMCreateEnumAttribute;28 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
31 pub const createStringAttribute = LLVMCreateStringAttribute;34 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
34 pub const pointerType = LLVMPointerTypeInContext;37 pub const pointerType = LLVMPointerTypeInContext;
35 extern fn LLVMPointerTypeInContext(C: *Context, AddressSpace: c_uint) *Type;38 extern fn LLVMPointerTypeInContext(C: *Context, AddressSpace: c_uint) *Type;
...@@ -309,12 +312,18 @@ pub const Value = opaque {...@@ -309,12 +312,18 @@ pub const Value = opaque {
309 pub const setAlignment = LLVMSetAlignment;312 pub const setAlignment = LLVMSetAlignment;
310 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;313 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
311314
312 pub const getFunctionCallConv = LLVMGetFunctionCallConv;
313 extern fn LLVMGetFunctionCallConv(Fn: *Value) CallConv;
314
315 pub const setFunctionCallConv = LLVMSetFunctionCallConv;315 pub const setFunctionCallConv = LLVMSetFunctionCallConv;
316 extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void;316 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
318 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;327 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;
319 extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;328 extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;
320329
...@@ -642,7 +651,17 @@ pub const Builder = opaque {...@@ -642,7 +651,17 @@ pub const Builder = opaque {
642 Name: [*:0]const u8,651 Name: [*:0]const u8,
643 ) *Value;652 ) *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;
646 extern fn ZigLLVMBuildCall(665 extern fn ZigLLVMBuildCall(
647 *Builder,666 *Builder,
648 *Type,667 *Type,
...@@ -1605,6 +1624,13 @@ pub const CallAttr = enum(c_int) {...@@ -1605,6 +1624,13 @@ pub const CallAttr = enum(c_int) {
1605 AlwaysInline,1624 AlwaysInline,
1606};1625};
16071626
1627pub const TailCallKind = enum(c_uint) {
1628 None,
1629 Tail,
1630 MustTail,
1631 NoTail,
1632};
1633
1608pub const DLLStorageClass = enum(c_uint) {1634pub const DLLStorageClass = enum(c_uint) {
1609 Default,1635 Default,
1610 DLLImport,1636 DLLImport,
src/zig_llvm.cpp+4-6
...@@ -453,6 +453,10 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,...@@ -453,6 +453,10 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
453 return wrap(call_inst);453 return wrap(call_inst);
454}454}
455455
456ZIG_EXTERN_C void ZigLLVMSetTailCallKind(LLVMValueRef Call, CallInst::TailCallKind TailCallKind) {
457 unwrap<CallInst>(Call)->setTailCallKind(TailCallKind);
458}
459
456void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {460void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
457 if (isa<Function>(unwrap(Val))) {461 if (isa<Function>(unwrap(Val))) {
458 unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));462 unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
...@@ -461,7 +465,6 @@ void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef...@@ -461,7 +465,6 @@ void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef
461 }465 }
462}466}
463467
464
465LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,468LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
466 LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)469 LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
467{470{
...@@ -1116,11 +1119,6 @@ void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const ch...@@ -1116,11 +1119,6 @@ void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const ch
1116 func->addFnAttr(attr_name, attr_value);1119 func->addFnAttr(attr_name, attr_value);
1117}1120}
11181121
1119void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) {
1120 Function *func = unwrap<Function>(fn_ref);
1121 func->addFnAttr(Attribute::Cold);
1122}
1123
1124void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {1122void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
1125 cl::ParseCommandLineOptions(argc, argv);1123 cl::ParseCommandLineOptions(argc, argv);
1126}1124}