authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-06-24 19:34:13-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-27 14:38:34-04:00
logb425e6869452ebeaf9b15ceb5739ce4b4bb5b87d
tree47b3425719a1d13a17935ec1c50d65f6e19644a6
parent865f329e4f9fd097bb9739566045f9b7179521c4

llvm: update for compiler_rt abi changes

Closes #12602 Closes #21234 Closes #35899 Closes #36127

38 files changed, 2145 insertions(+), 1478 deletions(-)

lib/compiler/aro/aro/Target.zig+3-3
...@@ -1559,15 +1559,15 @@ pub fn ptrBitWidth(target: *const Target) u16 {...@@ -1559,15 +1559,15 @@ pub fn ptrBitWidth(target: *const Target) u16 {
1559}1559}
15601560
1561pub fn cCharSignedness(target: *const Target) std.builtin.Signedness {1561pub fn cCharSignedness(target: *const Target) std.builtin.Signedness {
1562 return target.toZigTarget().cCharSignedness();1562 return target.toZigTarget().cCharSignedness().?;
1563}1563}
15641564
1565pub fn cTypeBitSize(target: *const Target, c_type: std.Target.CType) u16 {1565pub fn cTypeBitSize(target: *const Target, c_type: std.Target.CType) u16 {
1566 return target.toZigTarget().cTypeBitSize(c_type);1566 return target.toZigTarget().cTypeBitSize(c_type).?;
1567}1567}
15681568
1569pub fn cTypeAlignment(target: *const Target, c_type: std.Target.CType) u16 {1569pub fn cTypeAlignment(target: *const Target, c_type: std.Target.CType) u16 {
1570 return target.toZigTarget().cTypeAlignment(c_type);1570 return target.toZigTarget().cTypeAlignment(c_type).?;
1571}1571}
15721572
1573pub fn standardDynamicLinkerPath(target: *const Target) std.Target.DynamicLinker {1573pub fn standardDynamicLinkerPath(target: *const Target) std.Target.DynamicLinker {
lib/compiler/reduce.zig+1-1
...@@ -400,7 +400,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast {...@@ -400,7 +400,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast {
400 file_path,400 file_path,
401 gpa,401 gpa,
402 .limited(std.math.maxInt(u32)),402 .limited(std.math.maxInt(u32)),
403 .fromByteUnits(1),403 .@"1",
404 0,404 0,
405 ) catch |err| {405 ) catch |err| {
406 fatal("unable to open '{s}': {s}", .{ file_path, @errorName(err) });406 fatal("unable to open '{s}': {s}", .{ file_path, @errorName(err) });
lib/compiler/test_runner.zig+10-11
...@@ -91,24 +91,23 @@ fn mainServer(init: std.process.Init.Minimal) !void {...@@ -91,24 +91,23 @@ fn mainServer(init: std.process.Init.Minimal) !void {
91 return std.process.exit(0);91 return std.process.exit(0);
92 },92 },
93 .query_test_metadata => {93 .query_test_metadata => {
94 testing.allocator_instance = .init(std.heap.page_allocator, .{});94 var sa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
95 defer if (testing.allocator_instance.deinit() != 0) {95 defer if (sa.deinit() != 0) @panic("internal test runner memory leak");
96 @panic("internal test runner memory leak");96 const gpa = sa.allocator();
97 };
9897
99 var string_bytes: std.ArrayList(u8) = .empty;98 var string_bytes: std.ArrayList(u8) = .empty;
100 defer string_bytes.deinit(testing.allocator);99 defer string_bytes.deinit(gpa);
101 try string_bytes.append(testing.allocator, 0); // Reserve 0 for null.100 try string_bytes.append(gpa, 0); // Reserve 0 for null.
102101
103 const test_fns = builtin.test_functions;102 const test_fns = builtin.test_functions;
104 const names = try testing.allocator.alloc(u32, test_fns.len);103 const names = try gpa.alloc(u32, test_fns.len);
105 defer testing.allocator.free(names);104 defer gpa.free(names);
106 const expected_panic_msgs = try testing.allocator.alloc(u32, test_fns.len);105 const expected_panic_msgs = try gpa.alloc(u32, test_fns.len);
107 defer testing.allocator.free(expected_panic_msgs);106 defer gpa.free(expected_panic_msgs);
108107
109 for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| {108 for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| {
110 name.* = @intCast(string_bytes.items.len);109 name.* = @intCast(string_bytes.items.len);
111 try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1);110 try string_bytes.ensureUnusedCapacity(gpa, test_fn.name.len + 1);
112 string_bytes.appendSliceAssumeCapacity(test_fn.name);111 string_bytes.appendSliceAssumeCapacity(test_fn.name);
113 string_bytes.appendAssumeCapacity(0);112 string_bytes.appendAssumeCapacity(0);
114 expected_panic_msg.* = 0;113 expected_panic_msg.* = 0;
lib/compiler_rt/comparef.zig+1-1
...@@ -8,7 +8,7 @@ const Unordered = if (builtin.cpu.arch == .avr)...@@ -8,7 +8,7 @@ const Unordered = if (builtin.cpu.arch == .avr)
8 i88 i8
9else if (builtin.cpu.arch.isAARCH64())9else if (builtin.cpu.arch.isAARCH64())
10 i3210 i32
11else if (builtin.target.cTypeBitSize(.long) >= builtin.target.ptrBitWidth())11else if (builtin.target.cTypeBitSize(.long).? >= builtin.target.ptrBitWidth())
12 c_long12 c_long
13else13else
14 c_longlong;14 c_longlong;
lib/std/Io/Writer.zig+6-6
...@@ -2817,12 +2817,12 @@ pub const Allocating = struct {...@@ -2817,12 +2817,12 @@ pub const Allocating = struct {
2817 }2817 }
28182818
2819 test Allocating {2819 test Allocating {
2820 try testAllocating(.fromByteUnits(1));2820 try testAllocating(.@"1");
2821 try testAllocating(.fromByteUnits(4));2821 try testAllocating(.@"4");
2822 try testAllocating(.fromByteUnits(8));2822 try testAllocating(.@"8");
2823 try testAllocating(.fromByteUnits(16));2823 try testAllocating(.@"16");
2824 try testAllocating(.fromByteUnits(32));2824 try testAllocating(.@"32");
2825 try testAllocating(.fromByteUnits(64));2825 try testAllocating(.@"64");
2826 }2826 }
2827};2827};
28282828
lib/std/Target.zig+23-11
...@@ -3066,9 +3066,13 @@ pub fn stackGrowth(target: *const Target) StackGrowth {...@@ -3066,9 +3066,13 @@ pub fn stackGrowth(target: *const Target) StackGrowth {
3066/// Default signedness of `char` for the native C compiler for this target3066/// Default signedness of `char` for the native C compiler for this target
3067/// Note that char signedness is implementation-defined and many compilers provide3067/// Note that char signedness is implementation-defined and many compilers provide
3068/// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char3068/// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
3069pub fn cCharSignedness(target: *const Target) std.builtin.Signedness {3069/// Returns `null` if no C ABI is defined for this target.
3070pub fn cCharSignedness(target: *const Target) ?std.builtin.Signedness {
3071 switch (target.os.tag) {
3072 .opengl => return null,
3073 else => {},
3074 }
3070 if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed;3075 if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed;
3071
3072 return switch (target.cpu.arch) {3076 return switch (target.cpu.arch) {
3073 .aarch64,3077 .aarch64,
3074 .aarch64_be,3078 .aarch64_be,
...@@ -3114,7 +3118,8 @@ pub const CType = enum {...@@ -3114,7 +3118,8 @@ pub const CType = enum {
3114 longdouble,3118 longdouble,
3115};3119};
31163120
3117pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {3121/// Returns `null` if no C ABI is defined for this target.
3122pub fn cTypeByteSize(t: *const Target, c_type: CType) ?u16 {
3118 return switch (c_type) {3123 return switch (c_type) {
3119 .char,3124 .char,
3120 .short,3125 .short,
...@@ -3127,18 +3132,19 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {...@@ -3127,18 +3132,19 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {
3127 .ulonglong,3132 .ulonglong,
3128 .float,3133 .float,
3129 .double,3134 .double,
3130 => @divExact(cTypeBitSize(t, c_type), 8),3135 => @divExact(cTypeBitSize(t, c_type) orelse return null, 8),
31313136
3132 .longdouble => switch (cTypeBitSize(t, c_type)) {3137 .longdouble => switch (cTypeBitSize(t, c_type) orelse return null) {
3133 64 => 8,3138 64 => 8,
3134 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, .longdouble))),3139 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, c_type).?)),
3135 128 => 16,3140 128 => 16,
3136 else => unreachable,3141 else => unreachable,
3137 },3142 },
3138 };3143 };
3139}3144}
31403145
3141pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {3146/// Returns `null` if no C ABI is defined for this target.
3147pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3142 switch (target.os.tag) {3148 switch (target.os.tag) {
3143 .freestanding,3149 .freestanding,
3144 .other,3150 .other,
...@@ -3459,15 +3465,17 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {...@@ -3459,15 +3465,17 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
3459 .longlong, .ulonglong, .longdouble => return 64,3465 .longlong, .ulonglong, .longdouble => return 64,
3460 },3466 },
34613467
3468 .opengl => return null,
3469
3462 .ps3,3470 .ps3,
3463 .contiki,3471 .contiki,
3464 .managarm,3472 .managarm,
3465 .opengl,
3466 => @panic("specify the C integer and float type sizes for this OS"),3473 => @panic("specify the C integer and float type sizes for this OS"),
3467 }3474 }
3468}3475}
34693476
3470pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {3477/// Returns `null` if no C ABI is defined for this target.
3478pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {
3471 // Overrides for unusual alignments3479 // Overrides for unusual alignments
3472 switch (target.cpu.arch) {3480 switch (target.cpu.arch) {
3473 .avr,3481 .avr,
...@@ -3500,7 +3508,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {...@@ -3500,7 +3508,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
35003508
3501 // Next-power-of-two-aligned, up to a maximum.3509 // Next-power-of-two-aligned, up to a maximum.
3502 return @min(3510 return @min(
3503 std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),3511 std.math.ceilPowerOfTwoAssert(u16, ((cTypeBitSize(target, c_type) orelse return null) + 7) / 8),
3504 @as(u16, switch (target.cpu.arch) {3512 @as(u16, switch (target.cpu.arch) {
3505 .msp430,3513 .msp430,
3506 .x86_16,3514 .x86_16,
...@@ -3598,6 +3606,11 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {...@@ -3598,6 +3606,11 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {
3598 .xcore,3606 .xcore,
3599 => 4,3607 => 4,
36003608
3609 .x86 => switch (target.os.tag) {
3610 else => 4,
3611 .uefi, .windows => 8,
3612 },
3613
3601 .arm,3614 .arm,
3602 .armeb,3615 .armeb,
3603 .hexagon,3616 .hexagon,
...@@ -3616,7 +3629,6 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {...@@ -3616,7 +3629,6 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {
3616 .sparc,3629 .sparc,
3617 .thumb,3630 .thumb,
3618 .thumbeb,3631 .thumbeb,
3619 .x86,
3620 .xtensa,3632 .xtensa,
3621 .xtensaeb,3633 .xtensaeb,
3622 => 8,3634 => 8,
lib/std/math/gamma.zig-2
...@@ -263,8 +263,6 @@ test gamma {...@@ -263,8 +263,6 @@ test gamma {
263}263}
264264
265test "gamma.special" {265test "gamma.special" {
266 if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
267
268 inline for (&.{ f32, f64 }) |T| {266 inline for (&.{ f32, f64 }) |T| {
269 try expect(std.math.isNan(gamma(T, -std.math.nan(T))));267 try expect(std.math.isNan(gamma(T, -std.math.nan(T))));
270 try expect(std.math.isNan(gamma(T, std.math.nan(T))));268 try expect(std.math.isNan(gamma(T, std.math.nan(T))));
lib/std/zig/llvm/Builder.zig+2-2
...@@ -5999,7 +5999,7 @@ pub const WipFunction = struct {...@@ -5999,7 +5999,7 @@ pub const WipFunction = struct {
5999 alignment: Alignment,5999 alignment: Alignment,
6000 name: []const u8,6000 name: []const u8,
6001 ) Allocator.Error!Value {6001 ) Allocator.Error!Value {
6002 return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name);6002 return self.loadAtomic(access_kind, ty, ptr, undefined, .none, alignment, name);
6003 }6003 }
60046004
6005 pub fn loadAtomic(6005 pub fn loadAtomic(
...@@ -6043,7 +6043,7 @@ pub const WipFunction = struct {...@@ -6043,7 +6043,7 @@ pub const WipFunction = struct {
6043 ptr: Value,6043 ptr: Value,
6044 alignment: Alignment,6044 alignment: Alignment,
6045 ) Allocator.Error!Instruction.Index {6045 ) Allocator.Error!Instruction.Index {
6046 return self.storeAtomic(kind, val, ptr, .system, .none, alignment);6046 return self.storeAtomic(kind, val, ptr, undefined, .none, alignment);
6047 }6047 }
60486048
6049 pub fn storeAtomic(6049 pub fn storeAtomic(
lib/std/zig/target.zig+10-26
...@@ -499,31 +499,12 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 {...@@ -499,31 +499,12 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 {
499}499}
500500
501pub fn intAlignment(target: *const std.Target, bits: u16) u16 {501pub fn intAlignment(target: *const std.Target, bits: u16) u16 {
502 return switch (target.cpu.arch) {502 return switch (bits) {
503 .x86 => switch (bits) {503 0 => 1,
504 0...8 => 1,504 else => @min(
505 9...16 => 2,505 std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)),
506 17...32 => 4,506 target.cMaxIntAlignment(),
507 33...64 => switch (target.os.tag) {507 ),
508 .uefi, .windows => 8,
509 else => 4,
510 },
511 else => 16,
512 },
513 .x86_64 => switch (bits) {
514 0...8 => 1,
515 9...16 => 2,
516 17...32 => 4,
517 33...64 => 8,
518 else => 16,
519 },
520 else => switch (bits) {
521 0 => 1,
522 else => @min(
523 std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)),
524 target.cMaxIntAlignment(),
525 ),
526 },
527 };508 };
528}509}
529510
...@@ -536,7 +517,10 @@ pub fn compilerRtFloatAbi(target: *const std.Target, bits: u16) std.Target.Abi.F...@@ -536,7 +517,10 @@ pub fn compilerRtFloatAbi(target: *const std.Target, bits: u16) std.Target.Abi.F
536 16 => if (target.cpu.arch.isMIPS() or target.cpu.arch.isPowerPC()) return no_c_type_available,517 16 => if (target.cpu.arch.isMIPS() or target.cpu.arch.isPowerPC()) return no_c_type_available,
537 32, 64 => {},518 32, 64 => {},
538 80 => if (target.cTypeBitSize(.longdouble) != 80) return no_c_type_available,519 80 => if (target.cTypeBitSize(.longdouble) != 80) return no_c_type_available,
539 128 => if (target.cTypeBitSize(.longdouble) <= 64) return no_c_type_available,520 128 => {
521 if (target.cpu.arch.isX86()) return .hard; // if (target.abi == .msvc) __m128i else __float128
522 if (target.cTypeBitSize(.longdouble) != 128) return no_c_type_available;
523 },
540 }524 }
541 return .hard;525 return .hard;
542}526}
src/Sema.zig+4-4
...@@ -29657,7 +29657,7 @@ fn coerceVarArgParam(...@@ -29657,7 +29657,7 @@ fn coerceVarArgParam(
29657 .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),29657 .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
29658 .float => float: {29658 .float => float: {
29659 const target = zcu.getTarget();29659 const target = zcu.getTarget();
29660 const double_bits = target.cTypeBitSize(.double);29660 const double_bits = target.cTypeBitSize(.double) orelse break :float inst;
29661 const inst_bits = uncasted_ty.floatBits(target);29661 const inst_bits = uncasted_ty.floatBits(target);
29662 if (inst_bits >= double_bits) break :float inst;29662 if (inst_bits >= double_bits) break :float inst;
29663 switch (double_bits) {29663 switch (double_bits) {
...@@ -29673,21 +29673,21 @@ fn coerceVarArgParam(...@@ -29673,21 +29673,21 @@ fn coerceVarArgParam(
29673 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {29673 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {
29674 .signed => .int,29674 .signed => .int,
29675 .unsigned => .uint,29675 .unsigned => .uint,
29676 })) break :int try sema.coerce(block, switch (uncasted_info.signedness) {29676 }) orelse break :int inst) break :int try sema.coerce(block, switch (uncasted_info.signedness) {
29677 .signed => .c_int,29677 .signed => .c_int,
29678 .unsigned => .c_uint,29678 .unsigned => .c_uint,
29679 }, inst, inst_src);29679 }, inst, inst_src);
29680 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {29680 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {
29681 .signed => .long,29681 .signed => .long,
29682 .unsigned => .ulong,29682 .unsigned => .ulong,
29683 })) break :int try sema.coerce(block, switch (uncasted_info.signedness) {29683 }).?) break :int try sema.coerce(block, switch (uncasted_info.signedness) {
29684 .signed => .c_long,29684 .signed => .c_long,
29685 .unsigned => .c_ulong,29685 .unsigned => .c_ulong,
29686 }, inst, inst_src);29686 }, inst, inst_src);
29687 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {29687 if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {
29688 .signed => .longlong,29688 .signed => .longlong,
29689 .unsigned => .ulonglong,29689 .unsigned => .ulonglong,
29690 })) break :int try sema.coerce(block, switch (uncasted_info.signedness) {29690 }).?) break :int try sema.coerce(block, switch (uncasted_info.signedness) {
29691 .signed => .c_longlong,29691 .signed => .c_longlong,
29692 .unsigned => .c_ulonglong,29692 .unsigned => .c_ulonglong,
29693 }, inst, inst_src);29693 }, inst, inst_src);
src/Sema/type_resolution.zig+1-1
...@@ -364,7 +364,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -364,7 +364,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
364 const a = struct_obj.field_aligns.get(ip)[field_idx];364 const a = struct_obj.field_aligns.get(ip)[field_idx];
365 if (a != .none) break :a a;365 if (a != .none) break :a a;
366 }366 }
367 break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);367 break :a field_ty.abiAlignment(zcu);
368 };368 };
369 align_out.* = field_align;369 align_out.* = field_align;
370 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) {370 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) {
src/Type.zig+102-84
...@@ -957,10 +957,25 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -957,10 +957,25 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
957 if (vector_type.len == 0) return .@"1";957 if (vector_type.len == 0) return .@"1";
958 switch (zcu.comp.getZigBackend()) {958 switch (zcu.comp.getZigBackend()) {
959 else => {959 else => {
960 const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu));960 const elem_ty: Type = .fromInterned(vector_type.child);
961 switch (if (elem_ty.isRuntimeFloat())
962 std.zig.target.compilerRtFloatAbi(target, elem_ty.floatBits(target))
963 else
964 .hard) {
965 .hard => {},
966 .soft => return elem_ty.abiAlignment(zcu),
967 }
968 const elem_bits: u32 = @intCast(elem_ty.bitSize(zcu));
961 if (elem_bits == 0) return .@"1";969 if (elem_bits == 0) return .@"1";
962 const bytes = ((elem_bits * vector_type.len) + 7) / 8;970 const bytes = ((elem_bits * vector_type.len) + 7) / 8;
963 return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes));971 const arch = target.cpu.arch;
972 return .fromByteUnits(std.math.ceilPowerOfTwoAssert(
973 u32,
974 if (arch.isArm() or arch.isAARCH64() or arch == .s390x)
975 @min(bytes, target.stackAlignment())
976 else
977 bytes,
978 ));
964 },979 },
965 .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).abiAlignment(zcu),980 .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).abiAlignment(zcu),
966 .stage2_x86_64 => {981 .stage2_x86_64 => {
...@@ -1018,19 +1033,33 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {...@@ -1018,19 +1033,33 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
1018 .c_ulonglong => cTypeAlign(target, .ulonglong),1033 .c_ulonglong => cTypeAlign(target, .ulonglong),
1019 .c_longdouble => cTypeAlign(target, .longdouble),1034 .c_longdouble => cTypeAlign(target, .longdouble),
10201035
1021 .f16 => .@"2",1036 .f16 => .fromByteUnits(std.zig.target.intAlignment(target, 16)), // repr: u16
1022 .f32 => if (target.os.tag == .opengl) .@"4" else cTypeAlign(target, .float),1037 .f32 => if (target.cTypeBitSize(.float) == 32)
1023 .f64 => if (target.os.tag == .opengl) .@"8" else switch (target.cTypeBitSize(.double)) {1038 cTypeAlign(target, .float) // abi: c_float,
1024 64 => cTypeAlign(target, .double),1039 else
1025 else => .@"8",1040 .fromByteUnits(std.zig.target.intAlignment(target, 32)), // repr: u32,
1026 },1041 .f64 => if (target.cTypeBitSize(.double) == 64)
1027 .f80 => switch (target.cTypeBitSize(.longdouble)) {1042 cTypeAlign(target, .double) // abi: c_double,
1028 80 => cTypeAlign(target, .longdouble),1043 else
1029 else => Type.u80.abiAlignment(zcu),1044 .fromByteUnits(std.zig.target.intAlignment(target, 64)), // repr: u64,
1030 },1045 .f80 => if (target.cTypeBitSize(.longdouble) == 80)
1031 .f128 => switch (target.cTypeBitSize(.longdouble)) {1046 cTypeAlign(target, .longdouble) // abi: c_longdouble,
1032 128 => cTypeAlign(target, .longdouble),1047 else
1033 else => .@"16",1048 .fromByteUnits(switch (std.zig.target.compilerRtFloatAbi(target, 80)) {
1049 .hard => std.zig.target.intAlignment(target, 80), // repr: u80,
1050 .soft => @max(
1051 std.zig.target.intAlignment(target, 64), // mantissa: u64,
1052 std.zig.target.intAlignment(target, 16), // exponent: u16,
1053 ),
1054 }),
1055 .f128 => if (target.cTypeBitSize(.longdouble) == 128)
1056 cTypeAlign(target, .longdouble) // abi: c_longdouble,
1057 else switch (std.zig.target.compilerRtFloatAbi(target, 128)) {
1058 .hard => if (target.cpu.arch.isX86())
1059 .@"16" // abi: c___float128,
1060 else
1061 .fromByteUnits(std.zig.target.intAlignment(target, 128)), // repr: u128,
1062 .soft => .fromByteUnits(std.zig.target.intAlignment(target, 64)), // lo: u64, hi: u64,
1034 },1063 },
10351064
1036 .generic_poison => unreachable,1065 .generic_poison => unreachable,
...@@ -1111,7 +1140,13 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {...@@ -1111,7 +1140,13 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
1111 .vector_type => |vec| {1140 .vector_type => |vec| {
1112 const elem_ty: Type = .fromInterned(vec.child);1141 const elem_ty: Type = .fromInterned(vec.child);
1113 const bytes = switch (zcu.comp.getZigBackend()) {1142 const bytes = switch (zcu.comp.getZigBackend()) {
1114 else => @divCeil(vec.len * elem_ty.bitSize(zcu), 8),1143 else => switch (if (elem_ty.isRuntimeFloat())
1144 std.zig.target.compilerRtFloatAbi(target, elem_ty.floatBits(target))
1145 else
1146 .hard) {
1147 .hard => @divCeil(vec.len * elem_ty.bitSize(zcu), 8),
1148 .soft => vec.len * elem_ty.abiSize(zcu),
1149 },
1115 .stage2_c, .stage2_wasm => vec.len * elem_ty.abiSize(zcu),1150 .stage2_c, .stage2_wasm => vec.len * elem_ty.abiSize(zcu),
1116 .stage2_x86_64 => switch (elem_ty.toIntern()) {1151 .stage2_x86_64 => switch (elem_ty.toIntern()) {
1117 .bool_type => @divCeil(vec.len, 8),1152 .bool_type => @divCeil(vec.len, 8),
...@@ -1167,25 +1202,44 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {...@@ -1167,25 +1202,44 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
1167 .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu),1202 .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu),
1168 .usize, .isize => ptrAbiSize(target),1203 .usize, .isize => ptrAbiSize(target),
11691204
1170 .c_char => target.cTypeByteSize(.char),1205 .c_char => target.cTypeByteSize(.char).?,
1171 .c_short => target.cTypeByteSize(.short),1206 .c_short => target.cTypeByteSize(.short).?,
1172 .c_ushort => target.cTypeByteSize(.ushort),1207 .c_ushort => target.cTypeByteSize(.ushort).?,
1173 .c_int => target.cTypeByteSize(.int),1208 .c_int => target.cTypeByteSize(.int).?,
1174 .c_uint => target.cTypeByteSize(.uint),1209 .c_uint => target.cTypeByteSize(.uint).?,
1175 .c_long => target.cTypeByteSize(.long),1210 .c_long => target.cTypeByteSize(.long).?,
1176 .c_ulong => target.cTypeByteSize(.ulong),1211 .c_ulong => target.cTypeByteSize(.ulong).?,
1177 .c_longlong => target.cTypeByteSize(.longlong),1212 .c_longlong => target.cTypeByteSize(.longlong).?,
1178 .c_ulonglong => target.cTypeByteSize(.ulonglong),1213 .c_ulonglong => target.cTypeByteSize(.ulonglong).?,
1179 .c_longdouble => target.cTypeByteSize(.longdouble),1214 .c_longdouble => target.cTypeByteSize(.longdouble).?,
11801215
1181 .f16 => 2,1216 .f16 => std.zig.target.intByteSize(target, 16), // repr: u16
1182 .f32 => 4,1217 .f32 => if (target.cTypeBitSize(.float) == 32)
1183 .f64 => 8,1218 target.cTypeByteSize(.float).? // abi: c_float,
1184 .f80 => switch (target.cTypeBitSize(.longdouble)) {1219 else
1185 80 => target.cTypeByteSize(.longdouble),1220 std.zig.target.intByteSize(target, 32), // repr: u32,
1186 else => Type.u80.abiSize(zcu),1221 .f64 => if (target.cTypeBitSize(.double) == 64)
1222 target.cTypeByteSize(.double).? // abi: c_double,
1223 else
1224 std.zig.target.intByteSize(target, 64), // repr: u64,
1225 .f80 => if (target.cTypeBitSize(.longdouble) == 80)
1226 target.cTypeByteSize(.longdouble).? // abi: c_longdouble,
1227 else switch (std.zig.target.compilerRtFloatAbi(target, 80)) {
1228 .hard => std.zig.target.intByteSize(target, 80), // repr: u80,
1229 .soft => ty.abiAlignment(zcu).forward(
1230 std.zig.target.intByteSize(target, 64) + // mantissa: u64,
1231 std.zig.target.intByteSize(target, 16), // exponent: u16
1232 ),
1233 },
1234 .f128 => if (target.cTypeBitSize(.longdouble) == 128)
1235 target.cTypeByteSize(.longdouble).? // abi: c_longdouble,
1236 else switch (std.zig.target.compilerRtFloatAbi(target, 128)) {
1237 .hard => if (target.cpu.arch.isX86())
1238 16 // abi: c___float128,
1239 else
1240 std.zig.target.intByteSize(target, 128), // repr: u128,
1241 .soft => std.zig.target.intByteSize(target, 64) * 2, // lo: u64, hi: u64,
1187 },1242 },
1188 .f128 => 16,
11891243
1190 .anyopaque => unreachable,1244 .anyopaque => unreachable,
1191 .generic_poison => unreachable,1245 .generic_poison => unreachable,
...@@ -1733,7 +1787,7 @@ pub fn isInt(self: Type, zcu: *const Zcu) bool {...@@ -1733,7 +1787,7 @@ pub fn isInt(self: Type, zcu: *const Zcu) bool {
1733/// Returns true if and only if the type is a fixed-width, signed integer.1787/// Returns true if and only if the type is a fixed-width, signed integer.
1734pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool {1788pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool {
1735 return switch (ty.toIntern()) {1789 return switch (ty.toIntern()) {
1736 .c_char_type => zcu.getTarget().cCharSignedness() == .signed,1790 .c_char_type => zcu.getTarget().cCharSignedness().? == .signed,
1737 .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,1791 .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,
1738 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1792 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1739 .int_type => |int_type| int_type.signedness == .signed,1793 .int_type => |int_type| int_type.signedness == .signed,
...@@ -1745,7 +1799,7 @@ pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool {...@@ -1745,7 +1799,7 @@ pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool {
1745/// Returns true if and only if the type is a fixed-width, unsigned integer.1799/// Returns true if and only if the type is a fixed-width, unsigned integer.
1746pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool {1800pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool {
1747 return switch (ty.toIntern()) {1801 return switch (ty.toIntern()) {
1748 .c_char_type => zcu.getTarget().cCharSignedness() == .unsigned,1802 .c_char_type => zcu.getTarget().cCharSignedness().? == .unsigned,
1749 .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true,1803 .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true,
1750 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1804 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1751 .int_type => |int_type| int_type.signedness == .unsigned,1805 .int_type => |int_type| int_type.signedness == .unsigned,
...@@ -1776,15 +1830,15 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {...@@ -1776,15 +1830,15 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
1776 },1830 },
1777 .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() },1831 .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() },
1778 .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() },1832 .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() },
1779 .c_char_type => return .{ .signedness = zcu.getTarget().cCharSignedness(), .bits = target.cTypeBitSize(.char) },1833 .c_char_type => return .{ .signedness = target.cCharSignedness().?, .bits = target.cTypeBitSize(.char).? },
1780 .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short) },1834 .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short).? },
1781 .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort) },1835 .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort).? },
1782 .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int) },1836 .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int).? },
1783 .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint) },1837 .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint).? },
1784 .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long) },1838 .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long).? },
1785 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong) },1839 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong).? },
1786 .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong) },1840 .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong).? },
1787 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) },1841 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong).? },
1788 else => switch (ip.indexToKey(ty.toIntern())) {1842 else => switch (ip.indexToKey(ty.toIntern())) {
1789 .int_type => |int_type| return int_type,1843 .int_type => |int_type| return int_type,
1790 .struct_type => {1844 .struct_type => {
...@@ -1882,7 +1936,7 @@ pub fn floatBits(ty: Type, target: *const Target) u16 {...@@ -1882,7 +1936,7 @@ pub fn floatBits(ty: Type, target: *const Target) u16 {
1882 .f64_type => 64,1936 .f64_type => 64,
1883 .f80_type => 80,1937 .f80_type => 80,
1884 .f128_type, .comptime_float_type => 128,1938 .f128_type, .comptime_float_type => 128,
1885 .c_longdouble_type => target.cTypeBitSize(.longdouble),1939 .c_longdouble_type => target.cTypeBitSize(.longdouble).?,
18861940
1887 else => unreachable,1941 else => unreachable,
1888 };1942 };
...@@ -2147,13 +2201,6 @@ pub fn isVector(ty: Type, zcu: *const Zcu) bool {...@@ -2147,13 +2201,6 @@ pub fn isVector(ty: Type, zcu: *const Zcu) bool {
2147 return ty.zigTypeTag(zcu) == .vector;2201 return ty.zigTypeTag(zcu) == .vector;
2148}2202}
21492203
2150/// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len.
2151pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 {
2152 if (!ty.isVector(zcu)) return 0;
2153 const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type;
2154 return v.len * Type.fromInterned(v.child).bitSize(zcu);
2155}
2156
2157pub fn isArrayOrVector(ty: Type, zcu: *const Zcu) bool {2204pub fn isArrayOrVector(ty: Type, zcu: *const Zcu) bool {
2158 return switch (ty.zigTypeTag(zcu)) {2205 return switch (ty.zigTypeTag(zcu)) {
2159 .array, .vector => true,2206 .array, .vector => true,
...@@ -2416,34 +2463,6 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment...@@ -2416,34 +2463,6 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment
2416 };2463 };
2417}2464}
24182465
2419/// Returns the alignment a struct field of type `field_ty` will be given if no alignment is
2420/// explicitly specified. However, in an `extern struct`, a higher alignment may be available due
2421/// to the struct's full layout (i.e. a field might coincidentally be more aligned).
2422///
2423/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`.
2424pub fn defaultStructFieldAlignment(
2425 field_ty: Type,
2426 layout: std.lang.Type.ContainerLayout,
2427 zcu: *const Zcu,
2428) Alignment {
2429 const overalign_big_int = switch (layout) {
2430 .@"packed" => unreachable,
2431 .auto => zcu.getTarget().ofmt == .c,
2432 .@"extern" => true,
2433 };
2434 const abi_align = field_ty.abiAlignment(zcu);
2435 assert(abi_align != .none);
2436 // We check for anything over 64 here, because the C backend will lower e.g. u64 to a 128-bit
2437 // integer, which has 16-byte alignment.
2438 if (overalign_big_int and
2439 ((field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits > 64) or
2440 (field_ty.toIntern() == .f80_type and zcu.getTarget().cTypeBitSize(.longdouble) != 80)))
2441 {
2442 return abi_align.maxStrict(if (zcu.getTarget().cpu.arch == .s390x) .@"8" else .@"16");
2443 }
2444 return abi_align;
2445}
2446
2447pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value {2466pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value {
2448 const ip = &zcu.intern_pool;2467 const ip = &zcu.intern_pool;
2449 switch (ip.indexToKey(ty.toIntern())) {2468 switch (ip.indexToKey(ty.toIntern())) {
...@@ -2961,8 +2980,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator...@@ -2961,8 +2980,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator
2961 }2980 }
2962 const actual_field_align = switch (field_align) {2981 const actual_field_align = switch (field_align) {
2963 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {2982 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {
2964 .tuple_type, .union_type => field_ty.abiAlignment(zcu),2983 .struct_type, .tuple_type, .union_type => field_ty.abiAlignment(zcu),
2965 .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu),
2966 .ptr_type => Type.usize.abiAlignment(zcu),2984 .ptr_type => Type.usize.abiAlignment(zcu),
2967 else => unreachable,2985 else => unreachable,
2968 },2986 },
...@@ -3603,5 +3621,5 @@ pub fn smallestUnsignedBits(max: u64) u16 {...@@ -3603,5 +3621,5 @@ pub fn smallestUnsignedBits(max: u64) u16 {
3603pub const packed_struct_layout_version = 2;3621pub const packed_struct_layout_version = 2;
36043622
3605fn cTypeAlign(target: *const Target, c_type: Target.CType) Alignment {3623fn cTypeAlign(target: *const Target, c_type: Target.CType) Alignment {
3606 return Alignment.fromByteUnits(target.cTypeAlignment(c_type));3624 return .fromByteUnits(target.cTypeAlignment(c_type).?);
3607}3625}
src/Value.zig+1-6
...@@ -611,12 +611,7 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T {...@@ -611,12 +611,7 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T {
611 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {611 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
612 .int => |int| switch (int.storage) {612 .int => |int| switch (int.storage) {
613 .big_int => |big_int| big_int.toFloat(T, .nearest_even)[0],613 .big_int => |big_int| big_int.toFloat(T, .nearest_even)[0],
614 inline .u64, .i64 => |x| {614 inline .u64, .i64 => |x| @floatFromInt(x),
615 if (T == f80) {
616 @panic("TODO we can't lower this properly on non-x86 llvm backend yet");
617 }
618 return @floatFromInt(x);
619 },
620 },615 },
621 .float => |float| switch (float.storage) {616 .float => |float| switch (float.storage) {
622 inline else => |x| @floatCast(x),617 inline else => |x| @floatCast(x),
src/codegen/aarch64/Select.zig+1-1
...@@ -12388,7 +12388,7 @@ pub const CallAbiIterator = struct {...@@ -12388,7 +12388,7 @@ pub const CallAbiIterator = struct {
12388 .f32 => .single,12388 .f32 => .single,
12389 .f64 => .double,12389 .f64 => .double,
12390 .f128 => .quad,12390 .f128 => .quad,
12391 .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) {12391 .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble).?) {
12392 else => unreachable,12392 else => unreachable,
12393 64 => .double,12393 64 => .double,
12394 80 => null,12394 80 => null,
src/codegen/aarch64/abi.zig+6-1
...@@ -35,7 +35,12 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {...@@ -35,7 +35,12 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
35 if (bit_size > 64) return .double_integer;35 if (bit_size > 64) return .double_integer;
36 return .integer;36 return .integer;
37 },37 },
38 .int, .@"enum", .error_set, .float, .bool => return .byval,38 .int, .@"enum", .error_set, .bool => return .byval,
39 .float => return switch (ty.floatBits(zcu.getTarget())) {
40 else => unreachable,
41 16, 32, 64, 128 => .byval,
42 80 => .double_integer,
43 },
39 .vector => {44 .vector => {
40 const bit_size = ty.bitSize(zcu);45 const bit_size = ty.bitSize(zcu);
41 // TODO is this controlled by a cpu feature?46 // TODO is this controlled by a cpu feature?
src/codegen/arm/abi.zig+9-7
...@@ -39,7 +39,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {...@@ -39,7 +39,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
39 const float_count = countFloats(ty, zcu, &maybe_float_bits);39 const float_count = countFloats(ty, zcu, &maybe_float_bits);
40 if (float_count <= byval_float_count) return .byval;40 if (float_count <= byval_float_count) return .byval;
4141
42 if (ty.abiAlignment(zcu).compare(.gt, .@"32")) {42 if (ty.abiAlignment(zcu).compare(.gt, .@"4")) {
43 return Class.arrSize(bit_size, 64);43 return Class.arrSize(bit_size, 64);
44 }44 }
4545
...@@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {...@@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
62 const float_count = countFloats(ty, zcu, &maybe_float_bits);62 const float_count = countFloats(ty, zcu, &maybe_float_bits);
63 if (float_count <= byval_float_count) return .byval;63 if (float_count <= byval_float_count) return .byval;
6464
65 if (union_obj.alignment.compareStrict(.gt, .@"32")) {65 if (union_obj.alignment.compareStrict(.gt, .@"4")) {
66 return Class.arrSize(bit_size, 64);66 return Class.arrSize(bit_size, 64);
67 }67 }
6868
...@@ -73,14 +73,16 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {...@@ -73,14 +73,16 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
73 }73 }
74 return Class.arrSize(bit_size, 32);74 return Class.arrSize(bit_size, 32);
75 },75 },
76 .bool, .float => return .byval,76 .bool => return .byval,
77 .int => {77 .int => {
78 // TODO this is incorrect for _BitInt(128) but implementing78 if (ctx == .ret and ty.intInfo(zcu).bits > 64) return .memory;
79 // this correctly makes implementing compiler-rt impossible.
80 // const bit_size = ty.bitSize(zcu);
81 // if (bit_size > 64) return .memory;
82 return .byval;79 return .byval;
83 },80 },
81 .float => return switch (ty.floatBits(zcu.getTarget())) {
82 else => unreachable,
83 16, 32, 64 => .byval,
84 80, 128 => .{ .i64_array = 2 },
85 },
84 .@"enum", .error_set => {86 .@"enum", .error_set => {
85 const bit_size = ty.bitSize(zcu);87 const bit_size = ty.bitSize(zcu);
86 if (bit_size > 64) return .memory;88 if (bit_size > 64) return .memory;
src/codegen/c/type.zig+22-22
...@@ -130,28 +130,28 @@ pub const CType = union(enum) {...@@ -130,28 +130,28 @@ pub const CType = union(enum) {
130 pub fn bits(int: Int, target: *const std.Target) u16 {130 pub fn bits(int: Int, target: *const std.Target) u16 {
131 return switch (int) {131 return switch (int) {
132 // zig fmt: off132 // zig fmt: off
133 .char => target.cTypeBitSize(.char),133 .char => target.cTypeBitSize(.char).?,
134134
135 .@"unsigned short" => target.cTypeBitSize(.ushort),135 .@"unsigned short" => target.cTypeBitSize(.ushort).?,
136 .@"unsigned int" => target.cTypeBitSize(.uint),136 .@"unsigned int" => target.cTypeBitSize(.uint).?,
137 .@"unsigned long" => target.cTypeBitSize(.ulong),137 .@"unsigned long" => target.cTypeBitSize(.ulong).?,
138 .@"unsigned long long" => target.cTypeBitSize(.ulonglong),138 .@"unsigned long long" => target.cTypeBitSize(.ulonglong).?,
139139
140 .@"signed short" => target.cTypeBitSize(.short),140 .@"signed short" => target.cTypeBitSize(.short).?,
141 .@"signed int" => target.cTypeBitSize(.int),141 .@"signed int" => target.cTypeBitSize(.int).?,
142 .@"signed long" => target.cTypeBitSize(.long),142 .@"signed long" => target.cTypeBitSize(.long).?,
143 .@"signed long long" => target.cTypeBitSize(.longlong),143 .@"signed long long" => target.cTypeBitSize(.longlong).?,
144144
145 .uintptr_t, .intptr_t => target.ptrBitWidth(),145 .uintptr_t, .intptr_t => target.ptrBitWidth(),
146146
147 .uint8_t, .int8_t => 8,147 .uint8_t, .int8_t => 8,
148 .uint16_t, .int16_t => 16,148 .uint16_t, .int16_t => 16,
149 .uint24_t, .int24_t => 24,149 .uint24_t, .int24_t => 24,
150 .uint32_t, .int32_t => 32,150 .uint32_t, .int32_t => 32,
151 .uint48_t, .int48_t => 48,151 .uint48_t, .int48_t => 48,
152 .uint64_t, .int64_t => 64,152 .uint64_t, .int64_t => 64,
153 .zig_u128, .zig_i128 => 128,153 .zig_u128, .zig_i128 => 128,
154 // zig fmt: on154 // zig fmt: on
155 };155 };
156 }156 }
157 };157 };
src/codegen/c/type/render_defs.zig+14-12
...@@ -381,7 +381,7 @@ fn defineTuple(...@@ -381,7 +381,7 @@ fn defineTuple(
381 const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| {381 const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| {
382 const field_ty: Type = .fromInterned(field_ty_ip);382 const field_ty: Type = .fromInterned(field_ty_ip);
383 if (!field_ty.hasRuntimeBits(zcu)) continue;383 if (!field_ty.hasRuntimeBits(zcu)) continue;
384 const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu);384 const natural_align = field_ty.abiAlignment(zcu);
385 if (natural_align.compareStrict(.gte, tuple_align)) break false;385 if (natural_align.compareStrict(.gte, tuple_align)) break false;
386 } else true;386 } else true;
387387
...@@ -402,15 +402,17 @@ fn defineTuple(...@@ -402,15 +402,17 @@ fn defineTuple(
402 if (zig_offset == 0 and overalign) {402 if (zig_offset == 0 and overalign) {
403 // This is the first field; specify its alignment to align the tuple.403 // This is the first field; specify its alignment to align the tuple.
404 try writeFieldAlign(field_ty, tuple_align, w, zcu);404 try writeFieldAlign(field_ty, tuple_align, w, zcu);
405 } else if (zig_offset > c_offset) {405 } else switch (zig_offset - c_offset) {
406 // This field needs to be overaligned compared to what its offset would otherwise be.406 0 => {},
407 const need_align: Alignment = .minStrict(407 else => |need_bytes| {
408 tuple_align, // don't make the struct more aligned than it should be408 // This field needs to be overaligned compared to what its offset would otherwise be.
409 .fromLog2Units(@ctz(zig_offset)),409 const need_align: Alignment = .fromLog2Units(std.math.log2_int(u64, need_bytes) + 1);
410 );410 assert(need_align.compareStrict(.lte, tuple_align));
411 try writeFieldAlign(field_ty, need_align, w, zcu);411 try writeFieldAlign(field_ty, need_align, w, zcu);
412 c_offset = need_align.forward(c_offset);412 c_offset = need_align.forward(c_offset);
413 },
413 }414 }
415 assert(c_offset == zig_offset);
414 const field_cty: CType = try .lower(field_ty, deps, arena, zcu);416 const field_cty: CType = try .lower(field_ty, deps, arena, zcu);
415 try w.print("{f}f{d}{f};\n", .{417 try w.print("{f}f{d}{f};\n", .{
416 field_cty.fmtDeclaratorPrefix(zcu),418 field_cty.fmtDeclaratorPrefix(zcu),
...@@ -443,7 +445,7 @@ fn defineStruct(...@@ -443,7 +445,7 @@ fn defineStruct(
443 while (it.next()) |field_index| {445 while (it.next()) |field_index| {
444 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);446 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
445 if (!field_ty.hasRuntimeBits(zcu)) continue;447 if (!field_ty.hasRuntimeBits(zcu)) continue;
446 const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu);448 const natural_align = field_ty.abiAlignment(zcu);
447 const natural_offset = natural_align.forward(offset);449 const natural_offset = natural_align.forward(offset);
448 const actual_offset = struct_type.field_offsets.get(ip)[field_index];450 const actual_offset = struct_type.field_offsets.get(ip)[field_index];
449 if (actual_offset < natural_offset) break :pack true;451 if (actual_offset < natural_offset) break :pack true;
...@@ -464,7 +466,7 @@ fn defineStruct(...@@ -464,7 +466,7 @@ fn defineStruct(
464 while (it.next()) |field_index| {466 while (it.next()) |field_index| {
465 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);467 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
466 if (!field_ty.hasRuntimeBits(zcu)) continue;468 if (!field_ty.hasRuntimeBits(zcu)) continue;
467 const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu);469 const natural_align = field_ty.abiAlignment(zcu);
468 if (natural_align.compareStrict(.gte, struct_type.alignment)) break :overalign false;470 if (natural_align.compareStrict(.gte, struct_type.alignment)) break :overalign false;
469 }471 }
470 break :overalign true;472 break :overalign true;
...@@ -481,7 +483,7 @@ fn defineStruct(...@@ -481,7 +483,7 @@ fn defineStruct(
481 while (it.next()) |field_index| {483 while (it.next()) |field_index| {
482 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);484 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
483 if (!field_ty.hasRuntimeBits(zcu)) continue;485 if (!field_ty.hasRuntimeBits(zcu)) continue;
484 const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu);486 const natural_align = field_ty.abiAlignment(zcu);
485 const natural_offset = switch (pack) {487 const natural_offset = switch (pack) {
486 true => offset,488 true => offset,
487 false => natural_align.forward(offset),489 false => natural_align.forward(offset),
src/codegen/llvm.zig+608-316
...@@ -573,6 +573,8 @@ pub const Object = struct {...@@ -573,6 +573,8 @@ pub const Object = struct {
573 val: InternPool.Index,573 val: InternPool.Index,
574 @"addrspace": std.lang.AddressSpace,574 @"addrspace": std.lang.AddressSpace,
575 }, Builder.Variable.Index),575 }, Builder.Variable.Index),
576 /// Same as `uav_map` but for llvm values not originating from the frontend.
577 const_map: std.AutoHashMapUnmanaged(Builder.Constant, Builder.Variable.Index),
576 /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction.578 /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction.
577 enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),579 enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index),
578 /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction.580 /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction.
...@@ -693,6 +695,7 @@ pub const Object = struct {...@@ -693,6 +695,7 @@ pub const Object = struct {
693 .zcu = zcu,695 .zcu = zcu,
694 .nav_map = .empty,696 .nav_map = .empty,
695 .uav_map = .empty,697 .uav_map = .empty,
698 .const_map = .empty,
696 .enum_tag_name_map = .empty,699 .enum_tag_name_map = .empty,
697 .named_enum_map = .empty,700 .named_enum_map = .empty,
698 .type_map = .empty,701 .type_map = .empty,
...@@ -703,21 +706,22 @@ pub const Object = struct {...@@ -703,21 +706,22 @@ pub const Object = struct {
703 return obj;706 return obj;
704 }707 }
705708
706 pub fn deinit(self: *Object) void {709 pub fn deinit(o: *Object) void {
707 const gpa = self.gpa;710 const gpa = o.gpa;
708 self.type_pool.deinit(gpa);711 o.type_pool.deinit(gpa);
709 self.lazy_abi_aligns.deinit(gpa);712 o.lazy_abi_aligns.deinit(gpa);
710 self.debug_enums.deinit(gpa);713 o.debug_enums.deinit(gpa);
711 self.debug_globals.deinit(gpa);714 o.debug_globals.deinit(gpa);
712 self.debug_file_map.deinit(gpa);715 o.debug_file_map.deinit(gpa);
713 self.debug_types.deinit(gpa);716 o.debug_types.deinit(gpa);
714 self.nav_map.deinit(gpa);717 o.nav_map.deinit(gpa);
715 self.uav_map.deinit(gpa);718 o.uav_map.deinit(gpa);
716 self.enum_tag_name_map.deinit(gpa);719 o.const_map.deinit(gpa);
717 self.named_enum_map.deinit(gpa);720 o.enum_tag_name_map.deinit(gpa);
718 self.type_map.deinit(gpa);721 o.named_enum_map.deinit(gpa);
719 self.builder.deinit();722 o.type_map.deinit(gpa);
720 self.* = undefined;723 o.builder.deinit();
724 o.* = undefined;
721 }725 }
722726
723 fn genErrorNameTable(o: *Object) Allocator.Error!void {727 fn genErrorNameTable(o: *Object) Allocator.Error!void {
...@@ -741,16 +745,16 @@ pub const Object = struct {...@@ -741,16 +745,16 @@ pub const Object = struct {
741 for (llvm_errors[1..], error_name_list) |*llvm_error, name| {745 for (llvm_errors[1..], error_name_list) |*llvm_error, name| {
742 const name_string = try o.builder.stringNull(name.toSlice(ip));746 const name_string = try o.builder.stringNull(name.toSlice(ip));
743 const name_init = try o.builder.stringConst(name_string);747 const name_init = try o.builder.stringConst(name_string);
744 const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);748 const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
745 try name_variable_index.setInitializer(name_init, &o.builder);749 try name_llvm_variable.setInitializer(name_init, &o.builder);
746 name_variable_index.setMutability(.constant, &o.builder);750 name_llvm_variable.setMutability(.constant, &o.builder);
747 name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder);751 name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder);
748 const global_index = name_variable_index.ptrConst(&o.builder).global;752 const llvm_global = name_llvm_variable.ptrConst(&o.builder).global;
749 global_index.setLinkage(.private, &o.builder);753 llvm_global.setLinkage(.private, &o.builder);
750 global_index.setUnnamedAddr(.unnamed_addr, &o.builder);754 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
751755
752 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{756 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
753 name_variable_index.toConst(&o.builder),757 name_llvm_variable.toConst(&o.builder),
754 try o.builder.intConst(llvm_usize_ty, name_string.slice(&o.builder).?.len - 1),758 try o.builder.intConst(llvm_usize_ty, name_string.slice(&o.builder).?.len - 1),
755 });759 });
756 }760 }
...@@ -1199,19 +1203,33 @@ pub const Object = struct {...@@ -1199,19 +1203,33 @@ pub const Object = struct {
1199 global.dll_storage_class = .default;1203 global.dll_storage_class = .default;
1200 global.unnamed_addr = .unnamed_addr;1204 global.unnamed_addr = .unnamed_addr;
1201 }1205 }
1202 llvm_function.setAlignment(switch (nav.resolved.?.@"align") {1206 llvm_function.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder);
1203 .none => fn_ty.abiAlignment(zcu).toLlvm(),
1204 else => |a| a.toLlvm(),
1205 }, &o.builder);
1206 llvm_function.setSection(s: {1207 llvm_function.setSection(s: {
1207 const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none;1208 const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none;
1208 break :s try o.builder.string(section);1209 break :s try o.builder.string(section);
1209 }, &o.builder);1210 }, &o.builder);
1210 try o.addLlvmFunctionAttributes(pt, func.owner_nav, llvm_function);
12111211
1212 var attributes = try llvm_function.ptrConst(&o.builder).attributes.toWip(&o.builder);1212 var attributes: Builder.FunctionAttributes.Wip = .{};
1213 defer attributes.deinit(&o.builder);1213 defer attributes.deinit(&o.builder);
12141214
1215 // Function attributes that are independent of analysis results of the function body.
1216 try o.addCommonFnAttributes(
1217 &attributes,
1218 owner_mod,
1219 // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`,
1220 // so for these backends, LLVM will happily emit code that accesses the stack through
1221 // the frame pointer. This is nonsensical since what the `naked` attribute does is
1222 // suppress generation of the prologue and epilogue, and the prologue is where the
1223 // frame pointer normally gets set up. At time of writing, this is the case for at
1224 // least x86 and RISC-V.
1225 owner_mod.omit_frame_pointer or fn_info.cc == .naked,
1226 );
1227
1228 try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, if (nav.getExtern(ip)) |@"extern"| .{
1229 .name = nav.name.toSlice(ip),
1230 .lib_name = @"extern".lib_name.toSlice(ip),
1231 } else null, .fromIntern(fn_info, ip));
1232
1215 const func_analysis = func.analysisUnordered(ip);1233 const func_analysis = func.analysisUnordered(ip);
1216 if (func_analysis.is_noinline) {1234 if (func_analysis.is_noinline) {
1217 try attributes.addFnAttr(.@"noinline", &o.builder);1235 try attributes.addFnAttr(.@"noinline", &o.builder);
...@@ -1324,7 +1342,7 @@ pub const Object = struct {...@@ -1324,7 +1342,7 @@ pub const Object = struct {
1324 const counters_variable = try o.builder.addVariable(anon_name, .void, .default);1342 const counters_variable = try o.builder.addVariable(anon_name, .void, .default);
1325 try o.used.append(gpa, counters_variable.toConst(&o.builder));1343 try o.used.append(gpa, counters_variable.toConst(&o.builder));
1326 counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder);1344 counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder);
1327 counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);1345 counters_variable.setAlignment(comptime .fromByteUnits(1), &o.builder);
13281346
1329 if (target.ofmt == .macho) {1347 if (target.ofmt == .macho) {
1330 counters_variable.setSection(try o.builder.string("__DATA,__sancov_cntrs"), &o.builder);1348 counters_variable.setSection(try o.builder.string("__DATA,__sancov_cntrs"), &o.builder);
...@@ -1507,10 +1525,6 @@ pub const Object = struct {...@@ -1507,10 +1525,6 @@ pub const Object = struct {
1507 llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr;1525 llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr;
1508 }1526 }
15091527
1510 const llvm_align = switch (resolved.@"align") {
1511 .none => nav_ty.abiAlignment(zcu).toLlvm(),
1512 else => |a| a.toLlvm(),
1513 };
1514 const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: {1528 const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: {
1515 break :s try o.builder.string(section);1529 break :s try o.builder.string(section);
1516 } else .none;1530 } else .none;
...@@ -1519,13 +1533,20 @@ pub const Object = struct {...@@ -1519,13 +1533,20 @@ pub const Object = struct {
1519 // can see are extern functions or other comptime function body values (e.g. undefined). Of1533 // can see are extern functions or other comptime function body values (e.g. undefined). Of
1520 // these, only extern functions need to be lowered to LLVM functions.1534 // these, only extern functions need to be lowered to LLVM functions.
1521 if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) {1535 if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) {
1536 const fn_info = zcu.typeToFunc(nav_ty).?;
1522 const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) {1537 const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) {
1523 .function => |function| function, // re-use existing `Builder.Function`1538 .function => |function| function, // re-use existing `Builder.Function`
1524 .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder),1539 .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder),
1525 };1540 };
1526 llvm_function.setAlignment(llvm_align, &o.builder);1541 llvm_function.setAlignment(resolved.@"align".toLlvm(), &o.builder);
1527 llvm_function.setSection(llvm_section, &o.builder);1542 llvm_function.setSection(llvm_section, &o.builder);
1528 try o.addLlvmFunctionAttributes(pt, nav_id, llvm_function);1543 var attributes: Builder.FunctionAttributes.Wip = .{};
1544 defer attributes.deinit(&o.builder);
1545 try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{
1546 .name = nav.name.toSlice(ip),
1547 .lib_name = opt_extern.?.lib_name.toSlice(ip),
1548 }, .fromIntern(fn_info, ip));
1549 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
1529 } else {1550 } else {
1530 const file_scope = nav.srcInst(ip).resolveFile(ip);1551 const file_scope = nav.srcInst(ip).resolveFile(ip);
1531 const mod = zcu.fileByIndex(file_scope).mod.?;1552 const mod = zcu.fileByIndex(file_scope).mod.?;
...@@ -1534,7 +1555,10 @@ pub const Object = struct {...@@ -1534,7 +1555,10 @@ pub const Object = struct {
1534 .variable => |variable| variable, // re-use existing `Builder.Variable`1555 .variable => |variable| variable, // re-use existing `Builder.Variable`
1535 .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder),1556 .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder),
1536 };1557 };
1537 llvm_variable.setAlignment(llvm_align, &o.builder);1558 llvm_variable.setAlignment(switch (resolved.@"align") {
1559 .none => nav_ty.abiAlignment(zcu).toLlvm(),
1560 else => |a| a.toLlvm(),
1561 }, &o.builder);
1538 llvm_variable.setSection(llvm_section, &o.builder);1562 llvm_variable.setSection(llvm_section, &o.builder);
1539 llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder);1563 llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder);
1540 try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value, .in_memory), &o.builder);1564 try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value, .in_memory), &o.builder);
...@@ -1585,7 +1609,7 @@ pub const Object = struct {...@@ -1585,7 +1609,7 @@ pub const Object = struct {
1585 const uav_ty = Value.fromInterned(uav).typeOf(zcu);1609 const uav_ty = Value.fromInterned(uav).typeOf(zcu);
1586 const uav_ref = try o.lowerUavRef(1610 const uav_ref = try o.lowerUavRef(
1587 uav,1611 uav,
1588 uav_ty.abiAlignment(zcu),1612 uav_ty.abiAlignment(zcu).toLlvm(),
1589 target_util.defaultAddressSpace(zcu.getTarget(), .global_constant),1613 target_util.defaultAddressSpace(zcu.getTarget(), .global_constant),
1590 );1614 );
1591 break :exp .{ uav_ty, uav_ref };1615 break :exp .{ uav_ty, uav_ref };
...@@ -1599,7 +1623,7 @@ pub const Object = struct {...@@ -1599,7 +1623,7 @@ pub const Object = struct {
15991623
1600 fn updateExportedGlobal(1624 fn updateExportedGlobal(
1601 o: *Object,1625 o: *Object,
1602 global_index: Builder.Global.Index,1626 llvm_global: Builder.Global.Index,
1603 ty: Type,1627 ty: Type,
1604 export_indices: []const Zcu.Export.Index,1628 export_indices: []const Zcu.Export.Index,
1605 ) link.Error!void {1629 ) link.Error!void {
...@@ -1634,11 +1658,11 @@ pub const Object = struct {...@@ -1634,11 +1658,11 @@ pub const Object = struct {
1634 // make much sense: the linksection should be associated with the declaration itself rather1658 // make much sense: the linksection should be associated with the declaration itself rather
1635 // than some particular symbol it is exported as!1659 // than some particular symbol it is exported as!
1636 if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| {1660 if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| {
1637 const variable = &global_index.ptrConst(&o.builder).kind.variable;1661 const variable = &llvm_global.ptrConst(&o.builder).kind.variable;
1638 variable.setSection(try o.builder.string(section_slice), &o.builder);1662 variable.setSection(try o.builder.string(section_slice), &o.builder);
1639 }1663 }
16401664
1641 const llvm_global_ty = global_index.typeOf(&o.builder);1665 const llvm_global_ty = llvm_global.typeOf(&o.builder);
16421666
1643 // All exports are represented as aliases to the original global.1667 // All exports are represented as aliases to the original global.
16441668
...@@ -1661,8 +1685,8 @@ pub const Object = struct {...@@ -1661,8 +1685,8 @@ pub const Object = struct {
1661 const alias = try o.builder.addAlias(1685 const alias = try o.builder.addAlias(
1662 exp_name,1686 exp_name,
1663 llvm_global_ty,1687 llvm_global_ty,
1664 global_index.ptrConst(&o.builder).addr_space,1688 llvm_global.ptrConst(&o.builder).addr_space,
1665 global_index.toConst(),1689 llvm_global.toConst(),
1666 );1690 );
1667 break :global alias.ptrConst(&o.builder).global;1691 break :global alias.ptrConst(&o.builder).global;
1668 };1692 };
...@@ -1671,12 +1695,9 @@ pub const Object = struct {...@@ -1671,12 +1695,9 @@ pub const Object = struct {
1671 switch (existing_global.ptrConst(&o.builder).kind) {1695 switch (existing_global.ptrConst(&o.builder).kind) {
1672 .alias => |alias| {1696 .alias => |alias| {
1673 // We can just repurpose the existing alias.1697 // We can just repurpose the existing alias.
1674 alias.setAliasee(global_index.toConst(), &o.builder);1698 alias.setAliasee(llvm_global.toConst(), &o.builder);
1675 alias.ptrConst(&o.builder).global.ptr(&o.builder).type = global_index.typeOf(&o.builder);1699 alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global.typeOf(&o.builder);
1676 // If the type the alias is pointing to can change, then1700 alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space;
1677 // it makes sense that we should update the address
1678 // space too.
1679 alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = global_index.ptrConst(&o.builder).addr_space;
1680 break :global existing_global;1701 break :global existing_global;
1681 },1702 },
1682 .variable, .function => {1703 .variable, .function => {
...@@ -1686,13 +1707,13 @@ pub const Object = struct {...@@ -1686,13 +1707,13 @@ pub const Object = struct {
1686 // We need to make a new global which is an alias. Replace this existing one1707 // We need to make a new global which is an alias. Replace this existing one
1687 // with the target global, making the name available and fixing references1708 // with the target global, making the name available and fixing references
1688 // to this global to point to the target.1709 // to this global to point to the target.
1689 try existing_global.replace(global_index, &o.builder);1710 try existing_global.replace(llvm_global, &o.builder);
1690 // The name is now free, so create an alias.1711 // The name is now free, so create an alias.
1691 const alias = try o.builder.addAlias(1712 const alias = try o.builder.addAlias(
1692 exp_name,1713 exp_name,
1693 llvm_global_ty,1714 llvm_global_ty,
1694 global_index.ptrConst(&o.builder).addr_space,1715 llvm_global.ptrConst(&o.builder).addr_space,
1695 global_index.toConst(),1716 llvm_global.toConst(),
1696 );1717 );
1697 break :global alias.ptrConst(&o.builder).global;1718 break :global alias.ptrConst(&o.builder).global;
1698 },1719 },
...@@ -1725,11 +1746,11 @@ pub const Object = struct {...@@ -1725,11 +1746,11 @@ pub const Object = struct {
1725 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {1746 pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {
1726 _ = o.type_map.remove(ty);1747 _ = o.type_map.remove(ty);
1727 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);1748 try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
1728 if (o.named_enum_map.get(ty)) |function_index| {1749 if (o.named_enum_map.get(ty)) |llvm_function| {
1729 try o.updateIsNamedEnumValueFunction(.fromInterned(ty), function_index);1750 try o.updateIsNamedEnumValueFunction(.fromInterned(ty), llvm_function);
1730 }1751 }
1731 if (o.enum_tag_name_map.get(ty)) |function_index| {1752 if (o.enum_tag_name_map.get(ty)) |llvm_function| {
1732 try o.updateEnumTagNameFunction(.fromInterned(ty), function_index);1753 try o.updateEnumTagNameFunction(.fromInterned(ty), llvm_function);
1733 }1754 }
1734 }1755 }
17351756
...@@ -2102,7 +2123,7 @@ pub const Object = struct {...@@ -2102,7 +2123,7 @@ pub const Object = struct {
2102 payload_offset * 8,2123 payload_offset * 8,
2103 );2124 );
21042125
2105 return try o.builder.debugStructType(2126 return o.builder.debugStructType(
2106 name,2127 name,
2107 null, // File2128 null, // File
2108 o.debug_compile_unit.unwrap().?, // Scope2129 o.debug_compile_unit.unwrap().?, // Scope
...@@ -2140,7 +2161,7 @@ pub const Object = struct {...@@ -2140,7 +2161,7 @@ pub const Object = struct {
2140 defer debug_param_types.deinit(gpa);2161 defer debug_param_types.deinit(gpa);
21412162
2142 // Return type goes first.2163 // Return type goes first.
2143 if (try fnReturnStrat(o, fn_info) == .sret) {2164 if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) {
2144 // Actual return type is void, then first arg is the sret pointer.2165 // Actual return type is void, then first arg is the sret pointer.
2145 const ptr_ty = try pt.singleMutPtrType(.fromInterned(fn_info.return_type));2166 const ptr_ty = try pt.singleMutPtrType(.fromInterned(fn_info.return_type));
2146 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .void));2167 debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .void));
...@@ -2575,50 +2596,114 @@ pub const Object = struct {...@@ -2575,50 +2596,114 @@ pub const Object = struct {
2575 fn namespaceToDebugScope(o: *Object, pt: Zcu.PerThread, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata {2596 fn namespaceToDebugScope(o: *Object, pt: Zcu.PerThread, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata {
2576 const zcu = o.zcu;2597 const zcu = o.zcu;
2577 const namespace = zcu.namespacePtr(namespace_index);2598 const namespace = zcu.namespacePtr(namespace_index);
2578 if (namespace.parent == .none) return try o.getDebugFile(namespace.file_scope);2599 if (namespace.parent == .none) return o.getDebugFile(namespace.file_scope);
2579 return o.getDebugType(pt, .fromInterned(namespace.owner_type));2600 return o.getDebugType(pt, .fromInterned(namespace.owner_type));
2580 }2601 }
25812602
2582 /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the2603 fn addCommonFnAttributes(
2583 /// given `Nav` (which is a function).2604 o: *Object,
2584 fn addLlvmFunctionAttributes(2605 attributes: *Builder.FunctionAttributes.Wip,
2606 owner_mod: *Module,
2607 omit_frame_pointer: bool,
2608 ) Allocator.Error!void {
2609 if (!owner_mod.red_zone) {
2610 try attributes.addFnAttr(.noredzone, &o.builder);
2611 }
2612 if (omit_frame_pointer) {
2613 try attributes.addFnAttr(.{ .string = .{
2614 .kind = try o.builder.string("frame-pointer"),
2615 .value = try o.builder.string("none"),
2616 } }, &o.builder);
2617 } else {
2618 try attributes.addFnAttr(.{ .string = .{
2619 .kind = try o.builder.string("frame-pointer"),
2620 .value = try o.builder.string("all"),
2621 } }, &o.builder);
2622 }
2623 try attributes.addFnAttr(.nounwind, &o.builder);
2624 if (owner_mod.unwind_tables != .none) {
2625 try attributes.addFnAttr(
2626 .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync },
2627 &o.builder,
2628 );
2629 }
2630 if (owner_mod.optimize_mode == .small) {
2631 try attributes.addFnAttr(.minsize, &o.builder);
2632 try attributes.addFnAttr(.optsize, &o.builder);
2633 }
2634 const target = &owner_mod.resolved_target.result;
2635 if (target.cpu.model.llvm_name) |s| {
2636 try attributes.addFnAttr(.{ .string = .{
2637 .kind = try o.builder.string("target-cpu"),
2638 .value = try o.builder.string(s),
2639 } }, &o.builder);
2640 }
2641 if (owner_mod.resolved_target.llvm_cpu_features) |s| {
2642 try attributes.addFnAttr(.{ .string = .{
2643 .kind = try o.builder.string("target-features"),
2644 .value = try o.builder.string(std.mem.span(s)),
2645 } }, &o.builder);
2646 }
2647 if (target.abi.float() == .soft) {
2648 // `use-soft-float` means "use software routines for floating point computations". In
2649 // other words, it configures how LLVM lowers basic float instructions like `fcmp`,
2650 // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is
2651 // mostly an orthogonal concept, although obviously we do need hardware float operations
2652 // to actually be able to pass float values in float registers.
2653 //
2654 // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC
2655 // and Clang support for Arm32 and CSKY. We don't currently expose such an option in
2656 // Zig, and using CPU features as the source of truth for this makes for a miserable
2657 // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float
2658 // unless the compiler has explicitly been told otherwise. (And note that our baseline
2659 // CPU models almost all include FPU features!)
2660 //
2661 // Revisit this at some point.
2662 try attributes.addFnAttr(.{ .string = .{
2663 .kind = try o.builder.string("use-soft-float"),
2664 .value = try o.builder.string("true"),
2665 } }, &o.builder);
2666
2667 // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the
2668 // above, this should be revisited if `softfp` support is added.
2669 try attributes.addFnAttr(.noimplicitfloat, &o.builder);
2670 }
2671 }
2672
2673 pub fn addCallingConventionFnAttributes(
2585 o: *Object,2674 o: *Object,
2586 pt: Zcu.PerThread,2675 pt: Zcu.PerThread,
2587 nav_id: InternPool.Nav.Index,2676 llvm_function: Builder.Function.Index,
2588 function_index: Builder.Function.Index,2677 attributes: *Builder.FunctionAttributes.Wip,
2678 opt_extern: ?struct {
2679 name: []const u8,
2680 lib_name: ?[]const u8 = null,
2681 },
2682 fn_info: FuncInfo,
2589 ) Allocator.Error!void {2683 ) Allocator.Error!void {
2590 const zcu = o.zcu;2684 const zcu = o.zcu;
2591 const ip = &zcu.intern_pool;2685 const target = zcu.getTarget();
2592 const nav = ip.getNav(nav_id);
2593 const owner_mod = zcu.navFileScope(nav_id).mod.?;
2594 const ty: Type = .fromInterned(nav.resolved.?.type);
2595
2596 const fn_info = zcu.typeToFunc(ty).?;
2597 const target = &owner_mod.resolved_target.result;
25982686
2599 var attributes: Builder.FunctionAttributes.Wip = .{};2687 if (fn_info.cc == .async) {
2600 defer attributes.deinit(&o.builder);2688 @panic("TODO: LLVM backend lower async function");
2689 }
26012690
2602 if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| {2691 if (target.cpu.arch.isWasm()) if (opt_extern) |@"extern"| {
2603 try attributes.addFnAttr(.{ .string = .{2692 try attributes.addFnAttr(.{ .string = .{
2604 .kind = try o.builder.string("wasm-import-name"),2693 .kind = try o.builder.string("wasm-import-name"),
2605 .value = try o.builder.string(nav.name.toSlice(ip)),2694 .value = try o.builder.string(@"extern".name),
2606 } }, &o.builder);2695 } }, &o.builder);
2607 if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| {2696 if (@"extern".lib_name) |lib_name| {
2608 if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{2697 if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{
2609 .kind = try o.builder.string("wasm-import-module"),2698 .kind = try o.builder.string("wasm-import-module"),
2610 .value = try o.builder.string(lib_name_slice),2699 .value = try o.builder.string(lib_name),
2611 } }, &o.builder);2700 } }, &o.builder);
2612 }2701 }
2613 };2702 };
26142703
2615 if (fn_info.cc == .async) {
2616 @panic("TODO: LLVM backend lower async function");
2617 }
2618
2619 const cc_info = toLlvmCallConv(fn_info.cc, target).?;2704 const cc_info = toLlvmCallConv(fn_info.cc, target).?;
26202705
2621 function_index.setCallConv(cc_info.llvm_cc, &o.builder);2706 llvm_function.setCallConv(cc_info.llvm_cc, &o.builder);
26222707
2623 if (cc_info.align_stack) {2708 if (cc_info.align_stack) {
2624 try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder);2709 try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder);
...@@ -2672,29 +2757,16 @@ pub const Object = struct {...@@ -2672,29 +2757,16 @@ pub const Object = struct {
2672 else => {},2757 else => {},
2673 }2758 }
26742759
2675 // Function attributes that are independent of analysis results of the function body.
2676 try o.addCommonFnAttributes(
2677 &attributes,
2678 owner_mod,
2679 // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`,
2680 // so for these backends, LLVM will happily emit code that accesses the stack through
2681 // the frame pointer. This is nonsensical since what the `naked` attribute does is
2682 // suppress generation of the prologue and epilogue, and the prologue is where the
2683 // frame pointer normally gets set up. At time of writing, this is the case for at
2684 // least x86 and RISC-V.
2685 owner_mod.omit_frame_pointer or fn_info.cc == .naked,
2686 );
2687
2688 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);2760 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
26892761
2690 var it = iterateParamTypes(o, fn_info);2762 var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types);
2691 if (try fnReturnStrat(o, fn_info) == .sret) {2763 if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) {
2692 // Sret pointers must not be address 02764 try o.addSRetFnAttributes(
2693 try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder);2765 attributes,
2694 try attributes.addParamAttr(it.llvm_index, .@"noalias", &o.builder);2766 try o.lowerType(.fromInterned(fn_info.return_type), .in_memory),
26952767 Type.fromInterned(fn_info.return_type).abiAlignment(zcu).toLlvm(),
2696 const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type), .in_memory);2768 .declaration,
2697 try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder);2769 );
2698 it.llvm_index += 1;2770 it.llvm_index += 1;
2699 } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {2771 } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
2700 .signed => try attributes.addRetAttr(.signext, &o.builder),2772 .signed => try attributes.addRetAttr(.signext, &o.builder),
...@@ -2713,9 +2785,9 @@ pub const Object = struct {...@@ -2713,9 +2785,9 @@ pub const Object = struct {
2713 while (try it.next()) |lowering| switch (lowering) {2785 while (try it.next()) |lowering| switch (lowering) {
2714 .byval => {2786 .byval => {
2715 const param_index = it.zig_index - 1;2787 const param_index = it.zig_index - 1;
2716 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]);2788 const param_ty: Type = .fromInterned(fn_info.param_types[param_index]);
2717 if (!isByRef(param_ty, zcu)) {2789 if (!isByRef(param_ty, zcu)) {
2718 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);2790 try o.addByValParamAttrs(pt, attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
2719 }2791 }
27202792
2721 if (remaining_inreg_int > 0 and2793 if (remaining_inreg_int > 0 and
...@@ -2734,12 +2806,12 @@ pub const Object = struct {...@@ -2734,12 +2806,12 @@ pub const Object = struct {
2734 }2806 }
2735 },2807 },
2736 .byref => {2808 .byref => {
2737 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);2809 const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]);
2738 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty);2810 try o.addByRefParamAttrs(attributes, it.llvm_index - 1, it.byval_attr, param_ty);
2739 },2811 },
2740 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),2812 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
2741 .slice => {2813 .slice => {
2742 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);2814 const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]);
2743 const ptr_info = param_ty.ptrInfo(zcu);2815 const ptr_info = param_ty.ptrInfo(zcu);
2744 const llvm_ptr_index = it.llvm_index - 2;2816 const llvm_ptr_index = it.llvm_index - 2;
2745 if (std.math.cast(u5, it.zig_index - 1)) |i| {2817 if (std.math.cast(u5, it.zig_index - 1)) |i| {
...@@ -2771,78 +2843,24 @@ pub const Object = struct {...@@ -2771,78 +2843,24 @@ pub const Object = struct {
2771 .i64_array,2843 .i64_array,
2772 => continue,2844 => continue,
2773 };2845 };
2774
2775 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
2776 }2846 }
27772847
2778 fn addCommonFnAttributes(2848 pub fn addSRetFnAttributes(
2779 o: *Object,2849 o: *Object,
2780 attributes: *Builder.FunctionAttributes.Wip,2850 attributes: *Builder.FunctionAttributes.Wip,
2781 owner_mod: *Module,2851 ret_ty: Builder.Type,
2782 omit_frame_pointer: bool,2852 ret_align: Builder.Alignment,
2853 location: enum { declaration, callsite },
2783 ) Allocator.Error!void {2854 ) Allocator.Error!void {
2784 if (!owner_mod.red_zone) {2855 try attributes.addParamAttr(0, .dead_on_unwind, &o.builder);
2785 try attributes.addFnAttr(.noredzone, &o.builder);2856 switch (location) {
2786 }2857 .declaration => try attributes.addParamAttr(0, .@"noalias", &o.builder),
2787 if (omit_frame_pointer) {2858 .callsite => {},
2788 try attributes.addFnAttr(.{ .string = .{
2789 .kind = try o.builder.string("frame-pointer"),
2790 .value = try o.builder.string("none"),
2791 } }, &o.builder);
2792 } else {
2793 try attributes.addFnAttr(.{ .string = .{
2794 .kind = try o.builder.string("frame-pointer"),
2795 .value = try o.builder.string("all"),
2796 } }, &o.builder);
2797 }
2798 try attributes.addFnAttr(.nounwind, &o.builder);
2799 if (owner_mod.unwind_tables != .none) {
2800 try attributes.addFnAttr(
2801 .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync },
2802 &o.builder,
2803 );
2804 }
2805 if (owner_mod.optimize_mode == .small) {
2806 try attributes.addFnAttr(.minsize, &o.builder);
2807 try attributes.addFnAttr(.optsize, &o.builder);
2808 }
2809 const target = &owner_mod.resolved_target.result;
2810 if (target.cpu.model.llvm_name) |s| {
2811 try attributes.addFnAttr(.{ .string = .{
2812 .kind = try o.builder.string("target-cpu"),
2813 .value = try o.builder.string(s),
2814 } }, &o.builder);
2815 }
2816 if (owner_mod.resolved_target.llvm_cpu_features) |s| {
2817 try attributes.addFnAttr(.{ .string = .{
2818 .kind = try o.builder.string("target-features"),
2819 .value = try o.builder.string(std.mem.span(s)),
2820 } }, &o.builder);
2821 }
2822 if (target.abi.float() == .soft) {
2823 // `use-soft-float` means "use software routines for floating point computations". In
2824 // other words, it configures how LLVM lowers basic float instructions like `fcmp`,
2825 // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is
2826 // mostly an orthogonal concept, although obviously we do need hardware float operations
2827 // to actually be able to pass float values in float registers.
2828 //
2829 // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC
2830 // and Clang support for Arm32 and CSKY. We don't currently expose such an option in
2831 // Zig, and using CPU features as the source of truth for this makes for a miserable
2832 // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float
2833 // unless the compiler has explicitly been told otherwise. (And note that our baseline
2834 // CPU models almost all include FPU features!)
2835 //
2836 // Revisit this at some point.
2837 try attributes.addFnAttr(.{ .string = .{
2838 .kind = try o.builder.string("use-soft-float"),
2839 .value = try o.builder.string("true"),
2840 } }, &o.builder);
2841
2842 // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the
2843 // above, this should be revisited if `softfp` support is added.
2844 try attributes.addFnAttr(.noimplicitfloat, &o.builder);
2845 }2859 }
2860 try attributes.addParamAttr(0, .writeonly, &o.builder);
2861 try attributes.addParamAttr(0, .{ .captures = .none }, &o.builder);
2862 try attributes.addParamAttr(0, .{ .sret = ret_ty }, &o.builder);
2863 try attributes.addParamAttr(0, .{ .@"align" = .wrap(ret_align) }, &o.builder);
2846 }2864 }
28472865
2848 pub const TypeRepr = enum {2866 pub const TypeRepr = enum {
...@@ -2861,6 +2879,151 @@ pub const Object = struct {...@@ -2861,6 +2879,151 @@ pub const Object = struct {
2861 });2879 });
2862 }2880 }
28632881
2882 pub const SoftF80Layout = struct {
2883 alignment: InternPool.Alignment,
2884 /// byte offset of u64 field
2885 mantissa_offset: u64,
2886 /// byte offset of u16 field
2887 exponent_offset: u64,
2888 llvm_fields_len: u32,
2889
2890 pub const LlvmFieldTag = enum { mantissa, exponent, padding };
2891 };
2892 pub fn softF80Layout(o: *Object, opts: struct {
2893 llvm_field_tags_buf: []SoftF80Layout.LlvmFieldTag = &.{},
2894 llvm_field_types_buf: []Builder.Type = &.{},
2895 }) Allocator.Error!SoftF80Layout {
2896 const zcu = o.zcu;
2897 const target = zcu.getTarget();
2898 assert(std.zig.target.compilerRtFloatAbi(target, 80) == .soft);
2899 // Current compiler rt soft abi, which is not yet affected by endianness for simplicity:
2900 //
2901 // typedef struct { uint64_t mantissa; uint16_t exponent; } f80;
2902 //
2903 var layout: SoftF80Layout = .{
2904 .alignment = Type.f80.abiAlignment(zcu),
2905 .mantissa_offset = undefined,
2906 .exponent_offset = undefined,
2907 .llvm_fields_len = 0,
2908 };
2909 var offset: u64 = 0;
2910 for ([2]SoftF80Layout.LlvmFieldTag{ .mantissa, .exponent }, [2]Type{ .u64, .u16 }) |field_tag, field_type| {
2911 const field_align = field_type.abiAlignment(zcu);
2912 assert(field_align.compareStrict(.lte, layout.alignment));
2913 const field_offset = field_align.forward(offset);
2914 switch (field_offset - offset) {
2915 0 => {},
2916 else => |padding| {
2917 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2918 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2919 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2920 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2921 layout.llvm_fields_len += 1;
2922 },
2923 }
2924 switch (field_tag) {
2925 .mantissa => layout.mantissa_offset = field_offset,
2926 .exponent => layout.exponent_offset = field_offset,
2927 .padding => unreachable,
2928 }
2929 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2930 opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag;
2931 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2932 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory);
2933 layout.llvm_fields_len += 1;
2934 offset = field_offset + field_type.abiSize(zcu);
2935 }
2936 const end = layout.alignment.forward(offset);
2937 assert(end == Type.f80.abiSize(zcu));
2938 switch (end - offset) {
2939 0 => {},
2940 else => |padding| {
2941 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2942 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2943 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2944 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2945 layout.llvm_fields_len += 1;
2946 },
2947 }
2948 return layout;
2949 }
2950
2951 pub const SoftF128Layout = struct {
2952 alignment: InternPool.Alignment,
2953 /// byte offset of u64 field
2954 lo_offset: u64,
2955 /// byte offset of u64 field
2956 hi_offset: u64,
2957 llvm_fields_len: u32,
2958
2959 pub const LlvmFieldTag = enum { lo, hi, padding };
2960 };
2961 pub fn softF128Layout(o: *Object, opts: struct {
2962 llvm_field_tags_buf: []SoftF128Layout.LlvmFieldTag = &.{},
2963 llvm_field_types_buf: []Builder.Type = &.{},
2964 }) Allocator.Error!SoftF128Layout {
2965 const zcu = o.zcu;
2966 const target = zcu.getTarget();
2967 assert(std.zig.target.compilerRtFloatAbi(target, 128) == .soft);
2968 // Current compiler rt soft abi:
2969 //
2970 // #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
2971 // typedef struct { uint64_t hi, lo; } f128;
2972 // #else
2973 // typedef struct { uint64_t lo, hi; } f128;
2974 // #endif
2975 //
2976 var layout: SoftF128Layout = .{
2977 .alignment = Type.f128.abiAlignment(zcu),
2978 .lo_offset = undefined,
2979 .hi_offset = undefined,
2980 .llvm_fields_len = 0,
2981 };
2982 var offset: u64 = 0;
2983 for (@as([2]SoftF128Layout.LlvmFieldTag, switch (target.cpu.arch.endian()) {
2984 .big => .{ .hi, .lo },
2985 .little => .{ .lo, .hi },
2986 }), [2]Type{ .u64, .u64 }) |field_tag, field_type| {
2987 const field_align = field_type.abiAlignment(zcu);
2988 assert(field_align.compareStrict(.lte, layout.alignment));
2989 const field_offset = field_align.forward(offset);
2990 switch (field_offset - offset) {
2991 0 => {},
2992 else => |padding| {
2993 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
2994 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
2995 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
2996 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
2997 layout.llvm_fields_len += 1;
2998 },
2999 }
3000 switch (field_tag) {
3001 .lo => layout.lo_offset = field_offset,
3002 .hi => layout.hi_offset = field_offset,
3003 .padding => unreachable,
3004 }
3005 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
3006 opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag;
3007 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
3008 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory);
3009 layout.llvm_fields_len += 1;
3010 offset = field_offset + field_type.abiSize(zcu);
3011 }
3012 const end = layout.alignment.forward(offset);
3013 assert(end == Type.f128.abiSize(zcu));
3014 switch (end - offset) {
3015 0 => {},
3016 else => |padding| {
3017 if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len)
3018 opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding;
3019 if (layout.llvm_fields_len < opts.llvm_field_types_buf.len)
3020 opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8);
3021 layout.llvm_fields_len += 1;
3022 },
3023 }
3024 return layout;
3025 }
3026
2864 pub fn lowerType(o: *Object, t: Type, repr: TypeRepr) Allocator.Error!Builder.Type {3027 pub fn lowerType(o: *Object, t: Type, repr: TypeRepr) Allocator.Error!Builder.Type {
2865 const zcu = o.zcu;3028 const zcu = o.zcu;
2866 const target = zcu.getTarget();3029 const target = zcu.getTarget();
...@@ -2901,7 +3064,7 @@ pub const Object = struct {...@@ -2901,7 +3064,7 @@ pub const Object = struct {
2901 .c_ulonglong_type,3064 .c_ulonglong_type,
2902 => |tag| try o.builder.intType(target.cTypeBitSize(3065 => |tag| try o.builder.intType(target.cTypeBitSize(
2903 @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]),3066 @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]),
2904 )),3067 ).?),
2905 .c_longdouble_type,3068 .c_longdouble_type,
2906 .f16_type,3069 .f16_type,
2907 .f32_type,3070 .f32_type,
...@@ -2909,11 +3072,44 @@ pub const Object = struct {...@@ -2909,11 +3072,44 @@ pub const Object = struct {
2909 .f80_type,3072 .f80_type,
2910 .f128_type,3073 .f128_type,
2911 => switch (t.floatBits(target)) {3074 => switch (t.floatBits(target)) {
2912 16 => if (backendSupportsF16(target)) .half else .i16,3075 16 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
2913 32 => .float,3076 .hard => .half,
2914 64 => .double,3077 .soft => .i16,
2915 80 => if (backendSupportsF80(target)) .x86_fp80 else .i80,3078 },
2916 128 => .fp128,3079 32 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
3080 .hard => .float,
3081 .soft => .i32,
3082 },
3083 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
3084 .hard => .double,
3085 .soft => .i64,
3086 },
3087 80 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
3088 .hard => .x86_fp80,
3089 .soft => {
3090 var llvm_field_types_buf: [5]Builder.Type = undefined;
3091 const f80_layout = try o.softF80Layout(.{
3092 .llvm_field_types_buf = &llvm_field_types_buf,
3093 });
3094 return o.builder.structType(
3095 .normal,
3096 llvm_field_types_buf[0..f80_layout.llvm_fields_len],
3097 );
3098 },
3099 },
3100 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
3101 .hard => .fp128,
3102 .soft => {
3103 var llvm_field_types_buf: [5]Builder.Type = undefined;
3104 const f128_layout = try o.softF128Layout(.{
3105 .llvm_field_types_buf = &llvm_field_types_buf,
3106 });
3107 return o.builder.structType(
3108 .normal,
3109 llvm_field_types_buf[0..f128_layout.llvm_fields_len],
3110 );
3111 },
3112 },
2917 else => unreachable,3113 else => unreachable,
2918 },3114 },
2919 .anyopaque_type => {3115 .anyopaque_type => {
...@@ -2992,11 +3188,13 @@ pub const Object = struct {...@@ -2992,11 +3188,13 @@ pub const Object = struct {
2992 array_type.lenIncludingSentinel(),3188 array_type.lenIncludingSentinel(),
2993 try o.lowerType(.fromInterned(array_type.child), repr),3189 try o.lowerType(.fromInterned(array_type.child), repr),
2994 ),3190 ),
2995 .vector_type => |vector_type| o.builder.vectorType(3191 .vector_type => |vector_type| if (isByRef(t, zcu)) {
2996 .normal,3192 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .in_memory);
2997 vector_type.len,3193 return o.builder.arrayType(vector_type.len, child_llvm_ty);
2998 try o.lowerType(.fromInterned(vector_type.child), .as_value),3194 } else {
2999 ),3195 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .as_value);
3196 return o.builder.vectorType(.normal, vector_type.len, child_llvm_ty);
3197 },
3000 .opt_type => |child_ty| {3198 .opt_type => |child_ty| {
3001 // Must stay in sync with `opt_payload` logic in `lowerPtr`.3199 // Must stay in sync with `opt_payload` logic in `lowerPtr`.
3002 switch (Type.fromInterned(child_ty).classify(zcu)) {3200 switch (Type.fromInterned(child_ty).classify(zcu)) {
...@@ -3257,7 +3455,10 @@ pub const Object = struct {...@@ -3257,7 +3455,10 @@ pub const Object = struct {
3257 },3455 },
3258 .opaque_type, .spirv_type => unreachable, // no runtime bits3456 .opaque_type, .spirv_type => unreachable, // no runtime bits
3259 .enum_type => try o.lowerType(t.backingIntType(zcu), repr),3457 .enum_type => try o.lowerType(t.backingIntType(zcu), repr),
3260 .func_type => |func_type| try o.lowerFnType(t, func_type),3458 .func_type => |func_type| {
3459 assert(t.fnHasRuntimeBits(zcu));
3460 return o.lowerFnType(.fromIntern(func_type, ip));
3461 },
3261 .error_set_type, .inferred_error_set_type => try o.errorIntType(repr),3462 .error_set_type, .inferred_error_set_type => try o.errorIntType(repr),
3262 // values, not types3463 // values, not types
3263 .undef,3464 .undef,
...@@ -3283,14 +3484,28 @@ pub const Object = struct {...@@ -3283,14 +3484,28 @@ pub const Object = struct {
3283 };3484 };
3284 }3485 }
32853486
3286 fn lowerFnType(o: *Object, fn_ty: Type, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {3487 pub const FuncInfo = struct {
3488 cc: std.lang.CallingConvention,
3489 noalias_bits: u32 = 0,
3490 param_types: []const InternPool.Index,
3491 return_type: InternPool.Index = .void_type,
3492 is_var_args: bool = false,
3493
3494 pub fn fromIntern(fn_info: InternPool.Key.FuncType, ip: *InternPool) FuncInfo {
3495 return .{
3496 .cc = fn_info.cc,
3497 .noalias_bits = fn_info.noalias_bits,
3498 .param_types = fn_info.param_types.get(ip),
3499 .return_type = fn_info.return_type,
3500 .is_var_args = fn_info.is_var_args,
3501 };
3502 }
3503 };
3504 pub fn lowerFnType(o: *Object, fn_info: FuncInfo) Allocator.Error!Builder.Type {
3287 const zcu = o.zcu;3505 const zcu = o.zcu;
3288 const ip = &zcu.intern_pool;
3289 const target = zcu.getTarget();3506 const target = zcu.getTarget();
32903507
3291 assert(fn_ty.fnHasRuntimeBits(zcu));3508 const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type));
3292
3293 const ret_strat = try fnReturnStrat(o, fn_info);
32943509
3295 var llvm_params: std.ArrayList(Builder.Type) = .empty;3510 var llvm_params: std.ArrayList(Builder.Type) = .empty;
3296 defer llvm_params.deinit(o.gpa);3511 defer llvm_params.deinit(o.gpa);
...@@ -3305,24 +3520,24 @@ pub const Object = struct {...@@ -3305,24 +3520,24 @@ pub const Object = struct {
3305 try llvm_params.append(o.gpa, llvm_ptr_ty);3520 try llvm_params.append(o.gpa, llvm_ptr_ty);
3306 }3521 }
33073522
3308 var it = iterateParamTypes(o, fn_info);3523 var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types);
3309 while (try it.next()) |lowering| switch (lowering) {3524 while (try it.next()) |lowering| switch (lowering) {
3310 .no_bits => continue,3525 .no_bits => continue,
3311 .byval => {3526 .byval => {
3312 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);3527 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3313 try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .in_memory else .as_value));3528 try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .in_memory else .as_value));
3314 },3529 },
3315 .byref, .byref_mut => {3530 .byref, .byref_mut => {
3316 try llvm_params.append(o.gpa, .ptr);3531 try llvm_params.append(o.gpa, .ptr);
3317 },3532 },
3318 .abi_sized_int => {3533 .abi_sized_int => {
3319 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);3534 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3320 try llvm_params.append(o.gpa, try o.builder.intType(3535 try llvm_params.append(o.gpa, try o.builder.intType(
3321 @intCast(param_ty.abiSize(zcu) * 8),3536 @intCast(param_ty.abiSize(zcu) * 8),
3322 ));3537 ));
3323 },3538 },
3324 .slice => {3539 .slice => {
3325 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);3540 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3326 try llvm_params.appendSlice(o.gpa, &.{3541 try llvm_params.appendSlice(o.gpa, &.{
3327 try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(zcu), target)),3542 try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(zcu), target)),
3328 try o.lowerType(.usize, .as_value),3543 try o.lowerType(.usize, .as_value),
...@@ -3332,7 +3547,7 @@ pub const Object = struct {...@@ -3332,7 +3547,7 @@ pub const Object = struct {
3332 try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]);3547 try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]);
3333 },3548 },
3334 .float_array => |count| {3549 .float_array => |count| {
3335 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);3550 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3336 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .in_memory);3551 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .in_memory);
3337 try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty));3552 try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty));
3338 },3553 },
...@@ -3460,18 +3675,12 @@ pub const Object = struct {...@@ -3460,18 +3675,12 @@ pub const Object = struct {
3460 },3675 },
3461 .enum_tag => |enum_tag| o.lowerValue(enum_tag.int, repr),3676 .enum_tag => |enum_tag| o.lowerValue(enum_tag.int, repr),
3462 .float => switch (ty.floatBits(target)) {3677 .float => switch (ty.floatBits(target)) {
3463 16 => if (backendSupportsF16(target))
3464 try o.builder.halfConst(val.toFloat(f16, zcu))
3465 else
3466 try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, zcu)))),
3467 32 => try o.builder.floatConst(val.toFloat(f32, zcu)),
3468 64 => try o.builder.doubleConst(val.toFloat(f64, zcu)),
3469 80 => if (backendSupportsF80(target))
3470 try o.builder.x86_fp80Const(val.toFloat(f80, zcu))
3471 else
3472 try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, zcu)))),
3473 128 => try o.builder.fp128Const(val.toFloat(f128, zcu)),
3474 else => unreachable,3678 else => unreachable,
3679 16 => try o.f16Const(val.toFloat(f16, zcu)),
3680 32 => try o.f32Const(val.toFloat(f32, zcu)),
3681 64 => try o.f64Const(val.toFloat(f64, zcu)),
3682 80 => try o.f80Const(val.toFloat(f80, zcu)),
3683 128 => try o.f128Const(val.toFloat(f128, zcu)),
3475 },3684 },
3476 .ptr => try o.lowerPtr(arg_val, 0),3685 .ptr => try o.lowerPtr(arg_val, 0),
3477 .slice => |slice| return o.builder.structConst(try o.lowerType(ty, repr), &.{3686 .slice => |slice| return o.builder.structConst(try o.lowerType(ty, repr), &.{
...@@ -3590,12 +3799,13 @@ pub const Object = struct {...@@ -3590,12 +3799,13 @@ pub const Object = struct {
3590 },3799 },
3591 .vector_type => |vector_type| {3800 .vector_type => |vector_type| {
3592 const vector_ty = try o.lowerType(ty, repr);3801 const vector_ty = try o.lowerType(ty, repr);
3802 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3803 var bfa_buf: ExpectedContents = undefined;
3804 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3805 const allocator = bfa.allocator();
3806 const is_by_ref = isByRef(ty, zcu);
3593 switch (aggregate.storage) {3807 switch (aggregate.storage) {
3594 .bytes, .elems => {3808 .bytes, .elems => {
3595 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3596 var bfa_buf: ExpectedContents = undefined;
3597 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa);
3598 const allocator = bfa.allocator();
3599 const vals = try allocator.alloc(Builder.Constant, vector_type.len);3809 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3600 defer allocator.free(vals);3810 defer allocator.free(vals);
36013811
...@@ -3604,16 +3814,21 @@ pub const Object = struct {...@@ -3604,16 +3814,21 @@ pub const Object = struct {
3604 result_val.* = try o.builder.intConst(.i8, byte);3814 result_val.* = try o.builder.intConst(.i8, byte);
3605 },3815 },
3606 .elems => |elems| for (vals, elems) |*result_val, elem| {3816 .elems => |elems| for (vals, elems) |*result_val, elem| {
3607 result_val.* = try o.lowerValue(elem, .as_value);3817 result_val.* = try o.lowerValue(elem, if (is_by_ref) .in_memory else .as_value);
3608 },3818 },
3609 .repeated_elem => unreachable,3819 .repeated_elem => unreachable,
3610 }3820 }
3611 return o.builder.vectorConst(vector_ty, vals);3821 return if (is_by_ref)
3822 o.builder.arrayConst(vector_ty, vals)
3823 else
3824 o.builder.vectorConst(vector_ty, vals);
3612 },3825 },
3613 .repeated_elem => |elem| return o.builder.splatConst(3826 .repeated_elem => |elem| if (is_by_ref) {
3614 vector_ty,3827 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3615 try o.lowerValue(elem, .as_value),3828 defer allocator.free(vals);
3616 ),3829 @memset(vals, try o.lowerValue(elem, .in_memory));
3830 return o.builder.arrayConst(vector_ty, vals);
3831 } else return o.builder.splatConst(vector_ty, try o.lowerValue(elem, .as_value)),
3617 }3832 }
3618 },3833 },
3619 .tuple_type => |tuple| {3834 .tuple_type => |tuple| {
...@@ -3841,6 +4056,117 @@ pub const Object = struct {...@@ -3841,6 +4056,117 @@ pub const Object = struct {
3841 };4056 };
3842 }4057 }
38434058
4059 pub fn f16Const(o: *Object, val: f16) Allocator.Error!Builder.Constant {
4060 return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 16)) {
4061 .hard => o.builder.halfConst(val),
4062 .soft => o.builder.intConst(.i16, @as(u16, @bitCast(val))),
4063 };
4064 }
4065
4066 pub fn f32Const(o: *Object, val: f32) Allocator.Error!Builder.Constant {
4067 return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 32)) {
4068 .hard => o.builder.floatConst(val),
4069 .soft => o.builder.intConst(.i32, @as(u32, @bitCast(val))),
4070 };
4071 }
4072
4073 pub fn f64Const(o: *Object, val: f64) Allocator.Error!Builder.Constant {
4074 return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 64)) {
4075 .hard => o.builder.doubleConst(val),
4076 .soft => o.builder.intConst(.i64, @as(u64, @bitCast(val))),
4077 };
4078 }
4079
4080 pub fn f80Const(o: *Object, val: f80) Allocator.Error!Builder.Constant {
4081 switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 80)) {
4082 .hard => return o.builder.x86_fp80Const(val),
4083 .soft => {},
4084 }
4085 var llvm_field_tags_buf: [5]SoftF80Layout.LlvmFieldTag = undefined;
4086 var llvm_field_types_buf: [5]Builder.Type = undefined;
4087 const f80_layout = try o.softF80Layout(.{
4088 .llvm_field_tags_buf = &llvm_field_tags_buf,
4089 .llvm_field_types_buf = &llvm_field_types_buf,
4090 });
4091 const llvm_field_types = llvm_field_types_buf[0..f80_layout.llvm_fields_len];
4092 const f80_llvm_ty = try o.builder.structType(.normal, llvm_field_types);
4093 const f80_repr: packed struct { mantissa: u64, exponent: u16 } = @bitCast(val);
4094 var llvm_field_vals_buf: [5]Builder.Constant = undefined;
4095 const llvm_field_vals = llvm_field_vals_buf[0..f80_layout.llvm_fields_len];
4096 for (
4097 llvm_field_vals,
4098 llvm_field_tags_buf[0..f80_layout.llvm_fields_len],
4099 llvm_field_types,
4100 ) |*llvm_field_val, llvm_field_tag, llvm_field_type|
4101 llvm_field_val.* = switch (llvm_field_tag) {
4102 .mantissa => try o.builder.intConst(llvm_field_type, f80_repr.mantissa),
4103 .exponent => try o.builder.intConst(llvm_field_type, f80_repr.exponent),
4104 .padding => try o.builder.undefConst(llvm_field_type),
4105 };
4106 return o.builder.structConst(f80_llvm_ty, llvm_field_vals);
4107 }
4108
4109 pub fn f128Const(o: *Object, val: f128) Allocator.Error!Builder.Constant {
4110 switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 128)) {
4111 .hard => return o.builder.fp128Const(val),
4112 .soft => {},
4113 }
4114 var llvm_field_tags_buf: [5]SoftF128Layout.LlvmFieldTag = undefined;
4115 var llvm_field_types_buf: [5]Builder.Type = undefined;
4116 const f128_layout = try o.softF128Layout(.{
4117 .llvm_field_tags_buf = &llvm_field_tags_buf,
4118 .llvm_field_types_buf = &llvm_field_types_buf,
4119 });
4120 const llvm_field_types = llvm_field_types_buf[0..f128_layout.llvm_fields_len];
4121 const f128_llvm_ty = try o.builder.structType(.normal, llvm_field_types);
4122 const f128_repr: packed struct { lo: u64, hi: u64 } = @bitCast(val);
4123 var llvm_field_vals_buf: [5]Builder.Constant = undefined;
4124 const llvm_field_vals = llvm_field_vals_buf[0..f128_layout.llvm_fields_len];
4125 for (
4126 llvm_field_vals,
4127 llvm_field_tags_buf[0..f128_layout.llvm_fields_len],
4128 llvm_field_types,
4129 ) |*llvm_field_val, llvm_field_tag, llvm_field_type|
4130 llvm_field_val.* = switch (llvm_field_tag) {
4131 .lo => try o.builder.intConst(llvm_field_type, f128_repr.lo),
4132 .hi => try o.builder.intConst(llvm_field_type, f128_repr.hi),
4133 .padding => try o.builder.undefConst(llvm_field_type),
4134 };
4135 return o.builder.structConst(f128_llvm_ty, llvm_field_vals);
4136 }
4137
4138 pub fn lowerConstRef(
4139 o: *Object,
4140 constant: Builder.Constant,
4141 @"align": Builder.Alignment,
4142 ) Allocator.Error!Builder.Constant {
4143 assert(@"align" != .default);
4144 const zcu = o.zcu;
4145 const gpa = zcu.comp.gpa;
4146 const gop = try o.const_map.getOrPut(gpa, constant);
4147 if (gop.found_existing) {
4148 // Keep the greater of the two alignments.
4149 const llvm_variable = gop.value_ptr.*;
4150 const llvm_old_align = llvm_variable.getAlignment(&o.builder);
4151 const llvm_new_align = llvm_old_align.max(@"align");
4152 llvm_variable.setAlignment(llvm_new_align, &o.builder);
4153 return llvm_variable.ptrConst(&o.builder).global.toConst();
4154 }
4155 errdefer assert(o.const_map.remove(constant));
4156
4157 const llvm_ty = constant.typeOf(&o.builder);
4158 const llvm_addrspace = toLlvmAddressSpace(.generic, zcu.getTarget());
4159 const llvm_variable = try o.builder.addVariable(.empty, llvm_ty, llvm_addrspace);
4160 gop.value_ptr.* = llvm_variable;
4161 try llvm_variable.setInitializer(constant, &o.builder);
4162 llvm_variable.setMutability(.constant, &o.builder);
4163 llvm_variable.setAlignment(@"align", &o.builder);
4164 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
4165 llvm_global.setLinkage(.private, &o.builder);
4166 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
4167 return llvm_global.toConst();
4168 }
4169
3844 fn lowerPtr(4170 fn lowerPtr(
3845 o: *Object,4171 o: *Object,
3846 ptr_val: InternPool.Index,4172 ptr_val: InternPool.Index,
...@@ -3860,7 +4186,7 @@ pub const Object = struct {...@@ -3860,7 +4186,7 @@ pub const Object = struct {
3860 const orig_ptr_ty: Type = .fromInterned(uav.orig_ty);4186 const orig_ptr_ty: Type = .fromInterned(uav.orig_ty);
3861 const base_ptr = try o.lowerUavRef(4187 const base_ptr = try o.lowerUavRef(
3862 uav.val,4188 uav.val,
3863 orig_ptr_ty.ptrAlignment(zcu),4189 orig_ptr_ty.ptrAlignment(zcu).toLlvm(),
3864 orig_ptr_ty.ptrAddressSpace(zcu),4190 orig_ptr_ty.ptrAddressSpace(zcu),
3865 );4191 );
3866 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{4192 return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{
...@@ -3912,8 +4238,8 @@ pub const Object = struct {...@@ -3912,8 +4238,8 @@ pub const Object = struct {
39124238
3913 pub fn lowerPtrToVoid(4239 pub fn lowerPtrToVoid(
3914 o: *Object,4240 o: *Object,
3915 /// Must not be `.none`.4241 /// Must not be `.default`.
3916 @"align": InternPool.Alignment,4242 @"align": Builder.Alignment,
3917 @"addrspace": std.lang.AddressSpace,4243 @"addrspace": std.lang.AddressSpace,
3918 ) Allocator.Error!Builder.Constant {4244 ) Allocator.Error!Builder.Constant {
3919 const addr: u64 = @"align".toByteUnits().?;4245 const addr: u64 = @"align".toByteUnits().?;
...@@ -3926,11 +4252,11 @@ pub const Object = struct {...@@ -3926,11 +4252,11 @@ pub const Object = struct {
3926 pub fn lowerUavRef(4252 pub fn lowerUavRef(
3927 o: *Object,4253 o: *Object,
3928 uav_val: InternPool.Index,4254 uav_val: InternPool.Index,
3929 /// Must not be `.none`.4255 /// Must not be `.default`.
3930 @"align": InternPool.Alignment,4256 @"align": Builder.Alignment,
3931 @"addrspace": std.lang.AddressSpace,4257 @"addrspace": std.lang.AddressSpace,
3932 ) Allocator.Error!Builder.Constant {4258 ) Allocator.Error!Builder.Constant {
3933 assert(@"align" != .none);4259 assert(@"align" != .default);
39344260
3935 const zcu = o.zcu;4261 const zcu = o.zcu;
3936 const ip = &zcu.intern_pool;4262 const ip = &zcu.intern_pool;
...@@ -3955,7 +4281,7 @@ pub const Object = struct {...@@ -3955,7 +4281,7 @@ pub const Object = struct {
3955 // Keep the greater of the two alignments.4281 // Keep the greater of the two alignments.
3956 const llvm_variable = gop.value_ptr.*;4282 const llvm_variable = gop.value_ptr.*;
3957 const llvm_old_align = llvm_variable.getAlignment(&o.builder);4283 const llvm_old_align = llvm_variable.getAlignment(&o.builder);
3958 const llvm_new_align = llvm_old_align.max(@"align".toLlvm());4284 const llvm_new_align = llvm_old_align.max(@"align");
3959 llvm_variable.setAlignment(llvm_new_align, &o.builder);4285 llvm_variable.setAlignment(llvm_new_align, &o.builder);
3960 return llvm_variable.ptrConst(&o.builder).global.toConst();4286 return llvm_variable.ptrConst(&o.builder).global.toConst();
3961 }4287 }
...@@ -3967,7 +4293,7 @@ pub const Object = struct {...@@ -3967,7 +4293,7 @@ pub const Object = struct {
3967 gop.value_ptr.* = llvm_variable;4293 gop.value_ptr.* = llvm_variable;
3968 try llvm_variable.setInitializer(try o.lowerValue(uav_val, .in_memory), &o.builder);4294 try llvm_variable.setInitializer(try o.lowerValue(uav_val, .in_memory), &o.builder);
3969 llvm_variable.setMutability(.constant, &o.builder);4295 llvm_variable.setMutability(.constant, &o.builder);
3970 llvm_variable.setAlignment(@"align".toLlvm(), &o.builder);4296 llvm_variable.setAlignment(@"align", &o.builder);
3971 const llvm_global = llvm_variable.ptrConst(&o.builder).global;4297 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
3972 llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);4298 llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
3973 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);4299 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
...@@ -3986,7 +4312,7 @@ pub const Object = struct {...@@ -3986,7 +4312,7 @@ pub const Object = struct {
3986 .none => nav_ty.abiAlignment(zcu),4312 .none => nav_ty.abiAlignment(zcu),
3987 else => |a| a,4313 else => |a| a,
3988 };4314 };
3989 return o.lowerPtrToVoid(nav_align, nav.resolved.?.@"addrspace");4315 return o.lowerPtrToVoid(nav_align.toLlvm(), nav.resolved.?.@"addrspace");
3990 }4316 }
39914317
3992 const gop = try o.nav_map.getOrPut(gpa, nav_id);4318 const gop = try o.nav_map.getOrPut(gpa, nav_id);
...@@ -4015,7 +4341,7 @@ pub const Object = struct {...@@ -4015,7 +4341,7 @@ pub const Object = struct {
4015 attributes: *Builder.FunctionAttributes.Wip,4341 attributes: *Builder.FunctionAttributes.Wip,
4016 param_ty: Type,4342 param_ty: Type,
4017 param_index: u32,4343 param_index: u32,
4018 fn_info: InternPool.Key.FuncType,4344 fn_info: FuncInfo,
4019 llvm_arg_i: u32,4345 llvm_arg_i: u32,
4020 ) Allocator.Error!void {4346 ) Allocator.Error!void {
4021 const zcu = o.zcu;4347 const zcu = o.zcu;
...@@ -4075,18 +4401,18 @@ pub const Object = struct {...@@ -4075,18 +4401,18 @@ pub const Object = struct {
40754401
4076 const name = try o.builder.strtabString("__zig_error_name_table");4402 const name = try o.builder.strtabString("__zig_error_name_table");
4077 // TODO: Address space4403 // TODO: Address space
4078 const variable_index = try o.builder.addVariable(name, .ptr, .default);4404 const llvm_variable = try o.builder.addVariable(name, .ptr, .default);
4079 variable_index.setMutability(.constant, &o.builder);4405 llvm_variable.setMutability(.constant, &o.builder);
4080 variable_index.setAlignment(4406 llvm_variable.setAlignment(
4081 Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(),4407 Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(),
4082 &o.builder,4408 &o.builder,
4083 );4409 );
4084 const global_index = variable_index.ptrConst(&o.builder).global;4410 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
4085 global_index.setLinkage(.private, &o.builder);4411 llvm_global.setLinkage(.private, &o.builder);
4086 global_index.setUnnamedAddr(.unnamed_addr, &o.builder);4412 llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
40874413
4088 o.error_name_table = variable_index;4414 o.error_name_table = llvm_variable;
4089 return variable_index;4415 return llvm_variable;
4090 }4416 }
40914417
4092 pub fn getErrorsLen(o: *Object) Allocator.Error!Builder.Variable.Index {4418 pub fn getErrorsLen(o: *Object) Allocator.Error!Builder.Variable.Index {
...@@ -4094,13 +4420,13 @@ pub const Object = struct {...@@ -4094,13 +4420,13 @@ pub const Object = struct {
4094 if (o.errors_len_variable == .none) {4420 if (o.errors_len_variable == .none) {
4095 const llvm_err_int_ty = try o.errorIntType(.in_memory);4421 const llvm_err_int_ty = try o.errorIntType(.in_memory);
4096 const name = try builder.strtabString("__zig_errors_len");4422 const name = try builder.strtabString("__zig_errors_len");
4097 const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default);4423 const llvm_variable = try builder.addVariable(name, llvm_err_int_ty, .default);
4098 variable_index.setMutability(.constant, builder);4424 llvm_variable.setMutability(.constant, builder);
4099 variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder);4425 llvm_variable.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder);
4100 const global_index = variable_index.ptrConst(&o.builder).global;4426 const llvm_global = llvm_variable.ptrConst(&o.builder).global;
4101 global_index.setLinkage(.private, builder);4427 llvm_global.setLinkage(.private, builder);
4102 global_index.setUnnamedAddr(.unnamed_addr, builder);4428 llvm_global.setUnnamedAddr(.unnamed_addr, builder);
4103 o.errors_len_variable = variable_index;4429 o.errors_len_variable = llvm_variable;
4104 }4430 }
4105 return o.errors_len_variable;4431 return o.errors_len_variable;
4106 }4432 }
...@@ -4112,21 +4438,21 @@ pub const Object = struct {...@@ -4112,21 +4438,21 @@ pub const Object = struct {
4112 const gop = try o.enum_tag_name_map.getOrPut(o.gpa, enum_ty.toIntern());4438 const gop = try o.enum_tag_name_map.getOrPut(o.gpa, enum_ty.toIntern());
4113 if (gop.found_existing) return gop.value_ptr.*;4439 if (gop.found_existing) return gop.value_ptr.*;
4114 errdefer assert(o.enum_tag_name_map.remove(enum_ty.toIntern()));4440 errdefer assert(o.enum_tag_name_map.remove(enum_ty.toIntern()));
4115 const function_index = try o.builder.addFunction(4441 const llvm_function = try o.builder.addFunction(
4116 // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type.4442 // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type.
4117 // TODO: change the builder API so we don't need to do this.4443 // TODO: change the builder API so we don't need to do this.
4118 try o.builder.fnType(.void, &.{}, .normal),4444 try o.builder.fnType(.void, &.{}, .normal),
4119 try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),4445 try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),
4120 toLlvmAddressSpace(.generic, zcu.getTarget()),4446 toLlvmAddressSpace(.generic, zcu.getTarget()),
4121 );4447 );
4122 gop.value_ptr.* = function_index;4448 gop.value_ptr.* = llvm_function;
4123 try o.updateEnumTagNameFunction(enum_ty, function_index);4449 try o.updateEnumTagNameFunction(enum_ty, llvm_function);
4124 return function_index;4450 return llvm_function;
4125 }4451 }
4126 fn updateEnumTagNameFunction(4452 fn updateEnumTagNameFunction(
4127 o: *Object,4453 o: *Object,
4128 enum_ty: Type,4454 enum_ty: Type,
4129 function_index: Builder.Function.Index,4455 llvm_function: Builder.Function.Index,
4130 ) Allocator.Error!void {4456 ) Allocator.Error!void {
4131 const zcu = o.zcu;4457 const zcu = o.zcu;
4132 const ip = &zcu.intern_pool;4458 const ip = &zcu.intern_pool;
...@@ -4136,19 +4462,19 @@ pub const Object = struct {...@@ -4136,19 +4462,19 @@ pub const Object = struct {
4136 const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .as_value);4462 const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .as_value);
4137 const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value);4463 const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value);
41384464
4139 function_index.ptrConst(&o.builder).global.ptr(&o.builder).type =4465 llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type =
4140 try o.builder.fnType(llvm_ret_ty, &.{llvm_int_ty}, .normal);4466 try o.builder.fnType(llvm_ret_ty, &.{llvm_int_ty}, .normal);
41414467
4142 var attributes: Builder.FunctionAttributes.Wip = .{};4468 var attributes: Builder.FunctionAttributes.Wip = .{};
4143 defer attributes.deinit(&o.builder);4469 defer attributes.deinit(&o.builder);
4144 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);4470 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
41454471
4146 function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);4472 llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
4147 function_index.setCallConv(.fastcc, &o.builder);4473 llvm_function.setCallConv(.fastcc, &o.builder);
4148 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);4474 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
41494475
4150 var wip = try Builder.WipFunction.init(&o.builder, .{4476 var wip = try Builder.WipFunction.init(&o.builder, .{
4151 .function = function_index,4477 .function = llvm_function,
4152 .strip = true,4478 .strip = true,
4153 });4479 });
4154 defer wip.deinit();4480 defer wip.deinit();
...@@ -4167,16 +4493,16 @@ pub const Object = struct {...@@ -4167,16 +4493,16 @@ pub const Object = struct {
4167 for (0..loaded_enum.field_names.len) |field_index| {4493 for (0..loaded_enum.field_names.len) |field_index| {
4168 const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));4494 const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
4169 const name_init = try o.builder.stringConst(name);4495 const name_init = try o.builder.stringConst(name);
4170 const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);4496 const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
4171 try name_variable_index.setInitializer(name_init, &o.builder);4497 try name_llvm_variable.setInitializer(name_init, &o.builder);
4172 name_variable_index.setMutability(.constant, &o.builder);4498 name_llvm_variable.setMutability(.constant, &o.builder);
4173 name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);4499 name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder);
4174 const name_global_index = name_variable_index.ptrConst(&o.builder).global;4500 const name_llvm_global = name_llvm_variable.ptrConst(&o.builder).global;
4175 name_global_index.setLinkage(.private, &o.builder);4501 name_llvm_global.setLinkage(.private, &o.builder);
4176 name_global_index.setUnnamedAddr(.unnamed_addr, &o.builder);4502 name_llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder);
41774503
4178 const name_val = try o.builder.structValue(llvm_ret_ty, &.{4504 const name_val = try o.builder.structValue(llvm_ret_ty, &.{
4179 name_global_index.toConst(),4505 name_llvm_global.toConst(),
4180 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1),4506 try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1),
4181 });4507 });
41824508
...@@ -4209,40 +4535,40 @@ pub const Object = struct {...@@ -4209,40 +4535,40 @@ pub const Object = struct {
4209 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern());4535 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern());
4210 if (gop.found_existing) return gop.value_ptr.*;4536 if (gop.found_existing) return gop.value_ptr.*;
4211 errdefer assert(o.named_enum_map.remove(enum_ty.toIntern()));4537 errdefer assert(o.named_enum_map.remove(enum_ty.toIntern()));
4212 const function_index = try o.builder.addFunction(4538 const llvm_function = try o.builder.addFunction(
4213 // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.4539 // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.
4214 // TODO: change the builder API so we don't need to do this.4540 // TODO: change the builder API so we don't need to do this.
4215 try o.builder.fnType(.void, &.{}, .normal),4541 try o.builder.fnType(.void, &.{}, .normal),
4216 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),4542 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),
4217 toLlvmAddressSpace(.generic, zcu.getTarget()),4543 toLlvmAddressSpace(.generic, zcu.getTarget()),
4218 );4544 );
4219 gop.value_ptr.* = function_index;4545 gop.value_ptr.* = llvm_function;
4220 try o.updateIsNamedEnumValueFunction(enum_ty, function_index);4546 try o.updateIsNamedEnumValueFunction(enum_ty, llvm_function);
4221 return function_index;4547 return llvm_function;
4222 }4548 }
4223 fn updateIsNamedEnumValueFunction(4549 fn updateIsNamedEnumValueFunction(
4224 o: *Object,4550 o: *Object,
4225 enum_ty: Type,4551 enum_ty: Type,
4226 function_index: Builder.Function.Index,4552 llvm_function: Builder.Function.Index,
4227 ) Allocator.Error!void {4553 ) Allocator.Error!void {
4228 const zcu = o.zcu;4554 const zcu = o.zcu;
4229 const ip = &zcu.intern_pool;4555 const ip = &zcu.intern_pool;
4230 const loaded_enum = ip.loadEnumType(enum_ty.toIntern());4556 const loaded_enum = ip.loadEnumType(enum_ty.toIntern());
42314557
4232 const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value);4558 const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value);
4233 function_index.ptrConst(&o.builder).global.ptr(&o.builder).type =4559 llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type =
4234 try o.builder.fnType(.i1, &.{llvm_int_ty}, .normal);4560 try o.builder.fnType(.i1, &.{llvm_int_ty}, .normal);
42354561
4236 var attributes: Builder.FunctionAttributes.Wip = .{};4562 var attributes: Builder.FunctionAttributes.Wip = .{};
4237 defer attributes.deinit(&o.builder);4563 defer attributes.deinit(&o.builder);
4238 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);4564 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
42394565
4240 function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);4566 llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder);
4241 function_index.setCallConv(.fastcc, &o.builder);4567 llvm_function.setCallConv(.fastcc, &o.builder);
4242 function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);4568 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
42434569
4244 var wip: Builder.WipFunction = try .init(&o.builder, .{4570 var wip: Builder.WipFunction = try .init(&o.builder, .{
4245 .function = function_index,4571 .function = llvm_function,
4246 .strip = true,4572 .strip = true,
4247 });4573 });
4248 defer wip.deinit();4574 defer wip.deinit();
...@@ -4278,20 +4604,27 @@ pub const Object = struct {...@@ -4278,20 +4604,27 @@ pub const Object = struct {
42784604
4279 pub fn getLibcFunction(4605 pub fn getLibcFunction(
4280 o: *Object,4606 o: *Object,
4607 pt: Zcu.PerThread,
4281 fn_name: Builder.StrtabString,4608 fn_name: Builder.StrtabString,
4282 param_types: []const Builder.Type,4609 fn_info: FuncInfo,
4283 return_type: Builder.Type,
4284 ) Allocator.Error!Builder.Function.Index {4610 ) Allocator.Error!Builder.Function.Index {
4285 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {4611 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {
4286 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,4612 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,
4287 .function => |function| function,4613 .function => |function| function,
4288 .variable, .replaced => unreachable,4614 .variable, .replaced => unreachable,
4289 };4615 };
4290 return o.builder.addFunction(4616 const llvm_function = try o.builder.addFunction(
4291 try o.builder.fnType(return_type, param_types, .normal),4617 try o.lowerFnType(fn_info),
4292 fn_name,4618 fn_name,
4293 toLlvmAddressSpace(.generic, o.zcu.getTarget()),4619 toLlvmAddressSpace(.generic, o.zcu.getTarget()),
4294 );4620 );
4621 var attributes: Builder.FunctionAttributes.Wip = .{};
4622 defer attributes.deinit(&o.builder);
4623 try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{
4624 .name = fn_name.slice(&o.builder).?,
4625 }, fn_info);
4626 llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder);
4627 return llvm_function;
4295 }4628 }
4296};4629};
42974630
...@@ -4585,47 +4918,6 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.lang.AddressSpace, target:...@@ -4585,47 +4918,6 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.lang.AddressSpace, target:
4585 };4918 };
4586}4919}
45874920
4588/// This function returns true if we expect LLVM to lower f16 correctly
4589/// and false if we expect LLVM to crash if it encounters an f16 type,
4590/// or if it produces miscompilations.
4591pub fn backendSupportsF16(target: *const std.Target) bool {
4592 return switch (target.cpu.arch) {
4593 .arm,
4594 .armeb,
4595 .thumb,
4596 .thumbeb,
4597 => target.abi.float() == .soft or target.cpu.has(.arm, .fullfp16),
4598 else => true,
4599 };
4600}
4601
4602/// This function returns true if we expect LLVM to lower x86_fp80 correctly
4603/// and false if we expect LLVM to crash if it encounters an x86_fp80 type,
4604/// or if it produces miscompilations.
4605pub fn backendSupportsF80(target: *const std.Target) bool {
4606 return switch (target.cpu.arch) {
4607 .x86, .x86_64 => !target.cpu.has(.x86, .soft_float),
4608 else => false,
4609 };
4610}
4611
4612/// This function returns true if we expect LLVM to lower f128 correctly,
4613/// and false if we expect LLVM to crash if it encounters an f128 type,
4614/// or if it produces miscompilations.
4615pub fn backendSupportsF128(target: *const std.Target) bool {
4616 return switch (target.cpu.arch) {
4617 // https://github.com/llvm/llvm-project/issues/121122
4618 .amdgcn,
4619 => false,
4620 .arm,
4621 .armeb,
4622 .thumb,
4623 .thumbeb,
4624 => target.abi.float() == .soft or target.cpu.has(.arm, .fp_armv8),
4625 else => true,
4626 };
4627}
4628
4629/// We need to insert extra padding if LLVM's isn't enough.4921/// We need to insert extra padding if LLVM's isn't enough.
4630/// However we don't want to ever call LLVMABIAlignmentOfType or4922/// However we don't want to ever call LLVMABIAlignmentOfType or
4631/// LLVMABISizeOfType because these functions will trip assertions4923/// LLVMABISizeOfType because these functions will trip assertions
src/codegen/llvm/FuncGen.zig+1097-830
...@@ -169,7 +169,7 @@ fn resolveValue(self: *FuncGen, val: Value) Allocator.Error!Builder.Constant {...@@ -169,7 +169,7 @@ fn resolveValue(self: *FuncGen, val: Value) Allocator.Error!Builder.Constant {
169 // We need a pointer to a global constant, i.e. a UAV.169 // We need a pointer to a global constant, i.e. a UAV.
170 return o.lowerUavRef(170 return o.lowerUavRef(
171 val.toIntern(),171 val.toIntern(),
172 ty.abiAlignment(zcu),172 ty.abiAlignment(zcu).toLlvm(),
173 target_util.defaultAddressSpace(zcu.getTarget(), .global_constant),173 target_util.defaultAddressSpace(zcu.getTarget(), .global_constant),
174 );174 );
175 }175 }
...@@ -190,10 +190,10 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void {...@@ -190,10 +190,10 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void {
190 const fn_info = zcu.typeToFunc(fn_ty).?;190 const fn_info = zcu.typeToFunc(fn_ty).?;
191 const param_types = fn_info.param_types.get(ip);191 const param_types = fn_info.param_types.get(ip);
192192
193 var it = iterateParamTypes(o, fn_info);193 var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types.get(ip));
194194
195 // Populate `fg.ret_ptr`...195 // Populate `fg.ret_ptr`...
196 fg.ret_ptr = switch (try fnReturnStrat(o, fn_info)) {196 fg.ret_ptr = switch (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type))) {
197 .sret => rp: {197 .sret => rp: {
198 defer it.llvm_index += 1;198 defer it.llvm_index += 1;
199 break :rp fg.wip.arg(it.llvm_index);199 break :rp fg.wip.arg(it.llvm_index);
...@@ -721,29 +721,19 @@ fn genBodyDebugScope(...@@ -721,29 +721,19 @@ fn genBodyDebugScope(
721 try self.genBody(body, coverage_point);721 try self.genBody(body, coverage_point);
722}722}
723723
724const CallAttr = enum {724fn airCall(fg: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) Allocator.Error!Builder.Value {
725 Auto,725 const o = fg.object;
726 NeverTail,
727 NeverInline,
728 AlwaysTail,
729 AlwaysInline,
730};
731
732fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) Allocator.Error!Builder.Value {
733 const air_call = self.air.unwrapCall(inst);
734 const args = air_call.args;
735 const o = self.object;
736 const pt = self.pt;
737 const zcu = o.zcu;726 const zcu = o.zcu;
727 const air_call = fg.air.unwrapCall(inst);
728 const args = air_call.args;
738 const ip = &zcu.intern_pool;729 const ip = &zcu.intern_pool;
739 const callee_ty = self.typeOf(air_call.callee);730 const callee_ty = fg.typeOf(air_call.callee);
740 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {731 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {
741 .@"fn" => callee_ty,732 .@"fn" => callee_ty,
742 .pointer => callee_ty.childType(zcu),733 .pointer => callee_ty.childType(zcu),
743 else => unreachable,734 else => unreachable,
744 };735 };
745 const fn_info = zcu.typeToFunc(zig_fn_ty).?;736 const fn_info = zcu.typeToFunc(zig_fn_ty).?;
746 const return_type: Type = .fromInterned(fn_info.return_type);
747 const llvm_fn = llvm_fn: {737 const llvm_fn = llvm_fn: {
748 // If the callee is a function *body*, we need to use a pointer to the global.738 // If the callee is a function *body*, we need to use a pointer to the global.
749 if (air_call.callee.toInterned()) |ip_index| switch (ip.indexToKey(ip_index)) {739 if (air_call.callee.toInterned()) |ip_index| switch (ip.indexToKey(ip_index)) {
...@@ -752,22 +742,54 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -752,22 +742,54 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
752 else => {},742 else => {},
753 };743 };
754 // Otherwise, the operand is already a function pointer (possibly runtime-known).744 // Otherwise, the operand is already a function pointer (possibly runtime-known).
755 break :llvm_fn try self.resolveInst(air_call.callee);745 break :llvm_fn try fg.resolveInst(air_call.callee);
756 };746 };
747
748 const arg_types = try fg.gpa.alloc(InternPool.Index, args.len);
749 defer fg.gpa.free(arg_types);
750 const arg_values = try fg.gpa.alloc(Builder.Value, args.len);
751 defer fg.gpa.free(arg_values);
752 for (arg_types, arg_values, args) |*arg_type, *arg_value, arg| {
753 const arg_ty = fg.typeOf(arg);
754 arg_type.* = arg_ty.toIntern();
755 arg_value.* = if (arg_ty.hasRuntimeBits(zcu)) try fg.resolveInst(arg) else .none;
756 }
757 return fg.buildCall(.{
758 .is_unused = fg.liveness.isUnused(inst),
759 .modifier = modifier,
760 }, try o.lowerType(zig_fn_ty, .as_value), llvm_fn, .fromIntern(fn_info, ip), arg_types, arg_values);
761}
762
763fn buildCall(
764 fg: *FuncGen,
765 opts: struct {
766 is_unused: bool = false,
767 modifier: std.lang.CallModifier = .auto,
768 },
769 llvm_fn_ty: Builder.Type,
770 llvm_fn: Builder.Value,
771 fn_info: Object.FuncInfo,
772 arg_types: []const InternPool.Index,
773 arg_values: []const Builder.Value,
774) Allocator.Error!Builder.Value {
775 const o = fg.object;
776 const pt = fg.pt;
777 const zcu = o.zcu;
778 const return_type: Type = .fromInterned(fn_info.return_type);
757 const target = zcu.getTarget();779 const target = zcu.getTarget();
758 const ret_strat = try fnReturnStrat(o, fn_info);780 const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type));
759781
760 var llvm_args = std.array_list.Managed(Builder.Value).init(self.gpa);782 var llvm_args: std.ArrayList(Builder.Value) = .empty;
761 defer llvm_args.deinit();783 defer llvm_args.deinit(fg.gpa);
762784
763 var attributes: Builder.FunctionAttributes.Wip = .{};785 var attributes: Builder.FunctionAttributes.Wip = .{};
764 defer attributes.deinit(&o.builder);786 defer attributes.deinit(&o.builder);
765787
766 if (self.disable_intrinsics) {788 if (fg.disable_intrinsics) {
767 try attributes.addFnAttr(.nobuiltin, &o.builder);789 try attributes.addFnAttr(.nobuiltin, &o.builder);
768 }790 }
769791
770 switch (modifier) {792 switch (opts.modifier) {
771 .auto, .always_tail => {},793 .auto, .always_tail => {},
772 .never_tail, .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder),794 .never_tail, .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder),
773 .no_suspend, .always_inline, .compile_time => unreachable,795 .no_suspend, .always_inline, .compile_time => unreachable,
...@@ -775,10 +797,11 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -775,10 +797,11 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
775797
776 const sret_alloc: ?Builder.Value = switch (ret_strat) {798 const sret_alloc: ?Builder.Value = switch (ret_strat) {
777 .sret => sret_alloc: {799 .sret => sret_alloc: {
778 try attributes.addParamAttr(0, .{ .sret = try o.lowerType(return_type, .in_memory) }, &o.builder);800 const alignment = return_type.abiAlignment(zcu).toLlvm();
801 try o.addSRetFnAttributes(&attributes, try o.lowerType(return_type, .in_memory), alignment, .callsite);
779802
780 const ptr = try self.buildZigAlloca(return_type, .none);803 const ptr = try fg.buildZigAlloca(return_type, .none);
781 try llvm_args.append(ptr);804 try llvm_args.append(fg.gpa, ptr);
782 break :sret_alloc ptr;805 break :sret_alloc ptr;
783 },806 },
784 else => sret_alloc: {807 else => sret_alloc: {
...@@ -792,132 +815,111 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -792,132 +815,111 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
792815
793 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;816 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
794 if (err_return_tracing) {817 if (err_return_tracing) {
795 assert(self.err_ret_trace != .none);818 assert(fg.err_ret_trace != .none);
796 try llvm_args.append(self.err_ret_trace);819 try llvm_args.append(fg.gpa, fg.err_ret_trace);
797 }820 }
798
799 var it = iterateParamTypes(o, fn_info);
800 while (try it.nextCall(self, args)) |lowering| switch (lowering) {
801 .no_bits => continue,
802 .byval => {
803 const arg = args[it.zig_index - 1];
804 const param_ty = self.typeOf(arg);
805 const llvm_arg = try self.resolveInst(arg);
806 if (isByRef(param_ty, zcu)) {
807 const alignment = param_ty.abiAlignment(zcu).toLlvm();
808 // We don't need to handle non-ABI-sized integer types in memory here since they are
809 // never by-ref.
810 const llvm_param_ty = try o.lowerType(param_ty, .in_memory);
811 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
812 try llvm_args.append(loaded);
813 } else {
814 try llvm_args.append(llvm_arg);
815 }
816 },
817 .byref => {
818 const arg = args[it.zig_index - 1];
819 const param_ty = self.typeOf(arg);
820 const llvm_arg = try self.resolveInst(arg);
821 if (isByRef(param_ty, zcu)) {
822 try llvm_args.append(llvm_arg);
823 } else {
824 const arg_ptr = try self.buildZigAlloca(param_ty, .none);
825 try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal);
826 try llvm_args.append(arg_ptr);
827 }
828 },
829 .byref_mut => {
830 const arg = args[it.zig_index - 1];
831 const param_ty = self.typeOf(arg);
832 const llvm_arg = try self.resolveInst(arg);
833
834 const arg_ptr = try self.buildZigAlloca(param_ty, .none);
835 try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal);
836 try llvm_args.append(arg_ptr);
837 },
838 .abi_sized_int => {
839 const arg = args[it.zig_index - 1];
840 const param_ty = self.typeOf(arg);
841 const llvm_arg = try self.resolveInst(arg);
842 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(zcu) * 8));
843
844 if (isByRef(param_ty, zcu)) {
845 const alignment = param_ty.abiAlignment(zcu).toLlvm();
846 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
847 try llvm_args.append(loaded);
848 } else {
849 // LLVM does not allow bitcasting structs so we must allocate
850 // a local, store as one type, and then load as another type.
851 const alignment = param_ty.abiAlignment(zcu).toLlvm();
852 const ptr = try self.buildAlloca(int_llvm_ty, alignment);
853 try self.store(ptr, .none, llvm_arg, param_ty, .normal);
854 const loaded = try self.wip.load(.normal, int_llvm_ty, ptr, alignment, "");
855 try llvm_args.append(loaded);
856 }
857 },
858 .slice => {
859 const arg = args[it.zig_index - 1];
860 const llvm_arg = try self.resolveInst(arg);
861 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
862 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
863 try llvm_args.appendSlice(&.{ ptr, len });
864 },
865 .multiple_llvm_types => {
866 const arg = args[it.zig_index - 1];
867 const param_ty = self.typeOf(arg);
868 const llvm_arg = try self.resolveInst(arg);
869 const param_alignment = param_ty.abiAlignment(zcu);
870 const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8);
871 const arg_ptr = try self.buildAlloca(llvm_ty, param_alignment.toLlvm());
872 try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal);
873
874 try llvm_args.ensureUnusedCapacity(it.types_len);
875 for (it.types_buffer[0..it.types_len], it.offsets_buffer[0..it.types_len]) |field_ty, offset| {
876 const field_ptr = try self.ptraddConst(arg_ptr, offset);
877 const loaded = try self.wip.load(.normal, field_ty, field_ptr, param_alignment.offset(offset).toLlvm(), "");
878 llvm_args.appendAssumeCapacity(loaded);
879 }
880 },
881 .float_array => |count| {
882 const arg = args[it.zig_index - 1];
883 const arg_ty = self.typeOf(arg);
884 const arg_val = try self.resolveInst(arg);
885
886 const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: {
887 const ptr = try self.buildZigAlloca(arg_ty, .none);
888 try self.store(ptr, .none, arg_val, arg_ty, .normal);
889 break :ptr ptr;
890 } else arg_val;
891
892 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .in_memory);
893 const array_ty = try o.builder.arrayType(count, float_ty);
894821
895 const loaded = try self.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), "");822 var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types);
896 try llvm_args.append(loaded);823 while (try it.nextCall(arg_types)) |lowering| {
897 },824 const arg_ty: Type = .fromInterned(arg_types[it.zig_index - 1]);
898 .i32_array, .i64_array => |arr_len| {825 const arg_val = arg_values[it.zig_index - 1];
899 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;826 switch (lowering) {
900 const arg = args[it.zig_index - 1];827 .no_bits => continue,
901 const arg_ty = self.typeOf(arg);828 .byval => {
902 const arg_val = try self.resolveInst(arg);829 if (isByRef(arg_ty, zcu)) {
903830 const alignment = arg_ty.abiAlignment(zcu).toLlvm();
904 const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: {831 // We don't need to handle non-ABI-sized integer types in memory here since they are
905 const ptr = try self.buildZigAlloca(arg_ty, .none);832 // never by-ref.
906 try self.store(ptr, .none, arg_val, arg_ty, .normal);833 const llvm_arg_ty = try o.lowerType(arg_ty, .in_memory);
907 break :ptr ptr;834 const loaded = try fg.wip.load(.normal, llvm_arg_ty, arg_val, alignment, "");
908 } else arg_val;835 try llvm_args.append(fg.gpa, loaded);
836 } else {
837 try llvm_args.append(fg.gpa, arg_val);
838 }
839 },
840 .byref => {
841 if (isByRef(arg_ty, zcu)) {
842 try llvm_args.append(fg.gpa, arg_val);
843 } else {
844 const arg_ptr = try fg.buildZigAlloca(arg_ty, .none);
845 try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal);
846 try llvm_args.append(fg.gpa, arg_ptr);
847 }
848 },
849 .byref_mut => {
850 const arg_ptr = try fg.buildZigAlloca(arg_ty, .none);
851 try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal);
852 try llvm_args.append(fg.gpa, arg_ptr);
853 },
854 .abi_sized_int => {
855 const int_llvm_ty = try o.builder.intType(@intCast(arg_ty.abiSize(zcu) * 8));
909856
910 const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));857 if (isByRef(arg_ty, zcu)) {
911 const loaded = try self.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), "");858 const alignment = arg_ty.abiAlignment(zcu).toLlvm();
912 try llvm_args.append(loaded);859 const loaded = try fg.wip.load(.normal, int_llvm_ty, arg_val, alignment, "");
913 },860 try llvm_args.append(fg.gpa, loaded);
914 };861 } else {
862 // LLVM does not allow bitcasting structs so we must allocate
863 // a local, store as one type, and then load as another type.
864 const alignment = arg_ty.abiAlignment(zcu).toLlvm();
865 const ptr = try fg.buildAlloca(int_llvm_ty, alignment);
866 try fg.store(ptr, .none, arg_val, arg_ty, .normal);
867 const loaded = try fg.wip.load(.normal, int_llvm_ty, ptr, alignment, "");
868 try llvm_args.append(fg.gpa, loaded);
869 }
870 },
871 .slice => {
872 const ptr = try fg.wip.extractValue(arg_val, &.{0}, "");
873 const len = try fg.wip.extractValue(arg_val, &.{1}, "");
874 try llvm_args.appendSlice(fg.gpa, &.{ ptr, len });
875 },
876 .multiple_llvm_types => {
877 const arg_alignment = arg_ty.abiAlignment(zcu);
878 const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8);
879 const arg_ptr = try fg.buildAlloca(llvm_ty, arg_alignment.toLlvm());
880 try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal);
881
882 try llvm_args.ensureUnusedCapacity(fg.gpa, it.types_len);
883 for (it.types_buffer[0..it.types_len], it.offsets_buffer[0..it.types_len]) |field_ty, offset| {
884 const field_ptr = try fg.ptraddConst(arg_ptr, offset);
885 const loaded = try fg.wip.load(.normal, field_ty, field_ptr, arg_alignment.offset(offset).toLlvm(), "");
886 llvm_args.appendAssumeCapacity(loaded);
887 }
888 },
889 .float_array => |count| {
890 const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: {
891 const ptr = try fg.buildZigAlloca(arg_ty, .none);
892 try fg.store(ptr, .none, arg_val, arg_ty, .normal);
893 break :ptr ptr;
894 } else arg_val;
895
896 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .in_memory);
897 const array_ty = try o.builder.arrayType(count, float_ty);
898
899 const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), "");
900 try llvm_args.append(fg.gpa, loaded);
901 },
902 .i32_array, .i64_array => |arr_len| {
903 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
904
905 const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: {
906 const ptr = try fg.buildZigAlloca(arg_ty, .none);
907 try fg.store(ptr, .none, arg_val, arg_ty, .normal);
908 break :ptr ptr;
909 } else arg_val;
910
911 const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
912 const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), "");
913 try llvm_args.append(fg.gpa, loaded);
914 },
915 }
916 }
915917
916 const cc_info = llvm.toLlvmCallConv(fn_info.cc, target).?;918 const cc_info = llvm.toLlvmCallConv(fn_info.cc, target).?;
917919
918 {920 {
919 // Add argument attributes.921 // Add argument attributes.
920 it = iterateParamTypes(o, fn_info);922 it = iterateParamTypes(o, fn_info.cc, fn_info.param_types);
921 it.llvm_index += @intFromBool(ret_strat == .sret);923 it.llvm_index += @intFromBool(ret_strat == .sret);
922 it.llvm_index += @intFromBool(err_return_tracing);924 it.llvm_index += @intFromBool(err_return_tracing);
923 var remaining_inreg_int = cc_info.inreg_int_params;925 var remaining_inreg_int = cc_info.inreg_int_params;
...@@ -925,7 +927,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -925,7 +927,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
925 while (try it.next()) |lowering| switch (lowering) {927 while (try it.next()) |lowering| switch (lowering) {
926 .byval => {928 .byval => {
927 const param_index = it.zig_index - 1;929 const param_index = it.zig_index - 1;
928 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);930 const param_ty = Type.fromInterned(fn_info.param_types[param_index]);
929 if (!isByRef(param_ty, zcu)) {931 if (!isByRef(param_ty, zcu)) {
930 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);932 try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
931 }933 }
...@@ -947,7 +949,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -947,7 +949,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
947 },949 },
948 .byref => {950 .byref => {
949 const param_index = it.zig_index - 1;951 const param_index = it.zig_index - 1;
950 const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]);952 const param_ty: Type = .fromInterned(fn_info.param_types[param_index]);
951 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty);953 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty);
952 },954 },
953 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),955 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
...@@ -962,7 +964,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -962,7 +964,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
962964
963 .slice => {965 .slice => {
964 assert(!it.byval_attr);966 assert(!it.byval_attr);
965 const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);967 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
966 const ptr_info = param_ty.ptrInfo(zcu);968 const ptr_info = param_ty.ptrInfo(zcu);
967 const llvm_arg_i = it.llvm_index - 2;969 const llvm_arg_i = it.llvm_index - 2;
968970
...@@ -989,8 +991,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -989,8 +991,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
989 };991 };
990 }992 }
991993
992 const call = try self.wip.call(994 const call = try fg.wip.call(
993 switch (modifier) {995 switch (opts.modifier) {
994 .auto, .never_inline => .normal,996 .auto, .never_inline => .normal,
995 .never_tail => .notail,997 .never_tail => .notail,
996 .always_tail => .musttail,998 .always_tail => .musttail,
...@@ -998,19 +1000,14 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -998,19 +1000,14 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
998 },1000 },
999 cc_info.llvm_cc,1001 cc_info.llvm_cc,
1000 try attributes.finish(&o.builder),1002 try attributes.finish(&o.builder),
1001 try o.lowerType(zig_fn_ty, .as_value),1003 llvm_fn_ty,
1002 llvm_fn,1004 llvm_fn,
1003 llvm_args.items,1005 llvm_args.items,
1004 "",1006 "",
1005 );1007 );
10061008
1007 if (fn_info.return_type == .noreturn_type and modifier != .always_tail) {1009 if (opts.is_unused) return .none;
1008 return .none;1010 if (fn_info.return_type == .noreturn_type and opts.modifier != .always_tail) return .none;
1009 }
1010
1011 if (self.liveness.isUnused(inst)) {
1012 return .none;
1013 }
10141011
1015 // We exit this `switch` if we have a pointer to the return value.1012 // We exit this `switch` if we have a pointer to the return value.
1016 const ret_val_ptr: Builder.Value = switch (ret_strat) {1013 const ret_val_ptr: Builder.Value = switch (ret_strat) {
...@@ -1020,15 +1017,15 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier...@@ -1020,15 +1017,15 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier
1020 .sret => sret_alloc.?,1017 .sret => sret_alloc.?,
1021 .mem_cast => |llvm_ret_ty| ret_val_ptr: {1018 .mem_cast => |llvm_ret_ty| ret_val_ptr: {
1022 const alignment = return_type.abiAlignment(zcu).toLlvm();1019 const alignment = return_type.abiAlignment(zcu).toLlvm();
1023 const ptr = try self.buildAlloca(llvm_ret_ty, alignment);1020 const ptr = try fg.buildAlloca(llvm_ret_ty, alignment);
1024 _ = try self.wip.store(.normal, call, ptr, alignment);1021 _ = try fg.wip.store(.normal, call, ptr, alignment);
1025 break :ret_val_ptr ptr;1022 break :ret_val_ptr ptr;
1026 },1023 },
1027 };1024 };
1028 if (isByRef(return_type, zcu)) {1025 if (isByRef(return_type, zcu)) {
1029 return ret_val_ptr;1026 return ret_val_ptr;
1030 } else {1027 } else {
1031 return self.load(ret_val_ptr, .none, return_type, .normal);1028 return fg.load(ret_val_ptr, .none, return_type, .normal);
1032 }1029 }
1033}1030}
10341031
...@@ -1067,7 +1064,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo...@@ -1067,7 +1064,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo
10671064
1068 const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?;1065 const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?;
10691066
1070 const ret_strat = try fnReturnStrat(o, fn_info);1067 const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type));
1071 const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false;1068 const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false;
1072 const ret_ty_align = ret_ty.abiAlignment(zcu);1069 const ret_ty_align = ret_ty.abiAlignment(zcu);
10731070
...@@ -1141,7 +1138,7 @@ fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!void {...@@ -1141,7 +1138,7 @@ fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!void {
1141 const ret_ty = ptr_ty.childType(zcu);1138 const ret_ty = ptr_ty.childType(zcu);
1142 const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?;1139 const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?;
1143 const ptr = try self.resolveInst(un_op);1140 const ptr = try self.resolveInst(un_op);
1144 switch (try fnReturnStrat(o, fn_info)) {1141 switch (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type))) {
1145 .void => _ = try self.wip.retVoid(),1142 .void => _ = try self.wip.retVoid(),
1146 .sret => {1143 .sret => {
1147 assert(self.ret_ptr != .none);1144 assert(self.ret_ptr != .none);
...@@ -2028,135 +2025,95 @@ fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder...@@ -2028,135 +2025,95 @@ fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder
2028 return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");2025 return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");
2029}2026}
20302027
2031fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value {2028fn airFloatFromInt(fg: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value {
2032 const o = self.object;2029 const o = fg.object;
2033 const zcu = o.zcu;2030 const zcu = o.zcu;
2034 const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op;2031 const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
20352032
2036 const operand = try self.resolveInst(ty_op.operand);2033 const operand = try fg.resolveInst(ty_op.operand);
2037 const operand_ty = self.typeOf(ty_op.operand);2034 const operand_ty = fg.typeOf(ty_op.operand);
2038 const operand_scalar_ty = operand_ty.scalarType(zcu);2035 const operand_scalar_ty = operand_ty.scalarType(zcu);
2039 const is_signed_int = operand_scalar_ty.isSignedInt(zcu);2036 const operand_scalar_info = operand_scalar_ty.intInfo(zcu);
20402037
2041 const dest_ty = self.typeOfIndex(inst);2038 const dest_ty = fg.typeOfIndex(inst);
2042 const dest_scalar_ty = dest_ty.scalarType(zcu);2039 const dest_scalar_ty = dest_ty.scalarType(zcu);
2043 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);
2044 const target = zcu.getTarget();2040 const target = zcu.getTarget();
20452041
2046 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(2042 if (intrinsicsAllowed(dest_scalar_ty, target))
2047 if (is_signed_int) .signed else .unsigned,2043 return fg.wip.conv(.fromStdLang(operand_scalar_info.signedness), operand, try o.lowerType(dest_ty, .as_value), "");
2048 operand,
2049 dest_llvm_ty,
2050 "",
2051 );
20522044
2053 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(zcu))) orelse {2045 const rt_int_ty = compilerRtPromoteInt(operand_scalar_info) orelse {
2054 return self.todo("float_from_int on {d} bit integer", .{operand_scalar_ty.bitSize(zcu)});2046 return fg.todo("float_from_int on {d} bit integer", .{operand_scalar_info.bits});
2055 };2047 };
2056 const rt_int_ty = try o.builder.intType(rt_int_bits);2048 const vector_len = if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null;
2057 var extended = try self.wip.conv(2049 const rt_llvm_int_ty = try o.lowerType(rt_int_ty, .as_value);
2058 if (is_signed_int) .signed else .unsigned,2050 const extended = try fg.wip.conv(
2051 .fromStdLang(operand_scalar_info.signedness),
2059 operand,2052 operand,
2060 rt_int_ty,2053 if (vector_len) |len|
2054 try o.builder.vectorType(.normal, len, rt_llvm_int_ty)
2055 else
2056 rt_llvm_int_ty,
2061 "",2057 "",
2062 );2058 );
2063 const dest_bits = dest_scalar_ty.floatBits(target);
2064 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
2065 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
2066 const sign_prefix = if (is_signed_int) "" else "un";
2067 const fn_name = try o.builder.strtabStringFmt("__float{s}{s}i{s}f", .{2059 const fn_name = try o.builder.strtabStringFmt("__float{s}{s}i{s}f", .{
2068 sign_prefix,2060 switch (operand_scalar_info.signedness) {
2069 compiler_rt_operand_abbrev,2061 .signed => "",
2070 compiler_rt_dest_abbrev,2062 .unsigned => "un",
2063 },
2064 compilerRtIntAbbrev(rt_int_ty.intInfo(zcu).bits),
2065 compilerRtFloatAbbrev(target, dest_scalar_ty.floatBits(target)),
2071 });2066 });
20722067 return fg.buildElementwiseCall(fn_name, .{
2073 var param_type = rt_int_ty;2068 .cc = target.cCallingConvention().?,
2074 if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) {2069 .param_types = &.{rt_int_ty.toIntern()},
2075 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard2070 .return_type = dest_scalar_ty.toIntern(),
2076 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.2071 }, &.{extended}, vector_len);
2077 param_type = try o.builder.vectorType(.normal, 2, .i64);
2078 extended = try self.wip.cast(.bitcast, extended, param_type, "");
2079 }
2080
2081 const libc_fn = try o.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
2082 return self.wip.call(
2083 .normal,
2084 .ccc,
2085 .none,
2086 libc_fn.typeOf(&o.builder),
2087 libc_fn.toValue(&o.builder),
2088 &.{extended},
2089 "",
2090 );
2091}2072}
20922073
2093fn airIntFromFloat(2074fn airIntFromFloat(
2094 self: *FuncGen,2075 fg: *FuncGen,
2095 inst: Air.Inst.Index,2076 inst: Air.Inst.Index,
2096 fast: Builder.FastMathKind,2077 fast: Builder.FastMathKind,
2097) TodoError!Builder.Value {2078) TodoError!Builder.Value {
2098 _ = fast;2079 _ = fast;
20992080
2100 const o = self.object;2081 const o = fg.object;
2101 const zcu = o.zcu;2082 const zcu = o.zcu;
2102 const target = zcu.getTarget();2083 const target = zcu.getTarget();
2103 const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op;2084 const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
21042085
2105 const operand = try self.resolveInst(ty_op.operand);2086 const operand = try fg.resolveInst(ty_op.operand);
2106 const operand_ty = self.typeOf(ty_op.operand);2087 const operand_ty = fg.typeOf(ty_op.operand);
2107 const operand_scalar_ty = operand_ty.scalarType(zcu);2088 const operand_scalar_ty = operand_ty.scalarType(zcu);
21082089
2109 const dest_ty = self.typeOfIndex(inst);2090 const dest_ty = fg.typeOfIndex(inst);
2110 const dest_scalar_ty = dest_ty.scalarType(zcu);2091 const dest_scalar_ty = dest_ty.scalarType(zcu);
2111 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);2092 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);
2093 const dest_scalar_info = dest_scalar_ty.intInfo(zcu);
21122094
2113 if (intrinsicsAllowed(operand_scalar_ty, target)) {2095 if (intrinsicsAllowed(operand_scalar_ty, target)) {
2114 // TODO set fast math flag2096 // TODO set fast math flag
2115 return self.wip.conv(2097 return fg.wip.conv(.fromStdLang(dest_scalar_info.signedness), operand, dest_llvm_ty, "");
2116 if (dest_scalar_ty.isSignedInt(zcu)) .signed else .unsigned,
2117 operand,
2118 dest_llvm_ty,
2119 "",
2120 );
2121 }2098 }
21222099
2123 const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(zcu))) orelse {2100 const rt_int_ty = compilerRtPromoteInt(dest_scalar_info) orelse {
2124 return self.todo("int_from_float to {d} bit integer", .{dest_scalar_ty.bitSize(zcu)});2101 return fg.todo("int_from_float to {d} bit integer", .{dest_scalar_info.bits});
2125 };2102 };
2126 const ret_ty = try o.builder.intType(rt_int_bits);
2127 const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: {
2128 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
2129 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
2130 break :b try o.builder.vectorType(.normal, 2, .i64);
2131 } else ret_ty;
2132
2133 const operand_bits = operand_scalar_ty.floatBits(target);
2134 const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits);
2135
2136 const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits);
2137 const sign_prefix = if (dest_scalar_ty.isSignedInt(zcu)) "" else "uns";
2138
2139 const fn_name = try o.builder.strtabStringFmt("__fix{s}{s}f{s}i", .{2103 const fn_name = try o.builder.strtabStringFmt("__fix{s}{s}f{s}i", .{
2140 sign_prefix,2104 switch (dest_scalar_info.signedness) {
2141 compiler_rt_operand_abbrev,2105 .signed => "",
2142 compiler_rt_dest_abbrev,2106 .unsigned => "uns",
2107 },
2108 compilerRtFloatAbbrev(target, operand_scalar_ty.floatBits(target)),
2109 compilerRtIntAbbrev(rt_int_ty.intInfo(zcu).bits),
2143 });2110 });
21442111 const result = try fg.buildElementwiseCall(fn_name, .{
2145 const operand_llvm_ty = try o.lowerType(operand_ty, .as_value);2112 .cc = target.cCallingConvention().?,
2146 const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);2113 .param_types = &.{operand_scalar_ty.toIntern()},
2147 var result = try self.wip.call(2114 .return_type = rt_int_ty.toIntern(),
2148 .normal,2115 }, &.{operand}, if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null);
2149 .ccc,2116 return fg.wip.cast(.trunc, result, try o.lowerType(dest_ty, .as_value), "");
2150 .none,
2151 libc_fn.typeOf(&o.builder),
2152 libc_fn.toValue(&o.builder),
2153 &.{operand},
2154 "",
2155 );
2156
2157 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
2158 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
2159 return result;
2160}2117}
21612118
2162fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value {2119fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value {
...@@ -3692,15 +3649,17 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo...@@ -3692,15 +3649,17 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo
3692 const lhs = try self.resolveInst(bin_op.lhs);3649 const lhs = try self.resolveInst(bin_op.lhs);
3693 const rhs = try self.resolveInst(bin_op.rhs);3650 const rhs = try self.resolveInst(bin_op.rhs);
3694 const inst_ty = self.typeOfIndex(inst);3651 const inst_ty = self.typeOfIndex(inst);
3695 const inst_llvm_ty = try o.lowerType(inst_ty, .as_value);
3696 const scalar_ty = inst_ty.scalarType(zcu);3652 const scalar_ty = inst_ty.scalarType(zcu);
36973653
3698 if (scalar_ty.isRuntimeFloat()) {3654 if (scalar_ty.isRuntimeFloat()) {
3699 const a = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ lhs, rhs });3655 const a = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ lhs, rhs });
3700 const b = try self.buildFloatOp(.add, fast, inst_ty, 2, .{ a, rhs });3656 const b = try self.buildFloatOp(.add, fast, inst_ty, 2, .{ a, rhs });
3701 const c = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ b, rhs });3657 const c = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ b, rhs });
3702 const zero = try o.builder.zeroInitValue(inst_llvm_ty);3658 const zero = if (isByRef(inst_ty, zcu)) zero: {
3703 const ltz = try self.buildFloatCmp(fast, .lt, inst_ty, .{ lhs, zero });3659 const zero = try o.builder.zeroInitConst(try o.lowerType(inst_ty, .in_memory));
3660 break :zero try o.lowerConstRef(zero, inst_ty.abiAlignment(zcu).toLlvm());
3661 } else try o.builder.zeroInitConst(try o.lowerType(inst_ty, .as_value));
3662 const ltz = try self.buildFloatCmp(fast, .lt, inst_ty, .{ lhs, zero.toValue() });
3704 return self.wip.select(fast, ltz, c, a, "");3663 return self.wip.select(fast, ltz, c, a, "");
3705 }3664 }
3706 if (scalar_ty.isSignedInt(zcu)) {3665 if (scalar_ty.isSignedInt(zcu)) {
...@@ -3709,6 +3668,7 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo...@@ -3709,6 +3668,7 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo
3709 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa);3668 var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa);
3710 const allocator = bfa.allocator();3669 const allocator = bfa.allocator();
37113670
3671 const inst_llvm_ty = try o.lowerType(inst_ty, .as_value);
3712 const scalar_bits = scalar_ty.intInfo(zcu).bits;3672 const scalar_bits = scalar_ty.intInfo(zcu).bits;
3713 var smin_big_int: std.math.big.int.Mutable = .{3673 var smin_big_int: std.math.big.int.Mutable = .{
3714 .limbs = try allocator.alloc(3674 .limbs = try allocator.alloc(
...@@ -3818,34 +3778,97 @@ fn airOverflow(...@@ -3818,34 +3778,97 @@ fn airOverflow(
3818}3778}
38193779
3820fn buildElementwiseCall(3780fn buildElementwiseCall(
3821 self: *FuncGen,3781 fg: *FuncGen,
3822 llvm_fn: Builder.Function.Index,3782 fn_name: Builder.StrtabString,
3823 args_vectors: []const Builder.Value,3783 fn_info: Object.FuncInfo,
3824 result_vector: Builder.Value,3784 arg_values: []const Builder.Value,
3825 vector_len: usize,3785 vector_len: ?u32,
3826) Allocator.Error!Builder.Value {3786) Allocator.Error!Builder.Value {
3827 const o = self.object;3787 const o = fg.object;
3828 assert(args_vectors.len <= 3);3788 const zcu = o.zcu;
3789 const llvm_fn = try fg.object.getLibcFunction(fg.pt, fn_name, fn_info);
38293790
3830 var i: usize = 0;3791 const iterations = vector_len orelse 1;
3831 var result = result_vector;3792 const ret_ty: Type = .fromInterned(fn_info.return_type);
3832 while (i < vector_len) : (i += 1) {3793 const ret_is_by_ref = isByRef(ret_ty, zcu);
3833 const index_i32 = try o.builder.intValue(.i32, i);3794 if (iterations > 1 and (fn_info.return_type == .void_type or ret_is_by_ref) and
3795 for (fn_info.param_types) |param_type| {
3796 if (!isByRef(.fromInterned(param_type), zcu)) break false;
3797 } else true)
3798 {
3799 const entry_block = fg.wip.cursor.block;
3800 const loop_block = try fg.wip.block(2, "elementwise.loop");
3801 const done_block = try fg.wip.block(1, "elementwise.done");
3802
3803 const result_ptr = if (fn_info.return_type == .void_type) .none else result_ptr: {
3804 const ret_llvm_ty = try o.lowerType(ret_ty, .in_memory);
3805 break :result_ptr try fg.buildAlloca(
3806 if (vector_len) |len| try o.builder.arrayType(len, ret_llvm_ty) else ret_llvm_ty,
3807 ret_ty.abiAlignment(zcu).toLlvm(),
3808 );
3809 };
3810 _ = try fg.wip.br(loop_block);
38343811
3835 var args: [3]Builder.Value = undefined;3812 fg.wip.cursor = .{ .block = loop_block };
3836 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {3813 const index = try fg.wip.phi(.i32, "elementwise.index");
3837 arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, "");3814
3815 var arg_elems_buf: [3]Builder.Value = undefined;
3816 const arg_elems = arg_elems_buf[0..arg_values.len];
3817 for (arg_elems, fn_info.param_types, arg_values) |*arg_elem, param_type, arg_value| {
3818 const arg_elem_ptr = try fg.ptraddScaled(arg_value, index.toValue(), Type.fromInterned(param_type).abiSize(zcu));
3819 arg_elem.* = try fg.load(arg_elem_ptr, .none, .fromInterned(param_type), .normal);
3838 }3820 }
3839 const result_elem = try self.wip.call(3821 const result_elem = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, arg_elems);
3840 .normal,3822 if (fn_info.return_type == .void_type) {
3841 .ccc,3823 assert(result_elem == .none);
3842 .none,3824 } else if (result_elem != .none) {
3843 llvm_fn.typeOf(&o.builder),3825 const result_elem_ptr = try fg.ptraddScaled(result_ptr, index.toValue(), ret_ty.abiSize(zcu));
3844 llvm_fn.toValue(&o.builder),3826 try fg.store(result_elem_ptr, .none, result_elem, ret_ty, .normal);
3845 args[0..args_vectors.len],3827 }
3846 "",3828
3829 const next_index = try fg.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(.i32, 1), "elementwise.next_index");
3830 index.finish(&.{ try o.builder.intValue(.i32, 0), next_index }, &.{ entry_block, loop_block }, &fg.wip);
3831 const is_done = try fg.wip.icmp(.eq, next_index, try o.builder.intValue(.i32, iterations), "elementwise.is_done");
3832 _ = try fg.wip.brCond(is_done, done_block, loop_block, .none);
3833
3834 fg.wip.cursor = .{ .block = done_block };
3835 return result_ptr;
3836 }
3837
3838 var result = if (fn_info.return_type == .void_type) .none else if (ret_is_by_ref) result: {
3839 const ret_llvm_ty = try o.lowerType(ret_ty, .in_memory);
3840 break :result try fg.buildAlloca(
3841 if (vector_len) |len| try o.builder.arrayType(len, ret_llvm_ty) else ret_llvm_ty,
3842 ret_ty.abiAlignment(zcu).toLlvm(),
3847 );3843 );
3848 result = try self.wip.insertElement(result, result_elem, index_i32, "");3844 } else if (vector_len) |len| try o.builder.poisonValue(
3845 try o.builder.vectorType(.normal, len, try o.lowerType(ret_ty, .as_value)),
3846 ) else .none;
3847 for (0..iterations) |index| {
3848 const index_value = try o.builder.intValue(.i32, index);
3849 var arg_elems_buf: [3]Builder.Value = undefined;
3850 const arg_elems = arg_elems_buf[0..arg_values.len];
3851 for (arg_elems, fn_info.param_types, arg_values) |*arg_elem_value, param_type, arg_value| {
3852 const arg_ty: Type = .fromInterned(param_type);
3853 if (isByRef(arg_ty, zcu)) {
3854 const arg_elem_ptr = try fg.ptraddConst(arg_value, index * arg_ty.abiSize(zcu));
3855 arg_elem_value.* = try fg.load(arg_elem_ptr, .none, .fromInterned(param_type), .normal);
3856 } else if (vector_len) |_| {
3857 arg_elem_value.* = try fg.wip.extractElement(arg_value, index_value, "elementwise.arg_elem");
3858 } else arg_elem_value.* = arg_value;
3859 }
3860 const result_elem = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, arg_elems);
3861 if (fn_info.return_type == .void_type) {
3862 assert(result_elem == .none);
3863 } else if (ret_is_by_ref) {
3864 const result_elem_ptr = try fg.ptraddConst(result, index * ret_ty.abiSize(zcu));
3865 try fg.store(result_elem_ptr, .none, result_elem, ret_ty, .normal);
3866 } else if (vector_len) |_| {
3867 result = try fg.wip.insertElement(result, result_elem, index_value, "elementwise.result");
3868 } else {
3869 assert(result == .none);
3870 result = result_elem;
3871 }
3849 }3872 }
3850 return result;3873 return result;
3851}3874}
...@@ -3853,17 +3876,16 @@ fn buildElementwiseCall(...@@ -3853,17 +3876,16 @@ fn buildElementwiseCall(
3853/// Creates a floating point comparison by lowering to the appropriate3876/// Creates a floating point comparison by lowering to the appropriate
3854/// hardware instruction or softfloat routine for the target3877/// hardware instruction or softfloat routine for the target
3855fn buildFloatCmp(3878fn buildFloatCmp(
3856 self: *FuncGen,3879 fg: *FuncGen,
3857 fast: Builder.FastMathKind,3880 fast: Builder.FastMathKind,
3858 pred: math.CompareOperator,3881 pred: math.CompareOperator,
3859 ty: Type,3882 ty: Type,
3860 params: [2]Builder.Value,3883 params: [2]Builder.Value,
3861) Allocator.Error!Builder.Value {3884) Allocator.Error!Builder.Value {
3862 const o = self.object;3885 const o = fg.object;
3863 const zcu = o.zcu;3886 const zcu = o.zcu;
3864 const target = zcu.getTarget();3887 const target = zcu.getTarget();
3865 const scalar_ty = ty.scalarType(zcu);3888 const scalar_ty = ty.scalarType(zcu);
3866 const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value);
38673889
3868 if (intrinsicsAllowed(scalar_ty, target)) {3890 if (intrinsicsAllowed(scalar_ty, target)) {
3869 const cond: Builder.FloatCondition = switch (pred) {3891 const cond: Builder.FloatCondition = switch (pred) {
...@@ -3874,53 +3896,33 @@ fn buildFloatCmp(...@@ -3874,53 +3896,33 @@ fn buildFloatCmp(
3874 .gt => .ogt,3896 .gt => .ogt,
3875 .gte => .oge,3897 .gte => .oge,
3876 };3898 };
3877 return self.wip.fcmp(fast, cond, params[0], params[1], "");3899 return fg.wip.fcmp(fast, cond, params[0], params[1], "");
3878 }3900 }
38793901
3880 const float_bits = scalar_ty.floatBits(target);3902 const fn_name = try o.builder.strtabStringFmt("__{s}{s}f2", .{
3881 const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits);3903 switch (pred) {
3882 const fn_base_name = switch (pred) {3904 .neq => "ne",
3883 .neq => "ne",3905 .eq => "eq",
3884 .eq => "eq",3906 .lt => "lt",
3885 .lt => "lt",3907 .lte => "le",
3886 .lte => "le",3908 .gt => "gt",
3887 .gt => "gt",3909 .gte => "ge",
3888 .gte => "ge",3910 },
3889 };3911 compilerRtFloatAbbrev(target, scalar_ty.floatBits(target)),
3890 const fn_name = try o.builder.strtabStringFmt("__{s}{s}f2", .{ fn_base_name, compiler_rt_float_abbrev });3912 });
38913913 const result = try fg.buildElementwiseCall(fn_name, .{
3892 const libc_fn = try o.getLibcFunction(fn_name, &.{ scalar_llvm_ty, scalar_llvm_ty }, .i32);3914 .cc = target.cCallingConvention().?,
38933915 .param_types = &.{ scalar_ty.toIntern(), scalar_ty.toIntern() },
3894 const int_cond: Builder.IntegerCondition = switch (pred) {3916 .return_type = .i32_type,
3917 }, &params, if (ty.isVector(zcu)) ty.vectorLen(zcu) else null);
3918 return fg.wip.icmp(switch (pred) {
3895 .eq => .eq,3919 .eq => .eq,
3896 .neq => .ne,3920 .neq => .ne,
3897 .lt => .slt,3921 .lt => .slt,
3898 .lte => .sle,3922 .lte => .sle,
3899 .gt => .sgt,3923 .gt => .sgt,
3900 .gte => .sge,3924 .gte => .sge,
3901 };3925 }, result, try o.builder.splatValue(result.typeOfWip(&fg.wip), .@"0"), "");
3902
3903 if (ty.zigTypeTag(zcu) == .vector) {
3904 const vec_len = ty.vectorLen(zcu);
3905 const vector_result_ty = try o.builder.vectorType(.normal, vec_len, .i32);
3906
3907 const init = try o.builder.poisonValue(vector_result_ty);
3908 const result = try self.buildElementwiseCall(libc_fn, &params, init, vec_len);
3909
3910 const zero_vector = try o.builder.splatValue(vector_result_ty, .@"0");
3911 return self.wip.icmp(int_cond, result, zero_vector, "");
3912 }
3913
3914 const result = try self.wip.call(
3915 .normal,
3916 .ccc,
3917 .none,
3918 libc_fn.typeOf(&o.builder),
3919 libc_fn.toValue(&o.builder),
3920 &params,
3921 "",
3922 );
3923 return self.wip.icmp(int_cond, result, .@"0", "");
3924}3926}
39253927
3926const FloatOp = enum {3928const FloatOp = enum {
...@@ -3949,32 +3951,26 @@ const FloatOp = enum {...@@ -3949,32 +3951,26 @@ const FloatOp = enum {
3949 trunc,3951 trunc,
3950};3952};
39513953
3952const FloatOpStrat = union(enum) {
3953 intrinsic: []const u8,
3954 libc: Builder.String,
3955};
3956
3957/// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)3954/// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.)
3958/// by lowering to the appropriate hardware instruction or softfloat3955/// by lowering to the appropriate hardware instruction or softfloat
3959/// routine for the target3956/// routine for the target
3960fn buildFloatOp(3957fn buildFloatOp(
3961 self: *FuncGen,3958 fg: *FuncGen,
3962 comptime op: FloatOp,3959 comptime op: FloatOp,
3963 fast: Builder.FastMathKind,3960 fast: Builder.FastMathKind,
3964 ty: Type,3961 ty: Type,
3965 comptime params_len: usize,3962 comptime params_len: usize,
3966 params: [params_len]Builder.Value,3963 params: [params_len]Builder.Value,
3967) Allocator.Error!Builder.Value {3964) Allocator.Error!Builder.Value {
3968 const o = self.object;3965 const o = fg.object;
3969 const zcu = o.zcu;3966 const zcu = o.zcu;
3970 const target = zcu.getTarget();3967 const target = zcu.getTarget();
3971 const scalar_ty = ty.scalarType(zcu);3968 const scalar_ty = ty.scalarType(zcu);
3972 const llvm_ty = try o.lowerType(ty, .as_value);
39733969
3974 if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) {3970 if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) {
3975 // Some operations are dedicated LLVM instructions, not available as intrinsics3971 // Some operations are dedicated LLVM instructions, not available as intrinsics
3976 .neg => return self.wip.un(.fneg, params[0], ""),3972 .neg => return fg.wip.un(.fneg, params[0], ""),
3977 .add, .sub, .mul, .div, .fmod => return self.wip.bin(switch (fast) {3973 .add, .sub, .mul, .div, .fmod => return fg.wip.bin(switch (fast) {
3978 .normal => switch (op) {3974 .normal => switch (op) {
3979 .add => .fadd,3975 .add => .fadd,
3980 .sub => .fsub,3976 .sub => .fsub,
...@@ -4008,7 +4004,7 @@ fn buildFloatOp(...@@ -4008,7 +4004,7 @@ fn buildFloatOp(
4008 .sqrt,4004 .sqrt,
4009 .trunc,4005 .trunc,
4010 .fma,4006 .fma,
4011 => return self.wip.callIntrinsic(fast, .none, switch (op) {4007 => return fg.wip.callIntrinsic(fast, .none, switch (op) {
4012 .fmax => .maxnum,4008 .fmax => .maxnum,
4013 .fmin => .minnum,4009 .fmin => .minnum,
4014 .ceil => .ceil,4010 .ceil => .ceil,
...@@ -4026,36 +4022,152 @@ fn buildFloatOp(...@@ -4026,36 +4022,152 @@ fn buildFloatOp(
4026 .trunc => .trunc,4022 .trunc => .trunc,
4027 .fma => .fma,4023 .fma => .fma,
4028 else => unreachable,4024 else => unreachable,
4029 }, &.{llvm_ty}, &params, ""),4025 }, &.{try o.lowerType(ty, .as_value)}, &params, ""),
4030 .tan => unreachable,4026 .tan => unreachable,
4031 };4027 };
40324028
4033 const float_bits = scalar_ty.floatBits(target);4029 const float_bits = scalar_ty.floatBits(target);
4034 const fn_name = switch (op) {4030 const fn_name = switch (op) {
4035 .neg => {4031 // In these cases we can generate a softfloat operation by modifying the sign bit using a bitwise operation.
4036 // In this case we can generate a softfloat negation by XORing the4032 .neg, .fabs => if (isByRef(scalar_ty, zcu)) {
4037 // bits with a constant.4033 const is_vector = ty.toIntern() != scalar_ty.toIntern();
4034 const result_ptr = try fg.buildZigAlloca(ty, .none);
4035 const entry_block = fg.wip.cursor.block;
4036 const loop_block, const done_block, const llvm_usize_ty, const offset, const elem, const result_elem = if (is_vector) loop: {
4037 const loop_block = try fg.wip.block(2, "neg_fabs.loop");
4038 const done_block = try fg.wip.block(1, "neg_fabs.done");
4039 _ = try fg.wip.br(loop_block);
4040
4041 fg.wip.cursor = .{ .block = loop_block };
4042 const llvm_usize_ty = try o.lowerType(.usize, .as_value);
4043 const offset = try fg.wip.phi(llvm_usize_ty, "neg_fabs.offset");
4044 break :loop .{
4045 loop_block,
4046 done_block,
4047 llvm_usize_ty,
4048 offset,
4049 try fg.ptraddScaled(params[0], offset.toValue(), 1),
4050 try fg.ptraddScaled(result_ptr, offset.toValue(), 1),
4051 };
4052 } else .{ undefined, undefined, undefined, undefined, params[0], result_ptr };
4053 switch (scalar_ty.floatBits(target)) {
4054 else => unreachable,
4055 80 => {
4056 const f80_layout = o.softF80Layout(.{}) catch unreachable;
4057 const mantissa = try fg.load(
4058 try fg.ptraddConst(elem, f80_layout.mantissa_offset),
4059 f80_layout.alignment.offset(f80_layout.mantissa_offset),
4060 .u64,
4061 .normal,
4062 );
4063 const exponent = try fg.load(
4064 try fg.ptraddConst(elem, f80_layout.exponent_offset),
4065 f80_layout.alignment.offset(f80_layout.exponent_offset),
4066 .u16,
4067 .normal,
4068 );
4069 const exponent_sign_bit: u16 = 1 << (16 - 1);
4070 const updated_exponent = try fg.wip.bin(switch (op) {
4071 else => unreachable,
4072 .neg => .xor,
4073 .fabs => .@"and",
4074 }, exponent, try o.builder.intValue(.i16, switch (op) {
4075 else => unreachable,
4076 .neg => exponent_sign_bit,
4077 .fabs => exponent_sign_bit - 1,
4078 }), "neg_fabs.updated_exponent");
4079 try fg.store(
4080 try fg.ptraddConst(result_elem, f80_layout.mantissa_offset),
4081 f80_layout.alignment.offset(f80_layout.mantissa_offset),
4082 mantissa,
4083 .u64,
4084 .normal,
4085 );
4086 try fg.store(
4087 try fg.ptraddConst(result_elem, f80_layout.exponent_offset),
4088 f80_layout.alignment.offset(f80_layout.exponent_offset),
4089 updated_exponent,
4090 .u16,
4091 .normal,
4092 );
4093 },
4094 128 => {
4095 const f128_layout = o.softF128Layout(.{}) catch unreachable;
4096 const lo = try fg.load(
4097 try fg.ptraddConst(elem, f128_layout.lo_offset),
4098 f128_layout.alignment.offset(f128_layout.lo_offset),
4099 .u64,
4100 .normal,
4101 );
4102 const hi = try fg.load(
4103 try fg.ptraddConst(elem, f128_layout.hi_offset),
4104 f128_layout.alignment.offset(f128_layout.hi_offset),
4105 .u64,
4106 .normal,
4107 );
4108 const hi_sign_bit: u64 = 1 << (64 - 1);
4109 const updated_hi = try fg.wip.bin(switch (op) {
4110 else => unreachable,
4111 .neg => .xor,
4112 .fabs => .@"and",
4113 }, hi, try o.builder.intValue(.i64, switch (op) {
4114 else => unreachable,
4115 .neg => hi_sign_bit,
4116 .fabs => hi_sign_bit - 1,
4117 }), "neg_fabs.updated_hi");
4118 try fg.store(
4119 try fg.ptraddConst(result_elem, f128_layout.lo_offset),
4120 f128_layout.alignment.offset(f128_layout.lo_offset),
4121 lo,
4122 .u64,
4123 .normal,
4124 );
4125 try fg.store(
4126 try fg.ptraddConst(result_elem, f128_layout.hi_offset),
4127 f128_layout.alignment.offset(f128_layout.hi_offset),
4128 updated_hi,
4129 .u64,
4130 .normal,
4131 );
4132 },
4133 }
4134 if (is_vector) {
4135 const next_offset = try fg.wip.bin(.@"add nuw", offset.toValue(), try o.builder.intValue(llvm_usize_ty, scalar_ty.abiSize(zcu)), "neg_fabs.next_offset");
4136 offset.finish(&.{ try o.builder.intValue(llvm_usize_ty, 0), next_offset }, &.{ entry_block, loop_block }, &fg.wip);
4137 const is_done = try fg.wip.icmp(.eq, next_offset, try o.builder.intValue(llvm_usize_ty, ty.abiSize(zcu)), "neg_fabs.is_done");
4138 _ = try fg.wip.brCond(is_done, done_block, loop_block, .none);
4139
4140 fg.wip.cursor = .{ .block = done_block };
4141 }
4142 return result_ptr;
4143 } else {
4038 const int_ty = try o.builder.intType(@intCast(float_bits));4144 const int_ty = try o.builder.intType(@intCast(float_bits));
4039 const cast_ty = switch (ty.zigTypeTag(zcu)) {4145 const cast_ty = switch (ty.zigTypeTag(zcu)) {
4040 .vector => try o.builder.vectorType(.normal, ty.vectorLen(zcu), int_ty),4146 .vector => try o.builder.vectorType(.normal, ty.vectorLen(zcu), int_ty),
4041 else => int_ty,4147 else => int_ty,
4042 };4148 };
4043 const sign_mask = try o.builder.splatValue(4149 const sign_bit = @as(u128, 1) << @intCast(float_bits - 1);
4044 cast_ty,4150 const bitwise_rhs = try o.builder.splatValue(cast_ty, try o.builder.intConst(int_ty, switch (op) {
4045 try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),4151 else => unreachable,
4046 );4152 .neg => sign_bit,
4047 const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");4153 .fabs => sign_bit - 1,
4048 const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");4154 }));
4049 return self.wip.cast(.bitcast, result, llvm_ty, "");4155 const bitcasted_operand = try fg.wip.cast(.bitcast, params[0], cast_ty, "");
4156 const result = try fg.wip.bin(switch (op) {
4157 else => unreachable,
4158 .neg => .xor,
4159 .fabs => .@"and",
4160 }, bitcasted_operand, bitwise_rhs, "");
4161 const llvm_ty = try o.lowerType(ty, .as_value);
4162 return fg.wip.cast(.bitcast, result, llvm_ty, "");
4050 },4163 },
4051 .add, .sub, .div, .mul => try o.builder.strtabStringFmt("__{s}{s}f3", .{4164 .add, .sub, .div, .mul => try o.builder.strtabStringFmt("__{s}{s}f3", .{
4052 @tagName(op), compilerRtFloatAbbrev(float_bits),4165 @tagName(op), compilerRtFloatAbbrev(target, float_bits),
4053 }),4166 }),
4054 .ceil,4167 .ceil,
4055 .cos,4168 .cos,
4056 .exp,4169 .exp,
4057 .exp2,4170 .exp2,
4058 .fabs,
4059 .floor,4171 .floor,
4060 .fma,4172 .fma,
4061 .fmax,4173 .fmax,
...@@ -4073,27 +4185,27 @@ fn buildFloatOp(...@@ -4073,27 +4185,27 @@ fn buildFloatOp(
4073 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),4185 libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits),
4074 }),4186 }),
4075 };4187 };
4188 return fg.buildElementwiseCall(fn_name, .{
4189 .cc = target.cCallingConvention().?,
4190 .param_types = &@as([params_len]InternPool.Index, @splat(scalar_ty.toIntern())),
4191 .return_type = scalar_ty.toIntern(),
4192 }, &params, if (ty.isVector(zcu)) ty.vectorLen(zcu) else null);
4193}
40764194
4077 const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value);4195/// Creates a floating point cast operation by lowering to the specified softfloat routine.
4078 const libc_fn = try o.getLibcFunction(4196fn buildFloatCastCall(
4079 fn_name,4197 fg: *FuncGen,
4080 @as([3]Builder.Type, @splat(scalar_llvm_ty))[0..params.len],4198 dest_ty: Type,
4081 scalar_llvm_ty,4199 fn_name: Builder.StrtabString,
4082 );4200 operand_ty: Type,
4083 if (ty.zigTypeTag(zcu) == .vector) {4201 operand: Builder.Value,
4084 const result = try o.builder.poisonValue(llvm_ty);4202) Allocator.Error!Builder.Value {
4085 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(zcu));4203 const zcu = fg.object.zcu;
4086 }4204 return fg.buildElementwiseCall(fn_name, .{
40874205 .cc = zcu.getTarget().cCallingConvention().?,
4088 return self.wip.call(4206 .param_types = &.{operand_ty.scalarType(zcu).toIntern()},
4089 fast.toCallKind(),4207 .return_type = dest_ty.scalarType(zcu).toIntern(),
4090 .ccc,4208 }, &.{operand}, if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null);
4091 .none,
4092 libc_fn.typeOf(&o.builder),
4093 libc_fn.toValue(&o.builder),
4094 &params,
4095 "",
4096 );
4097}4209}
40984210
4099fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {4211fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
...@@ -4471,32 +4583,19 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu...@@ -4471,32 +4583,19 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu
4471 const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op;4583 const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op;
4472 const operand = try self.resolveInst(ty_op.operand);4584 const operand = try self.resolveInst(ty_op.operand);
4473 const operand_ty = self.typeOf(ty_op.operand);4585 const operand_ty = self.typeOf(ty_op.operand);
4586 const operand_scalar_ty = operand_ty.scalarType(zcu);
4474 const dest_ty = self.typeOfIndex(inst);4587 const dest_ty = self.typeOfIndex(inst);
4588 const dest_scalar_ty = dest_ty.scalarType(zcu);
4475 const target = zcu.getTarget();4589 const target = zcu.getTarget();
44764590
4477 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {4591 if (intrinsicsAllowed(dest_scalar_ty, target) and intrinsicsAllowed(operand_scalar_ty, target))
4478 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), "");4592 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), "");
4479 } else {4593 const dest_bits = dest_scalar_ty.floatBits(target);
4480 const operand_llvm_ty = try o.lowerType(operand_ty, .as_value);4594 const src_bits = operand_scalar_ty.floatBits(target);
4481 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);4595 const fn_name = try o.builder.strtabStringFmt("__trunc{s}f{s}f2", .{
44824596 compilerRtFloatAbbrev(target, src_bits), compilerRtFloatAbbrev(target, dest_bits),
4483 const dest_bits = dest_ty.floatBits(target);4597 });
4484 const src_bits = operand_ty.floatBits(target);4598 return self.buildFloatCastCall(dest_ty, fn_name, operand_ty, operand);
4485 const fn_name = try o.builder.strtabStringFmt("__trunc{s}f{s}f2", .{
4486 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
4487 });
4488
4489 const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
4490 return self.wip.call(
4491 .normal,
4492 .ccc,
4493 .none,
4494 libc_fn.typeOf(&o.builder),
4495 libc_fn.toValue(&o.builder),
4496 &.{operand},
4497 "",
4498 );
4499 }
4500}4599}
45014600
4502fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {4601fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
...@@ -4505,38 +4604,19 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value...@@ -4505,38 +4604,19 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value
4505 const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op;4604 const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op;
4506 const operand = try self.resolveInst(ty_op.operand);4605 const operand = try self.resolveInst(ty_op.operand);
4507 const operand_ty = self.typeOf(ty_op.operand);4606 const operand_ty = self.typeOf(ty_op.operand);
4607 const operand_scalar_ty = operand_ty.scalarType(zcu);
4508 const dest_ty = self.typeOfIndex(inst);4608 const dest_ty = self.typeOfIndex(inst);
4609 const dest_scalar_ty = dest_ty.scalarType(zcu);
4509 const target = zcu.getTarget();4610 const target = zcu.getTarget();
45104611
4511 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {4612 if (intrinsicsAllowed(dest_scalar_ty, target) and intrinsicsAllowed(operand_scalar_ty, target))
4512 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), "");4613 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), "");
4513 } else {4614 const dest_bits = dest_scalar_ty.floatBits(target);
4514 const operand_llvm_ty = try o.lowerType(operand_ty, .as_value);4615 const src_bits = operand_scalar_ty.floatBits(target);
4515 const dest_llvm_ty = try o.lowerType(dest_ty, .as_value);4616 const fn_name = try o.builder.strtabStringFmt("__extend{s}f{s}f2", .{
45164617 compilerRtFloatAbbrev(target, src_bits), compilerRtFloatAbbrev(target, dest_bits),
4517 const dest_bits = dest_ty.scalarType(zcu).floatBits(target);4618 });
4518 const src_bits = operand_ty.scalarType(zcu).floatBits(target);4619 return self.buildFloatCastCall(dest_ty, fn_name, operand_ty, operand);
4519 const fn_name = try o.builder.strtabStringFmt("__extend{s}f{s}f2", .{
4520 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
4521 });
4522
4523 const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
4524 if (dest_ty.isVector(zcu)) return self.buildElementwiseCall(
4525 libc_fn,
4526 &.{operand},
4527 try o.builder.poisonValue(dest_llvm_ty),
4528 dest_ty.vectorLen(zcu),
4529 );
4530 return self.wip.call(
4531 .normal,
4532 .ccc,
4533 .none,
4534 libc_fn.typeOf(&o.builder),
4535 libc_fn.toValue(&o.builder),
4536 &.{operand},
4537 "",
4538 );
4539 }
4540}4620}
45414621
4542fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value {4622fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value {
...@@ -4558,10 +4638,143 @@ fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!...@@ -4558,10 +4638,143 @@ fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!
4558 // * bool/int/float <-> bool/int/float4638 // * bool/int/float <-> bool/int/float
4559 // * `@Vector(n, A)` <-> `@Vector(n, B)`4639 // * `@Vector(n, A)` <-> `@Vector(n, B)`
4560 //4640 //
4561 // All of these cases can be handled by LLVM's `bitcast` instruction.4641 // Most of these cases can be handled by LLVM's `bitcast` instruction, except when
4642 // a non-native type like `f80` is used.
45624643
4563 assert(!isByRef(operand_ty, zcu));4644 if (isByRef(operand_ty, zcu)) {
4564 assert(!isByRef(dest_ty, zcu));4645 const operand_scalar_ty = operand_ty.scalarType(zcu);
4646 const target = zcu.getTarget();
4647 const bits = operand_scalar_ty.floatBits(target);
4648 const dest_scalar_ty = dest_ty.scalarType(zcu);
4649 if (isByRef(dest_ty, zcu)) {
4650 assert(dest_scalar_ty.floatBits(target) == bits);
4651 return operand;
4652 }
4653 assert(dest_scalar_ty.intInfo(zcu).bits == bits);
4654
4655 const len = if (operand_ty.toIntern() != operand_scalar_ty.toIntern())
4656 operand_ty.vectorLen(zcu)
4657 else
4658 null;
4659 const operand_scalar_size = operand_scalar_ty.abiSize(zcu);
4660 var result = if (len) |_|
4661 try o.builder.poisonValue(try o.lowerType(dest_ty, .as_value))
4662 else
4663 undefined;
4664 for (0..len orelse 1) |index| {
4665 const result_elem = result_elem: switch (bits) {
4666 else => unreachable,
4667 80 => {
4668 const f80_layout = o.softF80Layout(.{}) catch unreachable;
4669 const mantissa = try fg.load(
4670 try fg.ptraddConst(operand, operand_scalar_size * index + f80_layout.mantissa_offset),
4671 f80_layout.alignment.offset(f80_layout.mantissa_offset),
4672 .u64,
4673 .normal,
4674 );
4675 const exponent = try fg.load(
4676 try fg.ptraddConst(operand, operand_scalar_size * index + f80_layout.exponent_offset),
4677 f80_layout.alignment.offset(f80_layout.exponent_offset),
4678 .u16,
4679 .normal,
4680 );
4681 const casted_mantissa = try fg.wip.cast(.zext, mantissa, .i80, "bitCast.casted_mantissa");
4682 const casted_exponent = try fg.wip.cast(.zext, exponent, .i80, "bitCast.casted_exponent");
4683 const shifted_exponent = try fg.wip.bin(.@"shl nuw", casted_exponent, try o.builder.intValue(.i80, 64), "bitCast.shifted_exponent");
4684 break :result_elem try fg.wip.bin(.@"or", casted_mantissa, shifted_exponent, "bitCast.result_elem");
4685 },
4686 128 => {
4687 const f128_layout = o.softF128Layout(.{}) catch unreachable;
4688 const lo = try fg.load(
4689 try fg.ptraddConst(operand, operand_scalar_size * index + f128_layout.lo_offset),
4690 f128_layout.alignment.offset(f128_layout.lo_offset),
4691 .u64,
4692 .normal,
4693 );
4694 const hi = try fg.load(
4695 try fg.ptraddConst(operand, operand_scalar_size * index + f128_layout.hi_offset),
4696 f128_layout.alignment.offset(f128_layout.hi_offset),
4697 .u64,
4698 .normal,
4699 );
4700 const casted_lo = try fg.wip.cast(.zext, lo, .i128, "bitCast.casted_lo");
4701 const casted_hi = try fg.wip.cast(.zext, hi, .i128, "bitCast.casted_hi");
4702 const shifted_hi = try fg.wip.bin(.@"shl nuw", casted_hi, try o.builder.intValue(.i128, 64), "bitCast.shifted_hi");
4703 break :result_elem try fg.wip.bin(.@"or", casted_lo, shifted_hi, "bitCast.result_elem");
4704 },
4705 };
4706 result = if (len) |_|
4707 try fg.wip.insertElement(result, result_elem, try o.builder.intValue(.i32, index), "elementwise.result")
4708 else
4709 result_elem;
4710 }
4711 return result;
4712 }
4713
4714 if (isByRef(dest_ty, zcu)) {
4715 const dest_scalar_ty = dest_ty.scalarType(zcu);
4716 const bits = dest_scalar_ty.floatBits(zcu.getTarget());
4717 assert(dest_scalar_ty.isRuntimeFloat());
4718 const operand_scalar_ty = operand_ty.scalarType(zcu);
4719 assert(operand_scalar_ty.intInfo(zcu).bits == bits);
4720
4721 const len = if (operand_ty.toIntern() != operand_scalar_ty.toIntern())
4722 operand_ty.vectorLen(zcu)
4723 else
4724 null;
4725 const operand_scalar_size = operand_scalar_ty.abiSize(zcu);
4726 const result_ptr = try fg.buildZigAlloca(dest_ty, .none);
4727 for (0..len orelse 1) |index| {
4728 const operand_elem = if (len) |_|
4729 try fg.wip.extractElement(operand, try o.builder.intValue(.i32, index), "elementwise.operand_elem")
4730 else
4731 operand;
4732 switch (bits) {
4733 else => unreachable,
4734 80 => {
4735 const f80_layout = o.softF80Layout(.{}) catch unreachable;
4736 const mantissa = try fg.wip.cast(.trunc, operand_elem, .i64, "bitCast.mantissa");
4737 const shifted_exponent = try fg.wip.bin(.lshr, operand_elem, try o.builder.intValue(.i80, 64), "bitCast.shifted_exponent");
4738 const exponent = try fg.wip.cast(.@"trunc nuw", shifted_exponent, .i16, "bitCast.exponent");
4739 try fg.store(
4740 try fg.ptraddConst(result_ptr, operand_scalar_size * index + f80_layout.mantissa_offset),
4741 f80_layout.alignment.offset(f80_layout.mantissa_offset),
4742 mantissa,
4743 .u64,
4744 .normal,
4745 );
4746 try fg.store(
4747 try fg.ptraddConst(result_ptr, operand_scalar_size * index + f80_layout.exponent_offset),
4748 f80_layout.alignment.offset(f80_layout.exponent_offset),
4749 exponent,
4750 .u16,
4751 .normal,
4752 );
4753 },
4754 128 => {
4755 const f128_layout = o.softF128Layout(.{}) catch unreachable;
4756 const lo = try fg.wip.cast(.trunc, operand_elem, .i64, "bitCast.lo");
4757 const shifted_hi = try fg.wip.bin(.lshr, operand_elem, try o.builder.intValue(.i128, 64), "bitCast.shifted_hi");
4758 const hi = try fg.wip.cast(.@"trunc nuw", shifted_hi, .i64, "bitCast.hi");
4759 try fg.store(
4760 try fg.ptraddConst(result_ptr, operand_scalar_size * index + f128_layout.lo_offset),
4761 f128_layout.alignment.offset(f128_layout.lo_offset),
4762 lo,
4763 .u64,
4764 .normal,
4765 );
4766 try fg.store(
4767 try fg.ptraddConst(result_ptr, operand_scalar_size * index + f128_layout.hi_offset),
4768 f128_layout.alignment.offset(f128_layout.hi_offset),
4769 hi,
4770 .u64,
4771 .normal,
4772 );
4773 },
4774 }
4775 }
4776 return result_ptr;
4777 }
45654778
4566 const llvm_dest_ty = try o.lowerType(dest_ty, .as_value);4779 const llvm_dest_ty = try o.lowerType(dest_ty, .as_value);
4567 const result = try fg.wip.cast(.bitcast, operand, llvm_dest_ty, "");4780 const result = try fg.wip.cast(.bitcast, operand, llvm_dest_ty, "");
...@@ -4730,7 +4943,7 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value...@@ -4730,7 +4943,7 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value
4730 const ptr_align = ptr_ty.ptrAlignment(zcu);4943 const ptr_align = ptr_ty.ptrAlignment(zcu);
4731 const elem_ty = ptr_ty.childType(zcu);4944 const elem_ty = ptr_ty.childType(zcu);
4732 if (!elem_ty.hasRuntimeBits(zcu)) {4945 if (!elem_ty.hasRuntimeBits(zcu)) {
4733 return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue();4946 return (try o.lowerPtrToVoid(ptr_align.toLlvm(), ptr_ty.ptrAddressSpace(zcu))).toValue();
4734 }4947 }
4735 return self.buildZigAlloca(elem_ty, ptr_align);4948 return self.buildZigAlloca(elem_ty, ptr_align);
4736}4949}
...@@ -4743,7 +4956,7 @@ fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value...@@ -4743,7 +4956,7 @@ fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value
4743 const ptr_align = ptr_ty.ptrAlignment(zcu);4956 const ptr_align = ptr_ty.ptrAlignment(zcu);
4744 const elem_ty = ptr_ty.childType(zcu);4957 const elem_ty = ptr_ty.childType(zcu);
4745 if (!elem_ty.hasRuntimeBits(zcu)) {4958 if (!elem_ty.hasRuntimeBits(zcu)) {
4746 return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue();4959 return (try o.lowerPtrToVoid(ptr_align.toLlvm(), ptr_ty.ptrAddressSpace(zcu))).toValue();
4747 }4960 }
4748 return self.buildZigAlloca(elem_ty, ptr_align);4961 return self.buildZigAlloca(elem_ty, ptr_align);
4749}4962}
...@@ -4850,17 +5063,24 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu...@@ -4850,17 +5063,24 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu
4850 const elem = try fg.resolveInst(bin_op.rhs);5063 const elem = try fg.resolveInst(bin_op.rhs);
48515064
4852 if (ptr_info.flags.vector_index != .none) {5065 if (ptr_info.flags.vector_index != .none) {
4853 // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`.5066 if (isByRef(elem_ty, zcu)) {
4854 const vec_ty = try fg.pt.vectorType(.{5067 const offset = @backingInt(ptr_info.flags.vector_index) * elem_ty.abiSize(zcu);
4855 .len = ptr_info.packed_offset.host_size,5068 const elem_ptr = try fg.ptraddConst(ptr, offset);
4856 .child = elem_ty.toIntern(),5069 try fg.store(elem_ptr, ptr_alignment.offset(offset), elem, elem_ty, access_kind);
4857 });5070 } else {
5071 // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`.
5072 const vec_ty = try fg.pt.vectorType(.{
5073 .len = ptr_info.packed_offset.host_size,
5074 .child = elem_ty.toIntern(),
5075 });
48585076
4859 const loaded_vector = try fg.load(ptr, ptr_alignment, vec_ty, access_kind);5077 const loaded_vector = try fg.load(ptr, ptr_alignment, vec_ty, access_kind);
4860 const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index);5078 const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index);
4861 const modified_vector = try fg.wip.insertElement(loaded_vector, elem, index_val, "");5079 const modified_vector = try fg.wip.insertElement(loaded_vector, elem, index_val, "");
5080
5081 try fg.store(ptr, ptr_alignment, modified_vector, vec_ty, access_kind);
5082 }
48625083
4863 try fg.store(ptr, ptr_alignment, modified_vector, vec_ty, access_kind);
4864 return .none;5084 return .none;
4865 }5085 }
48665086
...@@ -4927,22 +5147,27 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {...@@ -4927,22 +5147,27 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
4927 if (ptr_info.flags.is_volatile) .@"volatile" else .normal;5147 if (ptr_info.flags.is_volatile) .@"volatile" else .normal;
49285148
4929 if (ptr_info.flags.vector_index != .none) {5149 if (ptr_info.flags.vector_index != .none) {
4930 // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`.5150 if (isByRef(elem_ty, zcu)) {
4931 const vec_ty = try fg.pt.vectorType(.{5151 const elem_size = elem_ty.abiSize(zcu);
4932 .len = ptr_info.packed_offset.host_size,5152 const offset = @backingInt(ptr_info.flags.vector_index) * elem_size;
4933 .child = elem_ty.toIntern(),5153 const elem_ptr = try fg.ptraddConst(ptr, offset);
4934 });5154 return fg.load(elem_ptr, ptr_align.offset(offset), elem_ty, access_kind);
4935 const vector_val = try fg.load(ptr, ptr_align, vec_ty, access_kind);5155 } else {
4936 const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index);5156 // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`.
4937 return fg.wip.extractElement(vector_val, index_val, "");5157 const vec_ty = try fg.pt.vectorType(.{
5158 .len = ptr_info.packed_offset.host_size,
5159 .child = elem_ty.toIntern(),
5160 });
5161 const vector_val = try fg.load(ptr, ptr_align, vec_ty, access_kind);
5162 const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index);
5163 return fg.wip.extractElement(vector_val, index_val, "");
5164 }
4938 }5165 }
49395166
4940 if (ptr_info.packed_offset.host_size == 0) {5167 if (ptr_info.packed_offset.host_size == 0) {
4941 return fg.load(ptr, ptr_align, elem_ty, access_kind);5168 return fg.load(ptr, ptr_align, elem_ty, access_kind);
4942 }5169 }
49435170
4944 assert(!isByRef(elem_ty, zcu)); // all packable types are by-val
4945
4946 // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`.5171 // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`.
4947 const backing_int_ty = try fg.pt.intType(.unsigned, @intCast(ptr_info.packed_offset.host_size * 8));5172 const backing_int_ty = try fg.pt.intType(.unsigned, @intCast(ptr_info.packed_offset.host_size * 8));
4948 const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .as_value);5173 const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .as_value);
...@@ -4952,6 +5177,67 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {...@@ -4952,6 +5177,67 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
4952 const elem_bits = ptr_ty.childType(zcu).bitSize(zcu);5177 const elem_bits = ptr_ty.childType(zcu).bitSize(zcu);
4953 const shift_amt = try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset);5178 const shift_amt = try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset);
4954 const shifted_value = try fg.wip.bin(.lshr, backing_int_val, shift_amt, "");5179 const shifted_value = try fg.wip.bin(.lshr, backing_int_val, shift_amt, "");
5180
5181 if (isByRef(elem_ty, zcu)) {
5182 const result_ptr = try fg.buildZigAlloca(elem_ty, .none);
5183 switch (elem_ty.floatBits(zcu.getTarget())) {
5184 else => unreachable,
5185 80 => {
5186 const f80_layout = o.softF80Layout(.{}) catch unreachable;
5187 const mantissa = try fg.wip.cast(.trunc, shifted_value, .i64, "load.mantissa");
5188 const shifted_exponent = try fg.wip.bin(
5189 .lshr,
5190 backing_int_val,
5191 try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset + 64),
5192 "load.shifted_exponent",
5193 );
5194 const exponent = try fg.wip.cast(.trunc, shifted_exponent, .i16, "load.exponent");
5195
5196 try fg.store(
5197 try fg.ptraddConst(result_ptr, f80_layout.mantissa_offset),
5198 f80_layout.alignment.offset(f80_layout.mantissa_offset),
5199 mantissa,
5200 .u64,
5201 .normal,
5202 );
5203 try fg.store(
5204 try fg.ptraddConst(result_ptr, f80_layout.exponent_offset),
5205 f80_layout.alignment.offset(f80_layout.exponent_offset),
5206 exponent,
5207 .u16,
5208 .normal,
5209 );
5210 },
5211 128 => {
5212 const f128_layout = o.softF128Layout(.{}) catch unreachable;
5213 const lo = try fg.wip.cast(.trunc, shifted_value, .i64, "load.lo");
5214 const shifted_hi = try fg.wip.bin(
5215 .lshr,
5216 backing_int_val,
5217 try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset + 64),
5218 "load.shifted_hi",
5219 );
5220 const hi = try fg.wip.cast(.trunc, shifted_hi, .i64, "load.hi");
5221
5222 try fg.store(
5223 try fg.ptraddConst(result_ptr, f128_layout.lo_offset),
5224 f128_layout.alignment.offset(f128_layout.lo_offset),
5225 lo,
5226 .u64,
5227 .normal,
5228 );
5229 try fg.store(
5230 try fg.ptraddConst(result_ptr, f128_layout.hi_offset),
5231 f128_layout.alignment.offset(f128_layout.hi_offset),
5232 hi,
5233 .u64,
5234 .normal,
5235 );
5236 },
5237 }
5238 return result_ptr;
5239 }
5240
4955 const elem_llvm_ty = try o.lowerType(elem_ty, .as_value);5241 const elem_llvm_ty = try o.lowerType(elem_ty, .as_value);
49565242
4957 if (elem_ty.zigTypeTag(zcu) == .float or elem_ty.zigTypeTag(zcu) == .vector) {5243 if (elem_ty.zigTypeTag(zcu) == .float or elem_ty.zigTypeTag(zcu) == .vector) {
...@@ -5848,95 +6134,25 @@ fn airShuffleTwo(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val...@@ -5848,95 +6134,25 @@ fn airShuffleTwo(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val
5848 );6134 );
5849}6135}
58506136
5851/// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.6137fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value {
5852///6138 const o = fg.object;
5853/// Equivalent to:
5854/// ```
5855/// var accum: T = init;
5856/// for (0..i) |i| {
5857/// accum = llvm_fn(accum, vec[i]);
5858/// }
5859/// // result is 'accum'
5860/// ```
5861fn buildReducedCall(
5862 self: *FuncGen,
5863 llvm_fn: Builder.Function.Index,
5864 operand_vector: Builder.Value,
5865 vector_len: usize,
5866 accum_init: Builder.Value,
5867) Allocator.Error!Builder.Value {
5868 const o = self.object;
5869 const llvm_usize_ty = try o.lowerType(.usize, .as_value);
5870 const llvm_vector_len = try o.builder.intValue(llvm_usize_ty, vector_len);
5871 const llvm_result_ty = accum_init.typeOfWip(&self.wip);
5872
5873 const entry_block = self.wip.cursor.block;
5874
5875 const cond_block = try self.wip.block(2, "ReduceLoopCond");
5876 const body_block = try self.wip.block(1, "ReduceLoopBody");
5877 const exit_block = try self.wip.block(1, "ReduceLoopExit");
5878
5879 _ = try self.wip.br(cond_block);
5880
5881 // ReduceLoopCond:
5882 // %index = phi iN [0, %Entry], [%new_index, %ReduceLoopBody]
5883 // %accum = phi T [%accum_init, %Entry], [%new_accum, %ReduceLoopBody]
5884 // %cond = icmp ult iN %index, %vector_len
5885 // br i1 %cond, label %ReduceLoopBody, label %ReduceLoopExit
5886 self.wip.cursor = .{ .block = cond_block };
5887 const index = try self.wip.phi(llvm_usize_ty, "");
5888 const accum = try self.wip.phi(llvm_result_ty, "");
5889 const cond = try self.wip.icmp(.ult, index.toValue(), llvm_vector_len, "");
5890 _ = try self.wip.brCond(cond, body_block, exit_block, .none);
5891
5892 // ReduceLoopBody:
5893 // %elem = extractelement <n x T> %operand_vec, iN %index
5894 // %new_accum = call T @llvm_fn(T %accum, T %elem)
5895 // %new_index = add nuw iN %index, 1
5896 // br label %ReduceLoopCond
5897 self.wip.cursor = .{ .block = body_block };
5898 const elem = try self.wip.extractElement(operand_vector, index.toValue(), "");
5899 const new_accum = try self.wip.call(
5900 .normal,
5901 .ccc,
5902 .none,
5903 llvm_fn.typeOf(&o.builder),
5904 llvm_fn.toValue(&o.builder),
5905 &.{ accum.toValue(), elem },
5906 "",
5907 );
5908 const new_index = try self.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(llvm_usize_ty, 1), "");
5909 _ = try self.wip.br(cond_block);
5910
5911 const index_init = try o.builder.intValue(llvm_usize_ty, 0);
5912 index.finish(&.{ index_init, new_index }, &.{ entry_block, body_block }, &self.wip);
5913 accum.finish(&.{ accum_init, new_accum }, &.{ entry_block, body_block }, &self.wip);
5914
5915 self.wip.cursor = .{ .block = exit_block };
5916 return accum.toValue();
5917}
5918
5919fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value {
5920 const o = self.object;
5921 const zcu = o.zcu;6139 const zcu = o.zcu;
5922 const target = zcu.getTarget();6140 const target = zcu.getTarget();
59236141
5924 const reduce = self.air.instructions.items(.data)[@backingInt(inst)].reduce;6142 const reduce = fg.air.instructions.items(.data)[@backingInt(inst)].reduce;
5925 const operand = try self.resolveInst(reduce.operand);6143 const operand = try fg.resolveInst(reduce.operand);
5926 const operand_ty = self.typeOf(reduce.operand);6144 const operand_ty = fg.typeOf(reduce.operand);
5927 const llvm_operand_ty = try o.lowerType(operand_ty, .as_value);6145 const scalar_ty = fg.typeOfIndex(inst);
5928 const scalar_ty = self.typeOfIndex(inst);
5929 const llvm_scalar_ty = try o.lowerType(scalar_ty, .as_value);
59306146
5931 switch (reduce.operation) {6147 switch (reduce.operation) {
5932 .And, .Or, .Xor => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) {6148 .And, .Or, .Xor => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) {
5933 .And => .@"vector.reduce.and",6149 .And => .@"vector.reduce.and",
5934 .Or => .@"vector.reduce.or",6150 .Or => .@"vector.reduce.or",
5935 .Xor => .@"vector.reduce.xor",6151 .Xor => .@"vector.reduce.xor",
5936 else => unreachable,6152 else => unreachable,
5937 }, &.{llvm_operand_ty}, &.{operand}, ""),6153 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),
5938 .Min, .Max => switch (scalar_ty.zigTypeTag(zcu)) {6154 .Min, .Max => switch (scalar_ty.zigTypeTag(zcu)) {
5939 .int => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) {6155 .int => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) {
5940 .Min => if (scalar_ty.isSignedInt(zcu))6156 .Min => if (scalar_ty.isSignedInt(zcu))
5941 .@"vector.reduce.smin"6157 .@"vector.reduce.smin"
5942 else6158 else
...@@ -5946,29 +6162,29 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A...@@ -5946,29 +6162,29 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A
5946 else6162 else
5947 .@"vector.reduce.umax",6163 .@"vector.reduce.umax",
5948 else => unreachable,6164 else => unreachable,
5949 }, &.{llvm_operand_ty}, &.{operand}, ""),6165 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),
5950 .float => if (intrinsicsAllowed(scalar_ty, target))6166 .float => if (intrinsicsAllowed(scalar_ty, target))
5951 return self.wip.callIntrinsic(fast, .none, switch (reduce.operation) {6167 return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) {
5952 .Min => .@"vector.reduce.fmin",6168 .Min => .@"vector.reduce.fmin",
5953 .Max => .@"vector.reduce.fmax",6169 .Max => .@"vector.reduce.fmax",
5954 else => unreachable,6170 else => unreachable,
5955 }, &.{llvm_operand_ty}, &.{operand}, ""),6171 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),
5956 else => unreachable,6172 else => unreachable,
5957 },6173 },
5958 .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) {6174 .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) {
5959 .int => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) {6175 .int => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) {
5960 .Add => .@"vector.reduce.add",6176 .Add => .@"vector.reduce.add",
5961 .Mul => .@"vector.reduce.mul",6177 .Mul => .@"vector.reduce.mul",
5962 else => unreachable,6178 else => unreachable,
5963 }, &.{llvm_operand_ty}, &.{operand}, ""),6179 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""),
5964 .float => if (intrinsicsAllowed(scalar_ty, target))6180 .float => if (intrinsicsAllowed(scalar_ty, target))
5965 return self.wip.callIntrinsic(fast, .none, switch (reduce.operation) {6181 return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) {
5966 .Add => .@"vector.reduce.fadd",6182 .Add => .@"vector.reduce.fadd",
5967 .Mul => .@"vector.reduce.fmul",6183 .Mul => .@"vector.reduce.fmul",
5968 else => unreachable,6184 else => unreachable,
5969 }, &.{llvm_operand_ty}, &.{ switch (reduce.operation) {6185 }, &.{try o.lowerType(operand_ty, .as_value)}, &.{ switch (reduce.operation) {
5970 .Add => try o.builder.fpValue(llvm_scalar_ty, -0.0),6186 .Add => try o.builder.fpValue(try o.lowerType(scalar_ty, .as_value), -0.0),
5971 .Mul => try o.builder.fpValue(llvm_scalar_ty, 1.0),6187 .Mul => try o.builder.fpValue(try o.lowerType(scalar_ty, .as_value), 1.0),
5972 else => unreachable,6188 else => unreachable,
5973 }, operand }, ""),6189 }, operand }, ""),
5974 else => unreachable,6190 else => unreachable,
...@@ -5986,62 +6202,119 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A...@@ -5986,62 +6202,119 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A
5986 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),6202 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
5987 }),6203 }),
5988 .Add => try o.builder.strtabStringFmt("__add{s}f3", .{6204 .Add => try o.builder.strtabStringFmt("__add{s}f3", .{
5989 compilerRtFloatAbbrev(float_bits),6205 compilerRtFloatAbbrev(target, float_bits),
5990 }),6206 }),
5991 .Mul => try o.builder.strtabStringFmt("__mul{s}f3", .{6207 .Mul => try o.builder.strtabStringFmt("__mul{s}f3", .{
5992 compilerRtFloatAbbrev(float_bits),6208 compilerRtFloatAbbrev(target, float_bits),
5993 }),6209 }),
5994 else => unreachable,6210 else => unreachable,
5995 };6211 };
59966212 const fn_info: Object.FuncInfo = .{
5997 const libc_fn = try o.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty);6213 .cc = target.cCallingConvention().?,
5998 const init_val = switch (llvm_scalar_ty) {6214 .param_types = &.{ scalar_ty.toIntern(), scalar_ty.toIntern() },
5999 .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast(6215 .return_type = scalar_ty.toIntern(),
6000 @as(f16, switch (reduce.operation) {6216 };
6001 .Min, .Max => std.math.nan(f16),6217 const llvm_fn = try fg.object.getLibcFunction(fg.pt, fn_name, fn_info);
6002 .Add => -0.0,6218 const init = switch (float_bits) {
6003 .Mul => 1.0,
6004 else => unreachable,
6005 }),
6006 ))),
6007 .i80 => try o.builder.intValue(.i80, @as(i80, @bitCast(
6008 @as(f80, switch (reduce.operation) {
6009 .Min, .Max => std.math.nan(f80),
6010 .Add => -0.0,
6011 .Mul => 1.0,
6012 else => unreachable,
6013 }),
6014 ))),
6015 .i128 => try o.builder.intValue(.i128, @as(i128, @bitCast(
6016 @as(f128, switch (reduce.operation) {
6017 .Min, .Max => std.math.nan(f128),
6018 .Add => -0.0,
6019 .Mul => 1.0,
6020 else => unreachable,
6021 }),
6022 ))),
6023 else => unreachable,6219 else => unreachable,
6220 16 => try o.f16Const(switch (reduce.operation) {
6221 else => unreachable,
6222 .Min, .Max => std.math.nan(f16),
6223 .Add => -0.0,
6224 .Mul => 1.0,
6225 }),
6226 32 => try o.f32Const(switch (reduce.operation) {
6227 else => unreachable,
6228 .Min, .Max => std.math.nan(f32),
6229 .Add => -0.0,
6230 .Mul => 1.0,
6231 }),
6232 64 => try o.f64Const(switch (reduce.operation) {
6233 else => unreachable,
6234 .Min, .Max => std.math.nan(f64),
6235 .Add => -0.0,
6236 .Mul => 1.0,
6237 }),
6238 80 => try o.f80Const(switch (reduce.operation) {
6239 else => unreachable,
6240 .Min, .Max => std.math.nan(f80),
6241 .Add => -0.0,
6242 .Mul => 1.0,
6243 }),
6244 128 => try o.f128Const(switch (reduce.operation) {
6245 else => unreachable,
6246 .Min, .Max => std.math.nan(f128),
6247 .Add => -0.0,
6248 .Mul => 1.0,
6249 }),
6024 };6250 };
6025 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(zcu), init_val);6251 const iterations = operand_ty.vectorLen(zcu);
6252 const is_by_ref = isByRef(operand_ty, zcu);
6253 if (iterations > 1 and is_by_ref) {
6254 const init_ref = try o.lowerConstRef(init, scalar_ty.abiAlignment(zcu).toLlvm());
6255
6256 const entry_block = fg.wip.cursor.block;
6257 const loop_block = try fg.wip.block(2, "reduce.loop");
6258 const done_block = try fg.wip.block(1, "reduce.loop");
6259
6260 _ = try fg.wip.br(loop_block);
6261
6262 fg.wip.cursor = .{ .block = loop_block };
6263 const index = try fg.wip.phi(.i32, "reduce.index");
6264 const result = try fg.wip.phi(.ptr, "reduce.result");
6265
6266 const rhs_elem_ptr = try fg.ptraddScaled(operand, index.toValue(), scalar_ty.abiSize(zcu));
6267 const rhs_elem = try fg.load(rhs_elem_ptr, .none, scalar_ty, .normal);
6268 const next_result = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, &.{ result.toValue(), rhs_elem });
6269
6270 const next_index = try fg.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(.i32, 1), "reduce.next_index");
6271 index.finish(&.{ try o.builder.intValue(.i32, 0), next_index }, &.{ entry_block, loop_block }, &fg.wip);
6272 result.finish(&.{ init_ref.toValue(), next_result }, &.{ entry_block, loop_block }, &fg.wip);
6273 const is_done = try fg.wip.icmp(.eq, next_index, try o.builder.intValue(.i32, iterations), "reduce.is_done");
6274 _ = try fg.wip.brCond(is_done, done_block, loop_block, .none);
6275
6276 fg.wip.cursor = .{ .block = done_block };
6277 return next_result;
6278 }
6279 var result = init.toValue();
6280 for (0..iterations) |index| {
6281 const index_value = try o.builder.intValue(.i32, index);
6282 const rhs_elem = if (is_by_ref) rhs_elem: {
6283 const rhs_elem_ptr = try fg.ptraddConst(operand, index * scalar_ty.abiSize(zcu));
6284 break :rhs_elem try fg.load(rhs_elem_ptr, .none, scalar_ty, .normal);
6285 } else try fg.wip.extractElement(operand, index_value, "reduce.rhs_elem");
6286 result = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, &.{ result, rhs_elem });
6287 }
6288 return result;
6026}6289}
60276290
6028fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {6291fn airAggregateInit(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
6029 const o = self.object;6292 const o = fg.object;
6030 const zcu = o.zcu;6293 const zcu = o.zcu;
6031 const ip = &zcu.intern_pool;6294 const ip = &zcu.intern_pool;
6032 const ty_pl = self.air.instructions.items(.data)[@backingInt(inst)].ty_pl;6295 const ty_pl = fg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
6033 const result_ty = self.typeOfIndex(inst);6296 const result_ty = fg.typeOfIndex(inst);
6034 const len: usize = @intCast(result_ty.arrayLen(zcu));6297 const len: usize = @intCast(result_ty.arrayLen(zcu));
6035 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[ty_pl.payload..][0..len]);6298 const elements: []const Air.Inst.Ref = @ptrCast(fg.air.extra.items[ty_pl.payload..][0..len]);
60366299
6037 switch (result_ty.zigTypeTag(zcu)) {6300 switch (result_ty.zigTypeTag(zcu)) {
6038 .vector => {6301 .vector => if (isByRef(result_ty, zcu)) {
6302 const elem_ty = result_ty.childType(zcu);
6303 const elem_size = elem_ty.abiSize(zcu);
6304 const result_ptr = try fg.buildZigAlloca(result_ty, .none);
6305 for (elements, 0..) |elem, elem_index| {
6306 const elem_ptr = try fg.ptraddConst(result_ptr, elem_index * elem_size);
6307 const llvm_elem = try fg.resolveInst(elem);
6308 try fg.store(elem_ptr, .none, llvm_elem, elem_ty, .normal);
6309 }
6310 return result_ptr;
6311 } else {
6039 const llvm_result_ty = try o.lowerType(result_ty, .as_value);6312 const llvm_result_ty = try o.lowerType(result_ty, .as_value);
6040 var vector = try o.builder.poisonValue(llvm_result_ty);6313 var vector = try o.builder.poisonValue(llvm_result_ty);
6041 for (elements, 0..) |elem, i| {6314 for (elements, 0..) |elem, elem_index| {
6042 const index_u32 = try o.builder.intValue(.i32, i);6315 const elem_index_val = try o.builder.intValue(.i32, elem_index);
6043 const llvm_elem = try self.resolveInst(elem);6316 const llvm_elem = try fg.resolveInst(elem);
6044 vector = try self.wip.insertElement(vector, llvm_elem, index_u32, "");6317 vector = try fg.wip.insertElement(vector, llvm_elem, elem_index_val, "");
6045 }6318 }
6046 return vector;6319 return vector;
6047 },6320 },
...@@ -6057,18 +6330,18 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde...@@ -6057,18 +6330,18 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde
6057 for (elements, struct_type.field_types.get(ip)) |elem, field_ty| {6330 for (elements, struct_type.field_types.get(ip)) |elem, field_ty| {
6058 if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;6331 if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
60596332
6060 const non_int_val = try self.resolveInst(elem);6333 const non_int_val = try fg.resolveInst(elem);
6061 const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(zcu));6334 const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(zcu));
6062 const small_int_ty = try o.builder.intType(ty_bit_size);6335 const small_int_ty = try o.builder.intType(ty_bit_size);
6063 const small_int_val = if (Type.fromInterned(field_ty).isPtrAtRuntime(zcu))6336 const small_int_val = if (Type.fromInterned(field_ty).isPtrAtRuntime(zcu))
6064 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")6337 try fg.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
6065 else6338 else
6066 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");6339 try fg.wip.cast(.bitcast, non_int_val, small_int_ty, "");
6067 const shift_rhs = try o.builder.intValue(int_ty, running_bits);6340 const shift_rhs = try o.builder.intValue(int_ty, running_bits);
6068 const extended_int_val =6341 const extended_int_val =
6069 try self.wip.conv(.unsigned, small_int_val, int_ty, "");6342 try fg.wip.conv(.unsigned, small_int_val, int_ty, "");
6070 const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, "");6343 const shifted = try fg.wip.bin(.shl, extended_int_val, shift_rhs, "");
6071 running_int = try self.wip.bin(.@"or", running_int, shifted, "");6344 running_int = try fg.wip.bin(.@"or", running_int, shifted, "");
6072 running_bits += ty_bit_size;6345 running_bits += ty_bit_size;
6073 }6346 }
6074 return running_int;6347 return running_int;
...@@ -6078,19 +6351,19 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde...@@ -6078,19 +6351,19 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde
6078 // TODO in debug builds init to undef so that the padding will be 0xaa6351 // TODO in debug builds init to undef so that the padding will be 0xaa
6079 // even if we fully populate the fields.6352 // even if we fully populate the fields.
6080 const struct_align = result_ty.abiAlignment(zcu);6353 const struct_align = result_ty.abiAlignment(zcu);
6081 const alloca_inst = try self.buildZigAlloca(result_ty, .none);6354 const alloca_inst = try fg.buildZigAlloca(result_ty, .none);
60826355
6083 for (elements, 0..) |elem, field_index| {6356 for (elements, 0..) |elem, field_index| {
6084 if (result_ty.structFieldIsComptime(field_index, zcu)) continue;6357 if (result_ty.structFieldIsComptime(field_index, zcu)) continue;
6085 const field_ty = result_ty.fieldType(field_index, zcu);6358 const field_ty = result_ty.fieldType(field_index, zcu);
6086 if (!field_ty.hasRuntimeBits(zcu)) continue;6359 if (!field_ty.hasRuntimeBits(zcu)) continue;
6087 const offset = result_ty.structFieldOffset(field_index, zcu);6360 const offset = result_ty.structFieldOffset(field_index, zcu);
6088 const field_ptr = try self.ptraddConst(alloca_inst, offset);6361 const field_ptr = try fg.ptraddConst(alloca_inst, offset);
6089 const field_ptr_align = struct_align.offset(offset);6362 const field_ptr_align = struct_align.offset(offset);
60906363
6091 const llvm_field_val = try self.resolveInst(elem);6364 const llvm_field_val = try fg.resolveInst(elem);
60926365
6093 try self.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal);6366 try fg.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal);
6094 }6367 }
60956368
6096 return alloca_inst;6369 return alloca_inst;
...@@ -6099,21 +6372,21 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde...@@ -6099,21 +6372,21 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde
6099 .array => {6372 .array => {
6100 assert(isByRef(result_ty, zcu));6373 assert(isByRef(result_ty, zcu));
61016374
6102 const alloca_inst = try self.buildZigAlloca(result_ty, .none);6375 const alloca_inst = try fg.buildZigAlloca(result_ty, .none);
61036376
6104 const array_info = result_ty.arrayInfo(zcu);6377 const array_info = result_ty.arrayInfo(zcu);
61056378
6106 const elem_size = array_info.elem_type.abiSize(zcu);6379 const elem_size = array_info.elem_type.abiSize(zcu);
61076380
6108 for (elements, 0..) |elem, i| {6381 for (elements, 0..) |elem, i| {
6109 const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * i);6382 const elem_ptr = try fg.ptraddConst(alloca_inst, elem_size * i);
6110 const llvm_elem = try self.resolveInst(elem);6383 const llvm_elem = try fg.resolveInst(elem);
6111 try self.store(elem_ptr, .none, llvm_elem, array_info.elem_type, .normal);6384 try fg.store(elem_ptr, .none, llvm_elem, array_info.elem_type, .normal);
6112 }6385 }
6113 if (array_info.sentinel) |sent_val| {6386 if (array_info.sentinel) |sent_val| {
6114 const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * array_info.len);6387 const elem_ptr = try fg.ptraddConst(alloca_inst, elem_size * array_info.len);
6115 const llvm_elem = try self.resolveValue(sent_val);6388 const llvm_elem = try fg.resolveValue(sent_val);
6116 try self.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal);6389 try fg.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal);
6117 }6390 }
61186391
6119 return alloca_inst;6392 return alloca_inst;
...@@ -6469,26 +6742,12 @@ fn store(...@@ -6469,26 +6742,12 @@ fn store(
6469 .unsigned => .zext,6742 .unsigned => .zext,
6470 .signed => .sext,6743 .signed => .sext,
6471 }, elem, llvm_memory_ty, "");6744 }, elem, llvm_memory_ty, "");
6472 _ = try fg.wip.storeAtomic(6745 _ = try fg.wip.store(access_kind, extended, ptr, llvm_ptr_align);
6473 access_kind,
6474 extended,
6475 ptr,
6476 fg.sync_scope,
6477 .none,
6478 llvm_ptr_align,
6479 );
6480 return;6746 return;
6481 }6747 }
64826748
6483 // `elem_ty` is a simple by-val type which requires no special handling.6749 // `elem_ty` is a simple by-val type which requires no special handling.
6484 _ = try fg.wip.storeAtomic(6750 _ = try fg.wip.store(access_kind, elem, ptr, llvm_ptr_align);
6485 access_kind,
6486 elem,
6487 ptr,
6488 fg.sync_scope,
6489 .none,
6490 llvm_ptr_align,
6491 );
6492}6751}
64936752
6494fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void {6753fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void {
...@@ -6650,7 +6909,8 @@ fn typeOfIndex(fg: *FuncGen, inst: Air.Inst.Index) Type {...@@ -6650,7 +6909,8 @@ fn typeOfIndex(fg: *FuncGen, inst: Air.Inst.Index) Type {
66506909
6651const ParamTypeIterator = struct {6910const ParamTypeIterator = struct {
6652 object: *Object,6911 object: *Object,
6653 fn_info: InternPool.Key.FuncType,6912 cc: std.lang.CallingConvention,
6913 param_types: []const InternPool.Index,
6654 zig_index: u32,6914 zig_index: u32,
6655 llvm_index: u32,6915 llvm_index: u32,
6656 types_len: u32,6916 types_len: u32,
...@@ -6672,63 +6932,66 @@ const ParamTypeIterator = struct {...@@ -6672,63 +6932,66 @@ const ParamTypeIterator = struct {
6672 };6932 };
66736933
6674 pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {6934 pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {
6675 if (it.zig_index >= it.fn_info.param_types.len) return null;6935 if (it.zig_index >= it.param_types.len) return null;
6676 const ip = &it.object.zcu.intern_pool;6936 const ty = it.param_types[it.zig_index];
6677 const ty = it.fn_info.param_types.get(ip)[it.zig_index];
6678 it.byval_attr = false;6937 it.byval_attr = false;
6679 return nextInner(it, Type.fromInterned(ty));6938 return nextInner(it, Type.fromInterned(ty));
6680 }6939 }
66816940
6682 /// `airCall` uses this instead of `next` so that it can take into account variadic functions.6941 /// `airCall` uses this instead of `next` so that it can take into account variadic functions.
6683 fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering {6942 fn nextCall(it: *ParamTypeIterator, arg_types: []const InternPool.Index) Allocator.Error!?Lowering {
6684 const ip = &it.object.zcu.intern_pool;6943 if (it.zig_index >= it.param_types.len) {
6685 if (it.zig_index >= it.fn_info.param_types.len) {6944 if (it.zig_index >= arg_types.len) {
6686 if (it.zig_index >= args.len) {
6687 return null;6945 return null;
6688 } else {6946 } else {
6689 return nextInner(it, fg.typeOf(args[it.zig_index]));6947 return nextInner(it, .fromInterned(arg_types[it.zig_index]));
6690 }6948 }
6691 } else {6949 } else {
6692 return nextInner(it, Type.fromInterned(it.fn_info.param_types.get(ip)[it.zig_index]));6950 return nextInner(it, .fromInterned(it.param_types[it.zig_index]));
6693 }6951 }
6694 }6952 }
66956953
6696 fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {6954 fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
6697 const zcu = it.object.zcu;6955 const zcu = it.object.zcu;
6698 const target = zcu.getTarget();6956 ty.assertHasLayout(zcu);
6699
6700 if (!ty.hasRuntimeBits(zcu)) {6957 if (!ty.hasRuntimeBits(zcu)) {
6701 it.zig_index += 1;6958 it.zig_index += 1;
6702 return .no_bits;6959 return .no_bits;
6703 }6960 }
6704 switch (it.fn_info.cc) {6961 switch (it.cc) {
6705 .@"inline" => unreachable,6962 .@"inline" => unreachable,
6706 .auto => {6963 .auto => {
6707 it.zig_index += 1;6964 it.zig_index += 1;
6708 it.llvm_index += 1;6965 it.llvm_index += 1;
6966
6967 // Match the c calling convention in some cases to avoid llvm bugs.
6968 const target = zcu.getTarget();
6969 if (target.cpu.arch == .x86_64 and ty.isVector(zcu) and ty.childType(zcu).toIntern() == .bool_type) return switch (ty.vectorLen(zcu)) {
6970 0 => .no_bits,
6971 1...32 => .abi_sized_int,
6972 33...64 => {
6973 it.types_buffer[0..1].* = .{.double};
6974 it.offsets_buffer[0..2].* = .{ 0, 8 };
6975 it.types_len = 1;
6976 return .multiple_llvm_types;
6977 },
6978 else => .byval,
6979 };
6980
6709 if (ty.isSlice(zcu) or6981 if (ty.isSlice(zcu) or
6710 (ty.zigTypeTag(zcu) == .optional and ty.optionalChild(zcu).isSlice(zcu) and !ty.ptrAllowsZero(zcu)))6982 (ty.zigTypeTag(zcu) == .optional and ty.optionalChild(zcu).isSlice(zcu) and !ty.ptrAllowsZero(zcu)))
6711 {6983 {
6712 it.llvm_index += 1;6984 it.llvm_index += 1;
6713 return .slice;6985 return .slice;
6714 } else if (isByRef(ty, zcu)) {
6715 return .byref;
6716 } else if (target.cpu.arch.isX86() and
6717 !target.cpu.has(.x86, .avx512f) and
6718 ty.totalVectorBits(zcu) >= 512)
6719 {
6720 // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns
6721 // "512-bit vector arguments require 'avx512f' for AVX512"
6722 return .byref;
6723 } else {
6724 return .byval;
6725 }6986 }
6987 if (isByRef(ty, zcu)) return .byref;
6988 return .byval;
6726 },6989 },
6727 .async => {6990 .async => {
6728 @panic("TODO implement async function lowering in the LLVM backend");6991 @panic("TODO implement async function lowering in the LLVM backend");
6729 },6992 },
6730 .x86_64_sysv, .x86_64_x32 => return it.nextSystemV(ty),6993 .x86_64_sysv, .x86_64_x32 => return try it.next_x86_64_sysv(ty),
6731 .x86_64_win => return it.nextWin64(ty),6994 .x86_64_win => return it.next_x86_64_win(ty),
6732 .x86_stdcall => {6995 .x86_stdcall => {
6733 it.zig_index += 1;6996 it.zig_index += 1;
6734 it.llvm_index += 1;6997 it.llvm_index += 1;
...@@ -6748,9 +7011,9 @@ const ParamTypeIterator = struct {...@@ -6748,9 +7011,9 @@ const ParamTypeIterator = struct {
6748 .float_array => |len| return Lowering{ .float_array = len },7011 .float_array => |len| return Lowering{ .float_array = len },
6749 .byval => return .byval,7012 .byval => return .byval,
6750 .integer => {7013 .integer => {
6751 it.types_len = 1;
6752 it.types_buffer[0..1].* = .{.i64};7014 it.types_buffer[0..1].* = .{.i64};
6753 it.offsets_buffer[0..2].* = .{ 0, 8 };7015 it.offsets_buffer[0..2].* = .{ 0, 8 };
7016 it.types_len = 1;
6754 return .multiple_llvm_types;7017 return .multiple_llvm_types;
6755 },7018 },
6756 .double_integer => return Lowering{ .i64_array = 2 },7019 .double_integer => return Lowering{ .i64_array = 2 },
...@@ -6857,7 +7120,7 @@ const ParamTypeIterator = struct {...@@ -6857,7 +7120,7 @@ const ParamTypeIterator = struct {
6857 }7120 }
6858 }7121 }
68597122
6860 fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering {7123 fn next_x86_64_win(it: *ParamTypeIterator, ty: Type) Lowering {
6861 const zcu = it.object.zcu;7124 const zcu = it.object.zcu;
6862 switch (x86_64_abi.classifyWindows(ty, zcu, zcu.getTarget(), .arg)) {7125 switch (x86_64_abi.classifyWindows(ty, zcu, zcu.getTarget(), .arg)) {
6863 .integer => {7126 .integer => {
...@@ -6898,113 +7161,108 @@ const ParamTypeIterator = struct {...@@ -6898,113 +7161,108 @@ const ParamTypeIterator = struct {
6898 }7161 }
6899 }7162 }
69007163
6901 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {7164 fn next_x86_64_sysv(it: *ParamTypeIterator, ty: Type) Allocator.Error!Lowering {
6902 const zcu = it.object.zcu;7165 const o = it.object;
6903 const ip = &zcu.intern_pool;7166 const zcu = o.zcu;
6904 ty.assertHasLayout(zcu);7167 const target = zcu.getTarget();
6905 const classes = x86_64_abi.classifySystemV(ty, zcu, zcu.getTarget(), .arg);7168 const classes = x86_64_abi.classifySystemV(ty, zcu, target, .arg);
6906 if (classes[0] == .memory) {7169 var types_len: u32 = 0;
6907 it.zig_index += 1;7170 const classes_len = for (classes, 0..) |class, class_index| switch (class) {
6908 it.llvm_index += 1;7171 .integer => {
6909 it.byval_attr = true;7172 it.types_buffer[types_len] = try o.builder.intType(@min(8 * ty.abiSize(zcu) - 64 * class_index, 64));
6910 return .byref;7173 it.offsets_buffer[types_len] = 8 * class_index;
6911 }7174 types_len += 1;
6912 if (isScalar(zcu, ty)) {7175 },
6913 it.zig_index += 1;7176 .sse => {
6914 it.llvm_index += 1;7177 it.types_buffer[types_len] = .double;
6915 return .byval;7178 it.offsets_buffer[types_len] = 8 * class_index;
6916 }7179 types_len += 1;
6917 var types_index: u32 = 0;7180 },
6918 var offset: u64 = 0;7181 .sseup => {
6919 for (classes) |class| {7182 if (it.types_buffer[types_len - 1] == .double) {
6920 switch (class) {7183 if (ty.isVector(zcu)) {
6921 .integer => {7184 it.zig_index += 1;
6922 it.types_buffer[types_index] = .i64;7185 it.llvm_index += 1;
6923 it.offsets_buffer[types_index] = offset;7186 return .byval;
6924 types_index += 1;
6925 },
6926 .sse => {
6927 it.types_buffer[types_index] = .double;
6928 it.offsets_buffer[types_index] = offset;
6929 types_index += 1;
6930 },
6931 .sseup => {
6932 if (it.types_buffer[types_index - 1] == .double) {
6933 it.types_buffer[types_index - 1] = .fp128;
6934 } else {
6935 it.types_buffer[types_index] = .double;
6936 it.offsets_buffer[types_index] = offset;
6937 types_index += 1;
6938 }7187 }
6939 },7188 it.types_buffer[types_len - 1] = .fp128;
6940 .float => {7189 } else {
6941 it.types_buffer[types_index] = .float;7190 it.types_buffer[types_len] = .double;
6942 it.offsets_buffer[types_index] = offset;7191 it.offsets_buffer[types_len] = 8 * class_index;
6943 types_index += 1;7192 types_len += 1;
6944 },7193 }
6945 .float_combine => {7194 },
6946 it.types_buffer[types_index] = try it.object.builder.vectorType(.normal, 2, .float);7195 .float => {
6947 it.offsets_buffer[types_index] = offset;7196 it.types_buffer[types_len] = .float;
6948 types_index += 1;7197 it.offsets_buffer[types_len] = 8 * class_index;
6949 },7198 types_len += 1;
6950 .x87 => {7199 },
6951 it.zig_index += 1;7200 .float_combine => {
6952 it.llvm_index += 1;7201 it.types_buffer[types_len] = try it.object.builder.vectorType(.normal, 2, .float);
6953 it.byval_attr = true;7202 it.offsets_buffer[types_len] = 8 * class_index;
6954 return .byref;7203 types_len += 1;
6955 },7204 },
6956 .x87up => unreachable,7205 .x87 => {
6957 .none => break,
6958 .memory => unreachable, // handled above
6959 .win_i128 => unreachable, // windows only
6960 .bool_vector_mask,
6961 .integer_per_element,
6962 .sse_per_element,
6963 .sse_sse_x87_per_qword,
6964 .sse_per_xword,
6965 .sse_per_yword,
6966 .sse_per_zword,
6967 => unreachable, // vectors already handled by `isScalar` above
6968 }
6969 offset += 8;
6970 }
6971 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});
6972 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
6973 assert(first_non_integer orelse classes.len == types_index);
6974 if (types_index == 1) {
6975 it.zig_index += 1;7206 it.zig_index += 1;
6976 it.llvm_index += 1;7207 it.llvm_index += 1;
6977 return .abi_sized_int;7208 it.byval_attr = true;
6978 }7209 return .byref;
6979 if (it.llvm_index + types_index > 6) {7210 },
7211 .x87up => unreachable,
7212 .none => break class_index,
7213 .memory => {
7214 it.zig_index += 1;
7215 it.llvm_index += 1;
7216 it.byval_attr = true;
7217 return .byref;
7218 },
7219 .win_i128 => unreachable, // windows only
7220 .bool_vector_mask,
7221 .integer_per_element,
7222 .sse_per_element,
7223 .sse_sse_x87_per_qword,
7224 .sse_per_xword,
7225 .sse_per_yword,
7226 .sse_per_zword,
7227 => {
7228 it.zig_index += 1;
7229 it.llvm_index += 1;
7230 return .byval;
7231 },
7232 } else classes.len;
7233 if (types_len > 1) {
7234 if (it.llvm_index + classes_len > 6) {
6980 it.zig_index += 1;7235 it.zig_index += 1;
6981 it.llvm_index += 1;7236 it.llvm_index += 1;
6982 it.byval_attr = true;7237 it.byval_attr = true;
6983 return .byref;7238 return .byref;
6984 }7239 }
6985 switch (ip.indexToKey(ty.toIntern())) {7240 } else if (!isByRef(ty, zcu)) {
6986 .struct_type => {7241 const llvm_ty = try o.lowerType(ty, .as_value);
6987 const size = ty.abiSize(zcu);7242 if (it.types_buffer[0] == llvm_ty or
6988 assert(@divCeil(size, 8) == types_index);7243 (it.types_buffer[0] == .i64 and llvm_ty.isPointer(&o.builder)))
6989 if (size % 8 > 0) {7244 {
6990 it.types_buffer[types_index - 1] =7245 it.zig_index += 1;
6991 try it.object.builder.intType(@intCast(size % 8 * 8));7246 it.llvm_index += 1;
6992 }7247 return .byval;
6993 },
6994 else => {},
6995 }7248 }
6996 }7249 }
6997 it.offsets_buffer[types_index] = offset;7250 it.offsets_buffer[types_len] = 8 * classes_len;
6998 it.types_len = types_index;7251 it.types_len = types_len;
6999 it.llvm_index += types_index;7252 it.llvm_index += types_len;
7000 it.zig_index += 1;7253 it.zig_index += 1;
7001 return .multiple_llvm_types;7254 return .multiple_llvm_types;
7002 }7255 }
7003};7256};
7004pub fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTypeIterator {7257pub fn iterateParamTypes(
7258 object: *Object,
7259 cc: std.lang.CallingConvention,
7260 param_types: []const InternPool.Index,
7261) ParamTypeIterator {
7005 return .{7262 return .{
7006 .object = object,7263 .object = object,
7007 .fn_info = fn_info,7264 .cc = cc,
7265 .param_types = param_types,
7008 .zig_index = 0,7266 .zig_index = 0,
7009 .llvm_index = 0,7267 .llvm_index = 0,
7010 .types_len = undefined,7268 .types_len = undefined,
...@@ -7035,35 +7293,34 @@ pub const FnReturnStrat = union(enum) {...@@ -7035,35 +7293,34 @@ pub const FnReturnStrat = union(enum) {
7035/// In order to support the C calling convention, some return types need to be lowered7293/// In order to support the C calling convention, some return types need to be lowered
7036/// completely differently in the function prototype to honor the C ABI, and then7294/// completely differently in the function prototype to honor the C ABI, and then
7037/// be effectively bitcasted to the actual return type.7295/// be effectively bitcasted to the actual return type.
7038pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat {7296pub fn fnReturnStrat(o: *Object, cc: std.lang.CallingConvention, ret_ty: Type) Allocator.Error!FnReturnStrat {
7039 const zcu = o.zcu;7297 const zcu = o.zcu;
7040 const ret_ty: Type = .fromInterned(fn_info.return_type);
7041 ret_ty.assertHasLayout(zcu);7298 ret_ty.assertHasLayout(zcu);
7042 if (!ret_ty.hasRuntimeBits(zcu)) return .void;7299 if (!ret_ty.hasRuntimeBits(zcu)) return .void;
7043 switch (fn_info.cc) {7300 switch (cc) {
7044 .@"inline" => unreachable,7301 .@"inline" => unreachable,
7045 .auto => {7302 .auto => {
7046 if (isByRef(ret_ty, zcu)) return .sret;7303 // Match the c calling convention in some cases to avoid llvm bugs.
7047
7048 const target = zcu.getTarget();7304 const target = zcu.getTarget();
7049 if (target.cpu.arch.isX86() and7305 if (target.cpu.arch == .x86_64 and ret_ty.isVector(zcu) and ret_ty.childType(zcu).toIntern() == .bool_type) return switch (ret_ty.vectorLen(zcu)) {
7050 !target.cpu.has(.x86, .avx512f) and7306 0 => .void,
7051 ret_ty.totalVectorBits(zcu) >= 512)7307 1...8 => .{ .mem_cast = .i8 },
7052 {7308 9...16 => .{ .mem_cast = .i16 },
7053 // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns7309 17...32 => .{ .mem_cast = .i32 },
7054 // "512-bit vector arguments require 'avx512f' for AVX512"7310 33...64 => .{ .mem_cast = .double },
7055 return .sret;7311 else => .by_val,
7056 }7312 };
70577313
7314 if (isByRef(ret_ty, zcu)) return .sret;
7058 return .by_val;7315 return .by_val;
7059 },7316 },
7060 .x86_64_sysv, .x86_64_x32 => return lowerSystemVFnRetTy(o, fn_info),7317 .x86_64_sysv, .x86_64_x32 => return fnReturnStrat_x86_64_sysv(o, ret_ty),
7061 .x86_64_win => return lowerWin64FnRetTy(o, fn_info),7318 .x86_64_win => return fnReturnStrat_x86_64_win(o, ret_ty),
7062 .x86_stdcall => if (isScalar(zcu, ret_ty)) {7319 .x86_stdcall => if (isScalar(zcu, ret_ty)) {
7063 assert(!isByRef(ret_ty, zcu));7320 assert(!isByRef(ret_ty, zcu));
7064 return .by_val;7321 return .by_val;
7065 } else return .sret,7322 } else return .sret,
7066 .x86_fastcall => return lowerX86FastcallFnRetTy(o, zcu, ret_ty),7323 .x86_fastcall => return fnReturnStrat_x86_fastcall(o, zcu, ret_ty),
7067 .x86_sysv, .x86_win => return if (isByRef(ret_ty, zcu)) .sret else .by_val,7324 .x86_sysv, .x86_win => return if (isByRef(ret_ty, zcu)) .sret else .by_val,
7068 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(ret_ty, zcu)) {7325 .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(ret_ty, zcu)) {
7069 .memory => return .sret,7326 .memory => return .sret,
...@@ -7124,7 +7381,7 @@ pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err...@@ -7124,7 +7381,7 @@ pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err
7124 }7381 }
7125}7382}
71267383
7127fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat {7384fn fnReturnStrat_x86_fastcall(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat {
7128 if (isScalar(zcu, ty)) {7385 if (isScalar(zcu, ty)) {
7129 assert(!isByRef(ty, zcu));7386 assert(!isByRef(ty, zcu));
7130 return .by_val;7387 return .by_val;
...@@ -7139,9 +7396,8 @@ fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnRe...@@ -7139,9 +7396,8 @@ fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnRe
7139 return .sret;7396 return .sret;
7140}7397}
71417398
7142fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat {7399fn fnReturnStrat_x86_64_win(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat {
7143 const zcu = o.zcu;7400 const zcu = o.zcu;
7144 const ret_ty = Type.fromInterned(fn_info.return_type);
7145 switch (x86_64_abi.classifyWindows(ret_ty, zcu, zcu.getTarget(), .ret)) {7401 switch (x86_64_abi.classifyWindows(ret_ty, zcu, zcu.getTarget(), .ret)) {
7146 .integer => if (isScalar(zcu, ret_ty)) {7402 .integer => if (isScalar(zcu, ret_ty)) {
7147 assert(!isByRef(ret_ty, zcu));7403 assert(!isByRef(ret_ty, zcu));
...@@ -7174,78 +7430,65 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err...@@ -7174,78 +7430,65 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err
7174 }7430 }
7175}7431}
71767432
7177fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat {7433fn fnReturnStrat_x86_64_sysv(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat {
7178 const zcu = o.zcu;7434 const zcu = o.zcu;
7179 const ip = &zcu.intern_pool;
7180 const ret_ty = Type.fromInterned(fn_info.return_type);
7181 if (isScalar(zcu, ret_ty)) {
7182 assert(!isByRef(ret_ty, zcu));
7183 return .by_val;
7184 }
7185 const classes = x86_64_abi.classifySystemV(ret_ty, zcu, zcu.getTarget(), .ret);7435 const classes = x86_64_abi.classifySystemV(ret_ty, zcu, zcu.getTarget(), .ret);
7186 var types_index: u32 = 0;
7187 var types_buffer: [8]Builder.Type = undefined;7436 var types_buffer: [8]Builder.Type = undefined;
7188 for (classes) |class| {7437 var types_len: u32 = 0;
7189 switch (class) {7438 for (classes, 0..) |class, class_index| switch (class) {
7190 .integer => {7439 .integer => {
7191 types_buffer[types_index] = .i64;7440 types_buffer[types_len] = try o.builder.intType(@min(8 * ret_ty.abiSize(zcu) - 64 * class_index, 64));
7192 types_index += 1;7441 types_len += 1;
7193 },7442 },
7194 .sse => {7443 .sse => {
7195 types_buffer[types_index] = .double;7444 types_buffer[types_len] = .double;
7196 types_index += 1;7445 types_len += 1;
7197 },7446 },
7198 .sseup => {7447 .sseup => {
7199 if (types_buffer[types_index - 1] == .double) {7448 if (types_buffer[types_len - 1] == .double) {
7200 types_buffer[types_index - 1] = .fp128;7449 if (ret_ty.isVector(zcu)) return .by_val;
7201 } else {7450 types_buffer[types_len - 1] = .fp128;
7202 types_buffer[types_index] = .double;7451 } else {
7203 types_index += 1;7452 types_buffer[types_len] = .double;
7204 }7453 types_len += 1;
7205 },7454 }
7206 .float => {7455 },
7207 types_buffer[types_index] = .float;7456 .float => {
7208 types_index += 1;7457 types_buffer[types_len] = .float;
7209 },7458 types_len += 1;
7210 .float_combine => {7459 },
7211 types_buffer[types_index] = try o.builder.vectorType(.normal, 2, .float);7460 .float_combine => {
7212 types_index += 1;7461 types_buffer[types_len] = try o.builder.vectorType(.normal, 2, .float);
7213 },7462 types_len += 1;
7214 .x87 => {7463 },
7215 if (types_index != 0 or classes[2] != .none) return .sret;7464 .x87 => {
7216 types_buffer[types_index] = .x86_fp80;7465 if (types_len > 0 or classes[2] != .none) return .sret;
7217 types_index += 1;7466 types_buffer[types_len] = .x86_fp80;
7218 },7467 types_len += 1;
7219 .x87up => continue,7468 },
7220 .none => break,7469 .x87up => continue,
7221 .memory => return .sret,7470 .none => break,
7222 .win_i128 => unreachable, // windows only7471 .memory => return if (ret_ty.isVector(zcu)) .by_val else .sret,
7223 .bool_vector_mask,7472 .win_i128 => unreachable, // windows only
7224 .integer_per_element,7473 .bool_vector_mask,
7225 .sse_per_element,7474 .integer_per_element,
7226 .sse_sse_x87_per_qword,7475 .sse_per_element,
7227 .sse_per_xword,7476 .sse_sse_x87_per_qword,
7228 .sse_per_yword,7477 .sse_per_xword,
7229 .sse_per_zword,7478 .sse_per_yword,
7230 => unreachable, // vectors already handled by `isScalar` above7479 .sse_per_zword,
7231 }7480 => return .by_val,
7232 }7481 };
7233 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});7482 if (types_len > 1) return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_len]) };
7234 if (first_non_integer == null or classes[first_non_integer.?] == .none) {7483 if (!isByRef(ret_ty, zcu)) {
7235 assert(first_non_integer orelse classes.len == types_index);7484 const llvm_ty = try o.lowerType(ret_ty, .as_value);
7236 switch (ip.indexToKey(ret_ty.toIntern())) {7485 if (types_buffer[0] == llvm_ty) return .by_val;
7237 .struct_type => {7486 if (types_buffer[0] == .i64 and llvm_ty.isPointer(&o.builder)) return .by_val;
7238 const size = ret_ty.abiSize(zcu);7487 if (types_buffer[0] == .double and llvm_ty.isVector(&o.builder) and
7239 assert(@divCeil(size, 8) == types_index);7488 llvm_ty.vectorLen(&o.builder) == 1 and
7240 if (size % 8 > 0) {7489 llvm_ty.scalarType(&o.builder) == .double) return .by_val;
7241 types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8));
7242 }
7243 },
7244 else => {},
7245 }
7246 if (types_index == 1) return .{ .mem_cast = types_buffer[0] };
7247 }7490 }
7248 return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_index]) };7491 return .{ .mem_cast = types_buffer[0] };
7249}7492}
72507493
7251/// This function deliberately does not handle `_BitInt` because it typically7494/// This function deliberately does not handle `_BitInt` because it typically
...@@ -7258,15 +7501,22 @@ pub fn ccAbiPromoteInt(cc: std.lang.CallingConvention, zcu: *Zcu, ty: Type) ?std...@@ -7258,15 +7501,22 @@ pub fn ccAbiPromoteInt(cc: std.lang.CallingConvention, zcu: *Zcu, ty: Type) ?std
7258 else => {},7501 else => {},
7259 }7502 }
72607503
7261 const ty_tag = ty.zigTypeTag(zcu);7504 const target = zcu.getTarget();
7262 const int_info = switch (ty_tag) {7505 const int_info: std.lang.Type.Int = if (ty.toIntern() == .bool_type)
7263 .bool => Type.u1.intInfo(zcu),7506 .{ .signedness = .unsigned, .bits = 1 }
7264 else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return null,7507 else if (ty.isAbiInt(zcu))
7265 };7508 ty.intInfo(zcu)
7509 else if (ty.isRuntimeFloat()) switch (ty.floatBits(target)) {
7510 else => unreachable,
7511 16, 32, 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
7512 .hard => return null,
7513 .soft => .{ .signedness = .unsigned, .bits = bits },
7514 },
7515 80, 128 => return null,
7516 } else return null;
72667517
7267 assert(int_info.bits == 0 or (int_info.bits == 1 and ty_tag == .bool) or std.math.isPowerOfTwo(int_info.bits));7518 assert(int_info.bits == 0 or (int_info.bits == 1 and ty.toIntern() == .bool_type) or std.math.isPowerOfTwo(int_info.bits));
72687519
7269 const target = zcu.getTarget();
7270 return switch (target.cpu.arch) {7520 return switch (target.cpu.arch) {
7271 .aarch64,7521 .aarch64,
7272 .aarch64_be,7522 .aarch64_be,
...@@ -7362,15 +7612,26 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool {...@@ -7362,15 +7612,26 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool {
7362 .void,7612 .void,
7363 .bool,7613 .bool,
7364 .int,7614 .int,
7365 .float,
7366 .pointer,7615 .pointer,
7367 .error_set,7616 .error_set,
7368 .@"fn",7617 .@"fn",
7369 .@"enum",7618 .@"enum",
7370 .vector,
7371 .@"anyframe",7619 .@"anyframe",
7372 => false,7620 => false,
73737621
7622 .float, .vector => {
7623 const target = zcu.getTarget();
7624 const scalar_ty = ty.scalarType(zcu);
7625 return if (scalar_ty.isRuntimeFloat()) switch (scalar_ty.floatBits(target)) {
7626 else => unreachable,
7627 16, 32, 64 => false,
7628 80, 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) {
7629 .hard => false,
7630 .soft => true,
7631 },
7632 } else false;
7633 },
7634
7374 .array,7635 .array,
7375 .frame,7636 .frame,
7376 => ty.hasRuntimeBits(zcu),7637 => ty.hasRuntimeBits(zcu),
...@@ -7431,12 +7692,19 @@ fn ptraddScaled(fg: *FuncGen, ptr: Builder.Value, index: Builder.Value, scale: u...@@ -7431,12 +7692,19 @@ fn ptraddScaled(fg: *FuncGen, ptr: Builder.Value, index: Builder.Value, scale: u
7431 return fg.wip.gep(.inbounds, llvm_scale_ty, ptr, &.{index}, "");7692 return fg.wip.gep(.inbounds, llvm_scale_ty, ptr, &.{index}, "");
7432}7693}
74337694
7434fn compilerRtIntBits(bits: u16) ?u16 {7695fn compilerRtPromoteInt(int_info: InternPool.Key.IntType) ?Type {
7435 inline for (.{ 32, 64, 128 }) |b| {7696 if (int_info.bits <= 32) return switch (int_info.signedness) {
7436 if (bits <= b) {7697 .signed => .i32,
7437 return b;7698 .unsigned => .u32,
7438 }7699 };
7439 }7700 if (int_info.bits <= 64) return switch (int_info.signedness) {
7701 .signed => .i64,
7702 .unsigned => .u64,
7703 };
7704 if (int_info.bits <= 128) return switch (int_info.signedness) {
7705 .signed => .i128,
7706 .unsigned => .u128,
7707 };
7440 return null;7708 return null;
7441}7709}
74427710
...@@ -7495,13 +7763,12 @@ fn appendConstraints(...@@ -7495,13 +7763,12 @@ fn appendConstraints(
7495}7763}
74967764
7497/// LLVM does not support all relevant intrinsics for all targets, so we7765/// LLVM does not support all relevant intrinsics for all targets, so we
7498/// may need to manually generate a compiler-rt call.7766/// may need to manually generate a compiler-rt call using a soft type.
7499fn intrinsicsAllowed(scalar_ty: Type, target: *const std.Target) bool {7767fn intrinsicsAllowed(scalar_ty: Type, target: *const std.Target) bool {
7500 return switch (scalar_ty.toIntern()) {7768 if (!scalar_ty.isRuntimeFloat()) return true;
7501 .f16_type => llvm.backendSupportsF16(target),7769 return switch (std.zig.target.compilerRtFloatAbi(target, scalar_ty.floatBits(target))) {
7502 .f80_type => (target.cTypeBitSize(.longdouble) == 80) and llvm.backendSupportsF80(target),7770 .hard => true,
7503 .f128_type => (target.cTypeBitSize(.longdouble) == 128) and llvm.backendSupportsF128(target),7771 .soft => false,
7504 else => true,
7505 };7772 };
7506}7773}
75077774
src/codegen/mips/abi.zig+8-1
...@@ -38,7 +38,14 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {...@@ -38,7 +38,14 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
38 return .byval;38 return .byval;
39 },39 },
40 .bool => return .byval,40 .bool => return .byval,
41 .float => return .byval,41 .float => return switch (ty.floatBits(target)) {
42 else => unreachable,
43 16, 32, 64 => .byval,
44 80, 128 => switch (max_direct_size) {
45 else => unreachable,
46 64 => .memory,
47 },
48 },
42 .int, .@"enum", .error_set => {49 .int, .@"enum", .error_set => {
43 return .byval;50 return .byval;
44 },51 },
src/codegen/riscv64/CodeGen.zig+2-2
...@@ -5036,7 +5036,7 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {...@@ -5036,7 +5036,7 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
5036 .register_pair,5036 .register_pair,
5037 => {5037 => {
5038 if (ret_ty.isVector(zcu)) {5038 if (ret_ty.isVector(zcu)) {
5039 const bit_size = ret_ty.totalVectorBits(zcu);5039 const bit_size = ret_ty.bitSize(zcu);
50405040
5041 // set the vtype to hold the entire vector's contents in a single element5041 // set the vtype to hold the entire vector's contents in a single element
5042 try func.setVl(.zero, 0, .{5042 try func.setVl(.zero, 0, .{
...@@ -6871,7 +6871,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6871,7 +6871,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6871 // size to the total size of the vector, and vmv.x.s will work then6871 // size to the total size of the vector, and vmv.x.s will work then
6872 if (src_reg.class() == .vector) {6872 if (src_reg.class() == .vector) {
6873 try func.setVl(.zero, 0, .{6873 try func.setVl(.zero, 0, .{
6874 .vsew = switch (ty.totalVectorBits(zcu)) {6874 .vsew = switch (ty.bitSize(zcu)) {
6875 8 => .@"8",6875 8 => .@"8",
6876 16 => .@"16",6876 16 => .@"16",
6877 32 => .@"32",6877 32 => .@"32",
src/codegen/riscv64/abi.zig+10-2
...@@ -56,12 +56,20 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {...@@ -56,12 +56,20 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
56 return .integer;56 return .integer;
57 },57 },
58 .bool => return .integer,58 .bool => return .integer,
59 .float => return .byval,
60 .int, .@"enum", .error_set => {59 .int, .@"enum", .error_set => {
61 const bit_size = ty.bitSize(zcu);60 const bit_size = ty.bitSize(zcu);
62 if (bit_size > max_byval_size) return .memory;61 if (bit_size > max_byval_size) return .memory;
63 return .byval;62 return .byval;
64 },63 },
64 .float => return switch (ty.floatBits(target)) {
65 else => unreachable,
66 16, 32, 64, 128 => .byval,
67 80 => switch (max_byval_size) {
68 else => unreachable,
69 64 => .memory,
70 128 => .double_integer,
71 },
72 },
65 .vector => {73 .vector => {
66 const bit_size = ty.bitSize(zcu);74 const bit_size = ty.bitSize(zcu);
67 if (bit_size > max_byval_size) return .memory;75 if (bit_size > max_byval_size) return .memory;
...@@ -190,7 +198,7 @@ pub fn classifySystem(ty: Type, zcu: *Zcu) [8]SystemClass {...@@ -190,7 +198,7 @@ pub fn classifySystem(ty: Type, zcu: *Zcu) [8]SystemClass {
190 },198 },
191 .vector => {199 .vector => {
192 // we pass vectors through integer registers if they are small enough to fit.200 // we pass vectors through integer registers if they are small enough to fit.
193 const vec_bits = ty.totalVectorBits(zcu);201 const vec_bits = ty.bitSize(zcu);
194 if (vec_bits <= 64) {202 if (vec_bits <= 64) {
195 result[0] = .integer;203 result[0] = .integer;
196 return result;204 return result;
src/codegen/s390x/abi.zig+5-3
...@@ -38,9 +38,11 @@ pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class {...@@ -38,9 +38,11 @@ pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class {
38 1...64 => .simple,38 1...64 => .simple,
39 else => .pointer,39 else => .pointer,
40 },40 },
41 .float => return switch (ty.floatBits(zcu.getTarget())) {41 .float => switch (ty.floatBits(zcu.getTarget())) {
42 16, 32, 64 => .double_or_float,42 else => unreachable,
43 else => .pointer,43 16, 32, 64 => return .double_or_float,
44 80 => {},
45 128 => return .pointer,
44 },46 },
45 .pointer, .optional => return .simple,47 .pointer, .optional => return .simple,
46 .array => switch (ty.arrayLen(zcu)) {48 .array => switch (ty.arrayLen(zcu)) {
src/codegen/wasm/CodeGen.zig+9-15
...@@ -24,12 +24,6 @@ const Alignment = InternPool.Alignment;...@@ -24,12 +24,6 @@ const Alignment = InternPool.Alignment;
24const errUnionPayloadOffset = codegen.errUnionPayloadOffset;24const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
25const errUnionErrorOffset = codegen.errUnionErrorOffset;25const errUnionErrorOffset = codegen.errUnionErrorOffset;
2626
27const target_util = @import("../../target.zig");
28const libcFloatPrefix = target_util.libcFloatPrefix;
29const libcFloatSuffix = target_util.libcFloatSuffix;
30const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
31const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
32
33pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {27pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
34 return comptime &.initMany(&.{28 return comptime &.initMany(&.{
35 .expand_bit_cast_safe,29 .expand_bit_cast_safe,
...@@ -2515,15 +2509,15 @@ const IntType = struct {...@@ -2515,15 +2509,15 @@ const IntType = struct {
2515 .anyerror, .adhoc_inferred_error_set => .{ .is_signed = false, .bits = zcu.errorSetBits() },2509 .anyerror, .adhoc_inferred_error_set => .{ .is_signed = false, .bits = zcu.errorSetBits() },
2516 .isize => .{ .is_signed = true, .bits = cg.target.ptrBitWidth() },2510 .isize => .{ .is_signed = true, .bits = cg.target.ptrBitWidth() },
2517 .usize => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },2511 .usize => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
2518 .c_char => .{ .is_signed = cg.target.cCharSignedness() == .signed, .bits = cg.target.cTypeBitSize(.char) },2512 .c_char => .{ .is_signed = cg.target.cCharSignedness().? == .signed, .bits = cg.target.cTypeBitSize(.char).? },
2519 .c_short => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.short) },2513 .c_short => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.short).? },
2520 .c_ushort => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.short) },2514 .c_ushort => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.short).? },
2521 .c_int => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.int) },2515 .c_int => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.int).? },
2522 .c_uint => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.int) },2516 .c_uint => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.int).? },
2523 .c_long => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.long) },2517 .c_long => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.long).? },
2524 .c_ulong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.long) },2518 .c_ulong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.long).? },
2525 .c_longlong => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.longlong) },2519 .c_longlong => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.longlong).? },
2526 .c_ulonglong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.longlong) },2520 .c_ulonglong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.longlong).? },
2527 .f16, .f32, .f64, .f80, .f128, .c_longdouble => unreachable,2521 .f16, .f32, .f64, .f80, .f128, .c_longdouble => unreachable,
2528 .anyopaque, .void, .type, .comptime_int, .comptime_float, .noreturn, .null, .undefined, .enum_literal, .generic_poison => unreachable,2522 .anyopaque, .void, .type, .comptime_int, .comptime_float, .noreturn, .null, .undefined, .enum_literal, .generic_poison => unreachable,
2529 },2523 },
src/codegen/wasm/abi.zig+5-1
...@@ -25,7 +25,11 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class {...@@ -25,7 +25,11 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class {
25 assert(ty.hasRuntimeBits(zcu));25 assert(ty.hasRuntimeBits(zcu));
26 switch (ty.zigTypeTag(zcu)) {26 switch (ty.zigTypeTag(zcu)) {
27 .int, .@"enum", .error_set => return .{ .direct = ty },27 .int, .@"enum", .error_set => return .{ .direct = ty },
28 .float => return .{ .direct = ty },28 .float => return switch (ty.floatBits(zcu.getTarget())) {
29 else => unreachable,
30 16, 32, 64, 128 => .{ .direct = ty },
31 80 => .indirect,
32 },
29 .bool => return .{ .direct = ty },33 .bool => return .{ .direct = ty },
30 .vector => return .{ .direct = ty },34 .vector => return .{ .direct = ty },
31 .array => return .indirect,35 .array => return .indirect,
src/codegen/x86_64/CodeGen.zig+9-9
...@@ -182636,15 +182636,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int {...@@ -182636,15 +182636,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int {
182636 .anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() },182636 .anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() },
182637 .isize => .{ .signedness = .signed, .bits = cg.target.ptrBitWidth() },182637 .isize => .{ .signedness = .signed, .bits = cg.target.ptrBitWidth() },
182638 .usize => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },182638 .usize => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
182639 .c_char => .{ .signedness = cg.target.cCharSignedness(), .bits = cg.target.cTypeBitSize(.char) },182639 .c_char => .{ .signedness = cg.target.cCharSignedness().?, .bits = cg.target.cTypeBitSize(.char).? },
182640 .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short) },182640 .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short).? },
182641 .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short) },182641 .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short).? },
182642 .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int) },182642 .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int).? },
182643 .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int) },182643 .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int).? },
182644 .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long) },182644 .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long).? },
182645 .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long) },182645 .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long).? },
182646 .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong) },182646 .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong).? },
182647 .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong) },182647 .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong).? },
182648 .f16, .f32, .f64, .f80, .f128, .c_longdouble => null,182648 .f16, .f32, .f64, .f80, .f128, .c_longdouble => null,
182649 .anyopaque,182649 .anyopaque,
182650 .void,182650 .void,
src/codegen/x86_64/abi.zig+7-5
...@@ -133,7 +133,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:...@@ -133,7 +133,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx:
133 .float => switch (ty.floatBits(target)) {133 .float => switch (ty.floatBits(target)) {
134 16, 32, 64 => .sse,134 16, 32, 64 => .sse,
135 80 => .memory,135 80 => .memory,
136 128 => if (ctx == .arg) .memory else .sse,136 128 => .win_i128,
137 else => unreachable,137 else => unreachable,
138 },138 },
139 .vector => {139 .vector => {
...@@ -238,16 +238,18 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont...@@ -238,16 +238,18 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont
238 };238 };
239 const unaligned_size = elem_ty.abiSize(zcu) * len;239 const unaligned_size = elem_ty.abiSize(zcu) * len;
240 if (unaligned_size <= 4) return Class.one_integer;240 if (unaligned_size <= 4) return Class.one_integer;
241 if (ctx == .arg and unaligned_size == 8 * 1 * 1 and len == 1 and241 if (unaligned_size == 8 * 1 * 1 and len == 1) {
242 elem_ty.isRuntimeFloat()) return Class.stack; // what242 if (ctx == .arg and elem_ty.isRuntimeFloat()) return Class.stack; // what?
243 if (ctx != .other and !elem_ty.isRuntimeFloat() and target.os.tag == .freebsd) return Class.one_integer; // who?
244 }
243 if (unaligned_size <= 8 * 1) return .{ .sse, .none, .none, .none, .none, .none, .none, .none };245 if (unaligned_size <= 8 * 1) return .{ .sse, .none, .none, .none, .none, .none, .none, .none };
244 if (unaligned_size <= 8 * 2) return .{ .sse, .sseup, .none, .none, .none, .none, .none, .none };246 if (unaligned_size <= 8 * 2) return .{ .sse, .sseup, .none, .none, .none, .none, .none, .none };
245 if (!target.cpu.has(.x86, .avx)) {247 if (!target.cpu.has(.x86, .avx)) {
246 if (ctx == .ret) switch (unaligned_size) {248 if (ctx == .ret) switch (unaligned_size) {
247 else => {},249 else => {},
248 8 * 3 => if (len == 3) return if (elem_ty.isRuntimeFloat()) .{250 8 * 3 => if (len == 3) return if (elem_ty.isRuntimeFloat()) .{
249 .sse_sse_x87_per_qword, .none, .none, .none, .none, .none, .none, .none, // how251 .sse_sse_x87_per_qword, .none, .none, .none, .none, .none, .none, .none, // how?
250 } else Class.len_integers, // why252 } else Class.len_integers, // why?
251 8 * 2 * 2, 8 * 2 * 4 => return .{ .sse_per_xword, .none, .none, .none, .none, .none, .none, .none },253 8 * 2 * 2, 8 * 2 * 4 => return .{ .sse_per_xword, .none, .none, .none, .none, .none, .none, .none },
252 };254 };
253 return Class.stack;255 return Class.stack;
src/libs/mingw/Preprocessor.zig+2-2
...@@ -91,9 +91,9 @@ fn addTokenAssumeCapacity(pp: *Preprocessor, tok: Token) void {...@@ -91,9 +91,9 @@ fn addTokenAssumeCapacity(pp: *Preprocessor, tok: Token) void {
9191
92fn defineBuiltins(pp: *Preprocessor) !void {92fn defineBuiltins(pp: *Preprocessor) !void {
93 var buf: [5]u8 = undefined;93 var buf: [5]u8 = undefined;
94 var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.longdouble)}) catch unreachable;94 var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeByteSize(.longdouble).?}) catch unreachable;
95 try pp.defineBuiltinValue("__SIZEOF_LONG_DOUBLE__", val, .pp_num);95 try pp.defineBuiltinValue("__SIZEOF_LONG_DOUBLE__", val, .pp_num);
96 val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.double)}) catch unreachable;96 val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeByteSize(.double).?}) catch unreachable;
97 try pp.defineBuiltinValue("__SIZEOF_DOUBLE__", val, .pp_num);97 try pp.defineBuiltinValue("__SIZEOF_DOUBLE__", val, .pp_num);
9898
99 if (pp.target.abi.isGnu()) {99 if (pp.target.abi.isGnu()) {
src/target.zig+2-2
...@@ -881,13 +881,13 @@ pub fn libcFloatSuffix(float_bits: u16) []const u8 {...@@ -881,13 +881,13 @@ pub fn libcFloatSuffix(float_bits: u16) []const u8 {
881 };881 };
882}882}
883883
884pub fn compilerRtFloatAbbrev(float_bits: u16) []const u8 {884pub fn compilerRtFloatAbbrev(target: *const std.Target, float_bits: u16) []const u8 {
885 return switch (float_bits) {885 return switch (float_bits) {
886 16 => "h",886 16 => "h",
887 32 => "s",887 32 => "s",
888 64 => "d",888 64 => "d",
889 80 => "x",889 80 => "x",
890 128 => "t",890 128 => if (target.cpu.arch.isPowerPC()) "k" else "t",
891 else => unreachable,891 else => unreachable,
892 };892 };
893}893}
test/behavior/align.zig+32-10
...@@ -129,8 +129,7 @@ test "alignment and size of structs with 128-bit fields" {...@@ -129,8 +129,7 @@ test "alignment and size of structs with 128-bit fields" {
129 y: u8,129 y: u8,
130 };130 };
131 const expected = switch (builtin.cpu.arch) {131 const expected = switch (builtin.cpu.arch) {
132 .s390x,132 .s390x => .{
133 => .{
134 .a_align = 8,133 .a_align = 8,
135 .a_size = 16,134 .a_size = 16,
136135
...@@ -142,7 +141,32 @@ test "alignment and size of structs with 128-bit fields" {...@@ -142,7 +141,32 @@ test "alignment and size of structs with 128-bit fields" {
142 .u129_align = 8,141 .u129_align = 8,
143 .u129_size = 24,142 .u129_size = 24,
144 },143 },
145144 .x86 => switch (builtin.os.tag) {
145 else => .{
146 .a_align = 4,
147 .a_size = 16,
148
149 .b_align = 4,
150 .b_size = 20,
151
152 .u128_align = 4,
153 .u128_size = 16,
154 .u129_align = 4,
155 .u129_size = 20,
156 },
157 .uefi, .windows => .{
158 .a_align = 8,
159 .a_size = 16,
160
161 .b_align = 8,
162 .b_size = 24,
163
164 .u128_align = 8,
165 .u128_size = 16,
166 .u129_align = 8,
167 .u129_size = 24,
168 },
169 },
146 .amdgcn,170 .amdgcn,
147 .arm,171 .arm,
148 .armeb,172 .armeb,
...@@ -155,12 +179,13 @@ test "alignment and size of structs with 128-bit fields" {...@@ -155,12 +179,13 @@ test "alignment and size of structs with 128-bit fields" {
155 .powerpc,179 .powerpc,
156 .powerpcle,180 .powerpcle,
157 .riscv32,181 .riscv32,
182 .sparc,
158 => .{183 => .{
159 .a_align = 8,184 .a_align = 8,
160 .a_size = 16,185 .a_size = 16,
161186
162 .b_align = 16,187 .b_align = 8,
163 .b_size = 32,188 .b_size = 24,
164189
165 .u128_align = 8,190 .u128_align = 8,
166 .u128_size = 16,191 .u128_size = 16,
...@@ -178,12 +203,10 @@ test "alignment and size of structs with 128-bit fields" {...@@ -178,12 +203,10 @@ test "alignment and size of structs with 128-bit fields" {
178 .nvptx64,203 .nvptx64,
179 .powerpc64,204 .powerpc64,
180 .powerpc64le,205 .powerpc64le,
181 .sparc,
182 .sparc64,206 .sparc64,
183 .riscv64,207 .riscv64,
184 .wasm32,208 .wasm32,
185 .wasm64,209 .wasm64,
186 .x86,
187 .x86_64,210 .x86_64,
188 => .{211 => .{
189 .a_align = 16,212 .a_align = 16,
...@@ -200,12 +223,11 @@ test "alignment and size of structs with 128-bit fields" {...@@ -200,12 +223,11 @@ test "alignment and size of structs with 128-bit fields" {
200223
201 else => return error.SkipZigTest,224 else => return error.SkipZigTest,
202 };225 };
203 const min_struct_align = if (builtin.zig_backend == .stage2_c) if (builtin.cpu.arch == .s390x) 8 else 16 else 0;
204 comptime {226 comptime {
205 assert(@alignOf(A) == @max(expected.a_align, min_struct_align));227 assert(@alignOf(A) == expected.a_align);
206 assert(@sizeOf(A) == expected.a_size);228 assert(@sizeOf(A) == expected.a_size);
207229
208 assert(@alignOf(B) == @max(expected.b_align, min_struct_align));230 assert(@alignOf(B) == expected.b_align);
209 assert(@sizeOf(B) == expected.b_size);231 assert(@sizeOf(B) == expected.b_size);
210232
211 assert(@alignOf(u128) == expected.u128_align);233 assert(@alignOf(u128) == expected.u128_align);
test/behavior/cast.zig+2-1
...@@ -181,6 +181,7 @@ test "@floatFromInt(f80)" {...@@ -181,6 +181,7 @@ test "@floatFromInt(f80)" {
181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;182 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
183 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;183 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
184 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
184185
185 const S = struct {186 const S = struct {
186 fn doTheTest(comptime Int: type) !void {187 fn doTheTest(comptime Int: type) !void {
...@@ -204,7 +205,7 @@ test "@floatFromInt(f80)" {...@@ -204,7 +205,7 @@ test "@floatFromInt(f80)" {
204 try S.doTheTest(i64);205 try S.doTheTest(i64);
205 try S.doTheTest(i80);206 try S.doTheTest(i80);
206 try S.doTheTest(i128);207 try S.doTheTest(i128);
207 // try S.doTheTest(i256); // TODO missing compiler_rt symbols208 try S.doTheTest(i256);
208 try comptime S.doTheTest(i31);209 try comptime S.doTheTest(i31);
209 try comptime S.doTheTest(i32);210 try comptime S.doTheTest(i32);
210 try comptime S.doTheTest(i45);211 try comptime S.doTheTest(i45);
test/behavior/floatop.zig-22
...@@ -118,7 +118,6 @@ fn testMul(comptime T: type) !void {...@@ -118,7 +118,6 @@ fn testMul(comptime T: type) !void {
118test "cmp f16" {118test "cmp f16" {
119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;120 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
121 if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
122121
123 try testCmp(f16);122 try testCmp(f16);
124 try comptime testCmp(f16);123 try comptime testCmp(f16);
...@@ -127,7 +126,6 @@ test "cmp f16" {...@@ -127,7 +126,6 @@ test "cmp f16" {
127test "cmp f32" {126test "cmp f32" {
128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;127 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
130 if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
131129
132 try testCmp(f32);130 try testCmp(f32);
133 try comptime testCmp(f32);131 try comptime testCmp(f32);
...@@ -1173,11 +1171,6 @@ test "@floor f80/f128/c_longdouble" {...@@ -1173,11 +1171,6 @@ test "@floor f80/f128/c_longdouble" {
1173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1171 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1174 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1172 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11751173
1176 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1177 // https://github.com/ziglang/zig/issues/12602
1178 return error.SkipZigTest;
1179 }
1180
1181 try testFloor(f80);1174 try testFloor(f80);
1182 try comptime testFloor(f80);1175 try comptime testFloor(f80);
1183 try testFloor(f128);1176 try testFloor(f128);
...@@ -1261,11 +1254,6 @@ test "@ceil f80/f128/c_longdouble" {...@@ -1261,11 +1254,6 @@ test "@ceil f80/f128/c_longdouble" {
1261 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1254 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1262 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1255 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12631256
1264 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1265 // https://github.com/ziglang/zig/issues/12602
1266 return error.SkipZigTest;
1267 }
1268
1269 try testCeil(f80);1257 try testCeil(f80);
1270 try comptime testCeil(f80);1258 try comptime testCeil(f80);
1271 try testCeil(f128);1259 try testCeil(f128);
...@@ -1280,11 +1268,6 @@ test "@ceil f80 maxInt(u64)" {...@@ -1280,11 +1268,6 @@ test "@ceil f80 maxInt(u64)" {
1280 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1268 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1281 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1269 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12821270
1283 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1284 // https://github.com/ziglang/zig/issues/12602
1285 return error.SkipZigTest;
1286 }
1287
1288 var x: u64 = std.math.maxInt(u64);1271 var x: u64 = std.math.maxInt(u64);
1289 x = x;1272 x = x;
1290 const float: f80 = @floatFromInt(x);1273 const float: f80 = @floatFromInt(x);
...@@ -1366,11 +1349,6 @@ test "@trunc f80/f128/c_longdouble" {...@@ -1366,11 +1349,6 @@ test "@trunc f80/f128/c_longdouble" {
1366 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1349 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1367 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1350 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13681351
1369 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1370 // https://github.com/ziglang/zig/issues/12602
1371 return error.SkipZigTest;
1372 }
1373
1374 try testTrunc(f80);1352 try testTrunc(f80);
1375 try comptime testTrunc(f80);1353 try comptime testTrunc(f80);
1376 try testTrunc(f128);1354 try testTrunc(f128);
test/behavior/math.zig-6
...@@ -2142,11 +2142,6 @@ test "remainder division" {...@@ -2142,11 +2142,6 @@ test "remainder division" {
2142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2143 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2143 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21442144
2145 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
2146 // https://github.com/ziglang/zig/issues/12602
2147 return error.SkipZigTest;
2148 }
2149
2150 if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;2145 if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
21512146
2152 try comptime remdiv(f16);2147 try comptime remdiv(f16);
...@@ -2337,7 +2332,6 @@ test "NaN comparison" {...@@ -2337,7 +2332,6 @@ test "NaN comparison" {
2337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2339 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2340 if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234
23412335
2342 try testNanEqNan(f16);2336 try testNanEqNan(f16);
2343 try testNanEqNan(f32);2337 try testNanEqNan(f32);
test/behavior/vector.zig+19-5
...@@ -774,6 +774,8 @@ test "vector reduce operation" {...@@ -774,6 +774,8 @@ test "vector reduce operation" {
774 try testReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9));774 try testReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9));
775 try testReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9));775 try testReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9));
776 try testReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9));776 try testReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9));
777 try testReduce(.Add, [4]f80{ -1.9, 5.1, -60.3, 100.0 }, @as(f80, 42.9));
778 try testReduce(.Add, [4]f128{ -1.9, 5.1, -60.3, 100.0 }, @as(f128, 42.9));
777779
778 try testReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false));780 try testReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false));
779 try testReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0));781 try testReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0));
...@@ -792,6 +794,8 @@ test "vector reduce operation" {...@@ -792,6 +794,8 @@ test "vector reduce operation" {
792 try testReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0));794 try testReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0));
793 try testReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0));795 try testReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0));
794 try testReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0));796 try testReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0));
797 try testReduce(.Min, [4]f80{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f80, -100.0));
798 try testReduce(.Min, [4]f128{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f128, -100.0));
795799
796 try testReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4));800 try testReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4));
797 try testReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4));801 try testReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4));
...@@ -804,6 +808,8 @@ test "vector reduce operation" {...@@ -804,6 +808,8 @@ test "vector reduce operation" {
804 try testReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9));808 try testReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9));
805 try testReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9));809 try testReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9));
806 try testReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9));810 try testReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9));
811 try testReduce(.Max, [4]f80{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f80, 10.0e9));
812 try testReduce(.Max, [4]f128{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f128, 10.0e9));
807813
808 try testReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24));814 try testReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24));
809 try testReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24));815 try testReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24));
...@@ -816,6 +822,8 @@ test "vector reduce operation" {...@@ -816,6 +822,8 @@ test "vector reduce operation" {
816 try testReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7));822 try testReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7));
817 try testReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7));823 try testReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7));
818 try testReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7));824 try testReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7));
825 try testReduce(.Mul, [4]f80{ -1.9, 5.1, -60.3, 100.0 }, @as(f80, 58430.7));
826 try testReduce(.Mul, [4]f128{ -1.9, 5.1, -60.3, 100.0 }, @as(f128, 58430.7));
819827
820 try testReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true));828 try testReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true));
821 try testReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1));829 try testReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1));
...@@ -823,6 +831,7 @@ test "vector reduce operation" {...@@ -823,6 +831,7 @@ test "vector reduce operation" {
823 try testReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0));831 try testReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0));
824 try testReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff));832 try testReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff));
825 try testReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff));833 try testReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff));
834 try testReduce(.Or, [4]u80{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u80, 0xffffffff));
826835
827 try testReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true));836 try testReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true));
828 try testReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1));837 try testReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1));
...@@ -835,22 +844,32 @@ test "vector reduce operation" {...@@ -835,22 +844,32 @@ test "vector reduce operation" {
835 const f16_nan = math.nan(f16);844 const f16_nan = math.nan(f16);
836 const f32_nan = math.nan(f32);845 const f32_nan = math.nan(f32);
837 const f64_nan = math.nan(f64);846 const f64_nan = math.nan(f64);
847 const f80_nan = math.nan(f80);
848 const f128_nan = math.nan(f128);
838849
839 try testReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);850 try testReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
840 try testReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);851 try testReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
841 try testReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);852 try testReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
853 try testReduce(.Add, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, f80_nan);
854 try testReduce(.Add, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, f128_nan);
842855
843 try testReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, -1.9));856 try testReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, -1.9));
844 try testReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, -1.9));857 try testReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, -1.9));
845 try testReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, -1.9));858 try testReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, -1.9));
859 try testReduce(.Min, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, @as(f80, -1.9));
860 try testReduce(.Min, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, @as(f128, -1.9));
846861
847 try testReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, 100.0));862 try testReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, 100.0));
848 try testReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, 100.0));863 try testReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, 100.0));
849 try testReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, 100.0));864 try testReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, 100.0));
865 try testReduce(.Max, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, @as(f80, 100.0));
866 try testReduce(.Max, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, @as(f128, 100.0));
850867
851 try testReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);868 try testReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
852 try testReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);869 try testReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
853 try testReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);870 try testReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
871 try testReduce(.Mul, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, f80_nan);
872 try testReduce(.Mul, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, f128_nan);
854 }873 }
855 };874 };
856875
...@@ -1319,11 +1338,6 @@ test "byte vector initialized in inline function" {...@@ -1319,11 +1338,6 @@ test "byte vector initialized in inline function" {
1319 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1338 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1320 if (builtin.cpu.arch == .hexagon and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;1339 if (builtin.cpu.arch == .hexagon and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
13211340
1322 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and comptime builtin.cpu.has(.x86, .avx512f)) {
1323 // TODO https://github.com/ziglang/zig/issues/13279
1324 return error.SkipZigTest;
1325 }
1326
1327 const S = struct {1341 const S = struct {
1328 fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {1342 fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
1329 return .{ e0, e1, e2, e3 };1343 return .{ e0, e1, e2, e3 };
test/c_abi/cfuncs.c+9-1
...@@ -408,7 +408,11 @@ void c_test_longdouble(void) {...@@ -408,7 +408,11 @@ void c_test_longdouble(void) {
408 zig_8_longdouble(0, 1, 2, 3, 4, 5, 6, 7, 10, 9);408 zig_8_longdouble(0, 1, 2, 3, 4, 5, 6, 7, 10, 9);
409}409}
410410
411#if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) || defined(__wasm__)411#ifndef __hexagon__
412#ifndef __loongarch__
413#ifndef __mips__
414#ifndef ZIG_PPC64
415#if !(defined(__i386__) && defined(_WIN32))
412416
413typedef bool Vector_2_bool __attribute__((ext_vector_type(2)));417typedef bool Vector_2_bool __attribute__((ext_vector_type(2)));
414418
...@@ -4657,6 +4661,10 @@ void c_test_vector_512_bool(void) {...@@ -4657,6 +4661,10 @@ void c_test_vector_512_bool(void) {
4657 });4661 });
4658}4662}
46594663
4664#endif
4665#endif
4666#endif
4667#endif
4660#endif4668#endif
46614669
4662typedef uint8_t Vector_1_u8 __attribute__((vector_size(1 * sizeof(uint8_t))));4670typedef uint8_t Vector_1_u8 __attribute__((vector_size(1 * sizeof(uint8_t))));
test/c_abi/main.zig+103-38
...@@ -451,8 +451,11 @@ test "long double" {...@@ -451,8 +451,11 @@ test "long double" {
451451
452comptime {452comptime {
453 skip: {453 skip: {
454 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;454 if (builtin.cpu.arch == .hexagon) break :skip;
455 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;455 if (builtin.cpu.arch == .loongarch64) break :skip;
456 if (builtin.cpu.arch.isMIPS()) break :skip;
457 if (builtin.cpu.arch.isPowerPC64()) break :skip;
458 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
456459
457 _ = struct {460 _ = struct {
458 export fn zig_ret_vector_2_bool() @Vector(2, bool) {461 export fn zig_ret_vector_2_bool() @Vector(2, bool) {
...@@ -474,7 +477,13 @@ extern fn c_vector_2_bool(@Vector(2, bool)) void;...@@ -474,7 +477,13 @@ extern fn c_vector_2_bool(@Vector(2, bool)) void;
474extern fn c_test_vector_2_bool() void;477extern fn c_test_vector_2_bool() void;
475478
476test "@Vector(2, bool)" {479test "@Vector(2, bool)" {
477 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;480 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
481 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
482 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
483 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
484 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
485 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
486 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
478487
479 const vec = c_ret_vector_2_bool();488 const vec = c_ret_vector_2_bool();
480 try expect(vec[0] == true);489 try expect(vec[0] == true);
...@@ -488,8 +497,11 @@ test "@Vector(2, bool)" {...@@ -488,8 +497,11 @@ test "@Vector(2, bool)" {
488497
489comptime {498comptime {
490 skip: {499 skip: {
491 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;500 if (builtin.cpu.arch == .hexagon) break :skip;
492 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;501 if (builtin.cpu.arch == .loongarch64) break :skip;
502 if (builtin.cpu.arch.isMIPS()) break :skip;
503 if (builtin.cpu.arch.isPowerPC64()) break :skip;
504 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
493505
494 _ = struct {506 _ = struct {
495 export fn zig_ret_vector_4_bool() @Vector(4, bool) {507 export fn zig_ret_vector_4_bool() @Vector(4, bool) {
...@@ -515,7 +527,13 @@ extern fn c_vector_4_bool(@Vector(4, bool)) void;...@@ -515,7 +527,13 @@ extern fn c_vector_4_bool(@Vector(4, bool)) void;
515extern fn c_test_vector_4_bool() void;527extern fn c_test_vector_4_bool() void;
516528
517test "@Vector(4, bool)" {529test "@Vector(4, bool)" {
518 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;530 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
531 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
532 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
533 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
534 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
535 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
536 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
519537
520 const vec = c_ret_vector_4_bool();538 const vec = c_ret_vector_4_bool();
521 try expect(vec[0] == true);539 try expect(vec[0] == true);
...@@ -533,8 +551,11 @@ test "@Vector(4, bool)" {...@@ -533,8 +551,11 @@ test "@Vector(4, bool)" {
533551
534comptime {552comptime {
535 skip: {553 skip: {
536 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;554 if (builtin.cpu.arch == .hexagon) break :skip;
537 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;555 if (builtin.cpu.arch == .loongarch64) break :skip;
556 if (builtin.cpu.arch.isMIPS()) break :skip;
557 if (builtin.cpu.arch.isPowerPC64()) break :skip;
558 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
538559
539 _ = struct {560 _ = struct {
540 export fn zig_ret_vector_8_bool() @Vector(8, bool) {561 export fn zig_ret_vector_8_bool() @Vector(8, bool) {
...@@ -568,7 +589,13 @@ extern fn c_vector_8_bool(@Vector(8, bool)) void;...@@ -568,7 +589,13 @@ extern fn c_vector_8_bool(@Vector(8, bool)) void;
568extern fn c_test_vector_8_bool() void;589extern fn c_test_vector_8_bool() void;
569590
570test "@Vector(8, bool)" {591test "@Vector(8, bool)" {
571 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;592 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
593 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
594 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
595 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
596 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
597 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
598 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
572599
573 const vec = c_ret_vector_8_bool();600 const vec = c_ret_vector_8_bool();
574 try expect(vec[0] == false);601 try expect(vec[0] == false);
...@@ -594,8 +621,11 @@ test "@Vector(8, bool)" {...@@ -594,8 +621,11 @@ test "@Vector(8, bool)" {
594621
595comptime {622comptime {
596 skip: {623 skip: {
597 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;624 if (builtin.cpu.arch == .hexagon) break :skip;
598 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;625 if (builtin.cpu.arch == .loongarch64) break :skip;
626 if (builtin.cpu.arch.isMIPS()) break :skip;
627 if (builtin.cpu.arch.isPowerPC64()) break :skip;
628 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
599629
600 _ = struct {630 _ = struct {
601 export fn zig_ret_vector_16_bool() @Vector(16, bool) {631 export fn zig_ret_vector_16_bool() @Vector(16, bool) {
...@@ -645,7 +675,13 @@ extern fn c_vector_16_bool(@Vector(16, bool)) void;...@@ -645,7 +675,13 @@ extern fn c_vector_16_bool(@Vector(16, bool)) void;
645extern fn c_test_vector_16_bool() void;675extern fn c_test_vector_16_bool() void;
646676
647test "@Vector(16, bool)" {677test "@Vector(16, bool)" {
648 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;678 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
679 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
680 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
681 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
682 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
683 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
684 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
649685
650 const vec = c_ret_vector_16_bool();686 const vec = c_ret_vector_16_bool();
651 try expect(vec[0] == true);687 try expect(vec[0] == true);
...@@ -687,8 +723,11 @@ test "@Vector(16, bool)" {...@@ -687,8 +723,11 @@ test "@Vector(16, bool)" {
687723
688comptime {724comptime {
689 skip: {725 skip: {
690 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;726 if (builtin.cpu.arch == .hexagon) break :skip;
691 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;727 if (builtin.cpu.arch == .loongarch64) break :skip;
728 if (builtin.cpu.arch.isMIPS()) break :skip;
729 if (builtin.cpu.arch.isPowerPC64()) break :skip;
730 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
692731
693 _ = struct {732 _ = struct {
694 export fn zig_ret_vector_32_bool() @Vector(32, bool) {733 export fn zig_ret_vector_32_bool() @Vector(32, bool) {
...@@ -770,7 +809,13 @@ extern fn c_vector_32_bool(@Vector(32, bool)) void;...@@ -770,7 +809,13 @@ extern fn c_vector_32_bool(@Vector(32, bool)) void;
770extern fn c_test_vector_32_bool() void;809extern fn c_test_vector_32_bool() void;
771810
772test "@Vector(32, bool)" {811test "@Vector(32, bool)" {
773 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;812 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
813 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
814 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
815 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
816 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
817 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
818 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
774819
775 const vec = c_ret_vector_32_bool();820 const vec = c_ret_vector_32_bool();
776 try expect(vec[0] == true);821 try expect(vec[0] == true);
...@@ -844,8 +889,11 @@ test "@Vector(32, bool)" {...@@ -844,8 +889,11 @@ test "@Vector(32, bool)" {
844889
845comptime {890comptime {
846 skip: {891 skip: {
847 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;892 if (builtin.cpu.arch == .hexagon) break :skip;
848 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;893 if (builtin.cpu.arch == .loongarch64) break :skip;
894 if (builtin.cpu.arch.isMIPS()) break :skip;
895 if (builtin.cpu.arch.isPowerPC64()) break :skip;
896 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
849897
850 _ = struct {898 _ = struct {
851 export fn zig_ret_vector_64_bool() @Vector(64, bool) {899 export fn zig_ret_vector_64_bool() @Vector(64, bool) {
...@@ -991,7 +1039,11 @@ extern fn c_vector_64_bool(@Vector(64, bool)) void;...@@ -991,7 +1039,11 @@ extern fn c_vector_64_bool(@Vector(64, bool)) void;
991extern fn c_test_vector_64_bool() void;1039extern fn c_test_vector_64_bool() void;
9921040
993test "@Vector(64, bool)" {1041test "@Vector(64, bool)" {
994 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;1042 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
1043 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
1044 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
1045 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
1046 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
9951047
996 const vec = c_ret_vector_64_bool();1048 const vec = c_ret_vector_64_bool();
997 try expect(vec[0] == false);1049 try expect(vec[0] == false);
...@@ -1129,8 +1181,11 @@ test "@Vector(64, bool)" {...@@ -1129,8 +1181,11 @@ test "@Vector(64, bool)" {
11291181
1130comptime {1182comptime {
1131 skip: {1183 skip: {
1132 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;1184 if (builtin.cpu.arch == .hexagon) break :skip;
1133 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;1185 if (builtin.cpu.arch == .loongarch64) break :skip;
1186 if (builtin.cpu.arch.isMIPS()) break :skip;
1187 if (builtin.cpu.arch.isPowerPC64()) break :skip;
1188 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
11341189
1135 _ = struct {1190 _ = struct {
1136 export fn zig_ret_vector_128_bool() @Vector(128, bool) {1191 export fn zig_ret_vector_128_bool() @Vector(128, bool) {
...@@ -1404,7 +1459,11 @@ extern fn c_vector_128_bool(@Vector(128, bool)) void;...@@ -1404,7 +1459,11 @@ extern fn c_vector_128_bool(@Vector(128, bool)) void;
1404extern fn c_test_vector_128_bool() void;1459extern fn c_test_vector_128_bool() void;
14051460
1406test "@Vector(128, bool)" {1461test "@Vector(128, bool)" {
1407 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;1462 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
1463 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
1464 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
1465 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
1466 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
14081467
1409 const vec = c_ret_vector_128_bool();1468 const vec = c_ret_vector_128_bool();
1410 try expect(vec[0] == false);1469 try expect(vec[0] == false);
...@@ -1670,8 +1729,11 @@ test "@Vector(128, bool)" {...@@ -1670,8 +1729,11 @@ test "@Vector(128, bool)" {
16701729
1671comptime {1730comptime {
1672 skip: {1731 skip: {
1673 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;1732 if (builtin.cpu.arch == .hexagon) break :skip;
1674 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;1733 if (builtin.cpu.arch == .loongarch64) break :skip;
1734 if (builtin.cpu.arch.isMIPS()) break :skip;
1735 if (builtin.cpu.arch.isPowerPC64()) break :skip;
1736 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
16751737
1676 _ = struct {1738 _ = struct {
1677 export fn zig_ret_vector_256_bool() @Vector(256, bool) {1739 export fn zig_ret_vector_256_bool() @Vector(256, bool) {
...@@ -2201,7 +2263,11 @@ extern fn c_vector_256_bool(@Vector(256, bool)) void;...@@ -2201,7 +2263,11 @@ extern fn c_vector_256_bool(@Vector(256, bool)) void;
2201extern fn c_test_vector_256_bool() void;2263extern fn c_test_vector_256_bool() void;
22022264
2203test "@Vector(256, bool)" {2265test "@Vector(256, bool)" {
2204 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;2266 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
2267 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
2268 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
2269 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
2270 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
22052271
2206 const vec = c_ret_vector_256_bool();2272 const vec = c_ret_vector_256_bool();
2207 try expect(vec[0] == true);2273 try expect(vec[0] == true);
...@@ -2723,8 +2789,11 @@ test "@Vector(256, bool)" {...@@ -2723,8 +2789,11 @@ test "@Vector(256, bool)" {
27232789
2724comptime {2790comptime {
2725 skip: {2791 skip: {
2726 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip;2792 if (builtin.cpu.arch == .hexagon) break :skip;
2727 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip;2793 if (builtin.cpu.arch == .loongarch64) break :skip;
2794 if (builtin.cpu.arch.isMIPS()) break :skip;
2795 if (builtin.cpu.arch.isPowerPC64()) break :skip;
2796 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip;
27282797
2729 _ = struct {2798 _ = struct {
2730 export fn zig_ret_vector_512_bool() @Vector(512, bool) {2799 export fn zig_ret_vector_512_bool() @Vector(512, bool) {
...@@ -3766,7 +3835,11 @@ extern fn c_vector_512_bool(@Vector(512, bool)) void;...@@ -3766,7 +3835,11 @@ extern fn c_vector_512_bool(@Vector(512, bool)) void;
3766extern fn c_test_vector_512_bool() void;3835extern fn c_test_vector_512_bool() void;
37673836
3768test "@Vector(512, bool)" {3837test "@Vector(512, bool)" {
3769 if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest;3838 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
3839 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
3840 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
3841 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
3842 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
37703843
3771 const vec = c_ret_vector_512_bool();3844 const vec = c_ret_vector_512_bool();
3772 try expect(vec[0] == false);3845 try expect(vec[0] == false);
...@@ -4840,7 +4913,7 @@ test "@Vector(2, u8)" {...@@ -4840,7 +4913,7 @@ test "@Vector(2, u8)" {
4840 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;4913 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
4841 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;4914 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
4842 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;4915 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
4843 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest;4916 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest;
48444917
4845 const v = c_ret_vector_2_u8();4918 const v = c_ret_vector_2_u8();
4846 try expect(v[0] == 9);4919 try expect(v[0] == 9);
...@@ -4869,7 +4942,6 @@ test "@Vector(3, u8)" {...@@ -4869,7 +4942,6 @@ test "@Vector(3, u8)" {
4869 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;4942 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
4870 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;4943 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
4871 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;4944 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
4872 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest;
48734945
4874 const v = c_ret_vector_3_u8();4946 const v = c_ret_vector_3_u8();
4875 try expect(v[0] == 19);4947 try expect(v[0] == 19);
...@@ -4912,7 +4984,7 @@ test "@Vector(4, u8)" {...@@ -4912,7 +4984,7 @@ test "@Vector(4, u8)" {
4912 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;4984 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
4913 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;4985 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
4914 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;4986 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
4915 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest;4987 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest;
49164988
4917 const v = c_ret_vector_4_u8();4989 const v = c_ret_vector_4_u8();
4918 try expect(v[0] == 41);4990 try expect(v[0] == 41);
...@@ -4946,7 +5018,6 @@ test "@Vector(6, u8)" {...@@ -4946,7 +5018,6 @@ test "@Vector(6, u8)" {
4946 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;5018 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
4947 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;5019 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
4948 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;5020 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
4949 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest;
49505021
4951 const v = c_ret_vector_6_u8();5022 const v = c_ret_vector_6_u8();
4952 try expect(v[0] == 53);5023 try expect(v[0] == 53);
...@@ -9063,7 +9134,7 @@ test "@Vector(2, u16)" {...@@ -9063,7 +9134,7 @@ test "@Vector(2, u16)" {
9063 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;9134 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
9064 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;9135 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
9065 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;9136 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
9066 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest;9137 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest;
90679138
9068 const v = c_ret_vector_2_u16();9139 const v = c_ret_vector_2_u16();
9069 try expect(v[0] == 9);9140 try expect(v[0] == 9);
...@@ -9091,7 +9162,6 @@ test "@Vector(3, u16)" {...@@ -9091,7 +9162,6 @@ test "@Vector(3, u16)" {
9091 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;9162 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
9092 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;9163 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
9093 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;9164 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
9094 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest;
90959165
9096 const v = c_ret_vector_3_u16();9166 const v = c_ret_vector_3_u16();
9097 try expect(v[0] == 19);9167 try expect(v[0] == 19);
...@@ -12564,8 +12634,6 @@ extern fn c_vector_1_u64(@Vector(1, u64), usize) void;...@@ -12564,8 +12634,6 @@ extern fn c_vector_1_u64(@Vector(1, u64), usize) void;
12564extern fn c_test_vector_1_u64() void;12634extern fn c_test_vector_1_u64() void;
1256512635
12566test "@Vector(1, u64)" {12636test "@Vector(1, u64)" {
12567 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest;
12568
12569 const v = c_ret_vector_1_u64();12637 const v = c_ret_vector_1_u64();
12570 try expect(v[0] == 3);12638 try expect(v[0] == 3);
12571 c_vector_1_u64(.{4}, 1);12639 c_vector_1_u64(.{4}, 1);
...@@ -13291,7 +13359,6 @@ test "@Vector(1, f32)" {...@@ -13291,7 +13359,6 @@ test "@Vector(1, f32)" {
13291 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;13359 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
13292 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;13360 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
13293 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;13361 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
13294 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest;
1329513362
13296 const v = c_ret_vector_1_f32();13363 const v = c_ret_vector_1_f32();
13297 try expect(v[0] == 3);13364 try expect(v[0] == 3);
...@@ -14633,7 +14700,6 @@ test "@Vector(4, f64)" {...@@ -14633,7 +14700,6 @@ test "@Vector(4, f64)" {
14633 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;14700 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
14634 if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest;14701 if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest;
14635 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;14702 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
14636 if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35899
1463714703
14638 const v = c_ret_vector_4_f64();14704 const v = c_ret_vector_4_f64();
14639 try expect(v[0] == 33);14705 try expect(v[0] == 33);
...@@ -14701,7 +14767,6 @@ test "@Vector(8, f64)" {...@@ -14701,7 +14767,6 @@ test "@Vector(8, f64)" {
14701 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;14767 if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest;
14702 if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest;14768 if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest;
14703 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;14769 if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
14704 if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35899
1470514770
14706 const v = c_ret_vector_8_f64();14771 const v = c_ret_vector_8_f64();
14707 try expect(v[0] == 81);14772 try expect(v[0] == 81);
test/tests.zig-6
...@@ -2015,7 +2015,6 @@ const c_abi_targets = blk: {...@@ -2015,7 +2015,6 @@ const c_abi_targets = blk: {
2015 .abi = .musl,2015 .abi = .musl,
2016 },2016 },
2017 .use_llvm = false,2017 .use_llvm = false,
2018 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
2019 },2018 },
2020 .{2019 .{
2021 .target = .{2020 .target = .{
...@@ -2026,7 +2025,6 @@ const c_abi_targets = blk: {...@@ -2026,7 +2025,6 @@ const c_abi_targets = blk: {
2026 },2025 },
2027 .use_llvm = false,2026 .use_llvm = false,
2028 .strip = true,2027 .strip = true,
2029 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
2030 },2028 },
2031 .{2029 .{
2032 .target = .{2030 .target = .{
...@@ -2037,7 +2035,6 @@ const c_abi_targets = blk: {...@@ -2037,7 +2035,6 @@ const c_abi_targets = blk: {
2037 },2035 },
2038 .use_llvm = false,2036 .use_llvm = false,
2039 .pic = true,2037 .pic = true,
2040 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
2041 },2038 },
2042 .{2039 .{
2043 .target = .{2040 .target = .{
...@@ -2082,7 +2079,6 @@ const c_abi_targets = blk: {...@@ -2082,7 +2079,6 @@ const c_abi_targets = blk: {
2082 .abi = .gnu,2079 .abi = .gnu,
2083 },2080 },
2084 .use_llvm = false,2081 .use_llvm = false,
2085 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
2086 },2082 },
2087 .{2083 .{
2088 .target = .{2084 .target = .{
...@@ -2092,7 +2088,6 @@ const c_abi_targets = blk: {...@@ -2092,7 +2088,6 @@ const c_abi_targets = blk: {
2092 .abi = .gnu,2088 .abi = .gnu,
2093 },2089 },
2094 .use_llvm = false,2090 .use_llvm = false,
2095 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
2096 },2091 },
2097 .{2092 .{
2098 .target = .{2093 .target = .{
...@@ -2102,7 +2097,6 @@ const c_abi_targets = blk: {...@@ -2102,7 +2097,6 @@ const c_abi_targets = blk: {
2102 .abi = .gnu,2097 .abi = .gnu,
2103 },2098 },
2104 .use_llvm = false,2099 .use_llvm = false,
2105 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
2106 },2100 },
2107 .{2101 .{
2108 .target = .{2102 .target = .{