Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A few steps towards AArch64 & ARM passing the behavior tests #3278

Merged
merged 4 commits into from
Sep 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -1630,7 +1630,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 @@ -1654,7 +1656,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 @@ -3375,7 +3377,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 @@ -3701,7 +3706,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 @@ -6693,8 +6699,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 @@ -6717,7 +6725,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);
}