authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-22 20:30:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-22 20:30:20-07:00
loge08b6149ab8fb80ad8fa4983ad3aca8ef3303a9f
treef4e943be0e2c2f456fe46106cd6d6842a1b7d3ff
parente8b99428737c401afeb118fa277da362e903b3ca

Sema: fix alignment of type-inferred locals


5 files changed, 70 insertions(+), 28 deletions(-)

src/Sema.zig+36-12
...@@ -1415,10 +1415,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1415,10 +1415,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1415 const ptr = sema.resolveInst(bin_inst.rhs);1415 const ptr = sema.resolveInst(bin_inst.rhs);
14161416
1417 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);1417 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
1418 const ptr_ty = try Type.ptr(sema.arena, .{
1419 .pointee_type = pointee_ty,
1420 .@"addrspace" = addr_space,
1421 });
14221418
1423 if (Air.refToIndex(ptr)) |ptr_inst| {1419 if (Air.refToIndex(ptr)) |ptr_inst| {
1424 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {1420 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
...@@ -1438,6 +1434,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1438,6 +1434,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1438 try inferred_alloc.stored_inst_list.append(sema.arena, operand);1434 try inferred_alloc.stored_inst_list.append(sema.arena, operand);
14391435
1440 try sema.requireRuntimeBlock(block, src);1436 try sema.requireRuntimeBlock(block, src);
1437 const ptr_ty = try Type.ptr(sema.arena, .{
1438 .pointee_type = pointee_ty,
1439 .@"align" = inferred_alloc.alignment,
1440 .@"addrspace" = addr_space,
1441 });
1441 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);1442 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
1442 return bitcasted_ptr;1443 return bitcasted_ptr;
1443 },1444 },
...@@ -1447,19 +1448,30 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1447,19 +1448,30 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1447 // The alloc will turn into a Decl.1448 // The alloc will turn into a Decl.
1448 var anon_decl = try block.startAnonDecl();1449 var anon_decl = try block.startAnonDecl();
1449 defer anon_decl.deinit();1450 defer anon_decl.deinit();
1450 iac.data = try anon_decl.finish(1451 iac.data.decl = try anon_decl.finish(
1451 try pointee_ty.copy(anon_decl.arena()),1452 try pointee_ty.copy(anon_decl.arena()),
1452 Value.undef,1453 Value.undef,
1453 );1454 );
1455 const ptr_ty = try Type.ptr(sema.arena, .{
1456 .pointee_type = pointee_ty,
1457 .@"align" = iac.data.alignment,
1458 .@"addrspace" = addr_space,
1459 });
1454 return sema.addConstant(1460 return sema.addConstant(
1455 ptr_ty,1461 ptr_ty,
1456 try Value.Tag.decl_ref_mut.create(sema.arena, .{1462 try Value.Tag.decl_ref_mut.create(sema.arena, .{
1457 .decl = iac.data,1463 .decl = iac.data.decl,
1458 .runtime_index = block.runtime_index,1464 .runtime_index = block.runtime_index,
1459 }),1465 }),
1460 );1466 );
1461 },1467 },
1462 .decl_ref_mut => return sema.addConstant(ptr_ty, ptr_val),1468 .decl_ref_mut => {
1469 const ptr_ty = try Type.ptr(sema.arena, .{
1470 .pointee_type = pointee_ty,
1471 .@"addrspace" = addr_space,
1472 });
1473 return sema.addConstant(ptr_ty, ptr_val);
1474 },
1463 else => {},1475 else => {},
1464 }1476 }
1465 }1477 }
...@@ -1491,6 +1503,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1491,6 +1503,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1491 sema.air_instructions.len -= 1;1503 sema.air_instructions.len -= 1;
1492 }1504 }
14931505
1506 const ptr_ty = try Type.ptr(sema.arena, .{
1507 .pointee_type = pointee_ty,
1508 .@"addrspace" = addr_space,
1509 });
1510
1494 var new_ptr = ptr;1511 var new_ptr = ptr;
14951512
1496 while (true) {1513 while (true) {
...@@ -2183,7 +2200,10 @@ fn zirAllocExtended(...@@ -2183,7 +2200,10 @@ fn zirAllocExtended(
2183 } else {2200 } else {
2184 return sema.addConstant(2201 return sema.addConstant(
2185 inferred_alloc_ty,2202 inferred_alloc_ty,
2186 try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined),2203 try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
2204 .decl = undefined,
2205 .alignment = alignment,
2206 }),
2187 );2207 );
2188 }2208 }
2189 }2209 }
...@@ -2208,7 +2228,7 @@ fn zirAllocExtended(...@@ -2208,7 +2228,7 @@ fn zirAllocExtended(
2208 // to the block even though it is currently a `.constant`.2228 // to the block even though it is currently a `.constant`.
2209 const result = try sema.addConstant(2229 const result = try sema.addConstant(
2210 inferred_alloc_ty,2230 inferred_alloc_ty,
2211 try Value.Tag.inferred_alloc.create(sema.arena, .{}),2231 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),
2212 );2232 );
2213 try sema.requireFunctionBlock(block, src);2233 try sema.requireFunctionBlock(block, src);
2214 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);2234 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
...@@ -2302,7 +2322,7 @@ fn zirAllocInferred(...@@ -2302,7 +2322,7 @@ fn zirAllocInferred(
2302 // to the block even though it is currently a `.constant`.2322 // to the block even though it is currently a `.constant`.
2303 const result = try sema.addConstant(2323 const result = try sema.addConstant(
2304 inferred_alloc_ty,2324 inferred_alloc_ty,
2305 try Value.Tag.inferred_alloc.create(sema.arena, .{}),2325 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),
2306 );2326 );
2307 try sema.requireFunctionBlock(block, src);2327 try sema.requireFunctionBlock(block, src);
2308 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);2328 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
...@@ -2331,12 +2351,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2331,12 +2351,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2331 switch (ptr_val.tag()) {2351 switch (ptr_val.tag()) {
2332 .inferred_alloc_comptime => {2352 .inferred_alloc_comptime => {
2333 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;2353 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
2334 const decl = iac.data;2354 const decl = iac.data.decl;
2335 try sema.mod.declareDeclDependency(sema.owner_decl, decl);2355 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
23362356
2337 const final_elem_ty = try decl.ty.copy(sema.arena);2357 const final_elem_ty = try decl.ty.copy(sema.arena);
2338 const final_ptr_ty = try Type.ptr(sema.arena, .{2358 const final_ptr_ty = try Type.ptr(sema.arena, .{
2339 .pointee_type = final_elem_ty,2359 .pointee_type = final_elem_ty,
2360 .@"align" = iac.data.alignment,
2340 .@"addrspace" = target_util.defaultAddressSpace(target, .local),2361 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
2341 });2362 });
2342 const final_ptr_ty_inst = try sema.addType(final_ptr_ty);2363 const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
...@@ -2365,6 +2386,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2365,6 +2386,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2365 // Change it to a normal alloc.2386 // Change it to a normal alloc.
2366 const final_ptr_ty = try Type.ptr(sema.arena, .{2387 const final_ptr_ty = try Type.ptr(sema.arena, .{
2367 .pointee_type = final_elem_ty,2388 .pointee_type = final_elem_ty,
2389 .@"align" = inferred_alloc.data.alignment,
2368 .@"addrspace" = target_util.defaultAddressSpace(target, .local),2390 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
2369 });2391 });
2370 sema.air_instructions.set(ptr_inst, .{2392 sema.air_instructions.set(ptr_inst, .{
...@@ -2681,10 +2703,11 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -2681,10 +2703,11 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
2681 }2703 }
2682 var anon_decl = try block.startAnonDecl();2704 var anon_decl = try block.startAnonDecl();
2683 defer anon_decl.deinit();2705 defer anon_decl.deinit();
2684 iac.data = try anon_decl.finish(2706 iac.data.decl = try anon_decl.finish(
2685 try operand_ty.copy(anon_decl.arena()),2707 try operand_ty.copy(anon_decl.arena()),
2686 try operand_val.copy(anon_decl.arena()),2708 try operand_val.copy(anon_decl.arena()),
2687 );2709 );
2710 // TODO set the alignment on the decl
2688 return;2711 return;
2689 } else {2712 } else {
2690 return sema.failWithNeededComptime(block, src);2713 return sema.failWithNeededComptime(block, src);
...@@ -2698,6 +2721,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -2698,6 +2721,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
2698 // Create a runtime bitcast instruction with exactly the type the pointer wants.2721 // Create a runtime bitcast instruction with exactly the type the pointer wants.
2699 const ptr_ty = try Type.ptr(sema.arena, .{2722 const ptr_ty = try Type.ptr(sema.arena, .{
2700 .pointee_type = operand_ty,2723 .pointee_type = operand_ty,
2724 .@"align" = inferred_alloc.data.alignment,
2701 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),2725 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
2702 });2726 });
2703 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);2727 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
src/value.zig+14-1
...@@ -256,7 +256,6 @@ pub const Value = extern union {...@@ -256,7 +256,6 @@ pub const Value = extern union {
256256
257 .extern_fn,257 .extern_fn,
258 .decl_ref,258 .decl_ref,
259 .inferred_alloc_comptime,
260 => Payload.Decl,259 => Payload.Decl,
261260
262 .repeated,261 .repeated,
...@@ -291,6 +290,7 @@ pub const Value = extern union {...@@ -291,6 +290,7 @@ pub const Value = extern union {
291 .float_128 => Payload.Float_128,290 .float_128 => Payload.Float_128,
292 .@"error" => Payload.Error,291 .@"error" => Payload.Error,
293 .inferred_alloc => Payload.InferredAlloc,292 .inferred_alloc => Payload.InferredAlloc,
293 .inferred_alloc_comptime => Payload.InferredAllocComptime,
294 .@"struct" => Payload.Struct,294 .@"struct" => Payload.Struct,
295 .@"union" => Payload.Union,295 .@"union" => Payload.Union,
296 .bound_fn => Payload.BoundFn,296 .bound_fn => Payload.BoundFn,
...@@ -2889,6 +2889,19 @@ pub const Value = extern union {...@@ -2889,6 +2889,19 @@ pub const Value = extern union {
2889 /// the items are contiguous in memory and thus can be passed to2889 /// the items are contiguous in memory and thus can be passed to
2890 /// `Module.resolvePeerTypes`.2890 /// `Module.resolvePeerTypes`.
2891 stored_inst_list: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},2891 stored_inst_list: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
2892 /// 0 means ABI-aligned.
2893 alignment: u16,
2894 },
2895 };
2896
2897 pub const InferredAllocComptime = struct {
2898 pub const base_tag = Tag.inferred_alloc_comptime;
2899
2900 base: Payload = .{ .tag = base_tag },
2901 data: struct {
2902 decl: *Module.Decl,
2903 /// 0 means ABI-aligned.
2904 alignment: u16,
2892 },2905 },
2893 };2906 };
28942907
test/behavior.zig+1
...@@ -44,6 +44,7 @@ test {...@@ -44,6 +44,7 @@ test {
4444
45 if (builtin.object_format != .c) {45 if (builtin.object_format != .c) {
46 // Tests that pass for stage1 and stage2 but not the C backend.46 // Tests that pass for stage1 and stage2 but not the C backend.
47 _ = @import("behavior/align_llvm.zig");
47 _ = @import("behavior/array.zig");48 _ = @import("behavior/array.zig");
48 _ = @import("behavior/atomics.zig");49 _ = @import("behavior/atomics.zig");
49 _ = @import("behavior/basic_llvm.zig");50 _ = @import("behavior/basic_llvm.zig");
test/behavior/align_llvm.zig created+19
...@@ -0,0 +1,19 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const builtin = @import("builtin");
4const native_arch = builtin.target.cpu.arch;
5
6test "page aligned array on stack" {
7 // Large alignment value to make it hard to accidentally pass.
8 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
9 var number1: u8 align(16) = 42;
10 var number2: u8 align(16) = 43;
11
12 try expect(@ptrToInt(&array[0]) & 0xFFF == 0);
13 try expect(array[3] == 4);
14
15 try expect(@truncate(u4, @ptrToInt(&number1)) == 0);
16 try expect(@truncate(u4, @ptrToInt(&number2)) == 0);
17 try expect(number1 == 42);
18 try expect(number2 == 43);
19}
test/behavior/align_stage1.zig-15
...@@ -223,18 +223,3 @@ test "align(N) on functions" {...@@ -223,18 +223,3 @@ test "align(N) on functions" {
223fn overaligned_fn() align(0x1000) i32 {223fn overaligned_fn() align(0x1000) i32 {
224 return 42;224 return 42;
225}225}
226
227test "page aligned array on stack" {
228 // Large alignment value to make it hard to accidentally pass.
229 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
230 var number1: u8 align(16) = 42;
231 var number2: u8 align(16) = 43;
232
233 try expect(@ptrToInt(&array[0]) & 0xFFF == 0);
234 try expect(array[3] == 4);
235
236 try expect(@truncate(u4, @ptrToInt(&number1)) == 0);
237 try expect(@truncate(u4, @ptrToInt(&number2)) == 0);
238 try expect(number1 == 42);
239 try expect(number2 == 43);
240}