From 152462e2e1513ca9d7db5c2d6a2a61b547c5151c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 Jun 2022 14:31:46 -0700 Subject: [PATCH 1/5] stage2: object format affects whether LLVM can be used --- src/Compilation.zig | 6 +----- src/target.zig | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index c6c7a94b41..99b502dbd7 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1024,10 +1024,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (options.use_llvm) |explicit| break :blk explicit; - // If we are outputting .c code we must use Zig backend. - if (ofmt == .c) - break :blk false; - // If emitting to LLVM bitcode object format, must use LLVM backend. if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) break :blk true; @@ -1042,7 +1038,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { break :blk true; // If LLVM does not support the target, then we can't use it. - if (!target_util.hasLlvmSupport(options.target)) + if (!target_util.hasLlvmSupport(options.target, ofmt)) break :blk false; // Prefer LLVM for release builds. diff --git a/src/target.zig b/src/target.zig index 93c179b7f0..ea8b3efc45 100644 --- a/src/target.zig +++ b/src/target.zig @@ -204,7 +204,24 @@ pub fn hasValgrindSupport(target: std.Target) bool { /// The set of targets that LLVM has non-experimental support for. /// Used to select between LLVM backend and self-hosted backend when compiling in /// release modes. -pub fn hasLlvmSupport(target: std.Target) bool { +pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool { + switch (ofmt) { + // LLVM does not support these object formats: + .c, + .plan9, + => return false, + + .coff, + .elf, + .macho, + .wasm, + .spirv, + .hex, + .raw, + .nvptx, + => {}, + } + return switch (target.cpu.arch) { .arm, .armeb, From 67db2b85b771d8b0f9d765922951c31fce9c8cc2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 Jun 2022 14:32:10 -0700 Subject: [PATCH 2/5] remove plan9 test coverage This regressed; the plan9 linker code is crashing when trying to build compiler-rt and we have no active plan9 maintainers involved in the Zig project. Anyone is welcome to come over and take the role; however, it's not one of the tier 1, 2, or 3 targets, so we will not be blocking progress towards 1.0 on plan9. --- test/cases/plan9/exit.zig | 5 ---- .../plan9/hello_world_with_updates.0.zig | 28 ------------------- .../plan9/hello_world_with_updates.1.zig | 10 ------- 3 files changed, 43 deletions(-) delete mode 100644 test/cases/plan9/exit.zig delete mode 100644 test/cases/plan9/hello_world_with_updates.0.zig delete mode 100644 test/cases/plan9/hello_world_with_updates.1.zig diff --git a/test/cases/plan9/exit.zig b/test/cases/plan9/exit.zig deleted file mode 100644 index 735818fb83..0000000000 --- a/test/cases/plan9/exit.zig +++ /dev/null @@ -1,5 +0,0 @@ -pub fn main() void {} - -// run -// target=x86_64-plan9,aarch64-plan9 -// diff --git a/test/cases/plan9/hello_world_with_updates.0.zig b/test/cases/plan9/hello_world_with_updates.0.zig deleted file mode 100644 index 7e7c373251..0000000000 --- a/test/cases/plan9/hello_world_with_updates.0.zig +++ /dev/null @@ -1,28 +0,0 @@ -pub fn main() void { - const str = "Hello World!\n"; - asm volatile ( - \\push $0 - \\push %%r10 - \\push %%r11 - \\push $1 - \\push $0 - \\syscall - \\pop %%r11 - \\pop %%r11 - \\pop %%r11 - \\pop %%r11 - \\pop %%r11 - : - // pwrite - : [syscall_number] "{rbp}" (51), - [hey] "{r11}" (@ptrToInt(str)), - [strlen] "{r10}" (str.len), - : "rcx", "rbp", "r11", "memory" - ); -} - -// run -// target=x86_64-plan9 -// -// Hello World -// diff --git a/test/cases/plan9/hello_world_with_updates.1.zig b/test/cases/plan9/hello_world_with_updates.1.zig deleted file mode 100644 index 4111a8dc08..0000000000 --- a/test/cases/plan9/hello_world_with_updates.1.zig +++ /dev/null @@ -1,10 +0,0 @@ -const std = @import("std"); -pub fn main() void { - const str = "Hello World!\n"; - _ = std.os.plan9.pwrite(1, str, str.len, 0); -} - -// run -// -// Hello World -// From c030ec1884ad7c553d6680944b47a1fc7653586f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 Jun 2022 15:58:51 -0700 Subject: [PATCH 3/5] LLVM: use unnamed struct llvm type for unions when necessary The constant value lowering for unions was missing a check for whether the payload was itself an unnamed struct. Lowerings of other types already handle this case. closes #11971 --- src/codegen/llvm.zig | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 7f85570e06..45a90c81e5 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3401,6 +3401,13 @@ pub const DeclGen = struct { const union_obj = tv.ty.cast(Type.Payload.Union).?.data; const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag, dg.module).?; assert(union_obj.haveFieldTypes()); + + // Sometimes we must make an unnamed struct because LLVM does + // not support bitcasting our payload struct to the true union payload type. + // Instead we use an unnamed struct and every reference to the global + // must pointer cast to the expected type before accessing the union. + var need_unnamed: bool = layout.most_aligned_field != field_index; + const field_ty = union_obj.fields.values()[field_index].ty; const payload = p: { if (!field_ty.hasRuntimeBitsIgnoreComptime()) { @@ -3408,6 +3415,7 @@ pub const DeclGen = struct { break :p dg.context.intType(8).arrayType(padding_len).getUndef(); } const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); + need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field); const field_size = field_ty.abiSize(target); if (field_size == layout.payload_size) { break :p field; @@ -3419,12 +3427,6 @@ pub const DeclGen = struct { break :p dg.context.constStruct(&fields, fields.len, .True); }; - // In this case we must make an unnamed struct because LLVM does - // not support bitcasting our payload struct to the true union payload type. - // Instead we use an unnamed struct and every reference to the global - // must pointer cast to the expected type before accessing the union. - const need_unnamed = layout.most_aligned_field != field_index; - if (layout.tag_size == 0) { const fields: [1]*const llvm.Value = .{payload}; if (need_unnamed) { From d3542be875704bffc931970948345d1a44e25b8e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 Jun 2022 16:32:03 -0700 Subject: [PATCH 4/5] LLVM: be sure to never pass align(0) attribute This can happen with pointers to zero-bit types. This commit fixes an LLVM assertion being tripped. --- src/codegen/llvm.zig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 45a90c81e5..c3194ccda1 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -768,7 +768,11 @@ pub const Object = struct { if (ptr_info.@"align" != 0) { dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align"); } else { - dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.pointee_type.abiAlignment(target)); + const elem_align = @maximum( + ptr_info.pointee_type.abiAlignment(target), + 1, + ); + dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align); } } } @@ -840,7 +844,8 @@ pub const Object = struct { if (ptr_info.@"align" != 0) { dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align"); } else { - dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.pointee_type.abiAlignment(target)); + const elem_align = @maximum(ptr_info.pointee_type.abiAlignment(target), 1); + dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align); } const ptr_param = llvm_func.getParam(llvm_arg_i); llvm_arg_i += 1; From 095e24e537fcb6a702b992d946d1ca73d6f608b3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 Jun 2022 19:09:21 -0700 Subject: [PATCH 5/5] stage2: implement alignment calculation of vectors closes #11856 --- lib/std/simd.zig | 1 - src/type.zig | 10 +++++++--- test/behavior/vector.zig | 24 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/std/simd.zig b/lib/std/simd.zig index a7ce0ab3fd..a30622aef6 100644 --- a/lib/std/simd.zig +++ b/lib/std/simd.zig @@ -160,7 +160,6 @@ pub fn extract( } test "vector patterns" { - if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; const base = @Vector(4, u32){ 10, 20, 30, 40 }; const other_base = @Vector(4, u32){ 55, 66, 77, 88 }; diff --git a/src/type.zig b/src/type.zig index 0ca7ba83c5..e116f1ed20 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2906,9 +2906,13 @@ pub const Type = extern union { .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat), - // TODO audit this - is there any more complicated logic to determine - // ABI alignment of vectors? - .vector => return AbiAlignmentAdvanced{ .scalar = 16 }, + .vector => { + const len = ty.arrayLen(); + const bits = try bitSizeAdvanced(ty.elemType(), target, sema_kit); + const bytes = (bits + 7) / 8; + const alignment = std.math.ceilPowerOfTwoAssert(u64, bytes * len); + return AbiAlignmentAdvanced{ .scalar = @intCast(u32, alignment) }; + }, .i16, .u16 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(16, target) }, .u29 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(29, target) }, diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index fc49bce6e2..e355db5166 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -1048,3 +1048,27 @@ test "@shlWithOverflow" { try S.doTheTest(); comptime try S.doTheTest(); } + +test "alignment of vectors" { + try expect(@alignOf(@Vector(2, u8)) == 2); + try expect(@alignOf(@Vector(2, u1)) == 2); + try expect(@alignOf(@Vector(1, u1)) == 1); + try expect(@alignOf(@Vector(2, u16)) == 4); +} + +test "loading the second vector from a slice of vectors" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + @setRuntimeSafety(false); + var small_bases = [2]@Vector(2, u8){ + @Vector(2, u8){ 0, 1 }, + @Vector(2, u8){ 2, 3 }, + }; + var a: []const @Vector(2, u8) = &small_bases; + var a4 = a[1][1]; + try expect(a4 == 3); +}