Skip to content

Commit

Permalink
Merge pull request #3278 from LemonBoy/struct-gen
Browse files Browse the repository at this point in the history
A few steps towards AArch64 & ARM passing the behavior tests
  • Loading branch information
andrewrk committed Sep 21, 2019
2 parents 533aff3 + 34d02f2 commit f3a7c34
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 12 deletions.
13 changes: 10 additions & 3 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7633,6 +7633,11 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
type->data.structure.resolve_status = ResolveStatusLLVMFull;
}

static LLVMTypeRef get_llvm_array_type(unsigned byte_size) {
return byte_size == 1 ?
LLVMInt8Type() : LLVMArrayType(LLVMInt8Type(), byte_size);
}

static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status,
ZigType *async_frame_type)
{
Expand Down Expand Up @@ -7730,16 +7735,17 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
if (full_abi_size * 8 == full_bit_count) {
// next field recovers ABI alignment
element_types[gen_field_index] = LLVMIntType((unsigned)(full_bit_count));
element_types[gen_field_index] = get_llvm_array_type(full_abi_size);
gen_field_index += 1;

first_packed_bits_offset_misalign = SIZE_MAX;
}
} else if (get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) * 8 != field_size_in_bits) {
first_packed_bits_offset_misalign = packed_bits_offset;
} else {
// This is a byte-aligned field (both start and end) in a packed struct.
element_types[gen_field_index] = get_llvm_type(g, field_type);
assert(get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) ==
LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index]));
gen_field_index += 1;
}
packed_bits_offset = next_packed_bits_offset;
Expand Down Expand Up @@ -7802,11 +7808,12 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
if (first_packed_bits_offset_misalign != SIZE_MAX) {
size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
element_types[gen_field_index] = LLVMIntType((unsigned)full_abi_size * 8);
element_types[gen_field_index] = get_llvm_array_type(full_abi_size);
gen_field_index += 1;
}

if (type_has_bits(struct_type)) {
assert(struct_type->data.structure.gen_field_count == gen_field_index);
LLVMStructSetBody(struct_type->llvm_type, element_types,
(unsigned)struct_type->data.structure.gen_field_count, packed);
}
Expand Down
35 changes: 29 additions & 6 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1644,7 +1644,9 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,

bool big_endian = g->is_big_endian;

LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0);
LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, "");
LLVMValueRef containing_int = gen_load(g, int_ptr, ptr_type, "");
uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
assert(host_bit_count == host_int_bytes * 8);
uint32_t size_in_bits = type_size_bits(g, child_type);
Expand All @@ -1668,7 +1670,7 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");

gen_store(g, ored_value, ptr, ptr_type);
gen_store(g, ored_value, int_ptr, ptr_type);
}

static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
Expand Down Expand Up @@ -3396,7 +3398,10 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI

bool big_endian = g->is_big_endian;

LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0);
LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, "");
LLVMValueRef containing_int = gen_load(g, int_ptr, ptr_type, "");

uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
assert(host_bit_count == host_int_bytes * 8);
uint32_t size_in_bits = type_size_bits(g, child_type);
Expand Down Expand Up @@ -3722,7 +3727,8 @@ static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {

LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), "");
LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, "");
LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false);
const unsigned alignment_factor = ZigLLVMDataLayoutGetStackAlignment(g->target_data_ref);
LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), alignment_factor, false);
LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, "");
return LLVMBuildNUWSub(g->builder, end_addr, align_adj, "");
}
Expand Down Expand Up @@ -6723,8 +6729,10 @@ check: switch (const_val->special) {
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
} else {
bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry),
LLVMTypeRef field_ty = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry),
(unsigned)type_struct_field->gen_index);
const size_t size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, field_ty);
LLVMTypeRef big_int_type_ref = LLVMIntType(size_in_bytes * 8);
LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
size_t used_bits = 0;
for (size_t i = src_field_index; i < src_field_index_end; i += 1) {
Expand All @@ -6747,7 +6755,22 @@ check: switch (const_val->special) {
used_bits += packed_bits_size;
}
}
fields[type_struct_field->gen_index] = val;
if (LLVMGetTypeKind(field_ty) != LLVMArrayTypeKind) {
assert(LLVMGetTypeKind(field_ty) == LLVMIntegerTypeKind);
fields[type_struct_field->gen_index] = val;
} else {
const LLVMValueRef MASK = LLVMConstInt(LLVMInt8Type(), 255, false);
const LLVMValueRef AMT = LLVMConstInt(LLVMInt8Type(), 8, false);

LLVMValueRef *values = allocate<LLVMValueRef>(size_in_bytes);
for (size_t i = 0; i < size_in_bytes; i++) {
const size_t idx = is_big_endian ? size_in_bytes - 1 - i : i;
values[idx] = LLVMConstTruncOrBitCast(LLVMConstAnd(val, MASK), LLVMInt8Type());
val = LLVMConstLShr(val, AMT);
}

fields[type_struct_field->gen_index] = LLVMConstArray(LLVMInt8Type(), values, size_in_bytes);
}
}

src_field_index = src_field_index_end;
Expand Down
4 changes: 4 additions & 0 deletions src/zig_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Tri
return reinterpret_cast<LLVMTargetMachineRef>(TM);
}

unsigned ZigLLVMDataLayoutGetStackAlignment(LLVMTargetDataRef TD) {
return unwrap(TD)->getStackAlignment();
}

bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
bool is_small, bool time_report)
Expand Down
2 changes: 2 additions & 0 deletions src/zig_llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -469,4 +469,6 @@ ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum
enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type,
enum ZigLLVM_ObjectFormatType *oformat);

ZIG_EXTERN_C unsigned ZigLLVMDataLayoutGetStackAlignment(LLVMTargetDataRef TD);

#endif
4 changes: 3 additions & 1 deletion test/stage1/behavior.zig
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ comptime {
_ = @import("behavior/misc.zig");
_ = @import("behavior/muladd.zig");
_ = @import("behavior/namespace_depends_on_compile_var.zig");
_ = @import("behavior/new_stack_call.zig");
// See #3268
if (@import("builtin").arch != .aarch64)
_ = @import("behavior/new_stack_call.zig");
_ = @import("behavior/null.zig");
_ = @import("behavior/optional.zig");
_ = @import("behavior/pointers.zig");
Expand Down
3 changes: 2 additions & 1 deletion test/stage1/behavior/error.zig
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ test "nested catch" {
test "implicit cast to optional to error union to return result loc" {
const S = struct {
fn entry() void {
if (func(undefined)) |opt| {
var x: Foo = undefined;
if (func(&x)) |opt| {
expect(opt != null);
} else |_| @panic("expected non error");
}
Expand Down
12 changes: 12 additions & 0 deletions test/stage1/behavior/struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -658,3 +658,15 @@ test "struct field init with catch" {
S.doTheTest();
comptime S.doTheTest();
}

test "packed struct with non-ABI-aligned field" {
const S = packed struct {
x: u9,
y: u183,
};
var s: S = undefined;
s.x = 1;
s.y = 42;
expect(s.x == 1);
expect(s.y == 42);
}
4 changes: 3 additions & 1 deletion test/stage1/behavior/widening.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ test "float widening" {
var b: f32 = a;
var c: f64 = b;
var d: f128 = c;
expect(d == a);
expect(a == b);
expect(b == c);
expect(c == d);
}

0 comments on commit f3a7c34

Please sign in to comment.