authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2022-01-20 22:46:15+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-23 17:23:55-05:00
logf1b91bb41b2d810ecabf4c69cad91b24b3846b77
tree59416bc00443451485832f6d1a1ce4b3d3357c58
parent7287c7482a2c694c7c7f56b9f7c1744a7ae7905f

c backend: Implement aligning fields and local/global variables

There are some restrictions here. - We either need C11 or a compiler that supports the aligned attribute - We cannot provide align less than the type's natural C alignment.

6 files changed, 63 insertions(+), 25 deletions(-)

src/codegen/c.zig+34-5
...@@ -121,7 +121,13 @@ pub const Function = struct {...@@ -121,7 +121,13 @@ pub const Function = struct {
121 const decl_c_value = f.allocLocalValue();121 const decl_c_value = f.allocLocalValue();
122 gop.value_ptr.* = decl_c_value;122 gop.value_ptr.* = decl_c_value;
123 try writer.writeAll("static ");123 try writer.writeAll("static ");
124 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const);124 try f.object.dg.renderTypeAndName(
125 writer,
126 ty,
127 decl_c_value,
128 .Const,
129 Value.initTag(.abi_align_default),
130 );
125 try writer.writeAll(" = ");131 try writer.writeAll(" = ");
126 try f.object.dg.renderValue(writer, ty, val);132 try f.object.dg.renderValue(writer, ty, val);
127 try writer.writeAll(";\n ");133 try writer.writeAll(";\n ");
...@@ -142,8 +148,18 @@ pub const Function = struct {...@@ -142,8 +148,18 @@ pub const Function = struct {
142 }148 }
143149
144 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {150 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
151 return f.allocAlignedLocal(ty, mutability, Value.initTag(.abi_align_default));
152 }
153
154 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: Value) !CValue {
145 const local_value = f.allocLocalValue();155 const local_value = f.allocLocalValue();
146 try f.object.dg.renderTypeAndName(f.object.writer(), ty, local_value, mutability);156 try f.object.dg.renderTypeAndName(
157 f.object.writer(),
158 ty,
159 local_value,
160 mutability,
161 alignment,
162 );
147 return local_value;163 return local_value;
148 }164 }
149165
...@@ -711,9 +727,11 @@ pub const DeclGen = struct {...@@ -711,9 +727,11 @@ pub const DeclGen = struct {
711 while (it.next()) |entry| {727 while (it.next()) |entry| {
712 const field_ty = entry.value_ptr.ty;728 const field_ty = entry.value_ptr.ty;
713 if (!field_ty.hasCodeGenBits()) continue;729 if (!field_ty.hasCodeGenBits()) continue;
730
731 const alignment = entry.value_ptr.abi_align;
714 const name: CValue = .{ .bytes = entry.key_ptr.* };732 const name: CValue = .{ .bytes = entry.key_ptr.* };
715 try buffer.append(' ');733 try buffer.append(' ');
716 try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut);734 try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment);
717 try buffer.appendSlice(";\n");735 try buffer.appendSlice(";\n");
718 }736 }
719 }737 }
...@@ -950,6 +968,7 @@ pub const DeclGen = struct {...@@ -950,6 +968,7 @@ pub const DeclGen = struct {
950 ty: Type,968 ty: Type,
951 name: CValue,969 name: CValue,
952 mutability: Mutability,970 mutability: Mutability,
971 alignment: Value,
953 ) error{ OutOfMemory, AnalysisFail }!void {972 ) error{ OutOfMemory, AnalysisFail }!void {
954 var suffix = std.ArrayList(u8).init(dg.gpa);973 var suffix = std.ArrayList(u8).init(dg.gpa);
955 defer suffix.deinit();974 defer suffix.deinit();
...@@ -962,6 +981,8 @@ pub const DeclGen = struct {...@@ -962,6 +981,8 @@ pub const DeclGen = struct {
962 render_ty = render_ty.elemType();981 render_ty = render_ty.elemType();
963 }982 }
964983
984 if (alignment.tag() != .abi_align_default and alignment.tag() != .null_value)
985 try w.print("ZIG_ALIGN({}) ", .{alignment.toUnsignedInt()});
965 try dg.renderType(w, render_ty);986 try dg.renderType(w, render_ty);
966987
967 const const_prefix = switch (mutability) {988 const const_prefix = switch (mutability) {
...@@ -1118,7 +1139,7 @@ pub fn genDecl(o: *Object) !void {...@@ -1118,7 +1139,7 @@ pub fn genDecl(o: *Object) !void {
1118 // https://github.com/ziglang/zig/issues/75821139 // https://github.com/ziglang/zig/issues/7582
11191140
1120 const decl_c_value: CValue = .{ .decl = o.dg.decl };1141 const decl_c_value: CValue = .{ .decl = o.dg.decl };
1121 try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut);1142 try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.align_val);
11221143
1123 try writer.writeAll(" = ");1144 try writer.writeAll(" = ");
1124 try o.dg.renderValue(writer, tv.ty, tv.val);1145 try o.dg.renderValue(writer, tv.ty, tv.val);
...@@ -1460,8 +1481,16 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1460,8 +1481,16 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
1460 return CValue{ .bytes = literal };1481 return CValue{ .bytes = literal };
1461 }1482 }
14621483
1484 const target = f.object.dg.module.getTarget();
1485 const alignment = inst_ty.ptrAlignment(target);
1486 var payload = Value.Payload.U64{
1487 .base = .{ .tag = .int_u64 },
1488 .data = alignment,
1489 };
1490 const alignment_value = Value.initPayload(&payload.base);
1491
1463 // First line: the variable used as data storage.1492 // First line: the variable used as data storage.
1464 const local = try f.allocLocal(elem_type, mutability);1493 const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value);
1465 try writer.writeAll(";\n");1494 try writer.writeAll(";\n");
14661495
1467 // Arrays are already pointers so they don't need to be referenced.1496 // Arrays are already pointers so they don't need to be referenced.
src/link/C/zig.h+9
...@@ -26,6 +26,15 @@...@@ -26,6 +26,15 @@
26#define ZIG_RESTRICT26#define ZIG_RESTRICT
27#endif27#endif
2828
29#if __STDC_VERSION__ >= 201112L
30#include <stdalign.h>
31#define ZIG_ALIGN(alignment) alignas(alignment)
32#elif defined(__GNUC__)
33#define ZIG_ALIGN(alignment) __attribute__((aligned(alignment)))
34#else
35#define ZIG_ALIGN(alignment) zig_compile_error("the C compiler being used does not support aligning variables")
36#endif
37
29#if __STDC_VERSION__ >= 199901L38#if __STDC_VERSION__ >= 199901L
30#include <stdbool.h>39#include <stdbool.h>
31#else40#else
test/behavior.zig-1
...@@ -71,7 +71,6 @@ test {...@@ -71,7 +71,6 @@ test {
7171
72 if (builtin.zig_backend != .stage2_c) {72 if (builtin.zig_backend != .stage2_c) {
73 // Tests that pass for stage1 and the llvm backend.73 // Tests that pass for stage1 and the llvm backend.
74 _ = @import("behavior/align_llvm.zig");
75 _ = @import("behavior/alignof.zig");74 _ = @import("behavior/alignof.zig");
76 _ = @import("behavior/array_llvm.zig");75 _ = @import("behavior/array_llvm.zig");
77 _ = @import("behavior/atomics.zig");76 _ = @import("behavior/atomics.zig");
test/behavior/align.zig+18
...@@ -163,3 +163,21 @@ test "return error union with 128-bit integer" {...@@ -163,3 +163,21 @@ test "return error union with 128-bit integer" {
163fn give() anyerror!u128 {163fn give() anyerror!u128 {
164 return 3;164 return 3;
165}165}
166
167test "page aligned array on stack" {
168 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm or
169 builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
170
171 // Large alignment value to make it hard to accidentally pass.
172 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
173 var number1: u8 align(16) = 42;
174 var number2: u8 align(16) = 43;
175
176 try expect(@ptrToInt(&array[0]) & 0xFFF == 0);
177 try expect(array[3] == 4);
178
179 try expect(@truncate(u4, @ptrToInt(&number1)) == 0);
180 try expect(@truncate(u4, @ptrToInt(&number2)) == 0);
181 try expect(number1 == 42);
182 try expect(number2 == 43);
183}
test/behavior/align_llvm.zig deleted-19
...@@ -1,19 +0,0 @@
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/struct.zig+2
...@@ -201,6 +201,8 @@ test "struct field init with catch" {...@@ -201,6 +201,8 @@ test "struct field init with catch" {
201}201}
202202
203test "packed struct field alignment" {203test "packed struct field alignment" {
204 if (builtin.object_format == .c) return error.SkipZigTest;
205
204 const Stage1 = struct {206 const Stage1 = struct {
205 var baz: packed struct {207 var baz: packed struct {
206 a: u32,208 a: u32,