authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-25 05:50:30-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-26 04:19:55-07:00
loga1f6a8ef90f0778e4fc5d314eeb1f0a0a93fa53a
tree7b8cefb2e4cd68db0dd1e3711e42048d6763efb8
parentb533e848a288bcf91da2720dc2646b88225642e9
signaturelock-open Commit is signed but in an unrecognized format.

riscv: airAsm rewrite

with this rewrite we can call functions inside of inline assembly, enabling us to use the default start.zig logic all that's left is to implement lr/sc loops for atomically manipulating 1 and 2 byte values, after which we can use the segfault handler logic.

12 files changed, 373 insertions(+), 150 deletions(-)

lib/std/start.zig+9-44
...@@ -20,8 +20,7 @@ pub const simplified_logic =...@@ -20,8 +20,7 @@ pub const simplified_logic =
20 builtin.zig_backend == .stage2_arm or20 builtin.zig_backend == .stage2_arm or
21 builtin.zig_backend == .stage2_sparc64 or21 builtin.zig_backend == .stage2_sparc64 or
22 builtin.cpu.arch == .spirv32 or22 builtin.cpu.arch == .spirv32 or
23 builtin.cpu.arch == .spirv64 or23 builtin.cpu.arch == .spirv64;
24 builtin.zig_backend == .stage2_riscv64;
2524
26comptime {25comptime {
27 // No matter what, we import the root file, so that any export, test, comptime26 // No matter what, we import the root file, so that any export, test, comptime
...@@ -41,10 +40,6 @@ comptime {...@@ -41,10 +40,6 @@ comptime {
41 } else if (builtin.os.tag == .opencl) {40 } else if (builtin.os.tag == .opencl) {
42 if (@hasDecl(root, "main"))41 if (@hasDecl(root, "main"))
43 @export(spirvMain2, .{ .name = "main" });42 @export(spirvMain2, .{ .name = "main" });
44 } else if (native_arch.isRISCV()) {
45 if (!@hasDecl(root, "_start")) {
46 @export(riscv_start, .{ .name = "_start" });
47 }
48 } else {43 } else {
49 if (!@hasDecl(root, "_start")) {44 if (!@hasDecl(root, "_start")) {
50 @export(_start2, .{ .name = "_start" });45 @export(_start2, .{ .name = "_start" });
...@@ -206,42 +201,6 @@ fn wasi_start() callconv(.C) void {...@@ -206,42 +201,6 @@ fn wasi_start() callconv(.C) void {
206 }201 }
207}202}
208203
209fn riscv_start() callconv(.C) noreturn {
210 std.process.exit(switch (@typeInfo(@typeInfo(@TypeOf(root.main)).Fn.return_type.?)) {
211 .NoReturn => root.main(),
212 .Void => ret: {
213 root.main();
214 break :ret 0;
215 },
216 .Int => |info| ret: {
217 if (info.bits != 8 or info.signedness == .signed) {
218 @compileError(bad_main_ret);
219 }
220 break :ret root.main();
221 },
222 .ErrorUnion => ret: {
223 const result = root.main() catch {
224 const stderr = std.io.getStdErr().writer();
225 stderr.writeAll("failed with error\n") catch {
226 @panic("failed to print when main returned error");
227 };
228 break :ret 1;
229 };
230 switch (@typeInfo(@TypeOf(result))) {
231 .Void => break :ret 0,
232 .Int => |info| {
233 if (info.bits != 8 or info.signedness == .signed) {
234 @compileError(bad_main_ret);
235 }
236 return result;
237 },
238 else => @compileError(bad_main_ret),
239 }
240 },
241 else => @compileError(bad_main_ret),
242 });
243}
244
245fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize {204fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize {
246 uefi.handle = handle;205 uefi.handle = handle;
247 uefi.system_table = system_table;206 uefi.system_table = system_table;
...@@ -519,8 +478,10 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {...@@ -519,8 +478,10 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
519 std.os.argv = argv[0..argc];478 std.os.argv = argv[0..argc];
520 std.os.environ = envp;479 std.os.environ = envp;
521480
522 std.debug.maybeEnableSegfaultHandler();481 if (builtin.zig_backend != .stage2_riscv64) {
523 maybeIgnoreSigpipe();482 std.debug.maybeEnableSegfaultHandler();
483 maybeIgnoreSigpipe();
484 }
524485
525 return callMain();486 return callMain();
526}487}
...@@ -563,6 +524,10 @@ pub inline fn callMain() u8 {...@@ -563,6 +524,10 @@ pub inline fn callMain() u8 {
563 if (@typeInfo(ReturnType) != .ErrorUnion) @compileError(bad_main_ret);524 if (@typeInfo(ReturnType) != .ErrorUnion) @compileError(bad_main_ret);
564525
565 const result = root.main() catch |err| {526 const result = root.main() catch |err| {
527 if (builtin.zig_backend == .stage2_riscv64) {
528 std.debug.print("error: failed with error\n", .{});
529 return 1;
530 }
566 std.log.err("{s}", .{@errorName(err)});531 std.log.err("{s}", .{@errorName(err)});
567 if (@errorReturnTrace()) |trace| {532 if (@errorReturnTrace()) |trace| {
568 std.debug.dumpStackTrace(trace.*);533 std.debug.dumpStackTrace(trace.*);
src/arch/riscv64/CodeGen.zig+353-84
...@@ -20,7 +20,6 @@ const InternPool = @import("../../InternPool.zig");...@@ -20,7 +20,6 @@ const InternPool = @import("../../InternPool.zig");
20const Compilation = @import("../../Compilation.zig");20const Compilation = @import("../../Compilation.zig");
21const trace = @import("../../tracy.zig").trace;21const trace = @import("../../tracy.zig").trace;
22const codegen = @import("../../codegen.zig");22const codegen = @import("../../codegen.zig");
23const Mnemonic = @import("mnem.zig").Mnemonic;
2423
25const ErrorMsg = Zcu.ErrorMsg;24const ErrorMsg = Zcu.ErrorMsg;
26const Target = std.Target;25const Target = std.Target;
...@@ -38,6 +37,10 @@ const DebugInfoOutput = codegen.DebugInfoOutput;...@@ -38,6 +37,10 @@ const DebugInfoOutput = codegen.DebugInfoOutput;
38const bits = @import("bits.zig");37const bits = @import("bits.zig");
39const abi = @import("abi.zig");38const abi = @import("abi.zig");
40const Lower = @import("Lower.zig");39const Lower = @import("Lower.zig");
40const mnem_import = @import("mnem.zig");
41const Mnemonic = mnem_import.Mnemonic;
42const Pseudo = mnem_import.Pseudo;
43const encoding = @import("encoding.zig");
4144
42const Register = bits.Register;45const Register = bits.Register;
43const CSR = bits.CSR;46const CSR = bits.CSR;
...@@ -46,6 +49,7 @@ const Memory = bits.Memory;...@@ -46,6 +49,7 @@ const Memory = bits.Memory;
46const FrameIndex = bits.FrameIndex;49const FrameIndex = bits.FrameIndex;
47const RegisterManager = abi.RegisterManager;50const RegisterManager = abi.RegisterManager;
48const RegisterLock = RegisterManager.RegisterLock;51const RegisterLock = RegisterManager.RegisterLock;
52const Instruction = encoding.Instruction;
4953
50const InnerError = CodeGenError || error{OutOfRegisters};54const InnerError = CodeGenError || error{OutOfRegisters};
5155
...@@ -3858,8 +3862,55 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3858,8 +3862,55 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
38583862
3859fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {3863fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
3860 const is_volatile = false; // TODO3864 const is_volatile = false; // TODO
3865 const pt = func.pt;
3866 const zcu = pt.zcu;
3861 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3867 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3862 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_elem_val for {}", .{func.target.cpu.arch});3868 const base_ptr_ty = func.typeOf(bin_op.lhs);
3869
3870 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {
3871 const elem_ty = base_ptr_ty.elemType2(zcu);
3872 if (!elem_ty.hasRuntimeBitsIgnoreComptime(pt)) break :result .none;
3873
3874 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);
3875 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
3876 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3877 else => null,
3878 };
3879 defer if (base_ptr_lock) |lock| func.register_manager.unlockReg(lock);
3880
3881 const index_mcv = try func.resolveInst(bin_op.rhs);
3882 const index_lock: ?RegisterLock = switch (index_mcv) {
3883 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3884 else => null,
3885 };
3886 defer if (index_lock) |lock| func.register_manager.unlockReg(lock);
3887
3888 const elem_ptr_reg = if (base_ptr_mcv.isRegister() and func.liveness.operandDies(inst, 0))
3889 base_ptr_mcv.register
3890 else
3891 try func.copyToTmpRegister(base_ptr_ty, base_ptr_mcv);
3892 const elem_ptr_lock = func.register_manager.lockRegAssumeUnused(elem_ptr_reg);
3893 defer func.register_manager.unlockReg(elem_ptr_lock);
3894
3895 try func.genBinOp(
3896 .ptr_add,
3897 base_ptr_mcv,
3898 base_ptr_ty,
3899 index_mcv,
3900 Type.u64,
3901 elem_ptr_reg,
3902 );
3903
3904 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
3905 const dst_lock = switch (dst_mcv) {
3906 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3907 else => null,
3908 };
3909 defer if (dst_lock) |lock| func.register_manager.unlockReg(lock);
3910
3911 try func.load(dst_mcv, .{ .register = elem_ptr_reg }, base_ptr_ty);
3912 break :result dst_mcv;
3913 };
3863 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });3914 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3864}3915}
38653916
...@@ -3873,13 +3924,6 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3873,13 +3924,6 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
3873 const elem_ptr_ty = func.typeOfIndex(inst);3924 const elem_ptr_ty = func.typeOfIndex(inst);
3874 const base_ptr_ty = func.typeOf(extra.lhs);3925 const base_ptr_ty = func.typeOf(extra.lhs);
38753926
3876 const base_ptr_mcv = try func.resolveInst(extra.lhs);
3877 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
3878 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3879 else => null,
3880 };
3881 defer if (base_ptr_lock) |lock| func.register_manager.unlockReg(lock);
3882
3883 if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {3927 if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {
3884 // break :result if (func.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv))3928 // break :result if (func.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv))
3885 // base_ptr_mcv3929 // base_ptr_mcv
...@@ -3888,6 +3932,13 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3888,6 +3932,13 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
3888 @panic("audit");3932 @panic("audit");
3889 }3933 }
38903934
3935 const base_ptr_mcv = try func.resolveInst(extra.lhs);
3936 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
3937 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3938 else => null,
3939 };
3940 defer if (base_ptr_lock) |lock| func.register_manager.unlockReg(lock);
3941
3891 const index_mcv = try func.resolveInst(extra.rhs);3942 const index_mcv = try func.resolveInst(extra.rhs);
3892 const index_lock: ?RegisterLock = switch (index_mcv) {3943 const index_lock: ?RegisterLock = switch (index_mcv) {
3893 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),3944 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
...@@ -4392,15 +4443,16 @@ fn airStore(func: *Func, inst: Air.Inst.Index, safety: bool) !void {...@@ -4392,15 +4443,16 @@ fn airStore(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
4392 const ptr = try func.resolveInst(bin_op.lhs);4443 const ptr = try func.resolveInst(bin_op.lhs);
4393 const value = try func.resolveInst(bin_op.rhs);4444 const value = try func.resolveInst(bin_op.rhs);
4394 const ptr_ty = func.typeOf(bin_op.lhs);4445 const ptr_ty = func.typeOf(bin_op.lhs);
4395 const value_ty = func.typeOf(bin_op.rhs);
43964446
4397 try func.store(ptr, value, ptr_ty, value_ty);4447 try func.store(ptr, value, ptr_ty);
43984448
4399 return func.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });4449 return func.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
4400}4450}
44014451
4402/// Loads `value` into the "payload" of `pointer`.4452/// Loads `value` into the "payload" of `pointer`.
4403fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty: Type) !void {4453fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type) !void {
4454 const zcu = func.pt.zcu;
4455 const src_ty = ptr_ty.childType(zcu);
4404 log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) });4456 log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) });
44054457
4406 switch (ptr_mcv) {4458 switch (ptr_mcv) {
...@@ -4429,7 +4481,7 @@ fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty:...@@ -4429,7 +4481,7 @@ fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty:
44294481
4430 try func.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);4482 try func.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
4431 },4483 },
4432 .air_ref => |ptr_ref| try func.store(try func.resolveInst(ptr_ref), src_mcv, ptr_ty, src_ty),4484 .air_ref => |ptr_ref| try func.store(try func.resolveInst(ptr_ref), src_mcv, ptr_ty),
4433 }4485 }
4434}4486}
44354487
...@@ -5795,7 +5847,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {...@@ -5795,7 +5847,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
5795fn airAsm(func: *Func, inst: Air.Inst.Index) !void {5847fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
5796 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5848 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5797 const extra = func.air.extraData(Air.Asm, ty_pl.payload);5849 const extra = func.air.extraData(Air.Asm, ty_pl.payload);
5798 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
5799 const clobbers_len: u31 = @truncate(extra.data.flags);5850 const clobbers_len: u31 = @truncate(extra.data.flags);
5800 var extra_i: usize = extra.end;5851 var extra_i: usize = extra.end;
5801 const outputs: []const Air.Inst.Ref =5852 const outputs: []const Air.Inst.Ref =
...@@ -5804,86 +5855,300 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -5804,86 +5855,300 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
5804 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);5855 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);
5805 extra_i += inputs.len;5856 extra_i += inputs.len;
58065857
5807 const dead = !is_volatile and func.liveness.isUnused(inst);5858 var result: MCValue = .none;
5808 const result: MCValue = if (dead) .unreach else result: {5859 var args = std.ArrayList(MCValue).init(func.gpa);
5809 if (outputs.len > 1) {5860 try args.ensureTotalCapacity(outputs.len + inputs.len);
5810 return func.fail("TODO implement codegen for asm with more than 1 output", .{});5861 defer {
5811 }5862 for (args.items) |arg| if (arg.getReg()) |reg| func.register_manager.unlockReg(.{
58125863 .tracked_index = RegisterManager.indexOfRegIntoTracked(reg) orelse continue,
5813 const output_constraint: ?[]const u8 = for (outputs) |output| {5864 });
5814 if (output != .none) {5865 args.deinit();
5815 return func.fail("TODO implement codegen for non-expr asm", .{});5866 }
5816 }5867 var arg_map = std.StringHashMap(u8).init(func.gpa);
5817 const extra_bytes = std.mem.sliceAsBytes(func.air.extra[extra_i..]);5868 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
5818 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);5869 defer arg_map.deinit();
5819 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);5870
5820 // This equation accounts for the fact that even if we have exactly 4 bytes5871 var outputs_extra_i = extra_i;
5821 // for the string, we still use the next u32 for the null terminator.5872 for (outputs) |output| {
5822 extra_i += (constraint.len + name.len + (2 + 3)) / 4;5873 const extra_bytes = mem.sliceAsBytes(func.air.extra[extra_i..]);
5874 const constraint = mem.sliceTo(mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
5875 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5876 // This equation accounts for the fact that even if we have exactly 4 bytes
5877 // for the string, we still use the next u32 for the null terminator.
5878 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5879
5880 const is_read = switch (constraint[0]) {
5881 '=' => false,
5882 '+' => read: {
5883 if (output == .none) return func.fail(
5884 "read-write constraint unsupported for asm result: '{s}'",
5885 .{constraint},
5886 );
5887 break :read true;
5888 },
5889 else => return func.fail("invalid constraint: '{s}'", .{constraint}),
5890 };
5891 const is_early_clobber = constraint[1] == '&';
5892 const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];
5893 const arg_mcv: MCValue = arg_mcv: {
5894 const arg_maybe_reg: ?Register = if (mem.eql(u8, rest, "m"))
5895 if (output != .none) null else return func.fail(
5896 "memory constraint unsupported for asm result: '{s}'",
5897 .{constraint},
5898 )
5899 else if (mem.startsWith(u8, rest, "{") and mem.endsWith(u8, rest, "}"))
5900 parseRegName(rest["{".len .. rest.len - "}".len]) orelse
5901 return func.fail("invalid register constraint: '{s}'", .{constraint})
5902 else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {
5903 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;
5904 if (index >= args.items.len) return func.fail("constraint out of bounds: '{s}'", .{
5905 constraint,
5906 });
5907 break :arg_mcv args.items[index];
5908 } else return func.fail("invalid constraint: '{s}'", .{constraint});
5909 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
5910 const ptr_mcv = try func.resolveInst(output);
5911 switch (ptr_mcv) {
5912 .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
5913 break :arg ptr_mcv.deref(),
5914 .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(),
5915 else => {},
5916 }
5917 break :arg .{ .indirect = .{ .reg = try func.copyToTmpRegister(Type.usize, ptr_mcv) } };
5918 };
5919 };
5920 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
5921 _ = func.register_manager.lockReg(reg);
5922 };
5923 if (!mem.eql(u8, name, "_"))
5924 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
5925 args.appendAssumeCapacity(arg_mcv);
5926 if (output == .none) result = arg_mcv;
5927 if (is_read) try func.load(arg_mcv, .{ .air_ref = output }, func.typeOf(output));
5928 }
58235929
5824 break constraint;5930 for (inputs) |input| {
5825 } else null;5931 const input_bytes = mem.sliceAsBytes(func.air.extra[extra_i..]);
5932 const constraint = mem.sliceTo(input_bytes, 0);
5933 const name = mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
5934 // This equation accounts for the fact that even if we have exactly 4 bytes
5935 // for the string, we still use the next u32 for the null terminator.
5936 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5937
5938 const ty = func.typeOf(input);
5939 const input_mcv = try func.resolveInst(input);
5940 const arg_mcv: MCValue = if (mem.eql(u8, constraint, "X"))
5941 input_mcv
5942 else if (mem.startsWith(u8, constraint, "{") and mem.endsWith(u8, constraint, "}")) arg: {
5943 const reg = parseRegName(constraint["{".len .. constraint.len - "}".len]) orelse
5944 return func.fail("invalid register constraint: '{s}'", .{constraint});
5945 try func.register_manager.getReg(reg, null);
5946 try func.genSetReg(ty, reg, input_mcv);
5947 break :arg .{ .register = reg };
5948 } else return func.fail("invalid constraint: '{s}'", .{constraint});
5949 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
5950 _ = func.register_manager.lockReg(reg);
5951 };
5952 if (!mem.eql(u8, name, "_"))
5953 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
5954 args.appendAssumeCapacity(arg_mcv);
5955 }
58265956
5827 for (inputs) |input| {5957 {
5828 const input_bytes = std.mem.sliceAsBytes(func.air.extra[extra_i..]);5958 var clobber_i: u32 = 0;
5829 const constraint = std.mem.sliceTo(input_bytes, 0);5959 while (clobber_i < clobbers_len) : (clobber_i += 1) {
5830 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);5960 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
5831 // This equation accounts for the fact that even if we have exactly 4 bytes5961 // This equation accounts for the fact that even if we have exactly 4 bytes
5832 // for the string, we still use the next u32 for the null terminator.5962 // for the string, we still use the next u32 for the null terminator.
5833 extra_i += (constraint.len + name.len + (2 + 3)) / 4;5963 extra_i += clobber.len / 4 + 1;
58345964
5835 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {5965 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
5836 return func.fail("unrecognized asm input constraint: '{s}'", .{constraint});5966 // nothing really to do
5967 } else {
5968 try func.register_manager.getReg(parseRegName(clobber) orelse
5969 return func.fail("invalid clobber: '{s}'", .{clobber}), null);
5837 }5970 }
5838 const reg_name = constraint[1 .. constraint.len - 1];
5839 const reg = parseRegName(reg_name) orelse
5840 return func.fail("unrecognized register: '{s}'", .{reg_name});
5841
5842 const arg_mcv = try func.resolveInst(input);
5843 try func.register_manager.getReg(reg, null);
5844 try func.genSetReg(func.typeOf(input), reg, arg_mcv);
5845 }5971 }
5972 }
58465973
5847 {5974 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];
5848 var clobber_i: u32 = 0;5975 var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");
5849 while (clobber_i < clobbers_len) : (clobber_i += 1) {5976 next_line: while (line_it.next()) |line| {
5850 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);5977 var mnem_it = mem.tokenizeAny(u8, line, " \t");
5851 // This equation accounts for the fact that even if we have exactly 4 bytes5978 const instruction: union(enum) { mnem: Mnemonic, pseudo: Pseudo } = while (mnem_it.next()) |mnem_str| {
5852 // for the string, we still use the next u32 for the null terminator.5979 if (mem.startsWith(u8, mnem_str, "#")) continue :next_line;
5853 extra_i += clobber.len / 4 + 1;5980 if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;
5981 if (std.meta.stringToEnum(Mnemonic, mnem_str)) |mnem| {
5982 break .{ .mnem = mnem };
5983 } else if (std.meta.stringToEnum(Pseudo, mnem_str)) |pseudo| {
5984 break .{ .pseudo = pseudo };
5985 } else return func.fail("TODO: airAsm labels, found '{s}'", .{mnem_str});
5986 } else continue;
5987
5988 const Operand = union(enum) {
5989 none,
5990 reg: Register,
5991 imm: Immediate,
5992 sym: SymbolOffset,
5993 };
58545994
5855 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {5995 var ops: [4]Operand = .{.none} ** 4;
5856 // nothing really to do5996 var last_op = false;
5857 } else {5997 var op_it = mem.splitScalar(u8, mnem_it.rest(), ',');
5858 try func.register_manager.getReg(parseRegName(clobber) orelse5998 next_op: for (&ops) |*op| {
5859 return func.fail("invalid clobber: '{s}'", .{clobber}), null);5999 const op_str = while (!last_op) {
5860 }6000 const full_str = op_it.next() orelse break :next_op;
5861 }6001 const code_str = if (mem.indexOfScalar(u8, full_str, '#') orelse
5862 }6002 mem.indexOf(u8, full_str, "//")) |comment|
6003 code: {
6004 last_op = true;
6005 break :code full_str[0..comment];
6006 } else full_str;
6007 const trim_str = mem.trim(u8, code_str, " \t*");
6008 if (trim_str.len > 0) break trim_str;
6009 } else break;
6010
6011 if (parseRegName(op_str)) |reg| {
6012 op.* = .{ .reg = reg };
6013 } else if (std.fmt.parseInt(i12, op_str, 10)) |int| {
6014 op.* = .{ .imm = Immediate.s(int) };
6015 } else |_| if (mem.startsWith(u8, op_str, "%[")) {
6016 const mod_index = mem.indexOf(u8, op_str, "]@");
6017 const modifier = if (mod_index) |index|
6018 op_str[index + "]@".len ..]
6019 else
6020 "";
6021
6022 op.* = switch (args.items[
6023 arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse
6024 return func.fail("no matching constraint: '{s}'", .{op_str})
6025 ]) {
6026 .load_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: {
6027 assert(sym_off.off == 0);
6028 break :blk .{ .sym = sym_off };
6029 } else return func.fail("invalid modifier: '{s}'", .{modifier}),
6030 else => return func.fail("invalid constraint: '{s}'", .{op_str}),
6031 };
6032 } else return func.fail("invalid operand: '{s}'", .{op_str});
6033 } else if (op_it.next()) |op_str| return func.fail("extra operand: '{s}'", .{op_str});
58636034
5864 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];6035 switch (instruction) {
6036 .mnem => |mnem| {
6037 _ = (switch (ops[0]) {
6038 .none => try func.addInst(.{
6039 .tag = mnem,
6040 .data = .none,
6041 }),
6042 .reg => |reg1| switch (ops[1]) {
6043 .reg => |reg2| switch (ops[2]) {
6044 .imm => |imm1| try func.addInst(.{
6045 .tag = mnem,
6046 .data = .{ .i_type = .{
6047 .rd = reg1,
6048 .rs1 = reg2,
6049 .imm12 = imm1,
6050 } },
6051 }),
6052 else => error.InvalidInstruction,
6053 },
6054 else => error.InvalidInstruction,
6055 },
6056 else => error.InvalidInstruction,
6057 }) catch |err| {
6058 switch (err) {
6059 error.InvalidInstruction => return func.fail(
6060 "invalid instruction: {s} {s} {s} {s} {s}",
6061 .{
6062 @tagName(mnem),
6063 @tagName(ops[0]),
6064 @tagName(ops[1]),
6065 @tagName(ops[2]),
6066 @tagName(ops[3]),
6067 },
6068 ),
6069 else => |e| return e,
6070 }
6071 };
6072 },
6073 .pseudo => |pseudo| {
6074 (@as(error{InvalidInstruction}!void, switch (pseudo) {
6075 .li => blk: {
6076 if (ops[0] != .reg or ops[1] != .imm) {
6077 break :blk error.InvalidInstruction;
6078 }
58656079
5866 if (std.meta.stringToEnum(Mnemonic, asm_source)) |tag| {6080 const reg = ops[0].reg;
5867 _ = try func.addInst(.{6081 const imm = ops[1].imm;
5868 .tag = tag,
5869 .data = .none,
5870 });
5871 } else {
5872 return func.fail("TODO: asm_source {s}", .{asm_source});
5873 }
58746082
5875 if (output_constraint) |output| {6083 try func.genSetReg(Type.usize, reg, .{ .immediate = imm.asBits(u64) });
5876 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {6084 },
5877 return func.fail("unrecognized asm output constraint: '{s}'", .{output});6085 .mv => blk: {
5878 }6086 if (ops[0] != .reg or ops[1] != .reg) {
5879 const reg_name = output[2 .. output.len - 1];6087 break :blk error.InvalidInstruction;
5880 const reg = parseRegName(reg_name) orelse6088 }
5881 return func.fail("unrecognized register: '{s}'", .{reg_name});6089
5882 break :result .{ .register = reg };6090 const dst = ops[0].reg;
5883 } else {6091 const src = ops[1].reg;
5884 break :result .{ .none = {} };6092
6093 if (dst.class() != .int or src.class() != .int) {
6094 return func.fail("pseudo instruction 'mv' only works on integer registers", .{});
6095 }
6096
6097 try func.genSetReg(Type.usize, dst, .{ .register = src });
6098 },
6099 .tail => blk: {
6100 if (ops[0] != .sym) {
6101 break :blk error.InvalidInstruction;
6102 }
6103
6104 const sym_offset = ops[0].sym;
6105 assert(sym_offset.off == 0);
6106
6107 const random_link_reg, const lock = try func.allocReg(.int);
6108 defer func.register_manager.unlockReg(lock);
6109
6110 _ = try func.addInst(.{
6111 .tag = .pseudo_extern_fn_reloc,
6112 .data = .{ .reloc = .{
6113 .register = random_link_reg,
6114 .atom_index = try func.owner.getSymbolIndex(func),
6115 .sym_index = sym_offset.sym,
6116 } },
6117 });
6118 },
6119 })) catch |err| {
6120 switch (err) {
6121 error.InvalidInstruction => return func.fail(
6122 "invalid instruction: {s} {s} {s} {s} {s}",
6123 .{
6124 @tagName(pseudo),
6125 @tagName(ops[0]),
6126 @tagName(ops[1]),
6127 @tagName(ops[2]),
6128 @tagName(ops[3]),
6129 },
6130 ),
6131 else => |e| return e,
6132 }
6133 };
6134 },
5885 }6135 }
5886 };6136 }
6137
6138 for (outputs, args.items[0..outputs.len]) |output, arg_mcv| {
6139 const extra_bytes = mem.sliceAsBytes(func.air.extra[outputs_extra_i..]);
6140 const constraint =
6141 mem.sliceTo(mem.sliceAsBytes(func.air.extra[outputs_extra_i..]), 0);
6142 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
6143 // This equation accounts for the fact that even if we have exactly 4 bytes
6144 // for the string, we still use the next u32 for the null terminator.
6145 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
6146
6147 if (output == .none) continue;
6148 if (arg_mcv != .register) continue;
6149 if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;
6150 try func.store(.{ .air_ref = output }, arg_mcv, func.typeOf(output));
6151 }
58876152
5888 simple: {6153 simple: {
5889 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);6154 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
...@@ -6867,7 +7132,7 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {...@@ -6867,7 +7132,7 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
6867 }7132 }
68687133
6869 switch (val_size) {7134 switch (val_size) {
6870 1, 2 => return func.fail("TODO: airAtomicRmw Int {}", .{val_size}),7135 1, 2 => return func.fail("TODO: airAtomicRmw {s} Int {}", .{ @tagName(op), val_size }),
6871 4, 8 => {},7136 4, 8 => {},
6872 else => unreachable,7137 else => unreachable,
6873 }7138 }
...@@ -6997,7 +7262,7 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr...@@ -6997,7 +7262,7 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr
6997 else => unreachable,7262 else => unreachable,
6998 }7263 }
69997264
7000 try func.store(ptr_mcv, val_mcv, ptr_ty, val_ty);7265 try func.store(ptr_mcv, val_mcv, ptr_ty);
7001 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });7266 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
7002}7267}
70037268
...@@ -7061,7 +7326,7 @@ fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {...@@ -7061,7 +7326,7 @@ fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
7061 const len = dst_ptr_ty.childType(zcu).arrayLen(zcu);7326 const len = dst_ptr_ty.childType(zcu).arrayLen(zcu);
70627327
7063 assert(len != 0); // prevented by Sema7328 assert(len != 0); // prevented by Sema
7064 try func.store(dst_ptr, src_val, elem_ptr_ty, elem_ty);7329 try func.store(dst_ptr, src_val, elem_ptr_ty);
70657330
7066 const second_elem_ptr_reg, const second_elem_ptr_lock = try func.allocReg(.int);7331 const second_elem_ptr_reg, const second_elem_ptr_lock = try func.allocReg(.int);
7067 defer func.register_manager.unlockReg(second_elem_ptr_lock);7332 defer func.register_manager.unlockReg(second_elem_ptr_lock);
...@@ -7108,6 +7373,10 @@ fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void {...@@ -7108,6 +7373,10 @@ fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void {
7108 );7373 );
7109 break :len .{ .register = len_reg };7374 break :len .{ .register = len_reg };
7110 },7375 },
7376 .One => len: {
7377 const array_ty = dst_ty.childType(zcu);
7378 break :len .{ .immediate = array_ty.arrayLen(zcu) * array_ty.childType(zcu).abiSize(pt) };
7379 },
7111 else => |size| return func.fail("TODO: airMemcpy size {s}", .{@tagName(size)}),7380 else => |size| return func.fail("TODO: airMemcpy size {s}", .{@tagName(size)}),
7112 };7381 };
7113 const len_lock: ?RegisterLock = switch (len_mcv) {7382 const len_lock: ?RegisterLock = switch (len_mcv) {
src/arch/riscv64/Lower.zig+5-4
...@@ -428,9 +428,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {...@@ -428,9 +428,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
428428
429 .pseudo_extern_fn_reloc => {429 .pseudo_extern_fn_reloc => {
430 const inst_reloc = inst.data.reloc;430 const inst_reloc = inst.data.reloc;
431 const link_reg = inst_reloc.register;
431432
432 try lower.emit(.auipc, &.{433 try lower.emit(.auipc, &.{
433 .{ .reg = .ra },434 .{ .reg = link_reg },
434 .{ .imm = lower.reloc(435 .{ .imm = lower.reloc(
435 .{ .call_extern_fn_reloc = .{436 .{ .call_extern_fn_reloc = .{
436 .atom_index = inst_reloc.atom_index,437 .atom_index = inst_reloc.atom_index,
...@@ -440,8 +441,8 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {...@@ -440,8 +441,8 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
440 });441 });
441442
442 try lower.emit(.jalr, &.{443 try lower.emit(.jalr, &.{
443 .{ .reg = .ra },444 .{ .reg = link_reg },
444 .{ .reg = .ra },445 .{ .reg = link_reg },
445 .{ .imm = Immediate.s(0) },446 .{ .imm = Immediate.s(0) },
446 });447 });
447 },448 },
...@@ -523,7 +524,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -523,7 +524,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
523 .{ .reg = csr.rs1 },524 .{ .reg = csr.rs1 },
524 .{ .reg = csr.rd },525 .{ .reg = csr.rd },
525 },526 },
526 else => return lower.fail("TODO: generic lower {s}", .{@tagName(mnemonic)}),527 else => return lower.fail("TODO: generic lower {s}", .{@tagName(inst.data)}),
527 });528 });
528}529}
529530
src/arch/riscv64/mnem.zig+6
...@@ -240,3 +240,9 @@ pub const Mnemonic = enum(u16) {...@@ -240,3 +240,9 @@ pub const Mnemonic = enum(u16) {
240 pseudo_fence,240 pseudo_fence,
241 pseudo_amo,241 pseudo_amo,
242};242};
243
244pub const Pseudo = enum(u8) {
245 li,
246 mv,
247 tail,
248};
test/behavior/basic.zig-4
...@@ -395,7 +395,6 @@ test "array 2D const double ptr" {...@@ -395,7 +395,6 @@ test "array 2D const double ptr" {
395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
399398
400 const rect_2d_vertexes = [_][1]f32{399 const rect_2d_vertexes = [_][1]f32{
401 [_]f32{1.0},400 [_]f32{1.0},
...@@ -408,7 +407,6 @@ test "array 2D const double ptr with offset" {...@@ -408,7 +407,6 @@ test "array 2D const double ptr with offset" {
408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
410 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
411 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
412410
413 const rect_2d_vertexes = [_][2]f32{411 const rect_2d_vertexes = [_][2]f32{
414 [_]f32{ 3.0, 4.239 },412 [_]f32{ 3.0, 4.239 },
...@@ -421,7 +419,6 @@ test "array 3D const double ptr with offset" {...@@ -421,7 +419,6 @@ test "array 3D const double ptr with offset" {
421 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
424 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
425422
426 const rect_3d_vertexes = [_][2][2]f32{423 const rect_3d_vertexes = [_][2][2]f32{
427 [_][2]f32{424 [_][2]f32{
...@@ -634,7 +631,6 @@ test "global constant is loaded with a runtime-known index" {...@@ -634,7 +631,6 @@ test "global constant is loaded with a runtime-known index" {
634631
635test "multiline string literal is null terminated" {632test "multiline string literal is null terminated" {
636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;633 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
637 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
638634
639 const s1 =635 const s1 =
640 \\one636 \\one
test/behavior/cast.zig-6
...@@ -599,7 +599,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {...@@ -599,7 +599,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
599test "cast *[1][*]const u8 to [*]const ?[*]const u8" {599test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
601 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO601 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
602 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
603602
604 const window_name = [1][*]const u8{"window name"};603 const window_name = [1][*]const u8{"window name"};
605 const x: [*]const ?[*]const u8 = &window_name;604 const x: [*]const ?[*]const u8 = &window_name;
...@@ -953,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" {...@@ -953,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" {
953 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;952 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
954 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO953 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO954 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
957955
958 const S = struct {956 const S = struct {
959 fn doTheTest() !void {957 fn doTheTest() !void {
...@@ -1019,7 +1017,6 @@ test "variable initialization uses result locations properly with regards to the...@@ -1019,7 +1017,6 @@ test "variable initialization uses result locations properly with regards to the
1019test "cast between C pointer with different but compatible types" {1017test "cast between C pointer with different but compatible types" {
1020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1021 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1022 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10231020
1024 const S = struct {1021 const S = struct {
1025 fn foo(arg: [*]c_ushort) u16 {1022 fn foo(arg: [*]c_ushort) u16 {
...@@ -1540,7 +1537,6 @@ test "cast typed undefined to int" {...@@ -1540,7 +1537,6 @@ test "cast typed undefined to int" {
15401537
1541test "implicit cast from [:0]T to [*c]T" {1538test "implicit cast from [:0]T to [*c]T" {
1542 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1543 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15441540
1545 var a: [:0]const u8 = "foo";1541 var a: [:0]const u8 = "foo";
1546 _ = &a;1542 _ = &a;
...@@ -2086,7 +2082,6 @@ test "peer type resolution: many compatible pointers" {...@@ -2086,7 +2082,6 @@ test "peer type resolution: many compatible pointers" {
2086 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2087 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2083 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2088 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO2084 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
2089 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20902085
2091 var buf = "foo-3".*;2086 var buf = "foo-3".*;
20922087
...@@ -2208,7 +2203,6 @@ test "peer type resolution: pointer attributes are combined correctly" {...@@ -2208,7 +2203,6 @@ test "peer type resolution: pointer attributes are combined correctly" {
2208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22122206
2213 var buf_a align(4) = "foo".*;2207 var buf_a align(4) = "foo".*;
2214 var buf_b align(4) = "bar".*;2208 var buf_b align(4) = "bar".*;
test/behavior/for.zig-1
...@@ -153,7 +153,6 @@ test "for loop with pointer elem var" {...@@ -153,7 +153,6 @@ test "for loop with pointer elem var" {
153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
157156
158 const source = "abcdefg";157 const source = "abcdefg";
159 var target: [source.len]u8 = undefined;158 var target: [source.len]u8 = undefined;
test/behavior/memcpy.zig-3
...@@ -7,7 +7,6 @@ test "memcpy and memset intrinsics" {...@@ -7,7 +7,6 @@ test "memcpy and memset intrinsics" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
12 try testMemcpyMemset();11 try testMemcpyMemset();
13 try comptime testMemcpyMemset();12 try comptime testMemcpyMemset();
...@@ -29,7 +28,6 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {...@@ -29,7 +28,6 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3331
34 try testMemcpyBothSinglePtrArrayOneIsNullTerminated();32 try testMemcpyBothSinglePtrArrayOneIsNullTerminated();
35 try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated();33 try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated();
...@@ -72,7 +70,6 @@ test "@memcpy slice" {...@@ -72,7 +70,6 @@ test "@memcpy slice" {
72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7673
77 try testMemcpySlice();74 try testMemcpySlice();
78 try comptime testMemcpySlice();75 try comptime testMemcpySlice();
test/behavior/pointers.zig-1
...@@ -342,7 +342,6 @@ test "array initialization types" {...@@ -342,7 +342,6 @@ test "array initialization types" {
342test "null terminated pointer" {342test "null terminated pointer" {
343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
345 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
346345
347 const S = struct {346 const S = struct {
348 fn doTheTest() !void {347 fn doTheTest() !void {
test/behavior/struct.zig-1
...@@ -504,7 +504,6 @@ test "packed struct fields are ordered from LSB to MSB" {...@@ -504,7 +504,6 @@ test "packed struct fields are ordered from LSB to MSB" {
504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;506 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
507 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
508507
509 var all: u64 = 0x7765443322221111;508 var all: u64 = 0x7765443322221111;
510 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;509 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;
test/behavior/threadlocal.zig-1
...@@ -28,7 +28,6 @@ test "pointer to thread local array" {...@@ -28,7 +28,6 @@ test "pointer to thread local array" {
28 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {31 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {
33 .x86_64, .x86 => {},32 .x86_64, .x86 => {},
34 else => return error.SkipZigTest,33 else => return error.SkipZigTest,
test/behavior/union.zig-1
...@@ -100,7 +100,6 @@ const FooExtern = extern union {...@@ -100,7 +100,6 @@ const FooExtern = extern union {
100test "basic extern unions" {100test "basic extern unions" {
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104103
105 var foo = FooExtern{ .int = 1 };104 var foo = FooExtern{ .int = 1 };
106 try expect(foo.int == 1);105 try expect(foo.int == 1);