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