authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-07 09:22:27-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-19 23:38:40-04:00
log3314fd83af5a6a269926a6f8ad3fcb62b04242c9
tree6a8f4fc3782b327cdee4f980a38b20ce67d57295
parentd195173ba2c06b56c1bf5554ebf0736795798c91

llvm: compute data layout without help like a grownup compiler


5 files changed, 511 insertions(+), 107 deletions(-)

lib/std/target.zig+14-4
......@@ -1357,8 +1357,6 @@ pub const Target = struct {
13571357 }
13581358 };
13591359
1360 pub const stack_align = 16;
1361
13621360 pub fn zigTriple(self: Target, allocator: mem.Allocator) ![]u8 {
13631361 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
13641362 }
......@@ -1833,7 +1831,7 @@ pub const Target = struct {
18331831 };
18341832 }
18351833
1836 pub fn ptrBitWidth(target: std.Target) u16 {
1834 pub fn ptrBitWidth(target: Target) u16 {
18371835 switch (target.abi) {
18381836 .gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,
18391837 .gnuabi64 => return 64,
......@@ -1910,6 +1908,18 @@ pub const Target = struct {
19101908 }
19111909 }
19121910
1911 pub fn stackAlignment(target: Target) u16 {
1912 return switch (target.cpu.arch) {
1913 .x86 => switch (target.os.tag) {
1914 .windows => 4,
1915 else => 16,
1916 },
1917 .arm, .armeb, .mips, .mipsel => 8,
1918 .aarch64, .aarch64_be, .powerpc64, .powerpc64le, .riscv64, .x86_64, .wasm32, .wasm64 => 16,
1919 else => @divExact(target.ptrBitWidth(), 8),
1920 };
1921 }
1922
19131923 /// Default signedness of `char` for the native C compiler for this target
19141924 /// Note that char signedness is implementation-defined and many compilers provide
19151925 /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
......@@ -2428,7 +2438,7 @@ pub const Target = struct {
24282438 else => {},
24292439 },
24302440 .avr => switch (c_type) {
2431 .int, .uint, .long, .ulong, .float, .longdouble => return 1,
2441 .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1,
24322442 .short, .ushort => return 2,
24332443 .double => return 4,
24342444 .longlong, .ulonglong => return 8,
lib/test_runner.zig+1-1
......@@ -136,7 +136,7 @@ fn mainTerminal() void {
136136 const have_tty = progress.terminal != null and
137137 (progress.supports_ansi_escape_codes or progress.is_windows_terminal);
138138
139 var async_frame_buffer: []align(std.Target.stack_align) u8 = undefined;
139 var async_frame_buffer: []align(builtin.target.stackAlignment()) u8 = undefined;
140140 // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
141141 // ignores the alignment of the slice.
142142 async_frame_buffer = &[_]u8{};
src/codegen/llvm.zig+425-60
......@@ -328,6 +328,212 @@ pub fn supportsTailCall(target: std.Target) bool {
328328 }
329329}
330330
331const DataLayoutBuilder = struct {
332 target: std.Target,
333
334 pub fn format(
335 self: DataLayoutBuilder,
336 comptime _: []const u8,
337 _: std.fmt.FormatOptions,
338 writer: anytype,
339 ) @TypeOf(writer).Error!void {
340 const is_aarch64_windows = self.target.cpu.arch == .aarch64 and self.target.os.tag == .windows;
341 try writer.print("{c}-m:{c}", .{
342 @as(u8, switch (self.target.cpu.arch.endian()) {
343 .Little => 'e',
344 .Big => 'E',
345 }),
346 @as(u8, if (self.target.cpu.arch.isMIPS())
347 'm' // Mips mangling: Private symbols get a $ prefix.
348 else switch (self.target.ofmt) {
349 .elf => 'e', // ELF mangling: Private symbols get a `.L` prefix.
350 //.goff => 'l', // GOFF mangling: Private symbols get a `@` prefix.
351 .macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
352 // Other symbols get a `_` prefix.
353 .coff => switch (self.target.os.tag) {
354 .windows => switch (self.target.cpu.arch) {
355 .x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual prefix.
356 // Regular C symbols get a `_` prefix. Functions with `__stdcall`, `__fastcall`,
357 // and `__vectorcall` have custom mangling that appends `@N` where N is the
358 // number of bytes used to pass parameters. C++ symbols starting with `?` are
359 // not mangled in any way.
360 else => 'w', // Windows COFF mangling: Similar to x, except that normal C
361 // symbols do not receive a `_` prefix.
362 },
363 else => 'e',
364 },
365 //.xcoff => 'a', // XCOFF mangling: Private symbols get a `L..` prefix.
366 else => 'e',
367 }),
368 });
369 var any_non_integral = false;
370 const ptr_bit_width = self.target.ptrBitWidth();
371 var default_info = struct { size: u16, abi: u16, pref: u16, idx: u16 }{
372 .size = 64,
373 .abi = 64,
374 .pref = 64,
375 .idx = 64,
376 };
377 const address_space_info = llvmAddressSpaceInfo(self.target);
378 assert(address_space_info[0].llvm == llvm.address_space.default);
379 for (address_space_info) |info| {
380 const is_default = info.llvm == llvm.address_space.default;
381 if (info.non_integral) {
382 assert(!is_default);
383 any_non_integral = true;
384 }
385 const size = info.size orelse ptr_bit_width;
386 const abi = info.abi orelse ptr_bit_width;
387 const pref = info.pref orelse abi;
388 const idx = info.idx orelse size;
389 const matches_default =
390 size == default_info.size and
391 abi == default_info.abi and
392 pref == default_info.pref and
393 idx == default_info.idx;
394 if (is_default) default_info = .{
395 .size = size,
396 .abi = abi,
397 .pref = pref,
398 .idx = idx,
399 };
400 if (!info.force_in_data_layout and matches_default and
401 self.target.cpu.arch != .riscv64 and !is_aarch64_windows) continue;
402 try writer.writeAll("-p");
403 if (!is_default) try writer.print("{d}", .{info.llvm});
404 try writer.print(":{d}:{d}", .{ size, abi });
405 if (pref != abi or idx != size) {
406 try writer.print(":{d}", .{pref});
407 if (idx != size) try writer.print(":{d}", .{idx});
408 }
409 }
410 if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
411 try writer.writeAll("-Fi8"); // for thumb interwork
412 try self.typeAlignment(.integer, 8, 8, 8, false, writer);
413 try self.typeAlignment(.integer, 16, 16, 16, false, writer);
414 try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer);
415 try self.typeAlignment(.integer, 64, 32, 64, false, writer);
416 try self.typeAlignment(.integer, 128, 32, 64, false, writer);
417 if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
418 try self.typeAlignment(.float, 32, 32, 32, false, writer);
419 try self.typeAlignment(.float, 64, 64, 64, false, writer);
420 if (backendSupportsF80(self.target)) try self.typeAlignment(.float, 80, 0, 0, false, writer);
421 try self.typeAlignment(.float, 128, 128, 128, false, writer);
422 try self.typeAlignment(.vector, 64, 64, 64, false, writer);
423 try self.typeAlignment(.vector, 128, 128, 128, false, writer);
424 if (self.target.os.tag != .windows) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
425 for (@as([]const u24, switch (self.target.cpu.arch) {
426 .aarch64_32,
427 .arm,
428 .armeb,
429 .mips,
430 .mipsel,
431 .powerpc,
432 .powerpcle,
433 .thumb,
434 .thumbeb,
435 .riscv32,
436 => &.{32},
437 .aarch64,
438 .aarch64_be,
439 .mips64,
440 .mips64el,
441 .powerpc64,
442 .powerpc64le,
443 .riscv64,
444 .wasm32,
445 .wasm64,
446 => &.{ 32, 64 },
447 .x86 => &.{ 8, 16, 32 },
448 .x86_64 => &.{ 8, 16, 32, 64 },
449 else => &.{},
450 }), 0..) |natural, index| switch (index) {
451 0 => try writer.print("-n{d}", .{natural}),
452 else => try writer.print(":{d}", .{natural}),
453 };
454 if (self.target.os.tag == .windows) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
455 const stack_abi = self.target.stackAlignment() * 8;
456 if (self.target.os.tag == .windows or stack_abi != ptr_bit_width)
457 try writer.print("-S{d}", .{stack_abi});
458 try self.typeAlignment(.vector, 256, 128, 128, true, writer);
459 try self.typeAlignment(.vector, 512, 128, 128, true, writer);
460 if (any_non_integral) {
461 try writer.writeAll("-ni");
462 for (address_space_info) |info| if (info.non_integral)
463 try writer.print(":{d}", .{info.llvm});
464 }
465 }
466
467 fn typeAlignment(
468 self: DataLayoutBuilder,
469 kind: enum { integer, vector, float, aggregate },
470 size: u24,
471 default_abi: u24,
472 default_pref: u24,
473 force_pref: bool,
474 writer: anytype,
475 ) @TypeOf(writer).Error!void {
476 var abi = default_abi;
477 var pref = default_pref;
478 if (kind == .float and size == 80) {
479 abi = 128;
480 pref = 128;
481 }
482 for (@as([]const std.Target.CType, switch (kind) {
483 .integer => &.{ .char, .short, .int, .long, .longlong },
484 .float => &.{ .float, .double, .longdouble },
485 .vector, .aggregate => &.{},
486 })) |cty| {
487 if (self.target.c_type_bit_size(cty) != size) continue;
488 abi = self.target.c_type_alignment(cty) * 8;
489 pref = self.target.c_type_preferred_alignment(cty) * 8;
490 break;
491 }
492 switch (kind) {
493 .integer => {
494 abi = @min(abi, self.target.maxIntAlignment() * 8);
495 switch (self.target.os.tag) {
496 .linux => switch (self.target.cpu.arch) {
497 .aarch64, .aarch64_be, .mips, .mipsel => pref = @max(pref, 32),
498 else => {},
499 },
500 else => {},
501 }
502 switch (self.target.cpu.arch) {
503 .aarch64, .aarch64_be, .riscv64 => switch (size) {
504 128 => {
505 abi = size;
506 pref = size;
507 },
508 else => {},
509 },
510 else => {},
511 }
512 },
513 .vector => if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb()) {
514 switch (size) {
515 128 => abi = 64,
516 else => {},
517 }
518 } else if (self.target.cpu.arch.isPPC64()) {
519 abi = size;
520 pref = size;
521 },
522 .float => {},
523 .aggregate => if (self.target.os.tag == .windows or
524 self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
525 {
526 pref = @min(pref, self.target.ptrBitWidth());
527 },
528 }
529 if (abi == default_abi and pref == default_pref) return;
530 try writer.print("-{c}", .{@tagName(kind)[0]});
531 if (size != 0) try writer.print("{d}", .{size});
532 try writer.print(":{d}", .{abi});
533 if (pref != abi or force_pref) try writer.print(":{d}", .{pref});
534 }
535};
536
331537/// TODO can this be done with simpler logic / different API binding?
332538fn deleteLlvmGlobal(llvm_global: *llvm.Value) void {
333539 if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
......@@ -530,12 +736,17 @@ pub const Object = struct {
530736 try builder.init();
531737 errdefer builder.deinit();
532738 builder.source_filename = try builder.string(options.root_name);
533 builder.data_layout = rep: {
739 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }});
740 builder.target_triple = try builder.string(llvm_target_triple);
741
742 if (std.debug.runtime_safety) {
534743 const rep = target_data.stringRep();
535744 defer llvm.disposeMessage(rep);
536 break :rep try builder.string(std.mem.span(rep));
537 };
538 builder.target_triple = try builder.string(llvm_target_triple);
745 std.testing.expectEqualStrings(
746 std.mem.span(rep),
747 builder.data_layout.toSlice(&builder).?,
748 ) catch unreachable;
749 }
539750
540751 return Object{
541752 .gpa = gpa,
......@@ -768,6 +979,10 @@ pub const Object = struct {
768979 if (comp.verbose_llvm_ir) |path| {
769980 if (std.mem.eql(u8, path, "-")) {
770981 self.llvm_module.dump();
982
983 const writer = std.io.getStdErr().writer();
984 try writer.writeAll("\n" ++ "-" ** 200 ++ "\n\n");
985 try self.builder.dump(writer);
771986 } else {
772987 const path_z = try comp.gpa.dupeZ(u8, path);
773988 defer comp.gpa.free(path_z);
......@@ -836,12 +1051,6 @@ pub const Object = struct {
8361051 emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
8371052 });
8381053
839 {
840 const writer = std.io.getStdErr().writer();
841 try writer.writeAll("\n" ++ "-" ** 200 ++ "\n\n");
842 try self.builder.dump(writer);
843 }
844
8451054 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
8461055 // So we call the entire pipeline multiple times if this is requested.
8471056 var error_message: [*:0]const u8 = undefined;
......@@ -1311,7 +1520,7 @@ pub const Object = struct {
13111520 try global_index.rename(&self.builder, decl_name);
13121521 const decl_name_slice = decl_name.toSlice(&self.builder).?;
13131522 const global = global_index.ptr(&self.builder);
1314 global.unnamed_addr = .none;
1523 global.unnamed_addr = .default;
13151524 llvm_global.setUnnamedAddr(.False);
13161525 global.linkage = .external;
13171526 llvm_global.setLinkage(.External);
......@@ -2674,11 +2883,15 @@ pub const Object = struct {
26742883
26752884 const target = mod.getTarget();
26762885
2677 const llvm_type = try o.lowerLlvmType(decl.ty);
2886 const ty = try o.lowerType(decl.ty);
2887 const llvm_type = if (ty != .none)
2888 o.builder.llvm_types.items[@intFromEnum(ty)]
2889 else
2890 try o.lowerLlvmType(decl.ty);
26782891 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
26792892
26802893 var global = Builder.Global{
2681 .type = .void,
2894 .type = if (ty != .none) ty else .void,
26822895 .kind = .{ .object = @enumFromInt(o.builder.objects.items.len) },
26832896 };
26842897 var object = Builder.Object{
......@@ -2698,7 +2911,7 @@ pub const Object = struct {
26982911
26992912 // This is needed for declarations created by `@extern`.
27002913 if (is_extern) {
2701 global.unnamed_addr = .none;
2914 global.unnamed_addr = .default;
27022915 llvm_global.setUnnamedAddr(.False);
27032916 global.linkage = .external;
27042917 llvm_global.setLinkage(.External);
......@@ -2708,7 +2921,7 @@ pub const Object = struct {
27082921 object.thread_local = .generaldynamic;
27092922 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
27102923 } else {
2711 object.thread_local = .none;
2924 object.thread_local = .default;
27122925 llvm_global.setThreadLocalMode(.NotThreadLocal);
27132926 }
27142927 if (variable.is_weak_linkage) {
......@@ -2962,9 +3175,9 @@ pub const Object = struct {
29623175 const name = try o.builder.string(mod.intern_pool.stringToSlice(
29633176 try struct_obj.getFullyQualifiedName(mod),
29643177 ));
2965 _ = try o.builder.opaqueType(name);
3178 const ty = try o.builder.opaqueType(name);
29663179
2967 const llvm_struct_ty = o.context.structCreateNamed(name.toSlice(&o.builder).?);
3180 const llvm_struct_ty = o.builder.llvm_types.items[@intFromEnum(ty)];
29683181 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
29693182
29703183 assert(struct_obj.haveFieldTypes());
......@@ -3101,16 +3314,6 @@ pub const Object = struct {
31013314 }
31023315 }
31033316
3104 fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type {
3105 const mod = o.module;
3106 switch (t.toIntern()) {
3107 .void_type, .noreturn_type => return .void,
3108 else => switch (mod.intern_pool.indexToKey(t.toIntern())) {
3109 else => return .none,
3110 },
3111 }
3112 }
3113
31143317 fn lowerLlvmTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type {
31153318 const mod = o.module;
31163319 const ip = &mod.intern_pool;
......@@ -3206,6 +3409,149 @@ pub const Object = struct {
32063409 return llvm_elem_ty;
32073410 }
32083411
3412 fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type {
3413 const mod = o.module;
3414 const target = mod.getTarget();
3415 return switch (t.toIntern()) {
3416 .u0_type, .i0_type => unreachable,
3417 inline .u1_type,
3418 .u8_type,
3419 .i8_type,
3420 .u16_type,
3421 .i16_type,
3422 .u29_type,
3423 .u32_type,
3424 .i32_type,
3425 .u64_type,
3426 .i64_type,
3427 .u80_type,
3428 .u128_type,
3429 .i128_type,
3430 => |tag| @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]),
3431 .usize_type, .isize_type => try o.builder.intType(target.ptrBitWidth()),
3432 inline .c_char_type,
3433 .c_short_type,
3434 .c_ushort_type,
3435 .c_int_type,
3436 .c_uint_type,
3437 .c_long_type,
3438 .c_ulong_type,
3439 .c_longlong_type,
3440 .c_ulonglong_type,
3441 => |tag| try o.builder.intType(target.c_type_bit_size(
3442 @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]),
3443 )),
3444 .c_longdouble_type,
3445 .f16_type,
3446 .f32_type,
3447 .f64_type,
3448 .f80_type,
3449 .f128_type,
3450 => switch (t.floatBits(target)) {
3451 16 => if (backendSupportsF16(target)) .half else .i16,
3452 32 => .float,
3453 64 => .double,
3454 80 => if (backendSupportsF80(target)) .x86_fp80 else .i80,
3455 128 => .fp128,
3456 else => unreachable,
3457 },
3458 .anyopaque_type => unreachable,
3459 .bool_type => .i1,
3460 .void_type => .void,
3461 .type_type => unreachable,
3462 .anyerror_type => .i16,
3463 .comptime_int_type, .comptime_float_type, .noreturn_type => unreachable,
3464 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3465 .null_type,
3466 .undefined_type,
3467 .enum_literal_type,
3468 .atomic_order_type,
3469 .atomic_rmw_op_type,
3470 .calling_convention_type,
3471 .address_space_type,
3472 .float_mode_type,
3473 .reduce_op_type,
3474 .call_modifier_type,
3475 .prefetch_options_type,
3476 .export_options_type,
3477 .extern_options_type,
3478 .type_info_type,
3479 => unreachable,
3480 .manyptr_u8_type,
3481 .manyptr_const_u8_type,
3482 .manyptr_const_u8_sentinel_0_type,
3483 .single_const_pointer_to_comptime_int_type,
3484 => .ptr,
3485 .slice_const_u8_type, .slice_const_u8_sentinel_0_type => .none,
3486 .optional_noreturn_type => unreachable,
3487 .anyerror_void_error_union_type => .i16,
3488 .generic_poison_type, .empty_struct_type => unreachable,
3489 // values, not types
3490 .undef,
3491 .zero,
3492 .zero_usize,
3493 .zero_u8,
3494 .one,
3495 .one_usize,
3496 .one_u8,
3497 .four_u8,
3498 .negative_one,
3499 .calling_convention_c,
3500 .calling_convention_inline,
3501 .void_value,
3502 .unreachable_value,
3503 .null_value,
3504 .bool_true,
3505 .bool_false,
3506 .empty_struct,
3507 .generic_poison,
3508 .var_args_param_type,
3509 .none,
3510 => unreachable,
3511 else => switch (mod.intern_pool.indexToKey(t.toIntern())) {
3512 .int_type => |int_type| try o.builder.intType(int_type.bits),
3513 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
3514 .One, .Many, .C => try o.builder.pointerType(@enumFromInt(
3515 toLlvmAddressSpace(ptr_type.flags.address_space, target),
3516 )),
3517 .Slice => .none,
3518 },
3519 .array_type, .vector_type, .opt_type => .none,
3520 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
3521 .error_union_type => .none,
3522 .simple_type => unreachable,
3523 .struct_type,
3524 .anon_struct_type,
3525 .union_type,
3526 .opaque_type,
3527 => .none,
3528 .enum_type => |enum_type| try o.lowerType(enum_type.tag_ty.toType()),
3529 .func_type, .error_set_type, .inferred_error_set_type => .none,
3530 // values, not types
3531 .undef,
3532 .runtime_value,
3533 .simple_value,
3534 .variable,
3535 .extern_func,
3536 .func,
3537 .int,
3538 .err,
3539 .error_union,
3540 .enum_literal,
3541 .enum_tag,
3542 .empty_enum_value,
3543 .float,
3544 .ptr,
3545 .opt,
3546 .aggregate,
3547 .un,
3548 // memoization, not types
3549 .memoized_call,
3550 => unreachable,
3551 },
3552 };
3553 }
3554
32093555 fn lowerValue(o: *Object, arg_tv: TypedValue) Error!*llvm.Value {
32103556 const mod = o.module;
32113557 const gpa = o.gpa;
......@@ -10606,44 +10952,63 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
1060610952
1060710953/// Convert a zig-address space to an llvm address space.
1060810954fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
10955 for (llvmAddressSpaceInfo(target)) |info| if (info.zig == address_space) return info.llvm;
10956 unreachable;
10957}
10958
10959const AddressSpaceInfo = struct {
10960 zig: ?std.builtin.AddressSpace,
10961 llvm: c_uint,
10962 non_integral: bool = false,
10963 size: ?u16 = null,
10964 abi: ?u16 = null,
10965 pref: ?u16 = null,
10966 idx: ?u16 = null,
10967 force_in_data_layout: bool = false,
10968};
10969fn llvmAddressSpaceInfo(target: std.Target) []const AddressSpaceInfo {
1060910970 return switch (target.cpu.arch) {
10610 .x86, .x86_64 => switch (address_space) {
10611 .generic => llvm.address_space.default,
10612 .gs => llvm.address_space.x86.gs,
10613 .fs => llvm.address_space.x86.fs,
10614 .ss => llvm.address_space.x86.ss,
10615 else => unreachable,
10971 .x86, .x86_64 => &.{
10972 .{ .zig = .generic, .llvm = llvm.address_space.default },
10973 .{ .zig = .gs, .llvm = llvm.address_space.x86.gs },
10974 .{ .zig = .fs, .llvm = llvm.address_space.x86.fs },
10975 .{ .zig = .ss, .llvm = llvm.address_space.x86.ss },
10976 .{ .zig = null, .llvm = llvm.address_space.x86.ptr32_sptr, .size = 32, .abi = 32, .force_in_data_layout = true },
10977 .{ .zig = null, .llvm = llvm.address_space.x86.ptr32_uptr, .size = 32, .abi = 32, .force_in_data_layout = true },
10978 .{ .zig = null, .llvm = llvm.address_space.x86.ptr64, .size = 64, .abi = 64, .force_in_data_layout = true },
1061610979 },
10617 .nvptx, .nvptx64 => switch (address_space) {
10618 .generic => llvm.address_space.default,
10619 .global => llvm.address_space.nvptx.global,
10620 .constant => llvm.address_space.nvptx.constant,
10621 .param => llvm.address_space.nvptx.param,
10622 .shared => llvm.address_space.nvptx.shared,
10623 .local => llvm.address_space.nvptx.local,
10624 else => unreachable,
10980 .nvptx, .nvptx64 => &.{
10981 .{ .zig = .generic, .llvm = llvm.address_space.default },
10982 .{ .zig = .global, .llvm = llvm.address_space.nvptx.global },
10983 .{ .zig = .constant, .llvm = llvm.address_space.nvptx.constant },
10984 .{ .zig = .param, .llvm = llvm.address_space.nvptx.param },
10985 .{ .zig = .shared, .llvm = llvm.address_space.nvptx.shared },
10986 .{ .zig = .local, .llvm = llvm.address_space.nvptx.local },
1062510987 },
10626 .amdgcn => switch (address_space) {
10627 .generic => llvm.address_space.amdgpu.flat,
10628 .global => llvm.address_space.amdgpu.global,
10629 .constant => llvm.address_space.amdgpu.constant,
10630 .shared => llvm.address_space.amdgpu.local,
10631 .local => llvm.address_space.amdgpu.private,
10632 else => unreachable,
10988 .amdgcn => &.{
10989 .{ .zig = .generic, .llvm = llvm.address_space.amdgpu.flat },
10990 .{ .zig = .global, .llvm = llvm.address_space.amdgpu.global },
10991 .{ .zig = .constant, .llvm = llvm.address_space.amdgpu.constant },
10992 .{ .zig = .shared, .llvm = llvm.address_space.amdgpu.local },
10993 .{ .zig = .local, .llvm = llvm.address_space.amdgpu.private },
1063310994 },
10634 .avr => switch (address_space) {
10635 .generic => llvm.address_space.default,
10636 .flash => llvm.address_space.avr.flash,
10637 .flash1 => llvm.address_space.avr.flash1,
10638 .flash2 => llvm.address_space.avr.flash2,
10639 .flash3 => llvm.address_space.avr.flash3,
10640 .flash4 => llvm.address_space.avr.flash4,
10641 .flash5 => llvm.address_space.avr.flash5,
10642 else => unreachable,
10995 .avr => &.{
10996 .{ .zig = .generic, .llvm = llvm.address_space.default },
10997 .{ .zig = .flash, .llvm = llvm.address_space.avr.flash },
10998 .{ .zig = .flash1, .llvm = llvm.address_space.avr.flash1 },
10999 .{ .zig = .flash2, .llvm = llvm.address_space.avr.flash2 },
11000 .{ .zig = .flash3, .llvm = llvm.address_space.avr.flash3 },
11001 .{ .zig = .flash4, .llvm = llvm.address_space.avr.flash4 },
11002 .{ .zig = .flash5, .llvm = llvm.address_space.avr.flash5 },
1064311003 },
10644 else => switch (address_space) {
10645 .generic => llvm.address_space.default,
10646 else => unreachable,
11004 .wasm32, .wasm64 => &.{
11005 .{ .zig = .generic, .llvm = llvm.address_space.default },
11006 .{ .zig = null, .llvm = llvm.address_space.wasm.variable, .non_integral = true },
11007 .{ .zig = null, .llvm = llvm.address_space.wasm.externref, .non_integral = true, .size = 8, .abi = 8 },
11008 .{ .zig = null, .llvm = llvm.address_space.wasm.funcref, .non_integral = true, .size = 8, .abi = 8 },
11009 },
11010 else => &.{
11011 .{ .zig = .generic, .llvm = llvm.address_space.default },
1064711012 },
1064811013 };
1064911014}
src/codegen/llvm/Builder.zig+64-42
......@@ -17,6 +17,7 @@ string_indices: std.ArrayListUnmanaged(u32) = .{},
1717
1818types: std.AutoArrayHashMapUnmanaged(String, Type) = .{},
1919next_unnamed_type: String = @enumFromInt(0),
20next_unique_type_id: std.AutoHashMapUnmanaged(String, u32) = .{},
2021type_map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
2122type_data: std.ArrayListUnmanaged(Type.Data) = .{},
2223type_extra: std.ArrayListUnmanaged(u32) = .{},
......@@ -109,8 +110,10 @@ pub const Type = enum(u32) {
109110 i1,
110111 i8,
111112 i16,
113 i29,
112114 i32,
113115 i64,
116 i80,
114117 i128,
115118 ptr,
116119
......@@ -173,17 +176,18 @@ pub const Type = enum(u32) {
173176 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
174177 const type_data = data.builder.type_data.items[@intFromEnum(data.type)];
175178 switch (type_data.tag) {
179 .integer => try writer.print("i{d}", .{type_data.data}),
176180 .named_structure => {
177181 const extra = data.builder.typeExtraData(NamedStructure, type_data.data);
178 if (comptime std.mem.eql(u8, fmt_str, "")) try writer.print("%{}", .{
179 extra.id.fmt(data.builder),
180 }) else if (comptime std.mem.eql(u8, fmt_str, "+")) switch (extra.child) {
182 if (comptime std.mem.eql(u8, fmt_str, "")) switch (extra.child) {
181183 .none => try writer.writeAll("opaque"),
182184 else => try format(.{
183185 .type = extra.child,
184186 .builder = data.builder,
185187 }, fmt_str, fmt_opts, writer),
186 } else @compileError("invalid format string: '" ++ fmt_str ++ "'");
188 } else if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
189 extra.id.fmt(data.builder),
190 }) else @compileError("invalid format string: '" ++ fmt_str ++ "'");
187191 },
188192 else => try writer.print("<type 0x{X}>", .{@intFromEnum(data.type)}),
189193 }
......@@ -220,7 +224,7 @@ pub const Linkage = enum {
220224};
221225
222226pub const Preemption = enum {
223 none,
227 default,
224228 dso_preemptable,
225229 dso_local,
226230
......@@ -230,7 +234,7 @@ pub const Preemption = enum {
230234 _: std.fmt.FormatOptions,
231235 writer: anytype,
232236 ) @TypeOf(writer).Error!void {
233 if (self == .none) return;
237 if (self == .default) return;
234238 try writer.writeAll(@tagName(self));
235239 try writer.writeByte(' ');
236240 }
......@@ -271,7 +275,7 @@ pub const DllStorageClass = enum {
271275};
272276
273277pub const ThreadLocal = enum {
274 none,
278 default,
275279 generaldynamic,
276280 localdynamic,
277281 initialexec,
......@@ -283,7 +287,7 @@ pub const ThreadLocal = enum {
283287 _: std.fmt.FormatOptions,
284288 writer: anytype,
285289 ) @TypeOf(writer).Error!void {
286 if (self == .none) return;
290 if (self == .default) return;
287291 try writer.writeAll("thread_local");
288292 if (self != .generaldynamic) {
289293 try writer.writeByte('(');
......@@ -295,7 +299,7 @@ pub const ThreadLocal = enum {
295299};
296300
297301pub const UnnamedAddr = enum {
298 none,
302 default,
299303 unnamed_addr,
300304 local_unnamed_addr,
301305
......@@ -305,14 +309,14 @@ pub const UnnamedAddr = enum {
305309 _: std.fmt.FormatOptions,
306310 writer: anytype,
307311 ) @TypeOf(writer).Error!void {
308 if (self == .none) return;
312 if (self == .default) return;
309313 try writer.writeAll(@tagName(self));
310314 try writer.writeByte(' ');
311315 }
312316};
313317
314318pub const AddrSpace = enum(u24) {
315 none,
319 default,
316320 _,
317321
318322 pub fn format(
......@@ -321,13 +325,13 @@ pub const AddrSpace = enum(u24) {
321325 _: std.fmt.FormatOptions,
322326 writer: anytype,
323327 ) @TypeOf(writer).Error!void {
324 if (self == .none) return;
328 if (self == .default) return;
325329 try writer.print("addrspace({d}) ", .{@intFromEnum(self)});
326330 }
327331};
328332
329333pub const ExternallyInitialized = enum {
330 none,
334 default,
331335 externally_initialized,
332336
333337 pub fn format(
......@@ -336,7 +340,7 @@ pub const ExternallyInitialized = enum {
336340 _: std.fmt.FormatOptions,
337341 writer: anytype,
338342 ) @TypeOf(writer).Error!void {
339 if (self == .none) return;
343 if (self == .default) return;
340344 try writer.writeAll(@tagName(self));
341345 try writer.writeByte(' ');
342346 }
......@@ -369,12 +373,12 @@ pub const Alignment = enum(u6) {
369373
370374pub const Global = struct {
371375 linkage: Linkage = .default,
372 preemption: Preemption = .none,
376 preemption: Preemption = .default,
373377 visibility: Visibility = .default,
374378 dll_storage_class: DllStorageClass = .default,
375 unnamed_addr: UnnamedAddr = .none,
376 addr_space: AddrSpace = .none,
377 externally_initialized: ExternallyInitialized = .none,
379 unnamed_addr: UnnamedAddr = .default,
380 addr_space: AddrSpace = .default,
381 externally_initialized: ExternallyInitialized = .default,
378382 type: Type,
379383 alignment: Alignment = .default,
380384 kind: union(enum) {
......@@ -459,7 +463,7 @@ pub const Alias = struct {
459463
460464pub const Object = struct {
461465 global: Global.Index,
462 thread_local: ThreadLocal = .none,
466 thread_local: ThreadLocal = .default,
463467 mutability: enum { global, constant } = .global,
464468 init: void = {},
465469
......@@ -525,7 +529,7 @@ pub fn init(self: *Builder) Allocator.Error!void {
525529 @field(llvm.Context, simple_field.name ++ "Type")(self.llvm_context),
526530 );
527531 }
528 inline for (.{ 1, 8, 16, 32, 64, 128 }) |bits| assert(self.intTypeAssumeCapacity(bits) ==
532 inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits| assert(self.intTypeAssumeCapacity(bits) ==
529533 @field(Type, std.fmt.comptimePrint("i{d}", .{bits})));
530534 inline for (.{0}) |addr_space|
531535 assert(self.pointerTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
......@@ -541,6 +545,7 @@ pub fn deinit(self: *Builder) void {
541545 self.string_indices.deinit(self.gpa);
542546
543547 self.types.deinit(self.gpa);
548 self.next_unique_type_id.deinit(self.gpa);
544549 self.type_map.deinit(self.gpa);
545550 self.type_data.deinit(self.gpa);
546551 self.type_extra.deinit(self.gpa);
......@@ -596,13 +601,18 @@ pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args:
596601}
597602
598603pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
604 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
605 try self.string_bytes.ensureUnusedCapacity(self.gpa, name.toSlice(self).?.len +
606 comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));
607 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
599608 try self.types.ensureUnusedCapacity(self.gpa, 1);
609 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
600610 try self.ensureUnusedCapacityTypes(1, Type.NamedStructure);
601611 return self.opaqueTypeAssumeCapacity(name);
602612}
603613
604614pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
605 try self.ensureUnusedCapacityTypes(1);
615 try self.ensureUnusedCapacityTypes(1, null);
606616 return self.intTypeAssumeCapacity(bits);
607617}
608618
......@@ -695,27 +705,39 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
695705 lhs == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
696706 }
697707 };
698 const id = if (name == .none) name: {
699 const next_name = self.next_unnamed_type;
700 assert(next_name != .none);
701 self.next_unnamed_type = @enumFromInt(@intFromEnum(next_name) + 1);
702 break :name next_name;
703 } else name: {
704 assert(name.toIndex() != null);
705 break :name name;
706 };
707 const gop = self.type_map.getOrPutAssumeCapacityAdapted(id, Adapter{ .builder = self });
708 if (!gop.found_existing) {
709 gop.key_ptr.* = {};
710 gop.value_ptr.* = {};
711 self.type_data.appendAssumeCapacity(.{
712 .tag = .named_structure,
713 .data = self.addTypeExtraAssumeCapacity(Type.NamedStructure{ .id = id, .child = .none }),
714 });
708 var id = name;
709 if (name == .none) {
710 id = self.next_unnamed_type;
711 assert(id != .none);
712 self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1);
713 } else assert(name.toIndex() != null);
714 while (true) {
715 const type_gop = self.types.getOrPutAssumeCapacity(id);
716 if (!type_gop.found_existing) {
717 const gop = self.type_map.getOrPutAssumeCapacityAdapted(id, Adapter{ .builder = self });
718 assert(!gop.found_existing);
719 gop.key_ptr.* = {};
720 gop.value_ptr.* = {};
721 self.type_data.appendAssumeCapacity(.{
722 .tag = .named_structure,
723 .data = self.addTypeExtraAssumeCapacity(Type.NamedStructure{
724 .id = id,
725 .child = .none,
726 }),
727 });
728 const result: Type = @enumFromInt(gop.index);
729 type_gop.value_ptr.* = result;
730 if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(
731 self.llvm_context.structCreateNamed(id.toSlice(self) orelse ""),
732 );
733 return result;
734 }
735
736 const unique_gop = self.next_unique_type_id.getOrPutAssumeCapacity(name);
737 if (!unique_gop.found_existing) unique_gop.value_ptr.* = 2;
738 id = self.fmtAssumeCapacity("{s}.{d}", .{ name.toSlice(self).?, unique_gop.value_ptr.* });
739 unique_gop.value_ptr.* += 1;
715740 }
716 const result: Type = @enumFromInt(gop.index);
717 self.types.putAssumeCapacityNoClobber(id, result);
718 return result;
719741}
720742
721743fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
......@@ -786,7 +808,7 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
786808 , .{self.target_triple.fmt(self)});
787809 try writer.writeByte('\n');
788810 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
789 \\%{} = type {+}
811 \\%{} = type {}
790812 \\
791813 , .{ id.fmt(self), ty.fmt(self) });
792814 try writer.writeByte('\n');
src/codegen/llvm/bindings.zig+7
......@@ -1612,6 +1612,13 @@ pub const address_space = struct {
16121612 pub const constant_buffer_14: c_uint = 22;
16131613 pub const constant_buffer_15: c_uint = 23;
16141614 };
1615
1616 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
1617 pub const wasm = struct {
1618 pub const variable = 1;
1619 pub const externref = 10;
1620 pub const funcref = 20;
1621 };
16151622};
16161623
16171624pub const DIEnumerator = opaque {};