authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-17 08:39:44+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-17 08:39:44+02:00
log9d9b5a11e873cc15e3f1b6e506ecf22c8380c87d
treef9fbf35c57d927db32236129c8dbd24550edee7b
parentddc399440dd8bcb814c288e43a30f873bfbaca39
parent5a4fe39fbbf9668b7fa14da774cb3de1c49604e7
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20474 from Rexicon226/riscv

more RISC-V backend progress

34 files changed, 1627 insertions(+), 496 deletions(-)

lib/std/simd.zig+32-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1//! SIMD (Single Instruction; Multiple Data) convenience functions.1//! SIMD (Single Instruction; Multiple Data) convenience functions.
2//!2//!
3//! May offer a potential boost in performance on some targets by performing3//! May offer a potential boost in performance on some targets by performing
4//! the same operations on multiple elements at once.4//! the same operation on multiple elements at once.
5//!5//!
6//! Some functions are known to not work on MIPS.6//! Some functions are known to not work on MIPS.
77
...@@ -10,7 +10,6 @@ const builtin = @import("builtin");...@@ -10,7 +10,6 @@ const builtin = @import("builtin");
1010
11pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) ?comptime_int {11pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) ?comptime_int {
12 // This is guesswork, if you have better suggestions can add it or edit the current here12 // This is guesswork, if you have better suggestions can add it or edit the current here
13 // This can run in comptime only, but stage 1 fails at it, stage 2 can understand it
14 const element_bit_size = @max(8, std.math.ceilPowerOfTwo(u16, @bitSizeOf(T)) catch unreachable);13 const element_bit_size = @max(8, std.math.ceilPowerOfTwo(u16, @bitSizeOf(T)) catch unreachable);
15 const vector_bit_size: u16 = blk: {14 const vector_bit_size: u16 = blk: {
16 if (cpu.arch.isX86()) {15 if (cpu.arch.isX86()) {
...@@ -37,8 +36,37 @@ pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu)...@@ -37,8 +36,37 @@ pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu)
37 // the 2048 bits or using just 64 per vector or something in between36 // the 2048 bits or using just 64 per vector or something in between
38 if (std.Target.mips.featureSetHas(cpu.features, std.Target.mips.Feature.mips3d)) break :blk 64;37 if (std.Target.mips.featureSetHas(cpu.features, std.Target.mips.Feature.mips3d)) break :blk 64;
39 } else if (cpu.arch.isRISCV()) {38 } else if (cpu.arch.isRISCV()) {
40 // in risc-v the Vector Extension allows configurable vector sizes, but a standard size of 128 is a safe estimate39 // In RISC-V Vector Registers are length agnostic so there's no good way to determine the best size.
41 if (std.Target.riscv.featureSetHas(cpu.features, .v)) break :blk 128;40 // The usual vector length in most RISC-V cpus is 256 bits, however it can get to multiple kB.
41 if (std.Target.riscv.featureSetHas(cpu.features, .v)) {
42 var vec_bit_length: u32 = 256;
43 if (std.Target.riscv.featureSetHas(cpu.features, .zvl32b)) {
44 vec_bit_length = 32;
45 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl64b)) {
46 vec_bit_length = 64;
47 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl128b)) {
48 vec_bit_length = 128;
49 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl256b)) {
50 vec_bit_length = 256;
51 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl512b)) {
52 vec_bit_length = 512;
53 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl1024b)) {
54 vec_bit_length = 1024;
55 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl2048b)) {
56 vec_bit_length = 2048;
57 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl4096b)) {
58 vec_bit_length = 4096;
59 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl8192b)) {
60 vec_bit_length = 8192;
61 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl16384b)) {
62 vec_bit_length = 16384;
63 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl32768b)) {
64 vec_bit_length = 32768;
65 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl65536b)) {
66 vec_bit_length = 65536;
67 }
68 break :blk vec_bit_length;
69 }
42 } else if (cpu.arch.isSPARC()) {70 } else if (cpu.arch.isSPARC()) {
43 // TODO: Test Sparc capability to handle bigger vectors71 // TODO: Test Sparc capability to handle bigger vectors
44 // In theory Sparc have 32 registers of 64 bits which can use in parallel72 // In theory Sparc have 32 registers of 64 bits which can use in parallel
lib/std/start.zig+20-1
...@@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn {...@@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn {
221 }221 }
222 break :ret root.main();222 break :ret root.main();
223 },223 },
224 else => @compileError("expected return type of main to be 'void', 'noreturn', 'u8'"),224 .ErrorUnion => ret: {
225 const result = root.main() catch {
226 const stderr = std.io.getStdErr().writer();
227 stderr.writeAll("failed with error\n") catch {
228 @panic("failed to print when main returned error");
229 };
230 break :ret 1;
231 };
232 switch (@typeInfo(@TypeOf(result))) {
233 .Void => break :ret 0,
234 .Int => |info| {
235 if (info.bits != 8 or info.signedness == .signed) {
236 @compileError(bad_main_ret);
237 }
238 return result;
239 },
240 else => @compileError(bad_main_ret),
241 }
242 },
243 else => @compileError(bad_main_ret),
225 });244 });
226}245}
227246
src/arch/riscv64/CodeGen.zig+830-239
...@@ -1,8 +1,12 @@...@@ -1,8 +1,12 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const build_options = @import("build_options");
4
3const mem = std.mem;5const mem = std.mem;
4const math = std.math;6const math = std.math;
5const assert = std.debug.assert;7const assert = std.debug.assert;
8const Allocator = mem.Allocator;
9
6const Air = @import("../../Air.zig");10const Air = @import("../../Air.zig");
7const Mir = @import("Mir.zig");11const Mir = @import("Mir.zig");
8const Emit = @import("Emit.zig");12const Emit = @import("Emit.zig");
...@@ -14,18 +18,16 @@ const Zcu = @import("../../Zcu.zig");...@@ -14,18 +18,16 @@ const Zcu = @import("../../Zcu.zig");
14const Package = @import("../../Package.zig");18const Package = @import("../../Package.zig");
15const InternPool = @import("../../InternPool.zig");19const InternPool = @import("../../InternPool.zig");
16const Compilation = @import("../../Compilation.zig");20const Compilation = @import("../../Compilation.zig");
21const trace = @import("../../tracy.zig").trace;
22const codegen = @import("../../codegen.zig");
23
17const ErrorMsg = Zcu.ErrorMsg;24const ErrorMsg = Zcu.ErrorMsg;
18const Target = std.Target;25const Target = std.Target;
19const Allocator = mem.Allocator;26
20const trace = @import("../../tracy.zig").trace;
21const DW = std.dwarf;
22const leb128 = std.leb;
23const log = std.log.scoped(.riscv_codegen);27const log = std.log.scoped(.riscv_codegen);
24const tracking_log = std.log.scoped(.tracking);28const tracking_log = std.log.scoped(.tracking);
25const verbose_tracking_log = std.log.scoped(.verbose_tracking);29const verbose_tracking_log = std.log.scoped(.verbose_tracking);
26const wip_mir_log = std.log.scoped(.wip_mir);30const wip_mir_log = std.log.scoped(.wip_mir);
27const build_options = @import("build_options");
28const codegen = @import("../../codegen.zig");
29const Alignment = InternPool.Alignment;31const Alignment = InternPool.Alignment;
3032
31const CodeGenError = codegen.CodeGenError;33const CodeGenError = codegen.CodeGenError;
...@@ -37,6 +39,7 @@ const abi = @import("abi.zig");...@@ -37,6 +39,7 @@ const abi = @import("abi.zig");
37const Lower = @import("Lower.zig");39const Lower = @import("Lower.zig");
3840
39const Register = bits.Register;41const Register = bits.Register;
42const CSR = bits.CSR;
40const Immediate = bits.Immediate;43const Immediate = bits.Immediate;
41const Memory = bits.Memory;44const Memory = bits.Memory;
42const FrameIndex = bits.FrameIndex;45const FrameIndex = bits.FrameIndex;
...@@ -45,15 +48,16 @@ const RegisterLock = RegisterManager.RegisterLock;...@@ -45,15 +48,16 @@ const RegisterLock = RegisterManager.RegisterLock;
4548
46const InnerError = CodeGenError || error{OutOfRegisters};49const InnerError = CodeGenError || error{OutOfRegisters};
4750
48gpa: Allocator,
49pt: Zcu.PerThread,51pt: Zcu.PerThread,
50air: Air,52air: Air,
51mod: *Package.Module,
52liveness: Liveness,53liveness: Liveness,
54zcu: *Zcu,
53bin_file: *link.File,55bin_file: *link.File,
56gpa: Allocator,
57
58mod: *Package.Module,
54target: *const std.Target,59target: *const std.Target,
55func_index: InternPool.Index,60func_index: InternPool.Index,
56code: *std.ArrayList(u8),
57debug_output: DebugInfoOutput,61debug_output: DebugInfoOutput,
58err_msg: ?*ErrorMsg,62err_msg: ?*ErrorMsg,
59args: []MCValue,63args: []MCValue,
...@@ -62,9 +66,7 @@ fn_type: Type,...@@ -62,9 +66,7 @@ fn_type: Type,
62arg_index: usize,66arg_index: usize,
63src_loc: Zcu.LazySrcLoc,67src_loc: Zcu.LazySrcLoc,
6468
65/// MIR Instructions
66mir_instructions: std.MultiArrayList(Mir.Inst) = .{},69mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
67/// MIR extra data
68mir_extra: std.ArrayListUnmanaged(u32) = .{},70mir_extra: std.ArrayListUnmanaged(u32) = .{},
6971
70/// Byte offset within the source file of the ending curly.72/// Byte offset within the source file of the ending curly.
...@@ -87,6 +89,10 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},...@@ -87,6 +89,10 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},
87/// across each runtime branch upon joining.89/// across each runtime branch upon joining.
88branch_stack: *std.ArrayList(Branch),90branch_stack: *std.ArrayList(Branch),
8991
92// Currently set vector properties, null means they haven't been set yet in the function.
93avl: ?u64,
94vtype: ?bits.VType,
95
90// Key is the block instruction96// Key is the block instruction
91blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},97blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
92register_manager: RegisterManager = .{},98register_manager: RegisterManager = .{},
...@@ -117,8 +123,9 @@ const MCValue = union(enum) {...@@ -117,8 +123,9 @@ const MCValue = union(enum) {
117 /// No more references to this value remain.123 /// No more references to this value remain.
118 /// The payload is the value of scope_generation at the point where the death occurred124 /// The payload is the value of scope_generation at the point where the death occurred
119 dead: u32,125 dead: u32,
120 /// The value is undefined.126 /// The value is undefined. Contains a symbol index to an undefined constant. Null means
121 undef,127 /// set the undefined value via immediate instead of a load.
128 undef: ?u32,
122 /// A pointer-sized integer that fits in a register.129 /// A pointer-sized integer that fits in a register.
123 /// If the type is a pointer, this is the pointer address in virtual address space.130 /// If the type is a pointer, this is the pointer address in virtual address space.
124 immediate: u64,131 immediate: u64,
...@@ -725,16 +732,16 @@ pub fn generate(...@@ -725,16 +732,16 @@ pub fn generate(
725 }732 }
726 try branch_stack.append(.{});733 try branch_stack.append(.{});
727734
728 var function = Func{735 var function: Func = .{
729 .gpa = gpa,736 .gpa = gpa,
730 .air = air,737 .air = air,
731 .pt = pt,738 .pt = pt,
732 .mod = mod,739 .mod = mod,
740 .zcu = zcu,
741 .bin_file = bin_file,
733 .liveness = liveness,742 .liveness = liveness,
734 .target = target,743 .target = target,
735 .bin_file = bin_file,
736 .func_index = func_index,744 .func_index = func_index,
737 .code = code,
738 .debug_output = debug_output,745 .debug_output = debug_output,
739 .err_msg = null,746 .err_msg = null,
740 .args = undefined, // populated after `resolveCallingConventionValues`747 .args = undefined, // populated after `resolveCallingConventionValues`
...@@ -746,6 +753,8 @@ pub fn generate(...@@ -746,6 +753,8 @@ pub fn generate(
746 .end_di_line = func.rbrace_line,753 .end_di_line = func.rbrace_line,
747 .end_di_column = func.rbrace_column,754 .end_di_column = func.rbrace_column,
748 .scope_generation = 0,755 .scope_generation = 0,
756 .avl = null,
757 .vtype = null,
749 };758 };
750 defer {759 defer {
751 function.frame_allocs.deinit(gpa);760 function.frame_allocs.deinit(gpa);
...@@ -817,7 +826,7 @@ pub fn generate(...@@ -817,7 +826,7 @@ pub fn generate(
817 else => |e| return e,826 else => |e| return e,
818 };827 };
819828
820 var mir = Mir{829 var mir: Mir = .{
821 .instructions = function.mir_instructions.toOwnedSlice(),830 .instructions = function.mir_instructions.toOwnedSlice(),
822 .extra = try function.mir_extra.toOwnedSlice(gpa),831 .extra = try function.mir_extra.toOwnedSlice(gpa),
823 .frame_locs = function.frame_locs.toOwnedSlice(),832 .frame_locs = function.frame_locs.toOwnedSlice(),
...@@ -825,7 +834,6 @@ pub fn generate(...@@ -825,7 +834,6 @@ pub fn generate(
825 defer mir.deinit(gpa);834 defer mir.deinit(gpa);
826835
827 var emit: Emit = .{836 var emit: Emit = .{
828 .bin_file = bin_file,
829 .lower = .{837 .lower = .{
830 .pt = pt,838 .pt = pt,
831 .allocator = gpa,839 .allocator = gpa,
...@@ -836,6 +844,7 @@ pub fn generate(...@@ -836,6 +844,7 @@ pub fn generate(
836 .link_mode = comp.config.link_mode,844 .link_mode = comp.config.link_mode,
837 .pic = mod.pic,845 .pic = mod.pic,
838 },846 },
847 .bin_file = bin_file,
839 .debug_output = debug_output,848 .debug_output = debug_output,
840 .code = code,849 .code = code,
841 .prev_di_pc = 0,850 .prev_di_pc = 0,
...@@ -896,7 +905,7 @@ fn formatWipMir(...@@ -896,7 +905,7 @@ fn formatWipMir(
896 .pic = comp.root_mod.pic,905 .pic = comp.root_mod.pic,
897 };906 };
898 var first = true;907 var first = true;
899 for ((lower.lowerMir(data.inst) catch |err| switch (err) {908 for ((lower.lowerMir(data.inst, .{ .allow_frame_locs = false }) catch |err| switch (err) {
900 error.LowerFail => {909 error.LowerFail => {
901 defer {910 defer {
902 lower.err_msg.?.deinit(data.func.gpa);911 lower.err_msg.?.deinit(data.func.gpa);
...@@ -924,7 +933,7 @@ fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir)...@@ -924,7 +933,7 @@ fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir)
924}933}
925934
926const FormatDeclData = struct {935const FormatDeclData = struct {
927 mod: *Zcu,936 zcu: *Zcu,
928 decl_index: InternPool.DeclIndex,937 decl_index: InternPool.DeclIndex,
929};938};
930fn formatDecl(939fn formatDecl(
...@@ -933,11 +942,11 @@ fn formatDecl(...@@ -933,11 +942,11 @@ fn formatDecl(
933 _: std.fmt.FormatOptions,942 _: std.fmt.FormatOptions,
934 writer: anytype,943 writer: anytype,
935) @TypeOf(writer).Error!void {944) @TypeOf(writer).Error!void {
936 try writer.print("{}", .{data.mod.declPtr(data.decl_index).fqn.fmt(&data.mod.intern_pool)});945 try writer.print("{}", .{data.zcu.declPtr(data.decl_index).fqn.fmt(&data.zcu.intern_pool)});
937}946}
938fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {947fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
939 return .{ .data = .{948 return .{ .data = .{
940 .mod = func.pt.zcu,949 .zcu = func.zcu,
941 .decl_index = decl_index,950 .decl_index = decl_index,
942 } };951 } };
943}952}
...@@ -989,13 +998,9 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {...@@ -989,13 +998,9 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
989 .pseudo_dbg_prologue_end,998 .pseudo_dbg_prologue_end,
990 .pseudo_dbg_line_column,999 .pseudo_dbg_line_column,
991 .pseudo_dbg_epilogue_begin,1000 .pseudo_dbg_epilogue_begin,
992 .pseudo_store_rm,
993 .pseudo_load_rm,
994 .pseudo_lea_rm,
995 .pseudo_mv,
996 .pseudo_dead,1001 .pseudo_dead,
997 => false,1002 => false,
998 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}) else wip_mir_log.debug(" | uses-mem", .{});1003 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)});
999 return result_index;1004 return result_index;
1000}1005}
10011006
...@@ -1042,9 +1047,84 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {...@@ -1042,9 +1047,84 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
1042 return result;1047 return result;
1043}1048}
10441049
1050/// Returns a temporary register that contains the value of the `reg` csr.
1051///
1052/// Caller's duty to lock the return register is needed.
1053fn getCsr(func: *Func, csr: CSR) !Register {
1054 assert(func.hasFeature(.zicsr));
1055 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.usize));
1056 _ = try func.addInst(.{
1057 .tag = .csrrs,
1058 .ops = .csr,
1059 .data = .{
1060 .csr = .{
1061 .csr = csr,
1062 .rd = dst_reg,
1063 .rs1 = .x0,
1064 },
1065 },
1066 });
1067 return dst_reg;
1068}
1069
1070fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
1071 if (func.avl == avl) if (func.vtype) |vtype| {
1072 // it's already set, we don't need to do anything
1073 if (@as(u8, @bitCast(vtype)) == @as(u8, @bitCast(options))) return;
1074 };
1075
1076 func.avl = avl;
1077 func.vtype = options;
1078
1079 if (avl == 0) {
1080 // the caller means to do "vsetvli zero, zero ..." which keeps the avl to whatever it was before
1081 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1082 _ = try func.addInst(.{
1083 .tag = .vsetvli,
1084 .ops = .rri,
1085 .data = .{ .i_type = .{
1086 .rd = dst_reg,
1087 .rs1 = .zero,
1088 .imm12 = Immediate.u(options_int),
1089 } },
1090 });
1091 } else {
1092 // if the avl can fit into u5 we can use vsetivli otherwise use vsetvli
1093 if (avl <= std.math.maxInt(u5)) {
1094 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));
1095 _ = try func.addInst(.{
1096 .tag = .vsetivli,
1097 .ops = .rri,
1098 .data = .{
1099 .i_type = .{
1100 .rd = dst_reg,
1101 .rs1 = @enumFromInt(avl),
1102 .imm12 = Immediate.u(options_int),
1103 },
1104 },
1105 });
1106 } else {
1107 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1108 const temp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = avl });
1109 _ = try func.addInst(.{
1110 .tag = .vsetvli,
1111 .ops = .rri,
1112 .data = .{ .i_type = .{
1113 .rd = dst_reg,
1114 .rs1 = temp_reg,
1115 .imm12 = Immediate.u(options_int),
1116 } },
1117 });
1118 }
1119 }
1120}
1121
1045const required_features = [_]Target.riscv.Feature{1122const required_features = [_]Target.riscv.Feature{
1046 .d,1123 .d,
1047 .m,1124 .m,
1125 .a,
1126 .zicsr,
1127 .v,
1048};1128};
10491129
1050fn gen(func: *Func) !void {1130fn gen(func: *Func) !void {
...@@ -1102,7 +1182,19 @@ fn gen(func: *Func) !void {...@@ -1102,7 +1182,19 @@ fn gen(func: *Func) !void {
1102 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);1182 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);
1103 const backpatch_fp_restore = try func.addPseudo(.pseudo_dead);1183 const backpatch_fp_restore = try func.addPseudo(.pseudo_dead);
1104 const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead);1184 const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead);
1105 try func.addPseudoNone(.pseudo_ret);1185
1186 // ret
1187 _ = try func.addInst(.{
1188 .tag = .jalr,
1189 .ops = .rri,
1190 .data = .{
1191 .i_type = .{
1192 .rd = .zero,
1193 .rs1 = .ra,
1194 .imm12 = Immediate.s(0),
1195 },
1196 },
1197 });
11061198
1107 const frame_layout = try func.computeFrameLayout();1199 const frame_layout = try func.computeFrameLayout();
1108 const need_save_reg = frame_layout.save_reg_list.count() > 0;1200 const need_save_reg = frame_layout.save_reg_list.count() > 0;
...@@ -1273,7 +1365,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {...@@ -1273,7 +1365,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1273 .round,1365 .round,
1274 .trunc_float,1366 .trunc_float,
1275 .neg,1367 .neg,
1276 => try func.airUnaryMath(inst),1368 => try func.airUnaryMath(inst, tag),
12771369
1278 .add_with_overflow => try func.airAddWithOverflow(inst),1370 .add_with_overflow => try func.airAddWithOverflow(inst),
1279 .sub_with_overflow => try func.airSubWithOverflow(inst),1371 .sub_with_overflow => try func.airSubWithOverflow(inst),
...@@ -1319,7 +1411,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {...@@ -1319,7 +1411,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1319 .breakpoint => try func.airBreakpoint(),1411 .breakpoint => try func.airBreakpoint(),
1320 .ret_addr => try func.airRetAddr(inst),1412 .ret_addr => try func.airRetAddr(inst),
1321 .frame_addr => try func.airFrameAddress(inst),1413 .frame_addr => try func.airFrameAddress(inst),
1322 .fence => try func.airFence(),1414 .fence => try func.airFence(inst),
1323 .cond_br => try func.airCondBr(inst),1415 .cond_br => try func.airCondBr(inst),
1324 .dbg_stmt => try func.airDbgStmt(inst),1416 .dbg_stmt => try func.airDbgStmt(inst),
1325 .fptrunc => try func.airFptrunc(inst),1417 .fptrunc => try func.airFptrunc(inst),
...@@ -1631,7 +1723,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout {...@@ -1631,7 +1723,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout {
16311723
1632 // The total frame size is calculated by the amount of s registers you need to save * 8, as each1724 // The total frame size is calculated by the amount of s registers you need to save * 8, as each
1633 // register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s01725 // register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s0
1634 // register. Finally we align the frame size to the align of the base pointer.1726 // register. Finally we align the frame size to the alignment of the base pointer.
1635 const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)];1727 const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)];
1636 const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)];1728 const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)];
1637 const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)];1729 const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)];
...@@ -1791,14 +1883,9 @@ fn symbolIndex(func: *Func) !u32 {...@@ -1791,14 +1883,9 @@ fn symbolIndex(func: *Func) !u32 {
1791 const pt = func.pt;1883 const pt = func.pt;
1792 const zcu = pt.zcu;1884 const zcu = pt.zcu;
1793 const decl_index = zcu.funcOwnerDeclIndex(func.func_index);1885 const decl_index = zcu.funcOwnerDeclIndex(func.func_index);
1794 return switch (func.bin_file.tag) {1886 const elf_file = func.bin_file.cast(link.File.Elf).?;
1795 .elf => blk: {1887 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
1796 const elf_file = func.bin_file.cast(link.File.Elf).?;1888 return atom_index;
1797 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
1798 break :blk atom_index;
1799 },
1800 else => return func.fail("TODO symbolIndex {s}", .{@tagName(func.bin_file.tag)}),
1801 };
1802}1889}
18031890
1804fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex {1891fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex {
...@@ -1843,48 +1930,44 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass {...@@ -1843,48 +1930,44 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass {
1843 const zcu = pt.zcu;1930 const zcu = pt.zcu;
1844 return switch (ty.zigTypeTag(zcu)) {1931 return switch (ty.zigTypeTag(zcu)) {
1845 .Float => .float,1932 .Float => .float,
1846 .Vector => @panic("TODO: typeRegClass for Vectors"),1933 .Vector => .vector,
1847 inline else => .int,1934 else => .int,
1848 };1935 };
1849}1936}
18501937
1851fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {1938fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
1852 const pt = func.pt;1939 return switch (ty.zigTypeTag(func.pt.zcu)) {
1853 const zcu = pt.zcu;
1854 return switch (ty.zigTypeTag(zcu)) {
1855 .Float => abi.Registers.Float.general_purpose,1940 .Float => abi.Registers.Float.general_purpose,
1856 .Vector => @panic("TODO: regGeneralClassForType for Vectors"),1941 .Vector => abi.Registers.Vector.general_purpose,
1857 else => abi.Registers.Integer.general_purpose,1942 else => abi.Registers.Integer.general_purpose,
1858 };1943 };
1859}1944}
18601945
1861fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {1946fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
1862 const pt = func.pt;1947 return switch (ty.zigTypeTag(func.pt.zcu)) {
1863 const zcu = pt.zcu;
1864 return switch (ty.zigTypeTag(zcu)) {
1865 .Float => abi.Registers.Float.temporary,1948 .Float => abi.Registers.Float.temporary,
1866 .Vector => @panic("TODO: regTempClassForType for Vectors"),1949 .Vector => abi.Registers.Vector.general_purpose, // there are no temporary vector registers
1867 else => abi.Registers.Integer.temporary,1950 else => abi.Registers.Integer.temporary,
1868 };1951 };
1869}1952}
18701953
1871fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {1954fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
1872 const pt = func.pt;1955 const pt = func.pt;
1956 const zcu = pt.zcu;
18731957
1874 const abi_size = math.cast(u32, elem_ty.abiSize(pt)) orelse {1958 const bit_size = elem_ty.bitSize(pt);
1875 return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)});1959 const min_size: u64 = switch (elem_ty.zigTypeTag(zcu)) {
1876 };1960 .Float => if (func.hasFeature(.d)) 64 else 32,
18771961 .Vector => 256, // TODO: calculate it from avl * vsew
1878 const min_size: u32 = switch (elem_ty.zigTypeTag(pt.zcu)) {1962 else => 64,
1879 .Float => 4,
1880 .Vector => @panic("allocRegOrMem Vector"),
1881 else => 8,
1882 };1963 };
18831964
1884 if (reg_ok and abi_size <= min_size) {1965 if (reg_ok and bit_size <= min_size) {
1885 if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| {1966 if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| {
1886 return .{ .register = reg };1967 return .{ .register = reg };
1887 }1968 }
1969 } else if (reg_ok and elem_ty.zigTypeTag(zcu) == .Vector) {
1970 return func.fail("did you forget to extend vector registers before allocating", .{});
1888 }1971 }
18891972
1890 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt));1973 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt));
...@@ -1897,10 +1980,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool...@@ -1897,10 +1980,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool
1897fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {1980fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {
1898 if (reg_class == .float and !func.hasFeature(.f))1981 if (reg_class == .float and !func.hasFeature(.f))
1899 std.debug.panic("allocReg class == float where F isn't enabled", .{});1982 std.debug.panic("allocReg class == float where F isn't enabled", .{});
1983 if (reg_class == .vector and !func.hasFeature(.v))
1984 std.debug.panic("allocReg class == vector where V isn't enabled", .{});
19001985
1901 const class = switch (reg_class) {1986 const class = switch (reg_class) {
1902 .int => abi.Registers.Integer.general_purpose,1987 .int => abi.Registers.Integer.general_purpose,
1903 .float => abi.Registers.Float.general_purpose,1988 .float => abi.Registers.Float.general_purpose,
1989 .vector => abi.Registers.Vector.general_purpose,
1904 };1990 };
19051991
1906 const reg = try func.register_manager.allocReg(null, class);1992 const reg = try func.register_manager.allocReg(null, class);
...@@ -1916,7 +2002,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi...@@ -1916,7 +2002,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi
1916 return .{ op_reg, func.register_manager.lockReg(operand.register) };2002 return .{ op_reg, func.register_manager.lockReg(operand.register) };
1917 }2003 }
19182004
1919 const reg, const lock = try func.allocReg(func.typeRegClass(ty));2005 const class = func.typeRegClass(ty);
2006 const reg, const lock = try func.allocReg(class);
1920 try func.genSetReg(ty, reg, operand);2007 try func.genSetReg(ty, reg, operand);
1921 return .{ reg, lock };2008 return .{ reg, lock };
1922}2009}
...@@ -2087,19 +2174,17 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {...@@ -2087,19 +2174,17 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
2087 const operand = try func.resolveInst(ty_op.operand);2174 const operand = try func.resolveInst(ty_op.operand);
2088 const ty = func.typeOf(ty_op.operand);2175 const ty = func.typeOf(ty_op.operand);
20892176
2090 switch (ty.zigTypeTag(zcu)) {2177 const operand_reg, const operand_lock = try func.promoteReg(ty, operand);
2091 .Bool => {2178 defer if (operand_lock) |lock| func.register_manager.unlockReg(lock);
2092 const operand_reg = blk: {
2093 if (operand == .register) break :blk operand.register;
2094 break :blk try func.copyToTmpRegister(ty, operand);
2095 };
20962179
2097 const dst_reg: Register =2180 const dst_reg: Register =
2098 if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)2181 if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
2099 operand.register2182 operand.register
2100 else2183 else
2101 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;2184 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
21022185
2186 switch (ty.zigTypeTag(zcu)) {
2187 .Bool => {
2103 _ = try func.addInst(.{2188 _ = try func.addInst(.{
2104 .tag = .pseudo,2189 .tag = .pseudo,
2105 .ops = .pseudo_not,2190 .ops = .pseudo_not,
...@@ -2110,12 +2195,34 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {...@@ -2110,12 +2195,34 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
2110 },2195 },
2111 },2196 },
2112 });2197 });
2198 },
2199 .Int => {
2200 const size = ty.bitSize(pt);
2201 if (!math.isPowerOfTwo(size))
2202 return func.fail("TODO: airNot non-pow 2 int size", .{});
21132203
2114 break :result .{ .register = dst_reg };2204 switch (size) {
2205 32, 64 => {
2206 _ = try func.addInst(.{
2207 .tag = .xori,
2208 .ops = .rri,
2209 .data = .{
2210 .i_type = .{
2211 .rd = dst_reg,
2212 .rs1 = operand_reg,
2213 .imm12 = Immediate.s(-1),
2214 },
2215 },
2216 });
2217 },
2218 8, 16 => return func.fail("TODO: airNot 8 or 16, {}", .{size}),
2219 else => unreachable,
2220 }
2115 },2221 },
2116 .Int => return func.fail("TODO: airNot ints", .{}),
2117 else => unreachable,2222 else => unreachable,
2118 }2223 }
2224
2225 break :result .{ .register = dst_reg };
2119 };2226 };
2120 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });2227 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2121}2228}
...@@ -2205,7 +2312,11 @@ fn binOp(...@@ -2205,7 +2312,11 @@ fn binOp(
2205 return func.fail("binOp libcall runtime-float ops", .{});2312 return func.fail("binOp libcall runtime-float ops", .{});
2206 }2313 }
22072314
2208 if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{});2315 // don't have support for certain sizes of addition
2316 switch (lhs_ty.zigTypeTag(pt.zcu)) {
2317 .Vector => {}, // works differently and fails in a different place
2318 else => if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{}),
2319 }
22092320
2210 const lhs_mcv = try func.resolveInst(lhs_air);2321 const lhs_mcv = try func.resolveInst(lhs_air);
2211 const rhs_mcv = try func.resolveInst(rhs_air);2322 const rhs_mcv = try func.resolveInst(rhs_air);
...@@ -2353,6 +2464,51 @@ fn genBinOp(...@@ -2353,6 +2464,51 @@ fn genBinOp(
2353 },2464 },
2354 });2465 });
2355 },2466 },
2467 .Vector => {
2468 const num_elem = lhs_ty.vectorLen(zcu);
2469 const elem_size = lhs_ty.childType(zcu).bitSize(pt);
2470
2471 const child_ty = lhs_ty.childType(zcu);
2472
2473 const mir_tag: Mir.Inst.Tag = switch (tag) {
2474 .add => switch (child_ty.zigTypeTag(zcu)) {
2475 .Int => .vaddvv,
2476 .Float => .vfaddvv,
2477 else => unreachable,
2478 },
2479 .sub => switch (child_ty.zigTypeTag(zcu)) {
2480 .Int => .vsubvv,
2481 .Float => .vfsubvv,
2482 else => unreachable,
2483 },
2484 else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}),
2485 };
2486
2487 try func.setVl(.zero, num_elem, .{
2488 .vsew = switch (elem_size) {
2489 8 => .@"8",
2490 16 => .@"16",
2491 32 => .@"32",
2492 64 => .@"64",
2493 else => unreachable,
2494 },
2495 .vlmul = .m1,
2496 .vma = true,
2497 .vta = true,
2498 });
2499
2500 _ = try func.addInst(.{
2501 .tag = mir_tag,
2502 .ops = .rrr,
2503 .data = .{
2504 .r_type = .{
2505 .rd = dst_reg,
2506 .rs1 = rhs_reg,
2507 .rs2 = lhs_reg,
2508 },
2509 },
2510 });
2511 },
2356 else => unreachable,2512 else => unreachable,
2357 }2513 }
2358 },2514 },
...@@ -2636,78 +2792,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -2636,78 +2792,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2636 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;2792 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
26372793
2638 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {2794 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2639 const lhs_ty = func.typeOf(extra.lhs);2795 const ty = func.typeOf(extra.lhs);
26402796 switch (ty.zigTypeTag(zcu)) {
2641 const int_info = lhs_ty.intInfo(zcu);2797 .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}),
26422798 .Int => {
2643 const tuple_ty = func.typeOfIndex(inst);2799 const int_info = ty.intInfo(zcu);
2644 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2645 const offset = result_mcv.load_frame;
2646
2647 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2648 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
2649 const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result);
2650 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2651 defer func.register_manager.unlockReg(add_result_reg_lock);
26522800
2653 const shift_amount: u6 = @intCast(Type.usize.bitSize(pt) - int_info.bits);2801 const tuple_ty = func.typeOfIndex(inst);
2802 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2803 const offset = result_mcv.load_frame;
26542804
2655 const shift_reg, const shift_lock = try func.allocReg(.int);2805 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2656 defer func.register_manager.unlockReg(shift_lock);2806 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
26572807
2658 _ = try func.addInst(.{2808 const add_result_reg = try func.copyToTmpRegister(ty, add_result);
2659 .tag = .slli,2809 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2660 .ops = .rri,2810 defer func.register_manager.unlockReg(add_result_reg_lock);
2661 .data = .{
2662 .i_type = .{
2663 .rd = shift_reg,
2664 .rs1 = add_result_reg,
2665 .imm12 = Immediate.u(shift_amount),
2666 },
2667 },
2668 });
26692811
2670 _ = try func.addInst(.{2812 try func.genSetMem(
2671 .tag = if (int_info.signedness == .unsigned) .srli else .srai,2813 .{ .frame = offset.index },
2672 .ops = .rri,2814 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2673 .data = .{2815 ty,
2674 .i_type = .{2816 add_result,
2675 .rd = shift_reg,2817 );
2676 .rs1 = shift_reg,
2677 .imm12 = Immediate.u(shift_amount),
2678 },
2679 },
2680 });
2681
2682 try func.genSetMem(
2683 .{ .frame = offset.index },
2684 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2685 lhs_ty,
2686 add_result,
2687 );
26882818
2689 const overflow_reg, const overflow_lock = try func.allocReg(.int);2819 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2690 defer func.register_manager.unlockReg(overflow_lock);2820 defer func.register_manager.unlockReg(overflow_lock);
26912821
2692 try func.genBinOp(2822 try func.genBinOp(
2693 .cmp_neq,2823 .cmp_neq,
2694 .{ .register = shift_reg },2824 .{ .register = add_result_reg },
2695 lhs_ty,2825 ty,
2696 .{ .register = add_result_reg },2826 .{ .register = add_result_reg },
2697 lhs_ty,2827 ty,
2698 overflow_reg,2828 overflow_reg,
2699 );2829 );
27002830
2701 try func.genSetMem(2831 try func.genSetMem(
2702 .{ .frame = offset.index },2832 .{ .frame = offset.index },
2703 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),2833 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),
2704 Type.u1,2834 Type.u1,
2705 .{ .register = overflow_reg },2835 .{ .register = overflow_reg },
2706 );2836 );
27072837
2708 break :result result_mcv;2838 break :result result_mcv;
2709 } else {2839 } else {
2710 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});2840 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
2841 }
2842 },
2843 else => unreachable,
2711 }2844 }
2712 };2845 };
27132846
...@@ -3229,7 +3362,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3229,7 +3362,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
3229 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, pt));3362 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, pt));
3230 const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, pt));3363 const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, pt));
3231 const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, pt));3364 const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, pt));
3232 try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef);3365 try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .{ .undef = null });
3233 const operand = try func.resolveInst(ty_op.operand);3366 const operand = try func.resolveInst(ty_op.operand);
3234 try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand);3367 try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand);
3235 break :result .{ .load_frame = .{ .index = frame_index } };3368 break :result .{ .load_frame = .{ .index = frame_index } };
...@@ -3451,20 +3584,54 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3451,20 +3584,54 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
3451 else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()),3584 else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()),
3452 }3585 }
34533586
3587 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
3588
3589 if (array_ty.isVector(zcu)) {
3590 // we need to load the vector, vslidedown to get the element we want
3591 // and store that element at in a load frame.
3592
3593 const src_reg, const src_lock = try func.allocReg(.vector);
3594 defer func.register_manager.unlockReg(src_lock);
3595
3596 // load the vector into a temporary register
3597 try func.genCopy(array_ty, .{ .register = src_reg }, .{ .indirect = .{ .reg = addr_reg } });
3598
3599 // we need to construct a 1xbitSize vector because of how lane splitting works in RISC-V
3600 const single_ty = try pt.vectorType(.{ .child = elem_ty.toIntern(), .len = 1 });
3601
3602 // we can do a shortcut here where we don't need a vslicedown
3603 // and can just copy to the frame index.
3604 if (!(index_mcv == .immediate and index_mcv.immediate == 0)) {
3605 const index_reg = try func.copyToTmpRegister(Type.usize, index_mcv);
3606
3607 _ = try func.addInst(.{
3608 .tag = .vslidedownvx,
3609 .ops = .rrr,
3610 .data = .{ .r_type = .{
3611 .rd = src_reg,
3612 .rs1 = index_reg,
3613 .rs2 = src_reg,
3614 } },
3615 });
3616 }
3617
3618 try func.genCopy(single_ty, dst_mcv, .{ .register = src_reg });
3619 break :result dst_mcv;
3620 }
3621
3454 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size);3622 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size);
3455 const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg);3623 const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
3456 defer func.register_manager.unlockReg(offset_lock);3624 defer func.register_manager.unlockReg(offset_lock);
3457
3458 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
3459 _ = try func.addInst(.{3625 _ = try func.addInst(.{
3460 .tag = .add,3626 .tag = .add,
3461 .ops = .rrr,3627 .ops = .rrr,
3462 .data = .{ .r_type = .{3628 .data = .{ .r_type = .{
3463 .rd = addr_reg,3629 .rd = addr_reg,
3464 .rs1 = offset_reg,3630 .rs1 = addr_reg,
3465 .rs2 = addr_reg,3631 .rs2 = offset_reg,
3466 } },3632 } },
3467 });3633 });
3634
3468 try func.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });3635 try func.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
3469 break :result dst_mcv;3636 break :result dst_mcv;
3470 };3637 };
...@@ -3541,9 +3708,50 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void {...@@ -3541,9 +3708,50 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
3541}3708}
35423709
3543fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {3710fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
3711 const pt = func.pt;
3544 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3712 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3545 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airGetUnionTag for {}", .{func.target.cpu.arch});3713
3546 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });3714 const tag_ty = func.typeOfIndex(inst);
3715 const union_ty = func.typeOf(ty_op.operand);
3716 const layout = union_ty.unionGetLayout(pt);
3717
3718 if (layout.tag_size == 0) {
3719 return func.finishAir(inst, .none, .{ ty_op.operand, .none, .none });
3720 }
3721
3722 const operand = try func.resolveInst(ty_op.operand);
3723
3724 const frame_mcv = try func.allocRegOrMem(union_ty, null, false);
3725 try func.genCopy(union_ty, frame_mcv, operand);
3726
3727 const tag_abi_size = tag_ty.abiSize(pt);
3728 const result_reg, const result_lock = try func.allocReg(.int);
3729 defer func.register_manager.unlockReg(result_lock);
3730
3731 switch (frame_mcv) {
3732 .load_frame => |frame_addr| {
3733 if (tag_abi_size <= 8) {
3734 const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
3735 @intCast(layout.payload_size)
3736 else
3737 0;
3738
3739 try func.genCopy(
3740 tag_ty,
3741 .{ .register = result_reg },
3742 .{ .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off } },
3743 );
3744 } else {
3745 return func.fail(
3746 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}",
3747 .{ frame_mcv, tag_ty.fmt(pt) },
3748 );
3749 }
3750 },
3751 else => return func.fail("TODO: airGetUnionTag {s}", .{@tagName(operand)}),
3752 }
3753
3754 return func.finishAir(inst, .{ .register = result_reg }, .{ ty_op.operand, .none, .none });
3547}3755}
35483756
3549fn airClz(func: *Func, inst: Air.Inst.Index) !void {3757fn airClz(func: *Func, inst: Air.Inst.Index) !void {
...@@ -3719,13 +3927,65 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void {...@@ -3719,13 +3927,65 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void {
3719 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });3927 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3720}3928}
37213929
3722fn airUnaryMath(func: *Func, inst: Air.Inst.Index) !void {3930fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
3723 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];3931 const pt = func.pt;
3724 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;3932 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3725 const result: MCValue = if (func.liveness.isUnused(inst))3933 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3726 .unreach3934 const ty = func.typeOf(un_op);
3727 else3935
3728 return func.fail("TODO implementairUnaryMath {s} for {}", .{ @tagName(tag), func.target.cpu.arch });3936 const operand = try func.resolveInst(un_op);
3937 const operand_bit_size = ty.bitSize(pt);
3938
3939 if (!math.isPowerOfTwo(operand_bit_size))
3940 return func.fail("TODO: airUnaryMath non-pow 2", .{});
3941
3942 const operand_reg, const operand_lock = try func.promoteReg(ty, operand);
3943 defer if (operand_lock) |lock| func.register_manager.unlockReg(lock);
3944
3945 const dst_class = func.typeRegClass(ty);
3946 const dst_reg, const dst_lock = try func.allocReg(dst_class);
3947 defer func.register_manager.unlockReg(dst_lock);
3948
3949 switch (ty.zigTypeTag(pt.zcu)) {
3950 .Float => {
3951 assert(dst_class == .float);
3952
3953 switch (operand_bit_size) {
3954 16, 80, 128 => return func.fail("TODO: airUnaryMath Float bit-size {}", .{operand_bit_size}),
3955 32, 64 => {},
3956 else => unreachable,
3957 }
3958
3959 switch (tag) {
3960 .sqrt => {
3961 _ = try func.addInst(.{
3962 .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts,
3963 .ops = .rrr,
3964 .data = .{
3965 .r_type = .{
3966 .rd = dst_reg,
3967 .rs1 = operand_reg,
3968 .rs2 = .f0, // unused, spec says it's 0
3969 },
3970 },
3971 });
3972 },
3973 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
3974 }
3975 },
3976 .Int => {
3977 assert(dst_class == .int);
3978
3979 switch (tag) {
3980 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
3981 }
3982 },
3983 else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}),
3984 }
3985
3986 break :result MCValue{ .register = dst_reg };
3987 };
3988
3729 return func.finishAir(inst, result, .{ un_op, .none, .none });3989 return func.finishAir(inst, result, .{ un_op, .none, .none });
3730}3990}
37313991
...@@ -3987,6 +4247,10 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3987,6 +4247,10 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
3987 });4247 });
3988 }4248 }
39894249
4250 if (field_off == 0) {
4251 try func.truncateRegister(field_ty, dst_reg);
4252 }
4253
3990 break :result if (field_off == 0) dst_mcv else try func.copyToNewRegister(inst, dst_mcv);4254 break :result if (field_off == 0) dst_mcv else try func.copyToNewRegister(inst, dst_mcv);
3991 },4255 },
3992 .load_frame => {4256 .load_frame => {
...@@ -4121,9 +4385,28 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {...@@ -4121,9 +4385,28 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
4121 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });4385 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
4122}4386}
41234387
4124fn airFence(func: *Func) !void {4388fn airFence(func: *Func, inst: Air.Inst.Index) !void {
4125 return func.fail("TODO implement fence() for {}", .{func.target.cpu.arch});4389 const order = func.air.instructions.items(.data)[@intFromEnum(inst)].fence;
4126 //return func.finishAirBookkeeping();4390 const pred: Mir.Barrier, const succ: Mir.Barrier = switch (order) {
4391 .unordered, .monotonic => unreachable,
4392 .acquire => .{ .r, .rw },
4393 .release => .{ .rw, .r },
4394 .acq_rel => .{ .rw, .rw },
4395 .seq_cst => .{ .rw, .rw },
4396 };
4397
4398 _ = try func.addInst(.{
4399 .tag = .pseudo,
4400 .ops = .pseudo_fence,
4401 .data = .{
4402 .fence = .{
4403 .pred = pred,
4404 .succ = succ,
4405 .fm = if (order == .acq_rel) .tso else .none,
4406 },
4407 },
4408 });
4409 return func.finishAirBookkeeping();
4127}4410}
41284411
4129fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4412fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
...@@ -4374,7 +4657,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {...@@ -4374,7 +4657,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
4374 .none => {},4657 .none => {},
4375 .register,4658 .register,
4376 .register_pair,4659 .register_pair,
4377 => try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op }),4660 => {
4661 if (ret_ty.isVector(zcu)) {
4662 const bit_size = ret_ty.totalVectorBits(pt);
4663
4664 // set the vtype to hold the entire vector's contents in a single element
4665 try func.setVl(.zero, 0, .{
4666 .vsew = switch (bit_size) {
4667 8 => .@"8",
4668 16 => .@"16",
4669 32 => .@"32",
4670 64 => .@"64",
4671 else => unreachable,
4672 },
4673 .vlmul = .m1,
4674 .vma = true,
4675 .vta = true,
4676 });
4677 }
4678
4679 try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op });
4680 },
4378 .indirect => |reg_off| {4681 .indirect => |reg_off| {
4379 try func.register_manager.getReg(reg_off.reg, null);4682 try func.register_manager.getReg(reg_off.reg, null);
4380 const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg);4683 const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg);
...@@ -5224,8 +5527,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -5224,8 +5527,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
5224 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);5527 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);
5225 extra_i += inputs.len;5528 extra_i += inputs.len;
52265529
5227 log.debug("airAsm input: {any}", .{inputs});
5228
5229 const dead = !is_volatile and func.liveness.isUnused(inst);5530 const dead = !is_volatile and func.liveness.isUnused(inst);
5230 const result: MCValue = if (dead) .unreach else result: {5531 const result: MCValue = if (dead) .unreach else result: {
5231 if (outputs.len > 1) {5532 if (outputs.len > 1) {
...@@ -5599,18 +5900,34 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5599,18 +5900,34 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5599 const zcu = pt.zcu;5900 const zcu = pt.zcu;
5600 const abi_size: u32 = @intCast(ty.abiSize(pt));5901 const abi_size: u32 = @intCast(ty.abiSize(pt));
56015902
5602 if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size});5903 const max_size: u32 = switch (reg.class()) {
56035904 .int => 64,
5905 .float => if (func.hasFeature(.d)) 64 else 32,
5906 .vector => 64, // TODO: calculate it from avl * vsew
5907 };
5908 if (abi_size > max_size) return std.debug.panic("tried to set reg with size {}", .{abi_size});
5604 const dst_reg_class = reg.class();5909 const dst_reg_class = reg.class();
56055910
5606 switch (src_mcv) {5911 switch (src_mcv) {
5607 .dead => unreachable,5912 .unreach,
5608 .unreach, .none => return, // Nothing to do.5913 .none,
5609 .undef => {5914 .dead,
5915 => unreachable,
5916 .undef => |sym_index| {
5610 if (!func.wantSafety())5917 if (!func.wantSafety())
5611 return; // The already existing value will do just fine.5918 return;
5612 // Write the debug undefined value.5919
5613 return func.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });5920 if (sym_index) |index| {
5921 return func.genSetReg(ty, reg, .{ .load_symbol = .{ .sym = index } });
5922 }
5923
5924 switch (abi_size) {
5925 1 => return func.genSetReg(ty, reg, .{ .immediate = 0xAA }),
5926 2 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAA }),
5927 3...4 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAAAAAA }),
5928 5...8 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAAAAAAAAAAAAAA }),
5929 else => unreachable,
5930 }
5614 },5931 },
5615 .immediate => |unsigned_x| {5932 .immediate => |unsigned_x| {
5616 assert(dst_reg_class == .int);5933 assert(dst_reg_class == .int);
...@@ -5688,11 +6005,25 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5688,11 +6005,25 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5688 if (src_reg.id() == reg.id())6005 if (src_reg.id() == reg.id())
5689 return;6006 return;
56906007
5691 const src_reg_class = src_reg.class();6008 // there is no instruction for loading the contents of a vector register
56926009 // into an integer register, however we can cheat a bit by setting the element
5693 if (src_reg_class == .float and dst_reg_class == .int) {6010 // size to the total size of the vector, and vmv.x.s will work then
5694 // to move from float -> int, we use FMV.X.W6011 if (src_reg.class() == .vector) {
5695 return func.fail("TODO: genSetReg float -> int", .{});6012 try func.setVl(.zero, 0, .{
6013 .vsew = switch (ty.totalVectorBits(pt)) {
6014 8 => .@"8",
6015 16 => .@"16",
6016 32 => .@"32",
6017 64 => .@"64",
6018 else => |vec_bits| return func.fail("TODO: genSetReg vec -> {s} bits {d}", .{
6019 @tagName(reg.class()),
6020 vec_bits,
6021 }),
6022 },
6023 .vlmul = .m1,
6024 .vta = true,
6025 .vma = true,
6026 });
5696 }6027 }
56976028
5698 // mv reg, src_reg6029 // mv reg, src_reg
...@@ -5707,21 +6038,31 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5707,21 +6038,31 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5707 },6038 },
5708 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),6039 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
5709 .load_frame => |frame| {6040 .load_frame => |frame| {
5710 _ = try func.addInst(.{6041 if (reg.class() == .vector) {
5711 .tag = .pseudo,6042 // vectors don't support an offset memory load so we need to put the true
5712 .ops = .pseudo_load_rm,6043 // address into a register before loading from it.
5713 .data = .{ .rm = .{6044 const addr_reg, const addr_lock = try func.allocReg(.int);
5714 .r = reg,6045 defer func.register_manager.unlockReg(addr_lock);
5715 .m = .{6046
5716 .base = .{ .frame = frame.index },6047 try func.genCopy(ty, .{ .register = addr_reg }, src_mcv.address());
5717 .mod = .{6048 try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } });
5718 .size = func.memSize(ty),6049 } else {
5719 .unsigned = ty.isUnsignedInt(zcu),6050 _ = try func.addInst(.{
5720 .disp = frame.off,6051 .tag = .pseudo,
6052 .ops = .pseudo_load_rm,
6053 .data = .{ .rm = .{
6054 .r = reg,
6055 .m = .{
6056 .base = .{ .frame = frame.index },
6057 .mod = .{
6058 .size = func.memSize(ty),
6059 .unsigned = ty.isUnsignedInt(zcu),
6060 .disp = frame.off,
6061 },
5721 },6062 },
5722 },6063 } },
5723 } },6064 });
5724 });6065 }
5725 },6066 },
5726 .memory => |addr| {6067 .memory => |addr| {
5727 try func.genSetReg(ty, reg, .{ .immediate = addr });6068 try func.genSetReg(ty, reg, .{ .immediate = addr });
...@@ -5740,45 +6081,89 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5740,45 +6081,89 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5740 _ = try func.addInst(.{6081 _ = try func.addInst(.{
5741 .tag = .pseudo,6082 .tag = .pseudo,
5742 .ops = .pseudo_lea_rm,6083 .ops = .pseudo_lea_rm,
5743 .data = .{ .rm = .{6084 .data = .{
5744 .r = reg,6085 .rm = .{
5745 .m = switch (src_mcv) {6086 .r = reg,
5746 .register_offset => |reg_off| .{6087 .m = switch (src_mcv) {
5747 .base = .{ .reg = reg_off.reg },6088 .register_offset => |reg_off| .{
5748 .mod = .{6089 .base = .{ .reg = reg_off.reg },
5749 .size = func.memSize(ty),6090 .mod = .{
5750 .disp = reg_off.off,6091 .size = .byte, // the size doesn't matter
5751 .unsigned = false,6092 .disp = reg_off.off,
6093 .unsigned = false,
6094 },
5752 },6095 },
5753 },6096 .lea_frame => |frame| .{
5754 .lea_frame => |frame| .{6097 .base = .{ .frame = frame.index },
5755 .base = .{ .frame = frame.index },6098 .mod = .{
5756 .mod = .{6099 .size = .byte, // the size doesn't matter
5757 .size = func.memSize(ty),6100 .disp = frame.off,
5758 .disp = frame.off,6101 .unsigned = false,
5759 .unsigned = false,6102 },
5760 },6103 },
6104 else => unreachable,
5761 },6105 },
5762 else => unreachable,
5763 },6106 },
5764 } },6107 },
5765 });6108 });
5766 },6109 },
5767 .indirect => |reg_off| {6110 .indirect => |reg_off| {
5768 const float_class = dst_reg_class == .float;6111 const load_tag: Mir.Inst.Tag = switch (reg.class()) {
6112 .float => switch (abi_size) {
6113 1 => unreachable, // Zig does not support 8-bit floats
6114 2 => return func.fail("TODO: genSetReg indirect 16-bit float", .{}),
6115 4 => .flw,
6116 8 => .fld,
6117 else => return std.debug.panic("TODO: genSetReg for float size {d}", .{abi_size}),
6118 },
6119 .int => switch (abi_size) {
6120 1 => .lb,
6121 2 => .lh,
6122 4 => .lw,
6123 8 => .ld,
6124 else => return std.debug.panic("TODO: genSetReg for int size {d}", .{abi_size}),
6125 },
6126 .vector => {
6127 assert(reg_off.off == 0);
6128
6129 // There is no vector instruction for loading with an offset to a base register,
6130 // so we need to get an offset register containing the address of the vector first
6131 // and load from it.
6132 const len = ty.vectorLen(zcu);
6133 const elem_ty = ty.childType(zcu);
6134 const elem_size = elem_ty.abiSize(pt);
6135
6136 try func.setVl(.zero, len, .{
6137 .vsew = switch (elem_size) {
6138 1 => .@"8",
6139 2 => .@"16",
6140 4 => .@"32",
6141 8 => .@"64",
6142 else => unreachable,
6143 },
6144 .vlmul = .m1,
6145 .vma = true,
6146 .vta = true,
6147 });
57696148
5770 const load_tag: Mir.Inst.Tag = switch (abi_size) {6149 _ = try func.addInst(.{
5771 1 => if (float_class)6150 .tag = .pseudo,
5772 unreachable // Zig does not support 8-bit floats6151 .ops = .pseudo_load_rm,
5773 else6152 .data = .{ .rm = .{
5774 .lb,6153 .r = reg,
5775 2 => if (float_class)6154 .m = .{
5776 return func.fail("TODO: genSetReg indirect 16-bit float", .{})6155 .base = .{ .reg = reg_off.reg },
5777 else6156 .mod = .{
5778 .lh,6157 .size = func.memSize(elem_ty),
5779 4 => if (float_class) .flw else .lw,6158 .unsigned = false,
5780 8 => if (float_class) .fld else .ld,6159 .disp = 0,
5781 else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}),6160 },
6161 },
6162 } },
6163 });
6164
6165 return;
6166 },
5782 };6167 };
57836168
5784 _ = try func.addInst(.{6169 _ = try func.addInst(.{
...@@ -5793,7 +6178,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5793,7 +6178,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5793 },6178 },
5794 .lea_symbol => |sym_off| {6179 .lea_symbol => |sym_off| {
5795 assert(sym_off.off == 0);6180 assert(sym_off.off == 0);
5796
5797 const atom_index = try func.symbolIndex();6181 const atom_index = try func.symbolIndex();
57986182
5799 _ = try func.addInst(.{6183 _ = try func.addInst(.{
...@@ -5826,6 +6210,8 @@ fn genSetMem(...@@ -5826,6 +6210,8 @@ fn genSetMem(
5826 src_mcv: MCValue,6210 src_mcv: MCValue,
5827) InnerError!void {6211) InnerError!void {
5828 const pt = func.pt;6212 const pt = func.pt;
6213 const zcu = pt.zcu;
6214
5829 const abi_size: u32 = @intCast(ty.abiSize(pt));6215 const abi_size: u32 = @intCast(ty.abiSize(pt));
5830 const dst_ptr_mcv: MCValue = switch (base) {6216 const dst_ptr_mcv: MCValue = switch (base) {
5831 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },6217 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
...@@ -5838,11 +6224,17 @@ fn genSetMem(...@@ -5838,11 +6224,17 @@ fn genSetMem(
5838 .dead,6224 .dead,
5839 .reserved_frame,6225 .reserved_frame,
5840 => unreachable,6226 => unreachable,
5841 .undef => try func.genInlineMemset(6227 .undef => |sym_index| {
5842 dst_ptr_mcv,6228 if (sym_index) |index| {
5843 src_mcv,6229 return func.genSetMem(base, disp, ty, .{ .load_symbol = .{ .sym = index } });
5844 .{ .immediate = abi_size },6230 }
5845 ),6231
6232 try func.genInlineMemset(
6233 dst_ptr_mcv,
6234 src_mcv,
6235 .{ .immediate = abi_size },
6236 );
6237 },
5846 .register_offset,6238 .register_offset,
5847 .memory,6239 .memory,
5848 .indirect,6240 .indirect,
...@@ -5853,12 +6245,12 @@ fn genSetMem(...@@ -5853,12 +6245,12 @@ fn genSetMem(
5853 => switch (abi_size) {6245 => switch (abi_size) {
5854 0 => {},6246 0 => {},
5855 1, 2, 4, 8 => {6247 1, 2, 4, 8 => {
5856 // no matter what type, it should use an integer register6248 const reg = try func.register_manager.allocReg(null, abi.Registers.Integer.temporary);
5857 const src_reg = try func.copyToTmpRegister(Type.usize, src_mcv);6249 const src_lock = func.register_manager.lockRegAssumeUnused(reg);
5858 const src_lock = func.register_manager.lockRegAssumeUnused(src_reg);
5859 defer func.register_manager.unlockReg(src_lock);6250 defer func.register_manager.unlockReg(src_lock);
58606251
5861 try func.genSetMem(base, disp, ty, .{ .register = src_reg });6252 try func.genSetReg(ty, reg, src_mcv);
6253 try func.genSetMem(base, disp, ty, .{ .register = reg });
5862 },6254 },
5863 else => try func.genInlineMemcpy(6255 else => try func.genInlineMemcpy(
5864 dst_ptr_mcv,6256 dst_ptr_mcv,
...@@ -5867,6 +6259,44 @@ fn genSetMem(...@@ -5867,6 +6259,44 @@ fn genSetMem(
5867 ),6259 ),
5868 },6260 },
5869 .register => |reg| {6261 .register => |reg| {
6262 if (reg.class() == .vector) {
6263 const addr_reg = try func.copyToTmpRegister(Type.usize, dst_ptr_mcv);
6264
6265 const num_elem = ty.vectorLen(zcu);
6266 const elem_size = ty.childType(zcu).bitSize(pt);
6267
6268 try func.setVl(.zero, num_elem, .{
6269 .vsew = switch (elem_size) {
6270 8 => .@"8",
6271 16 => .@"16",
6272 32 => .@"32",
6273 64 => .@"64",
6274 else => unreachable,
6275 },
6276 .vlmul = .m1,
6277 .vma = true,
6278 .vta = true,
6279 });
6280
6281 _ = try func.addInst(.{
6282 .tag = .pseudo,
6283 .ops = .pseudo_store_rm,
6284 .data = .{ .rm = .{
6285 .r = reg,
6286 .m = .{
6287 .base = .{ .reg = addr_reg },
6288 .mod = .{
6289 .disp = 0,
6290 .size = func.memSize(ty.childType(zcu)),
6291 .unsigned = false,
6292 },
6293 },
6294 } },
6295 });
6296
6297 return;
6298 }
6299
5870 const mem_size = switch (base) {6300 const mem_size = switch (base) {
5871 .frame => |base_fi| mem_size: {6301 .frame => |base_fi| mem_size: {
5872 assert(disp >= 0);6302 assert(disp >= 0);
...@@ -6042,19 +6472,161 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {...@@ -6042,19 +6472,161 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {
6042}6472}
60436473
6044fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {6474fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
6045 _ = inst;6475 const pt = func.pt;
6046 return func.fail("TODO implement airCmpxchg for {}", .{func.target.cpu.arch});6476 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6477 const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data;
6478
6479 const op = extra.op();
6480 const order = extra.ordering();
6481
6482 const ptr_ty = func.typeOf(pl_op.operand);
6483 const ptr_mcv = try func.resolveInst(pl_op.operand);
6484
6485 const val_ty = func.typeOf(extra.operand);
6486 const val_size = val_ty.abiSize(pt);
6487 const val_mcv = try func.resolveInst(extra.operand);
6488
6489 if (!math.isPowerOfTwo(val_size))
6490 return func.fail("TODO: airAtomicRmw non-pow 2", .{});
6491
6492 switch (val_ty.zigTypeTag(pt.zcu)) {
6493 .Int => {},
6494 inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}),
6495 else => unreachable,
6496 }
6497
6498 switch (val_size) {
6499 1, 2 => return func.fail("TODO: airAtomicRmw Int {}", .{val_size}),
6500 4, 8 => {},
6501 else => unreachable,
6502 }
6503
6504 const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv);
6505 defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock);
6506
6507 const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv);
6508 defer if (val_lock) |lock| func.register_manager.unlockReg(lock);
6509
6510 const result_mcv = try func.allocRegOrMem(val_ty, inst, true);
6511 assert(result_mcv == .register); // should fit into 8 bytes
6512
6513 const aq, const rl = switch (order) {
6514 .unordered => unreachable,
6515 .monotonic => .{ false, false },
6516 .acquire => .{ true, false },
6517 .release => .{ false, true },
6518 .acq_rel => .{ true, true },
6519 .seq_cst => .{ true, true },
6520 };
6521
6522 _ = try func.addInst(.{
6523 .tag = .pseudo,
6524 .ops = .pseudo_amo,
6525 .data = .{ .amo = .{
6526 .rd = result_mcv.register,
6527 .rs1 = ptr_register,
6528 .rs2 = val_register,
6529 .aq = if (aq) .aq else .none,
6530 .rl = if (rl) .rl else .none,
6531 .op = switch (op) {
6532 .Xchg => .SWAP,
6533 .Add => .ADD,
6534 .Sub => return func.fail("TODO: airAtomicRmw SUB", .{}),
6535 .And => .AND,
6536 .Nand => return func.fail("TODO: airAtomicRmw NAND", .{}),
6537 .Or => .OR,
6538 .Xor => .XOR,
6539 .Max => .MAX,
6540 .Min => .MIN,
6541 },
6542 .ty = val_ty,
6543 } },
6544 });
6545
6546 return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none });
6047}6547}
60486548
6049fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {6549fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
6050 _ = inst;6550 const zcu = func.pt.zcu;
6051 return func.fail("TODO implement airAtomicLoad for {}", .{func.target.cpu.arch});6551 const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
6552 const order: std.builtin.AtomicOrder = atomic_load.order;
6553
6554 const ptr_ty = func.typeOf(atomic_load.ptr);
6555 const elem_ty = ptr_ty.childType(zcu);
6556 const ptr_mcv = try func.resolveInst(atomic_load.ptr);
6557
6558 const result_mcv = try func.allocRegOrMem(elem_ty, inst, true);
6559 assert(result_mcv == .register); // should be less than 8 bytes
6560
6561 if (order == .seq_cst) {
6562 _ = try func.addInst(.{
6563 .tag = .pseudo,
6564 .ops = .pseudo_fence,
6565 .data = .{
6566 .fence = .{
6567 .pred = .rw,
6568 .succ = .rw,
6569 .fm = .none,
6570 },
6571 },
6572 });
6573 }
6574
6575 try func.load(result_mcv, ptr_mcv, ptr_ty);
6576
6577 switch (order) {
6578 // Don't guarnetee other memory operations to be ordered after the load.
6579 .unordered => {},
6580 .monotonic => {},
6581 // Make sure all previous reads happen before any reading or writing accurs.
6582 .seq_cst, .acquire => {
6583 _ = try func.addInst(.{
6584 .tag = .pseudo,
6585 .ops = .pseudo_fence,
6586 .data = .{
6587 .fence = .{
6588 .pred = .r,
6589 .succ = .rw,
6590 .fm = .none,
6591 },
6592 },
6593 });
6594 },
6595 else => unreachable,
6596 }
6597
6598 return func.finishAir(inst, result_mcv, .{ atomic_load.ptr, .none, .none });
6052}6599}
60536600
6054fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {6601fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
6055 _ = inst;6602 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6056 _ = order;6603
6057 return func.fail("TODO implement airAtomicStore for {}", .{func.target.cpu.arch});6604 const ptr_ty = func.typeOf(bin_op.lhs);
6605 const ptr_mcv = try func.resolveInst(bin_op.lhs);
6606
6607 const val_ty = func.typeOf(bin_op.rhs);
6608 const val_mcv = try func.resolveInst(bin_op.rhs);
6609
6610 switch (order) {
6611 .unordered, .monotonic => {},
6612 .release, .seq_cst => {
6613 _ = try func.addInst(.{
6614 .tag = .pseudo,
6615 .ops = .pseudo_fence,
6616 .data = .{
6617 .fence = .{
6618 .pred = .rw,
6619 .succ = .w,
6620 .fm = .none,
6621 },
6622 },
6623 });
6624 },
6625 else => unreachable,
6626 }
6627
6628 try func.store(ptr_mcv, val_mcv, ptr_ty, val_ty);
6629 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
6058}6630}
60596631
6060fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {6632fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
...@@ -6441,18 +7013,39 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {...@@ -6441,18 +7013,39 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
64417013
6442fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {7014fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
6443 const pt = func.pt;7015 const pt = func.pt;
6444 const zcu = pt.zcu;7016 const gpa = func.gpa;
7017
7018 const owner_decl_index = pt.zcu.funcOwnerDeclIndex(func.func_index);
7019 const lf = func.bin_file;
7020 const src_loc = func.src_loc;
7021
7022 if (val.isUndef(pt.zcu)) {
7023 const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| {
7024 const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)});
7025 func.err_msg = msg;
7026 return error.CodegenFail;
7027 };
7028 switch (lf.tag) {
7029 .elf => {
7030 const elf_file = lf.cast(link.File.Elf).?;
7031 const local = elf_file.symbol(local_sym_index);
7032 return MCValue{ .undef = local.esym_index };
7033 },
7034 else => unreachable,
7035 }
7036 }
7037
6445 const result = try codegen.genTypedValue(7038 const result = try codegen.genTypedValue(
6446 func.bin_file,7039 lf,
6447 pt,7040 pt,
6448 func.src_loc,7041 src_loc,
6449 val,7042 val,
6450 zcu.funcOwnerDeclIndex(func.func_index),7043 owner_decl_index,
6451 );7044 );
6452 const mcv: MCValue = switch (result) {7045 const mcv: MCValue = switch (result) {
6453 .mcv => |mcv| switch (mcv) {7046 .mcv => |mcv| switch (mcv) {
6454 .none => .none,7047 .none => .none,
6455 .undef => .undef,7048 .undef => unreachable,
6456 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },7049 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
6457 .immediate => |imm| .{ .immediate = imm },7050 .immediate => |imm| .{ .immediate = imm },
6458 .memory => |addr| .{ .memory = addr },7051 .memory => |addr| .{ .memory = addr },
...@@ -6670,9 +7263,7 @@ fn parseRegName(name: []const u8) ?Register {...@@ -6670,9 +7263,7 @@ fn parseRegName(name: []const u8) ?Register {
6670}7263}
66717264
6672fn typeOf(func: *Func, inst: Air.Inst.Ref) Type {7265fn typeOf(func: *Func, inst: Air.Inst.Ref) Type {
6673 const pt = func.pt;7266 return func.air.typeOf(inst, &func.pt.zcu.intern_pool);
6674 const zcu = pt.zcu;
6675 return func.air.typeOf(inst, &zcu.intern_pool);
6676}7267}
66777268
6678fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type {7269fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type {
src/arch/riscv64/Emit.zig+2-2
...@@ -26,7 +26,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -26,7 +26,7 @@ pub fn emitMir(emit: *Emit) Error!void {
26 mir_index,26 mir_index,
27 @intCast(emit.code.items.len),27 @intCast(emit.code.items.len),
28 );28 );
29 const lowered = try emit.lower.lowerMir(mir_index);29 const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true });
30 var lowered_relocs = lowered.relocs;30 var lowered_relocs = lowered.relocs;
31 for (lowered.insts, 0..) |lowered_inst, lowered_index| {31 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
32 const start_offset: u32 = @intCast(emit.code.items.len);32 const start_offset: u32 = @intCast(emit.code.items.len);
...@@ -75,7 +75,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -75,7 +75,7 @@ pub fn emitMir(emit: *Emit) Error!void {
75 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,75 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,
76 .r_addend = 0,76 .r_addend = 0,
77 });77 });
78 } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{});78 } else unreachable;
79 },79 },
80 .call_extern_fn_reloc => |symbol| {80 .call_extern_fn_reloc => |symbol| {
81 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {81 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
src/arch/riscv64/Encoding.zig+376-40
...@@ -2,37 +2,55 @@ mnemonic: Mnemonic,...@@ -2,37 +2,55 @@ mnemonic: Mnemonic,
2data: Data,2data: Data,
33
4const OpCode = enum(u7) {4const OpCode = enum(u7) {
5 OP = 0b0110011,5 LOAD = 0b0000011,
6 LOAD_FP = 0b0000111,
7 MISC_MEM = 0b0001111,
6 OP_IMM = 0b0010011,8 OP_IMM = 0b0010011,
9 AUIPC = 0b0010111,
7 OP_IMM_32 = 0b0011011,10 OP_IMM_32 = 0b0011011,
8 OP_32 = 0b0111011,
9
10 BRANCH = 0b1100011,
11 LOAD = 0b0000011,
12 STORE = 0b0100011,11 STORE = 0b0100011,
13 SYSTEM = 0b1110011,
14
15 OP_FP = 0b1010011,
16 LOAD_FP = 0b0000111,
17 STORE_FP = 0b0100111,12 STORE_FP = 0b0100111,
1813 AMO = 0b0101111,
19 JALR = 0b1100111,14 OP_V = 0b1010111,
20 AUIPC = 0b0010111,15 OP = 0b0110011,
16 OP_32 = 0b0111011,
21 LUI = 0b0110111,17 LUI = 0b0110111,
18 MADD = 0b1000011,
19 MSUB = 0b1000111,
20 NMSUB = 0b1001011,
21 NMADD = 0b1001111,
22 OP_FP = 0b1010011,
23 OP_IMM_64 = 0b1011011,
24 BRANCH = 0b1100011,
25 JALR = 0b1100111,
22 JAL = 0b1101111,26 JAL = 0b1101111,
23 NONE = 0b0000000,27 SYSTEM = 0b1110011,
28 OP_64 = 0b1111011,
29 NONE = 0b00000000,
24};30};
2531
26const Fmt = enum(u2) {32const FpFmt = enum(u2) {
27 /// 32-bit single-precision33 /// 32-bit single-precision
28 S = 0b00,34 S = 0b00,
29 /// 64-bit double-precision35 /// 64-bit double-precision
30 D = 0b01,36 D = 0b01,
31 _reserved = 0b10,37
38 // H = 0b10, unused in the G extension
39
32 /// 128-bit quad-precision40 /// 128-bit quad-precision
33 Q = 0b11,41 Q = 0b11,
34};42};
3543
44const AmoWidth = enum(u3) {
45 W = 0b010,
46 D = 0b011,
47};
48
49const FenceMode = enum(u4) {
50 none = 0b0000,
51 tso = 0b1000,
52};
53
36const Enc = struct {54const Enc = struct {
37 opcode: OpCode,55 opcode: OpCode,
3856
...@@ -42,11 +60,19 @@ const Enc = struct {...@@ -42,11 +60,19 @@ const Enc = struct {
42 funct3: u3,60 funct3: u3,
43 funct7: u7,61 funct7: u7,
44 },62 },
63 amo: struct {
64 funct5: u5,
65 width: AmoWidth,
66 },
67 fence: struct {
68 funct3: u3,
69 fm: FenceMode,
70 },
45 /// funct5 + rm + fmt71 /// funct5 + rm + fmt
46 fmt: struct {72 fmt: struct {
47 funct5: u5,73 funct5: u5,
48 rm: u3,74 rm: u3,
49 fmt: Fmt,75 fmt: FpFmt,
50 },76 },
51 /// funct377 /// funct3
52 f: struct {78 f: struct {
...@@ -58,9 +84,55 @@ const Enc = struct {...@@ -58,9 +84,55 @@ const Enc = struct {
58 funct3: u3,84 funct3: u3,
59 has_5: bool,85 has_5: bool,
60 },86 },
87 vecls: struct {
88 width: VecWidth,
89 umop: Umop,
90 vm: bool,
91 mop: Mop,
92 mew: bool,
93 nf: u3,
94 },
95 vecmath: struct {
96 vm: bool,
97 funct6: u6,
98 funct3: VecType,
99 },
61 /// U-type100 /// U-type
62 none,101 none,
63 },102 },
103
104 const Mop = enum(u2) {
105 unit = 0b00,
106 unord = 0b01,
107 stride = 0b10,
108 ord = 0b11,
109 };
110
111 const Umop = enum(u5) {
112 unit = 0b00000,
113 whole = 0b01000,
114 mask = 0b01011,
115 fault = 0b10000,
116 };
117
118 const VecWidth = enum(u3) {
119 // zig fmt: off
120 @"8" = 0b000,
121 @"16" = 0b101,
122 @"32" = 0b110,
123 @"64" = 0b111,
124 // zig fmt: on
125 };
126
127 const VecType = enum(u3) {
128 OPIVV = 0b000,
129 OPFVV = 0b001,
130 OPMVV = 0b010,
131 OPIVI = 0b011,
132 OPIVX = 0b100,
133 OPFVF = 0b101,
134 OPMVX = 0b110,
135 };
64};136};
65137
66pub const Mnemonic = enum {138pub const Mnemonic = enum {
...@@ -90,6 +162,9 @@ pub const Mnemonic = enum {...@@ -90,6 +162,9 @@ pub const Mnemonic = enum {
90 addi,162 addi,
91 jalr,163 jalr,
92164
165 vsetivli,
166 vsetvli,
167
93 // U Type168 // U Type
94 lui,169 lui,
95 auipc,170 auipc,
...@@ -130,6 +205,8 @@ pub const Mnemonic = enum {...@@ -130,6 +205,8 @@ pub const Mnemonic = enum {
130 ebreak,205 ebreak,
131 unimp,206 unimp,
132207
208 csrrs,
209
133 // M extension210 // M extension
134 mul,211 mul,
135 mulw,212 mulw,
...@@ -192,6 +269,58 @@ pub const Mnemonic = enum {...@@ -192,6 +269,58 @@ pub const Mnemonic = enum {
192 fsgnjnd,269 fsgnjnd,
193 fsgnjxd,270 fsgnjxd,
194271
272 // V Extension
273 vle8v,
274 vle16v,
275 vle32v,
276 vle64v,
277
278 vse8v,
279 vse16v,
280 vse32v,
281 vse64v,
282
283 vsoxei8v,
284
285 vaddvv,
286 vsubvv,
287
288 vfaddvv,
289 vfsubvv,
290
291 vadcvv,
292
293 vmvvx,
294
295 vslidedownvx,
296
297 // MISC
298 fence,
299 fencetso,
300
301 // AMO
302 amoswapw,
303 amoaddw,
304 amoandw,
305 amoorw,
306 amoxorw,
307 amomaxw,
308 amominw,
309 amomaxuw,
310 amominuw,
311
312 amoswapd,
313 amoaddd,
314 amoandd,
315 amoord,
316 amoxord,
317 amomaxd,
318 amomind,
319 amomaxud,
320 amominud,
321
322 // TODO: Q extension
323
195 pub fn encoding(mnem: Mnemonic) Enc {324 pub fn encoding(mnem: Mnemonic) Enc {
196 return switch (mnem) {325 return switch (mnem) {
197 // zig fmt: off326 // zig fmt: off
...@@ -322,14 +451,25 @@ pub const Mnemonic = enum {...@@ -322,14 +451,25 @@ pub const Mnemonic = enum {
322 // LOAD_FP451 // LOAD_FP
323452
324 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },453 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
325 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },454 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
455
456 .vle8v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
457 .vle16v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
458 .vle32v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
459 .vle64v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
326 460
327461
328 // STORE_FP462 // STORE_FP
329463
330 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },464 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
331 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },465 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
332466
467 .vse8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
468 .vse16v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
469 .vse32v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
470 .vse64v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
471
472 .vsoxei8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .ord, .mew = false, .nf = 0b000 } } },
333473
334 // JALR474 // JALR
335475
...@@ -360,6 +500,8 @@ pub const Mnemonic = enum {...@@ -360,6 +500,8 @@ pub const Mnemonic = enum {
360500
361 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },501 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
362 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },502 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
503
504 .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } },
363 505
364506
365 // NONE507 // NONE
...@@ -367,6 +509,52 @@ pub const Mnemonic = enum {...@@ -367,6 +509,52 @@ pub const Mnemonic = enum {
367 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },509 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
368510
369511
512 // MISC_MEM
513
514 .fence => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } },
515 .fencetso => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } },
516
517
518 // AMO
519
520 .amoaddw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } },
521 .amoswapw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } },
522 // LR.W
523 // SC.W
524 .amoxorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } },
525 .amoandw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } },
526 .amoorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } },
527 .amominw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } },
528 .amomaxw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } },
529 .amominuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } },
530 .amomaxuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } },
531
532 .amoaddd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } },
533 .amoswapd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } },
534 // LR.D
535 // SC.D
536 .amoxord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } },
537 .amoandd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } },
538 .amoord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } },
539 .amomind => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } },
540 .amomaxd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } },
541 .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
542 .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
543
544 // OP_V
545 .vsetivli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
546 .vsetvli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
547 .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
548 .vsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },
549
550 .vfaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPFVV } } },
551 .vfsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPFVV } } },
552
553 .vadcvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
554 .vmvvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },
555
556 .vslidedownvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b001111, .funct3 = .OPIVX } } },
557
370 // zig fmt: on558 // zig fmt: on
371 };559 };
372 }560 }
...@@ -380,8 +568,8 @@ pub const InstEnc = enum {...@@ -380,8 +568,8 @@ pub const InstEnc = enum {
380 B,568 B,
381 U,569 U,
382 J,570 J,
383571 fence,
384 /// extras that have unusual op counts572 amo,
385 system,573 system,
386574
387 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {575 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
...@@ -410,6 +598,10 @@ pub const InstEnc = enum {...@@ -410,6 +598,10 @@ pub const InstEnc = enum {
410598
411 .flw,599 .flw,
412 .fld,600 .fld,
601
602 .csrrs,
603 .vsetivli,
604 .vsetvli,
413 => .I,605 => .I,
414606
415 .lui,607 .lui,
...@@ -503,26 +695,73 @@ pub const InstEnc = enum {...@@ -503,26 +695,73 @@ pub const InstEnc = enum {
503695
504 .fsgnjxs,696 .fsgnjxs,
505 .fsgnjxd,697 .fsgnjxd,
698
699 .vle8v,
700 .vle16v,
701 .vle32v,
702 .vle64v,
703
704 .vse8v,
705 .vse16v,
706 .vse32v,
707 .vse64v,
708
709 .vsoxei8v,
710
711 .vaddvv,
712 .vsubvv,
713 .vfaddvv,
714 .vfsubvv,
715 .vadcvv,
716 .vmvvx,
717 .vslidedownvx,
506 => .R,718 => .R,
507719
508 .ecall,720 .ecall,
509 .ebreak,721 .ebreak,
510 .unimp,722 .unimp,
511 => .system,723 => .system,
724
725 .fence,
726 .fencetso,
727 => .fence,
728
729 .amoswapw,
730 .amoaddw,
731 .amoandw,
732 .amoorw,
733 .amoxorw,
734 .amomaxw,
735 .amominw,
736 .amomaxuw,
737 .amominuw,
738
739 .amoswapd,
740 .amoaddd,
741 .amoandd,
742 .amoord,
743 .amoxord,
744 .amomaxd,
745 .amomind,
746 .amomaxud,
747 .amominud,
748 => .amo,
512 };749 };
513 }750 }
514751
515 pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {752 pub fn opsList(enc: InstEnc) [5]std.meta.FieldEnum(Operand) {
516 return switch (enc) {753 return switch (enc) {
517 // zig fmt: off754 // zig fmt: off
518 .R => .{ .reg, .reg, .reg, .none },755 .R => .{ .reg, .reg, .reg, .none, .none, },
519 .R4 => .{ .reg, .reg, .reg, .reg }, 756 .R4 => .{ .reg, .reg, .reg, .reg, .none, },
520 .I => .{ .reg, .reg, .imm, .none },757 .I => .{ .reg, .reg, .imm, .none, .none, },
521 .S => .{ .reg, .reg, .imm, .none },758 .S => .{ .reg, .reg, .imm, .none, .none, },
522 .B => .{ .reg, .reg, .imm, .none },759 .B => .{ .reg, .reg, .imm, .none, .none, },
523 .U => .{ .reg, .imm, .none, .none },760 .U => .{ .reg, .imm, .none, .none, .none, },
524 .J => .{ .reg, .imm, .none, .none },761 .J => .{ .reg, .imm, .none, .none, .none, },
525 .system => .{ .none, .none, .none, .none },762 .system => .{ .none, .none, .none, .none, .none, },
763 .fence => .{ .barrier, .barrier, .none, .none, .none, },
764 .amo => .{ .reg, .reg, .reg, .barrier, .barrier },
526 // zig fmt: on765 // zig fmt: on
527 };766 };
528 }767 }
...@@ -584,20 +823,38 @@ pub const Data = union(InstEnc) {...@@ -584,20 +823,38 @@ pub const Data = union(InstEnc) {
584 imm1_10: u10,823 imm1_10: u10,
585 imm20: u1,824 imm20: u1,
586 },825 },
587 system: void,826 fence: packed struct {
827 opcode: u7,
828 rd: u5 = 0,
829 funct3: u3,
830 rs1: u5 = 0,
831 succ: u4,
832 pred: u4,
833 fm: u4,
834 },
835 amo: packed struct {
836 opcode: u7,
837 rd: u5,
838 funct3: u3,
839 rs1: u5,
840 rs2: u5,
841 rl: bool,
842 aq: bool,
843 funct5: u5,
844 },
845 system: u32,
846
847 comptime {
848 for (std.meta.fields(Data)) |field| {
849 assert(@bitSizeOf(field.type) == 32);
850 }
851 }
588852
589 pub fn toU32(self: Data) u32 {853 pub fn toU32(self: Data) u32 {
590 return switch (self) {854 return switch (self) {
591 // zig fmt: off855 .fence => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.rd)) << 7) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.succ)) << 20) + (@as(u32, @intCast(v.pred)) << 24) + (@as(u32, @intCast(v.fm)) << 28),
592 .R => |v| @bitCast(v),856 inline else => |v| @bitCast(v),
593 .R4 => |v| @bitCast(v),
594 .I => |v| @bitCast(v),
595 .S => |v| @bitCast(v),
596 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),
597 .U => |v| @bitCast(v),
598 .J => |v| @bitCast(v),
599 .system => unreachable,857 .system => unreachable,
600 // zig fmt: on
601 };858 };
602 }859 }
603860
...@@ -628,6 +885,25 @@ pub const Data = union(InstEnc) {...@@ -628,6 +885,25 @@ pub const Data = union(InstEnc) {
628 },885 },
629 };886 };
630 },887 },
888 .csrrs => {
889 assert(ops.len == 3);
890
891 const csr = ops[0].csr;
892 const rs1 = ops[1].reg;
893 const rd = ops[2].reg;
894
895 return .{
896 .I = .{
897 .rd = rd.encodeId(),
898 .rs1 = rs1.encodeId(),
899
900 .imm0_11 = @intFromEnum(csr),
901
902 .opcode = @intFromEnum(enc.opcode),
903 .funct3 = enc.data.f.funct3,
904 },
905 };
906 },
631 else => {},907 else => {},
632 }908 }
633909
...@@ -654,6 +930,25 @@ pub const Data = union(InstEnc) {...@@ -654,6 +930,25 @@ pub const Data = union(InstEnc) {
654 .funct3 = fmt.rm,930 .funct3 = fmt.rm,
655 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),931 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
656 },932 },
933 .vecls => |vec| .{
934 .rd = ops[0].reg.encodeId(),
935 .rs1 = ops[1].reg.encodeId(),
936
937 .rs2 = @intFromEnum(vec.umop),
938
939 .opcode = @intFromEnum(enc.opcode),
940 .funct3 = @intFromEnum(vec.width),
941 .funct7 = (@as(u7, vec.nf) << 4) | (@as(u7, @intFromBool(vec.mew)) << 3) | (@as(u7, @intFromEnum(vec.mop)) << 1) | @intFromBool(vec.vm),
942 },
943 .vecmath => |vec| .{
944 .rd = ops[0].reg.encodeId(),
945 .rs1 = ops[1].reg.encodeId(),
946 .rs2 = ops[2].reg.encodeId(),
947
948 .opcode = @intFromEnum(enc.opcode),
949 .funct3 = @intFromEnum(vec.funct3),
950 .funct7 = (@as(u7, vec.funct6) << 1) | @intFromBool(vec.vm),
951 },
657 else => unreachable,952 else => unreachable,
658 },953 },
659 };954 };
...@@ -748,7 +1043,48 @@ pub const Data = union(InstEnc) {...@@ -748,7 +1043,48 @@ pub const Data = union(InstEnc) {
748 },1043 },
749 };1044 };
750 },1045 },
1046 .fence => {
1047 assert(ops.len == 2);
1048
1049 const succ = ops[0].barrier;
1050 const pred = ops[1].barrier;
1051
1052 return .{
1053 .fence = .{
1054 .succ = @intFromEnum(succ),
1055 .pred = @intFromEnum(pred),
1056
1057 .opcode = @intFromEnum(enc.opcode),
1058 .funct3 = enc.data.fence.funct3,
1059 .fm = @intFromEnum(enc.data.fence.fm),
1060 },
1061 };
1062 },
1063 .amo => {
1064 assert(ops.len == 5);
1065
1066 const rd = ops[0].reg;
1067 const rs1 = ops[1].reg;
1068 const rs2 = ops[2].reg;
1069 const rl = ops[3].barrier;
1070 const aq = ops[4].barrier;
7511071
1072 return .{
1073 .amo = .{
1074 .rd = rd.encodeId(),
1075 .rs1 = rs1.encodeId(),
1076 .rs2 = rs2.encodeId(),
1077
1078 // TODO: https://github.com/ziglang/zig/issues/20113
1079 .rl = if (rl == .rl) true else false,
1080 .aq = if (aq == .aq) true else false,
1081
1082 .opcode = @intFromEnum(enc.opcode),
1083 .funct3 = @intFromEnum(enc.data.amo.width),
1084 .funct5 = enc.data.amo.funct5,
1085 },
1086 };
1087 },
752 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),1088 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
753 }1089 }
754 }1090 }
src/arch/riscv64/Lower.zig+171-59
...@@ -40,7 +40,9 @@ pub const Reloc = struct {...@@ -40,7 +40,9 @@ pub const Reloc = struct {
40};40};
4141
42/// The returned slice is overwritten by the next call to lowerMir.42/// The returned slice is overwritten by the next call to lowerMir.
43pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {43pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
44 allow_frame_locs: bool,
45}) Error!struct {
44 insts: []const Instruction,46 insts: []const Instruction,
45 relocs: []const Reloc,47 relocs: []const Reloc,
46} {48} {
...@@ -69,64 +71,102 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -69,64 +71,102 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
69 .pseudo_load_rm, .pseudo_store_rm => {71 .pseudo_load_rm, .pseudo_store_rm => {
70 const rm = inst.data.rm;72 const rm = inst.data.rm;
7173
72 const frame_loc = rm.m.toFrameLoc(lower.mir);74 const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs)
75 rm.m.toFrameLoc(lower.mir)
76 else
77 .{ .base = .s0, .disp = 0 };
7378
74 switch (inst.ops) {79 switch (inst.ops) {
75 .pseudo_load_rm => {80 .pseudo_load_rm => {
76 const dest_reg = rm.r;81 const dest_reg = rm.r;
77 const dest_reg_class = dest_reg.class();82 const dest_reg_class = dest_reg.class();
78 const float = dest_reg_class == .float;
7983
80 const src_size = rm.m.mod.size;84 const src_size = rm.m.mod.size;
81 const unsigned = rm.m.mod.unsigned;85 const unsigned = rm.m.mod.unsigned;
8286
83 const tag: Encoding.Mnemonic = if (!float)87 const tag: Encoding.Mnemonic = switch (dest_reg_class) {
84 switch (src_size) {88 .int => switch (src_size) {
85 .byte => if (unsigned) .lbu else .lb,89 .byte => if (unsigned) .lbu else .lb,
86 .hword => if (unsigned) .lhu else .lh,90 .hword => if (unsigned) .lhu else .lh,
87 .word => if (unsigned) .lwu else .lw,91 .word => if (unsigned) .lwu else .lw,
88 .dword => .ld,92 .dword => .ld,
89 }93 },
90 else switch (src_size) {94 .float => switch (src_size) {
91 .byte => unreachable, // Zig does not support 8-bit floats95 .byte => unreachable, // Zig does not support 8-bit floats
92 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),96 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
93 .word => .flw,97 .word => .flw,
94 .dword => .fld,98 .dword => .fld,
99 },
100 .vector => switch (src_size) {
101 .byte => .vle8v,
102 .hword => .vle32v,
103 .word => .vle32v,
104 .dword => .vle64v,
105 },
95 };106 };
96107
97 try lower.emit(tag, &.{108 switch (dest_reg_class) {
98 .{ .reg = rm.r },109 .int, .float => {
99 .{ .reg = frame_loc.base },110 try lower.emit(tag, &.{
100 .{ .imm = Immediate.s(frame_loc.disp) },111 .{ .reg = rm.r },
101 });112 .{ .reg = frame_loc.base },
113 .{ .imm = Immediate.s(frame_loc.disp) },
114 });
115 },
116 .vector => {
117 assert(frame_loc.disp == 0);
118 try lower.emit(tag, &.{
119 .{ .reg = rm.r },
120 .{ .reg = frame_loc.base },
121 .{ .reg = .zero },
122 });
123 },
124 }
102 },125 },
103 .pseudo_store_rm => {126 .pseudo_store_rm => {
104 const src_reg = rm.r;127 const src_reg = rm.r;
105 const src_reg_class = src_reg.class();128 const src_reg_class = src_reg.class();
106 const float = src_reg_class == .float;
107129
108 // TODO: do we actually need this? are all stores not usize?
109 const dest_size = rm.m.mod.size;130 const dest_size = rm.m.mod.size;
110131
111 const tag: Encoding.Mnemonic = if (!float)132 const tag: Encoding.Mnemonic = switch (src_reg_class) {
112 switch (dest_size) {133 .int => switch (dest_size) {
113 .byte => .sb,134 .byte => .sb,
114 .hword => .sh,135 .hword => .sh,
115 .word => .sw,136 .word => .sw,
116 .dword => .sd,137 .dword => .sd,
117 }138 },
118 else switch (dest_size) {139 .float => switch (dest_size) {
119 .byte => unreachable, // Zig does not support 8-bit floats140 .byte => unreachable, // Zig does not support 8-bit floats
120 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),141 .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}),
121 .word => .fsw,142 .word => .fsw,
122 .dword => .fsd,143 .dword => .fsd,
144 },
145 .vector => switch (dest_size) {
146 .byte => .vse8v,
147 .hword => .vse16v,
148 .word => .vse32v,
149 .dword => .vse64v,
150 },
123 };151 };
124152
125 try lower.emit(tag, &.{153 switch (src_reg_class) {
126 .{ .reg = frame_loc.base },154 .int, .float => {
127 .{ .reg = rm.r },155 try lower.emit(tag, &.{
128 .{ .imm = Immediate.s(frame_loc.disp) },156 .{ .reg = frame_loc.base },
129 });157 .{ .reg = rm.r },
158 .{ .imm = Immediate.s(frame_loc.disp) },
159 });
160 },
161 .vector => {
162 assert(frame_loc.disp == 0);
163 try lower.emit(tag, &.{
164 .{ .reg = rm.r },
165 .{ .reg = frame_loc.base },
166 .{ .reg = .zero },
167 });
168 },
169 }
130 },170 },
131 else => unreachable,171 else => unreachable,
132 }172 }
...@@ -138,34 +178,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -138,34 +178,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
138 const dst_class = rr.rd.class();178 const dst_class = rr.rd.class();
139 const src_class = rr.rs.class();179 const src_class = rr.rs.class();
140180
141 assert(dst_class == src_class);181 switch (src_class) {
142182 .float => switch (dst_class) {
143 switch (dst_class) {183 .float => {
144 .float => {184 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
145 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{185 .{ .reg = rr.rd },
146 .{ .reg = rr.rd },186 .{ .reg = rr.rs },
147 .{ .reg = rr.rs },187 .{ .reg = rr.rs },
148 .{ .reg = rr.rs },188 });
149 });189 },
190 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),
150 },191 },
151 .int => {192 .int => switch (dst_class) {
152 try lower.emit(.addi, &.{193 .int => {
153 .{ .reg = rr.rd },194 try lower.emit(.addi, &.{
154 .{ .reg = rr.rs },195 .{ .reg = rr.rd },
155 .{ .imm = Immediate.s(0) },196 .{ .reg = rr.rs },
156 });197 .{ .imm = Immediate.s(0) },
198 });
199 },
200 .vector => {
201 try lower.emit(.vmvvx, &.{
202 .{ .reg = rr.rd },
203 .{ .reg = rr.rs },
204 .{ .reg = .x0 },
205 });
206 },
207 .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}),
208 },
209 .vector => switch (dst_class) {
210 .int => {
211 try lower.emit(.vadcvv, &.{
212 .{ .reg = rr.rd },
213 .{ .reg = .zero },
214 .{ .reg = rr.rs },
215 });
216 },
217 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),
157 },218 },
158 }219 }
159 },220 },
160221
161 .pseudo_ret => {
162 try lower.emit(.jalr, &.{
163 .{ .reg = .zero },
164 .{ .reg = .ra },
165 .{ .imm = Immediate.s(0) },
166 });
167 },
168
169 .pseudo_j => {222 .pseudo_j => {
170 try lower.emit(.jal, &.{223 try lower.emit(.jal, &.{
171 .{ .reg = .zero },224 .{ .reg = .zero },
...@@ -204,7 +257,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -204,7 +257,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
204 const rm = inst.data.rm;257 const rm = inst.data.rm;
205 assert(rm.r.class() == .int);258 assert(rm.r.class() == .int);
206259
207 const frame = rm.m.toFrameLoc(lower.mir);260 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
261 rm.m.toFrameLoc(lower.mir)
262 else
263 .{ .base = .s0, .disp = 0 };
208264
209 try lower.emit(.addi, &.{265 try lower.emit(.addi, &.{
210 .{ .reg = rm.r },266 .{ .reg = rm.r },
...@@ -371,6 +427,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -371,6 +427,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
371 });427 });
372 },428 },
373 },429 },
430 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),
374 }431 }
375 },432 },
376433
...@@ -378,7 +435,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -378,7 +435,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
378 const rr = inst.data.rr;435 const rr = inst.data.rr;
379 assert(rr.rs.class() == .int and rr.rd.class() == .int);436 assert(rr.rs.class() == .int and rr.rd.class() == .int);
380437
381 try lower.emit(.xori, &.{438 // mask out any other bits that aren't the boolean
439 try lower.emit(.andi, &.{
440 .{ .reg = rr.rs },
441 .{ .reg = rr.rs },
442 .{ .imm = Immediate.s(1) },
443 });
444
445 try lower.emit(.sltiu, &.{
382 .{ .reg = rr.rd },446 .{ .reg = rr.rd },
383 .{ .reg = rr.rs },447 .{ .reg = rr.rs },
384 .{ .imm = Immediate.s(1) },448 .{ .imm = Immediate.s(1) },
...@@ -405,6 +469,44 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -405,6 +469,44 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
405 });469 });
406 },470 },
407471
472 .pseudo_amo => {
473 const amo = inst.data.amo;
474 const is_d = amo.ty.abiSize(pt) == 8;
475 const is_un = amo.ty.isUnsignedInt(pt.zcu);
476
477 const mnem: Encoding.Mnemonic = switch (amo.op) {
478 // zig fmt: off
479 .SWAP => if (is_d) .amoswapd else .amoswapw,
480 .ADD => if (is_d) .amoaddd else .amoaddw,
481 .AND => if (is_d) .amoandd else .amoandw,
482 .OR => if (is_d) .amoord else .amoorw,
483 .XOR => if (is_d) .amoxord else .amoxorw,
484 .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw,
485 .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw,
486 // zig fmt: on
487 };
488
489 try lower.emit(mnem, &.{
490 .{ .reg = inst.data.amo.rd },
491 .{ .reg = inst.data.amo.rs1 },
492 .{ .reg = inst.data.amo.rs2 },
493 .{ .barrier = inst.data.amo.rl },
494 .{ .barrier = inst.data.amo.aq },
495 });
496 },
497
498 .pseudo_fence => {
499 const fence = inst.data.fence;
500
501 try lower.emit(switch (fence.fm) {
502 .tso => .fencetso,
503 .none => .fence,
504 }, &.{
505 .{ .barrier = fence.succ },
506 .{ .barrier = fence.pred },
507 });
508 },
509
408 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),510 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
409 },511 },
410 }512 }
...@@ -447,6 +549,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -447,6 +549,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
447 .{ .reg = inst.data.r_type.rs1 },549 .{ .reg = inst.data.r_type.rs1 },
448 .{ .reg = inst.data.r_type.rs2 },550 .{ .reg = inst.data.r_type.rs2 },
449 },551 },
552 .csr => &.{
553 .{ .csr = inst.data.csr.csr },
554 .{ .reg = inst.data.csr.rs1 },
555 .{ .reg = inst.data.csr.rd },
556 },
450 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),557 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
451 });558 });
452}559}
...@@ -473,17 +580,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register...@@ -473,17 +580,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
473 while (it.next()) |i| {580 while (it.next()) |i| {
474 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));581 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));
475 const reg = abi.Registers.all_preserved[i];582 const reg = abi.Registers.all_preserved[i];
583
476 const reg_class = reg.class();584 const reg_class = reg.class();
477 const is_float_reg = reg_class == .float;585 const load_inst: Encoding.Mnemonic, const store_inst: Encoding.Mnemonic = switch (reg_class) {
586 .int => .{ .ld, .sd },
587 .float => .{ .fld, .fsd },
588 .vector => unreachable,
589 };
478590
479 if (spilling) {591 if (spilling) {
480 try lower.emit(if (is_float_reg) .fsd else .sd, &.{592 try lower.emit(store_inst, &.{
481 .{ .reg = frame.base },593 .{ .reg = frame.base },
482 .{ .reg = abi.Registers.all_preserved[i] },594 .{ .reg = abi.Registers.all_preserved[i] },
483 .{ .imm = Immediate.s(frame.disp + reg_i) },595 .{ .imm = Immediate.s(frame.disp + reg_i) },
484 });596 });
485 } else {597 } else {
486 try lower.emit(if (is_float_reg) .fld else .ld, &.{598 try lower.emit(load_inst, &.{
487 .{ .reg = abi.Registers.all_preserved[i] },599 .{ .reg = abi.Registers.all_preserved[i] },
488 .{ .reg = frame.base },600 .{ .reg = frame.base },
489 .{ .imm = Immediate.s(frame.disp + reg_i) },601 .{ .imm = Immediate.s(frame.disp + reg_i) },
src/arch/riscv64/Mir.zig+70-48
...@@ -31,6 +31,7 @@ pub const Inst = struct {...@@ -31,6 +31,7 @@ pub const Inst = struct {
31 @"and",31 @"and",
32 andi,32 andi,
3333
34 xori,
34 xor,35 xor,
35 @"or",36 @"or",
3637
...@@ -133,6 +134,19 @@ pub const Inst = struct {...@@ -133,6 +134,19 @@ pub const Inst = struct {
133 fltd,134 fltd,
134 fled,135 fled,
135136
137 // Zicsr Extension Instructions
138 csrrs,
139
140 // V Extension Instructions
141 vsetvli,
142 vsetivli,
143 vsetvl,
144 vaddvv,
145 vfaddvv,
146 vsubvv,
147 vfsubvv,
148 vslidedownvx,
149
136 /// A pseudo-instruction. Used for anything that isn't 1:1 with an150 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
137 /// assembly instruction.151 /// assembly instruction.
138 pseudo,152 pseudo,
...@@ -142,91 +156,57 @@ pub const Inst = struct {...@@ -142,91 +156,57 @@ pub const Inst = struct {
142 /// this union. `Ops` determines which union field is active, as well as156 /// this union. `Ops` determines which union field is active, as well as
143 /// how to interpret the data within.157 /// how to interpret the data within.
144 pub const Data = union {158 pub const Data = union {
145 /// No additional data
146 ///
147 /// Used by e.g. ebreak
148 nop: void,159 nop: void,
149 /// Another instruction.
150 ///
151 /// Used by e.g. b
152 inst: Index,160 inst: Index,
153 /// Index into `extra`. Meaning of what can be found there is context-dependent.
154 ///
155 /// Used by e.g. load_memory
156 payload: u32,161 payload: u32,
157
158 r_type: struct {162 r_type: struct {
159 rd: Register,163 rd: Register,
160 rs1: Register,164 rs1: Register,
161 rs2: Register,165 rs2: Register,
162 },166 },
163
164 i_type: struct {167 i_type: struct {
165 rd: Register,168 rd: Register,
166 rs1: Register,169 rs1: Register,
167 imm12: Immediate,170 imm12: Immediate,
168 },171 },
169
170 s_type: struct {172 s_type: struct {
171 rs1: Register,173 rs1: Register,
172 rs2: Register,174 rs2: Register,
173 imm5: Immediate,175 imm5: Immediate,
174 imm7: Immediate,176 imm7: Immediate,
175 },177 },
176
177 b_type: struct {178 b_type: struct {
178 rs1: Register,179 rs1: Register,
179 rs2: Register,180 rs2: Register,
180 inst: Inst.Index,181 inst: Inst.Index,
181 },182 },
182
183 u_type: struct {183 u_type: struct {
184 rd: Register,184 rd: Register,
185 imm20: Immediate,185 imm20: Immediate,
186 },186 },
187
188 j_type: struct {187 j_type: struct {
189 rd: Register,188 rd: Register,
190 inst: Inst.Index,189 inst: Inst.Index,
191 },190 },
192
193 /// Debug info: line and column
194 ///
195 /// Used by e.g. pseudo_dbg_line
196 pseudo_dbg_line_column: struct {191 pseudo_dbg_line_column: struct {
197 line: u32,192 line: u32,
198 column: u32,193 column: u32,
199 },194 },
200
201 // Custom types to be lowered
202
203 /// Register + Memory
204 rm: struct {195 rm: struct {
205 r: Register,196 r: Register,
206 m: Memory,197 m: Memory,
207 },198 },
208
209 reg_list: Mir.RegisterList,199 reg_list: Mir.RegisterList,
210
211 /// A register
212 ///
213 /// Used by e.g. blr
214 reg: Register,200 reg: Register,
215
216 /// Two registers
217 ///
218 /// Used by e.g. mv
219 rr: struct {201 rr: struct {
220 rd: Register,202 rd: Register,
221 rs: Register,203 rs: Register,
222 },204 },
223
224 fabs: struct {205 fabs: struct {
225 rd: Register,206 rd: Register,
226 rs: Register,207 rs: Register,
227 bits: u16,208 bits: u16,
228 },209 },
229
230 compare: struct {210 compare: struct {
231 rd: Register,211 rd: Register,
232 rs1: Register,212 rs1: Register,
...@@ -241,11 +221,32 @@ pub const Inst = struct {...@@ -241,11 +221,32 @@ pub const Inst = struct {
241 },221 },
242 ty: Type,222 ty: Type,
243 },223 },
244
245 reloc: struct {224 reloc: struct {
246 atom_index: u32,225 atom_index: u32,
247 sym_index: u32,226 sym_index: u32,
248 },227 },
228 fence: struct {
229 pred: Barrier,
230 succ: Barrier,
231 fm: enum {
232 none,
233 tso,
234 },
235 },
236 amo: struct {
237 rd: Register,
238 rs1: Register,
239 rs2: Register,
240 aq: Barrier,
241 rl: Barrier,
242 op: AmoOp,
243 ty: Type,
244 },
245 csr: struct {
246 csr: CSR,
247 rs1: Register,
248 rd: Register,
249 },
249 };250 };
250251
251 pub const Ops = enum {252 pub const Ops = enum {
...@@ -270,6 +271,9 @@ pub const Inst = struct {...@@ -270,6 +271,9 @@ pub const Inst = struct {
270 /// Another instruction.271 /// Another instruction.
271 inst,272 inst,
272273
274 /// Control and Status Register Instruction.
275 csr,
276
273 /// Pseudo-instruction that will generate a backpatched277 /// Pseudo-instruction that will generate a backpatched
274 /// function prologue.278 /// function prologue.
275 pseudo_prologue,279 pseudo_prologue,
...@@ -298,11 +302,6 @@ pub const Inst = struct {...@@ -298,11 +302,6 @@ pub const Inst = struct {
298 /// Uses `rm` payload.302 /// Uses `rm` payload.
299 pseudo_lea_rm,303 pseudo_lea_rm,
300304
301 /// Shorthand for returning, aka jumping to ra register.
302 ///
303 /// Uses nop payload.
304 pseudo_ret,
305
306 /// Jumps. Uses `inst` payload.305 /// Jumps. Uses `inst` payload.
307 pseudo_j,306 pseudo_j,
308307
...@@ -326,19 +325,19 @@ pub const Inst = struct {...@@ -326,19 +325,19 @@ pub const Inst = struct {
326 pseudo_spill_regs,325 pseudo_spill_regs,
327326
328 pseudo_compare,327 pseudo_compare,
328
329 /// NOT operation on booleans. Does an `andi reg, reg, 1` to mask out any other bits from the boolean.
329 pseudo_not,330 pseudo_not,
330331
331 /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc332 /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc
332 pseudo_extern_fn_reloc,333 pseudo_extern_fn_reloc,
333 };
334334
335 // Make sure we don't accidentally make instructions bigger than expected.335 /// IORW, IORW
336 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.336 pseudo_fence,
337 // comptime {337
338 // if (builtin.mode != .Debug) {338 /// Ordering, Src, Addr, Dest
339 // assert(@sizeOf(Inst) == 8);339 pseudo_amo,
340 // }340 };
341 // }
342341
343 pub fn format(342 pub fn format(
344 inst: Inst,343 inst: Inst,
...@@ -365,6 +364,28 @@ pub const FrameLoc = struct {...@@ -365,6 +364,28 @@ pub const FrameLoc = struct {
365 disp: i32,364 disp: i32,
366};365};
367366
367pub const Barrier = enum(u4) {
368 // Fence
369 w = 0b0001,
370 r = 0b0010,
371 rw = 0b0011,
372
373 // Amo
374 none,
375 aq,
376 rl,
377};
378
379pub const AmoOp = enum(u5) {
380 SWAP,
381 ADD,
382 AND,
383 OR,
384 XOR,
385 MAX,
386 MIN,
387};
388
368/// Returns the requested data, as well as the new index which is at the start of the389/// Returns the requested data, as well as the new index which is at the start of the
369/// trailers for the object.390/// trailers for the object.
370pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {391pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
...@@ -437,6 +458,7 @@ const assert = std.debug.assert;...@@ -437,6 +458,7 @@ const assert = std.debug.assert;
437458
438const bits = @import("bits.zig");459const bits = @import("bits.zig");
439const Register = bits.Register;460const Register = bits.Register;
461const CSR = bits.CSR;
440const Immediate = bits.Immediate;462const Immediate = bits.Immediate;
441const Memory = bits.Memory;463const Memory = bits.Memory;
442const FrameIndex = bits.FrameIndex;464const FrameIndex = bits.FrameIndex;
src/arch/riscv64/abi.zig+24-2
...@@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass {...@@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass {
193 }193 }
194 return memory_class;194 return memory_class;
195 },195 },
196 .Vector => {
197 // we pass vectors through integer registers if they are small enough to fit.
198 const vec_bits = ty.totalVectorBits(pt);
199 if (vec_bits <= 64) {
200 result[0] = .integer;
201 return result;
202 }
203 return memory_class;
204 },
196 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),205 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
197 }206 }
198}207}
...@@ -254,15 +263,15 @@ fn classifyStruct(...@@ -254,15 +263,15 @@ fn classifyStruct(
254 }263 }
255}264}
256265
257const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs;266const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs ++ Registers.Vector.all_regs;
258pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);267pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
259268
260// Register classes
261const RegisterBitSet = RegisterManager.RegisterBitSet;269const RegisterBitSet = RegisterManager.RegisterBitSet;
262270
263pub const RegisterClass = enum {271pub const RegisterClass = enum {
264 int,272 int,
265 float,273 float,
274 vector,
266};275};
267276
268pub const Registers = struct {277pub const Registers = struct {
...@@ -322,6 +331,19 @@ pub const Registers = struct {...@@ -322,6 +331,19 @@ pub const Registers = struct {
322331
323 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;332 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
324 };333 };
334
335 pub const Vector = struct {
336 pub const general_purpose = initRegBitSet(Integer.all_regs.len + Float.all_regs.len, all_regs.len);
337
338 // zig fmt: off
339 pub const all_regs = [_]Register{
340 .v0, .v1, .v2, .v3, .v4, .v5, .v6, .v7,
341 .v8, .v9, .v10, .v11, .v12, .v13, .v14, .v15,
342 .v16, .v17, .v18, .v19, .v20, .v21, .v22, .v23,
343 .v24, .v25, .v26, .v27, .v28, .v29, .v30, .v31,
344 };
345 // zig fmt: on
346 };
325};347};
326348
327fn initRegBitSet(start: usize, length: usize) RegisterBitSet {349fn initRegBitSet(start: usize, length: usize) RegisterBitSet {
src/arch/riscv64/bits.zig+42-2
...@@ -41,7 +41,7 @@ pub const Memory = struct {...@@ -41,7 +41,7 @@ pub const Memory = struct {
41 2...2 => .hword,41 2...2 => .hword,
42 3...4 => .word,42 3...4 => .word,
43 5...8 => .dword,43 5...8 => .dword,
44 else => unreachable,44 else => std.debug.panic("fromByteSize {}", .{size}),
45 };45 };
46 }46 }
4747
...@@ -128,6 +128,12 @@ pub const Immediate = union(enum) {...@@ -128,6 +128,12 @@ pub const Immediate = union(enum) {
128 }128 }
129};129};
130130
131pub const CSR = enum(u12) {
132 vl = 0xC20,
133 vtype = 0xC21,
134 vlenb = 0xC22,
135};
136
131pub const Register = enum(u8) {137pub const Register = enum(u8) {
132 // zig fmt: off138 // zig fmt: off
133139
...@@ -169,6 +175,13 @@ pub const Register = enum(u8) {...@@ -169,6 +175,13 @@ pub const Register = enum(u8) {
169 f16, f17, f18, f19, f20, f21, f22, f23, 175 f16, f17, f18, f19, f20, f21, f22, f23,
170 f24, f25, f26, f27, f28, f29, f30, f31, 176 f24, f25, f26, f27, f28, f29, f30, f31,
171177
178
179 // V extension registers
180 v0, v1, v2, v3, v4, v5, v6, v7,
181 v8, v9, v10, v11, v12, v13, v14, v15,
182 v16, v17, v18, v19, v20, v21, v22, v23,
183 v24, v25, v26, v27, v28, v29, v30, v31,
184
172 // zig fmt: on185 // zig fmt: on
173186
174 /// in RISC-V registers are stored as 5 bit IDs and a register can have187 /// in RISC-V registers are stored as 5 bit IDs and a register can have
...@@ -180,11 +193,12 @@ pub const Register = enum(u8) {...@@ -180,11 +193,12 @@ pub const Register = enum(u8) {
180 /// The goal of this function is to return the same ID for `zero` and `x0` but two193 /// The goal of this function is to return the same ID for `zero` and `x0` but two
181 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers194 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers
182 /// and is repeated twice, once for the named version, once for the number version.195 /// and is repeated twice, once for the named version, once for the number version.
183 pub fn id(reg: Register) u7 {196 pub fn id(reg: Register) u8 {
184 const base = switch (@intFromEnum(reg)) {197 const base = switch (@intFromEnum(reg)) {
185 // zig fmt: off198 // zig fmt: off
186 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),199 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),
187 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0),200 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0),
201 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => @intFromEnum(Register.v0),
188 else => unreachable,202 else => unreachable,
189 // zig fmt: on203 // zig fmt: on
190 };204 };
...@@ -207,6 +221,7 @@ pub const Register = enum(u8) {...@@ -207,6 +221,7 @@ pub const Register = enum(u8) {
207 // zig fmt: off221 // zig fmt: off
208 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,222 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
209 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,223 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,
224 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => 256, // TODO: look at suggestVectorSize
210 else => unreachable,225 else => unreachable,
211 // zig fmt: on226 // zig fmt: on
212 };227 };
...@@ -217,6 +232,7 @@ pub const Register = enum(u8) {...@@ -217,6 +232,7 @@ pub const Register = enum(u8) {
217 // zig fmt: off232 // zig fmt: off
218 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int,233 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int,
219 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float,234 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float,
235 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => .vector,
220 else => unreachable,236 else => unreachable,
221 // zig fmt: on237 // zig fmt: on
222 };238 };
...@@ -272,3 +288,27 @@ pub const Symbol = struct {...@@ -272,3 +288,27 @@ pub const Symbol = struct {
272 /// Index into the linker's symbol table.288 /// Index into the linker's symbol table.
273 sym_index: u32,289 sym_index: u32,
274};290};
291
292pub const VType = packed struct(u8) {
293 vlmul: VlMul,
294 vsew: VSew,
295 vta: bool,
296 vma: bool,
297};
298
299const VSew = enum(u3) {
300 @"8" = 0b000,
301 @"16" = 0b001,
302 @"32" = 0b010,
303 @"64" = 0b011,
304};
305
306const VlMul = enum(u3) {
307 mf8 = 0b101,
308 mf4 = 0b110,
309 mf2 = 0b111,
310 m1 = 0b000,
311 m2 = 0b001,
312 m4 = 0b010,
313 m8 = 0b011,
314};
src/arch/riscv64/encoder.zig+11-4
...@@ -1,26 +1,30 @@...@@ -1,26 +1,30 @@
1pub const Instruction = struct {1pub const Instruction = struct {
2 encoding: Encoding,2 encoding: Encoding,
3 ops: [3]Operand = .{.none} ** 3,3 ops: [5]Operand = .{.none} ** 5,
44
5 pub const Operand = union(enum) {5 pub const Operand = union(enum) {
6 none,6 none,
7 reg: Register,7 reg: Register,
8 csr: CSR,
8 mem: Memory,9 mem: Memory,
9 imm: Immediate,10 imm: Immediate,
11 barrier: Mir.Barrier,
10 };12 };
1113
12 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {14 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
13 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {15 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {
14 std.log.err("no encoding found for: {s} [{s} {s} {s}]", .{16 std.log.err("no encoding found for: {s} [{s} {s} {s} {s} {s}]", .{
15 @tagName(mnemonic),17 @tagName(mnemonic),
16 @tagName(if (ops.len > 0) ops[0] else .none),18 @tagName(if (ops.len > 0) ops[0] else .none),
17 @tagName(if (ops.len > 1) ops[1] else .none),19 @tagName(if (ops.len > 1) ops[1] else .none),
18 @tagName(if (ops.len > 2) ops[2] else .none),20 @tagName(if (ops.len > 2) ops[2] else .none),
21 @tagName(if (ops.len > 3) ops[3] else .none),
22 @tagName(if (ops.len > 4) ops[4] else .none),
19 });23 });
20 return error.InvalidInstruction;24 return error.InvalidInstruction;
21 };25 };
2226
23 var result_ops: [3]Operand = .{.none} ** 3;27 var result_ops: [5]Operand = .{.none} ** 5;
24 @memcpy(result_ops[0..ops.len], ops);28 @memcpy(result_ops[0..ops.len], ops);
2529
26 return .{30 return .{
...@@ -53,7 +57,9 @@ pub const Instruction = struct {...@@ -53,7 +57,9 @@ pub const Instruction = struct {
53 .none => unreachable, // it's sliced out above57 .none => unreachable, // it's sliced out above
54 .reg => |reg| try writer.writeAll(@tagName(reg)),58 .reg => |reg| try writer.writeAll(@tagName(reg)),
55 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),59 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
56 .mem => unreachable, // there is no "mem" operand in the actual instructions60 .mem => try writer.writeAll("mem"),
61 .barrier => |barrier| try writer.writeAll(@tagName(barrier)),
62 .csr => |csr| try writer.writeAll(@tagName(csr)),
57 }63 }
58 }64 }
59 }65 }
...@@ -67,6 +73,7 @@ const bits = @import("bits.zig");...@@ -67,6 +73,7 @@ const bits = @import("bits.zig");
67const Encoding = @import("Encoding.zig");73const Encoding = @import("Encoding.zig");
6874
69const Register = bits.Register;75const Register = bits.Register;
76const CSR = bits.CSR;
70const Memory = bits.Memory;77const Memory = bits.Memory;
71const Immediate = bits.Immediate;78const Immediate = bits.Immediate;
7279
src/arch/x86_64/Lower.zig+2
...@@ -65,6 +65,8 @@ pub const Reloc = struct {...@@ -65,6 +65,8 @@ pub const Reloc = struct {
65 };65 };
66};66};
6767
68const Options = struct { allow_frame_locs: bool };
69
68/// The returned slice is overwritten by the next call to lowerMir.70/// The returned slice is overwritten by the next call to lowerMir.
69pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {71pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
70 insts: []const Instruction,72 insts: []const Instruction,
src/codegen.zig+2-1
...@@ -987,8 +987,9 @@ pub fn genTypedValue(...@@ -987,8 +987,9 @@ pub fn genTypedValue(
987987
988 log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)});988 log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)});
989989
990 if (val.isUndef(zcu))990 if (val.isUndef(zcu)) {
991 return GenResult.mcv(.undef);991 return GenResult.mcv(.undef);
992 }
992993
993 const owner_decl = zcu.declPtr(owner_decl_index);994 const owner_decl = zcu.declPtr(owner_decl_index);
994 const namespace = zcu.namespacePtr(owner_decl.src_namespace);995 const namespace = zcu.namespacePtr(owner_decl.src_namespace);
src/link/Elf/ZigObject.zig+11-7
...@@ -540,8 +540,8 @@ inline fn isGlobal(index: Symbol.Index) bool {...@@ -540,8 +540,8 @@ inline fn isGlobal(index: Symbol.Index) bool {
540540
541pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {541pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
542 const actual_index = index & symbol_mask;542 const actual_index = index & symbol_mask;
543 if (isGlobal(index)) return self.global_symbols.items[actual_index];543 if (isGlobal(index)) return self.globals()[actual_index];
544 return self.local_symbols.items[actual_index];544 return self.locals()[actual_index];
545}545}
546546
547pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {547pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
...@@ -1334,11 +1334,15 @@ fn lowerConst(...@@ -1334,11 +1334,15 @@ fn lowerConst(
13341334
1335 const sym_index = try self.addAtom(elf_file);1335 const sym_index = try self.addAtom(elf_file);
13361336
1337 const res = try codegen.generateSymbol(&elf_file.base, pt, src_loc, val, &code_buffer, .{1337 const res = try codegen.generateSymbol(
1338 .none = {},1338 &elf_file.base,
1339 }, .{1339 pt,
1340 .parent_atom_index = sym_index,1340 src_loc,
1341 });1341 val,
1342 &code_buffer,
1343 .{ .none = {} },
1344 .{ .parent_atom_index = sym_index },
1345 );
1342 const code = switch (res) {1346 const code = switch (res) {
1343 .ok => code_buffer.items,1347 .ok => code_buffer.items,
1344 .fail => |em| return .{ .fail = em },1348 .fail => |em| return .{ .fail = em },
test/behavior/array.zig-2
...@@ -580,7 +580,6 @@ test "type coercion of anon struct literal to array" {...@@ -580,7 +580,6 @@ test "type coercion of anon struct literal to array" {
580 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO580 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
583 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
584583
585 const S = struct {584 const S = struct {
586 const U = union {585 const U = union {
...@@ -1011,7 +1010,6 @@ test "union that needs padding bytes inside an array" {...@@ -1011,7 +1010,6 @@ test "union that needs padding bytes inside an array" {
1011 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1012 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1013 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1014 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10151013
1016 const B = union(enum) {1014 const B = union(enum) {
1017 D: u8,1015 D: u8,
test/behavior/atomics.zig-17
...@@ -42,7 +42,6 @@ test "fence" {...@@ -42,7 +42,6 @@ test "fence" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;44 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4645
47 var x: i32 = 1234;46 var x: i32 = 1234;
48 @fence(.seq_cst);47 @fence(.seq_cst);
...@@ -188,21 +187,6 @@ test "atomic store" {...@@ -188,21 +187,6 @@ test "atomic store" {
188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
190 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;189 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
192
193 var x: u32 = 0;
194 @atomicStore(u32, &x, 1, .seq_cst);
195 try expect(@atomicLoad(u32, &x, .seq_cst) == 1);
196 @atomicStore(u32, &x, 12345678, .seq_cst);
197 try expect(@atomicLoad(u32, &x, .seq_cst) == 12345678);
198}
199
200test "atomic store comptime" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
205 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
206190
207 try comptime testAtomicStore();191 try comptime testAtomicStore();
208 try testAtomicStore();192 try testAtomicStore();
...@@ -451,7 +435,6 @@ test "return @atomicStore, using it as a void value" {...@@ -451,7 +435,6 @@ test "return @atomicStore, using it as a void value" {
451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO435 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;437 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
454 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
455438
456 const S = struct {439 const S = struct {
457 const A = struct {440 const A = struct {
test/behavior/bitcast.zig-2
...@@ -192,7 +192,6 @@ test "@bitCast packed structs at runtime and comptime" {...@@ -192,7 +192,6 @@ test "@bitCast packed structs at runtime and comptime" {
192test "@bitCast extern structs at runtime and comptime" {192test "@bitCast extern structs at runtime and comptime" {
193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
196195
197 const Full = extern struct {196 const Full = extern struct {
198 number: u16,197 number: u16,
...@@ -227,7 +226,6 @@ test "bitcast packed struct to integer and back" {...@@ -227,7 +226,6 @@ test "bitcast packed struct to integer and back" {
227 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;226 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
228 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
229 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;228 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
231229
232 const LevelUpMove = packed struct {230 const LevelUpMove = packed struct {
233 move_id: u9,231 move_id: u9,
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
...@@ -11,7 +11,6 @@ test {...@@ -11,7 +11,6 @@ test {
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;13 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1514
16 var val: u8 = undefined;15 var val: u8 = undefined;
17 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered));16 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered));
test/behavior/enum.zig-1
...@@ -908,7 +908,6 @@ test "enum literal casting to tagged union" {...@@ -908,7 +908,6 @@ test "enum literal casting to tagged union" {
908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
909 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;909 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO910 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
911 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
912911
913 const Arch = union(enum) {912 const Arch = union(enum) {
914 x86_64,913 x86_64,
test/behavior/error.zig-1
...@@ -535,7 +535,6 @@ test "return result loc as peer result loc in inferred error set function" {...@@ -535,7 +535,6 @@ test "return result loc as peer result loc in inferred error set function" {
535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
538 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
539538
540 const S = struct {539 const S = struct {
541 fn doTheTest() !void {540 fn doTheTest() !void {
test/behavior/eval.zig-2
...@@ -395,7 +395,6 @@ test "return 0 from function that has u0 return type" {...@@ -395,7 +395,6 @@ test "return 0 from function that has u0 return type" {
395test "statically initialized struct" {395test "statically initialized struct" {
396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
399398
400 st_init_str_foo.x += 1;399 st_init_str_foo.x += 1;
401 try expect(st_init_str_foo.x == 14);400 try expect(st_init_str_foo.x == 14);
...@@ -446,7 +445,6 @@ test "binary math operator in partially inlined function" {...@@ -446,7 +445,6 @@ test "binary math operator in partially inlined function" {
446 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO445 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO446 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO447 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
450448
451 var s: [4]u32 = undefined;449 var s: [4]u32 = undefined;
452 var b: [16]u8 = undefined;450 var b: [16]u8 = undefined;
test/behavior/floatop.zig-1
...@@ -281,7 +281,6 @@ test "@sqrt f32/f64" {...@@ -281,7 +281,6 @@ test "@sqrt f32/f64" {
281 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO281 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
283 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;283 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
285284
286 try testSqrt(f32);285 try testSqrt(f32);
287 try comptime testSqrt(f32);286 try comptime testSqrt(f32);
test/behavior/inline_switch.zig-1
...@@ -49,7 +49,6 @@ test "inline switch unions" {...@@ -49,7 +49,6 @@ test "inline switch unions" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5352
54 var x: U = .a;53 var x: U = .a;
55 _ = &x;54 _ = &x;
test/behavior/math.zig-1
...@@ -1269,7 +1269,6 @@ test "@subWithOverflow" {...@@ -1269,7 +1269,6 @@ test "@subWithOverflow" {
1269 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1269 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12731272
1274 {1273 {
1275 var a: u8 = 1;1274 var a: u8 = 1;
test/behavior/optional.zig-1
...@@ -397,7 +397,6 @@ test "array of optional unaligned types" {...@@ -397,7 +397,6 @@ test "array of optional unaligned types" {
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
400 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
401400
402 const Enum = enum { one, two, three };401 const Enum = enum { one, two, three };
403402
test/behavior/packed-struct.zig-1
...@@ -785,7 +785,6 @@ test "nested packed struct field access test" {...@@ -785,7 +785,6 @@ test "nested packed struct field access test" {
785test "nested packed struct at non-zero offset" {785test "nested packed struct at non-zero offset" {
786 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO786 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
787 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;787 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
788 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
789788
790 const Pair = packed struct(u24) {789 const Pair = packed struct(u24) {
791 a: u16 = 0,790 a: u16 = 0,
test/behavior/reflection.zig-1
...@@ -28,7 +28,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {...@@ -28,7 +28,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
28test "reflection: @field" {28test "reflection: @field" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3231
33 var f = Foo{32 var f = Foo{
34 .one = 42,33 .one = 42,
test/behavior/struct.zig-3
...@@ -875,7 +875,6 @@ test "packed struct field passed to generic function" {...@@ -875,7 +875,6 @@ test "packed struct field passed to generic function" {
875test "anonymous struct literal syntax" {875test "anonymous struct literal syntax" {
876 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;876 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
878 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
879878
880 const S = struct {879 const S = struct {
881 const Point = struct {880 const Point = struct {
...@@ -985,7 +984,6 @@ test "struct with union field" {...@@ -985,7 +984,6 @@ test "struct with union field" {
985 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
986 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
987 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO986 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
988 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
989987
990 const Value = struct {988 const Value = struct {
991 ref: u32 = 2,989 ref: u32 = 2,
...@@ -1368,7 +1366,6 @@ test "store to comptime field" {...@@ -1368,7 +1366,6 @@ test "store to comptime field" {
1368test "struct field init value is size of the struct" {1366test "struct field init value is size of the struct" {
1369 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1368 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1371 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13721369
1373 const namespace = struct {1370 const namespace = struct {
1374 const S = extern struct {1371 const S = extern struct {
test/behavior/switch.zig-2
...@@ -256,7 +256,6 @@ test "switch on enum using pointer capture" {...@@ -256,7 +256,6 @@ test "switch on enum using pointer capture" {
256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
257 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO257 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
259 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
260259
261 try testSwitchEnumPtrCapture();260 try testSwitchEnumPtrCapture();
262 try comptime testSwitchEnumPtrCapture();261 try comptime testSwitchEnumPtrCapture();
...@@ -693,7 +692,6 @@ test "switch capture copies its payload" {...@@ -693,7 +692,6 @@ test "switch capture copies its payload" {
693 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO692 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
694 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO693 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
695 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO694 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
696 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
697695
698 const S = struct {696 const S = struct {
699 fn doTheTest() !void {697 fn doTheTest() !void {
test/behavior/this.zig-1
...@@ -27,7 +27,6 @@ test "this refer to module call private fn" {...@@ -27,7 +27,6 @@ test "this refer to module call private fn" {
27test "this refer to container" {27test "this refer to container" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3130
32 var pt: Point(i32) = undefined;31 var pt: Point(i32) = undefined;
33 pt.x = 12;32 pt.x = 12;
test/behavior/tuple.zig-1
...@@ -131,7 +131,6 @@ test "tuple initializer for var" {...@@ -131,7 +131,6 @@ test "tuple initializer for var" {
131test "array-like initializer for tuple types" {131test "array-like initializer for tuple types" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
135134
136 const T = @Type(.{135 const T = @Type(.{
137 .Struct = .{136 .Struct = .{
test/behavior/type.zig-1
...@@ -383,7 +383,6 @@ test "Type.Union" {...@@ -383,7 +383,6 @@ test "Type.Union" {
383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;385 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
386 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
387386
388 const Untagged = @Type(.{387 const Untagged = @Type(.{
389 .Union = .{388 .Union = .{
test/behavior/union.zig-23
...@@ -43,7 +43,6 @@ test "basic unions" {...@@ -43,7 +43,6 @@ test "basic unions" {
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4746
48 var foo = Foo{ .int = 1 };47 var foo = Foo{ .int = 1 };
49 try expect(foo.int == 1);48 try expect(foo.int == 1);
...@@ -276,7 +275,6 @@ test "comparison between union and enum literal" {...@@ -276,7 +275,6 @@ test "comparison between union and enum literal" {
276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
280278
281 try testComparison();279 try testComparison();
282 try comptime testComparison();280 try comptime testComparison();
...@@ -292,7 +290,6 @@ test "cast union to tag type of union" {...@@ -292,7 +290,6 @@ test "cast union to tag type of union" {
292 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;291 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
296293
297 try testCastUnionToTag();294 try testCastUnionToTag();
298 try comptime testCastUnionToTag();295 try comptime testCastUnionToTag();
...@@ -314,7 +311,6 @@ test "cast tag type of union to union" {...@@ -314,7 +311,6 @@ test "cast tag type of union to union" {
314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;311 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;312 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
316 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
317 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
318314
319 var x: Value2 = Letter2.B;315 var x: Value2 = Letter2.B;
320 _ = &x;316 _ = &x;
...@@ -331,7 +327,6 @@ test "implicit cast union to its tag type" {...@@ -331,7 +327,6 @@ test "implicit cast union to its tag type" {
331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
332 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;328 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO329 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
335330
336 var x: Value2 = Letter2.B;331 var x: Value2 = Letter2.B;
337 _ = &x;332 _ = &x;
...@@ -353,7 +348,6 @@ test "constant packed union" {...@@ -353,7 +348,6 @@ test "constant packed union" {
353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
354 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;349 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
355 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO350 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
356 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
357351
358 try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }});352 try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }});
359}353}
...@@ -503,7 +497,6 @@ test "initialize global array of union" {...@@ -503,7 +497,6 @@ test "initialize global array of union" {
503 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
504 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
507500
508 glbl_array[1] = FooUnion{ .U1 = 2 };501 glbl_array[1] = FooUnion{ .U1 = 2 };
509 glbl_array[0] = FooUnion{ .U0 = 1 };502 glbl_array[0] = FooUnion{ .U0 = 1 };
...@@ -515,7 +508,6 @@ test "update the tag value for zero-sized unions" {...@@ -515,7 +508,6 @@ test "update the tag value for zero-sized unions" {
515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
519511
520 const S = union(enum) {512 const S = union(enum) {
521 U0: void,513 U0: void,
...@@ -636,7 +628,6 @@ test "tagged union with all void fields but a meaningful tag" {...@@ -636,7 +628,6 @@ test "tagged union with all void fields but a meaningful tag" {
636 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;628 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
637 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;629 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
638 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO630 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
640631
641 const S = struct {632 const S = struct {
642 const B = union(enum) {633 const B = union(enum) {
...@@ -758,7 +749,6 @@ test "@intFromEnum works on unions" {...@@ -758,7 +749,6 @@ test "@intFromEnum works on unions" {
758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO749 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO750 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
760 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO751 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
761 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
762752
763 const Bar = union(enum) {753 const Bar = union(enum) {
764 A: bool,754 A: bool,
...@@ -874,7 +864,6 @@ test "@unionInit can modify a union type" {...@@ -874,7 +864,6 @@ test "@unionInit can modify a union type" {
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO864 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
875 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
876 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO866 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
877 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
878867
879 const UnionInitEnum = union(enum) {868 const UnionInitEnum = union(enum) {
880 Boolean: bool,869 Boolean: bool,
...@@ -898,7 +887,6 @@ test "@unionInit can modify a pointer value" {...@@ -898,7 +887,6 @@ test "@unionInit can modify a pointer value" {
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
899 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO888 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
900 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO889 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
901 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
902890
903 const UnionInitEnum = union(enum) {891 const UnionInitEnum = union(enum) {
904 Boolean: bool,892 Boolean: bool,
...@@ -1089,7 +1077,6 @@ test "switching on non exhaustive union" {...@@ -1089,7 +1077,6 @@ test "switching on non exhaustive union" {
1089 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1090 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1078 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1091 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1079 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1092 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10931080
1094 const S = struct {1081 const S = struct {
1095 const E = enum(u8) {1082 const E = enum(u8) {
...@@ -1199,7 +1186,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel...@@ -1199,7 +1186,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel
1199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1186 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1200 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1202 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12031189
1204 const T = struct {1190 const T = struct {
1205 const U = union(enum) {1191 const U = union(enum) {
...@@ -1352,7 +1338,6 @@ test "noreturn field in union" {...@@ -1352,7 +1338,6 @@ test "noreturn field in union" {
1352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1354 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1355 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13561341
1357 const U = union(enum) {1342 const U = union(enum) {
1358 a: u32,1343 a: u32,
...@@ -1434,7 +1419,6 @@ test "union field ptr - zero sized payload" {...@@ -1434,7 +1419,6 @@ test "union field ptr - zero sized payload" {
1434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1437 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14381422
1439 const U = union {1423 const U = union {
1440 foo: void,1424 foo: void,
...@@ -1449,7 +1433,6 @@ test "union field ptr - zero sized field" {...@@ -1449,7 +1433,6 @@ test "union field ptr - zero sized field" {
1449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1435 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14531436
1454 const U = union {1437 const U = union {
1455 foo: void,1438 foo: void,
...@@ -1589,7 +1572,6 @@ test "reinterpreting enum value inside packed union" {...@@ -1589,7 +1572,6 @@ test "reinterpreting enum value inside packed union" {
15891572
1590test "access the tag of a global tagged union" {1573test "access the tag of a global tagged union" {
1591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1574 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1592 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15931575
1594 const U = union(enum) {1576 const U = union(enum) {
1595 a,1577 a,
...@@ -1601,7 +1583,6 @@ test "access the tag of a global tagged union" {...@@ -1601,7 +1583,6 @@ test "access the tag of a global tagged union" {
16011583
1602test "coerce enum literal to union in result loc" {1584test "coerce enum literal to union in result loc" {
1603 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1604 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16051586
1606 const U = union(enum) {1587 const U = union(enum) {
1607 a,1588 a,
...@@ -1864,7 +1845,6 @@ test "reinterpret extern union" {...@@ -1864,7 +1845,6 @@ test "reinterpret extern union" {
18641845
1865test "reinterpret packed union" {1846test "reinterpret packed union" {
1866 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1847 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1867 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18681848
1869 const U = packed union {1849 const U = packed union {
1870 foo: u8,1850 foo: u8,
...@@ -2044,7 +2024,6 @@ test "extern union initialized via reintepreted struct field initializer" {...@@ -2044,7 +2024,6 @@ test "extern union initialized via reintepreted struct field initializer" {
20442024
2045test "packed union initialized via reintepreted struct field initializer" {2025test "packed union initialized via reintepreted struct field initializer" {
2046 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;2026 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20482027
2049 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };2028 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20502029
...@@ -2065,7 +2044,6 @@ test "packed union initialized via reintepreted struct field initializer" {...@@ -2065,7 +2044,6 @@ test "packed union initialized via reintepreted struct field initializer" {
20652044
2066test "store of comptime reinterpreted memory to extern union" {2045test "store of comptime reinterpreted memory to extern union" {
2067 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;2046 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2068 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20692047
2070 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };2048 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20712049
...@@ -2088,7 +2066,6 @@ test "store of comptime reinterpreted memory to extern union" {...@@ -2088,7 +2066,6 @@ test "store of comptime reinterpreted memory to extern union" {
20882066
2089test "store of comptime reinterpreted memory to packed union" {2067test "store of comptime reinterpreted memory to packed union" {
2090 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;2068 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2091 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20922069
2093 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };2070 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20942071
test/behavior/vector.zig+28-19
...@@ -97,29 +97,40 @@ test "vector int operators" {...@@ -97,29 +97,40 @@ test "vector int operators" {
9797
98test "vector float operators" {98test "vector float operators" {
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;103 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
105 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;104 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
107107
108 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {108 const S = struct {
109 const S = struct {109 fn doTheTest(T: type) !void {
110 fn doTheTest() !void {110 var v: @Vector(4, T) = .{ 10, 20, 30, 40 };
111 var v: @Vector(4, T) = [4]T{ 10, 20, 30, 40 };111 var x: @Vector(4, T) = .{ 1, 2, 3, 4 };
112 var x: @Vector(4, T) = [4]T{ 1, 2, 3, 4 };112 _ = .{ &v, &x };
113 _ = .{ &v, &x };113 try expectEqual(v + x, .{ 11, 22, 33, 44 });
114 try expect(mem.eql(T, &@as([4]T, v + x), &[4]T{ 11, 22, 33, 44 }));114 try expectEqual(v - x, .{ 9, 18, 27, 36 });
115 try expect(mem.eql(T, &@as([4]T, v - x), &[4]T{ 9, 18, 27, 36 }));115 try expectEqual(v * x, .{ 10, 40, 90, 160 });
116 try expect(mem.eql(T, &@as([4]T, v * x), &[4]T{ 10, 40, 90, 160 }));116 try expectEqual(-x, .{ -1, -2, -3, -4 });
117 try expect(mem.eql(T, &@as([4]T, -x), &[4]T{ -1, -2, -3, -4 }));117 }
118 }118 };
119 };119
120 try S.doTheTest();120 try S.doTheTest(f32);
121 try comptime S.doTheTest();121 try comptime S.doTheTest(f32);
122 }122
123 try S.doTheTest(f64);
124 try comptime S.doTheTest(f64);
125
126 try S.doTheTest(f16);
127 try comptime S.doTheTest(f16);
128
129 try S.doTheTest(f80);
130 try comptime S.doTheTest(f80);
131
132 try S.doTheTest(f128);
133 try comptime S.doTheTest(f128);
123}134}
124135
125test "vector bit operators" {136test "vector bit operators" {
...@@ -1245,7 +1256,6 @@ test "array of vectors is copied" {...@@ -1245,7 +1256,6 @@ test "array of vectors is copied" {
1245 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1248 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12491259
1250 const Vec3 = @Vector(3, i32);1260 const Vec3 = @Vector(3, i32);
1251 var points = [_]Vec3{1261 var points = [_]Vec3{
...@@ -1316,6 +1326,7 @@ test "zero multiplicand" {...@@ -1316,6 +1326,7 @@ test "zero multiplicand" {
1316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1318 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1329 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13191330
1320 const zeros = @Vector(2, u32){ 0.0, 0.0 };1331 const zeros = @Vector(2, u32){ 0.0, 0.0 };
1321 var ones = @Vector(2, u32){ 1.0, 1.0 };1332 var ones = @Vector(2, u32){ 1.0, 1.0 };
...@@ -1410,7 +1421,6 @@ test "store to vector in slice" {...@@ -1410,7 +1421,6 @@ test "store to vector in slice" {
1410 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1411 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1412 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;1423 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
1413 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14141424
1415 var v = [_]@Vector(3, f32){1425 var v = [_]@Vector(3, f32){
1416 .{ 1, 1, 1 },1426 .{ 1, 1, 1 },
...@@ -1608,7 +1618,6 @@ test "@reduce on bool vector" {...@@ -1608,7 +1618,6 @@ test "@reduce on bool vector" {
1608test "bitcast vector to array of smaller vectors" {1618test "bitcast vector to array of smaller vectors" {
1609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1610 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1620 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1611 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16121621
1613 const u8x32 = @Vector(32, u8);1622 const u8x32 = @Vector(32, u8);
1614 const u8x64 = @Vector(64, u8);1623 const u8x64 = @Vector(64, u8);
test/tests.zig+6-5
...@@ -436,11 +436,12 @@ const test_targets = blk: {...@@ -436,11 +436,12 @@ const test_targets = blk: {
436 //},436 //},
437437
438 .{438 .{
439 .target = .{439 .target = std.Target.Query.parse(
440 .cpu_arch = .riscv64,440 .{
441 .os_tag = .linux,441 .arch_os_abi = "riscv64-linux-musl",
442 .abi = .musl,442 .cpu_features = "baseline+v",
443 },443 },
444 ) catch @panic("OOM"),
444 .use_llvm = false,445 .use_llvm = false,
445 .use_lld = false,446 .use_lld = false,
446 },447 },