authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-24 02:16:00-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-24 02:16:00-07:00
logd21d1d4ba25701410b9ae99921326f8bfc8a44dd
treec56738ededf5966ce448e57be393996f76976426
parent98c7aec4e4ae7deac5e802a8c592c2d91b6b77af
parent3fc2e36de2d125b2de255b03abc24bea30899caf
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16487 from jacobly0/llvm-builder

llvm: incremental Builder improvements

12 files changed, 2883 insertions(+), 863 deletions(-)

lib/std/Build/Step.zig+3-1
......@@ -294,7 +294,7 @@ pub fn evalZigProcess(
294294 s: *Step,
295295 argv: []const []const u8,
296296 prog_node: *std.Progress.Node,
297) ![]const u8 {
297) !?[]const u8 {
298298 assert(argv.len != 0);
299299 const b = s.owner;
300300 const arena = b.allocator;
......@@ -423,6 +423,8 @@ pub fn evalZigProcess(
423423 });
424424 }
425425
426 if (s.cast(Compile)) |compile| if (compile.emit_bin == .no_emit) return result;
427
426428 return result orelse return s.fail(
427429 "the following command failed to communicate the compilation result:\n{s}",
428430 .{try allocPrintCmd(arena, null, argv)},
lib/std/Build/Step/Compile.zig+4-3
......@@ -1997,7 +1997,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
19971997 try zig_args.append(resolved_args_file);
19981998 }
19991999
2000 const output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) {
2000 const maybe_output_bin_path = step.evalZigProcess(zig_args.items, prog_node) catch |err| switch (err) {
20012001 error.NeedCompileErrorCheck => {
20022002 assert(self.expect_errors.len != 0);
20032003 try checkCompileErrors(self);
......@@ -2005,10 +2005,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
20052005 },
20062006 else => |e| return e,
20072007 };
2008 const output_dir = fs.path.dirname(output_bin_path).?;
20092008
20102009 // Update generated files
2011 {
2010 if (maybe_output_bin_path) |output_bin_path| {
2011 const output_dir = fs.path.dirname(output_bin_path).?;
2012
20122013 self.output_dirname_source.path = output_dir;
20132014
20142015 self.output_path_source.path = b.pathJoin(
lib/std/Build/Step/TranslateC.zig+2-2
......@@ -148,8 +148,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
148148
149149 const output_path = try step.evalZigProcess(argv_list.items, prog_node);
150150
151 self.out_basename = fs.path.basename(output_path);
152 const output_dir = fs.path.dirname(output_path).?;
151 self.out_basename = fs.path.basename(output_path.?);
152 const output_dir = fs.path.dirname(output_path.?).?;
153153
154154 self.output_file.path = try fs.path.join(
155155 b.allocator,
lib/std/target.zig+7-3
......@@ -1912,7 +1912,7 @@ pub const Target = struct {
19121912 return switch (target.cpu.arch) {
19131913 .amdgcn => 4,
19141914 .x86 => switch (target.os.tag) {
1915 .windows => 4,
1915 .windows, .uefi => 4,
19161916 else => 16,
19171917 },
19181918 .arm,
......@@ -1931,8 +1931,6 @@ pub const Target = struct {
19311931 .bpfel,
19321932 .mips64,
19331933 .mips64el,
1934 .powerpc64,
1935 .powerpc64le,
19361934 .riscv32,
19371935 .riscv64,
19381936 .sparc64,
......@@ -1941,6 +1939,12 @@ pub const Target = struct {
19411939 .wasm32,
19421940 .wasm64,
19431941 => 16,
1942 .powerpc64,
1943 .powerpc64le,
1944 => switch (target.os.tag) {
1945 else => 8,
1946 .linux => 16,
1947 },
19441948 else => @divExact(target.ptrBitWidth(), 8),
19451949 };
19461950 }
src/Compilation.zig+1
......@@ -1053,6 +1053,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
10531053 buf.appendSliceAssumeCapacity(",");
10541054 }
10551055 }
1056 if (buf.items.len == 0) break :blk "";
10561057 assert(mem.endsWith(u8, buf.items, ","));
10571058 buf.items[buf.items.len - 1] = 0;
10581059 buf.shrinkAndFree(buf.items.len);
src/codegen/llvm.zig+505-331
......@@ -340,7 +340,6 @@ const DataLayoutBuilder = struct {
340340 _: std.fmt.FormatOptions,
341341 writer: anytype,
342342 ) @TypeOf(writer).Error!void {
343 const is_aarch64_windows = self.target.cpu.arch == .aarch64 and self.target.os.tag == .windows;
344343 try writer.writeByte(switch (self.target.cpu.arch.endian()) {
345344 .Little => 'e',
346345 .Big => 'E',
......@@ -359,7 +358,7 @@ const DataLayoutBuilder = struct {
359358 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
360359 // Other symbols get a `_` prefix.
361360 .coff => switch (self.target.os.tag) {
362 .windows => switch (self.target.cpu.arch) {
361 .uefi, .windows => switch (self.target.cpu.arch) {
363362 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
364363 // prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
365364 //`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
......@@ -407,7 +406,8 @@ const DataLayoutBuilder = struct {
407406 };
408407 if (self.target.cpu.arch == .aarch64_32) continue;
409408 if (!info.force_in_data_layout and matches_default and
410 self.target.cpu.arch != .riscv64 and !is_aarch64_windows and
409 self.target.cpu.arch != .riscv64 and !(self.target.cpu.arch == .aarch64 and
410 (self.target.os.tag == .uefi or self.target.os.tag == .windows)) and
411411 self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue;
412412 try writer.writeAll("-p");
413413 if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)});
......@@ -423,7 +423,7 @@ const DataLayoutBuilder = struct {
423423 if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer);
424424 try self.typeAlignment(.integer, 8, 8, 8, false, writer);
425425 try self.typeAlignment(.integer, 16, 16, 16, false, writer);
426 try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer);
426 try self.typeAlignment(.integer, 32, 32, 32, false, writer);
427427 try self.typeAlignment(.integer, 64, 32, 64, false, writer);
428428 try self.typeAlignment(.integer, 128, 32, 64, false, writer);
429429 if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
......@@ -453,8 +453,15 @@ const DataLayoutBuilder = struct {
453453 try self.typeAlignment(.vector, 128, 128, 128, true, writer);
454454 },
455455 }
456 if (self.target.os.tag != .windows and self.target.cpu.arch != .avr)
457 try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
456 const swap_agg_nat = switch (self.target.cpu.arch) {
457 .x86, .x86_64 => switch (self.target.os.tag) {
458 .uefi, .windows => true,
459 else => false,
460 },
461 .avr => true,
462 else => false,
463 };
464 if (!swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
458465 for (@as([]const u24, switch (self.target.cpu.arch) {
459466 .avr => &.{8},
460467 .msp430 => &.{ 8, 16 },
......@@ -498,6 +505,7 @@ const DataLayoutBuilder = struct {
498505 0 => try writer.print("-n{d}", .{natural}),
499506 else => try writer.print(":{d}", .{natural}),
500507 };
508 if (swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
501509 if (self.target.cpu.arch == .hexagon) {
502510 try self.typeAlignment(.integer, 64, 64, 64, true, writer);
503511 try self.typeAlignment(.integer, 32, 32, 32, true, writer);
......@@ -506,11 +514,9 @@ const DataLayoutBuilder = struct {
506514 try self.typeAlignment(.float, 32, 32, 32, true, writer);
507515 try self.typeAlignment(.float, 64, 64, 64, true, writer);
508516 }
509 if (self.target.os.tag == .windows or self.target.cpu.arch == .avr)
510 try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
511517 const stack_abi = self.target.stackAlignment() * 8;
512 if (self.target.os.tag == .windows or self.target.cpu.arch == .msp430 or
513 stack_abi != ptr_bit_width)
518 if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
519 self.target.cpu.arch == .msp430 or stack_abi != ptr_bit_width)
514520 try writer.print("-S{d}", .{stack_abi});
515521 switch (self.target.cpu.arch) {
516522 .hexagon, .ve => {
......@@ -571,22 +577,21 @@ const DataLayoutBuilder = struct {
571577 .integer => {
572578 if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
573579 abi = @min(abi, self.target.maxIntAlignment() * 8);
574 switch (self.target.os.tag) {
575 .linux => switch (self.target.cpu.arch) {
576 .aarch64,
577 .aarch64_be,
578 .aarch64_32,
579 .mips,
580 .mipsel,
581 => pref = @max(pref, 32),
582 else => {},
583 },
584 else => {},
585 }
586580 switch (self.target.cpu.arch) {
587581 .aarch64,
588582 .aarch64_be,
589583 .aarch64_32,
584 => if (size == 128) {
585 abi = size;
586 pref = size;
587 } else switch (self.target.os.tag) {
588 .macos => {},
589 .uefi, .windows => {
590 pref = size;
591 force_abi = size >= 32;
592 },
593 else => pref = @max(pref, 32),
594 },
590595 .bpfeb,
591596 .bpfel,
592597 .nvptx,
......@@ -597,6 +602,9 @@ const DataLayoutBuilder = struct {
597602 pref = size;
598603 },
599604 .hexagon => force_abi = true,
605 .mips,
606 .mipsel,
607 => pref = @max(pref, 32),
600608 .mips64,
601609 .mips64el,
602610 => if (size <= 32) {
......@@ -617,7 +625,8 @@ const DataLayoutBuilder = struct {
617625 128 => abi = 64,
618626 else => {},
619627 }
620 } else if ((self.target.cpu.arch.isPPC64() and (size == 256 or size == 512)) or
628 } else if ((self.target.cpu.arch.isPPC64() and self.target.os.tag == .linux and
629 (size == 256 or size == 512)) or
621630 (self.target.cpu.arch.isNvptx() and (size == 16 or size == 32)))
622631 {
623632 force_abi = true;
......@@ -646,17 +655,21 @@ const DataLayoutBuilder = struct {
646655 .hexagon => if (size == 32 or size == 64) {
647656 force_abi = true;
648657 },
649 .aarch64_32 => if (size == 128) {
658 .aarch64_32, .amdgcn => if (size == 128) {
650659 abi = size;
651660 pref = size;
652661 },
662 .wasm32, .wasm64 => if (self.target.os.tag == .emscripten and size == 128) {
663 abi = 64;
664 pref = 64;
665 },
653666 .ve => if (size == 64) {
654667 abi = size;
655668 pref = size;
656669 },
657670 else => {},
658671 },
659 .aggregate => if (self.target.os.tag == .windows or
672 .aggregate => if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
660673 self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
661674 {
662675 pref = @min(pref, self.target.ptrBitWidth());
......@@ -794,7 +807,7 @@ pub const Object = struct {
794807 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
795808 DW.LANG.C99,
796809 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
797 producer.toSlice(&builder).?,
810 producer.slice(&builder).?,
798811 options.optimize_mode != .Debug,
799812 "", // flags
800813 0, // runtime version
......@@ -830,7 +843,7 @@ pub const Object = struct {
830843
831844 target_machine = llvm.TargetMachine.create(
832845 builder.llvm.target.?,
833 builder.target_triple.toSlice(&builder).?,
846 builder.target_triple.slice(&builder).?,
834847 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
835848 options.llvm_cpu_features,
836849 opt_level,
......@@ -861,7 +874,7 @@ pub const Object = struct {
861874 defer llvm.disposeMessage(rep);
862875 std.testing.expectEqualStrings(
863876 std.mem.span(rep),
864 builder.data_layout.toSlice(&builder).?,
877 builder.data_layout.slice(&builder).?,
865878 ) catch unreachable;
866879 }
867880 }
......@@ -963,7 +976,7 @@ pub const Object = struct {
963976
964977 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
965978 global_index.toConst(),
966 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),
979 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len),
967980 });
968981 }
969982
......@@ -1021,15 +1034,11 @@ pub const Object = struct {
10211034
10221035 fn genModuleLevelAssembly(object: *Object) !void {
10231036 const mod = object.module;
1024 if (mod.global_assembly.count() == 0) return;
1025 var buffer = std.ArrayList(u8).init(mod.gpa);
1026 defer buffer.deinit();
1027 var it = mod.global_assembly.iterator();
1028 while (it.next()) |kv| {
1029 try buffer.appendSlice(kv.value_ptr.*);
1030 try buffer.append('\n');
1031 }
1032 object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);
1037
1038 const writer = object.builder.setModuleAsm();
1039 var it = mod.global_assembly.valueIterator();
1040 while (it.next()) |assembly| try writer.print("{s}\n", .{assembly.*});
1041 try object.builder.finishModuleAsm();
10331042 }
10341043
10351044 fn resolveExportExternCollisions(object: *Object) !void {
......@@ -1223,6 +1232,7 @@ pub const Object = struct {
12231232 const func = mod.funcInfo(func_index);
12241233 const decl_index = func.owner_decl;
12251234 const decl = mod.declPtr(decl_index);
1235 const fn_info = mod.typeToFunc(decl.ty).?;
12261236 const target = mod.getTarget();
12271237 const ip = &mod.intern_pool;
12281238
......@@ -1237,28 +1247,43 @@ pub const Object = struct {
12371247 const global = function.ptrConst(&o.builder).global;
12381248 const llvm_func = global.toLlvm(&o.builder);
12391249
1250 var attributes = try function.ptrConst(&o.builder).attributes.toWip(&o.builder);
1251 defer attributes.deinit(&o.builder);
1252
12401253 if (func.analysis(ip).is_noinline) {
1254 try attributes.addFnAttr(.@"noinline", &o.builder);
12411255 o.addFnAttr(llvm_func, "noinline");
12421256 } else {
1257 _ = try attributes.removeFnAttr(.@"noinline");
12431258 Object.removeFnAttr(llvm_func, "noinline");
12441259 }
12451260
12461261 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {
1262 try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);
1263 try attributes.addFnAttr(.@"noinline", &o.builder);
12471264 o.addFnAttrInt(llvm_func, "alignstack", alignment);
12481265 o.addFnAttr(llvm_func, "noinline");
12491266 } else {
1267 _ = try attributes.removeFnAttr(.alignstack);
12501268 Object.removeFnAttr(llvm_func, "alignstack");
12511269 }
12521270
12531271 if (func.analysis(ip).is_cold) {
1272 try attributes.addFnAttr(.cold, &o.builder);
12541273 o.addFnAttr(llvm_func, "cold");
12551274 } else {
1275 _ = try attributes.removeFnAttr(.cold);
12561276 Object.removeFnAttr(llvm_func, "cold");
12571277 }
12581278
12591279 // TODO: disable this if safety is off for the function scope
12601280 const ssp_buf_size = mod.comp.bin_file.options.stack_protector;
12611281 if (ssp_buf_size != 0) {
1282 try attributes.addFnAttr(.sspstrong, &o.builder);
1283 try attributes.addFnAttr(.{ .string = .{
1284 .kind = try o.builder.string("stack-protector-buffer-size"),
1285 .value = try o.builder.fmt("{d}", .{ssp_buf_size}),
1286 } }, &o.builder);
12621287 var buf: [12]u8 = undefined;
12631288 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
12641289 o.addFnAttr(llvm_func, "sspstrong");
......@@ -1267,8 +1292,16 @@ pub const Object = struct {
12671292
12681293 // TODO: disable this if safety is off for the function scope
12691294 if (mod.comp.bin_file.options.stack_check) {
1295 try attributes.addFnAttr(.{ .string = .{
1296 .kind = try o.builder.string("probe-stack"),
1297 .value = try o.builder.string("__zig_probe_stack"),
1298 } }, &o.builder);
12701299 o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");
12711300 } else if (target.os.tag == .uefi) {
1301 try attributes.addFnAttr(.{ .string = .{
1302 .kind = try o.builder.string("no-stack-arg-probe"),
1303 .value = .empty,
1304 } }, &o.builder);
12721305 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
12731306 }
12741307
......@@ -1286,18 +1319,22 @@ pub const Object = struct {
12861319 var llvm_arg_i: u32 = 0;
12871320
12881321 // This gets the LLVM values from the function and stores them in `dg.args`.
1289 const fn_info = mod.typeToFunc(decl.ty).?;
12901322 const sret = firstParamSRet(fn_info, mod);
12911323 const ret_ptr: Builder.Value = if (sret) param: {
12921324 const param = wip.arg(llvm_arg_i);
12931325 llvm_arg_i += 1;
12941326 break :param param;
12951327 } else .none;
1296 const gpa = o.gpa;
12971328
12981329 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"),
1330 .signed => {
1331 try attributes.addRetAttr(.signext, &o.builder);
1332 o.addAttr(llvm_func, 0, "signext");
1333 },
1334 .unsigned => {
1335 try attributes.addRetAttr(.zeroext, &o.builder);
1336 o.addAttr(llvm_func, 0, "zeroext");
1337 },
13011338 };
13021339
13031340 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
......@@ -1312,6 +1349,7 @@ pub const Object = struct {
13121349 // This is the list of args we will use that correspond directly to the AIR arg
13131350 // instructions. Depending on the calling convention, this list is not necessarily
13141351 // a bijection with the actual LLVM parameters of the function.
1352 const gpa = o.gpa;
13151353 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
13161354 defer args.deinit(gpa);
13171355
......@@ -1337,7 +1375,7 @@ pub const Object = struct {
13371375 } else {
13381376 args.appendAssumeCapacity(param);
13391377
1340 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
1378 try o.addByValParamAttrsOld(&attributes, llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
13411379 }
13421380 llvm_arg_i += 1;
13431381 },
......@@ -1347,7 +1385,7 @@ pub const Object = struct {
13471385 const param = wip.arg(llvm_arg_i);
13481386 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
13491387
1350 o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);
1388 try o.addByRefParamAttrsOld(&attributes, llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
13511389 llvm_arg_i += 1;
13521390
13531391 if (isByRef(param_ty, mod)) {
......@@ -1362,7 +1400,8 @@ pub const Object = struct {
13621400 const param = wip.arg(llvm_arg_i);
13631401 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
13641402
1365 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
1403 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
1404 o.addArgAttr(llvm_func, llvm_arg_i, "noundef");
13661405 llvm_arg_i += 1;
13671406
13681407 if (isByRef(param_ty, mod)) {
......@@ -1398,21 +1437,28 @@ pub const Object = struct {
13981437
13991438 if (math.cast(u5, it.zig_index - 1)) |i| {
14001439 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1401 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noalias");
1440 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
1441 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
14021442 }
14031443 }
14041444 if (param_ty.zigTypeTag(mod) != .Optional) {
1405 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "nonnull");
1445 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
1446 o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
14061447 }
14071448 if (ptr_info.flags.is_const) {
1408 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "readonly");
1449 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
1450 o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
14091451 }
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;
1452 const elem_align = Builder.Alignment.fromByteUnits(
1453 ptr_info.flags.alignment.toByteUnitsOptional() orelse
1454 @max(ptr_info.child.toType().abiAlignment(mod), 1),
1455 );
1456 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1457 o.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
1458 const ptr_param = wip.arg(llvm_arg_i);
1459 llvm_arg_i += 1;
1460 const len_param = wip.arg(llvm_arg_i);
1461 llvm_arg_i += 1;
14161462
14171463 const slice_llvm_ty = try o.lowerType(param_ty);
14181464 args.appendAssumeCapacity(
......@@ -1482,6 +1528,8 @@ pub const Object = struct {
14821528 }
14831529 }
14841530
1531 function.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
1532
14851533 var di_file: ?*llvm.DIFile = null;
14861534 var di_scope: ?*llvm.DIScope = null;
14871535
......@@ -1618,7 +1666,7 @@ pub const Object = struct {
16181666 llvm_global.setDLLStorageClass(.Default);
16191667 }
16201668 if (self.di_map.get(decl)) |di_node| {
1621 const decl_name_slice = decl_name.toSlice(&self.builder).?;
1669 const decl_name_slice = decl_name.slice(&self.builder).?;
16221670 if (try decl.isFunction(mod)) {
16231671 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
16241672 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
......@@ -1655,7 +1703,7 @@ pub const Object = struct {
16551703 llvm_global.setDLLStorageClass(.DLLExport);
16561704 }
16571705 if (self.di_map.get(decl)) |di_node| {
1658 const exp_name_slice = exp_name.toSlice(&self.builder).?;
1706 const exp_name_slice = exp_name.slice(&self.builder).?;
16591707 if (try decl.isFunction(mod)) {
16601708 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
16611709 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
......@@ -2816,7 +2864,7 @@ pub const Object = struct {
28162864 const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
28172865
28182866 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));
2867 const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.slice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
28202868
28212869 var global = Builder.Global{
28222870 .type = fn_type,
......@@ -2826,6 +2874,9 @@ pub const Object = struct {
28262874 .global = @enumFromInt(o.builder.globals.count()),
28272875 };
28282876
2877 var attributes: Builder.FunctionAttributes.Wip = .{};
2878 defer attributes.deinit(&o.builder);
2879
28292880 const is_extern = decl.isExtern(mod);
28302881 if (!is_extern) {
28312882 global.linkage = .internal;
......@@ -2834,43 +2885,64 @@ pub const Object = struct {
28342885 llvm_fn.setUnnamedAddr(.True);
28352886 } else {
28362887 if (target.isWasm()) {
2888 try attributes.addFnAttr(.{ .string = .{
2889 .kind = try o.builder.string("wasm-import-name"),
2890 .value = try o.builder.string(ip.stringToSlice(decl.name)),
2891 } }, &o.builder);
28372892 o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));
28382893 if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
28392894 if (!std.mem.eql(u8, lib_name, "c")) {
2895 try attributes.addFnAttr(.{ .string = .{
2896 .kind = try o.builder.string("wasm-import-module"),
2897 .value = try o.builder.string(lib_name),
2898 } }, &o.builder);
28402899 o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);
28412900 }
28422901 }
28432902 }
28442903 }
28452904
2905 var llvm_arg_i: u32 = 0;
28462906 if (sret) {
2847 o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
2848 o.addArgAttr(llvm_fn, 0, "noalias");
2907 // Sret pointers must not be address 0
2908 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2909 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
2910 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); // Sret pointers must not be address 0
2911 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
28492912
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);
2913 const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
2914 try attributes.addParamAttr(llvm_arg_i, .{ .sret = raw_llvm_ret_ty }, &o.builder);
2915 llvm_fn.addSretAttr(raw_llvm_ret_ty.toLlvm(&o.builder));
2916
2917 llvm_arg_i += 1;
28522918 }
28532919
28542920 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
28552921 mod.comp.bin_file.options.error_return_tracing;
28562922
28572923 if (err_return_tracing) {
2858 o.addArgAttr(llvm_fn, @intFromBool(sret), "nonnull");
2924 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
2925 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
2926 llvm_arg_i += 1;
28592927 }
28602928
28612929 switch (fn_info.cc) {
28622930 .Unspecified, .Inline => {
2931 function.call_conv = .fastcc;
28632932 llvm_fn.setFunctionCallConv(.Fast);
28642933 },
28652934 .Naked => {
2935 try attributes.addFnAttr(.naked, &o.builder);
28662936 o.addFnAttr(llvm_fn, "naked");
28672937 },
28682938 .Async => {
2939 function.call_conv = .fastcc;
28692940 llvm_fn.setFunctionCallConv(.Fast);
28702941 @panic("TODO: LLVM backend lower async function");
28712942 },
28722943 else => {
2873 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
2944 function.call_conv = toLlvmCallConv(fn_info.cc, target);
2945 llvm_fn.setFunctionCallConv(@enumFromInt(@intFromEnum(function.call_conv)));
28742946 },
28752947 }
28762948
......@@ -2880,9 +2952,10 @@ pub const Object = struct {
28802952 }
28812953
28822954 // Function attributes that are independent of analysis results of the function body.
2883 o.addCommonFnAttributes(llvm_fn);
2955 try o.addCommonFnAttributes(&attributes, llvm_fn);
28842956
28852957 if (fn_info.return_type == .noreturn_type) {
2958 try attributes.addFnAttr(.noreturn, &o.builder);
28862959 o.addFnAttr(llvm_fn, "noreturn");
28872960 }
28882961
......@@ -2890,23 +2963,24 @@ pub const Object = struct {
28902963 // because functions with bodies are handled in `updateFunc`.
28912964 if (is_extern) {
28922965 var it = iterateParamTypes(o, fn_info);
2893 it.llvm_index += @intFromBool(sret);
2894 it.llvm_index += @intFromBool(err_return_tracing);
2966 it.llvm_index = llvm_arg_i;
28952967 while (try it.next()) |lowering| switch (lowering) {
28962968 .byval => {
28972969 const param_index = it.zig_index - 1;
28982970 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
28992971 if (!isByRef(param_ty, mod)) {
2900 o.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
2972 try o.addByValParamAttrsOld(&attributes, llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
29012973 }
29022974 },
29032975 .byref => {
29042976 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
29052977 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);
2978 const alignment =
2979 Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod));
2980 try o.addByRefParamAttrsOld(&attributes, llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
29082981 },
29092982 .byref_mut => {
2983 try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder);
29102984 o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
29112985 },
29122986 // No attributes needed for these.
......@@ -2924,25 +2998,42 @@ pub const Object = struct {
29242998 };
29252999 }
29263000
3001 function.attributes = try attributes.finish(&o.builder);
3002
29273003 try o.builder.llvm.globals.append(o.gpa, llvm_fn);
29283004 gop.value_ptr.* = try o.builder.addGlobal(fqn, global);
29293005 try o.builder.functions.append(o.gpa, function);
29303006 return global.kind.function;
29313007 }
29323008
2933 fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {
3009 fn addCommonFnAttributes(
3010 o: *Object,
3011 attributes: *Builder.FunctionAttributes.Wip,
3012 llvm_fn: *llvm.Value,
3013 ) Allocator.Error!void {
29343014 const comp = o.module.comp;
29353015
29363016 if (!comp.bin_file.options.red_zone) {
3017 try attributes.addFnAttr(.noredzone, &o.builder);
29373018 o.addFnAttr(llvm_fn, "noredzone");
29383019 }
29393020 if (comp.bin_file.options.omit_frame_pointer) {
3021 try attributes.addFnAttr(.{ .string = .{
3022 .kind = try o.builder.string("frame-pointer"),
3023 .value = try o.builder.string("none"),
3024 } }, &o.builder);
29403025 o.addFnAttrString(llvm_fn, "frame-pointer", "none");
29413026 } else {
3027 try attributes.addFnAttr(.{ .string = .{
3028 .kind = try o.builder.string("frame-pointer"),
3029 .value = try o.builder.string("all"),
3030 } }, &o.builder);
29423031 o.addFnAttrString(llvm_fn, "frame-pointer", "all");
29433032 }
3033 try attributes.addFnAttr(.nounwind, &o.builder);
29443034 o.addFnAttr(llvm_fn, "nounwind");
29453035 if (comp.unwind_tables) {
3036 try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
29463037 o.addFnAttrInt(llvm_fn, "uwtable", 2);
29473038 }
29483039 if (comp.bin_file.options.skip_linker_dependencies or
......@@ -2953,22 +3044,38 @@ pub const Object = struct {
29533044 // and llvm detects that the body is equivalent to memcpy, it may replace the
29543045 // body of memcpy with a call to memcpy, which would then cause a stack
29553046 // overflow instead of performing memcpy.
3047 try attributes.addFnAttr(.nobuiltin, &o.builder);
29563048 o.addFnAttr(llvm_fn, "nobuiltin");
29573049 }
29583050 if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
3051 try attributes.addFnAttr(.minsize, &o.builder);
3052 try attributes.addFnAttr(.optsize, &o.builder);
29593053 o.addFnAttr(llvm_fn, "minsize");
29603054 o.addFnAttr(llvm_fn, "optsize");
29613055 }
29623056 if (comp.bin_file.options.tsan) {
3057 try attributes.addFnAttr(.sanitize_thread, &o.builder);
29633058 o.addFnAttr(llvm_fn, "sanitize_thread");
29643059 }
29653060 if (comp.getTarget().cpu.model.llvm_name) |s| {
3061 try attributes.addFnAttr(.{ .string = .{
3062 .kind = try o.builder.string("target-cpu"),
3063 .value = try o.builder.string(s),
3064 } }, &o.builder);
29663065 llvm_fn.addFunctionAttr("target-cpu", s);
29673066 }
29683067 if (comp.bin_file.options.llvm_cpu_features) |s| {
3068 try attributes.addFnAttr(.{ .string = .{
3069 .kind = try o.builder.string("target-features"),
3070 .value = try o.builder.string(std.mem.span(s)),
3071 } }, &o.builder);
29693072 llvm_fn.addFunctionAttr("target-features", s);
29703073 }
29713074 if (comp.getTarget().cpu.arch.isBpf()) {
3075 try attributes.addFnAttr(.{ .string = .{
3076 .kind = try o.builder.string("no-builtins"),
3077 .value = .empty,
3078 } }, &o.builder);
29723079 llvm_fn.addFunctionAttr("no-builtins", "");
29733080 }
29743081 }
......@@ -3002,7 +3109,7 @@ pub const Object = struct {
30023109 fqn;
30033110 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
30043111 global.type.toLlvm(&o.builder),
3005 fqn.toSlice(&o.builder).?,
3112 fqn.slice(&o.builder).?,
30063113 @intFromEnum(global.addr_space),
30073114 );
30083115
......@@ -4403,47 +4510,114 @@ pub const Object = struct {
44034510
44044511 fn addByValParamAttrs(
44054512 o: *Object,
4513 attributes: *Builder.FunctionAttributes.Wip,
4514 param_ty: Type,
4515 param_index: u32,
4516 fn_info: InternPool.Key.FuncType,
4517 llvm_arg_i: u32,
4518 ) Allocator.Error!void {
4519 const mod = o.module;
4520 if (param_ty.isPtrAtRuntime(mod)) {
4521 const ptr_info = param_ty.ptrInfo(mod);
4522 if (math.cast(u5, param_index)) |i| {
4523 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4524 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
4525 }
4526 }
4527 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4528 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4529 }
4530 if (ptr_info.flags.is_const) {
4531 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4532 }
4533 const elem_align = Builder.Alignment.fromByteUnits(
4534 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4535 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4536 );
4537 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4538 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4539 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
4540 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
4541 };
4542 }
4543
4544 fn addByRefParamAttrs(
4545 o: *Object,
4546 attributes: *Builder.FunctionAttributes.Wip,
4547 llvm_arg_i: u32,
4548 alignment: Builder.Alignment,
4549 byval_attr: bool,
4550 param_llvm_ty: Builder.Type,
4551 ) Allocator.Error!void {
4552 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4553 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4554 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
4555 if (byval_attr) {
4556 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
4557 }
4558 }
4559
4560 fn addByValParamAttrsOld(
4561 o: *Object,
4562 attributes: *Builder.FunctionAttributes.Wip,
44064563 llvm_fn: *llvm.Value,
44074564 param_ty: Type,
44084565 param_index: u32,
44094566 fn_info: InternPool.Key.FuncType,
44104567 llvm_arg_i: u32,
4411 ) void {
4568 ) Allocator.Error!void {
44124569 const mod = o.module;
44134570 if (param_ty.isPtrAtRuntime(mod)) {
44144571 const ptr_info = param_ty.ptrInfo(mod);
44154572 if (math.cast(u5, param_index)) |i| {
44164573 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
4574 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
44174575 o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
44184576 }
44194577 }
44204578 if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
4579 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
44214580 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
44224581 }
44234582 if (ptr_info.flags.is_const) {
4583 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
44244584 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
44254585 }
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);
4586 const elem_align = Builder.Alignment.fromByteUnits(
4587 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4588 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4589 );
4590 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4591 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
44294592 } 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"),
4593 .signed => {
4594 try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder);
4595 o.addArgAttr(llvm_fn, llvm_arg_i, "signext");
4596 },
4597 .unsigned => {
4598 try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder);
4599 o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext");
4600 },
44324601 };
44334602 }
44344603
4435 fn addByRefParamAttrs(
4604 fn addByRefParamAttrsOld(
44364605 o: *Object,
4606 attributes: *Builder.FunctionAttributes.Wip,
44374607 llvm_fn: *llvm.Value,
44384608 llvm_arg_i: u32,
4439 alignment: u32,
4609 alignment: Builder.Alignment,
44404610 byval_attr: bool,
44414611 param_llvm_ty: Builder.Type,
4442 ) void {
4612 ) Allocator.Error!void {
4613 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
4614 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4615 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
44434616 o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
44444617 o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
4445 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
4618 o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment.toByteUnits() orelse 0);
44464619 if (byval_attr) {
4620 try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
44474621 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
44484622 }
44494623 }
......@@ -4841,10 +5015,10 @@ pub const FuncGen = struct {
48415015 .slice_ptr => try self.airSliceField(inst, 0),
48425016 .slice_len => try self.airSliceField(inst, 1),
48435017
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),
5018 .call => try self.airCall(inst, .auto),
5019 .call_always_tail => try self.airCall(inst, .always_tail),
5020 .call_never_tail => try self.airCall(inst, .never_tail),
5021 .call_never_inline => try self.airCall(inst, .never_inline),
48485022
48495023 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
48505024 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
......@@ -4953,7 +5127,15 @@ pub const FuncGen = struct {
49535127 }
49545128 }
49555129
4956 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !Builder.Value {
5130 pub const CallAttr = enum {
5131 Auto,
5132 NeverTail,
5133 NeverInline,
5134 AlwaysTail,
5135 AlwaysInline,
5136 };
5137
5138 fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !Builder.Value {
49575139 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
49585140 const extra = self.air.extraData(Air.Call, pl_op.payload);
49595141 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
......@@ -4972,14 +5154,25 @@ pub const FuncGen = struct {
49725154 const target = mod.getTarget();
49735155 const sret = firstParamSRet(fn_info, mod);
49745156
4975 var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa);
5157 var llvm_args = std.ArrayList(Builder.Value).init(self.gpa);
49765158 defer llvm_args.deinit();
49775159
5160 var attributes: Builder.FunctionAttributes.Wip = .{};
5161 defer attributes.deinit(&o.builder);
5162
5163 switch (modifier) {
5164 .auto, .never_tail, .always_tail => {},
5165 .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder),
5166 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5167 }
5168
49785169 const ret_ptr = if (!sret) null else blk: {
49795170 const llvm_ret_ty = try o.lowerType(return_type);
5171 try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
5172
49805173 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
49815174 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4982 try llvm_args.append(ret_ptr.toLlvm(&self.wip));
5175 try llvm_args.append(ret_ptr);
49835176 break :blk ret_ptr;
49845177 };
49855178
......@@ -4987,7 +5180,7 @@ pub const FuncGen = struct {
49875180 o.module.comp.bin_file.options.error_return_tracing;
49885181 if (err_return_tracing) {
49895182 assert(self.err_ret_trace != .none);
4990 try llvm_args.append(self.err_ret_trace.toLlvm(&self.wip));
5183 try llvm_args.append(self.err_ret_trace);
49915184 }
49925185
49935186 var it = iterateParamTypes(o, fn_info);
......@@ -5001,9 +5194,9 @@ pub const FuncGen = struct {
50015194 if (isByRef(param_ty, mod)) {
50025195 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
50035196 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
5004 try llvm_args.append(loaded.toLlvm(&self.wip));
5197 try llvm_args.append(loaded);
50055198 } else {
5006 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
5199 try llvm_args.append(llvm_arg);
50075200 }
50085201 },
50095202 .byref => {
......@@ -5011,13 +5204,13 @@ pub const FuncGen = struct {
50115204 const param_ty = self.typeOf(arg);
50125205 const llvm_arg = try self.resolveInst(arg);
50135206 if (isByRef(param_ty, mod)) {
5014 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
5207 try llvm_args.append(llvm_arg);
50155208 } else {
50165209 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
50175210 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
50185211 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
50195212 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
5020 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
5213 try llvm_args.append(arg_ptr);
50215214 }
50225215 },
50235216 .byref_mut => {
......@@ -5034,7 +5227,7 @@ pub const FuncGen = struct {
50345227 } else {
50355228 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
50365229 }
5037 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
5230 try llvm_args.append(arg_ptr);
50385231 },
50395232 .abi_sized_int => {
50405233 const arg = args[it.zig_index - 1];
......@@ -5045,7 +5238,7 @@ pub const FuncGen = struct {
50455238 if (isByRef(param_ty, mod)) {
50465239 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
50475240 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
5048 try llvm_args.append(loaded.toLlvm(&self.wip));
5241 try llvm_args.append(loaded);
50495242 } else {
50505243 // LLVM does not allow bitcasting structs so we must allocate
50515244 // a local, store as one type, and then load as another type.
......@@ -5056,7 +5249,7 @@ pub const FuncGen = struct {
50565249 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
50575250 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
50585251 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
5059 try llvm_args.append(loaded.toLlvm(&self.wip));
5252 try llvm_args.append(loaded);
50605253 }
50615254 },
50625255 .slice => {
......@@ -5064,7 +5257,7 @@ pub const FuncGen = struct {
50645257 const llvm_arg = try self.resolveInst(arg);
50655258 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
50665259 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
5067 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
5260 try llvm_args.appendSlice(&.{ ptr, len });
50685261 },
50695262 .multiple_llvm_types => {
50705263 const arg = args[it.zig_index - 1];
......@@ -5086,14 +5279,14 @@ pub const FuncGen = struct {
50865279 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
50875280 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
50885281 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
5089 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
5282 llvm_args.appendAssumeCapacity(loaded);
50905283 }
50915284 },
50925285 .as_u16 => {
50935286 const arg = args[it.zig_index - 1];
50945287 const llvm_arg = try self.resolveInst(arg);
50955288 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
5096 try llvm_args.append(casted.toLlvm(&self.wip));
5289 try llvm_args.append(casted);
50975290 },
50985291 .float_array => |count| {
50995292 const arg = args[it.zig_index - 1];
......@@ -5110,7 +5303,7 @@ pub const FuncGen = struct {
51105303 const array_ty = try o.builder.arrayType(count, float_ty);
51115304
51125305 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5113 try llvm_args.append(loaded.toLlvm(&self.wip));
5306 try llvm_args.append(loaded);
51145307 },
51155308 .i32_array, .i64_array => |arr_len| {
51165309 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
......@@ -5127,24 +5320,10 @@ pub const FuncGen = struct {
51275320 const array_ty =
51285321 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
51295322 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5130 try llvm_args.append(loaded.toLlvm(&self.wip));
5323 try llvm_args.append(loaded);
51315324 },
51325325 };
51335326
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
51485327 if (callee_ty.zigTypeTag(mod) == .Pointer) {
51495328 // Add argument attributes for function pointer calls.
51505329 it = iterateParamTypes(o, fn_info);
......@@ -5155,19 +5334,17 @@ pub const FuncGen = struct {
51555334 const param_index = it.zig_index - 1;
51565335 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
51575336 if (!isByRef(param_ty, mod)) {
5158 o.addByValParamAttrs(call.toLlvm(&self.wip), param_ty, param_index, fn_info, it.llvm_index - 1);
5337 try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
51595338 }
51605339 },
51615340 .byref => {
51625341 const param_index = it.zig_index - 1;
51635342 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
51645343 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");
5344 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5345 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
51705346 },
5347 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
51715348 // No attributes needed for these.
51725349 .no_bits,
51735350 .abi_sized_int,
......@@ -5186,23 +5363,40 @@ pub const FuncGen = struct {
51865363
51875364 if (math.cast(u5, it.zig_index - 1)) |i| {
51885365 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
5189 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "noalias");
5366 try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
51905367 }
51915368 }
51925369 if (param_ty.zigTypeTag(mod) != .Optional) {
5193 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "nonnull");
5370 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
51945371 }
51955372 if (ptr_info.flags.is_const) {
5196 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "readonly");
5373 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
51975374 }
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);
5375 const elem_align = Builder.Alignment.fromByteUnits(
5376 ptr_info.flags.alignment.toByteUnitsOptional() orelse
5377 @max(ptr_info.child.toType().abiAlignment(mod), 1),
5378 );
5379 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
52015380 },
52025381 };
52035382 }
52045383
5205 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
5384 const call = try self.wip.call(
5385 switch (modifier) {
5386 .auto, .never_inline => .normal,
5387 .never_tail => .notail,
5388 .always_tail => .musttail,
5389 .async_kw, .no_async, .always_inline, .compile_time => unreachable,
5390 },
5391 toLlvmCallConv(fn_info.cc, target),
5392 try attributes.finish(&o.builder),
5393 try o.lowerType(zig_fn_ty),
5394 llvm_fn,
5395 llvm_args.items,
5396 "",
5397 );
5398
5399 if (fn_info.return_type == .noreturn_type and modifier != .always_tail) {
52065400 return .none;
52075401 }
52085402
......@@ -5211,9 +5405,7 @@ pub const FuncGen = struct {
52115405 }
52125406
52135407 const llvm_ret_ty = try o.lowerType(return_type);
5214
52155408 if (ret_ptr) |rp| {
5216 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
52175409 if (isByRef(return_type, mod)) {
52185410 return rp;
52195411 } else {
......@@ -5269,25 +5461,24 @@ pub const FuncGen = struct {
52695461 // ptr null, ; stack trace
52705462 // ptr @2, ; addr (null ?usize)
52715463 // )
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 };
52785464 const panic_func = mod.funcInfo(mod.panic_func_index);
52795465 const panic_decl = mod.declPtr(panic_func.owner_decl);
52805466 const fn_info = mod.typeToFunc(panic_decl.ty).?;
52815467 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,
5468 _ = try fg.wip.call(
5469 .normal,
52875470 toLlvmCallConv(fn_info.cc, target),
5288 .Auto,
5471 .none,
5472 panic_global.typeOf(&o.builder),
5473 panic_global.toValue(&o.builder),
5474 &.{
5475 msg_ptr.toValue(),
5476 try o.builder.intValue(llvm_usize, msg_len),
5477 try o.builder.nullValue(.ptr),
5478 null_opt_addr_global.toValue(),
5479 },
52895480 "",
5290 ), &fg.wip);
5481 );
52915482 _ = try fg.wip.@"unreachable"();
52925483 }
52935484
......@@ -5395,7 +5586,7 @@ pub const FuncGen = struct {
53955586 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
53965587
53975588 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(
5589 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
53995590 llvm_fn_ty.toLlvm(&o.builder),
54005591 llvm_fn,
54015592 &args,
......@@ -5422,7 +5613,7 @@ pub const FuncGen = struct {
54225613 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54235614
54245615 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5425 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5616 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
54265617 llvm_fn_ty.toLlvm(&o.builder),
54275618 llvm_fn,
54285619 &args,
......@@ -5449,7 +5640,7 @@ pub const FuncGen = struct {
54495640 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54505641
54515642 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5452 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5643 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
54535644 llvm_fn_ty.toLlvm(&o.builder),
54545645 llvm_fn,
54555646 &args,
......@@ -5495,16 +5686,15 @@ pub const FuncGen = struct {
54955686 const un_op = self.air.instructions.items(.data)[inst].un_op;
54965687 const operand = try self.resolveInst(un_op);
54975688 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,
5689 return self.wip.call(
5690 .normal,
5691 .fastcc,
5692 .none,
5693 llvm_fn.typeOf(&o.builder),
5694 llvm_fn.toValue(&o.builder),
5695 &.{operand},
55065696 "",
5507 ), &self.wip);
5697 );
55085698 }
55095699
55105700 fn cmp(
......@@ -5953,16 +6143,15 @@ pub const FuncGen = struct {
59536143 }
59546144
59556145 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,
6146 return self.wip.call(
6147 .normal,
6148 .ccc,
6149 .none,
6150 libc_fn.typeOf(&o.builder),
6151 libc_fn.toValue(&o.builder),
6152 &.{extended},
59646153 "",
5965 ), &self.wip);
6154 );
59666155 }
59676156
59686157 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
......@@ -6013,16 +6202,15 @@ pub const FuncGen = struct {
60136202
60146203 const operand_llvm_ty = try o.lowerType(operand_ty);
60156204 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,
6205 var result = try self.wip.call(
6206 .normal,
6207 .ccc,
6208 .none,
6209 libc_fn.typeOf(&o.builder),
6210 libc_fn.toValue(&o.builder),
6211 &.{operand},
60246212 "",
6025 ), &self.wip);
6213 );
60266214
60276215 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
60286216 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
......@@ -6588,7 +6776,7 @@ pub const FuncGen = struct {
65886776
65896777 const max_param_count = inputs.len + outputs.len;
65906778 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
6591 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
6779 const llvm_param_values = try arena.alloc(Builder.Value, max_param_count);
65926780 // This stores whether we need to add an elementtype attribute and
65936781 // if so, the element type itself.
65946782 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
......@@ -6628,7 +6816,7 @@ pub const FuncGen = struct {
66286816 // Pass the result by reference as an indirect output (e.g. "=*m")
66296817 llvm_constraints.appendAssumeCapacity('*');
66306818
6631 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
6819 llvm_param_values[llvm_param_i] = output_inst;
66326820 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
66336821 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
66346822 llvm_param_i += 1;
......@@ -6678,25 +6866,25 @@ pub const FuncGen = struct {
66786866 if (isByRef(arg_ty, mod)) {
66796867 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
66806868 if (constraintAllowsMemory(constraint)) {
6681 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6869 llvm_param_values[llvm_param_i] = arg_llvm_value;
66826870 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66836871 } else {
66846872 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
66856873 const arg_llvm_ty = try o.lowerType(arg_ty);
66866874 const load_inst =
66876875 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6688 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
6876 llvm_param_values[llvm_param_i] = load_inst;
66896877 llvm_param_types[llvm_param_i] = arg_llvm_ty;
66906878 }
66916879 } else {
66926880 if (constraintAllowsRegister(constraint)) {
6693 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6881 llvm_param_values[llvm_param_i] = arg_llvm_value;
66946882 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66956883 } else {
66966884 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
66976885 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
66986886 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6699 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
6887 llvm_param_values[llvm_param_i] = arg_ptr;
67006888 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
67016889 }
67026890 }
......@@ -6843,38 +7031,26 @@ pub const FuncGen = struct {
68437031 }
68447032 }
68457033
7034 var attributes: Builder.FunctionAttributes.Wip = .{};
7035 defer attributes.deinit(&o.builder);
7036 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| if (llvm_elem_ty != .none)
7037 try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
7038
68467039 const ret_llvm_ty = switch (return_count) {
68477040 0 => .void,
68487041 1 => llvm_ret_types[0],
68497042 else => try o.builder.structType(.normal, llvm_ret_types),
68507043 };
6851
68527044 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
6853 const asm_fn = llvm.getInlineAsm(
6854 llvm_fn_ty.toLlvm(&o.builder),
6855 rendered_template.items.ptr,
6856 rendered_template.items.len,
6857 llvm_constraints.items.ptr,
6858 llvm_constraints.items.len,
6859 llvm.Bool.fromBool(is_volatile),
6860 .False,
6861 .ATT,
6862 .False,
6863 );
6864 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
6865 llvm_fn_ty.toLlvm(&o.builder),
6866 asm_fn,
6867 llvm_param_values.ptr,
6868 @intCast(param_count),
6869 .C,
6870 .Auto,
7045 const call = try self.wip.callAsm(
7046 try attributes.finish(&o.builder),
7047 llvm_fn_ty,
7048 .{ .sideeffect = is_volatile },
7049 try o.builder.string(rendered_template.items),
7050 try o.builder.string(llvm_constraints.items),
7051 llvm_param_values[0..param_count],
68717052 "",
6872 ), &self.wip);
6873 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6874 if (llvm_elem_ty != .none) {
6875 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
6876 }
6877 }
7053 );
68787054
68797055 var ret_val = call;
68807056 llvm_ret_i = 0;
......@@ -7287,7 +7463,7 @@ pub const FuncGen = struct {
72877463 const args: [1]*llvm.Value = .{
72887464 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
72897465 };
7290 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7466 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
72917467 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
72927468 llvm_fn,
72937469 &args,
......@@ -7308,7 +7484,7 @@ pub const FuncGen = struct {
73087484 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
73097485 operand.toLlvm(&self.wip),
73107486 };
7311 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7487 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
73127488 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
73137489 llvm_fn,
73147490 &args,
......@@ -7425,7 +7601,7 @@ pub const FuncGen = struct {
74257601 });
74267602 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);
74277603 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(
7604 const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCallOld(
74297605 llvm_fn_ty.toLlvm(&o.builder),
74307606 llvm_fn,
74317607 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
......@@ -7768,7 +7944,7 @@ pub const FuncGen = struct {
77687944 );
77697945 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);
77707946 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
7771 self.builder.buildCall(
7947 self.builder.buildCallOld(
77727948 llvm_fn_ty.toLlvm(&o.builder),
77737949 llvm_fn,
77747950 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
......@@ -7818,29 +7994,23 @@ pub const FuncGen = struct {
78187994 const o = self.dg.object;
78197995 assert(args_vectors.len <= 3);
78207996
7821 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
7822 const llvm_scalar_ty = llvm_fn_ty.functionReturn(&o.builder);
7823
78247997 var i: usize = 0;
78257998 var result = result_vector;
78267999 while (i < vector_len) : (i += 1) {
78278000 const index_i32 = try o.builder.intValue(.i32, i);
78288001
7829 var args: [3]*llvm.Value = undefined;
8002 var args: [3]Builder.Value = undefined;
78308003 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);
8004 arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, "");
78328005 }
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,
8006 const result_elem = try self.wip.call(
8007 .normal,
8008 .ccc,
8009 .none,
8010 llvm_fn.typeOf(&o.builder),
8011 llvm_fn.toValue(&o.builder),
8012 args[0..args_vectors.len],
8013 "",
78448014 );
78458015 result = try self.wip.insertElement(result, result_elem, index_i32, "");
78468016 }
......@@ -7861,7 +8031,7 @@ pub const FuncGen = struct {
78618031 };
78628032
78638033 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));
8034 const f = o.llvm_module.addFunction(fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
78658035
78668036 var global = Builder.Global{
78678037 .type = fn_type,
......@@ -7942,20 +8112,15 @@ pub const FuncGen = struct {
79428112 return self.wip.icmp(int_cond, result, zero_vector, "");
79438113 }
79448114
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,
8115 const result = try self.wip.call(
8116 .normal,
8117 .ccc,
8118 .none,
8119 libc_fn.typeOf(&o.builder),
8120 libc_fn.toValue(&o.builder),
8121 &params,
79578122 "",
7958 ), &self.wip);
8123 );
79598124 return self.wip.icmp(int_cond, result, zero.toValue(), "");
79608125 }
79618126
......@@ -8085,7 +8250,7 @@ pub const FuncGen = struct {
80858250 );
80868251 var llvm_params: [params_len]*llvm.Value = undefined;
80878252 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(
8253 return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCallOld(
80898254 llvm_fn_ty.toLlvm(&o.builder),
80908255 llvm_fn,
80918256 &llvm_params,
......@@ -8311,17 +8476,16 @@ pub const FuncGen = struct {
83118476 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
83128477 });
83138478
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,
8479 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8480 return self.wip.call(
8481 .normal,
8482 .ccc,
8483 .none,
8484 libc_fn.typeOf(&o.builder),
8485 libc_fn.toValue(&o.builder),
8486 &.{operand},
83238487 "",
8324 ), &self.wip);
8488 );
83258489 }
83268490 }
83278491
......@@ -8346,17 +8510,16 @@ pub const FuncGen = struct {
83468510 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
83478511 });
83488512
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,
8513 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8514 return self.wip.call(
8515 .normal,
8516 .ccc,
8517 .none,
8518 libc_fn.typeOf(&o.builder),
8519 libc_fn.toValue(&o.builder),
8520 &.{operand},
83588521 "",
8359 ), &self.wip);
8522 );
83608523 }
83618524 }
83628525
......@@ -8657,7 +8820,7 @@ pub const FuncGen = struct {
86578820 _ = inst;
86588821 const o = self.dg.object;
86598822 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8660 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8823 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
86618824 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
86628825 llvm_fn,
86638826 undefined,
......@@ -8674,7 +8837,7 @@ pub const FuncGen = struct {
86748837 _ = inst;
86758838 const o = self.dg.object;
86768839 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8677 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8840 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
86788841 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
86798842 llvm_fn,
86808843 undefined,
......@@ -8701,7 +8864,7 @@ pub const FuncGen = struct {
87018864 const params = [_]*llvm.Value{
87028865 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
87038866 };
8704 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(
8867 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCallOld(
87058868 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
87068869 llvm_fn,
87078870 &params,
......@@ -8727,7 +8890,7 @@ pub const FuncGen = struct {
87278890 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
87288891 };
87298892 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8730 self.builder.buildCall(
8893 self.builder.buildCallOld(
87318894 llvm_fn_ty.toLlvm(&o.builder),
87328895 llvm_fn,
87338896 &params,
......@@ -9256,7 +9419,7 @@ pub const FuncGen = struct {
92569419 Builder.Constant.false.toLlvm(&o.builder),
92579420 };
92589421 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9259 self.builder.buildCall(
9422 self.builder.buildCallOld(
92609423 llvm_fn_ty.toLlvm(&o.builder),
92619424 fn_val,
92629425 &params,
......@@ -9283,7 +9446,7 @@ pub const FuncGen = struct {
92839446
92849447 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
92859448 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9286 self.builder.buildCall(
9449 self.builder.buildCallOld(
92879450 llvm_fn_ty.toLlvm(&o.builder),
92889451 fn_val,
92899452 &params,
......@@ -9331,7 +9494,7 @@ pub const FuncGen = struct {
93319494
93329495 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
93339496 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9334 self.builder.buildCall(
9497 self.builder.buildCallOld(
93359498 llvm_fn_ty.toLlvm(&o.builder),
93369499 fn_val,
93379500 &params,
......@@ -9389,16 +9552,15 @@ pub const FuncGen = struct {
93899552 const enum_ty = self.typeOf(un_op);
93909553
93919554 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,
9555 return self.wip.call(
9556 .normal,
9557 .fastcc,
9558 .none,
9559 llvm_fn.typeOf(&o.builder),
9560 llvm_fn.toValue(&o.builder),
9561 &.{operand},
94009562 "",
9401 ), &self.wip);
9563 );
94029564 }
94039565
94049566 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
......@@ -9416,13 +9578,16 @@ pub const FuncGen = struct {
94169578 fqn.fmt(&mod.intern_pool),
94179579 });
94189580
9581 var attributes: Builder.FunctionAttributes.Wip = .{};
9582 defer attributes.deinit(&o.builder);
9583
94199584 const fn_type = try o.builder.fnType(.i1, &.{
94209585 try o.lowerType(enum_type.tag_ty.toType()),
94219586 }, .normal);
9422 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9587 const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
94239588 fn_val.setLinkage(.Internal);
94249589 fn_val.setFunctionCallConv(.Fast);
9425 o.addCommonFnAttributes(fn_val);
9590 try o.addCommonFnAttributes(&attributes, fn_val);
94269591
94279592 var global = Builder.Global{
94289593 .linkage = .internal,
......@@ -9431,6 +9596,8 @@ pub const FuncGen = struct {
94319596 };
94329597 var function = Builder.Function{
94339598 .global = @enumFromInt(o.builder.globals.count()),
9599 .call_conv = .fastcc,
9600 .attributes = try attributes.finish(&o.builder),
94349601 };
94359602 try o.builder.llvm.globals.append(self.gpa, fn_val);
94369603 _ = try o.builder.addGlobal(llvm_fn_name, global);
......@@ -9470,19 +9637,14 @@ pub const FuncGen = struct {
94709637 const enum_ty = self.typeOf(un_op);
94719638
94729639 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,
9640 return self.wip.call(
9641 .normal,
9642 .fastcc,
9643 .none,
9644 llvm_fn.typeOf(&o.builder),
9645 llvm_fn.toValue(&o.builder),
9646 &.{operand},
9647 "",
94869648 );
94879649 }
94889650
......@@ -9499,16 +9661,19 @@ pub const FuncGen = struct {
94999661 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
95009662 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
95019663
9664 var attributes: Builder.FunctionAttributes.Wip = .{};
9665 defer attributes.deinit(&o.builder);
9666
95029667 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
95039668 const usize_ty = try o.lowerType(Type.usize);
95049669
95059670 const fn_type = try o.builder.fnType(ret_ty, &.{
95069671 try o.lowerType(enum_type.tag_ty.toType()),
95079672 }, .normal);
9508 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9673 const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
95099674 fn_val.setLinkage(.Internal);
95109675 fn_val.setFunctionCallConv(.Fast);
9511 o.addCommonFnAttributes(fn_val);
9676 try o.addCommonFnAttributes(&attributes, fn_val);
95129677
95139678 var global = Builder.Global{
95149679 .linkage = .internal,
......@@ -9517,6 +9682,8 @@ pub const FuncGen = struct {
95179682 };
95189683 var function = Builder.Function{
95199684 .global = @enumFromInt(o.builder.globals.count()),
9685 .call_conv = .fastcc,
9686 .attributes = try attributes.finish(&o.builder),
95209687 };
95219688 try o.builder.llvm.globals.append(self.gpa, fn_val);
95229689 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
......@@ -9561,7 +9728,7 @@ pub const FuncGen = struct {
95619728
95629729 const slice_val = try o.builder.structValue(ret_ty, &.{
95639730 global_index.toConst(),
9564 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
9731 try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
95659732 });
95669733
95679734 const return_block = try wip.block(1, "Name");
......@@ -9590,11 +9757,14 @@ pub const FuncGen = struct {
95909757 // Function signature: fn (anyerror) bool
95919758
95929759 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));
9760 const llvm_fn = o.llvm_module.addFunction(name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
9761
9762 var attributes: Builder.FunctionAttributes.Wip = .{};
9763 defer attributes.deinit(&o.builder);
95949764
95959765 llvm_fn.setLinkage(.Internal);
95969766 llvm_fn.setFunctionCallConv(.Fast);
9597 o.addCommonFnAttributes(llvm_fn);
9767 try o.addCommonFnAttributes(&attributes, llvm_fn);
95989768
95999769 var global = Builder.Global{
96009770 .linkage = .internal,
......@@ -9603,6 +9773,8 @@ pub const FuncGen = struct {
96039773 };
96049774 var function = Builder.Function{
96059775 .global = @enumFromInt(o.builder.globals.count()),
9776 .call_conv = .fastcc,
9777 .attributes = try attributes.finish(&o.builder),
96069778 };
96079779
96089780 try o.builder.llvm.globals.append(self.gpa, llvm_fn);
......@@ -9731,18 +9903,14 @@ pub const FuncGen = struct {
97319903 // accum = f(accum, vec[i]);
97329904 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
97339905 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,
9906 const new_accum = try self.wip.call(
9907 .normal,
9908 .ccc,
9909 .none,
9910 llvm_fn.typeOf(&o.builder),
9911 llvm_fn.toValue(&o.builder),
9912 &.{ accum, element },
9913 "",
97469914 );
97479915 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
97489916
......@@ -10190,7 +10358,7 @@ pub const FuncGen = struct {
1019010358 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
1019110359 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
1019210360 };
10193 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
10361 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
1019410362 llvm_fn_ty.toLlvm(&o.builder),
1019510363 fn_val,
1019610364 &params,
......@@ -10222,7 +10390,7 @@ pub const FuncGen = struct {
1022210390
1022310391 const args: [0]*llvm.Value = .{};
1022410392 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
10225 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
10393 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
1022610394 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
1022710395 llvm_fn,
1022810396 &args,
......@@ -10252,12 +10420,15 @@ pub const FuncGen = struct {
1025210420 const dimension = pl_op.payload;
1025310421 if (dimension >= 3) return o.builder.intValue(.i32, 1);
1025410422
10423 var attributes: Builder.FunctionAttributes.Wip = .{};
10424 defer attributes.deinit(&o.builder);
10425
1025510426 // Fetch the dispatch pointer, which points to this structure:
1025610427 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
1025710428 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
1025810429 const args: [0]*llvm.Value = .{};
1025910430 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(
10431 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCallOld(
1026110432 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
1026210433 llvm_fn,
1026310434 &args,
......@@ -10266,6 +10437,9 @@ pub const FuncGen = struct {
1026610437 .Auto,
1026710438 "",
1026810439 ), &self.wip);
10440 try attributes.addRetAttr(.{
10441 .@"align" = comptime Builder.Alignment.fromByteUnits(4),
10442 }, &o.builder);
1026910443 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
1027010444
1027110445 // Load the work_group_* member from the struct as u16.
......@@ -10298,7 +10472,7 @@ pub const FuncGen = struct {
1029810472 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
1029910473
1030010474 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).?);
10475 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.slice(&o.builder).?);
1030210476 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
1030310477 error_name_table_global.setLinkage(.Private);
1030410478 error_name_table_global.setGlobalConstant(.True);
......@@ -10751,7 +10925,7 @@ pub const FuncGen = struct {
1075110925 );
1075210926
1075310927 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10754 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10928 fg.builder.buildCallOld(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
1075510929 &fg.wip,
1075610930 );
1075710931 return call;
......@@ -10991,33 +11165,33 @@ fn toLlvmAtomicRmwBinOp(
1099111165 };
1099211166}
1099311167
10994fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {
11168fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {
1099511169 return switch (cc) {
10996 .Unspecified, .Inline, .Async => .Fast,
10997 .C, .Naked => .C,
10998 .Stdcall => .X86_StdCall,
10999 .Fastcall => .X86_FastCall,
11170 .Unspecified, .Inline, .Async => .fastcc,
11171 .C, .Naked => .ccc,
11172 .Stdcall => .x86_stdcallcc,
11173 .Fastcall => .x86_fastcallcc,
1100011174 .Vectorcall => return switch (target.cpu.arch) {
11001 .x86, .x86_64 => .X86_VectorCall,
11002 .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,
11175 .x86, .x86_64 => .x86_vectorcallcc,
11176 .aarch64, .aarch64_be, .aarch64_32 => .aarch64_vector_pcs,
1100311177 else => unreachable,
1100411178 },
11005 .Thiscall => .X86_ThisCall,
11006 .APCS => .ARM_APCS,
11007 .AAPCS => .ARM_AAPCS,
11008 .AAPCSVFP => .ARM_AAPCS_VFP,
11179 .Thiscall => .x86_thiscallcc,
11180 .APCS => .arm_apcscc,
11181 .AAPCS => .arm_aapcscc,
11182 .AAPCSVFP => .arm_aapcs_vfpcc,
1100911183 .Interrupt => return switch (target.cpu.arch) {
11010 .x86, .x86_64 => .X86_INTR,
11011 .avr => .AVR_INTR,
11012 .msp430 => .MSP430_INTR,
11184 .x86, .x86_64 => .x86_intrcc,
11185 .avr => .avr_intrcc,
11186 .msp430 => .msp430_intrcc,
1101311187 else => unreachable,
1101411188 },
11015 .Signal => .AVR_SIGNAL,
11016 .SysV => .X86_64_SysV,
11017 .Win64 => .Win64,
11189 .Signal => .avr_signalcc,
11190 .SysV => .x86_64_sysvcc,
11191 .Win64 => .win64cc,
1101811192 .Kernel => return switch (target.cpu.arch) {
11019 .nvptx, .nvptx64 => .PTX_Kernel,
11020 .amdgcn => .AMDGPU_KERNEL,
11193 .nvptx, .nvptx64 => .ptx_kernel,
11194 .amdgcn => .amdgpu_kernel,
1102111195 else => unreachable,
1102211196 },
1102311197 };
src/codegen/llvm/Builder.zig+2190-510
......@@ -4,22 +4,25 @@ strip: bool,
44
55llvm: if (build_options.have_llvm) struct {
66 context: *llvm.Context,
7 module: ?*llvm.Module = null,
8 target: ?*llvm.Target = null,
9 di_builder: ?*llvm.DIBuilder = null,
10 di_compile_unit: ?*llvm.DICompileUnit = null,
11 types: std.ArrayListUnmanaged(*llvm.Type) = .{},
12 globals: std.ArrayListUnmanaged(*llvm.Value) = .{},
13 constants: std.ArrayListUnmanaged(*llvm.Value) = .{},
7 module: ?*llvm.Module,
8 target: ?*llvm.Target,
9 di_builder: ?*llvm.DIBuilder,
10 di_compile_unit: ?*llvm.DICompileUnit,
11 attribute_kind_ids: ?*[Attribute.Kind.len]c_uint,
12 attributes: std.ArrayListUnmanaged(*llvm.Attribute),
13 types: std.ArrayListUnmanaged(*llvm.Type),
14 globals: std.ArrayListUnmanaged(*llvm.Value),
15 constants: std.ArrayListUnmanaged(*llvm.Value),
1416} else void,
1517
1618source_filename: String,
1719data_layout: String,
1820target_triple: String,
21module_asm: std.ArrayListUnmanaged(u8),
1922
2023string_map: std.AutoArrayHashMapUnmanaged(void, void),
21string_bytes: std.ArrayListUnmanaged(u8),
2224string_indices: std.ArrayListUnmanaged(u32),
25string_bytes: std.ArrayListUnmanaged(u8),
2326
2427types: std.AutoArrayHashMapUnmanaged(String, Type),
2528next_unnamed_type: String,
......@@ -28,6 +31,11 @@ type_map: std.AutoArrayHashMapUnmanaged(void, void),
2831type_items: std.ArrayListUnmanaged(Type.Item),
2932type_extra: std.ArrayListUnmanaged(u32),
3033
34attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void),
35attributes_map: std.AutoArrayHashMapUnmanaged(void, void),
36attributes_indices: std.ArrayListUnmanaged(u32),
37attributes_extra: std.ArrayListUnmanaged(u32),
38
3139globals: std.AutoArrayHashMapUnmanaged(String, Global),
3240next_unnamed_global: String,
3341next_replaced_global: String,
......@@ -41,6 +49,7 @@ constant_items: std.MultiArrayList(Constant.Item),
4149constant_extra: std.ArrayListUnmanaged(u32),
4250constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
4351
52pub const expected_args_len = 16;
4453pub const expected_fields_len = 32;
4554pub const expected_gep_indices_len = 8;
4655pub const expected_cases_len = 8;
......@@ -65,7 +74,7 @@ pub const String = enum(u32) {
6574 return self.toIndex() == null;
6675 }
6776
68 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
77 pub fn slice(self: String, b: *const Builder) ?[:0]const u8 {
6978 const index = self.toIndex() orelse return null;
7079 const start = b.string_indices.items[index];
7180 const end = b.string_indices.items[index + 1];
......@@ -85,20 +94,14 @@ pub const String = enum(u32) {
8594 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
8695 @compileError("invalid format string: '" ++ fmt_str ++ "'");
8796 assert(data.string != .none);
88 const slice = data.string.toSlice(data.builder) orelse
97 const sentinel_slice = data.string.slice(data.builder) orelse
8998 return writer.print("{d}", .{@intFromEnum(data.string)});
90 const full_slice = slice[0 .. slice.len + comptime @intFromBool(
99 try printEscapedString(sentinel_slice[0 .. sentinel_slice.len + comptime @intFromBool(
91100 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
92 )];
93 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or
94 !isValidIdentifier(full_slice);
95 if (need_quotes) try writer.writeByte('"');
96 for (full_slice) |character| switch (character) {
97 '\\' => try writer.writeAll("\\\\"),
98 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character),
99 else => try writer.print("\\{X:0>2}", .{character}),
100 };
101 if (need_quotes) try writer.writeByte('"');
101 )], if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
102 .always_quote
103 else
104 .quote_unless_valid_identifier, writer);
102105 }
103106 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
104107 return .{ .data = .{ .string = self, .builder = builder } };
......@@ -108,6 +111,7 @@ pub const String = enum(u32) {
108111 return @enumFromInt(@as(u32, @intCast((index orelse return .none) +
109112 @intFromEnum(String.empty))));
110113 }
114
111115 fn toIndex(self: String) ?usize {
112116 return std.math.sub(u32, @intFromEnum(self), @intFromEnum(String.empty)) catch null;
113117 }
......@@ -118,7 +122,7 @@ pub const String = enum(u32) {
118122 return @truncate(std.hash.Wyhash.hash(0, key));
119123 }
120124 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).?);
125 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).slice(ctx.builder).?);
122126 }
123127 };
124128};
......@@ -290,6 +294,17 @@ pub const Type = enum(u32) {
290294 };
291295 }
292296
297 pub fn pointerAddrSpace(self: Type, builder: *const Builder) AddrSpace {
298 switch (self) {
299 .ptr => return .default,
300 else => {
301 const item = builder.type_items.items[@intFromEnum(self)];
302 assert(item.tag == .pointer);
303 return @enumFromInt(item.data);
304 },
305 }
306 }
307
293308 pub fn isFunction(self: Type, builder: *const Builder) bool {
294309 return switch (self.tag(builder)) {
295310 .function, .vararg_function => true,
......@@ -606,7 +621,7 @@ pub const Type = enum(u32) {
606621 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
607622 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
608623 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
609 try writer.print("t{s}", .{extra.data.name.toSlice(data.builder).?});
624 try writer.print("t{s}", .{extra.data.name.slice(data.builder).?});
610625 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
611626 for (ints) |int| try writer.print("_{d}", .{int});
612627 try writer.writeByte('t');
......@@ -641,7 +656,7 @@ pub const Type = enum(u32) {
641656 .named_structure => {
642657 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
643658 try writer.writeAll("s_");
644 if (extra.id.toSlice(data.builder)) |id| try writer.writeAll(id);
659 if (extra.id.slice(data.builder)) |id| try writer.writeAll(id);
645660 },
646661 }
647662 return;
......@@ -823,6 +838,849 @@ pub const Type = enum(u32) {
823838 }
824839};
825840
841pub const Attribute = union(Kind) {
842 // Parameter Attributes
843 zeroext,
844 signext,
845 inreg,
846 byval: Type,
847 byref: Type,
848 preallocated: Type,
849 inalloca: Type,
850 sret: Type,
851 elementtype: Type,
852 @"align": Alignment,
853 @"noalias",
854 nocapture,
855 nofree,
856 nest,
857 returned,
858 nonnull,
859 dereferenceable: u32,
860 dereferenceable_or_null: u32,
861 swiftself,
862 swiftasync,
863 swifterror,
864 immarg,
865 noundef,
866 nofpclass: FpClass,
867 alignstack: Alignment,
868 allocalign,
869 allocptr,
870 readnone,
871 readonly,
872 writeonly,
873
874 // Function Attributes
875 //alignstack: Alignment,
876 allockind: AllocKind,
877 allocsize: AllocSize,
878 alwaysinline,
879 builtin,
880 cold,
881 convergent,
882 disable_sanitizer_information,
883 fn_ret_thunk_extern,
884 hot,
885 inlinehint,
886 jumptable,
887 memory: Memory,
888 minsize,
889 naked,
890 nobuiltin,
891 nocallback,
892 noduplicate,
893 //nofree,
894 noimplicitfloat,
895 @"noinline",
896 nomerge,
897 nonlazybind,
898 noprofile,
899 skipprofile,
900 noredzone,
901 noreturn,
902 norecurse,
903 willreturn,
904 nosync,
905 nounwind,
906 nosanitize_bounds,
907 nosanitize_coverage,
908 null_pointer_is_valid,
909 optforfuzzing,
910 optnone,
911 optsize,
912 //preallocated: Type,
913 returns_twice,
914 safestack,
915 sanitize_address,
916 sanitize_memory,
917 sanitize_thread,
918 sanitize_hwaddress,
919 sanitize_memtag,
920 speculative_load_hardening,
921 speculatable,
922 ssp,
923 sspstrong,
924 sspreq,
925 strictfp,
926 uwtable: UwTable,
927 nocf_check,
928 shadowcallstack,
929 mustprogress,
930 vscale_range: VScaleRange,
931
932 // Global Attributes
933 no_sanitize_address,
934 no_sanitize_hwaddress,
935 //sanitize_memtag,
936 sanitize_address_dyninit,
937
938 string: struct { kind: String, value: String },
939 none: noreturn,
940
941 pub const Index = enum(u32) {
942 _,
943
944 pub fn getKind(self: Index, builder: *const Builder) Kind {
945 return self.toStorage(builder).kind;
946 }
947
948 pub fn toAttribute(self: Index, builder: *const Builder) Attribute {
949 @setEvalBranchQuota(2_000);
950 const storage = self.toStorage(builder);
951 if (storage.kind.toString()) |kind| return .{ .string = .{
952 .kind = kind,
953 .value = @enumFromInt(storage.value),
954 } } else return switch (storage.kind) {
955 inline .zeroext,
956 .signext,
957 .inreg,
958 .byval,
959 .byref,
960 .preallocated,
961 .inalloca,
962 .sret,
963 .elementtype,
964 .@"align",
965 .@"noalias",
966 .nocapture,
967 .nofree,
968 .nest,
969 .returned,
970 .nonnull,
971 .dereferenceable,
972 .dereferenceable_or_null,
973 .swiftself,
974 .swiftasync,
975 .swifterror,
976 .immarg,
977 .noundef,
978 .nofpclass,
979 .alignstack,
980 .allocalign,
981 .allocptr,
982 .readnone,
983 .readonly,
984 .writeonly,
985 //.alignstack,
986 .allockind,
987 .allocsize,
988 .alwaysinline,
989 .builtin,
990 .cold,
991 .convergent,
992 .disable_sanitizer_information,
993 .fn_ret_thunk_extern,
994 .hot,
995 .inlinehint,
996 .jumptable,
997 .memory,
998 .minsize,
999 .naked,
1000 .nobuiltin,
1001 .nocallback,
1002 .noduplicate,
1003 //.nofree,
1004 .noimplicitfloat,
1005 .@"noinline",
1006 .nomerge,
1007 .nonlazybind,
1008 .noprofile,
1009 .skipprofile,
1010 .noredzone,
1011 .noreturn,
1012 .norecurse,
1013 .willreturn,
1014 .nosync,
1015 .nounwind,
1016 .nosanitize_bounds,
1017 .nosanitize_coverage,
1018 .null_pointer_is_valid,
1019 .optforfuzzing,
1020 .optnone,
1021 .optsize,
1022 //.preallocated,
1023 .returns_twice,
1024 .safestack,
1025 .sanitize_address,
1026 .sanitize_memory,
1027 .sanitize_thread,
1028 .sanitize_hwaddress,
1029 .sanitize_memtag,
1030 .speculative_load_hardening,
1031 .speculatable,
1032 .ssp,
1033 .sspstrong,
1034 .sspreq,
1035 .strictfp,
1036 .uwtable,
1037 .nocf_check,
1038 .shadowcallstack,
1039 .mustprogress,
1040 .vscale_range,
1041 .no_sanitize_address,
1042 .no_sanitize_hwaddress,
1043 .sanitize_address_dyninit,
1044 => |kind| {
1045 const field = @typeInfo(Attribute).Union.fields[@intFromEnum(kind)];
1046 comptime assert(std.mem.eql(u8, @tagName(kind), field.name));
1047 return @unionInit(Attribute, field.name, switch (field.type) {
1048 void => {},
1049 u32 => storage.value,
1050 Alignment, String, Type, UwTable => @enumFromInt(storage.value),
1051 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
1052 else => @compileError("bad payload type: " ++ @typeName(field.type)),
1053 });
1054 },
1055 .string, .none => unreachable,
1056 _ => unreachable,
1057 };
1058 }
1059
1060 const FormatData = struct {
1061 attribute_index: Index,
1062 builder: *const Builder,
1063 };
1064 fn format(
1065 data: FormatData,
1066 comptime fmt_str: []const u8,
1067 _: std.fmt.FormatOptions,
1068 writer: anytype,
1069 ) @TypeOf(writer).Error!void {
1070 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
1071 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1072 const attribute = data.attribute_index.toAttribute(data.builder);
1073 switch (attribute) {
1074 .zeroext,
1075 .signext,
1076 .inreg,
1077 .@"noalias",
1078 .nocapture,
1079 .nofree,
1080 .nest,
1081 .returned,
1082 .nonnull,
1083 .swiftself,
1084 .swiftasync,
1085 .swifterror,
1086 .immarg,
1087 .noundef,
1088 .allocalign,
1089 .allocptr,
1090 .readnone,
1091 .readonly,
1092 .writeonly,
1093 .alwaysinline,
1094 .builtin,
1095 .cold,
1096 .convergent,
1097 .disable_sanitizer_information,
1098 .fn_ret_thunk_extern,
1099 .hot,
1100 .inlinehint,
1101 .jumptable,
1102 .minsize,
1103 .naked,
1104 .nobuiltin,
1105 .nocallback,
1106 .noduplicate,
1107 .noimplicitfloat,
1108 .@"noinline",
1109 .nomerge,
1110 .nonlazybind,
1111 .noprofile,
1112 .skipprofile,
1113 .noredzone,
1114 .noreturn,
1115 .norecurse,
1116 .willreturn,
1117 .nosync,
1118 .nounwind,
1119 .nosanitize_bounds,
1120 .nosanitize_coverage,
1121 .null_pointer_is_valid,
1122 .optforfuzzing,
1123 .optnone,
1124 .optsize,
1125 .returns_twice,
1126 .safestack,
1127 .sanitize_address,
1128 .sanitize_memory,
1129 .sanitize_thread,
1130 .sanitize_hwaddress,
1131 .sanitize_memtag,
1132 .speculative_load_hardening,
1133 .speculatable,
1134 .ssp,
1135 .sspstrong,
1136 .sspreq,
1137 .strictfp,
1138 .nocf_check,
1139 .shadowcallstack,
1140 .mustprogress,
1141 .no_sanitize_address,
1142 .no_sanitize_hwaddress,
1143 .sanitize_address_dyninit,
1144 => try writer.print(" {s}", .{@tagName(attribute)}),
1145 .byval,
1146 .byref,
1147 .preallocated,
1148 .inalloca,
1149 .sret,
1150 .elementtype,
1151 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1152 .@"align" => |alignment| try writer.print("{}", .{alignment}),
1153 .dereferenceable,
1154 .dereferenceable_or_null,
1155 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1156 .nofpclass => |fpclass| {
1157 const Int = @typeInfo(FpClass).Struct.backing_integer.?;
1158 try writer.print("{s}(", .{@tagName(attribute)});
1159 var any = false;
1160 var remaining: Int = @bitCast(fpclass);
1161 inline for (@typeInfo(FpClass).Struct.decls) |decl| {
1162 if (!decl.is_pub) continue;
1163 const pattern: Int = @bitCast(@field(FpClass, decl.name));
1164 if (remaining & pattern == pattern) {
1165 if (!any) {
1166 try writer.writeByte(' ');
1167 any = true;
1168 }
1169 try writer.writeAll(decl.name);
1170 remaining &= ~pattern;
1171 }
1172 }
1173 try writer.writeByte(')');
1174 },
1175 .alignstack => |alignment| try writer.print(
1176 if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
1177 "{s}={d}"
1178 else
1179 "{s}({d})",
1180 .{ @tagName(attribute), alignment.toByteUnits() orelse return },
1181 ),
1182 .allockind => |allockind| {
1183 try writer.print("{s}(\"", .{@tagName(attribute)});
1184 var any = false;
1185 inline for (@typeInfo(AllocKind).Struct.fields) |field| {
1186 if (comptime std.mem.eql(u8, field.name, "_")) continue;
1187 if (@field(allockind, field.name)) {
1188 if (!any) {
1189 try writer.writeByte(',');
1190 any = true;
1191 }
1192 try writer.writeAll(field.name);
1193 }
1194 }
1195 try writer.writeAll("\")");
1196 },
1197 .allocsize => |allocsize| {
1198 try writer.print("{s}({d}", .{ @tagName(attribute), allocsize.elem_size });
1199 if (allocsize.num_elems != AllocSize.none)
1200 try writer.print(",{d}", .{allocsize.num_elems});
1201 try writer.writeByte(')');
1202 },
1203 .memory => |memory| try writer.print("{s}({s}, argmem: {s}, inaccessiblemem: {s})", .{
1204 @tagName(attribute),
1205 @tagName(memory.other),
1206 @tagName(memory.argmem),
1207 @tagName(memory.inaccessiblemem),
1208 }),
1209 .uwtable => |uwtable| if (uwtable != .none) {
1210 try writer.writeAll(@tagName(attribute));
1211 if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
1212 },
1213 .vscale_range => |vscale_range| try writer.print("{s}({d},{d})", .{
1214 @tagName(attribute),
1215 vscale_range.min.toByteUnits().?,
1216 vscale_range.max.toByteUnits() orelse 0,
1217 }),
1218 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1219 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1220 if (string_attr.value != .empty)
1221 try writer.print("={\"}", .{string_attr.value.fmt(data.builder)});
1222 },
1223 .none => unreachable,
1224 }
1225 }
1226 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1227 return .{ .data = .{ .attribute_index = self, .builder = builder } };
1228 }
1229
1230 fn toStorage(self: Index, builder: *const Builder) Storage {
1231 return builder.attributes.keys()[@intFromEnum(self)];
1232 }
1233
1234 fn toLlvm(self: Index, builder: *const Builder) *llvm.Attribute {
1235 assert(builder.useLibLlvm());
1236 return builder.llvm.attributes.items[@intFromEnum(self)];
1237 }
1238 };
1239
1240 pub const Kind = enum(u32) {
1241 // Parameter Attributes
1242 zeroext,
1243 signext,
1244 inreg,
1245 byval,
1246 byref,
1247 preallocated,
1248 inalloca,
1249 sret,
1250 elementtype,
1251 @"align",
1252 @"noalias",
1253 nocapture,
1254 nofree,
1255 nest,
1256 returned,
1257 nonnull,
1258 dereferenceable,
1259 dereferenceable_or_null,
1260 swiftself,
1261 swiftasync,
1262 swifterror,
1263 immarg,
1264 noundef,
1265 nofpclass,
1266 alignstack,
1267 allocalign,
1268 allocptr,
1269 readnone,
1270 readonly,
1271 writeonly,
1272
1273 // Function Attributes
1274 //alignstack,
1275 allockind,
1276 allocsize,
1277 alwaysinline,
1278 builtin,
1279 cold,
1280 convergent,
1281 disable_sanitizer_information,
1282 fn_ret_thunk_extern,
1283 hot,
1284 inlinehint,
1285 jumptable,
1286 memory,
1287 minsize,
1288 naked,
1289 nobuiltin,
1290 nocallback,
1291 noduplicate,
1292 //nofree,
1293 noimplicitfloat,
1294 @"noinline",
1295 nomerge,
1296 nonlazybind,
1297 noprofile,
1298 skipprofile,
1299 noredzone,
1300 noreturn,
1301 norecurse,
1302 willreturn,
1303 nosync,
1304 nounwind,
1305 nosanitize_bounds,
1306 nosanitize_coverage,
1307 null_pointer_is_valid,
1308 optforfuzzing,
1309 optnone,
1310 optsize,
1311 //preallocated,
1312 returns_twice,
1313 safestack,
1314 sanitize_address,
1315 sanitize_memory,
1316 sanitize_thread,
1317 sanitize_hwaddress,
1318 sanitize_memtag,
1319 speculative_load_hardening,
1320 speculatable,
1321 ssp,
1322 sspstrong,
1323 sspreq,
1324 strictfp,
1325 uwtable,
1326 nocf_check,
1327 shadowcallstack,
1328 mustprogress,
1329 vscale_range,
1330
1331 // Global Attributes
1332 no_sanitize_address,
1333 no_sanitize_hwaddress,
1334 //sanitize_memtag,
1335 sanitize_address_dyninit,
1336
1337 string = std.math.maxInt(u31) - 1,
1338 none = std.math.maxInt(u31),
1339 _,
1340
1341 pub const len = @typeInfo(Kind).Enum.fields.len - 2;
1342
1343 pub fn fromString(str: String) Kind {
1344 assert(!str.isAnon());
1345 return @enumFromInt(@intFromEnum(str));
1346 }
1347
1348 fn toString(self: Kind) ?String {
1349 const str: String = @enumFromInt(@intFromEnum(self));
1350 return if (str.isAnon()) null else str;
1351 }
1352 };
1353
1354 pub const FpClass = packed struct(u32) {
1355 signaling_nan: bool = false,
1356 quiet_nan: bool = false,
1357 negative_infinity: bool = false,
1358 negative_normal: bool = false,
1359 negative_subnormal: bool = false,
1360 negative_zero: bool = false,
1361 positive_zero: bool = false,
1362 positive_subnormal: bool = false,
1363 positive_normal: bool = false,
1364 positive_infinity: bool = false,
1365 _: u22 = 0,
1366
1367 pub const all = FpClass{
1368 .signaling_nan = true,
1369 .quiet_nan = true,
1370 .negative_infinity = true,
1371 .negative_normal = true,
1372 .negative_subnormal = true,
1373 .negative_zero = true,
1374 .positive_zero = true,
1375 .positive_subnormal = true,
1376 .positive_normal = true,
1377 .positive_infinity = true,
1378 };
1379
1380 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1381 pub const snan = FpClass{ .signaling_nan = true };
1382 pub const qnan = FpClass{ .quiet_nan = true };
1383
1384 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1385 pub const ninf = FpClass{ .negative_infinity = true };
1386 pub const pinf = FpClass{ .positive_infinity = true };
1387
1388 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1389 pub const nzero = FpClass{ .negative_zero = true };
1390 pub const pzero = FpClass{ .positive_zero = true };
1391
1392 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1393 pub const nsub = FpClass{ .negative_subnormal = true };
1394 pub const psub = FpClass{ .positive_subnormal = true };
1395
1396 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1397 pub const nnorm = FpClass{ .negative_normal = true };
1398 pub const pnorm = FpClass{ .positive_normal = true };
1399 };
1400
1401 pub const AllocKind = packed struct(u32) {
1402 alloc: bool,
1403 realloc: bool,
1404 free: bool,
1405 uninitialized: bool,
1406 zeroed: bool,
1407 aligned: bool,
1408 _: u26 = 0,
1409 };
1410
1411 pub const AllocSize = packed struct(u32) {
1412 elem_size: u16,
1413 num_elems: u16,
1414
1415 pub const none = std.math.maxInt(u16);
1416
1417 fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
1418 return .{ .num_elems = switch (self.num_elems) {
1419 else => self.num_elems,
1420 none => std.math.maxInt(u32),
1421 }, .elem_size = self.elem_size };
1422 }
1423 };
1424
1425 pub const Memory = packed struct(u32) {
1426 argmem: Effect,
1427 inaccessiblemem: Effect,
1428 other: Effect,
1429 _: u26 = 0,
1430
1431 pub const Effect = enum(u2) { none, read, write, readwrite };
1432 };
1433
1434 pub const UwTable = enum(u32) {
1435 none,
1436 sync,
1437 @"async",
1438
1439 pub const default = UwTable.@"async";
1440 };
1441
1442 pub const VScaleRange = packed struct(u32) {
1443 min: Alignment,
1444 max: Alignment,
1445 _: u20 = 0,
1446
1447 fn toLlvm(self: VScaleRange) packed struct(u64) { max: u32, min: u32 } {
1448 return .{
1449 .max = @intCast(self.max.toByteUnits() orelse 0),
1450 .min = @intCast(self.min.toByteUnits().?),
1451 };
1452 }
1453 };
1454
1455 pub fn getKind(self: Attribute) Kind {
1456 return switch (self) {
1457 else => self,
1458 .string => |string_attr| Kind.fromString(string_attr.kind),
1459 };
1460 }
1461
1462 const Storage = extern struct {
1463 kind: Kind,
1464 value: u32,
1465 };
1466
1467 fn toStorage(self: Attribute) Storage {
1468 return switch (self) {
1469 inline else => |value| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
1470 void => 0,
1471 u32 => value,
1472 Alignment, String, Type, UwTable => @intFromEnum(value),
1473 AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
1474 else => @compileError("bad payload type: " ++ @typeName(@TypeOf(value))),
1475 } },
1476 .string => |string_attr| .{
1477 .kind = Kind.fromString(string_attr.kind),
1478 .value = @intFromEnum(string_attr.value),
1479 },
1480 .none => unreachable,
1481 };
1482 }
1483};
1484
1485pub const Attributes = enum(u32) {
1486 none,
1487 _,
1488
1489 pub fn slice(self: Attributes, builder: *const Builder) []const Attribute.Index {
1490 const start = builder.attributes_indices.items[@intFromEnum(self)];
1491 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1492 return @ptrCast(builder.attributes_extra.items[start..end]);
1493 }
1494
1495 const FormatData = struct {
1496 attributes: Attributes,
1497 builder: *const Builder,
1498 };
1499 fn format(
1500 data: FormatData,
1501 comptime fmt_str: []const u8,
1502 fmt_opts: std.fmt.FormatOptions,
1503 writer: anytype,
1504 ) @TypeOf(writer).Error!void {
1505 for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{
1506 .attribute_index = attribute_index,
1507 .builder = data.builder,
1508 }, fmt_str, fmt_opts, writer);
1509 }
1510 pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) {
1511 return .{ .data = .{ .attributes = self, .builder = builder } };
1512 }
1513};
1514
1515pub const FunctionAttributes = enum(u32) {
1516 none,
1517 _,
1518
1519 const function_index = 0;
1520 const return_index = 1;
1521 const params_index = 2;
1522
1523 pub const Wip = struct {
1524 maps: Maps = .{},
1525
1526 const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index);
1527 const Maps = std.ArrayListUnmanaged(Map);
1528
1529 pub fn deinit(self: *Wip, builder: *const Builder) void {
1530 for (self.maps.items) |*map| map.deinit(builder.gpa);
1531 self.maps.deinit(builder.gpa);
1532 self.* = undefined;
1533 }
1534
1535 pub fn addFnAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1536 try self.addAttr(function_index, attribute, builder);
1537 }
1538
1539 pub fn addFnAttrIndex(
1540 self: *Wip,
1541 attribute_index: Attribute.Index,
1542 builder: *const Builder,
1543 ) Allocator.Error!void {
1544 try self.addAttrIndex(function_index, attribute_index, builder);
1545 }
1546
1547 pub fn removeFnAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1548 return self.removeAttr(function_index, attribute_kind);
1549 }
1550
1551 pub fn addRetAttr(self: *Wip, attribute: Attribute, builder: *Builder) Allocator.Error!void {
1552 try self.addAttr(return_index, attribute, builder);
1553 }
1554
1555 pub fn addRetAttrIndex(
1556 self: *Wip,
1557 attribute_index: Attribute.Index,
1558 builder: *const Builder,
1559 ) Allocator.Error!void {
1560 try self.addAttrIndex(return_index, attribute_index, builder);
1561 }
1562
1563 pub fn removeRetAttr(self: *Wip, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1564 return self.removeAttr(return_index, attribute_kind);
1565 }
1566
1567 pub fn addParamAttr(
1568 self: *Wip,
1569 param_index: usize,
1570 attribute: Attribute,
1571 builder: *Builder,
1572 ) Allocator.Error!void {
1573 try self.addAttr(params_index + param_index, attribute, builder);
1574 }
1575
1576 pub fn addParamAttrIndex(
1577 self: *Wip,
1578 param_index: usize,
1579 attribute_index: Attribute.Index,
1580 builder: *const Builder,
1581 ) Allocator.Error!void {
1582 try self.addAttrIndex(params_index + param_index, attribute_index, builder);
1583 }
1584
1585 pub fn removeParamAttr(
1586 self: *Wip,
1587 param_index: usize,
1588 attribute_kind: Attribute.Kind,
1589 ) Allocator.Error!bool {
1590 return self.removeAttr(params_index + param_index, attribute_kind);
1591 }
1592
1593 pub fn finish(self: *const Wip, builder: *Builder) Allocator.Error!FunctionAttributes {
1594 const attributes = try builder.gpa.alloc(Attributes, self.maps.items.len);
1595 defer builder.gpa.free(attributes);
1596 for (attributes, self.maps.items) |*attribute, map|
1597 attribute.* = try builder.attrs(map.values());
1598 return builder.fnAttrs(attributes);
1599 }
1600
1601 fn addAttr(
1602 self: *Wip,
1603 index: usize,
1604 attribute: Attribute,
1605 builder: *Builder,
1606 ) Allocator.Error!void {
1607 const map = try self.getOrPutMap(builder.gpa, index);
1608 try map.put(builder.gpa, attribute.getKind(), try builder.attr(attribute));
1609 }
1610
1611 fn addAttrIndex(
1612 self: *Wip,
1613 index: usize,
1614 attribute_index: Attribute.Index,
1615 builder: *const Builder,
1616 ) Allocator.Error!void {
1617 const map = try self.getOrPutMap(builder.gpa, index);
1618 try map.put(builder.gpa, attribute_index.getKind(builder), attribute_index);
1619 }
1620
1621 fn removeAttr(self: *Wip, index: usize, attribute_kind: Attribute.Kind) Allocator.Error!bool {
1622 const map = self.getMap(index) orelse return false;
1623 return map.swapRemove(attribute_kind);
1624 }
1625
1626 fn getOrPutMap(self: *Wip, allocator: Allocator, index: usize) Allocator.Error!*Map {
1627 if (index >= self.maps.items.len)
1628 try self.maps.appendNTimes(allocator, .{}, index + 1 - self.maps.items.len);
1629 return &self.maps.items[index];
1630 }
1631
1632 fn getMap(self: *Wip, index: usize) ?*Map {
1633 return if (index >= self.maps.items.len) null else &self.maps.items[index];
1634 }
1635
1636 fn ensureTotalLength(self: *Wip, new_len: usize) Allocator.Error!void {
1637 try self.maps.appendNTimes(
1638 .{},
1639 std.math.sub(usize, new_len, self.maps.items.len) catch return,
1640 );
1641 }
1642 };
1643
1644 pub fn func(self: FunctionAttributes, builder: *const Builder) Attributes {
1645 return self.get(function_index, builder);
1646 }
1647
1648 pub fn ret(self: FunctionAttributes, builder: *const Builder) Attributes {
1649 return self.get(return_index, builder);
1650 }
1651
1652 pub fn param(self: FunctionAttributes, param_index: usize, builder: *const Builder) Attributes {
1653 return self.get(params_index + param_index, builder);
1654 }
1655
1656 pub fn toWip(self: FunctionAttributes, builder: *const Builder) Allocator.Error!Wip {
1657 var wip: Wip = .{};
1658 errdefer wip.deinit(builder);
1659 const attributes_slice = self.slice(builder);
1660 try wip.maps.ensureTotalCapacityPrecise(builder.gpa, attributes_slice.len);
1661 for (attributes_slice) |attributes| {
1662 const map = wip.maps.addOneAssumeCapacity();
1663 map.* = .{};
1664 const attribute_slice = attributes.slice(builder);
1665 try map.ensureTotalCapacity(builder.gpa, attribute_slice.len);
1666 for (attributes.slice(builder)) |attribute|
1667 map.putAssumeCapacityNoClobber(attribute.getKind(builder), attribute);
1668 }
1669 return wip;
1670 }
1671
1672 fn get(self: FunctionAttributes, index: usize, builder: *const Builder) Attributes {
1673 const attribute_slice = self.slice(builder);
1674 return if (index < attribute_slice.len) attribute_slice[index] else .none;
1675 }
1676
1677 fn slice(self: FunctionAttributes, builder: *const Builder) []const Attributes {
1678 const start = builder.attributes_indices.items[@intFromEnum(self)];
1679 const end = builder.attributes_indices.items[@intFromEnum(self) + 1];
1680 return @ptrCast(builder.attributes_extra.items[start..end]);
1681 }
1682};
1683
8261684pub const Linkage = enum {
8271685 external,
8281686 private,
......@@ -1053,6 +1911,127 @@ pub const Alignment = enum(u6) {
10531911 }
10541912};
10551913
1914pub const CallConv = enum(u10) {
1915 ccc,
1916
1917 fastcc = 8,
1918 coldcc,
1919 ghccc,
1920
1921 webkit_jscc = 12,
1922 anyregcc,
1923 preserve_mostcc,
1924 preserve_allcc,
1925 swiftcc,
1926 cxx_fast_tlscc,
1927 tailcc,
1928 cfguard_checkcc,
1929 swifttailcc,
1930
1931 x86_stdcallcc = 64,
1932 x86_fastcallcc,
1933 arm_apcscc,
1934 arm_aapcscc,
1935 arm_aapcs_vfpcc,
1936 msp430_intrcc,
1937 x86_thiscallcc,
1938 ptx_kernel,
1939 ptx_device,
1940
1941 spir_func = 75,
1942 spir_kernel,
1943 intel_ocl_bicc,
1944 x86_64_sysvcc,
1945 win64cc,
1946 x86_vectorcallcc,
1947 hhvmcc,
1948 hhvm_ccc,
1949 x86_intrcc,
1950 avr_intrcc,
1951 avr_signalcc,
1952
1953 amdgpu_vs = 87,
1954 amdgpu_gs,
1955 amdgpu_ps,
1956 amdgpu_cs,
1957 amdgpu_kernel,
1958 x86_regcallcc,
1959 amdgpu_hs,
1960
1961 amdgpu_ls = 95,
1962 amdgpu_es,
1963 aarch64_vector_pcs,
1964 aarch64_sve_vector_pcs,
1965
1966 amdgpu_gfx = 100,
1967
1968 aarch64_sme_preservemost_from_x0 = 102,
1969 aarch64_sme_preservemost_from_x2,
1970
1971 _,
1972
1973 pub const default = CallConv.ccc;
1974
1975 pub fn format(
1976 self: CallConv,
1977 comptime _: []const u8,
1978 _: std.fmt.FormatOptions,
1979 writer: anytype,
1980 ) @TypeOf(writer).Error!void {
1981 switch (self) {
1982 default => {},
1983 .fastcc,
1984 .coldcc,
1985 .ghccc,
1986 .webkit_jscc,
1987 .anyregcc,
1988 .preserve_mostcc,
1989 .preserve_allcc,
1990 .swiftcc,
1991 .cxx_fast_tlscc,
1992 .tailcc,
1993 .cfguard_checkcc,
1994 .swifttailcc,
1995 .x86_stdcallcc,
1996 .x86_fastcallcc,
1997 .arm_apcscc,
1998 .arm_aapcscc,
1999 .arm_aapcs_vfpcc,
2000 .msp430_intrcc,
2001 .x86_thiscallcc,
2002 .ptx_kernel,
2003 .ptx_device,
2004 .spir_func,
2005 .spir_kernel,
2006 .intel_ocl_bicc,
2007 .x86_64_sysvcc,
2008 .win64cc,
2009 .x86_vectorcallcc,
2010 .hhvmcc,
2011 .hhvm_ccc,
2012 .x86_intrcc,
2013 .avr_intrcc,
2014 .avr_signalcc,
2015 .amdgpu_vs,
2016 .amdgpu_gs,
2017 .amdgpu_ps,
2018 .amdgpu_cs,
2019 .amdgpu_kernel,
2020 .x86_regcallcc,
2021 .amdgpu_hs,
2022 .amdgpu_ls,
2023 .amdgpu_es,
2024 .aarch64_vector_pcs,
2025 .aarch64_sve_vector_pcs,
2026 .amdgpu_gfx,
2027 .aarch64_sme_preservemost_from_x0,
2028 .aarch64_sme_preservemost_from_x2,
2029 => try writer.print(" {s}", .{@tagName(self)}),
2030 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
2031 }
2032 }
2033};
2034
10562035pub const Global = struct {
10572036 linkage: Linkage = .external,
10582037 preemption: Preemption = .dso_preemptable,
......@@ -1170,7 +2149,7 @@ pub const Global = struct {
11702149 fn updateName(self: Index, builder: *const Builder) void {
11712150 if (!builder.useLibLlvm()) return;
11722151 const index = @intFromEnum(self.unwrap(builder));
1173 const name_slice = self.name(builder).toSlice(builder) orelse "";
2152 const name_slice = self.name(builder).slice(builder) orelse "";
11742153 builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
11752154 }
11762155
......@@ -1301,6 +2280,8 @@ pub const Variable = struct {
13012280
13022281pub const Function = struct {
13032282 global: Global.Index,
2283 call_conv: CallConv = CallConv.default,
2284 attributes: FunctionAttributes = .none,
13042285 section: String = .none,
13052286 alignment: Alignment = .default,
13062287 blocks: []const Block = &.{},
......@@ -1364,6 +2345,8 @@ pub const Function = struct {
13642345 block,
13652346 br,
13662347 br_cond,
2348 call,
2349 @"call fast",
13672350 extractelement,
13682351 extractvalue,
13692352 fadd,
......@@ -1454,6 +2437,10 @@ pub const Function = struct {
14542437 @"mul nsw",
14552438 @"mul nuw",
14562439 @"mul nuw nsw",
2440 @"musttail call",
2441 @"musttail call fast",
2442 @"notail call",
2443 @"notail call fast",
14572444 @"or",
14582445 phi,
14592446 @"phi fast",
......@@ -1481,6 +2468,8 @@ pub const Function = struct {
14812468 @"sub nuw",
14822469 @"sub nuw nsw",
14832470 @"switch",
2471 @"tail call",
2472 @"tail call fast",
14842473 trunc,
14852474 udiv,
14862475 @"udiv exact",
......@@ -1511,6 +2500,7 @@ pub const Function = struct {
15112500 .br_cond,
15122501 .ret,
15132502 .@"ret void",
2503 .@"switch",
15142504 .@"unreachable",
15152505 => true,
15162506 else => false,
......@@ -1528,8 +2518,19 @@ pub const Function = struct {
15282518 .@"store atomic",
15292519 .@"store atomic volatile",
15302520 .@"store volatile",
2521 .@"switch",
15312522 .@"unreachable",
15322523 => false,
2524 .call,
2525 .@"call fast",
2526 .@"musttail call",
2527 .@"musttail call fast",
2528 .@"notail call",
2529 .@"notail call fast",
2530 .@"tail call",
2531 .@"tail call fast",
2532 .unimplemented,
2533 => self.typeOfWip(wip) != .void,
15332534 else => true,
15342535 };
15352536 }
......@@ -1625,6 +2626,15 @@ pub const Function = struct {
16252626 .@"switch",
16262627 .@"unreachable",
16272628 => .none,
2629 .call,
2630 .@"call fast",
2631 .@"musttail call",
2632 .@"musttail call fast",
2633 .@"notail call",
2634 .@"notail call fast",
2635 .@"tail call",
2636 .@"tail call fast",
2637 => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
16282638 .extractelement => wip.extraData(ExtractElement, instruction.data)
16292639 .val.typeOfWip(wip).childType(wip.builder),
16302640 .extractvalue => {
......@@ -1813,6 +2823,15 @@ pub const Function = struct {
18132823 .@"switch",
18142824 .@"unreachable",
18152825 => .none,
2826 .call,
2827 .@"call fast",
2828 .@"musttail call",
2829 .@"musttail call fast",
2830 .@"notail call",
2831 .@"notail call fast",
2832 .@"tail call",
2833 .@"tail call fast",
2834 => function.extraData(Call, instruction.data).ty.functionReturn(builder),
18162835 .extractelement => function.extraData(ExtractElement, instruction.data)
18172836 .val.typeOf(function_index, builder).childType(builder),
18182837 .extractvalue => {
......@@ -1955,7 +2974,7 @@ pub const Function = struct {
19552974 return if (wip.builder.strip)
19562975 ""
19572976 else
1958 wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?;
2977 wip.names.items[@intFromEnum(self)].slice(wip.builder).?;
19592978 }
19602979 };
19612980
......@@ -2063,6 +3082,30 @@ pub const Function = struct {
20633082 rhs: Value,
20643083 };
20653084
3085 pub const Call = struct {
3086 info: Info,
3087 attributes: FunctionAttributes,
3088 ty: Type,
3089 callee: Value,
3090 args_len: u32,
3091 //args: [args_len]Value,
3092
3093 pub const Kind = enum {
3094 normal,
3095 fast,
3096 musttail,
3097 musttail_fast,
3098 notail,
3099 notail_fast,
3100 tail,
3101 tail_fast,
3102 };
3103 pub const Info = packed struct(u32) {
3104 call_conv: CallConv,
3105 _: u22 = undefined,
3106 };
3107 };
3108
20663109 pub const VaArg = struct {
20673110 list: Value,
20683111 type: Type,
......@@ -2117,8 +3160,17 @@ pub const Function = struct {
21173160 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
21183161 @field(result, field.name) = switch (field.type) {
21193162 u32 => value,
2120 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
2121 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3163 Alignment,
3164 AtomicOrdering,
3165 Block.Index,
3166 FunctionAttributes,
3167 Type,
3168 Value,
3169 => @enumFromInt(value),
3170 MemoryAccessInfo,
3171 Instruction.Alloca.Info,
3172 Instruction.Call.Info,
3173 => @bitCast(value),
21223174 else => @compileError("bad field type: " ++ @typeName(field.type)),
21233175 };
21243176 return .{
......@@ -2243,7 +3295,7 @@ pub const WipFunction = struct {
22433295 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
22443296 self.builder.llvm.context.appendBasicBlock(
22453297 self.function.toLlvm(self.builder),
2246 final_name.toSlice(self.builder).?,
3298 final_name.slice(self.builder).?,
22473299 ),
22483300 );
22493301 return index;
......@@ -2755,7 +3807,7 @@ pub const WipFunction = struct {
27553807 @intFromEnum(addr_space),
27563808 instruction.llvmName(self),
27573809 );
2758 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
3810 if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
27593811 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
27603812 }
27613813 return instruction.toValue();
......@@ -2811,7 +3863,7 @@ pub const WipFunction = struct {
28113863 instruction.llvmName(self),
28123864 );
28133865 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2814 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
3866 if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
28153867 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
28163868 }
28173869 return instruction.toValue();
......@@ -2865,7 +3917,7 @@ pub const WipFunction = struct {
28653917 .@"volatile" => llvm_instruction.setVolatile(.True),
28663918 }
28673919 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2868 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
3920 if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
28693921 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
28703922 }
28713923 return instruction;
......@@ -3162,6 +4214,102 @@ pub const WipFunction = struct {
31624214 return self.selectTag(.@"select fast", cond, lhs, rhs, name);
31634215 }
31644216
4217 pub fn call(
4218 self: *WipFunction,
4219 kind: Instruction.Call.Kind,
4220 call_conv: CallConv,
4221 function_attributes: FunctionAttributes,
4222 ty: Type,
4223 callee: Value,
4224 args: []const Value,
4225 name: []const u8,
4226 ) Allocator.Error!Value {
4227 const ret_ty = ty.functionReturn(self.builder);
4228 assert(ty.isFunction(self.builder));
4229 assert(callee.typeOfWip(self).isPointer(self.builder));
4230 const params = ty.functionParameters(self.builder);
4231 for (params, args[0..params.len]) |param, arg_val| assert(param == arg_val.typeOfWip(self));
4232
4233 try self.ensureUnusedExtraCapacity(1, Instruction.Call, args.len);
4234 const instruction = try self.addInst(switch (ret_ty) {
4235 .void => null,
4236 else => name,
4237 }, .{
4238 .tag = .call,
4239 .data = self.addExtraAssumeCapacity(Instruction.Call{
4240 .info = .{ .call_conv = call_conv },
4241 .attributes = function_attributes,
4242 .ty = ty,
4243 .callee = callee,
4244 .args_len = @intCast(args.len),
4245 }),
4246 });
4247 self.extra.appendSliceAssumeCapacity(@ptrCast(args));
4248 if (self.builder.useLibLlvm()) {
4249 const ExpectedContents = [expected_args_len]*llvm.Value;
4250 var stack align(@alignOf(ExpectedContents)) =
4251 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
4252 const allocator = stack.get();
4253
4254 const llvm_args = try allocator.alloc(*llvm.Value, args.len);
4255 defer allocator.free(llvm_args);
4256 for (llvm_args, args) |*llvm_arg, arg_val| llvm_arg.* = arg_val.toLlvm(self);
4257
4258 switch (kind) {
4259 .normal,
4260 .musttail,
4261 .notail,
4262 .tail,
4263 => self.llvm.builder.setFastMath(false),
4264 .fast,
4265 .musttail_fast,
4266 .notail_fast,
4267 .tail_fast,
4268 => self.llvm.builder.setFastMath(true),
4269 }
4270 const llvm_instruction = self.llvm.builder.buildCall(
4271 ty.toLlvm(self.builder),
4272 callee.toLlvm(self),
4273 llvm_args.ptr,
4274 @intCast(llvm_args.len),
4275 switch (ret_ty) {
4276 .void => "",
4277 else => instruction.llvmName(self),
4278 },
4279 );
4280 llvm_instruction.setInstructionCallConv(@enumFromInt(@intFromEnum(call_conv)));
4281 llvm_instruction.setTailCallKind(switch (kind) {
4282 .normal, .fast => .None,
4283 .musttail, .musttail_fast => .MustTail,
4284 .notail, .notail_fast => .NoTail,
4285 .tail, .tail_fast => .Tail,
4286 });
4287 for (0.., function_attributes.slice(self.builder)) |index, attributes| {
4288 const attribute_index = @as(llvm.AttributeIndex, @intCast(index)) -% 1;
4289 for (attributes.slice(self.builder)) |attribute| llvm_instruction.addCallSiteAttribute(
4290 attribute_index,
4291 attribute.toLlvm(self.builder),
4292 );
4293 }
4294 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
4295 }
4296 return instruction.toValue();
4297 }
4298
4299 pub fn callAsm(
4300 self: *WipFunction,
4301 function_attributes: FunctionAttributes,
4302 ty: Type,
4303 kind: Constant.Asm.Info,
4304 assembly: String,
4305 constraints: String,
4306 args: []const Value,
4307 name: []const u8,
4308 ) Allocator.Error!Value {
4309 const callee = try self.builder.asmValue(ty, kind, assembly, constraints);
4310 return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
4311 }
4312
31654313 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
31664314 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
31674315 const instruction = try self.addInst(name, .{
......@@ -3246,8 +4394,17 @@ pub const WipFunction = struct {
32464394 const value = @field(extra, field.name);
32474395 wip_extra.items[wip_extra.index] = switch (field.type) {
32484396 u32 => value,
3249 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3250 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
4397 Alignment,
4398 AtomicOrdering,
4399 Block.Index,
4400 FunctionAttributes,
4401 Type,
4402 Value,
4403 => @intFromEnum(value),
4404 MemoryAccessInfo,
4405 Instruction.Alloca.Info,
4406 Instruction.Call.Info,
4407 => @bitCast(value),
32514408 else => @compileError("bad field type: " ++ @typeName(field.type)),
32524409 };
32534410 wip_extra.index += 1;
......@@ -3256,13 +4413,14 @@ pub const WipFunction = struct {
32564413 }
32574414
32584415 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
3259 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) @compileError("use appendValues");
4416 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value)
4417 @compileError("use appendMappedValues");
32604418 const data: []const u32 = @ptrCast(slice);
32614419 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
32624420 wip_extra.index += @intCast(data.len);
32634421 }
32644422
3265 fn appendValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
4423 fn appendMappedValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
32664424 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
32674425 extra.* = @intFromEnum(ctx.map(val));
32684426 wip_extra.index += @intCast(vals.len);
......@@ -3494,6 +4652,26 @@ pub const WipFunction = struct {
34944652 .@"else" = extra.@"else",
34954653 });
34964654 },
4655 .call,
4656 .@"call fast",
4657 .@"musttail call",
4658 .@"musttail call fast",
4659 .@"notail call",
4660 .@"notail call fast",
4661 .@"tail call",
4662 .@"tail call fast",
4663 => {
4664 var extra = self.extraDataTrail(Instruction.Call, instruction.data);
4665 const args = extra.trail.next(extra.data.args_len, Value, self);
4666 instruction.data = wip_extra.addExtra(Instruction.Call{
4667 .info = extra.data.info,
4668 .attributes = extra.data.attributes,
4669 .ty = extra.data.ty,
4670 .callee = instructions.map(extra.data.callee),
4671 .args_len = extra.data.args_len,
4672 });
4673 wip_extra.appendMappedValues(args, instructions);
4674 },
34974675 .extractvalue => {
34984676 var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
34994677 const indices = extra.trail.next(extra.data.indices_len, u32, self);
......@@ -3517,7 +4695,7 @@ pub const WipFunction = struct {
35174695 .base = instructions.map(extra.data.base),
35184696 .indices_len = extra.data.indices_len,
35194697 });
3520 wip_extra.appendValues(indices, instructions);
4698 wip_extra.appendMappedValues(indices, instructions);
35214699 },
35224700 .insertelement => {
35234701 const extra = self.extraData(Instruction.InsertElement, instruction.data);
......@@ -3559,7 +4737,7 @@ pub const WipFunction = struct {
35594737 instruction.data = wip_extra.addExtra(Instruction.Phi{
35604738 .type = extra.data.type,
35614739 });
3562 wip_extra.appendValues(incoming_vals, instructions);
4740 wip_extra.appendMappedValues(incoming_vals, instructions);
35634741 wip_extra.appendSlice(incoming_blocks);
35644742 },
35654743 .select,
......@@ -3932,8 +5110,17 @@ pub const WipFunction = struct {
39325110 const value = @field(extra, field.name);
39335111 self.extra.appendAssumeCapacity(switch (field.type) {
39345112 u32 => value,
3935 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3936 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
5113 Alignment,
5114 AtomicOrdering,
5115 Block.Index,
5116 FunctionAttributes,
5117 Type,
5118 Value,
5119 => @intFromEnum(value),
5120 MemoryAccessInfo,
5121 Instruction.Alloca.Info,
5122 Instruction.Call.Info,
5123 => @bitCast(value),
39375124 else => @compileError("bad field type: " ++ @typeName(field.type)),
39385125 });
39395126 }
......@@ -3971,8 +5158,17 @@ pub const WipFunction = struct {
39715158 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
39725159 @field(result, field.name) = switch (field.type) {
39735160 u32 => value,
3974 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
3975 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
5161 Alignment,
5162 AtomicOrdering,
5163 Block.Index,
5164 FunctionAttributes,
5165 Type,
5166 Value,
5167 => @enumFromInt(value),
5168 MemoryAccessInfo,
5169 Instruction.Alloca.Info,
5170 Instruction.Call.Info,
5171 => @bitCast(value),
39765172 else => @compileError("bad field type: " ++ @typeName(field.type)),
39775173 };
39785174 return .{
......@@ -4092,7 +5288,7 @@ pub const Constant = enum(u32) {
40925288
40935289 const first_global: Constant = @enumFromInt(1 << 30);
40945290
4095 pub const Tag = enum(u6) {
5291 pub const Tag = enum(u7) {
40965292 positive_integer,
40975293 negative_integer,
40985294 half,
......@@ -4152,6 +5348,22 @@ pub const Constant = enum(u32) {
41525348 @"and",
41535349 @"or",
41545350 xor,
5351 @"asm",
5352 @"asm sideeffect",
5353 @"asm alignstack",
5354 @"asm sideeffect alignstack",
5355 @"asm inteldialect",
5356 @"asm sideeffect inteldialect",
5357 @"asm alignstack inteldialect",
5358 @"asm sideeffect alignstack inteldialect",
5359 @"asm unwind",
5360 @"asm sideeffect unwind",
5361 @"asm alignstack unwind",
5362 @"asm sideeffect alignstack unwind",
5363 @"asm inteldialect unwind",
5364 @"asm sideeffect inteldialect unwind",
5365 @"asm alignstack inteldialect unwind",
5366 @"asm sideeffect alignstack inteldialect unwind",
41555367 };
41565368
41575369 pub const Item = struct {
......@@ -4247,6 +5459,19 @@ pub const Constant = enum(u32) {
42475459 rhs: Constant,
42485460 };
42495461
5462 pub const Asm = extern struct {
5463 type: Type,
5464 assembly: String,
5465 constraints: String,
5466
5467 pub const Info = packed struct {
5468 sideeffect: bool = false,
5469 alignstack: bool = false,
5470 inteldialect: bool = false,
5471 unwind: bool = false,
5472 };
5473 };
5474
42505475 pub fn unwrap(self: Constant) union(enum) {
42515476 constant: u30,
42525477 global: Global.Index,
......@@ -4294,7 +5519,7 @@ pub const Constant = enum(u32) {
42945519 .string,
42955520 .string_null,
42965521 => builder.arrayTypeAssumeCapacity(
4297 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +
5522 @as(String, @enumFromInt(item.data)).slice(builder).?.len +
42985523 @intFromBool(item.tag == .string_null),
42995524 .i8,
43005525 ),
......@@ -4365,6 +5590,23 @@ pub const Constant = enum(u32) {
43655590 .@"or",
43665591 .xor,
43675592 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
5593 .@"asm",
5594 .@"asm sideeffect",
5595 .@"asm alignstack",
5596 .@"asm sideeffect alignstack",
5597 .@"asm inteldialect",
5598 .@"asm sideeffect inteldialect",
5599 .@"asm alignstack inteldialect",
5600 .@"asm sideeffect alignstack inteldialect",
5601 .@"asm unwind",
5602 .@"asm sideeffect unwind",
5603 .@"asm alignstack unwind",
5604 .@"asm sideeffect alignstack unwind",
5605 .@"asm inteldialect unwind",
5606 .@"asm sideeffect inteldialect unwind",
5607 .@"asm alignstack inteldialect unwind",
5608 .@"asm sideeffect alignstack inteldialect unwind",
5609 => .ptr,
43685610 };
43695611 },
43705612 .global => |global| return builder.ptrTypeAssumeCapacity(
......@@ -4712,6 +5954,30 @@ pub const Constant = enum(u32) {
47125954 extra.rhs.fmt(data.builder),
47135955 });
47145956 },
5957 .@"asm",
5958 .@"asm sideeffect",
5959 .@"asm alignstack",
5960 .@"asm sideeffect alignstack",
5961 .@"asm inteldialect",
5962 .@"asm sideeffect inteldialect",
5963 .@"asm alignstack inteldialect",
5964 .@"asm sideeffect alignstack inteldialect",
5965 .@"asm unwind",
5966 .@"asm sideeffect unwind",
5967 .@"asm alignstack unwind",
5968 .@"asm sideeffect alignstack unwind",
5969 .@"asm inteldialect unwind",
5970 .@"asm sideeffect inteldialect unwind",
5971 .@"asm alignstack inteldialect unwind",
5972 .@"asm sideeffect alignstack inteldialect unwind",
5973 => |tag| {
5974 const extra = data.builder.constantExtraData(Asm, item.data);
5975 try writer.print("{s} {\"}, {\"}", .{
5976 @tagName(tag),
5977 extra.assembly.fmt(data.builder),
5978 extra.constraints.fmt(data.builder),
5979 });
5980 },
47155981 }
47165982 },
47175983 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
......@@ -4819,10 +6085,11 @@ pub fn init(options: Options) InitError!Builder {
48196085 .source_filename = .none,
48206086 .data_layout = .none,
48216087 .target_triple = .none,
6088 .module_asm = .{},
48226089
48236090 .string_map = .{},
4824 .string_bytes = .{},
48256091 .string_indices = .{},
6092 .string_bytes = .{},
48266093
48276094 .types = .{},
48286095 .next_unnamed_type = @enumFromInt(0),
......@@ -4831,6 +6098,11 @@ pub fn init(options: Options) InitError!Builder {
48316098 .type_items = .{},
48326099 .type_extra = .{},
48336100
6101 .attributes = .{},
6102 .attributes_map = .{},
6103 .attributes_indices = .{},
6104 .attributes_extra = .{},
6105
48346106 .globals = .{},
48356107 .next_unnamed_global = @enumFromInt(0),
48366108 .next_replaced_global = .none,
......@@ -4844,7 +6116,18 @@ pub fn init(options: Options) InitError!Builder {
48446116 .constant_extra = .{},
48456117 .constant_limbs = .{},
48466118 };
4847 if (self.useLibLlvm()) self.llvm = .{ .context = llvm.Context.create() };
6119 if (self.useLibLlvm()) self.llvm = .{
6120 .context = llvm.Context.create(),
6121 .module = null,
6122 .target = null,
6123 .di_builder = null,
6124 .di_compile_unit = null,
6125 .attribute_kind_ids = null,
6126 .attributes = .{},
6127 .types = .{},
6128 .globals = .{},
6129 .constants = .{},
6130 };
48486131 errdefer self.deinit();
48496132
48506133 try self.string_indices.append(self.gpa, 0);
......@@ -4853,7 +6136,7 @@ pub fn init(options: Options) InitError!Builder {
48536136 if (options.name.len > 0) self.source_filename = try self.string(options.name);
48546137 self.initializeLLVMTarget(options.target.cpu.arch);
48556138 if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(
4856 (self.source_filename.toSlice(&self) orelse "").ptr,
6139 (self.source_filename.slice(&self) orelse "").ptr,
48576140 self.llvm.context,
48586141 );
48596142
......@@ -4864,20 +6147,20 @@ pub fn init(options: Options) InitError!Builder {
48646147 var error_message: [*:0]const u8 = undefined;
48656148 var target: *llvm.Target = undefined;
48666149 if (llvm.Target.getFromTriple(
4867 self.target_triple.toSlice(&self).?,
6150 self.target_triple.slice(&self).?,
48686151 &target,
48696152 &error_message,
48706153 ).toBool()) {
48716154 defer llvm.disposeMessage(error_message);
48726155
48736156 log.err("LLVM failed to parse '{s}': {s}", .{
4874 self.target_triple.toSlice(&self).?,
6157 self.target_triple.slice(&self).?,
48756158 error_message,
48766159 });
48776160 return InitError.InvalidLlvmTriple;
48786161 }
48796162 self.llvm.target = target;
4880 self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?);
6163 self.llvm.module.?.setTarget(self.target_triple.slice(&self).?);
48816164 }
48826165 }
48836166
......@@ -4902,6 +6185,16 @@ pub fn init(options: Options) InitError!Builder {
49026185 assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
49036186 }
49046187
6188 {
6189 if (self.useLibLlvm()) {
6190 self.llvm.attribute_kind_ids = try self.gpa.create([Attribute.Kind.len]c_uint);
6191 @memset(self.llvm.attribute_kind_ids.?, 0);
6192 }
6193 try self.attributes_indices.append(self.gpa, 0);
6194 assert(try self.attrs(&.{}) == .none);
6195 assert(try self.fnAttrs(&.{}) == .none);
6196 }
6197
49056198 assert(try self.intConst(.i1, 0) == .false);
49066199 assert(try self.intConst(.i1, 1) == .true);
49076200 assert(try self.noneConst(.token) == .none);
......@@ -4910,9 +6203,11 @@ pub fn init(options: Options) InitError!Builder {
49106203}
49116204
49126205pub fn deinit(self: *Builder) void {
6206 self.module_asm.deinit(self.gpa);
6207
49136208 self.string_map.deinit(self.gpa);
4914 self.string_bytes.deinit(self.gpa);
49156209 self.string_indices.deinit(self.gpa);
6210 self.string_bytes.deinit(self.gpa);
49166211
49176212 self.types.deinit(self.gpa);
49186213 self.next_unique_type_id.deinit(self.gpa);
......@@ -4920,6 +6215,11 @@ pub fn deinit(self: *Builder) void {
49206215 self.type_items.deinit(self.gpa);
49216216 self.type_extra.deinit(self.gpa);
49226217
6218 self.attributes.deinit(self.gpa);
6219 self.attributes_map.deinit(self.gpa);
6220 self.attributes_indices.deinit(self.gpa);
6221 self.attributes_extra.deinit(self.gpa);
6222
49236223 self.globals.deinit(self.gpa);
49246224 self.next_unique_global_id.deinit(self.gpa);
49256225 self.aliases.deinit(self.gpa);
......@@ -4936,6 +6236,8 @@ pub fn deinit(self: *Builder) void {
49366236 self.llvm.constants.deinit(self.gpa);
49376237 self.llvm.globals.deinit(self.gpa);
49386238 self.llvm.types.deinit(self.gpa);
6239 self.llvm.attributes.deinit(self.gpa);
6240 if (self.llvm.attribute_kind_ids) |attribute_kind_ids| self.gpa.destroy(attribute_kind_ids);
49396241 if (self.llvm.di_builder) |di_builder| di_builder.dispose();
49406242 if (self.llvm.module) |module| module.dispose();
49416243 self.llvm.context.dispose();
......@@ -5136,6 +6438,22 @@ pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) voi
51366438 }
51376439}
51386440
6441pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
6442 self.module_asm.clearRetainingCapacity();
6443 return self.appendModuleAsm();
6444}
6445
6446pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
6447 return self.module_asm.writer(self.gpa);
6448}
6449
6450pub fn finishModuleAsm(self: *Builder) Allocator.Error!void {
6451 if (self.module_asm.getLastOrNull()) |last| if (last != '\n')
6452 try self.module_asm.append(self.gpa, '\n');
6453 if (self.useLibLlvm())
6454 self.llvm.module.?.setModuleInlineAsm(self.module_asm.items.ptr, self.module_asm.items.len);
6455}
6456
51396457pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
51406458 try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1);
51416459 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
......@@ -5230,7 +6548,7 @@ pub fn structType(
52306548
52316549pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
52326550 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
5233 if (name.toSlice(self)) |id| {
6551 if (name.slice(self)) |id| {
52346552 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
52356553 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
52366554 }
......@@ -5268,6 +6586,99 @@ pub fn namedTypeSetBody(
52686586 }
52696587}
52706588
6589pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Index {
6590 try self.attributes.ensureUnusedCapacity(self.gpa, 1);
6591 if (self.useLibLlvm()) try self.llvm.attributes.ensureUnusedCapacity(self.gpa, 1);
6592
6593 const gop = self.attributes.getOrPutAssumeCapacity(attribute.toStorage());
6594 if (!gop.found_existing) {
6595 gop.value_ptr.* = {};
6596 if (self.useLibLlvm()) self.llvm.attributes.appendAssumeCapacity(switch (attribute) {
6597 else => llvm_attr: {
6598 const kind_id = &self.llvm.attribute_kind_ids.?[@intFromEnum(attribute)];
6599 if (kind_id.* == 0) {
6600 const name = @tagName(attribute);
6601 kind_id.* = llvm.getEnumAttributeKindForName(name.ptr, name.len);
6602 assert(kind_id.* != 0);
6603 }
6604 break :llvm_attr switch (attribute) {
6605 else => switch (attribute) {
6606 inline else => |value| self.llvm.context.createEnumAttribute(
6607 kind_id.*,
6608 switch (@TypeOf(value)) {
6609 void => 0,
6610 u32 => value,
6611 Attribute.FpClass,
6612 Attribute.AllocKind,
6613 Attribute.Memory,
6614 => @as(u32, @bitCast(value)),
6615 Alignment => value.toByteUnits() orelse 0,
6616 Attribute.AllocSize,
6617 Attribute.VScaleRange,
6618 => @bitCast(value.toLlvm()),
6619 Attribute.UwTable => @intFromEnum(value),
6620 else => @compileError(
6621 "bad payload type: " ++ @typeName(@TypeOf(value)),
6622 ),
6623 },
6624 ),
6625 .byval,
6626 .byref,
6627 .preallocated,
6628 .inalloca,
6629 .sret,
6630 .elementtype,
6631 .string,
6632 .none,
6633 => unreachable,
6634 },
6635 .byval,
6636 .byref,
6637 .preallocated,
6638 .inalloca,
6639 .sret,
6640 .elementtype,
6641 => |ty| self.llvm.context.createTypeAttribute(kind_id.*, ty.toLlvm(self)),
6642 .string, .none => unreachable,
6643 };
6644 },
6645 .string => |string_attr| llvm_attr: {
6646 const kind = string_attr.kind.slice(self).?;
6647 const value = string_attr.value.slice(self).?;
6648 break :llvm_attr self.llvm.context.createStringAttribute(
6649 kind.ptr,
6650 @intCast(kind.len),
6651 value.ptr,
6652 @intCast(value.len),
6653 );
6654 },
6655 .none => unreachable,
6656 });
6657 }
6658 return @enumFromInt(gop.index);
6659}
6660
6661pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attributes {
6662 std.sort.heap(Attribute.Index, attributes, self, struct {
6663 pub fn lessThan(builder: *const Builder, lhs: Attribute.Index, rhs: Attribute.Index) bool {
6664 const lhs_kind = lhs.getKind(builder);
6665 const rhs_kind = rhs.getKind(builder);
6666 assert(lhs_kind != rhs_kind);
6667 return @intFromEnum(lhs_kind) < @intFromEnum(rhs_kind);
6668 }
6669 }.lessThan);
6670 return @enumFromInt(try self.attrGeneric(@ptrCast(attributes)));
6671}
6672
6673pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes {
6674 return @enumFromInt(try self.attrGeneric(@ptrCast(
6675 fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last|
6676 last + 1
6677 else
6678 0],
6679 )));
6680}
6681
52716682pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
52726683 assert(!name.isAnon());
52736684 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
......@@ -5295,7 +6706,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
52956706
52966707 const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
52976708 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
5298 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
6709 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
52996710 unique_gop.value_ptr.* += 1;
53006711 }
53016712}
......@@ -5309,8 +6720,9 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta
53096720 switch (@typeInfo(@TypeOf(value))) {
53106721 .Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
53116722 .ComptimeInt => std.math.big.int.calcLimbLen(value),
5312 else => @compileError("intConst expected an integral value, got " ++
5313 @typeName(@TypeOf(value))),
6723 else => @compileError(
6724 "intConst expected an integral value, got " ++ @typeName(@TypeOf(value)),
6725 ),
53146726 }
53156727 ]std.math.big.Limb = undefined;
53166728 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
......@@ -5721,6 +7133,27 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant)
57217133 return (try self.binConst(tag, lhs, rhs)).toValue();
57227134}
57237135
7136pub fn asmConst(
7137 self: *Builder,
7138 ty: Type,
7139 info: Constant.Asm.Info,
7140 assembly: String,
7141 constraints: String,
7142) Allocator.Error!Constant {
7143 try self.ensureUnusedConstantCapacity(1, Constant.Asm, 0);
7144 return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
7145}
7146
7147pub fn asmValue(
7148 self: *Builder,
7149 ty: Type,
7150 info: Constant.Asm.Info,
7151 assembly: String,
7152 constraints: String,
7153) Allocator.Error!Value {
7154 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
7155}
7156
57247157pub fn dump(self: *Builder) void {
57257158 if (self.useLibLlvm())
57267159 self.llvm.module.?.dump()
......@@ -5766,457 +7199,604 @@ pub fn printUnbuffered(
57667199 self: *Builder,
57677200 writer: anytype,
57687201) (@TypeOf(writer).Error || Allocator.Error)!void {
5769 if (self.source_filename != .none) try writer.print(
5770 \\; ModuleID = '{s}'
5771 \\source_filename = {"}
5772 \\
5773 , .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) });
5774 if (self.data_layout != .none) try writer.print(
5775 \\target datalayout = {"}
5776 \\
5777 , .{self.data_layout.fmt(self)});
5778 if (self.target_triple != .none) try writer.print(
5779 \\target triple = {"}
5780 \\
5781 , .{self.target_triple.fmt(self)});
5782 try writer.writeByte('\n');
5783 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
5784 \\%{} = type {}
5785 \\
5786 , .{ id.fmt(self), ty.fmt(self) });
5787 try writer.writeByte('\n');
5788 for (self.variables.items) |variable| {
5789 if (variable.global.getReplacement(self) != .none) continue;
5790 const global = variable.global.ptrConst(self);
5791 try writer.print(
5792 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
7202 var need_newline = false;
7203
7204 if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) {
7205 if (need_newline) try writer.writeByte('\n');
7206 if (self.source_filename != .none) try writer.print(
7207 \\; ModuleID = '{s}'
7208 \\source_filename = {"}
57937209 \\
5794 , .{
5795 variable.global.fmt(self),
5796 global.linkage,
5797 global.preemption,
5798 global.visibility,
5799 global.dll_storage_class,
5800 variable.thread_local,
5801 global.unnamed_addr,
5802 global.addr_space,
5803 global.externally_initialized,
5804 @tagName(variable.mutability),
5805 global.type.fmt(self),
5806 variable.init.fmt(self),
5807 variable.alignment,
5808 });
7210 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
7211 if (self.data_layout != .none) try writer.print(
7212 \\target datalayout = {"}
7213 \\
7214 , .{self.data_layout.fmt(self)});
7215 if (self.target_triple != .none) try writer.print(
7216 \\target triple = {"}
7217 \\
7218 , .{self.target_triple.fmt(self)});
7219 need_newline = true;
58097220 }
5810 try writer.writeByte('\n');
5811 for (0.., self.functions.items) |function_i, function| {
5812 const function_index: Function.Index = @enumFromInt(function_i);
5813 if (function.global.getReplacement(self) != .none) continue;
5814 const global = function.global.ptrConst(self);
5815 const params_len = global.type.functionParameters(self).len;
5816 try writer.print(
5817 \\{s}{}{}{}{} {} {}(
5818 , .{
5819 if (function.instructions.len > 0) "define" else "declare",
5820 global.linkage,
5821 global.preemption,
5822 global.visibility,
5823 global.dll_storage_class,
5824 global.type.functionReturn(self).fmt(self),
5825 function.global.fmt(self),
5826 });
5827 for (0..params_len) |arg| {
5828 if (arg > 0) try writer.writeAll(", ");
5829 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)});
7221
7222 if (self.module_asm.items.len > 0) {
7223 if (need_newline) try writer.writeByte('\n');
7224 var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n');
7225 while (line_it.next()) |line| {
7226 try writer.writeAll("module asm ");
7227 try printEscapedString(line, .always_quote, writer);
7228 try writer.writeByte('\n');
58337229 }
5834 switch (global.type.functionKind(self)) {
5835 .normal => {},
5836 .vararg => {
5837 if (params_len > 0) try writer.writeAll(", ");
5838 try writer.writeAll("...");
5839 },
7230 need_newline = true;
7231 }
7232
7233 if (self.types.count() > 0) {
7234 if (need_newline) try writer.writeByte('\n');
7235 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
7236 \\%{} = type {}
7237 \\
7238 , .{ id.fmt(self), ty.fmt(self) });
7239 need_newline = true;
7240 }
7241
7242 if (self.variables.items.len > 0) {
7243 if (need_newline) try writer.writeByte('\n');
7244 for (self.variables.items) |variable| {
7245 if (variable.global.getReplacement(self) != .none) continue;
7246 const global = variable.global.ptrConst(self);
7247 try writer.print(
7248 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
7249 \\
7250 , .{
7251 variable.global.fmt(self),
7252 global.linkage,
7253 global.preemption,
7254 global.visibility,
7255 global.dll_storage_class,
7256 variable.thread_local,
7257 global.unnamed_addr,
7258 global.addr_space,
7259 global.externally_initialized,
7260 @tagName(variable.mutability),
7261 global.type.fmt(self),
7262 variable.init.fmt(self),
7263 variable.alignment,
7264 });
58407265 }
5841 try writer.print("){}{}", .{ global.unnamed_addr, function.alignment });
5842 if (function.instructions.len > 0) {
5843 var block_incoming_len: u32 = undefined;
5844 try writer.writeAll(" {\n");
5845 for (params_len..function.instructions.len) |instruction_i| {
5846 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
5847 const instruction = function.instructions.get(@intFromEnum(instruction_index));
5848 switch (instruction.tag) {
5849 .add,
5850 .@"add nsw",
5851 .@"add nuw",
5852 .@"add nuw nsw",
5853 .@"and",
5854 .ashr,
5855 .@"ashr exact",
5856 .fadd,
5857 .@"fadd fast",
5858 .@"fcmp false",
5859 .@"fcmp fast false",
5860 .@"fcmp fast oeq",
5861 .@"fcmp fast oge",
5862 .@"fcmp fast ogt",
5863 .@"fcmp fast ole",
5864 .@"fcmp fast olt",
5865 .@"fcmp fast one",
5866 .@"fcmp fast ord",
5867 .@"fcmp fast true",
5868 .@"fcmp fast ueq",
5869 .@"fcmp fast uge",
5870 .@"fcmp fast ugt",
5871 .@"fcmp fast ule",
5872 .@"fcmp fast ult",
5873 .@"fcmp fast une",
5874 .@"fcmp fast uno",
5875 .@"fcmp oeq",
5876 .@"fcmp oge",
5877 .@"fcmp ogt",
5878 .@"fcmp ole",
5879 .@"fcmp olt",
5880 .@"fcmp one",
5881 .@"fcmp ord",
5882 .@"fcmp true",
5883 .@"fcmp ueq",
5884 .@"fcmp uge",
5885 .@"fcmp ugt",
5886 .@"fcmp ule",
5887 .@"fcmp ult",
5888 .@"fcmp une",
5889 .@"fcmp uno",
5890 .fdiv,
5891 .@"fdiv fast",
5892 .fmul,
5893 .@"fmul fast",
5894 .frem,
5895 .@"frem fast",
5896 .fsub,
5897 .@"fsub fast",
5898 .@"icmp eq",
5899 .@"icmp ne",
5900 .@"icmp sge",
5901 .@"icmp sgt",
5902 .@"icmp sle",
5903 .@"icmp slt",
5904 .@"icmp uge",
5905 .@"icmp ugt",
5906 .@"icmp ule",
5907 .@"icmp ult",
5908 .lshr,
5909 .@"lshr exact",
5910 .mul,
5911 .@"mul nsw",
5912 .@"mul nuw",
5913 .@"mul nuw nsw",
5914 .@"or",
5915 .sdiv,
5916 .@"sdiv exact",
5917 .srem,
5918 .shl,
5919 .@"shl nsw",
5920 .@"shl nuw",
5921 .@"shl nuw nsw",
5922 .sub,
5923 .@"sub nsw",
5924 .@"sub nuw",
5925 .@"sub nuw nsw",
5926 .udiv,
5927 .@"udiv exact",
5928 .urem,
5929 .xor,
5930 => |tag| {
5931 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
5932 try writer.print(" %{} = {s} {%}, {}\n", .{
5933 instruction_index.name(&function).fmt(self),
5934 @tagName(tag),
5935 extra.lhs.fmt(function_index, self),
5936 extra.rhs.fmt(function_index, self),
5937 });
5938 },
5939 .addrspacecast,
5940 .bitcast,
5941 .fpext,
5942 .fptosi,
5943 .fptoui,
5944 .fptrunc,
5945 .inttoptr,
5946 .ptrtoint,
5947 .sext,
5948 .sitofp,
5949 .trunc,
5950 .uitofp,
5951 .zext,
5952 => |tag| {
5953 const extra = function.extraData(Function.Instruction.Cast, instruction.data);
5954 try writer.print(" %{} = {s} {%} to {%}\n", .{
5955 instruction_index.name(&function).fmt(self),
5956 @tagName(tag),
5957 extra.val.fmt(function_index, self),
5958 extra.type.fmt(self),
5959 });
5960 },
5961 .alloca,
5962 .@"alloca inalloca",
5963 => |tag| {
5964 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
5965 try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{
5966 instruction_index.name(&function).fmt(self),
5967 @tagName(tag),
5968 extra.type.fmt(self),
5969 extra.len.fmt(function_index, self),
5970 extra.info.alignment,
5971 extra.info.addr_space,
5972 });
5973 },
5974 .arg => unreachable,
5975 .block => {
5976 block_incoming_len = instruction.data;
5977 const name = instruction_index.name(&function);
5978 if (@intFromEnum(instruction_index) > params_len) try writer.writeByte('\n');
5979 try writer.print("{}:\n", .{name.fmt(self)});
5980 },
5981 .br => |tag| {
5982 const target: Function.Block.Index = @enumFromInt(instruction.data);
5983 try writer.print(" {s} {%}\n", .{
5984 @tagName(tag), target.toInst(&function).fmt(function_index, self),
5985 });
5986 },
5987 .br_cond => {
5988 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
5989 try writer.print(" br {%}, {%}, {%}\n", .{
5990 extra.cond.fmt(function_index, self),
5991 extra.then.toInst(&function).fmt(function_index, self),
5992 extra.@"else".toInst(&function).fmt(function_index, self),
5993 });
5994 },
5995 .extractelement => |tag| {
5996 const extra =
5997 function.extraData(Function.Instruction.ExtractElement, instruction.data);
5998 try writer.print(" %{} = {s} {%}, {%}\n", .{
5999 instruction_index.name(&function).fmt(self),
6000 @tagName(tag),
6001 extra.val.fmt(function_index, self),
6002 extra.index.fmt(function_index, self),
6003 });
6004 },
6005 .extractvalue => |tag| {
6006 var extra =
6007 function.extraDataTrail(Function.Instruction.ExtractValue, instruction.data);
6008 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
6009 try writer.print(" %{} = {s} {%}", .{
6010 instruction_index.name(&function).fmt(self),
6011 @tagName(tag),
6012 extra.data.val.fmt(function_index, self),
6013 });
6014 for (indices) |index| try writer.print(", {d}", .{index});
6015 try writer.writeByte('\n');
6016 },
6017 .fence => |tag| {
6018 const info: MemoryAccessInfo = @bitCast(instruction.data);
6019 try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
6020 },
6021 .fneg,
6022 .@"fneg fast",
6023 .ret,
6024 => |tag| {
6025 const val: Value = @enumFromInt(instruction.data);
6026 try writer.print(" {s} {%}\n", .{
6027 @tagName(tag),
6028 val.fmt(function_index, self),
6029 });
6030 },
6031 .getelementptr,
6032 .@"getelementptr inbounds",
6033 => |tag| {
6034 var extra = function.extraDataTrail(
6035 Function.Instruction.GetElementPtr,
6036 instruction.data,
6037 );
6038 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
6039 try writer.print(" %{} = {s} {%}, {%}", .{
6040 instruction_index.name(&function).fmt(self),
6041 @tagName(tag),
6042 extra.data.type.fmt(self),
6043 extra.data.base.fmt(function_index, self),
6044 });
6045 for (indices) |index| try writer.print(", {%}", .{
6046 index.fmt(function_index, self),
6047 });
6048 try writer.writeByte('\n');
6049 },
6050 .insertelement => |tag| {
6051 const extra =
6052 function.extraData(Function.Instruction.InsertElement, instruction.data);
6053 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6054 instruction_index.name(&function).fmt(self),
6055 @tagName(tag),
6056 extra.val.fmt(function_index, self),
6057 extra.elem.fmt(function_index, self),
6058 extra.index.fmt(function_index, self),
6059 });
6060 },
6061 .insertvalue => |tag| {
6062 var extra =
6063 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
6064 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
6065 try writer.print(" %{} = {s} {%}, {%}", .{
6066 instruction_index.name(&function).fmt(self),
6067 @tagName(tag),
6068 extra.data.val.fmt(function_index, self),
6069 extra.data.elem.fmt(function_index, self),
6070 });
6071 for (indices) |index| try writer.print(", {d}", .{index});
6072 try writer.writeByte('\n');
6073 },
6074 .@"llvm.maxnum.",
6075 .@"llvm.minnum.",
6076 .@"llvm.sadd.sat.",
6077 .@"llvm.smax.",
6078 .@"llvm.smin.",
6079 .@"llvm.smul.fix.sat.",
6080 .@"llvm.sshl.sat.",
6081 .@"llvm.ssub.sat.",
6082 .@"llvm.uadd.sat.",
6083 .@"llvm.umax.",
6084 .@"llvm.umin.",
6085 .@"llvm.umul.fix.sat.",
6086 .@"llvm.ushl.sat.",
6087 .@"llvm.usub.sat.",
6088 => |tag| {
6089 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
6090 const ty = instruction_index.typeOf(function_index, self);
6091 try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{
6092 instruction_index.name(&function).fmt(self),
6093 ty.fmt(self),
6094 @tagName(tag),
6095 ty.fmt(self),
6096 extra.lhs.fmt(function_index, self),
6097 extra.rhs.fmt(function_index, self),
6098 });
6099 },
6100 .load,
6101 .@"load atomic",
6102 .@"load atomic volatile",
6103 .@"load volatile",
6104 => |tag| {
6105 const extra = function.extraData(Function.Instruction.Load, instruction.data);
6106 try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
6107 instruction_index.name(&function).fmt(self),
6108 @tagName(tag),
6109 extra.type.fmt(self),
6110 extra.ptr.fmt(function_index, self),
6111 extra.info.scope,
6112 extra.info.ordering,
6113 extra.info.alignment,
6114 });
6115 },
6116 .phi,
6117 .@"phi fast",
6118 => |tag| {
6119 var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data);
6120 const vals = extra.trail.next(block_incoming_len, Value, &function);
6121 const blocks =
6122 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
6123 try writer.print(" %{} = {s} {%} ", .{
6124 instruction_index.name(&function).fmt(self),
6125 @tagName(tag),
6126 vals[0].typeOf(function_index, self).fmt(self),
6127 });
6128 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
6129 if (incoming_index > 0) try writer.writeAll(", ");
6130 try writer.print("[ {}, {} ]", .{
6131 incoming_val.fmt(function_index, self),
6132 incoming_block.toInst(&function).fmt(function_index, self),
7266 need_newline = true;
7267 }
7268
7269 var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{};
7270 defer attribute_groups.deinit(self.gpa);
7271
7272 if (self.functions.items.len > 0) {
7273 if (need_newline) try writer.writeByte('\n');
7274 for (0.., self.functions.items) |function_i, function| {
7275 if (function_i > 0) try writer.writeByte('\n');
7276 const function_index: Function.Index = @enumFromInt(function_i);
7277 if (function.global.getReplacement(self) != .none) continue;
7278 const global = function.global.ptrConst(self);
7279 const params_len = global.type.functionParameters(self).len;
7280 const function_attributes = function.attributes.func(self);
7281 if (function_attributes != .none) try writer.print(
7282 \\; Function Attrs:{}
7283 \\
7284 , .{function_attributes.fmt(self)});
7285 try writer.print(
7286 \\{s}{}{}{}{}{}{"} {} {}(
7287 , .{
7288 if (function.instructions.len > 0) "define" else "declare",
7289 global.linkage,
7290 global.preemption,
7291 global.visibility,
7292 global.dll_storage_class,
7293 function.call_conv,
7294 function.attributes.ret(self).fmt(self),
7295 global.type.functionReturn(self).fmt(self),
7296 function.global.fmt(self),
7297 });
7298 for (0..params_len) |arg| {
7299 if (arg > 0) try writer.writeAll(", ");
7300 try writer.print(
7301 \\{%}{"}
7302 , .{
7303 global.type.functionParameters(self)[arg].fmt(self),
7304 function.attributes.param(arg, self).fmt(self),
7305 });
7306 if (function.instructions.len > 0)
7307 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
7308 }
7309 switch (global.type.functionKind(self)) {
7310 .normal => {},
7311 .vararg => {
7312 if (params_len > 0) try writer.writeAll(", ");
7313 try writer.writeAll("...");
7314 },
7315 }
7316 try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space });
7317 if (function_attributes != .none) try writer.print(" #{d}", .{
7318 (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
7319 });
7320 try writer.print("{}", .{function.alignment});
7321 if (function.instructions.len > 0) {
7322 var block_incoming_len: u32 = undefined;
7323 try writer.writeAll(" {\n");
7324 for (params_len..function.instructions.len) |instruction_i| {
7325 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
7326 const instruction = function.instructions.get(@intFromEnum(instruction_index));
7327 switch (instruction.tag) {
7328 .add,
7329 .@"add nsw",
7330 .@"add nuw",
7331 .@"add nuw nsw",
7332 .@"and",
7333 .ashr,
7334 .@"ashr exact",
7335 .fadd,
7336 .@"fadd fast",
7337 .@"fcmp false",
7338 .@"fcmp fast false",
7339 .@"fcmp fast oeq",
7340 .@"fcmp fast oge",
7341 .@"fcmp fast ogt",
7342 .@"fcmp fast ole",
7343 .@"fcmp fast olt",
7344 .@"fcmp fast one",
7345 .@"fcmp fast ord",
7346 .@"fcmp fast true",
7347 .@"fcmp fast ueq",
7348 .@"fcmp fast uge",
7349 .@"fcmp fast ugt",
7350 .@"fcmp fast ule",
7351 .@"fcmp fast ult",
7352 .@"fcmp fast une",
7353 .@"fcmp fast uno",
7354 .@"fcmp oeq",
7355 .@"fcmp oge",
7356 .@"fcmp ogt",
7357 .@"fcmp ole",
7358 .@"fcmp olt",
7359 .@"fcmp one",
7360 .@"fcmp ord",
7361 .@"fcmp true",
7362 .@"fcmp ueq",
7363 .@"fcmp uge",
7364 .@"fcmp ugt",
7365 .@"fcmp ule",
7366 .@"fcmp ult",
7367 .@"fcmp une",
7368 .@"fcmp uno",
7369 .fdiv,
7370 .@"fdiv fast",
7371 .fmul,
7372 .@"fmul fast",
7373 .frem,
7374 .@"frem fast",
7375 .fsub,
7376 .@"fsub fast",
7377 .@"icmp eq",
7378 .@"icmp ne",
7379 .@"icmp sge",
7380 .@"icmp sgt",
7381 .@"icmp sle",
7382 .@"icmp slt",
7383 .@"icmp uge",
7384 .@"icmp ugt",
7385 .@"icmp ule",
7386 .@"icmp ult",
7387 .lshr,
7388 .@"lshr exact",
7389 .mul,
7390 .@"mul nsw",
7391 .@"mul nuw",
7392 .@"mul nuw nsw",
7393 .@"or",
7394 .sdiv,
7395 .@"sdiv exact",
7396 .srem,
7397 .shl,
7398 .@"shl nsw",
7399 .@"shl nuw",
7400 .@"shl nuw nsw",
7401 .sub,
7402 .@"sub nsw",
7403 .@"sub nuw",
7404 .@"sub nuw nsw",
7405 .udiv,
7406 .@"udiv exact",
7407 .urem,
7408 .xor,
7409 => |tag| {
7410 const extra =
7411 function.extraData(Function.Instruction.Binary, instruction.data);
7412 try writer.print(" %{} = {s} {%}, {}\n", .{
7413 instruction_index.name(&function).fmt(self),
7414 @tagName(tag),
7415 extra.lhs.fmt(function_index, self),
7416 extra.rhs.fmt(function_index, self),
61337417 });
6134 }
6135 try writer.writeByte('\n');
6136 },
6137 .@"ret void",
6138 .@"unreachable",
6139 => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
6140 .select,
6141 .@"select fast",
6142 => |tag| {
6143 const extra = function.extraData(Function.Instruction.Select, instruction.data);
6144 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6145 instruction_index.name(&function).fmt(self),
6146 @tagName(tag),
6147 extra.cond.fmt(function_index, self),
6148 extra.lhs.fmt(function_index, self),
6149 extra.rhs.fmt(function_index, self),
6150 });
6151 },
6152 .shufflevector => |tag| {
6153 const extra =
6154 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
6155 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6156 instruction_index.name(&function).fmt(self),
6157 @tagName(tag),
6158 extra.lhs.fmt(function_index, self),
6159 extra.rhs.fmt(function_index, self),
6160 extra.mask.fmt(function_index, self),
6161 });
6162 },
6163 .store,
6164 .@"store atomic",
6165 .@"store atomic volatile",
6166 .@"store volatile",
6167 => |tag| {
6168 const extra = function.extraData(Function.Instruction.Store, instruction.data);
6169 try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
6170 @tagName(tag),
6171 extra.val.fmt(function_index, self),
6172 extra.ptr.fmt(function_index, self),
6173 extra.info.scope,
6174 extra.info.ordering,
6175 extra.info.alignment,
6176 });
6177 },
6178 .@"switch" => |tag| {
6179 var extra =
6180 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
6181 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
6182 const blocks =
6183 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
6184 try writer.print(" {s} {%}, {%} [", .{
6185 @tagName(tag),
6186 extra.data.val.fmt(function_index, self),
6187 extra.data.default.toInst(&function).fmt(function_index, self),
6188 });
6189 for (vals, blocks) |case_val, case_block| try writer.print(" {%}, {%}\n", .{
6190 case_val.fmt(self),
6191 case_block.toInst(&function).fmt(function_index, self),
6192 });
6193 try writer.writeAll(" ]\n");
6194 },
6195 .unimplemented => |tag| {
6196 const ty: Type = @enumFromInt(instruction.data);
6197 try writer.writeAll(" ");
6198 switch (ty) {
6199 .none, .void => {},
6200 else => try writer.print("%{} = ", .{
7418 },
7419 .addrspacecast,
7420 .bitcast,
7421 .fpext,
7422 .fptosi,
7423 .fptoui,
7424 .fptrunc,
7425 .inttoptr,
7426 .ptrtoint,
7427 .sext,
7428 .sitofp,
7429 .trunc,
7430 .uitofp,
7431 .zext,
7432 => |tag| {
7433 const extra =
7434 function.extraData(Function.Instruction.Cast, instruction.data);
7435 try writer.print(" %{} = {s} {%} to {%}\n", .{
62017436 instruction_index.name(&function).fmt(self),
6202 }),
6203 }
6204 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
6205 },
6206 .va_arg => |tag| {
6207 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
6208 try writer.print(" %{} = {s} {%}, {%}\n", .{
6209 instruction_index.name(&function).fmt(self),
6210 @tagName(tag),
6211 extra.list.fmt(function_index, self),
6212 extra.type.fmt(self),
6213 });
6214 },
7437 @tagName(tag),
7438 extra.val.fmt(function_index, self),
7439 extra.type.fmt(self),
7440 });
7441 },
7442 .alloca,
7443 .@"alloca inalloca",
7444 => |tag| {
7445 const extra =
7446 function.extraData(Function.Instruction.Alloca, instruction.data);
7447 try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{
7448 instruction_index.name(&function).fmt(self),
7449 @tagName(tag),
7450 extra.type.fmt(self),
7451 extra.len.fmt(function_index, self),
7452 extra.info.alignment,
7453 extra.info.addr_space,
7454 });
7455 },
7456 .arg => unreachable,
7457 .block => {
7458 block_incoming_len = instruction.data;
7459 const name = instruction_index.name(&function);
7460 if (@intFromEnum(instruction_index) > params_len)
7461 try writer.writeByte('\n');
7462 try writer.print("{}:\n", .{name.fmt(self)});
7463 },
7464 .br => |tag| {
7465 const target: Function.Block.Index = @enumFromInt(instruction.data);
7466 try writer.print(" {s} {%}\n", .{
7467 @tagName(tag), target.toInst(&function).fmt(function_index, self),
7468 });
7469 },
7470 .br_cond => {
7471 const extra =
7472 function.extraData(Function.Instruction.BrCond, instruction.data);
7473 try writer.print(" br {%}, {%}, {%}\n", .{
7474 extra.cond.fmt(function_index, self),
7475 extra.then.toInst(&function).fmt(function_index, self),
7476 extra.@"else".toInst(&function).fmt(function_index, self),
7477 });
7478 },
7479 .call,
7480 .@"call fast",
7481 .@"musttail call",
7482 .@"musttail call fast",
7483 .@"notail call",
7484 .@"notail call fast",
7485 .@"tail call",
7486 .@"tail call fast",
7487 => |tag| {
7488 var extra =
7489 function.extraDataTrail(Function.Instruction.Call, instruction.data);
7490 const args = extra.trail.next(extra.data.args_len, Value, &function);
7491 try writer.writeAll(" ");
7492 const ret_ty = extra.data.ty.functionReturn(self);
7493 switch (ret_ty) {
7494 .void => {},
7495 else => try writer.print("%{} = ", .{
7496 instruction_index.name(&function).fmt(self),
7497 }),
7498 .none => unreachable,
7499 }
7500 try writer.print("{s}{}{}{} {%} {}(", .{
7501 @tagName(tag),
7502 extra.data.info.call_conv,
7503 extra.data.attributes.ret(self).fmt(self),
7504 extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
7505 switch (extra.data.ty.functionKind(self)) {
7506 .normal => ret_ty,
7507 .vararg => extra.data.ty,
7508 }.fmt(self),
7509 extra.data.callee.fmt(function_index, self),
7510 });
7511 for (0.., args) |arg_index, arg| {
7512 if (arg_index > 0) try writer.writeAll(", ");
7513 try writer.print("{%}{} {}", .{
7514 arg.typeOf(function_index, self).fmt(self),
7515 extra.data.attributes.param(arg_index, self).fmt(self),
7516 arg.fmt(function_index, self),
7517 });
7518 }
7519 try writer.writeByte(')');
7520 const call_function_attributes = extra.data.attributes.func(self);
7521 if (call_function_attributes != .none) try writer.print(" #{d}", .{
7522 (try attribute_groups.getOrPutValue(
7523 self.gpa,
7524 call_function_attributes,
7525 {},
7526 )).index,
7527 });
7528 try writer.writeByte('\n');
7529 },
7530 .extractelement => |tag| {
7531 const extra = function.extraData(
7532 Function.Instruction.ExtractElement,
7533 instruction.data,
7534 );
7535 try writer.print(" %{} = {s} {%}, {%}\n", .{
7536 instruction_index.name(&function).fmt(self),
7537 @tagName(tag),
7538 extra.val.fmt(function_index, self),
7539 extra.index.fmt(function_index, self),
7540 });
7541 },
7542 .extractvalue => |tag| {
7543 var extra = function.extraDataTrail(
7544 Function.Instruction.ExtractValue,
7545 instruction.data,
7546 );
7547 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
7548 try writer.print(" %{} = {s} {%}", .{
7549 instruction_index.name(&function).fmt(self),
7550 @tagName(tag),
7551 extra.data.val.fmt(function_index, self),
7552 });
7553 for (indices) |index| try writer.print(", {d}", .{index});
7554 try writer.writeByte('\n');
7555 },
7556 .fence => |tag| {
7557 const info: MemoryAccessInfo = @bitCast(instruction.data);
7558 try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
7559 },
7560 .fneg,
7561 .@"fneg fast",
7562 .ret,
7563 => |tag| {
7564 const val: Value = @enumFromInt(instruction.data);
7565 try writer.print(" {s} {%}\n", .{
7566 @tagName(tag),
7567 val.fmt(function_index, self),
7568 });
7569 },
7570 .getelementptr,
7571 .@"getelementptr inbounds",
7572 => |tag| {
7573 var extra = function.extraDataTrail(
7574 Function.Instruction.GetElementPtr,
7575 instruction.data,
7576 );
7577 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
7578 try writer.print(" %{} = {s} {%}, {%}", .{
7579 instruction_index.name(&function).fmt(self),
7580 @tagName(tag),
7581 extra.data.type.fmt(self),
7582 extra.data.base.fmt(function_index, self),
7583 });
7584 for (indices) |index| try writer.print(", {%}", .{
7585 index.fmt(function_index, self),
7586 });
7587 try writer.writeByte('\n');
7588 },
7589 .insertelement => |tag| {
7590 const extra = function.extraData(
7591 Function.Instruction.InsertElement,
7592 instruction.data,
7593 );
7594 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
7595 instruction_index.name(&function).fmt(self),
7596 @tagName(tag),
7597 extra.val.fmt(function_index, self),
7598 extra.elem.fmt(function_index, self),
7599 extra.index.fmt(function_index, self),
7600 });
7601 },
7602 .insertvalue => |tag| {
7603 var extra = function.extraDataTrail(
7604 Function.Instruction.InsertValue,
7605 instruction.data,
7606 );
7607 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
7608 try writer.print(" %{} = {s} {%}, {%}", .{
7609 instruction_index.name(&function).fmt(self),
7610 @tagName(tag),
7611 extra.data.val.fmt(function_index, self),
7612 extra.data.elem.fmt(function_index, self),
7613 });
7614 for (indices) |index| try writer.print(", {d}", .{index});
7615 try writer.writeByte('\n');
7616 },
7617 .@"llvm.maxnum.",
7618 .@"llvm.minnum.",
7619 .@"llvm.sadd.sat.",
7620 .@"llvm.smax.",
7621 .@"llvm.smin.",
7622 .@"llvm.smul.fix.sat.",
7623 .@"llvm.sshl.sat.",
7624 .@"llvm.ssub.sat.",
7625 .@"llvm.uadd.sat.",
7626 .@"llvm.umax.",
7627 .@"llvm.umin.",
7628 .@"llvm.umul.fix.sat.",
7629 .@"llvm.ushl.sat.",
7630 .@"llvm.usub.sat.",
7631 => |tag| {
7632 const extra =
7633 function.extraData(Function.Instruction.Binary, instruction.data);
7634 const ty = instruction_index.typeOf(function_index, self);
7635 try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{
7636 instruction_index.name(&function).fmt(self),
7637 ty.fmt(self),
7638 @tagName(tag),
7639 ty.fmt(self),
7640 extra.lhs.fmt(function_index, self),
7641 extra.rhs.fmt(function_index, self),
7642 switch (tag) {
7643 .@"llvm.smul.fix.sat.",
7644 .@"llvm.umul.fix.sat.",
7645 => ", i32 0",
7646 else => "",
7647 },
7648 });
7649 },
7650 .load,
7651 .@"load atomic",
7652 .@"load atomic volatile",
7653 .@"load volatile",
7654 => |tag| {
7655 const extra =
7656 function.extraData(Function.Instruction.Load, instruction.data);
7657 try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
7658 instruction_index.name(&function).fmt(self),
7659 @tagName(tag),
7660 extra.type.fmt(self),
7661 extra.ptr.fmt(function_index, self),
7662 extra.info.scope,
7663 extra.info.ordering,
7664 extra.info.alignment,
7665 });
7666 },
7667 .phi,
7668 .@"phi fast",
7669 => |tag| {
7670 var extra =
7671 function.extraDataTrail(Function.Instruction.Phi, instruction.data);
7672 const vals = extra.trail.next(block_incoming_len, Value, &function);
7673 const blocks =
7674 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
7675 try writer.print(" %{} = {s} {%} ", .{
7676 instruction_index.name(&function).fmt(self),
7677 @tagName(tag),
7678 vals[0].typeOf(function_index, self).fmt(self),
7679 });
7680 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
7681 if (incoming_index > 0) try writer.writeAll(", ");
7682 try writer.print("[ {}, {} ]", .{
7683 incoming_val.fmt(function_index, self),
7684 incoming_block.toInst(&function).fmt(function_index, self),
7685 });
7686 }
7687 try writer.writeByte('\n');
7688 },
7689 .@"ret void",
7690 .@"unreachable",
7691 => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
7692 .select,
7693 .@"select fast",
7694 => |tag| {
7695 const extra =
7696 function.extraData(Function.Instruction.Select, instruction.data);
7697 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
7698 instruction_index.name(&function).fmt(self),
7699 @tagName(tag),
7700 extra.cond.fmt(function_index, self),
7701 extra.lhs.fmt(function_index, self),
7702 extra.rhs.fmt(function_index, self),
7703 });
7704 },
7705 .shufflevector => |tag| {
7706 const extra = function.extraData(
7707 Function.Instruction.ShuffleVector,
7708 instruction.data,
7709 );
7710 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
7711 instruction_index.name(&function).fmt(self),
7712 @tagName(tag),
7713 extra.lhs.fmt(function_index, self),
7714 extra.rhs.fmt(function_index, self),
7715 extra.mask.fmt(function_index, self),
7716 });
7717 },
7718 .store,
7719 .@"store atomic",
7720 .@"store atomic volatile",
7721 .@"store volatile",
7722 => |tag| {
7723 const extra =
7724 function.extraData(Function.Instruction.Store, instruction.data);
7725 try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
7726 @tagName(tag),
7727 extra.val.fmt(function_index, self),
7728 extra.ptr.fmt(function_index, self),
7729 extra.info.scope,
7730 extra.info.ordering,
7731 extra.info.alignment,
7732 });
7733 },
7734 .@"switch" => |tag| {
7735 var extra =
7736 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
7737 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
7738 const blocks =
7739 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
7740 try writer.print(" {s} {%}, {%} [\n", .{
7741 @tagName(tag),
7742 extra.data.val.fmt(function_index, self),
7743 extra.data.default.toInst(&function).fmt(function_index, self),
7744 });
7745 for (vals, blocks) |case_val, case_block| try writer.print(
7746 " {%}, {%}\n",
7747 .{
7748 case_val.fmt(self),
7749 case_block.toInst(&function).fmt(function_index, self),
7750 },
7751 );
7752 try writer.writeAll(" ]\n");
7753 },
7754 .unimplemented => |tag| {
7755 const ty: Type = @enumFromInt(instruction.data);
7756 if (true) {
7757 try writer.writeAll(" ");
7758 switch (ty) {
7759 .none, .void => {},
7760 else => try writer.print("%{} = ", .{
7761 instruction_index.name(&function).fmt(self),
7762 }),
7763 }
7764 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
7765 } else switch (ty) {
7766 .none, .void => {},
7767 else => try writer.print(" %{} = load {%}, ptr undef\n", .{
7768 instruction_index.name(&function).fmt(self),
7769 ty.fmt(self),
7770 }),
7771 }
7772 },
7773 .va_arg => |tag| {
7774 const extra =
7775 function.extraData(Function.Instruction.VaArg, instruction.data);
7776 try writer.print(" %{} = {s} {%}, {%}\n", .{
7777 instruction_index.name(&function).fmt(self),
7778 @tagName(tag),
7779 extra.list.fmt(function_index, self),
7780 extra.type.fmt(self),
7781 });
7782 },
7783 }
62157784 }
7785 try writer.writeByte('}');
62167786 }
6217 try writer.writeByte('}');
7787 try writer.writeByte('\n');
62187788 }
6219 try writer.writeAll("\n\n");
7789 need_newline = true;
7790 }
7791
7792 if (attribute_groups.count() > 0) {
7793 if (need_newline) try writer.writeByte('\n') else need_newline = true;
7794 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
7795 try writer.print(
7796 \\attributes #{d} = {{{#"} }}
7797 \\
7798 , .{ attribute_group_index, attribute_group.fmt(self) });
7799 need_newline = true;
62207800 }
62217801}
62227802
......@@ -6227,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool {
62277807const NoExtra = struct {};
62287808
62297809fn isValidIdentifier(id: []const u8) bool {
6230 for (id, 0..) |character, index| switch (character) {
7810 for (id, 0..) |byte, index| switch (byte) {
62317811 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
62327812 '0'...'9' => if (index == 0) return false,
62337813 else => return false,
......@@ -6235,10 +7815,29 @@ fn isValidIdentifier(id: []const u8) bool {
62357815 return true;
62367816}
62377817
7818const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier };
7819fn printEscapedString(
7820 slice: []const u8,
7821 quotes: QuoteBehavior,
7822 writer: anytype,
7823) @TypeOf(writer).Error!void {
7824 const need_quotes = switch (quotes) {
7825 .always_quote => true,
7826 .quote_unless_valid_identifier => !isValidIdentifier(slice),
7827 };
7828 if (need_quotes) try writer.writeByte('"');
7829 for (slice) |byte| switch (byte) {
7830 '\\' => try writer.writeAll("\\\\"),
7831 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte),
7832 else => try writer.print("\\{X:0>2}", .{byte}),
7833 };
7834 if (need_quotes) try writer.writeByte('"');
7835}
7836
62387837fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {
62397838 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);
62407839 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
6241 if (name.toSlice(self)) |id| {
7840 if (name.slice(self)) |id| {
62427841 const count: usize = comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)});
62437842 try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
62447843 }
......@@ -6528,14 +8127,14 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
65288127 const result: Type = @enumFromInt(gop.index);
65298128 type_gop.value_ptr.* = result;
65308129 if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(
6531 self.llvm.context.structCreateNamed(id.toSlice(self) orelse ""),
8130 self.llvm.context.structCreateNamed(id.slice(self) orelse ""),
65328131 );
65338132 return result;
65348133 }
65358134
65368135 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
65378136 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
6538 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
8137 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.slice(self).?, unique_gop.value_ptr.* });
65398138 unique_gop.value_ptr.* += 1;
65408139 }
65418140}
......@@ -6636,6 +8235,30 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraI
66368235 return self.typeExtraDataTrail(T, index).data;
66378236}
66388237
8238fn attrGeneric(self: *Builder, data: []const u32) Allocator.Error!u32 {
8239 try self.attributes_map.ensureUnusedCapacity(self.gpa, 1);
8240 try self.attributes_indices.ensureUnusedCapacity(self.gpa, 1);
8241 try self.attributes_extra.ensureUnusedCapacity(self.gpa, data.len);
8242
8243 const Adapter = struct {
8244 builder: *const Builder,
8245 pub fn hash(_: @This(), key: []const u32) u32 {
8246 return @truncate(std.hash.Wyhash.hash(1, std.mem.sliceAsBytes(key)));
8247 }
8248 pub fn eql(ctx: @This(), lhs_key: []const u32, _: void, rhs_index: usize) bool {
8249 const start = ctx.builder.attributes_indices.items[rhs_index];
8250 const end = ctx.builder.attributes_indices.items[rhs_index + 1];
8251 return std.mem.eql(u32, lhs_key, ctx.builder.attributes_extra.items[start..end]);
8252 }
8253 };
8254 const gop = self.attributes_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
8255 if (!gop.found_existing) {
8256 self.attributes_extra.appendSliceAssumeCapacity(data);
8257 self.attributes_indices.appendAssumeCapacity(@intCast(self.attributes_extra.items.len));
8258 }
8259 return @intCast(gop.index);
8260}
8261
66398262fn bigIntConstAssumeCapacity(
66408263 self: *Builder,
66418264 ty: Type,
......@@ -7073,7 +8696,7 @@ fn arrayConstAssumeCapacity(
70738696}
70748697
70758698fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
7076 const slice = val.toSlice(self).?;
8699 const slice = val.slice(self).?;
70778700 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
70788701 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
70798702 const result = self.getOrPutConstantNoExtraAssumeCapacity(
......@@ -7086,7 +8709,7 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
70868709}
70878710
70888711fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
7089 const slice = val.toSlice(self).?;
8712 const slice = val.slice(self).?;
70908713 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
70918714 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
70928715 const result = self.getOrPutConstantNoExtraAssumeCapacity(
......@@ -7737,30 +9360,30 @@ fn binConstAssumeCapacity(
77379360 => {},
77389361 else => unreachable,
77399362 }
7740 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
9363 const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
77419364 const Adapter = struct {
77429365 builder: *const Builder,
77439366 pub fn hash(_: @This(), key: Key) u32 {
77449367 return @truncate(std.hash.Wyhash.hash(
77459368 std.hash.uint32(@intFromEnum(key.tag)),
7746 std.mem.asBytes(&key.bin),
9369 std.mem.asBytes(&key.extra),
77479370 ));
77489371 }
77499372 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
77509373 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
77519374 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
77529375 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
7753 return std.meta.eql(lhs_key.bin, rhs_extra);
9376 return std.meta.eql(lhs_key.extra, rhs_extra);
77549377 }
77559378 };
7756 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };
9379 const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
77579380 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
77589381 if (!gop.found_existing) {
77599382 gop.key_ptr.* = {};
77609383 gop.value_ptr.* = {};
77619384 self.constant_items.appendAssumeCapacity(.{
77629385 .tag = tag,
7763 .data = self.addConstantExtraAssumeCapacity(data.bin),
9386 .data = self.addConstantExtraAssumeCapacity(data.extra),
77649387 });
77659388 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
77669389 .add => &llvm.Value.constAdd,
......@@ -7778,6 +9401,63 @@ fn binConstAssumeCapacity(
77789401 return @enumFromInt(gop.index);
77799402}
77809403
9404fn asmConstAssumeCapacity(
9405 self: *Builder,
9406 ty: Type,
9407 info: Constant.Asm.Info,
9408 assembly: String,
9409 constraints: String,
9410) Constant {
9411 assert(ty.functionKind(self) == .normal);
9412
9413 const Key = struct { tag: Constant.Tag, extra: Constant.Asm };
9414 const Adapter = struct {
9415 builder: *const Builder,
9416 pub fn hash(_: @This(), key: Key) u32 {
9417 return @truncate(std.hash.Wyhash.hash(
9418 std.hash.uint32(@intFromEnum(key.tag)),
9419 std.mem.asBytes(&key.extra),
9420 ));
9421 }
9422 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
9423 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
9424 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
9425 const rhs_extra = ctx.builder.constantExtraData(Constant.Asm, rhs_data);
9426 return std.meta.eql(lhs_key.extra, rhs_extra);
9427 }
9428 };
9429
9430 const data = Key{
9431 .tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))),
9432 .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints },
9433 };
9434 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
9435 if (!gop.found_existing) {
9436 gop.key_ptr.* = {};
9437 gop.value_ptr.* = {};
9438 self.constant_items.appendAssumeCapacity(.{
9439 .tag = data.tag,
9440 .data = self.addConstantExtraAssumeCapacity(data.extra),
9441 });
9442 if (self.useLibLlvm()) {
9443 const assembly_slice = assembly.slice(self).?;
9444 const constraints_slice = constraints.slice(self).?;
9445 self.llvm.constants.appendAssumeCapacity(llvm.getInlineAsm(
9446 ty.toLlvm(self),
9447 assembly_slice.ptr,
9448 assembly_slice.len,
9449 constraints_slice.ptr,
9450 constraints_slice.len,
9451 llvm.Bool.fromBool(info.sideeffect),
9452 llvm.Bool.fromBool(info.alignstack),
9453 if (info.inteldialect) .Intel else .ATT,
9454 llvm.Bool.fromBool(info.unwind),
9455 ));
9456 }
9457 }
9458 return @enumFromInt(gop.index);
9459}
9460
77819461fn ensureUnusedConstantCapacity(
77829462 self: *Builder,
77839463 count: usize,
......@@ -7868,7 +9548,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
78689548 const value = @field(extra, field.name);
78699549 self.constant_extra.appendAssumeCapacity(switch (field.type) {
78709550 u32 => value,
7871 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
9551 String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
78729552 Constant.GetElementPtr.Info => @bitCast(value),
78739553 else => @compileError("bad field type: " ++ @typeName(field.type)),
78749554 });
......@@ -7907,7 +9587,7 @@ fn constantExtraDataTrail(
79079587 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
79089588 @field(result, field.name) = switch (field.type) {
79099589 u32 => value,
7910 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
9590 String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
79119591 Constant.GetElementPtr.Info => @bitCast(value),
79129592 else => @compileError("bad field type: " ++ @typeName(field.type)),
79139593 };
src/codegen/llvm/bindings.zig+33-7
......@@ -26,10 +26,13 @@ pub const Context = opaque {
2626 extern fn LLVMContextDispose(C: *Context) void;
2727
2828 pub const createEnumAttribute = LLVMCreateEnumAttribute;
29 extern fn LLVMCreateEnumAttribute(*Context, KindID: c_uint, Val: u64) *Attribute;
29 extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) *Attribute;
30
31 pub const createTypeAttribute = LLVMCreateTypeAttribute;
32 extern fn LLVMCreateTypeAttribute(C: *Context, KindID: c_uint, Type: *Type) *Attribute;
3033
3134 pub const createStringAttribute = LLVMCreateStringAttribute;
32 extern fn LLVMCreateStringAttribute(*Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *Attribute;
35 extern fn LLVMCreateStringAttribute(C: *Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *Attribute;
3336
3437 pub const pointerType = LLVMPointerTypeInContext;
3538 extern fn LLVMPointerTypeInContext(C: *Context, AddressSpace: c_uint) *Type;
......@@ -309,12 +312,18 @@ pub const Value = opaque {
309312 pub const setAlignment = LLVMSetAlignment;
310313 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
311314
312 pub const getFunctionCallConv = LLVMGetFunctionCallConv;
313 extern fn LLVMGetFunctionCallConv(Fn: *Value) CallConv;
314
315315 pub const setFunctionCallConv = LLVMSetFunctionCallConv;
316316 extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void;
317317
318 pub const setInstructionCallConv = LLVMSetInstructionCallConv;
319 extern fn LLVMSetInstructionCallConv(Instr: *Value, CC: CallConv) void;
320
321 pub const setTailCallKind = ZigLLVMSetTailCallKind;
322 extern fn ZigLLVMSetTailCallKind(CallInst: *Value, TailCallKind: TailCallKind) void;
323
324 pub const addCallSiteAttribute = LLVMAddCallSiteAttribute;
325 extern fn LLVMAddCallSiteAttribute(C: *Value, Idx: AttributeIndex, A: *Attribute) void;
326
318327 pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;
319328 extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;
320329
......@@ -531,7 +540,7 @@ pub const Module = opaque {
531540 pub const createDIBuilder = ZigLLVMCreateDIBuilder;
532541 extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) *DIBuilder;
533542
534 pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2;
543 pub const setModuleInlineAsm = LLVMSetModuleInlineAsm2;
535544 extern fn LLVMSetModuleInlineAsm2(M: *Module, Asm: [*]const u8, Len: usize) void;
536545
537546 pub const printModuleToFile = LLVMPrintModuleToFile;
......@@ -642,7 +651,17 @@ pub const Builder = opaque {
642651 Name: [*:0]const u8,
643652 ) *Value;
644653
645 pub const buildCall = ZigLLVMBuildCall;
654 pub const buildCall = LLVMBuildCall2;
655 extern fn LLVMBuildCall2(
656 *Builder,
657 *Type,
658 Fn: *Value,
659 Args: [*]const *Value,
660 NumArgs: c_uint,
661 Name: [*:0]const u8,
662 ) *Value;
663
664 pub const buildCallOld = ZigLLVMBuildCall;
646665 extern fn ZigLLVMBuildCall(
647666 *Builder,
648667 *Type,
......@@ -1605,6 +1624,13 @@ pub const CallAttr = enum(c_int) {
16051624 AlwaysInline,
16061625};
16071626
1627pub const TailCallKind = enum(c_uint) {
1628 None,
1629 Tail,
1630 MustTail,
1631 NoTail,
1632};
1633
16081634pub const DLLStorageClass = enum(c_uint) {
16091635 Default,
16101636 DLLImport,
src/zig_llvm.cpp+4-6
......@@ -453,6 +453,10 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
453453 return wrap(call_inst);
454454}
455455
456ZIG_EXTERN_C void ZigLLVMSetTailCallKind(LLVMValueRef Call, CallInst::TailCallKind TailCallKind) {
457 unwrap<CallInst>(Call)->setTailCallKind(TailCallKind);
458}
459
456460void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
457461 if (isa<Function>(unwrap(Val))) {
458462 unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
......@@ -461,7 +465,6 @@ void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef
461465 }
462466}
463467
464
465468LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
466469 LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
467470{
......@@ -1116,11 +1119,6 @@ void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const ch
11161119 func->addFnAttr(attr_name, attr_value);
11171120}
11181121
1119void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) {
1120 Function *func = unwrap<Function>(fn_ref);
1121 func->addFnAttr(Attribute::Cold);
1122}
1123
11241122void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
11251123 cl::ParseCommandLineOptions(argc, argv);
11261124}
test/cases.zig+1
......@@ -4,5 +4,6 @@ const Cases = @import("src/Cases.zig");
44pub fn addCases(cases: *Cases) !void {
55 try @import("compile_errors.zig").addCases(cases);
66 try @import("cbe.zig").addCases(cases);
7 try @import("llvm_targets.zig").addCases(cases);
78 try @import("nvptx.zig").addCases(cases);
89}
test/llvm_targets.zig created+117
......@@ -0,0 +1,117 @@
1const std = @import("std");
2const Cases = @import("src/Cases.zig");
3
4const targets = [_]std.zig.CrossTarget{
5 .{ .cpu_arch = .aarch64, .os_tag = .freestanding, .abi = .none },
6 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .none },
7 .{ .cpu_arch = .aarch64, .os_tag = .macos, .abi = .none },
8 .{ .cpu_arch = .aarch64, .os_tag = .uefi, .abi = .none },
9 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .gnu },
10 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .msvc },
11 .{ .cpu_arch = .aarch64_be, .os_tag = .freestanding, .abi = .none },
12 .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .none },
13 .{ .cpu_arch = .aarch64_32, .os_tag = .freestanding, .abi = .none },
14 .{ .cpu_arch = .aarch64_32, .os_tag = .linux, .abi = .none },
15 .{ .cpu_arch = .amdgcn, .os_tag = .amdhsa, .abi = .none },
16 .{ .cpu_arch = .amdgcn, .os_tag = .amdpal, .abi = .none },
17 .{ .cpu_arch = .amdgcn, .os_tag = .linux, .abi = .none },
18 //.{ .cpu_arch = .amdgcn, .os_tag = .mesa3d, .abi = .none },
19 .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .none },
20 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .none },
21 .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .none },
22 .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .none },
23 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .none },
24 .{ .cpu_arch = .avr, .os_tag = .freebsd, .abi = .none },
25 .{ .cpu_arch = .avr, .os_tag = .freestanding, .abi = .none },
26 .{ .cpu_arch = .avr, .os_tag = .linux, .abi = .none },
27 .{ .cpu_arch = .bpfel, .os_tag = .linux, .abi = .gnu },
28 .{ .cpu_arch = .bpfel, .os_tag = .linux, .abi = .none },
29 .{ .cpu_arch = .bpfeb, .os_tag = .linux, .abi = .gnu },
30 .{ .cpu_arch = .bpfeb, .os_tag = .linux, .abi = .none },
31 .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .none },
32 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabihf },
33 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musl },
34 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .none },
35 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabihf },
36 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musl },
37 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .none },
38 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .none },
39 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .none },
40 .{ .cpu_arch = .msp430, .os_tag = .freebsd, .abi = .none },
41 .{ .cpu_arch = .msp430, .os_tag = .freestanding, .abi = .none },
42 .{ .cpu_arch = .msp430, .os_tag = .linux, .abi = .none },
43 //.{ .cpu_arch = .nvptx, .os_tag = .cuda, .abi = .none },
44 //.{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
45 .{ .cpu_arch = .powerpc, .os_tag = .freebsd, .abi = .none },
46 .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .none },
47 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .gnueabihf },
48 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musl },
49 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .none },
50 .{ .cpu_arch = .powerpcle, .os_tag = .freebsd, .abi = .none },
51 .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .none },
52 .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .gnu },
53 .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .musl },
54 .{ .cpu_arch = .powerpcle, .os_tag = .linux, .abi = .none },
55 .{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
56 .{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
57 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },
58 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .musl },
59 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .none },
60 .{ .cpu_arch = .powerpc64le, .os_tag = .freebsd, .abi = .none },
61 .{ .cpu_arch = .powerpc64le, .os_tag = .freestanding, .abi = .none },
62 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .gnu },
63 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .musl },
64 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .none },
65 //.{ .cpu_arch = .r600, .os_tag = .mesa3d, .abi = .none },
66 .{ .cpu_arch = .riscv32, .os_tag = .freestanding, .abi = .none },
67 .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .none },
68 .{ .cpu_arch = .riscv64, .os_tag = .freestanding, .abi = .none },
69 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .gnu },
70 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .musl },
71 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .none },
72 .{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none },
73 .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu },
74 .{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
75 .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
76 .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none },
77 .{ .cpu_arch = .sparcel, .os_tag = .freestanding, .abi = .none },
78 .{ .cpu_arch = .sparcel, .os_tag = .linux, .abi = .gnu },
79 .{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none },
80 .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .gnu },
81 //.{ .cpu_arch = .spirv32, .os_tag = .opencl, .abi = .none },
82 //.{ .cpu_arch = .spirv32, .os_tag = .glsl450, .abi = .none },
83 //.{ .cpu_arch = .spirv32, .os_tag = .vulkan, .abi = .none },
84 //.{ .cpu_arch = .spirv64, .os_tag = .opencl, .abi = .none },
85 //.{ .cpu_arch = .spirv64, .os_tag = .glsl450, .abi = .none },
86 //.{ .cpu_arch = .spirv64, .os_tag = .vulkan, .abi = .none },
87 .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .none },
88 .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .none },
89 .{ .cpu_arch = .ve, .os_tag = .linux, .abi = .none },
90 .{ .cpu_arch = .wasm32, .os_tag = .emscripten, .abi = .none },
91 .{ .cpu_arch = .wasm32, .os_tag = .freestanding, .abi = .none },
92 .{ .cpu_arch = .wasm32, .os_tag = .linux, .abi = .none },
93 .{ .cpu_arch = .wasm32, .os_tag = .wasi, .abi = .none },
94 .{ .cpu_arch = .wasm64, .os_tag = .emscripten, .abi = .none },
95 .{ .cpu_arch = .wasm64, .os_tag = .freestanding, .abi = .none },
96 .{ .cpu_arch = .wasm64, .os_tag = .linux, .abi = .none },
97 .{ .cpu_arch = .wasm64, .os_tag = .wasi, .abi = .none },
98 .{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none },
99 .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .none },
100 .{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none },
101 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu },
102 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .msvc },
103 .{ .cpu_arch = .x86_64, .os_tag = .freebsd, .abi = .none },
104 .{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none },
105 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none },
106 .{ .cpu_arch = .x86_64, .os_tag = .macos, .abi = .none },
107 .{ .cpu_arch = .x86_64, .os_tag = .uefi, .abi = .none },
108 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu },
109 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .msvc },
110};
111
112pub fn addCases(ctx: *Cases) !void {
113 for (targets) |target| {
114 var case = ctx.noEmitUsingLlvmBackend("llvm_targets", target);
115 case.addCompile("");
116 }
117}
test/src/Cases.zig+16
......@@ -76,6 +76,7 @@ pub const Case = struct {
7676 output_mode: std.builtin.OutputMode,
7777 optimize_mode: std.builtin.Mode = .Debug,
7878 updates: std.ArrayList(Update),
79 emit_bin: bool = true,
7980 emit_h: bool = false,
8081 is_test: bool = false,
8182 expect_exact: bool = false,
......@@ -176,6 +177,19 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target: CrossTarget) *Cas
176177 return &ctx.cases.items[ctx.cases.items.len - 1];
177178}
178179
180pub fn noEmitUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case {
181 ctx.cases.append(Case{
182 .name = name,
183 .target = target,
184 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
185 .output_mode = .Obj,
186 .emit_bin = false,
187 .deps = std.ArrayList(DepModule).init(ctx.arena),
188 .backend = .llvm,
189 }) catch @panic("out of memory");
190 return &ctx.cases.items[ctx.cases.items.len - 1];
191}
192
179193/// Adds a test case that uses the LLVM backend to emit an executable.
180194/// Currently this implies linking libc, because only then we can generate a testable executable.
181195pub fn exeUsingLlvmBackend(ctx: *Cases, name: []const u8, target: CrossTarget) *Case {
......@@ -537,6 +551,8 @@ pub fn lowerToBuildSteps(
537551 }),
538552 };
539553
554 artifact.emit_bin = if (case.emit_bin) .default else .no_emit;
555
540556 if (case.link_libc) artifact.linkLibC();
541557
542558 switch (case.backend) {