mirror of
https://github.com/ziglang/zig.git
synced 2024-12-12 14:16:59 +00:00
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.
This commit is contained in:
parent
7287c7482a
commit
f1b91bb41b
@ -121,7 +121,13 @@ pub const Function = struct {
|
||||
const decl_c_value = f.allocLocalValue();
|
||||
gop.value_ptr.* = decl_c_value;
|
||||
try writer.writeAll("static ");
|
||||
try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const);
|
||||
try f.object.dg.renderTypeAndName(
|
||||
writer,
|
||||
ty,
|
||||
decl_c_value,
|
||||
.Const,
|
||||
Value.initTag(.abi_align_default),
|
||||
);
|
||||
try writer.writeAll(" = ");
|
||||
try f.object.dg.renderValue(writer, ty, val);
|
||||
try writer.writeAll(";\n ");
|
||||
@ -142,8 +148,18 @@ pub const Function = struct {
|
||||
}
|
||||
|
||||
fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
|
||||
return f.allocAlignedLocal(ty, mutability, Value.initTag(.abi_align_default));
|
||||
}
|
||||
|
||||
fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: Value) !CValue {
|
||||
const local_value = f.allocLocalValue();
|
||||
try f.object.dg.renderTypeAndName(f.object.writer(), ty, local_value, mutability);
|
||||
try f.object.dg.renderTypeAndName(
|
||||
f.object.writer(),
|
||||
ty,
|
||||
local_value,
|
||||
mutability,
|
||||
alignment,
|
||||
);
|
||||
return local_value;
|
||||
}
|
||||
|
||||
@ -711,9 +727,11 @@ pub const DeclGen = struct {
|
||||
while (it.next()) |entry| {
|
||||
const field_ty = entry.value_ptr.ty;
|
||||
if (!field_ty.hasCodeGenBits()) continue;
|
||||
|
||||
const alignment = entry.value_ptr.abi_align;
|
||||
const name: CValue = .{ .bytes = entry.key_ptr.* };
|
||||
try buffer.append(' ');
|
||||
try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut);
|
||||
try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment);
|
||||
try buffer.appendSlice(";\n");
|
||||
}
|
||||
}
|
||||
@ -950,6 +968,7 @@ pub const DeclGen = struct {
|
||||
ty: Type,
|
||||
name: CValue,
|
||||
mutability: Mutability,
|
||||
alignment: Value,
|
||||
) error{ OutOfMemory, AnalysisFail }!void {
|
||||
var suffix = std.ArrayList(u8).init(dg.gpa);
|
||||
defer suffix.deinit();
|
||||
@ -962,6 +981,8 @@ pub const DeclGen = struct {
|
||||
render_ty = render_ty.elemType();
|
||||
}
|
||||
|
||||
if (alignment.tag() != .abi_align_default and alignment.tag() != .null_value)
|
||||
try w.print("ZIG_ALIGN({}) ", .{alignment.toUnsignedInt()});
|
||||
try dg.renderType(w, render_ty);
|
||||
|
||||
const const_prefix = switch (mutability) {
|
||||
@ -1118,7 +1139,7 @@ pub fn genDecl(o: *Object) !void {
|
||||
// https://github.com/ziglang/zig/issues/7582
|
||||
|
||||
const decl_c_value: CValue = .{ .decl = o.dg.decl };
|
||||
try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut);
|
||||
try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.align_val);
|
||||
|
||||
try writer.writeAll(" = ");
|
||||
try o.dg.renderValue(writer, tv.ty, tv.val);
|
||||
@ -1460,8 +1481,16 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
return CValue{ .bytes = literal };
|
||||
}
|
||||
|
||||
const target = f.object.dg.module.getTarget();
|
||||
const alignment = inst_ty.ptrAlignment(target);
|
||||
var payload = Value.Payload.U64{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = alignment,
|
||||
};
|
||||
const alignment_value = Value.initPayload(&payload.base);
|
||||
|
||||
// First line: the variable used as data storage.
|
||||
const local = try f.allocLocal(elem_type, mutability);
|
||||
const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value);
|
||||
try writer.writeAll(";\n");
|
||||
|
||||
// Arrays are already pointers so they don't need to be referenced.
|
||||
|
@ -26,6 +26,15 @@
|
||||
#define ZIG_RESTRICT
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#include <stdalign.h>
|
||||
#define ZIG_ALIGN(alignment) alignas(alignment)
|
||||
#elif defined(__GNUC__)
|
||||
#define ZIG_ALIGN(alignment) __attribute__((aligned(alignment)))
|
||||
#else
|
||||
#define ZIG_ALIGN(alignment) zig_compile_error("the C compiler being used does not support aligning variables")
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
|
@ -71,7 +71,6 @@ test {
|
||||
|
||||
if (builtin.zig_backend != .stage2_c) {
|
||||
// Tests that pass for stage1 and the llvm backend.
|
||||
_ = @import("behavior/align_llvm.zig");
|
||||
_ = @import("behavior/alignof.zig");
|
||||
_ = @import("behavior/array_llvm.zig");
|
||||
_ = @import("behavior/atomics.zig");
|
||||
|
@ -163,3 +163,21 @@ test "return error union with 128-bit integer" {
|
||||
fn give() anyerror!u128 {
|
||||
return 3;
|
||||
}
|
||||
|
||||
test "page aligned array on stack" {
|
||||
if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm or
|
||||
builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
|
||||
// Large alignment value to make it hard to accidentally pass.
|
||||
var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
var number1: u8 align(16) = 42;
|
||||
var number2: u8 align(16) = 43;
|
||||
|
||||
try expect(@ptrToInt(&array[0]) & 0xFFF == 0);
|
||||
try expect(array[3] == 4);
|
||||
|
||||
try expect(@truncate(u4, @ptrToInt(&number1)) == 0);
|
||||
try expect(@truncate(u4, @ptrToInt(&number2)) == 0);
|
||||
try expect(number1 == 42);
|
||||
try expect(number2 == 43);
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const builtin = @import("builtin");
|
||||
const native_arch = builtin.target.cpu.arch;
|
||||
|
||||
test "page aligned array on stack" {
|
||||
// Large alignment value to make it hard to accidentally pass.
|
||||
var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
var number1: u8 align(16) = 42;
|
||||
var number2: u8 align(16) = 43;
|
||||
|
||||
try expect(@ptrToInt(&array[0]) & 0xFFF == 0);
|
||||
try expect(array[3] == 4);
|
||||
|
||||
try expect(@truncate(u4, @ptrToInt(&number1)) == 0);
|
||||
try expect(@truncate(u4, @ptrToInt(&number2)) == 0);
|
||||
try expect(number1 == 42);
|
||||
try expect(number2 == 43);
|
||||
}
|
@ -201,6 +201,8 @@ test "struct field init with catch" {
|
||||
}
|
||||
|
||||
test "packed struct field alignment" {
|
||||
if (builtin.object_format == .c) return error.SkipZigTest;
|
||||
|
||||
const Stage1 = struct {
|
||||
var baz: packed struct {
|
||||
a: u32,
|
||||
|
Loading…
Reference in New Issue
Block a user