diff options
| -rw-r--r-- | lib/std/os/bits/linux.zig | 2 | ||||
| -rw-r--r-- | lib/std/os/linux.zig | 1 | ||||
| -rw-r--r-- | lib/std/os/linux/thumb.zig | 168 | ||||
| -rw-r--r-- | lib/std/os/linux/tls.zig | 6 | ||||
| -rw-r--r-- | lib/std/os/test.zig | 2 | ||||
| -rw-r--r-- | lib/std/special/c.zig | 2 | ||||
| -rw-r--r-- | lib/std/special/compiler_rt/clzsi2.zig | 27 | ||||
| -rw-r--r-- | lib/std/special/compiler_rt/clzsi2_test.zig | 2 | ||||
| -rw-r--r-- | lib/std/start.zig | 2 | ||||
| -rw-r--r-- | lib/std/zig/system.zig | 9 | ||||
| -rw-r--r-- | src/link/MachO/Archive.zig | 9 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 26 | ||||
| -rw-r--r-- | src/link/MachO/Symbol.zig | 10 | ||||
| -rw-r--r-- | src/link/MachO/Zld.zig | 31 | ||||
| -rw-r--r-- | src/link/MachO/reloc/aarch64.zig | 2 | ||||
| -rw-r--r-- | src/stage1/codegen.cpp | 4 | ||||
| -rw-r--r-- | src/stage1/parser.cpp | 11 | ||||
| -rw-r--r-- | test/behavior/align.zig | 3 | ||||
| -rw-r--r-- | test/behavior/asm.zig | 15 | ||||
| -rw-r--r-- | test/behavior/async_fn.zig | 5 | ||||
| -rw-r--r-- | test/behavior/atomics.zig | 8 | ||||
| -rw-r--r-- | test/behavior/vector.zig | 15 |
22 files changed, 305 insertions, 55 deletions
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index b877976072..556eb20ab2 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -18,7 +18,7 @@ pub usingnamespace switch (arch) { .i386 => @import("linux/i386.zig"), .x86_64 => @import("linux/x86_64.zig"), .aarch64 => @import("linux/arm64.zig"), - .arm => @import("linux/arm-eabi.zig"), + .arm, .thumb => @import("linux/arm-eabi.zig"), .riscv64 => @import("linux/riscv64.zig"), .sparcv9 => @import("linux/sparc64.zig"), .mips, .mipsel => @import("linux/mips.zig"), diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 5e5fde2b97..65cbc87e36 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -24,6 +24,7 @@ pub usingnamespace switch (native_arch) { .x86_64 => @import("linux/x86_64.zig"), .aarch64 => @import("linux/arm64.zig"), .arm => @import("linux/arm-eabi.zig"), + .thumb => @import("linux/thumb.zig"), .riscv64 => @import("linux/riscv64.zig"), .sparcv9 => @import("linux/sparc64.zig"), .mips, .mipsel => @import("linux/mips.zig"), diff --git a/lib/std/os/linux/thumb.zig b/lib/std/os/linux/thumb.zig new file mode 100644 index 0000000000..5db9d2cbf4 --- /dev/null +++ b/lib/std/os/linux/thumb.zig @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +usingnamespace @import("../bits.zig"); + +// The syscall interface is identical to the ARM one but we're facing an extra +// challenge: r7, the register where the syscall number is stored, may be +// reserved for the frame pointer. +// Save and restore r7 around the syscall without touching the stack pointer not +// to break the frame chain. + +pub fn syscall0(number: SYS) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r1}" (buf) + : "memory" + ); +} + +pub fn syscall1(number: SYS, arg1: usize) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r1}" (buf), + [arg1] "{r0}" (arg1) + : "memory" + ); +} + +pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r2}" (buf), + [arg1] "{r0}" (arg1), + [arg2] "{r1}" (arg2) + : "memory" + ); +} + +pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r3}" (buf), + [arg1] "{r0}" (arg1), + [arg2] "{r1}" (arg2), + [arg3] "{r2}" (arg3) + : "memory" + ); +} + +pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r4}" (buf), + [arg1] "{r0}" (arg1), + [arg2] "{r1}" (arg2), + [arg3] "{r2}" (arg3), + [arg4] "{r3}" (arg4) + : "memory" + ); +} + +pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r5}" (buf), + [arg1] "{r0}" (arg1), + [arg2] "{r1}" (arg2), + [arg3] "{r2}" (arg3), + [arg4] "{r3}" (arg4), + [arg5] "{r4}" (arg5) + : "memory" + ); +} + +pub fn syscall6( + number: SYS, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + @setRuntimeSafety(false); + + var buf: [2]usize = .{ @enumToInt(number), undefined }; + return asm volatile ( + \\ str r7, [%[tmp], #4] + \\ ldr r7, [%[tmp]] + \\ svc #0 + \\ ldr r7, [%[tmp], #4] + : [ret] "={r0}" (-> usize) + : [tmp] "{r6}" (buf), + [arg1] "{r0}" (arg1), + [arg2] "{r1}" (arg2), + [arg3] "{r2}" (arg3), + [arg4] "{r3}" (arg4), + [arg5] "{r4}" (arg5), + [arg6] "{r5}" (arg6) + : "memory" + ); +} + +/// This matches the libc clone function. +pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; + +pub fn restore() callconv(.Naked) void { + return asm volatile ( + \\ mov r7, %[number] + \\ svc #0 + : + : [number] "I" (@enumToInt(SYS.sigreturn)) + ); +} + +pub fn restore_rt() callconv(.Naked) void { + return asm volatile ( + \\ mov r7, %[number] + \\ svc #0 + : + : [number] "I" (@enumToInt(SYS.rt_sigreturn)) + : "memory" + ); +} diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index 38a307ac2f..4d5dba3112 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -53,7 +53,7 @@ const TLSVariant = enum { }; const tls_variant = switch (native_arch) { - .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, + .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, .x86_64, .i386, .sparcv9 => TLSVariant.VariantII, else => @compileError("undefined tls_variant for this architecture"), }; @@ -62,7 +62,7 @@ const tls_variant = switch (native_arch) { const tls_tcb_size = switch (native_arch) { // ARM EABI mandates enough space for two pointers: the first one points to // the DTV while the second one is unspecified but reserved - .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), + .arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), // One pointer-sized word that points either to the DTV or the TCB itself else => @sizeOf(usize), }; @@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void { : [addr] "r" (addr) ); }, - .arm => { + .arm, .thumb => { const rc = std.os.linux.syscall1(.set_tls, addr); assert(rc == 0); }, diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index bae03ba6aa..bcb2fa339a 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -43,6 +43,8 @@ test "chdir smoke test" { // Next, change current working directory to one level above const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute try os.chdir(parent); + // Restore cwd because process may have other tests that do not tolerate chdir. + defer os.chdir(old_cwd) catch unreachable; var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; const new_cwd = try os.getcwd(new_cwd_buf[0..]); expect(mem.eql(u8, parent, new_cwd)); diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 6515a790b3..8a9093f3ea 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -388,7 +388,7 @@ fn clone() callconv(.Naked) void { \\ svc #0 ); }, - .arm => { + .arm, .thumb => { // __clone(func, stack, flags, arg, ptid, tls, ctid) // r0, r1, r2, r3, +0, +4, +8 diff --git a/lib/std/special/compiler_rt/clzsi2.zig b/lib/std/special/compiler_rt/clzsi2.zig index c10786b462..d7464d5ea9 100644 --- a/lib/std/special/compiler_rt/clzsi2.zig +++ b/lib/std/special/compiler_rt/clzsi2.zig @@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 { } fn __clzsi2_thumb1() callconv(.Naked) void { + @setRuntimeSafety(false); + // Similar to the generic version with the last two rounds replaced by a LUT asm volatile ( \\ movs r1, #32 @@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void { } fn __clzsi2_arm32() callconv(.Naked) void { + @setRuntimeSafety(false); + asm volatile ( \\ // Assumption: n != 0 \\ // r0: n @@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void { unreachable; } -pub const __clzsi2 = switch (std.Target.current.cpu.arch) { - .arm, .armeb => if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm)) - __clzsi2_thumb1 - else - __clzsi2_arm32, - .thumb, .thumbeb => __clzsi2_thumb1, - else => __clzsi2_generic, +pub const __clzsi2 = impl: { + switch (std.Target.current.cpu.arch) { + .arm, .armeb, .thumb, .thumbeb => { + const use_thumb1 = + (std.Target.current.cpu.arch.isThumb() or + std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm)) and + !std.Target.arm.featureSetHas(std.Target.current.cpu.features, .thumb2); + + if (use_thumb1) break :impl __clzsi2_thumb1 + // From here on we're either targeting Thumb2 or ARM. + else if (!std.Target.current.cpu.arch.isThumb()) break :impl __clzsi2_arm32 + // Use the generic implementation otherwise. + else break :impl __clzsi2_generic; + }, + else => break :impl __clzsi2_generic, + } }; test "test clzsi2" { diff --git a/lib/std/special/compiler_rt/clzsi2_test.zig b/lib/std/special/compiler_rt/clzsi2_test.zig index 2b860afd22..c74a1c3ec2 100644 --- a/lib/std/special/compiler_rt/clzsi2_test.zig +++ b/lib/std/special/compiler_rt/clzsi2_test.zig @@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig"); const testing = @import("std").testing; fn test__clzsi2(a: u32, expected: i32) void { + // XXX At high optimization levels this test may be horribly miscompiled if + // one of the naked implementations is selected. var nakedClzsi2 = clzsi2.__clzsi2; var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2); var x = @bitCast(i32, a); diff --git a/lib/std/start.zig b/lib/std/start.zig index 998dba6074..fa9d5a92b6 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -182,7 +182,7 @@ fn _start() callconv(.Naked) noreturn { : [argc] "={esp}" (-> [*]usize) ); }, - .aarch64, .aarch64_be, .arm, .armeb => { + .aarch64, .aarch64_be, .arm, .armeb, .thumb => { argc_argv_ptr = asm volatile ( \\ mov fp, #0 \\ mov lr, #0 diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 04b3d75cb4..5792e7f115 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -350,6 +350,15 @@ pub const NativeTargetInfo = struct { } } }, + .arm, .armeb => { + // XXX What do we do if the target has the noarm feature? + // What do we do if the user specifies +thumb_mode? + }, + .thumb, .thumbeb => { + result.target.cpu.features.addFeature( + @enumToInt(std.Target.arm.Feature.thumb_mode), + ); + }, else => {}, } cross_target.updateCpuFeatures(&result.target.cpu.features); diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index 5a0b9609ad..702a807a4d 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -16,7 +16,7 @@ allocator: *Allocator, arch: ?std.Target.Cpu.Arch = null, file: ?fs.File = null, header: ?ar_hdr = null, -name: ?[]u8 = null, +name: ?[]const u8 = null, /// Parsed table of contents. /// Each symbol name points to a list of all definition @@ -195,7 +195,7 @@ fn parseTableOfContents(self: *Archive, reader: anytype) !void { } /// Caller owns the Object instance. -pub fn parseObject(self: Archive, offset: u32) !Object { +pub fn parseObject(self: Archive, offset: u32) !*Object { var reader = self.file.?.reader(); try reader.context.seekTo(offset); @@ -217,7 +217,10 @@ pub fn parseObject(self: Archive, offset: u32) !Object { break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_name }); }; - var object = Object.init(self.allocator); + var object = try self.allocator.create(Object); + errdefer self.allocator.destroy(object); + + object.* = Object.init(self.allocator); object.arch = self.arch.?; object.file = try fs.cwd().openFile(self.name.?, .{}); object.name = name; diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 31cc63cfe0..4d2ade7aad 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -22,7 +22,7 @@ arch: ?std.Target.Cpu.Arch = null, header: ?macho.mach_header_64 = null, file: ?fs.File = null, file_offset: ?u32 = null, -name: ?[]u8 = null, +name: ?[]const u8 = null, load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, sections: std.ArrayListUnmanaged(Section) = .{}, @@ -343,14 +343,22 @@ pub fn parseSymbols(self: *Object) !void { _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff); for (slice) |sym| { + const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx)); + if (Symbol.isStab(sym)) { - log.err("TODO handle stabs embedded within object files", .{}); - return error.HandleStabsInObjects; + log.err("stab {s} in {s}", .{ sym_name, self.name.? }); + return error.UnhandledSymbolType; + } + if (Symbol.isIndr(sym)) { + log.err("indirect symbol {s} in {s}", .{ sym_name, self.name.? }); + return error.UnhandledSymbolType; + } + if (Symbol.isAbs(sym)) { + log.err("absolute symbol {s} in {s}", .{ sym_name, self.name.? }); + return error.UnhandledSymbolType; } - const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx)); const name = try self.allocator.dupe(u8, sym_name); - const symbol: *Symbol = symbol: { if (Symbol.isSect(sym)) { const linkage: Symbol.Regular.Linkage = linkage: { @@ -374,6 +382,14 @@ pub fn parseSymbols(self: *Object) !void { break :symbol ®ular.base; } + if (sym.n_value != 0) { + log.err("common symbol {s} in {s}", .{ sym_name, self.name.? }); + return error.UnhandledSymbolType; + // const comm_size = sym.n_value; + // const comm_align = (sym.n_desc >> 8) & 0x0f; + // log.warn("Common symbol: size 0x{x}, align 0x{x}", .{ comm_size, comm_align }); + } + const undef = try self.allocator.create(Symbol.Unresolved); errdefer self.allocator.destroy(undef); undef.* = .{ diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 4b8ee3c77c..f928c807a3 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -133,6 +133,16 @@ pub fn isUndf(sym: macho.nlist_64) bool { return type_ == macho.N_UNDF; } +pub fn isIndr(sym: macho.nlist_64) bool { + const type_ = macho.N_TYPE & sym.n_type; + return type_ == macho.N_INDR; +} + +pub fn isAbs(sym: macho.nlist_64) bool { + const type_ = macho.N_TYPE & sym.n_type; + return type_ == macho.N_ABS; +} + pub fn isWeakDef(sym: macho.nlist_64) bool { return (sym.n_desc & macho.N_WEAK_DEF) != 0; } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 1b343fad3f..4d19da1e97 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -82,7 +82,7 @@ unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, -threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, +threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, stubs: std.ArrayListUnmanaged(*Symbol) = .{}, got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, @@ -92,6 +92,15 @@ stub_helper_stubs_start_off: ?u64 = null, mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, +const TlvOffset = struct { + source_addr: u64, + offset: u64, + + fn cmp(context: void, a: TlvOffset, b: TlvOffset) bool { + return a.source_addr < b.source_addr; + } +}; + const MappingKey = struct { object_id: u16, source_sect_id: u16, @@ -277,7 +286,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { object.* = Object.init(self.allocator); object.arch = self.arch.?; - object.name = try self.allocator.dupe(u8, input.name); + object.name = input.name; object.file = input.file; try object.parse(); try self.objects.append(self.allocator, object); @@ -288,7 +297,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { archive.* = Archive.init(self.allocator); archive.arch = self.arch.?; - archive.name = try self.allocator.dupe(u8, input.name); + archive.name = input.name; archive.file = input.file; try archive.parse(); try self.archives.append(self.allocator, archive); @@ -1362,10 +1371,7 @@ fn resolveSymbols(self: *Zld) !void { }; assert(offsets.items.len > 0); - const object = try self.allocator.create(Object); - errdefer self.allocator.destroy(object); - - object.* = try archive.parseObject(offsets.items[0]); + const object = try archive.parseObject(offsets.items[0]); try self.objects.append(self.allocator, object); try self.resolveSymbolsInObject(object); @@ -1567,7 +1573,10 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { }; // Since we require TLV data to always preceed TLV bss section, we calculate // offsets wrt to the former if it is defined; otherwise, wrt to the latter. - try self.threadlocal_offsets.append(self.allocator, args.target_addr - base_addr); + try self.threadlocal_offsets.append(self.allocator, .{ + .source_addr = args.source_addr, + .offset = args.target_addr - base_addr, + }); } }, .got_page, .got_page_off, .got_load, .got => { @@ -2093,10 +2102,12 @@ fn flush(self: *Zld) !void { var stream = std.io.fixedBufferStream(buffer); var writer = stream.writer(); + std.sort.sort(TlvOffset, self.threadlocal_offsets.items, {}, TlvOffset.cmp); + const seek_amt = 2 * @sizeOf(u64); - while (self.threadlocal_offsets.popOrNull()) |offset| { + for (self.threadlocal_offsets.items) |tlv| { try writer.context.seekBy(seek_amt); - try writer.writeIntLittle(u64, offset); + try writer.writeIntLittle(u64, tlv.offset); } try self.file.?.pwriteAll(buffer, sect.offset); diff --git a/src/link/MachO/reloc/aarch64.zig b/src/link/MachO/reloc/aarch64.zig index dbc233b3a5..c08934d84b 100644 --- a/src/link/MachO/reloc/aarch64.zig +++ b/src/link/MachO/reloc/aarch64.zig @@ -25,7 +25,7 @@ pub const Branch = struct { log.debug(" | displacement 0x{x}", .{displacement}); var inst = branch.inst; - inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement) >> 2); + inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32()); } }; diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index cf1cf81004..b34f09bc2c 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -4880,6 +4880,9 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I type_ref = get_llvm_type(g, wider_type); value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref); } + } else if (handle_is_ptr(g, type)) { + ZigType *gen_type = get_pointer_to_type(g, type, true); + type_ref = get_llvm_type(g, gen_type); } param_types[param_index] = type_ref; @@ -9302,7 +9305,6 @@ static void init(CodeGen *g) { char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref); LLVMSetDataLayout(g->module, layout_str); - assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref)); g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp index d57277cd51..f152f245b7 100644 --- a/src/stage1/parser.cpp +++ b/src/stage1/parser.cpp @@ -825,7 +825,16 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { AstNode *return_type = nullptr; if (anytype == nullptr) { exmark = eat_token_if(pc, TokenIdBang); - return_type = ast_expect(pc, ast_parse_type_expr); + return_type = ast_parse_type_expr(pc); + if (return_type == nullptr) { + Token *next = peek_token(pc); + ast_error( + pc, + next, + "expected return type (use 'void' to return nothing), found: '%s'", + token_name(next->id) + ); + } } AstNode *res = ast_create_node(pc, NodeTypeFnProto, first); diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 3ef147746c..49d32ed061 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -142,6 +142,7 @@ fn alignedBig() align(16) i32 { test "@alignCast functions" { // function alignment is a compile error on wasm32/wasm64 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + if (native_arch == .thumb) return error.SkipZigTest; expect(fnExpectsOnly1(simple4) == 0x19); } @@ -158,6 +159,7 @@ fn simple4() align(4) i32 { test "generic function with align param" { // function alignment is a compile error on wasm32/wasm64 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + if (native_arch == .thumb) return error.SkipZigTest; expect(whyWouldYouEverDoThis(1) == 0x1); expect(whyWouldYouEverDoThis(4) == 0x1); @@ -339,6 +341,7 @@ test "align(@alignOf(T)) T does not force resolution of T" { test "align(N) on functions" { // function alignment is a compile error on wasm32/wasm64 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + if (native_arch == .thumb) return error.SkipZigTest; expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0); } diff --git a/test/behavior/asm.zig b/test/behavior/asm.zig index 170ad3325d..ade774910d 100644 --- a/test/behavior/asm.zig +++ b/test/behavior/asm.zig @@ -87,6 +87,21 @@ test "sized integer/float in asm input" { ); } +test "struct/array/union types as input values" { + asm volatile ("" + : + : [_] "m" (@as([1]u32, undefined)) + ); // fails + asm volatile ("" + : + : [_] "m" (@as(struct { x: u32, y: u8 }, undefined)) + ); // fails + asm volatile ("" + : + : [_] "m" (@as(union { x: u32, y: u8 }, undefined)) + ); // fails +} + extern fn this_is_my_alias() i32; export fn derp() i32 { diff --git a/test/behavior/async_fn.zig b/test/behavior/async_fn.zig index 0765eac7e8..d451f6274c 100644 --- a/test/behavior/async_fn.zig +++ b/test/behavior/async_fn.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const builtin = std.builtin; +const builtin = @import("builtin"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const expectEqualStrings = std.testing.expectEqualStrings; @@ -110,6 +110,9 @@ test "calling an inferred async function" { } test "@frameSize" { + if (builtin.target.cpu.arch == .thumb or builtin.target.cpu.arch == .thumbeb) + return error.SkipZigTest; + const S = struct { fn doTheTest() void { { diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index b1fd2b3001..6103a40a3a 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -149,12 +149,10 @@ fn testAtomicStore() void { } test "atomicrmw with floats" { - if (builtin.target.cpu.arch == .aarch64 or - builtin.target.cpu.arch == .arm or - builtin.target.cpu.arch == .riscv64) - { + switch (builtin.target.cpu.arch) { // https://github.com/ziglang/zig/issues/4457 - return error.SkipZigTest; + .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest, + else => {}, } testAtomicRmwFloat(); comptime testAtomicRmwFloat(); diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 5035a824c7..adee221959 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -510,21 +510,6 @@ test "vector reduce operation" { const N = @typeInfo(@TypeOf(x)).Array.len; const TX = @typeInfo(@TypeOf(x)).Array.child; - // wasmtime: unknown import: `env::fminf` has not been defined - // https://github.com/ziglang/zig/issues/8131 - switch (builtin.target.cpu.arch) { - .wasm32 => switch (@typeInfo(TX)) { - .Float => switch (op) { - .Min, - .Max, - => return, - else => {}, - }, - else => {}, - }, - else => {}, - } - var r = @reduce(op, @as(Vector(N, TX), x)); switch (@typeInfo(TX)) { .Int, .Bool => expectEqual(expected, r), |
