authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-15 08:44:30-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-27 14:38:37-04:00
log6aed49f6baad85fc4a509f4c631da8c623e7c28f
tree2dfb92be8edb34b8363d0a0d149fbcbd00e276da
parentb425e6869452ebeaf9b15ceb5739ce4b4bb5b87d

llvm.Builder: parse llvm alignment information from data layout

This is required to correctly lower types in the llvm backend.

3 files changed, 618 insertions(+), 236 deletions(-)

lib/std/zig/llvm/Builder.zig+547-16
......@@ -17,7 +17,7 @@ gpa: Allocator,
1717strip: bool,
1818
1919source_filename: String,
20data_layout: String,
20data_layout: DataLayout,
2121target_triple: String,
2222module_asm: std.ArrayList(u8),
2323
......@@ -87,6 +87,455 @@ pub const Options = struct {
8787 triple: []const u8 = &.{},
8888};
8989
90pub const DataLayout = struct {
91 endian: ?std.lang.Endian,
92 int_specs: PrimitiveSpec.Map,
93 float_specs: PrimitiveSpec.Map,
94 vector_specs: PrimitiveSpec.Map,
95 pointer_specs: PointerSpec.Map,
96 string_repr: String,
97
98 const PrimitiveSpec = packed struct(u32) {
99 bit_width: BitWidth,
100 abi_align: Alignment,
101 pref_align: Alignment,
102
103 const BitWidth = u20;
104
105 const Map = std.array_hash_map.Custom(PrimitiveSpec, void, Context, false);
106
107 const Context = struct {
108 pub fn hash(_: Context, spec: PrimitiveSpec) u32 {
109 return std.hash.int(spec.bit_width);
110 }
111
112 pub fn eql(_: Context, lhs_spec: PrimitiveSpec, rhs_spec: PrimitiveSpec, _: usize) bool {
113 return lhs_spec.bit_width == rhs_spec.bit_width;
114 }
115 };
116 };
117
118 const PointerSpec = struct {
119 bit_width: BitWidth,
120 index_bit_width: BitWidth,
121 flags: packed struct(u32) {
122 abi_align: Alignment,
123 pref_align: Alignment,
124 has_unstable_repr: bool,
125 has_external_state: bool,
126 null_ptr_repr: NullPtrRepr,
127 unused: u17 = 0,
128 },
129 addr_space_name: String,
130
131 const BitWidth = u32;
132
133 const NullPtrRepr = enum(u1) { all_zeros, all_ones };
134
135 const Map = std.array_hash_map.Auto(AddrSpace, PointerSpec);
136 };
137
138 pub fn stringForTarget(target: *const std.Target) []const u8 {
139 // These data layouts should match Clang.
140 return switch (target.cpu.arch) {
141 .arc => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32",
142 .xcore => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32",
143 .hexagon => "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048",
144 .lanai => "E-m:e-p:32:32-i64:64-a:0:32-n32-S64",
145 .aarch64 => if (target.ofmt == .macho)
146 if (target.os.tag == .windows or target.os.tag == .uefi)
147 "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
148 else if (target.abi == .ilp32)
149 "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
150 else
151 "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
152 else if (target.os.tag == .windows or target.os.tag == .uefi)
153 "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
154 else
155 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
156 .aarch64_be => "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
157 .arm => if (target.ofmt == .macho)
158 "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
159 else
160 "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
161 .armeb, .thumbeb => if (target.ofmt == .macho)
162 "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
163 else
164 "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
165 .thumb => if (target.ofmt == .macho)
166 "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
167 else if (target.os.tag == .windows or target.os.tag == .uefi)
168 "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
169 else
170 "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
171 .avr => "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8",
172 .bpfeb => "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
173 .bpfel => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
174 .msp430 => "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16",
175 .mips => "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
176 .mipsel => "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
177 .mips64 => switch (target.abi) {
178 .gnuabin32, .muslabin32, .abin32 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
179 else => "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
180 },
181 .mips64el => switch (target.abi) {
182 .gnuabin32, .muslabin32, .abin32 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
183 else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
184 },
185 .m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16",
186 .powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32",
187 .powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32",
188 .powerpc64 => switch (target.os.tag) {
189 .linux => "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512",
190 .ps3 => "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64",
191 else => "E-m:e-Fn32-i64:64-i128:128-n32:64",
192 },
193 .powerpc64le => if (target.os.tag == .linux)
194 "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
195 else
196 "e-m:e-Fn32-i64:64-i128:128-n32:64",
197 .nvptx => "e-p:32:32-p6:32:32-p7:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64",
198 .nvptx64 => "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64",
199 .amdgcn => "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9",
200 .riscv32 => if (target.cpu.has(.riscv, .e))
201 "e-m:e-p:32:32-i64:64-n32-S32"
202 else
203 "e-m:e-p:32:32-i64:64-n32-S128",
204 .riscv32be => if (target.cpu.has(.riscv, .e))
205 "E-m:e-p:32:32-i64:64-n32-S32"
206 else
207 "E-m:e-p:32:32-i64:64-n32-S128",
208 .riscv64 => if (target.cpu.has(.riscv, .e))
209 "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64"
210 else
211 "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
212 .riscv64be => if (target.cpu.has(.riscv, .e))
213 "E-m:e-p:64:64-i64:64-i128:128-n32:64-S64"
214 else
215 "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
216 .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64",
217 .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128",
218 .s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
219 .x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) {
220 .gnu => if (target.ofmt == .coff)
221 "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"
222 else
223 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32",
224 else => blk: {
225 const msvc = switch (target.abi) {
226 .none, .msvc => true,
227 else => false,
228 };
229
230 break :blk if (target.ofmt == .coff)
231 if (msvc)
232 "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
233 else
234 "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"
235 else if (msvc)
236 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
237 else
238 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32";
239 },
240 } else if (target.ofmt == .macho)
241 "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128"
242 else
243 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
244 .x86_64 => if (target.os.tag.isDarwin() or target.ofmt == .macho)
245 "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
246 else switch (target.abi) {
247 .gnux32, .muslx32, .x32 => "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
248 else => if ((target.os.tag == .windows or target.os.tag == .uefi) and target.ofmt == .coff)
249 "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
250 else
251 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
252 },
253 .spirv32 => switch (target.os.tag) {
254 .vulkan, .opengl => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1",
255 else => "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1",
256 },
257 .spirv64 => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1",
258 .wasm32 => if (target.os.tag == .emscripten)
259 "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20"
260 else
261 "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20",
262 .wasm64 => if (target.os.tag == .emscripten)
263 "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20"
264 else
265 "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20",
266 .ve => "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64",
267 .csky => "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32",
268 .loongarch32 => "e-m:e-p:32:32-i64:64-n32-S128",
269 .loongarch64 => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
270 .xtensa => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32",
271
272 .alpha,
273 .arceb,
274 .ez80,
275 .hppa,
276 .hppa64,
277 .kalimba,
278 .kvx,
279 .m88k,
280 .microblaze,
281 .microblazeel,
282 .or1k,
283 .propeller,
284 .sh,
285 .sheb,
286 .x86_16,
287 .xtensaeb,
288 => unreachable,
289 };
290 }
291
292 const default_int_specs: []const PrimitiveSpec = &.{
293 .{ .bit_width = 8, .abi_align = .fromByteUnits(1), .pref_align = .fromByteUnits(1) }, // i8:8:8
294 .{ .bit_width = 16, .abi_align = .fromByteUnits(2), .pref_align = .fromByteUnits(2) }, // i16:16:16
295 .{ .bit_width = 32, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(4) }, // i32:32:32
296 .{ .bit_width = 64, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(8) }, // i64:32:64
297 };
298 const default_float_specs: []const PrimitiveSpec = &.{
299 .{ .bit_width = 16, .abi_align = .fromByteUnits(2), .pref_align = .fromByteUnits(2) }, // f16:16:16
300 .{ .bit_width = 32, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(4) }, // f32:32:32
301 .{ .bit_width = 64, .abi_align = .fromByteUnits(8), .pref_align = .fromByteUnits(8) }, // f64:64:64
302 .{ .bit_width = 128, .abi_align = .fromByteUnits(16), .pref_align = .fromByteUnits(16) }, // f128:128:128
303 };
304 const default_vector_specs: []const PrimitiveSpec = &.{
305 .{ .bit_width = 64, .abi_align = .fromByteUnits(8), .pref_align = .fromByteUnits(8) }, // v64:64:64
306 .{ .bit_width = 128, .abi_align = .fromByteUnits(16), .pref_align = .fromByteUnits(16) }, // v128:128:128
307 };
308
309 pub fn parseString(string_repr: String, builder: *Builder) Allocator.Error!DataLayout {
310 const gpa = builder.gpa;
311
312 var int_specs: PrimitiveSpec.Map = .empty;
313 defer int_specs.deinit(gpa);
314 var float_specs: PrimitiveSpec.Map = .empty;
315 defer float_specs.deinit(gpa);
316 var vector_specs: PrimitiveSpec.Map = .empty;
317 defer vector_specs.deinit(gpa);
318 var pointer_specs: PointerSpec.Map = .empty;
319 defer pointer_specs.deinit(gpa);
320 var non_integral_addr_spaces: std.ArrayList(AddrSpace) = .empty;
321 defer non_integral_addr_spaces.deinit(gpa);
322
323 try int_specs.ensureTotalCapacity(gpa, default_int_specs.len);
324 for (default_int_specs) |int_spec| int_specs.putAssumeCapacityNoClobber(int_spec, {});
325 try float_specs.ensureTotalCapacity(gpa, default_float_specs.len);
326 for (default_float_specs) |float_spec| float_specs.putAssumeCapacityNoClobber(float_spec, {});
327 try vector_specs.ensureTotalCapacity(gpa, default_vector_specs.len);
328 for (default_vector_specs) |vector_spec| vector_specs.putAssumeCapacityNoClobber(vector_spec, {});
329 try pointer_specs.putNoClobber(gpa, .default, comptime .{
330 .bit_width = 64,
331 .index_bit_width = 64,
332 .flags = .{
333 .abi_align = .fromByteUnits(8),
334 .pref_align = .fromByteUnits(8),
335 .has_unstable_repr = false,
336 .has_external_state = false,
337 .null_ptr_repr = .all_zeros,
338 },
339 .addr_space_name = .none,
340 });
341
342 var endian: ?std.lang.Endian = null;
343 var spec_it = std.mem.splitScalar(u8, string_repr.slice(builder).?, '-');
344 while (spec_it.next()) |spec| switch (spec[0]) {
345 else => {},
346 'E' => {
347 assert(spec.len == 1);
348 assert(endian == null);
349 endian = .big;
350 },
351 'e' => {
352 assert(spec.len == 1);
353 assert(endian == null);
354 endian = .little;
355 },
356 'p' => {
357 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
358
359 const first = field_it.first();
360 var has_unstable_repr = false;
361 var has_external_state = false;
362 var null_ptr_repr: ?PointerSpec.NullPtrRepr = null;
363 var addr_space_name: String = .none;
364 const addr_space = for (first, 0..) |flag, as_start| switch (flag) {
365 'u' => has_unstable_repr = true,
366 'e' => has_external_state = true,
367 'z' => {
368 assert(null_ptr_repr == null);
369 null_ptr_repr = .all_zeros;
370 },
371 'o' => {
372 assert(null_ptr_repr == null);
373 null_ptr_repr = .all_ones;
374 },
375 else => {
376 if (first[first.len - ")".len] != ')') break first[as_start..];
377 const name_start = std.mem.findScalarPos(u8, first, as_start, '(').?;
378 addr_space_name = try builder.string(first[name_start + "(".len .. first.len - ")".len]);
379 break first[as_start..name_start];
380 },
381 } else first[first.len..];
382 const bit_width = std.fmt.parseInt(PointerSpec.BitWidth, field_it.next().?, 10) catch unreachable;
383 const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable);
384 const pref_align: Alignment = if (field_it.next()) |pref_align|
385 .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable)
386 else
387 abi_align;
388 const index_bit_width = if (field_it.next()) |index_bit_width|
389 std.fmt.parseInt(PointerSpec.BitWidth, index_bit_width, 10) catch unreachable
390 else
391 bit_width;
392 assert(field_it.peek() == null);
393
394 try pointer_specs.put(gpa, switch (addr_space.len) {
395 0 => .default,
396 else => @fromBackingInt(std.fmt.parseInt(u24, addr_space, 10) catch unreachable),
397 }, .{
398 .bit_width = bit_width,
399 .index_bit_width = index_bit_width,
400 .flags = .{
401 .abi_align = abi_align,
402 .pref_align = pref_align,
403 .has_unstable_repr = has_unstable_repr,
404 .has_external_state = has_external_state,
405 .null_ptr_repr = null_ptr_repr orelse .all_zeros,
406 },
407 .addr_space_name = addr_space_name,
408 });
409 },
410 'i', 'f', 'v' => |kind| {
411 if (std.mem.eql(u8, spec, "ve")) {
412 vector_specs.clearRetainingCapacity();
413 continue;
414 }
415 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
416 const bit_width = std.fmt.parseInt(PrimitiveSpec.BitWidth, field_it.first(), 10) catch unreachable;
417 const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable);
418 const pref_align: Alignment = if (field_it.next()) |pref_align|
419 .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable)
420 else
421 abi_align;
422 assert(field_it.peek() == null);
423 const specs = switch (kind) {
424 else => unreachable,
425 'i' => &int_specs,
426 'f' => &float_specs,
427 'v' => &vector_specs,
428 };
429 try specs.put(gpa, .{ .bit_width = bit_width, .abi_align = abi_align, .pref_align = pref_align }, {});
430 },
431 'n' => {
432 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
433 if (std.mem.eql(u8, field_it.first(), "i")) {
434 while (field_it.next()) |non_integral_addr_space| try non_integral_addr_spaces.append(
435 gpa,
436 @fromBackingInt(std.fmt.parseInt(u24, non_integral_addr_space, 10) catch unreachable),
437 );
438 } else {
439 field_it.reset();
440 while (field_it.next()) |native_bit_width| {
441 _ = std.fmt.parseInt(PrimitiveSpec.BitWidth, native_bit_width, 10) catch unreachable;
442 }
443 }
444 },
445 };
446
447 for (non_integral_addr_spaces.items) |non_integral_addr_space| {
448 const pointer_spec_gop = try pointer_specs.getOrPut(gpa, non_integral_addr_space);
449 if (!pointer_spec_gop.found_existing) pointer_spec_gop.value_ptr.* = pointer_specs.get(.default).?;
450 pointer_spec_gop.value_ptr.flags.has_unstable_repr = true;
451 pointer_spec_gop.value_ptr.flags.has_external_state = false;
452 }
453
454 {
455 const SortContext = struct {
456 specs: []const PrimitiveSpec,
457 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
458 return ctx.specs[lhs_index].bit_width < ctx.specs[rhs_index].bit_width;
459 }
460 };
461 int_specs.sortUnstable(SortContext{ .specs = int_specs.keys() });
462 float_specs.sortUnstable(SortContext{ .specs = float_specs.keys() });
463 vector_specs.sortUnstable(SortContext{ .specs = vector_specs.keys() });
464 }
465 {
466 const SortContext = struct {
467 addr_spaces: []const AddrSpace,
468 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
469 return @backingInt(ctx.addr_spaces[lhs_index]) < @backingInt(ctx.addr_spaces[rhs_index]);
470 }
471 };
472 pointer_specs.sortUnstable(SortContext{ .addr_spaces = pointer_specs.keys() });
473 assert(pointer_specs.keys()[0] == .default);
474 }
475
476 return .{
477 .endian = endian,
478 .int_specs = int_specs.move(),
479 .float_specs = float_specs.move(),
480 .vector_specs = vector_specs.move(),
481 .pointer_specs = pointer_specs.move(),
482 .string_repr = string_repr,
483 };
484 }
485
486 pub fn deinit(data_layout: *DataLayout, gpa: Allocator) void {
487 data_layout.int_specs.deinit(gpa);
488 data_layout.float_specs.deinit(gpa);
489 data_layout.vector_specs.deinit(gpa);
490 data_layout.pointer_specs.deinit(gpa);
491 }
492
493 pub fn getIntegerSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec {
494 const specs = data_layout.int_specs.keys();
495 return specs[
496 @min(std.sort.lowerBound(PrimitiveSpec, specs, bit_width, struct {
497 fn order(ctx: PrimitiveSpec.BitWidth, spec: PrimitiveSpec) std.math.Order {
498 return std.math.order(ctx, spec.bit_width);
499 }
500 }.order), specs.len - 1)
501 ];
502 }
503
504 pub fn getFloatSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec {
505 if (data_layout.float_specs.getEntry(.{
506 .bit_width = bit_width,
507 .abi_align = .default,
508 .pref_align = .default,
509 })) |entry| return entry.key_ptr.*;
510 const default_align: Alignment = .fromByteUnits(
511 std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, bit_width / 8),
512 );
513 return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align };
514 }
515
516 pub fn getVectorSpec(
517 data_layout: *const DataLayout,
518 bit_width: PrimitiveSpec.BitWidth,
519 store_size: Type.Size,
520 ) PrimitiveSpec {
521 if (data_layout.float_specs.getEntry(.{
522 .bit_width = bit_width,
523 .abi_align = .default,
524 .pref_align = .default,
525 })) |entry| return entry.key_ptr.*;
526 const default_align: Alignment = .fromByteUnits(
527 std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, switch (store_size) {
528 .fixed, .scalable => |known_min| known_min,
529 }),
530 );
531 return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align };
532 }
533
534 pub fn getPointerSpec(data_layout: *const DataLayout, addr_space: AddrSpace) PointerSpec {
535 return data_layout.pointer_specs.get(addr_space) orelse data_layout.pointer_specs.values()[0];
536 }
537};
538
90539pub const String = enum(u32) {
91540 none = maxInt(u31),
92541 empty,
......@@ -489,7 +938,10 @@ pub const Type = enum(u32) {
489938 .double, .i64, .x86_mmx => 64,
490939 .x86_fp80, .i80 => 80,
491940 .fp128, .ppc_fp128, .i128 => 128,
492 .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"),
941 .ptr => @intCast(builder.data_layout.getPointerSpec(.default).bit_width),
942 .@"ptr addrspace(4)" => @intCast(
943 builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(4))).bit_width,
944 ),
493945 _ => {
494946 const item = builder.type_items.items[@backingInt(self)];
495947 return switch (item.tag) {
......@@ -498,7 +950,9 @@ pub const Type = enum(u32) {
498950 .vararg_function,
499951 => unreachable,
500952 .integer => @intCast(item.data),
501 .pointer => @panic("TODO: query data layout"),
953 .pointer => @intCast(
954 builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width,
955 ),
502956 .target => unreachable,
503957 .vector,
504958 .scalable_vector,
......@@ -931,6 +1385,67 @@ pub const Type = enum(u32) {
9311385 },
9321386 };
9331387 }
1388
1389 const Size = union(enum) { fixed: u64, scalable: u64 };
1390 pub fn bits(ty: Type, builder: *const Builder) Size {
1391 const item = builder.type_items.items[@backingInt(ty)];
1392 return switch (item.tag) {
1393 else => unreachable,
1394 .simple => switch (@as(Simple, @fromBackingInt(@intCast(item.data)))) {
1395 else => unreachable,
1396 .label => .{ .fixed = builder.data_layout.getPointerSpec(.default).bit_width },
1397 .half, .bfloat => .{ .fixed = 16 },
1398 .float => .{ .fixed = 32 },
1399 .double => .{ .fixed = 64 },
1400 .ppc_fp128, .fp128 => .{ .fixed = 128 },
1401 .x86_amx => .{ .fixed = 8192 },
1402 .x86_fp80 => .{ .fixed = 80 },
1403 },
1404 .integer => .{ .fixed = item.data },
1405 .pointer => .{
1406 .fixed = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width,
1407 },
1408 };
1409 }
1410
1411 pub fn alignment(ty: Type, kind: enum { abi, pref }, builder: *const Builder) Alignment {
1412 const item = builder.type_items.items[@backingInt(ty)];
1413 switch (item.tag) {
1414 else => unreachable,
1415 .simple => switch (@as(Simple, @fromBackingInt(@intCast(item.data)))) {
1416 else => unreachable,
1417 .label => {
1418 const spec = builder.data_layout.getPointerSpec(.default);
1419 return switch (kind) {
1420 .abi => spec.flags.abi_align,
1421 .pref => spec.flags.pref_align,
1422 };
1423 },
1424 .half, .bfloat, .float, .double, .ppc_fp128, .fp128, .x86_fp80 => {
1425 const spec = builder.data_layout.getFloatSpec(@intCast(ty.bits(builder).fixed));
1426 return switch (kind) {
1427 .abi => spec.abi_align,
1428 .pref => spec.pref_align,
1429 };
1430 },
1431 .x86_amx => return comptime .fromByteUnits(64),
1432 },
1433 .integer => {
1434 const spec = builder.data_layout.getIntegerSpec(@intCast(item.data));
1435 return switch (kind) {
1436 .abi => spec.abi_align,
1437 .pref => spec.pref_align,
1438 };
1439 },
1440 .pointer => {
1441 const spec = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data)));
1442 return switch (kind) {
1443 .abi => spec.flags.abi_align,
1444 .pref => spec.flags.pref_align,
1445 };
1446 },
1447 }
1448 }
9341449};
9351450
9361451pub const Attribute = union(Kind) {
......@@ -2182,11 +2697,18 @@ pub const Alignment = enum(u6) {
21822697 };
21832698 }
21842699
2185 /// Asserts that neither `a` nor `b` is `.default`.
2186 pub fn max(a: Alignment, b: Alignment) Alignment {
2187 assert(a != .default);
2188 assert(b != .default);
2189 return @fromBackingInt(@intCast(@max(@backingInt(a), @backingInt(b))));
2700 /// Asserts that neither `lhs` nor `rhs` is `.default`.
2701 pub fn max(lhs: Alignment, rhs: Alignment) Alignment {
2702 assert(lhs != .default);
2703 assert(rhs != .default);
2704 return @fromBackingInt(@max(@backingInt(lhs), @backingInt(rhs)));
2705 }
2706
2707 /// Asserts that neither `lhs` nor `rhs` is `.default`.
2708 pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order {
2709 assert(lhs != .default);
2710 assert(rhs != .default);
2711 return std.math.order(@backingInt(lhs), @backingInt(rhs));
21902712 }
21912713
21922714 pub fn toLlvm(self: Alignment) u6 {
......@@ -9023,7 +9545,14 @@ pub fn init(options: Options) Allocator.Error!Builder {
90239545 .strip = options.strip,
90249546
90259547 .source_filename = .none,
9026 .data_layout = .none,
9548 .data_layout = .{
9549 .endian = null,
9550 .int_specs = .empty,
9551 .float_specs = .empty,
9552 .vector_specs = .empty,
9553 .pointer_specs = .empty,
9554 .string_repr = .none,
9555 },
90279556 .target_triple = .none,
90289557 .module_asm = .empty,
90299558
......@@ -9079,14 +9608,14 @@ pub fn init(options: Options) Allocator.Error!Builder {
90799608 try self.string_indices.append(self.gpa, 0);
90809609 assert(try self.string("") == .empty);
90819610
9611 self.data_layout = try .parseString(try self.string(DataLayout.stringForTarget(options.target)), &self);
9612
90829613 try self.strtab_string_indices.append(self.gpa, 0);
90839614 assert(try self.strtabString("") == .empty);
90849615
90859616 if (options.name.len > 0) self.source_filename = try self.string(options.name);
90869617
9087 if (options.triple.len > 0) {
9088 self.target_triple = try self.string(options.triple);
9089 }
9618 if (options.triple.len > 0) self.target_triple = try self.string(options.triple);
90909619
90919620 {
90929621 const static_len = @typeInfo(Type).@"enum".field_names.len - 1;
......@@ -9179,6 +9708,8 @@ pub fn clearAndFree(self: *Builder) void {
91799708pub fn deinit(self: *Builder) void {
91809709 const gpa = self.gpa;
91819710
9711 self.data_layout.deinit(gpa);
9712
91829713 self.module_asm.deinit(gpa);
91839714
91849715 self.string_map.deinit(gpa);
......@@ -9998,17 +10529,17 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
999810529 var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined };
999910530 defer metadata_formatter.map.deinit(self.gpa);
1000010531
10001 if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) {
10532 if (self.source_filename != .none or self.data_layout.string_repr != .none or self.target_triple != .none) {
1000210533 if (need_newline) try w.writeByte('\n') else need_newline = true;
1000310534 if (self.source_filename != .none) try w.print(
1000410535 \\; ModuleID = '{s}'
1000510536 \\source_filename = {f}
1000610537 \\
1000710538 , .{ self.source_filename.slice(self).?, self.source_filename.fmtQ(self) });
10008 if (self.data_layout != .none) try w.print(
10539 if (self.data_layout.string_repr != .none) try w.print(
1000910540 \\target datalayout = {f}
1001010541 \\
10011 , .{self.data_layout.fmtQ(self)});
10542 , .{self.data_layout.string_repr.fmtQ(self)});
1001210543 if (self.target_triple != .none) try w.print(
1001310544 \\target triple = {f}
1001410545 \\
......@@ -13706,7 +14237,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1370614237 });
1370714238 }
1370814239
13709 if (self.data_layout.slice(self)) |data_layout| {
14240 if (self.data_layout.string_repr.slice(self)) |data_layout| {
1371014241 try module_block.writeAbbrev(ModuleBlock.String{
1371114242 .code = 3,
1371214243 .string = data_layout,
src/codegen/llvm.zig+62-208
......@@ -345,160 +345,6 @@ pub fn supportsTailCall(target: *const std.Target) bool {
345345 };
346346}
347347
348pub fn dataLayout(target: *const std.Target) []const u8 {
349 // These data layouts should match Clang.
350 return switch (target.cpu.arch) {
351 .arc => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32",
352 .xcore => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32",
353 .hexagon => "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048",
354 .lanai => "E-m:e-p:32:32-i64:64-a:0:32-n32-S64",
355 .aarch64 => if (target.ofmt == .macho)
356 if (target.os.tag == .windows or target.os.tag == .uefi)
357 "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
358 else if (target.abi == .ilp32)
359 "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
360 else
361 "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
362 else if (target.os.tag == .windows or target.os.tag == .uefi)
363 "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
364 else
365 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
366 .aarch64_be => "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
367 .arm => if (target.ofmt == .macho)
368 "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
369 else
370 "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
371 .armeb, .thumbeb => if (target.ofmt == .macho)
372 "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
373 else
374 "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
375 .thumb => if (target.ofmt == .macho)
376 "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
377 else if (target.os.tag == .windows or target.os.tag == .uefi)
378 "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
379 else
380 "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
381 .avr => "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8",
382 .bpfeb => "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
383 .bpfel => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
384 .msp430 => "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16",
385 .mips => "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
386 .mipsel => "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
387 .mips64 => switch (target.abi) {
388 .gnuabin32, .muslabin32, .abin32 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
389 else => "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
390 },
391 .mips64el => switch (target.abi) {
392 .gnuabin32, .muslabin32, .abin32 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
393 else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
394 },
395 .m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16",
396 .powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32",
397 .powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32",
398 .powerpc64 => switch (target.os.tag) {
399 .linux => "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512",
400 .ps3 => "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64",
401 else => "E-m:e-Fn32-i64:64-i128:128-n32:64",
402 },
403 .powerpc64le => if (target.os.tag == .linux)
404 "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
405 else
406 "e-m:e-Fn32-i64:64-i128:128-n32:64",
407 .nvptx => "e-p:32:32-p6:32:32-p7:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64",
408 .nvptx64 => "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64",
409 .amdgcn => "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9",
410 .riscv32 => if (target.cpu.has(.riscv, .e))
411 "e-m:e-p:32:32-i64:64-n32-S32"
412 else
413 "e-m:e-p:32:32-i64:64-n32-S128",
414 .riscv32be => if (target.cpu.has(.riscv, .e))
415 "E-m:e-p:32:32-i64:64-n32-S32"
416 else
417 "E-m:e-p:32:32-i64:64-n32-S128",
418 .riscv64 => if (target.cpu.has(.riscv, .e))
419 "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64"
420 else
421 "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
422 .riscv64be => if (target.cpu.has(.riscv, .e))
423 "E-m:e-p:64:64-i64:64-i128:128-n32:64-S64"
424 else
425 "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
426 .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64",
427 .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128",
428 .s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
429 .x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) {
430 .gnu => if (target.ofmt == .coff)
431 "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"
432 else
433 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32",
434 else => blk: {
435 const msvc = switch (target.abi) {
436 .none, .msvc => true,
437 else => false,
438 };
439
440 break :blk if (target.ofmt == .coff)
441 if (msvc)
442 "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
443 else
444 "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"
445 else if (msvc)
446 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
447 else
448 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32";
449 },
450 } else if (target.ofmt == .macho)
451 "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128"
452 else
453 "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
454 .x86_64 => if (target.os.tag.isDarwin() or target.ofmt == .macho)
455 "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
456 else switch (target.abi) {
457 .gnux32, .muslx32, .x32 => "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
458 else => if ((target.os.tag == .windows or target.os.tag == .uefi) and target.ofmt == .coff)
459 "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
460 else
461 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
462 },
463 .spirv32 => switch (target.os.tag) {
464 .vulkan, .opengl => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1",
465 else => "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1",
466 },
467 .spirv64 => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1",
468 .wasm32 => if (target.os.tag == .emscripten)
469 "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20"
470 else
471 "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20",
472 .wasm64 => if (target.os.tag == .emscripten)
473 "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20"
474 else
475 "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20",
476 .ve => "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64",
477 .csky => "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32",
478 .loongarch32 => "e-m:e-p:32:32-i64:64-n32-S128",
479 .loongarch64 => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
480 .xtensa => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32",
481
482 .alpha,
483 .arceb,
484 .ez80,
485 .hppa,
486 .hppa64,
487 .kalimba,
488 .kvx,
489 .m88k,
490 .microblaze,
491 .microblazeel,
492 .or1k,
493 .propeller,
494 .sh,
495 .sheb,
496 .x86_16,
497 .xtensaeb,
498 => unreachable, // Gated by hasLlvmSupport().
499 };
500}
501
502348// Avoid depending on `bindings.CodeModel` in the bitcode-only case.
503349const CodeModel = enum {
504350 default,
......@@ -618,8 +464,6 @@ pub const Object = struct {
618464 });
619465 errdefer builder.deinit();
620466
621 builder.data_layout = try builder.string(dataLayout(target));
622
623467 const debug_compile_unit, const debug_enums_fwd_ref, const debug_globals_fwd_ref =
624468 if (!builder.strip) debug_info: {
625469 // We fully resolve all paths at this point to avoid lack of
......@@ -2865,18 +2709,38 @@ pub const Object = struct {
28652709
28662710 pub const TypeRepr = enum {
28672711 /// The representation of the type when it is being manipulated as a value in a function.
2868 /// e.g. Zig `u5` -> LLVM `i5`
2712 /// e.g. Zig `u90` -> LLVM `i90`
28692713 as_value,
2870 /// The representation of the type when it is stored in memory.
2871 /// e.g. Zig `u5` -> LLVM `i8`
2714 /// The representation of the type when it is loaded from or stored to memory.
2715 /// e.g. Zig `u90` -> LLVM `i96`
2716 memory_access,
2717 /// The representation of the type when it is in memory.
2718 /// e.g. Zig `u90` -> LLVM `[12 x i8]`
28722719 in_memory,
28732720 };
28742721
2722 pub fn intType(o: *Object, bits: u16, repr: TypeRepr) Allocator.Error!Builder.Type {
2723 switch (repr) {
2724 .as_value => return o.builder.intType(bits),
2725 .memory_access, .in_memory => {},
2726 }
2727 const target = o.zcu.getTarget();
2728 const abi_size = std.zig.target.intByteSize(target, bits);
2729 const llvm_bit_width = @as(u20, 8) * abi_size;
2730 switch (repr) {
2731 .as_value => unreachable,
2732 .memory_access => {},
2733 .in_memory => {
2734 const zig_align = std.zig.target.intAlignment(target, bits);
2735 const llvm_align = o.builder.data_layout.getIntegerSpec(llvm_bit_width).abi_align;
2736 if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8);
2737 },
2738 }
2739 return o.builder.intType(llvm_bit_width);
2740 }
2741
28752742 pub fn errorIntType(o: *Object, repr: TypeRepr) Allocator.Error!Builder.Type {
2876 return o.builder.intType(switch (repr) {
2877 .as_value => o.zcu.errorSetBits(),
2878 .in_memory => @intCast(Type.anyerror.abiSize(o.zcu) * 8),
2879 });
2743 return o.intType(o.zcu.errorSetBits(), repr);
28802744 }
28812745
28822746 pub const SoftF80Layout = struct {
......@@ -3029,42 +2893,31 @@ pub const Object = struct {
30292893 const target = zcu.getTarget();
30302894 const ip = &zcu.intern_pool;
30312895
3032 if (repr == .as_value) {
3033 assert(!isByRef(t, zcu)); // by-ref types must only be manipulated in memory
2896 switch (repr) {
2897 .as_value => assert(!isByRef(t, zcu)), // by-ref types must only be manipulated in memory
2898 .memory_access, .in_memory => {},
30342899 }
30352900
30362901 return switch (t.toIntern()) {
30372902 .u0_type => unreachable, // no runtime bits
3038 inline .u1_type,
3039 .u8_type,
3040 .i8_type,
3041 .u16_type,
3042 .i16_type,
3043 .u29_type,
3044 .u32_type,
3045 .i32_type,
3046 .u64_type,
3047 .i64_type,
3048 .u80_type,
3049 .u128_type,
3050 .i128_type,
3051 => |tag| switch (repr) {
3052 .as_value => @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]),
3053 .in_memory => try o.builder.intType(@intCast(t.abiSize(zcu) * 8)),
3054 },
3055 .usize_type, .isize_type => try o.builder.intType(target.ptrBitWidth()),
3056 inline .c_char_type,
3057 .c_short_type,
3058 .c_ushort_type,
3059 .c_int_type,
3060 .c_uint_type,
3061 .c_long_type,
3062 .c_ulong_type,
3063 .c_longlong_type,
3064 .c_ulonglong_type,
3065 => |tag| try o.builder.intType(target.cTypeBitSize(
3066 @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]),
3067 ).?),
2903 .u1_type => try o.intType(1, repr),
2904 .u8_type, .i8_type => try o.intType(8, repr),
2905 .u16_type, .i16_type => try o.intType(16, repr),
2906 .u29_type => try o.intType(29, repr),
2907 .u32_type, .i32_type => try o.intType(32, repr),
2908 .u64_type, .i64_type => try o.intType(64, repr),
2909 .u80_type => try o.intType(80, repr),
2910 .u128_type, .i128_type => try o.intType(128, repr),
2911 .usize_type, .isize_type => try o.intType(target.ptrBitWidth(), repr),
2912 .c_char_type => try o.intType(target.cTypeBitSize(.char).?, repr),
2913 .c_short_type => try o.intType(target.cTypeBitSize(.short).?, repr),
2914 .c_ushort_type => try o.intType(target.cTypeBitSize(.ushort).?, repr),
2915 .c_int_type => try o.intType(target.cTypeBitSize(.int).?, repr),
2916 .c_uint_type => try o.intType(target.cTypeBitSize(.uint).?, repr),
2917 .c_long_type => try o.intType(target.cTypeBitSize(.long).?, repr),
2918 .c_ulong_type => try o.intType(target.cTypeBitSize(.ulong).?, repr),
2919 .c_longlong_type => try o.intType(target.cTypeBitSize(.longlong).?, repr),
2920 .c_ulonglong_type => try o.intType(target.cTypeBitSize(.ulonglong).?, repr),
30682921 .c_longdouble_type,
30692922 .f16_type,
30702923 .f32_type,
......@@ -3168,10 +3021,7 @@ pub const Object = struct {
31683021 .none,
31693022 => unreachable,
31703023 else => switch (ip.indexToKey(t.toIntern())) {
3171 .int_type => |int_type| switch (repr) {
3172 .as_value => try o.builder.intType(int_type.bits),
3173 .in_memory => try o.builder.intType(@intCast(t.abiSize(zcu) * 8)),
3174 },
3024 .int_type => |int_type| o.intType(int_type.bits, repr),
31753025 .ptr_type => |ptr_type| type: {
31763026 const ptr_ty = try o.builder.ptrType(
31773027 toLlvmAddressSpace(ptr_type.flags.address_space, target),
......@@ -3189,7 +3039,7 @@ pub const Object = struct {
31893039 try o.lowerType(.fromInterned(array_type.child), repr),
31903040 ),
31913041 .vector_type => |vector_type| if (isByRef(t, zcu)) {
3192 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .in_memory);
3042 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), repr);
31933043 return o.builder.arrayType(vector_type.len, child_llvm_ty);
31943044 } else {
31953045 const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .as_value);
......@@ -3454,7 +3304,7 @@ pub const Object = struct {
34543304 return ty;
34553305 },
34563306 .opaque_type, .spirv_type => unreachable, // no runtime bits
3457 .enum_type => try o.lowerType(t.backingIntType(zcu), repr),
3307 .enum_type => try o.intType(t.backingIntType(zcu).intInfo(zcu).bits, repr),
34583308 .func_type => |func_type| {
34593309 assert(t.fnHasRuntimeBits(zcu));
34603310 return o.lowerFnType(.fromIntern(func_type, ip));
......@@ -3525,7 +3375,7 @@ pub const Object = struct {
35253375 .no_bits => continue,
35263376 .byval => {
35273377 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3528 try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .in_memory else .as_value));
3378 try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .memory_access else .as_value));
35293379 },
35303380 .byref, .byref_mut => {
35313381 try llvm_params.append(o.gpa, .ptr);
......@@ -3548,7 +3398,7 @@ pub const Object = struct {
35483398 },
35493399 .float_array => |count| {
35503400 const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]);
3551 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .in_memory);
3401 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .memory_access);
35523402 try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty));
35533403 },
35543404 .i32_array, .i64_array => |arr_len| {
......@@ -3620,7 +3470,12 @@ pub const Object = struct {
36203470 var bigint_space: Value.BigIntSpace = undefined;
36213471 const bigint = val.toBigInt(&bigint_space, zcu);
36223472 const llvm_int_ty = try o.lowerType(ty, repr);
3623 return o.builder.bigIntConst(llvm_int_ty, bigint);
3473 if (llvm_int_ty.isInteger(&o.builder))
3474 return o.builder.bigIntConst(llvm_int_ty, bigint);
3475 const buffer = try o.gpa.alloc(u8, llvm_int_ty.aggregateLen(&o.builder));
3476 defer o.gpa.free(buffer);
3477 bigint.writeTwosComplement(buffer, target.cpu.arch.endian());
3478 return o.builder.stringConst(try o.builder.string(buffer));
36243479 },
36253480 .err => |err| {
36263481 const int = zcu.intern_pool.getErrorValueIfExists(err.name).?;
......@@ -3814,7 +3669,7 @@ pub const Object = struct {
38143669 result_val.* = try o.builder.intConst(.i8, byte);
38153670 },
38163671 .elems => |elems| for (vals, elems) |*result_val, elem| {
3817 result_val.* = try o.lowerValue(elem, if (is_by_ref) .in_memory else .as_value);
3672 result_val.* = try o.lowerValue(elem, if (is_by_ref) repr else .as_value);
38183673 },
38193674 .repeated_elem => unreachable,
38203675 }
......@@ -3826,7 +3681,7 @@ pub const Object = struct {
38263681 .repeated_elem => |elem| if (is_by_ref) {
38273682 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
38283683 defer allocator.free(vals);
3829 @memset(vals, try o.lowerValue(elem, .in_memory));
3684 @memset(vals, try o.lowerValue(elem, repr));
38303685 return o.builder.arrayConst(vector_ty, vals);
38313686 } else return o.builder.splatConst(vector_ty, try o.lowerValue(elem, .as_value)),
38323687 }
......@@ -4287,9 +4142,8 @@ pub const Object = struct {
42874142 }
42884143 errdefer assert(o.uav_map.remove(.{ .val = uav_val, .@"addrspace" = @"addrspace" }));
42894144
4290 const llvm_ty = try o.lowerType(uav_ty, .in_memory);
42914145 const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@backingInt(uav_val)});
4292 const llvm_variable = try o.builder.addVariable(llvm_name, llvm_ty, llvm_addrspace);
4146 const llvm_variable = try o.builder.addVariable(llvm_name, .void, llvm_addrspace);
42934147 gop.value_ptr.* = llvm_variable;
42944148 try llvm_variable.setInitializer(try o.lowerValue(uav_val, .in_memory), &o.builder);
42954149 llvm_variable.setMutability(.constant, &o.builder);
src/codegen/llvm/FuncGen.zig+9-12
......@@ -830,7 +830,7 @@ fn buildCall(
830830 const alignment = arg_ty.abiAlignment(zcu).toLlvm();
831831 // We don't need to handle non-ABI-sized integer types in memory here since they are
832832 // never by-ref.
833 const llvm_arg_ty = try o.lowerType(arg_ty, .in_memory);
833 const llvm_arg_ty = try o.lowerType(arg_ty, .memory_access);
834834 const loaded = try fg.wip.load(.normal, llvm_arg_ty, arg_val, alignment, "");
835835 try llvm_args.append(fg.gpa, loaded);
836836 } else {
......@@ -893,7 +893,7 @@ fn buildCall(
893893 break :ptr ptr;
894894 } else arg_val;
895895
896 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .in_memory);
896 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .memory_access);
897897 const array_ty = try o.builder.arrayType(count, float_ty);
898898
899899 const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), "");
......@@ -4967,10 +4967,7 @@ fn buildZigAlloca(fg: *FuncGen, ty: Type, @"align": InternPool.Alignment) Alloca
49674967 .none => ty.abiAlignment(o.zcu),
49684968 else => |a| a,
49694969 };
4970 return fg.buildAlloca(
4971 try o.lowerType(ty, .in_memory),
4972 resolved_align.toLlvm(),
4973 );
4970 return fg.buildAlloca(try o.lowerType(ty, .in_memory), resolved_align.toLlvm());
49744971}
49754972
49764973/// Unlike `WipFunction.alloca`, this puts the alloca instruction at the top of the function.
......@@ -6657,10 +6654,10 @@ fn load(
66576654 return result_ptr;
66586655 }
66596656
6660 const llvm_memory_ty = try o.lowerType(load_ty, .in_memory);
6657 const llvm_access_ty = try o.lowerType(load_ty, .memory_access);
66616658 const llvm_value_ty = try o.lowerType(load_ty, .as_value);
66626659
6663 if (llvm_memory_ty != llvm_value_ty) {
6660 if (llvm_access_ty != llvm_value_ty) {
66646661 assert(load_ty.isAbiInt(zcu));
66656662 // `load_ty` is an integer type with padding bits. In theory, we shouldn't need any special
66666663 // handling for these, as LLVM's documented semantics are a valid implementation of Zig's
......@@ -6674,7 +6671,7 @@ fn load(
66746671 //
66756672 // Therefore, we handle these memory accesses specially: in this case we will actually load
66766673 // the next-largest "natural" integer type and then truncate to `load_ty`.
6677 const loaded = try fg.wip.load(access_kind, llvm_memory_ty, ptr, llvm_ptr_align, "");
6674 const loaded = try fg.wip.load(access_kind, llvm_access_ty, ptr, llvm_ptr_align, "");
66786675 // For packed structs, current Zig semantics don't really allow us to make the padding bits
66796676 // well-defined. This should be solved once https://github.com/ziglang/zig/issues/24061 is
66806677 // implemented, but until then, do a normal trunc for packed types.
......@@ -6731,17 +6728,17 @@ fn store(
67316728
67326729 assert(elem.typeOfWip(&fg.wip) == try o.lowerType(elem_ty, .as_value));
67336730
6734 const llvm_memory_ty = try o.lowerType(elem_ty, .in_memory);
6731 const llvm_access_ty = try o.lowerType(elem_ty, .memory_access);
67356732 const llvm_value_ty = try o.lowerType(elem_ty, .as_value);
67366733
6737 if (llvm_memory_ty != llvm_value_ty) {
6734 if (llvm_access_ty != llvm_value_ty) {
67386735 assert(elem_ty.isAbiInt(zcu));
67396736 // `elem_ty` is an integer type with padding bits, so we need to handle it specially---see
67406737 // the corresponding comment in `FuncGen.load` for more details.
67416738 const extended = try fg.wip.cast(switch (elem_ty.intInfo(zcu).signedness) {
67426739 .unsigned => .zext,
67436740 .signed => .sext,
6744 }, elem, llvm_memory_ty, "");
6741 }, elem, llvm_access_ty, "");
67456742 _ = try fg.wip.store(access_kind, extended, ptr, llvm_ptr_align);
67466743 return;
67476744 }