diff --git a/ci/zinc/linux_test.sh b/ci/zinc/linux_test.sh index e24e8c2d53..4c3b3842bf 100755 --- a/ci/zinc/linux_test.sh +++ b/ci/zinc/linux_test.sh @@ -52,22 +52,22 @@ stage2/bin/zig build -p stage3 -Dstatic-llvm -Dtarget=native-native-musl --searc stage3/bin/zig build # test building self-hosted without LLVM stage3/bin/zig build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm -stage3/bin/zig build test-compiler-rt -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-behavior -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-std -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-universal-libc -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-compare-output -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-asm-link -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-fmt -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-translate-c -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-standalone -fqemu -fwasmtime -Denable-llvm -stage3/bin/zig build test-cli -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-compiler-rt -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-behavior -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-std -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-universal-libc -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-compare-output -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-asm-link -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-fmt -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-translate-c -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-run-translated-c -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-standalone -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-cli -fqemu -fwasmtime -Denable-llvm # https://github.com/ziglang/zig/issues/12144 -stage3/bin/zig build test-cases -fqemu -fwasmtime -stage3/bin/zig build test-link -fqemu -fwasmtime -Denable-llvm +stage3/bin/zig build test-cases -fqemu -fwasmtime +stage3/bin/zig build test-link -fqemu -fwasmtime -Denable-llvm $STAGE1_ZIG build test-stack-traces -fqemu -fwasmtime -$STAGE1_ZIG build test-run-translated-c -fqemu -fwasmtime $STAGE1_ZIG build docs -fqemu -fwasmtime # Produce the experimental std lib documentation. diff --git a/src/AstGen.zig b/src/AstGen.zig index e194e94d05..528ef930e6 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -10282,11 +10282,11 @@ const GenZir = struct { try astgen.extra.ensureUnusedCapacity( gpa, @typeInfo(Zir.Inst.FuncFancy).Struct.fields.len + - fancyFnExprExtraLen(align_body, args.align_ref) + - fancyFnExprExtraLen(addrspace_body, args.addrspace_ref) + - fancyFnExprExtraLen(section_body, args.section_ref) + - fancyFnExprExtraLen(cc_body, args.cc_ref) + - fancyFnExprExtraLen(ret_body, ret_ref) + + fancyFnExprExtraLen(astgen, align_body, args.align_ref) + + fancyFnExprExtraLen(astgen, addrspace_body, args.addrspace_ref) + + fancyFnExprExtraLen(astgen, section_body, args.section_ref) + + fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) + + fancyFnExprExtraLen(astgen, ret_body, ret_ref) + body_len + src_locs.len + @boolToInt(args.lib_name != 0) + @boolToInt(args.noalias_bits != 0), @@ -10322,36 +10322,36 @@ const GenZir = struct { const zir_datas = astgen.instructions.items(.data); if (align_body.len != 0) { - astgen.extra.appendAssumeCapacity(@intCast(u32, align_body.len)); - astgen.extra.appendSliceAssumeCapacity(align_body); + astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, align_body)); + astgen.appendBodyWithFixups(align_body); zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index; } else if (args.align_ref != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref)); } if (addrspace_body.len != 0) { - astgen.extra.appendAssumeCapacity(@intCast(u32, addrspace_body.len)); - astgen.extra.appendSliceAssumeCapacity(addrspace_body); + astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, addrspace_body)); + astgen.appendBodyWithFixups(addrspace_body); zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index; } else if (args.addrspace_ref != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref)); } if (section_body.len != 0) { - astgen.extra.appendAssumeCapacity(@intCast(u32, section_body.len)); - astgen.extra.appendSliceAssumeCapacity(section_body); + astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, section_body)); + astgen.appendBodyWithFixups(section_body); zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index; } else if (args.section_ref != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref)); } if (cc_body.len != 0) { - astgen.extra.appendAssumeCapacity(@intCast(u32, cc_body.len)); - astgen.extra.appendSliceAssumeCapacity(cc_body); + astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, cc_body)); + astgen.appendBodyWithFixups(cc_body); zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index; } else if (args.cc_ref != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref)); } if (ret_body.len != 0) { - astgen.extra.appendAssumeCapacity(@intCast(u32, ret_body.len)); - astgen.extra.appendSliceAssumeCapacity(ret_body); + astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, ret_body)); + astgen.appendBodyWithFixups(ret_body); zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; } else if (ret_ref != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); @@ -10389,11 +10389,12 @@ const GenZir = struct { try astgen.extra.ensureUnusedCapacity( gpa, @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 + - @maximum(ret_body.len, @boolToInt(ret_ref != .none)) + + fancyFnExprExtraLen(astgen, ret_body, ret_ref) + body_len + src_locs.len, ); + const ret_body_len = if (ret_body.len != 0) - @intCast(u32, ret_body.len) + countBodyLenAfterFixups(astgen, ret_body) else @boolToInt(ret_ref != .none); @@ -10404,7 +10405,7 @@ const GenZir = struct { }); const zir_datas = astgen.instructions.items(.data); if (ret_body.len != 0) { - astgen.extra.appendSliceAssumeCapacity(ret_body); + astgen.appendBodyWithFixups(ret_body); zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; } else if (ret_ref != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); @@ -10435,10 +10436,10 @@ const GenZir = struct { } } - fn fancyFnExprExtraLen(body: []Zir.Inst.Index, ref: Zir.Inst.Ref) usize { + fn fancyFnExprExtraLen(astgen: *AstGen, body: []Zir.Inst.Index, ref: Zir.Inst.Ref) u32 { // In the case of non-empty body, there is one for the body length, // and then one for each instruction. - return body.len + @boolToInt(ref != .none); + return countBodyLenAfterFixups(astgen, body) + @boolToInt(ref != .none); } fn addVar(gz: *GenZir, args: struct { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index e7915e08b3..6a2e346113 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3646,6 +3646,24 @@ pub const DeclGen = struct { }, .Struct => { const field_ty = parent_ty.structFieldType(field_index); + if (parent_ty.containerLayout() == .Packed) { + const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); + const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); + // count bits of fields before this one + const prev_bits = b: { + var b: usize = 0; + for (parent_ty.structFields().values()[0..field_index]) |field| { + if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; + b += field.ty.bitSize(target); + } + break :b b; + }; + const byte_offset = llvm_usize.constInt((prev_bits + 7) / 8, .False); + const field_addr = base_addr.constAdd(byte_offset); + bitcast_needed = false; + const final_llvm_ty = (try dg.lowerType(ptr_child_ty)).pointerType(0); + break :blk field_addr.constIntToPtr(final_llvm_ty); + } bitcast_needed = !field_ty.eql(ptr_child_ty, dg.module); var ty_buf: Type.Payload.Pointer = undefined; @@ -4473,17 +4491,29 @@ pub const FuncGen = struct { } return null; } + const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); + const ptr_abi_ty = abi_ret_ty.pointerType(0); const operand = try self.resolveInst(un_op); + const target = self.dg.module.getTarget(); + const alignment = ret_ty.abiAlignment(target); + + if (isByRef(ret_ty)) { + // operand is a pointer however self.ret_ptr is null so that means + // we need to return a value. + const casted_ptr = self.builder.buildBitCast(operand, ptr_abi_ty, ""); + const load_inst = self.builder.buildLoad(casted_ptr, ""); + load_inst.setAlignment(alignment); + _ = self.builder.buildRet(load_inst); + return null; + } + const llvm_ret_ty = operand.typeOf(); if (abi_ret_ty == llvm_ret_ty) { _ = self.builder.buildRet(operand); return null; } - const target = self.dg.module.getTarget(); - const alignment = ret_ty.abiAlignment(target); - const ptr_abi_ty = abi_ret_ty.pointerType(0); const rp = self.buildAlloca(llvm_ret_ty); rp.setAlignment(alignment); const store_inst = self.builder.buildStore(operand, rp); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 07408f12b9..e4357b8060 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -169,6 +169,9 @@ pub const Value = opaque { pub const constNot = LLVMConstNot; extern fn LLVMConstNot(ConstantVal: *const Value) *const Value; + pub const constAdd = LLVMConstAdd; + extern fn LLVMConstAdd(LHSConstant: *const Value, RHSConstant: *const Value) *const Value; + pub const setWeak = LLVMSetWeak; extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void; diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 383d553781..044e4ff049 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -408,3 +408,17 @@ test "function with inferred error set but returning no error" { const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); } + +test "import passed byref to function in return type" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const S = struct { + fn get() @import("std").ArrayListUnmanaged(i32) { + var x: @import("std").ArrayListUnmanaged(i32) = .{}; + return x; + } + }; + var list = S.get(); + try expect(list.items.len == 0); +} diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 52083a492d..2dea485bf5 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -436,3 +436,25 @@ test "load pointer from packed struct" { try expect(i == 123); } } + +test "@ptrToInt on a packed struct field" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const S = struct { + const P = packed struct { + x: u8, + y: u8, + z: u32, + }; + var p0: P = P{ + .x = 1, + .y = 2, + .z = 0, + }; + }; + try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2); +} diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 8e4b262565..2f6fa78f0c 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1226,3 +1226,33 @@ test "extern union most-aligned field is smaller" { var a: ?U = .{ .un = [_]u8{0} ** 110 }; try expect(a != null); } + +test "return an extern union from C calling convention" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const namespace = struct { + const S = extern struct { + x: c_int, + }; + const U = extern union { + l: c_long, + d: f64, + s: S, + }; + + fn bar(arg_u: U) callconv(.C) U { + var u = arg_u; + return u; + } + }; + + var u: namespace.U = namespace.U{ + .l = @as(c_long, 42), + }; + u = namespace.bar(namespace.U{ + .d = 4.0, + }); + try expect(u.d == 4.0); +} diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index cfd7f2d15e..871ec98fbc 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -891,39 +891,42 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\} , ""); - cases.add("Obscure ways of calling functions; issue #4124", - \\#include - \\static int add(int a, int b) { - \\ return a + b; - \\} - \\typedef int (*adder)(int, int); - \\typedef void (*funcptr)(void); - \\int main() { - \\ if ((add)(1, 2) != 3) abort(); - \\ if ((&add)(1, 2) != 3) abort(); - \\ if (add(3, 1) != 4) abort(); - \\ if ((*add)(2, 3) != 5) abort(); - \\ if ((**add)(7, -1) != 6) abort(); - \\ if ((***add)(-2, 9) != 7) abort(); - \\ - \\ int (*ptr)(int a, int b); - \\ ptr = add; - \\ - \\ if (ptr(1, 2) != 3) abort(); - \\ if ((*ptr)(3, 1) != 4) abort(); - \\ if ((**ptr)(2, 3) != 5) abort(); - \\ if ((***ptr)(7, -1) != 6) abort(); - \\ if ((****ptr)(-2, 9) != 7) abort(); - \\ - \\ funcptr addr1 = (funcptr)(add); - \\ funcptr addr2 = (funcptr)(&add); - \\ - \\ if (addr1 != addr2) abort(); - \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort(); - \\ if (((adder)addr2)(1, 2) != 3) abort(); - \\ return 0; - \\} - , ""); + if (@import("builtin").zig_backend == .stage1) { + // https://github.com/ziglang/zig/issues/12263 + cases.add("Obscure ways of calling functions; issue #4124", + \\#include + \\static int add(int a, int b) { + \\ return a + b; + \\} + \\typedef int (*adder)(int, int); + \\typedef void (*funcptr)(void); + \\int main() { + \\ if ((add)(1, 2) != 3) abort(); + \\ if ((&add)(1, 2) != 3) abort(); + \\ if (add(3, 1) != 4) abort(); + \\ if ((*add)(2, 3) != 5) abort(); + \\ if ((**add)(7, -1) != 6) abort(); + \\ if ((***add)(-2, 9) != 7) abort(); + \\ + \\ int (*ptr)(int a, int b); + \\ ptr = add; + \\ + \\ if (ptr(1, 2) != 3) abort(); + \\ if ((*ptr)(3, 1) != 4) abort(); + \\ if ((**ptr)(2, 3) != 5) abort(); + \\ if ((***ptr)(7, -1) != 6) abort(); + \\ if ((****ptr)(-2, 9) != 7) abort(); + \\ + \\ funcptr addr1 = (funcptr)(add); + \\ funcptr addr2 = (funcptr)(&add); + \\ + \\ if (addr1 != addr2) abort(); + \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort(); + \\ if (((adder)addr2)(1, 2) != 3) abort(); + \\ return 0; + \\} + , ""); + } cases.add("Return boolean expression as int; issue #6215", \\#include @@ -1319,25 +1322,28 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\} , ""); - cases.add("basic vector expressions", - \\#include - \\#include - \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); - \\int main(int argc, char**argv) { - \\ __v8hi uninitialized; - \\ __v8hi empty_init = {}; - \\ __v8hi partial_init = {0, 1, 2, 3}; - \\ - \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7}; - \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800}; - \\ - \\ __v8hi sum = a + b; - \\ for (int i = 0; i < 8; i++) { - \\ if (sum[i] != a[i] + b[i]) abort(); - \\ } - \\ return 0; - \\} - , ""); + if (@import("builtin").zig_backend == .stage1) { + // https://github.com/ziglang/zig/issues/12264 + cases.add("basic vector expressions", + \\#include + \\#include + \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); + \\int main(int argc, char**argv) { + \\ __v8hi uninitialized; + \\ __v8hi empty_init = {}; + \\ __v8hi partial_init = {0, 1, 2, 3}; + \\ + \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7}; + \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800}; + \\ + \\ __v8hi sum = a + b; + \\ for (int i = 0; i < 8; i++) { + \\ if (sum[i] != a[i] + b[i]) abort(); + \\ } + \\ return 0; + \\} + , ""); + } cases.add("__builtin_shufflevector", \\#include