authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-28 11:34:23+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-28 11:34:23+02:00
log91c17979f10db4fdc6639b176c0563718f060f47
tree7ae29768d6ad64678c389685752f2848ecec76ba
parent1fba9e1280efb935e935f09a196ae35d5391ed48
parentb20007daf74f44cfc86c5f2d2d7e2acde079e127
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20807 from Rexicon226/riscv

riscv: more backend progress

64 files changed, 3516 insertions(+), 3279 deletions(-)

CMakeLists.txt+5-2
......@@ -535,11 +535,14 @@ set(ZIG_STAGE2_SOURCES
535535 src/arch/arm/Mir.zig
536536 src/arch/arm/abi.zig
537537 src/arch/arm/bits.zig
538 src/arch/riscv64/abi.zig
539 src/arch/riscv64/bits.zig
538540 src/arch/riscv64/CodeGen.zig
539541 src/arch/riscv64/Emit.zig
542 src/arch/riscv64/encoding.zig
543 src/arch/riscv64/Lower.zig
540544 src/arch/riscv64/Mir.zig
541 src/arch/riscv64/abi.zig
542 src/arch/riscv64/bits.zig
545 src/arch/riscv64/mnem.zig
543546 src/arch/sparc64/CodeGen.zig
544547 src/arch/sparc64/Emit.zig
545548 src/arch/sparc64/Mir.zig
lib/compiler/test_runner.zig+8-7
......@@ -282,11 +282,13 @@ pub fn mainSimple() anyerror!void {
282282 const stderr = if (comptime enable_print) std.io.getStdErr() else {};
283283
284284 for (builtin.test_functions) |test_fn| {
285 if (enable_print) {
286 stderr.writeAll(test_fn.name) catch {};
287 stderr.writeAll("... ") catch {};
288 }
289 test_fn.func() catch |err| {
285 if (test_fn.func()) |_| {
286 if (enable_print) {
287 stderr.writeAll(test_fn.name) catch {};
288 stderr.writeAll("... ") catch {};
289 stderr.writeAll("PASS\n") catch {};
290 }
291 } else |err| if (enable_print) {
290292 if (enable_print) {
291293 stderr.writeAll(test_fn.name) catch {};
292294 stderr.writeAll("... ") catch {};
......@@ -300,8 +302,7 @@ pub fn mainSimple() anyerror!void {
300302 if (enable_print) stderr.writeAll("SKIP\n") catch {};
301303 skipped += 1;
302304 continue;
303 };
304 if (enable_print) stderr.writeAll("PASS\n") catch {};
305 }
305306 passed += 1;
306307 }
307308 if (enable_print and print_summary) {
lib/std/Thread.zig+1-1
......@@ -385,7 +385,7 @@ pub fn yield() YieldError!void {
385385}
386386
387387/// State to synchronize detachment of spawner thread to spawned thread
388const Completion = std.atomic.Value(enum(u8) {
388const Completion = std.atomic.Value(enum(if (builtin.zig_backend == .stage2_riscv64) u32 else u8) {
389389 running,
390390 detached,
391391 completed,
lib/std/builtin.zig+2-8
......@@ -775,14 +775,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
775775 }
776776
777777 if (builtin.zig_backend == .stage2_riscv64) {
778 asm volatile ("ecall"
779 :
780 : [number] "{a7}" (64),
781 [arg1] "{a0}" (1),
782 [arg2] "{a1}" (@intFromPtr(msg.ptr)),
783 [arg3] "{a2}" (msg.len),
784 : "memory"
785 );
778 std.debug.print("panic: {s}\n", .{msg});
779 @breakpoint();
786780 std.posix.exit(127);
787781 }
788782
lib/std/start.zig+5-42
......@@ -20,8 +20,7 @@ pub const simplified_logic =
2020 builtin.zig_backend == .stage2_arm or
2121 builtin.zig_backend == .stage2_sparc64 or
2222 builtin.cpu.arch == .spirv32 or
23 builtin.cpu.arch == .spirv64 or
24 builtin.zig_backend == .stage2_riscv64;
23 builtin.cpu.arch == .spirv64;
2524
2625comptime {
2726 // No matter what, we import the root file, so that any export, test, comptime
......@@ -41,10 +40,6 @@ comptime {
4140 } else if (builtin.os.tag == .opencl) {
4241 if (@hasDecl(root, "main"))
4342 @export(spirvMain2, .{ .name = "main" });
44 } else if (native_arch.isRISCV()) {
45 if (!@hasDecl(root, "_start")) {
46 @export(riscv_start, .{ .name = "_start" });
47 }
4843 } else {
4944 if (!@hasDecl(root, "_start")) {
5045 @export(_start2, .{ .name = "_start" });
......@@ -206,42 +201,6 @@ fn wasi_start() callconv(.C) void {
206201 }
207202}
208203
209fn riscv_start() callconv(.C) noreturn {
210 std.process.exit(switch (@typeInfo(@typeInfo(@TypeOf(root.main)).Fn.return_type.?)) {
211 .NoReturn => root.main(),
212 .Void => ret: {
213 root.main();
214 break :ret 0;
215 },
216 .Int => |info| ret: {
217 if (info.bits != 8 or info.signedness == .signed) {
218 @compileError(bad_main_ret);
219 }
220 break :ret root.main();
221 },
222 .ErrorUnion => ret: {
223 const result = root.main() catch {
224 const stderr = std.io.getStdErr().writer();
225 stderr.writeAll("failed with error\n") catch {
226 @panic("failed to print when main returned error");
227 };
228 break :ret 1;
229 };
230 switch (@typeInfo(@TypeOf(result))) {
231 .Void => break :ret 0,
232 .Int => |info| {
233 if (info.bits != 8 or info.signedness == .signed) {
234 @compileError(bad_main_ret);
235 }
236 return result;
237 },
238 else => @compileError(bad_main_ret),
239 }
240 },
241 else => @compileError(bad_main_ret),
242 });
243}
244
245204fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize {
246205 uefi.handle = handle;
247206 uefi.system_table = system_table;
......@@ -563,6 +522,10 @@ pub inline fn callMain() u8 {
563522 if (@typeInfo(ReturnType) != .ErrorUnion) @compileError(bad_main_ret);
564523
565524 const result = root.main() catch |err| {
525 if (builtin.zig_backend == .stage2_riscv64) {
526 std.debug.print("error: failed with error\n", .{});
527 return 1;
528 }
566529 std.log.err("{s}", .{@errorName(err)});
567530 if (@errorReturnTrace()) |trace| {
568531 std.debug.dumpStackTrace(trace.*);
src/Compilation.zig+1
......@@ -6334,6 +6334,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
63346334 }
63356335 return switch (target_util.zigBackend(target, use_llvm)) {
63366336 .stage2_llvm => true,
6337 .stage2_riscv64 => true,
63376338 .stage2_x86_64 => if (target.ofmt == .elf or target.ofmt == .macho) true else build_options.have_llvm,
63386339 else => build_options.have_llvm,
63396340 };
src/arch/riscv64/CodeGen.zig+1914-894
......@@ -37,6 +37,10 @@ const DebugInfoOutput = codegen.DebugInfoOutput;
3737const bits = @import("bits.zig");
3838const abi = @import("abi.zig");
3939const Lower = @import("Lower.zig");
40const mnem_import = @import("mnem.zig");
41const Mnemonic = mnem_import.Mnemonic;
42const Pseudo = mnem_import.Pseudo;
43const encoding = @import("encoding.zig");
4044
4145const Register = bits.Register;
4246const CSR = bits.CSR;
......@@ -45,19 +49,18 @@ const Memory = bits.Memory;
4549const FrameIndex = bits.FrameIndex;
4650const RegisterManager = abi.RegisterManager;
4751const RegisterLock = RegisterManager.RegisterLock;
52const Instruction = encoding.Instruction;
4853
4954const InnerError = CodeGenError || error{OutOfRegisters};
5055
5156pt: Zcu.PerThread,
5257air: Air,
5358liveness: Liveness,
54zcu: *Zcu,
5559bin_file: *link.File,
5660gpa: Allocator,
5761
5862mod: *Package.Module,
5963target: *const std.Target,
60func_index: InternPool.Index,
6164debug_output: DebugInfoOutput,
6265err_msg: ?*ErrorMsg,
6366args: []MCValue,
......@@ -67,7 +70,8 @@ arg_index: usize,
6770src_loc: Zcu.LazySrcLoc,
6871
6972mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
70mir_extra: std.ArrayListUnmanaged(u32) = .{},
73
74owner: Owner,
7175
7276/// Byte offset within the source file of the ending curly.
7377end_di_line: u32,
......@@ -113,6 +117,34 @@ const SymbolOffset = struct { sym: u32, off: i32 = 0 };
113117const RegisterOffset = struct { reg: Register, off: i32 = 0 };
114118pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
115119
120const Owner = union(enum) {
121 func_index: InternPool.Index,
122 lazy_sym: link.File.LazySymbol,
123
124 fn getDecl(owner: Owner, zcu: *Zcu) InternPool.DeclIndex {
125 return switch (owner) {
126 .func_index => |func_index| zcu.funcOwnerDeclIndex(func_index),
127 .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(zcu),
128 };
129 }
130
131 fn getSymbolIndex(owner: Owner, func: *Func) !u32 {
132 const pt = func.pt;
133 switch (owner) {
134 .func_index => |func_index| {
135 const decl_index = func.pt.zcu.funcOwnerDeclIndex(func_index);
136 const elf_file = func.bin_file.cast(link.File.Elf).?;
137 return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
138 },
139 .lazy_sym => |lazy_sym| {
140 const elf_file = func.bin_file.cast(link.File.Elf).?;
141 return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
142 func.fail("{s} creating lazy symbol", .{@errorName(err)});
143 },
144 }
145 }
146};
147
116148const MCValue = union(enum) {
117149 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
118150 /// TODO Look into deleting this tag and using `dead` instead, since every use
......@@ -131,8 +163,12 @@ const MCValue = union(enum) {
131163 immediate: u64,
132164 /// The value doesn't exist in memory yet.
133165 load_symbol: SymbolOffset,
166 /// A TLV value.
167 load_tlv: u32,
134168 /// The address of the memory location not-yet-allocated by the linker.
135169 lea_symbol: SymbolOffset,
170 /// The address of a TLV value.
171 lea_tlv: u32,
136172 /// The value is in a target-specific register.
137173 register: Register,
138174 /// The value is split across two registers
......@@ -189,6 +225,7 @@ const MCValue = union(enum) {
189225 .lea_frame,
190226 .undef,
191227 .lea_symbol,
228 .lea_tlv,
192229 .air_ref,
193230 .reserved_frame,
194231 => false,
......@@ -198,6 +235,7 @@ const MCValue = union(enum) {
198235 .register_offset,
199236 .load_frame,
200237 .load_symbol,
238 .load_tlv,
201239 .indirect,
202240 => true,
203241 };
......@@ -216,10 +254,12 @@ const MCValue = union(enum) {
216254 .undef,
217255 .air_ref,
218256 .lea_symbol,
257 .lea_tlv,
219258 .reserved_frame,
220259 => unreachable, // not in memory
221260
222261 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
262 .load_tlv => |sym| .{ .lea_tlv = sym },
223263 .memory => |addr| .{ .immediate = addr },
224264 .load_frame => |off| .{ .lea_frame = off },
225265 .indirect => |reg_off| switch (reg_off.off) {
......@@ -238,17 +278,19 @@ const MCValue = union(enum) {
238278 .indirect,
239279 .undef,
240280 .air_ref,
241 .load_frame,
242281 .register_pair,
282 .load_frame,
243283 .load_symbol,
284 .load_tlv,
244285 .reserved_frame,
245286 => unreachable, // not a pointer
246287
247288 .immediate => |addr| .{ .memory = addr },
248 .lea_frame => |off| .{ .load_frame = off },
249289 .register => |reg| .{ .indirect = .{ .reg = reg } },
250290 .register_offset => |reg_off| .{ .indirect = reg_off },
291 .lea_frame => |off| .{ .load_frame = off },
251292 .lea_symbol => |sym_off| .{ .load_symbol = sym_off },
293 .lea_tlv => |sym| .{ .load_tlv = sym },
252294 };
253295 }
254296
......@@ -264,13 +306,15 @@ const MCValue = union(enum) {
264306 .register_pair,
265307 .memory,
266308 .indirect,
267 .load_frame,
268309 .load_symbol,
269310 .lea_symbol,
311 .lea_tlv,
312 .load_tlv,
270313 => switch (off) {
271314 0 => mcv,
272 else => unreachable, // not offsettable
315 else => unreachable,
273316 },
317 .load_frame => |frame| .{ .load_frame = .{ .index = frame.index, .off = frame.off + off } },
274318 .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
275319 .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
276320 .register_offset => |reg_off| .{ .register_offset = .{ .reg = reg_off.reg, .off = reg_off.off + off } },
......@@ -323,6 +367,8 @@ const InstTracking = struct {
323367 .memory,
324368 .load_frame,
325369 .lea_frame,
370 .load_tlv,
371 .lea_tlv,
326372 .load_symbol,
327373 .lea_symbol,
328374 => result,
......@@ -378,6 +424,8 @@ const InstTracking = struct {
378424 .lea_frame,
379425 .load_symbol,
380426 .lea_symbol,
427 .load_tlv,
428 .lea_tlv,
381429 => inst_tracking.long,
382430 .dead,
383431 .register,
......@@ -406,6 +454,8 @@ const InstTracking = struct {
406454 .lea_frame,
407455 .load_symbol,
408456 .lea_symbol,
457 .load_tlv,
458 .lea_tlv,
409459 => assert(std.meta.eql(inst_tracking.long, target.long)),
410460 .load_frame,
411461 .reserved_frame,
......@@ -737,12 +787,11 @@ pub fn generate(
737787 .air = air,
738788 .pt = pt,
739789 .mod = mod,
740 .zcu = zcu,
741790 .bin_file = bin_file,
742791 .liveness = liveness,
743792 .target = target,
744 .func_index = func_index,
745793 .debug_output = debug_output,
794 .owner = .{ .func_index = func_index },
746795 .err_msg = null,
747796 .args = undefined, // populated after `resolveCallingConventionValues`
748797 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
......@@ -767,7 +816,6 @@ pub fn generate(
767816 function.const_tracking.deinit(gpa);
768817 function.exitlude_jump_relocs.deinit(gpa);
769818 function.mir_instructions.deinit(gpa);
770 function.mir_extra.deinit(gpa);
771819 }
772820
773821 wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
......@@ -799,11 +847,11 @@ pub fn generate(
799847 function.args = call_info.args;
800848 function.ret_mcv = call_info.return_value;
801849 function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{
802 .size = Type.usize.abiSize(pt),
803 .alignment = Type.usize.abiAlignment(pt).min(call_info.stack_align),
850 .size = Type.u64.abiSize(pt),
851 .alignment = Type.u64.abiAlignment(pt).min(call_info.stack_align),
804852 }));
805853 function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{
806 .size = Type.usize.abiSize(pt),
854 .size = Type.u64.abiSize(pt),
807855 .alignment = Alignment.min(
808856 call_info.stack_align,
809857 Alignment.fromNonzeroByteUnits(function.target.stackAlignment()),
......@@ -815,7 +863,7 @@ pub fn generate(
815863 }));
816864 function.frame_allocs.set(@intFromEnum(FrameIndex.spill_frame), FrameAlloc.init(.{
817865 .size = 0,
818 .alignment = Type.usize.abiAlignment(pt),
866 .alignment = Type.u64.abiAlignment(pt),
819867 }));
820868
821869 function.gen() catch |err| switch (err) {
......@@ -828,7 +876,6 @@ pub fn generate(
828876
829877 var mir: Mir = .{
830878 .instructions = function.mir_instructions.toOwnedSlice(),
831 .extra = try function.mir_extra.toOwnedSlice(gpa),
832879 .frame_locs = function.frame_locs.toOwnedSlice(),
833880 };
834881 defer mir.deinit(gpa);
......@@ -878,6 +925,102 @@ pub fn generate(
878925 }
879926}
880927
928pub fn generateLazy(
929 bin_file: *link.File,
930 pt: Zcu.PerThread,
931 src_loc: Zcu.LazySrcLoc,
932 lazy_sym: link.File.LazySymbol,
933 code: *std.ArrayList(u8),
934 debug_output: DebugInfoOutput,
935) CodeGenError!Result {
936 const comp = bin_file.comp;
937 const gpa = comp.gpa;
938 const mod = comp.root_mod;
939
940 var function: Func = .{
941 .gpa = gpa,
942 .air = undefined,
943 .pt = pt,
944 .mod = mod,
945 .bin_file = bin_file,
946 .liveness = undefined,
947 .target = &mod.resolved_target.result,
948 .debug_output = debug_output,
949 .owner = .{ .lazy_sym = lazy_sym },
950 .err_msg = null,
951 .args = undefined, // populated after `resolveCallingConventionValues`
952 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
953 .fn_type = undefined,
954 .arg_index = 0,
955 .branch_stack = undefined,
956 .src_loc = src_loc,
957 .end_di_line = undefined,
958 .end_di_column = undefined,
959 .scope_generation = 0,
960 .avl = null,
961 .vtype = null,
962 };
963 defer function.mir_instructions.deinit(gpa);
964
965 function.genLazy(lazy_sym) catch |err| switch (err) {
966 error.CodegenFail => return Result{ .fail = function.err_msg.? },
967 error.OutOfRegisters => return Result{
968 .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
969 },
970 else => |e| return e,
971 };
972
973 var mir: Mir = .{
974 .instructions = function.mir_instructions.toOwnedSlice(),
975 .frame_locs = function.frame_locs.toOwnedSlice(),
976 };
977 defer mir.deinit(gpa);
978
979 var emit: Emit = .{
980 .lower = .{
981 .pt = pt,
982 .allocator = gpa,
983 .mir = mir,
984 .cc = .Unspecified,
985 .src_loc = src_loc,
986 .output_mode = comp.config.output_mode,
987 .link_mode = comp.config.link_mode,
988 .pic = mod.pic,
989 },
990 .bin_file = bin_file,
991 .debug_output = debug_output,
992 .code = code,
993 .prev_di_pc = undefined, // no debug info yet
994 .prev_di_line = undefined, // no debug info yet
995 .prev_di_column = undefined, // no debug info yet
996 };
997 defer emit.deinit();
998
999 emit.emitMir() catch |err| switch (err) {
1000 error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? },
1001 error.InvalidInstruction => |e| {
1002 const msg = switch (e) {
1003 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
1004 };
1005 return Result{
1006 .fail = try ErrorMsg.create(
1007 gpa,
1008 src_loc,
1009 "{s} This is a bug in the Zig compiler.",
1010 .{msg},
1011 ),
1012 };
1013 },
1014 else => |e| return e,
1015 };
1016
1017 if (function.err_msg) |em| {
1018 return Result{ .fail = em };
1019 } else {
1020 return Result.ok;
1021 }
1022}
1023
8811024const FormatWipMirData = struct {
8821025 func: *Func,
8831026 inst: Mir.Inst.Index,
......@@ -895,7 +1038,6 @@ fn formatWipMir(
8951038 .allocator = data.func.gpa,
8961039 .mir = .{
8971040 .instructions = data.func.mir_instructions.slice(),
898 .extra = data.func.mir_extra.items,
8991041 .frame_locs = data.func.frame_locs.slice(),
9001042 },
9011043 .cc = .Unspecified,
......@@ -946,7 +1088,7 @@ fn formatDecl(
9461088}
9471089fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
9481090 return .{ .data = .{
949 .zcu = func.zcu,
1091 .zcu = func.pt.zcu,
9501092 .decl_index = decl_index,
9511093 } };
9521094}
......@@ -993,7 +1135,7 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
9931135 try func.mir_instructions.ensureUnusedCapacity(gpa, 1);
9941136 const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len);
9951137 func.mir_instructions.appendAssumeCapacity(inst);
996 if (inst.tag != .pseudo or switch (inst.ops) {
1138 if (switch (inst.tag) {
9971139 else => true,
9981140 .pseudo_dbg_prologue_end,
9991141 .pseudo_dbg_line_column,
......@@ -1004,65 +1146,26 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
10041146 return result_index;
10051147}
10061148
1007fn addNop(func: *Func) error{OutOfMemory}!Mir.Inst.Index {
1149fn addPseudo(func: *Func, mnem: Mnemonic) error{OutOfMemory}!Mir.Inst.Index {
10081150 return func.addInst(.{
1009 .tag = .nop,
1010 .ops = .none,
1011 .data = undefined,
1151 .tag = mnem,
1152 .data = .none,
10121153 });
10131154}
10141155
1015fn addPseudoNone(func: *Func, ops: Mir.Inst.Ops) !void {
1016 _ = try func.addInst(.{
1017 .tag = .pseudo,
1018 .ops = ops,
1019 .data = undefined,
1020 });
1021}
1022
1023fn addPseudo(func: *Func, ops: Mir.Inst.Ops) !Mir.Inst.Index {
1024 return func.addInst(.{
1025 .tag = .pseudo,
1026 .ops = ops,
1027 .data = undefined,
1028 });
1029}
1030
1031pub fn addExtra(func: *Func, extra: anytype) Allocator.Error!u32 {
1032 const fields = std.meta.fields(@TypeOf(extra));
1033 try func.mir_extra.ensureUnusedCapacity(func.gpa, fields.len);
1034 return func.addExtraAssumeCapacity(extra);
1035}
1036
1037pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
1038 const fields = std.meta.fields(@TypeOf(extra));
1039 const result: u32 = @intCast(func.mir_extra.items.len);
1040 inline for (fields) |field| {
1041 func.mir_extra.appendAssumeCapacity(switch (field.type) {
1042 u32 => @field(extra, field.name),
1043 i32 => @bitCast(@field(extra, field.name)),
1044 else => @compileError("bad field type"),
1045 });
1046 }
1047 return result;
1048}
1049
10501156/// Returns a temporary register that contains the value of the `reg` csr.
10511157///
10521158/// Caller's duty to lock the return register is needed.
10531159fn getCsr(func: *Func, csr: CSR) !Register {
10541160 assert(func.hasFeature(.zicsr));
1055 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.usize));
1161 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.u64));
10561162 _ = try func.addInst(.{
10571163 .tag = .csrrs,
1058 .ops = .csr,
1059 .data = .{
1060 .csr = .{
1061 .csr = csr,
1062 .rd = dst_reg,
1063 .rs1 = .x0,
1064 },
1065 },
1164 .data = .{ .csr = .{
1165 .csr = csr,
1166 .rd = dst_reg,
1167 .rs1 = .x0,
1168 } },
10661169 });
10671170 return dst_reg;
10681171}
......@@ -1081,7 +1184,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
10811184 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
10821185 _ = try func.addInst(.{
10831186 .tag = .vsetvli,
1084 .ops = .rri,
10851187 .data = .{ .i_type = .{
10861188 .rd = dst_reg,
10871189 .rs1 = .zero,
......@@ -1094,7 +1196,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
10941196 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));
10951197 _ = try func.addInst(.{
10961198 .tag = .vsetivli,
1097 .ops = .rri,
10981199 .data = .{
10991200 .i_type = .{
11001201 .rd = dst_reg,
......@@ -1105,10 +1206,9 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
11051206 });
11061207 } else {
11071208 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1108 const temp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = avl });
1209 const temp_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = avl });
11091210 _ = try func.addInst(.{
11101211 .tag = .vsetvli,
1111 .ops = .rri,
11121212 .data = .{ .i_type = .{
11131213 .rd = dst_reg,
11141214 .rs1 = temp_reg,
......@@ -1125,6 +1225,7 @@ const required_features = [_]Target.riscv.Feature{
11251225 .a,
11261226 .zicsr,
11271227 .v,
1228 .zbb,
11281229};
11291230
11301231fn gen(func: *Func) !void {
......@@ -1142,7 +1243,7 @@ fn gen(func: *Func) !void {
11421243 }
11431244
11441245 if (fn_info.cc != .Naked) {
1145 try func.addPseudoNone(.pseudo_dbg_prologue_end);
1246 _ = try func.addPseudo(.pseudo_dbg_prologue_end);
11461247
11471248 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);
11481249 const backpatch_ra_spill = try func.addPseudo(.pseudo_dead);
......@@ -1156,11 +1257,11 @@ fn gen(func: *Func) !void {
11561257 // The address where to store the return value for the caller is in a
11571258 // register which the callee is free to clobber. Therefore, we purposely
11581259 // spill it to stack immediately.
1159 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(Type.usize, pt));
1260 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(Type.u64, pt));
11601261 try func.genSetMem(
11611262 .{ .frame = frame_index },
11621263 0,
1163 Type.usize,
1264 Type.u64,
11641265 func.ret_mcv.long.address().offset(-func.ret_mcv.short.indirect.off),
11651266 );
11661267 func.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } };
......@@ -1172,11 +1273,11 @@ fn gen(func: *Func) !void {
11721273 try func.genBody(func.air.getMainBody());
11731274
11741275 for (func.exitlude_jump_relocs.items) |jmp_reloc| {
1175 func.mir_instructions.items(.data)[jmp_reloc].inst =
1276 func.mir_instructions.items(.data)[jmp_reloc].j_type.inst =
11761277 @intCast(func.mir_instructions.len);
11771278 }
11781279
1179 try func.addPseudoNone(.pseudo_dbg_epilogue_begin);
1280 _ = try func.addPseudo(.pseudo_dbg_epilogue_begin);
11801281
11811282 const backpatch_restore_callee_preserved_regs = try func.addPseudo(.pseudo_dead);
11821283 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);
......@@ -1186,14 +1287,11 @@ fn gen(func: *Func) !void {
11861287 // ret
11871288 _ = try func.addInst(.{
11881289 .tag = .jalr,
1189 .ops = .rri,
1190 .data = .{
1191 .i_type = .{
1192 .rd = .zero,
1193 .rs1 = .ra,
1194 .imm12 = Immediate.s(0),
1195 },
1196 },
1290 .data = .{ .i_type = .{
1291 .rd = .zero,
1292 .rs1 = .ra,
1293 .imm12 = Immediate.s(0),
1294 } },
11971295 });
11981296
11991297 const frame_layout = try func.computeFrameLayout();
......@@ -1201,7 +1299,6 @@ fn gen(func: *Func) !void {
12011299
12021300 func.mir_instructions.set(backpatch_stack_alloc, .{
12031301 .tag = .addi,
1204 .ops = .rri,
12051302 .data = .{ .i_type = .{
12061303 .rd = .sp,
12071304 .rs1 = .sp,
......@@ -1209,8 +1306,7 @@ fn gen(func: *Func) !void {
12091306 } },
12101307 });
12111308 func.mir_instructions.set(backpatch_ra_spill, .{
1212 .tag = .pseudo,
1213 .ops = .pseudo_store_rm,
1309 .tag = .pseudo_store_rm,
12141310 .data = .{ .rm = .{
12151311 .r = .ra,
12161312 .m = .{
......@@ -1220,8 +1316,7 @@ fn gen(func: *Func) !void {
12201316 } },
12211317 });
12221318 func.mir_instructions.set(backpatch_ra_restore, .{
1223 .tag = .pseudo,
1224 .ops = .pseudo_load_rm,
1319 .tag = .pseudo_load_rm,
12251320 .data = .{ .rm = .{
12261321 .r = .ra,
12271322 .m = .{
......@@ -1231,8 +1326,7 @@ fn gen(func: *Func) !void {
12311326 } },
12321327 });
12331328 func.mir_instructions.set(backpatch_fp_spill, .{
1234 .tag = .pseudo,
1235 .ops = .pseudo_store_rm,
1329 .tag = .pseudo_store_rm,
12361330 .data = .{ .rm = .{
12371331 .r = .s0,
12381332 .m = .{
......@@ -1242,8 +1336,7 @@ fn gen(func: *Func) !void {
12421336 } },
12431337 });
12441338 func.mir_instructions.set(backpatch_fp_restore, .{
1245 .tag = .pseudo,
1246 .ops = .pseudo_load_rm,
1339 .tag = .pseudo_load_rm,
12471340 .data = .{ .rm = .{
12481341 .r = .s0,
12491342 .m = .{
......@@ -1254,7 +1347,6 @@ fn gen(func: *Func) !void {
12541347 });
12551348 func.mir_instructions.set(backpatch_fp_add, .{
12561349 .tag = .addi,
1257 .ops = .rri,
12581350 .data = .{ .i_type = .{
12591351 .rd = .s0,
12601352 .rs1 = .sp,
......@@ -1263,7 +1355,6 @@ fn gen(func: *Func) !void {
12631355 });
12641356 func.mir_instructions.set(backpatch_stack_alloc_restore, .{
12651357 .tag = .addi,
1266 .ops = .rri,
12671358 .data = .{ .i_type = .{
12681359 .rd = .sp,
12691360 .rs1 = .sp,
......@@ -1273,27 +1364,24 @@ fn gen(func: *Func) !void {
12731364
12741365 if (need_save_reg) {
12751366 func.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{
1276 .tag = .pseudo,
1277 .ops = .pseudo_spill_regs,
1367 .tag = .pseudo_spill_regs,
12781368 .data = .{ .reg_list = frame_layout.save_reg_list },
12791369 });
12801370
12811371 func.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{
1282 .tag = .pseudo,
1283 .ops = .pseudo_restore_regs,
1372 .tag = .pseudo_restore_regs,
12841373 .data = .{ .reg_list = frame_layout.save_reg_list },
12851374 });
12861375 }
12871376 } else {
1288 try func.addPseudoNone(.pseudo_dbg_prologue_end);
1377 _ = try func.addPseudo(.pseudo_dbg_prologue_end);
12891378 try func.genBody(func.air.getMainBody());
1290 try func.addPseudoNone(.pseudo_dbg_epilogue_begin);
1379 _ = try func.addPseudo(.pseudo_dbg_epilogue_begin);
12911380 }
12921381
12931382 // Drop them off at the rbrace.
12941383 _ = try func.addInst(.{
1295 .tag = .pseudo,
1296 .ops = .pseudo_dbg_line_column,
1384 .tag = .pseudo_dbg_line_column,
12971385 .data = .{ .pseudo_dbg_line_column = .{
12981386 .line = func.end_di_line,
12991387 .column = func.end_di_column,
......@@ -1301,6 +1389,101 @@ fn gen(func: *Func) !void {
13011389 });
13021390}
13031391
1392fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
1393 const pt = func.pt;
1394 const mod = pt.zcu;
1395 const ip = &mod.intern_pool;
1396 switch (lazy_sym.ty.zigTypeTag(mod)) {
1397 .Enum => {
1398 const enum_ty = lazy_sym.ty;
1399 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
1400
1401 const param_regs = abi.Registers.Integer.function_arg_regs;
1402 const ret_reg = param_regs[0];
1403 const enum_mcv: MCValue = .{ .register = param_regs[1] };
1404
1405 const exitlude_jump_relocs = try func.gpa.alloc(Mir.Inst.Index, enum_ty.enumFieldCount(mod));
1406 defer func.gpa.free(exitlude_jump_relocs);
1407
1408 const data_reg, const data_lock = try func.allocReg(.int);
1409 defer func.register_manager.unlockReg(data_lock);
1410
1411 const elf_file = func.bin_file.cast(link.File.Elf).?;
1412 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, .{
1413 .kind = .const_data,
1414 .ty = enum_ty,
1415 }) catch |err|
1416 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
1417 const sym = elf_file.symbol(sym_index);
1418
1419 try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym.esym_index } });
1420
1421 const cmp_reg, const cmp_lock = try func.allocReg(.int);
1422 defer func.register_manager.unlockReg(cmp_lock);
1423
1424 var data_off: i32 = 0;
1425 const tag_names = enum_ty.enumFields(mod);
1426 for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| {
1427 const tag_name_len = tag_names.get(ip)[tag_index].length(ip);
1428 const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index));
1429 const tag_mcv = try func.genTypedValue(tag_val);
1430
1431 _ = try func.genBinOp(
1432 .cmp_neq,
1433 enum_mcv,
1434 enum_ty,
1435 tag_mcv,
1436 enum_ty,
1437 cmp_reg,
1438 );
1439 const skip_reloc = try func.condBr(Type.bool, .{ .register = cmp_reg });
1440
1441 try func.genSetMem(
1442 .{ .reg = ret_reg },
1443 0,
1444 Type.u64,
1445 .{ .register_offset = .{ .reg = data_reg, .off = data_off } },
1446 );
1447
1448 try func.genSetMem(
1449 .{ .reg = ret_reg },
1450 8,
1451 Type.u64,
1452 .{ .immediate = tag_name_len },
1453 );
1454
1455 exitlude_jump_reloc.* = try func.addInst(.{
1456 .tag = .pseudo_j,
1457 .data = .{ .j_type = .{
1458 .rd = .zero,
1459 .inst = undefined,
1460 } },
1461 });
1462 func.performReloc(skip_reloc);
1463
1464 data_off += @intCast(tag_name_len + 1);
1465 }
1466
1467 try func.airTrap();
1468
1469 for (exitlude_jump_relocs) |reloc| func.performReloc(reloc);
1470
1471 _ = try func.addInst(.{
1472 .tag = .jalr,
1473 .data = .{ .i_type = .{
1474 .rd = .zero,
1475 .rs1 = .ra,
1476 .imm12 = Immediate.s(0),
1477 } },
1478 });
1479 },
1480 else => return func.fail(
1481 "TODO implement {s} for {}",
1482 .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(pt) },
1483 ),
1484 }
1485}
1486
13041487fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13051488 const pt = func.pt;
13061489 const zcu = pt.zcu;
......@@ -1322,9 +1505,12 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13221505 .sub,
13231506 .sub_wrap,
13241507
1508 .add_sat,
1509
13251510 .mul,
13261511 .mul_wrap,
13271512 .div_trunc,
1513 .rem,
13281514
13291515 .shl, .shl_exact,
13301516 .shr, .shr_exact,
......@@ -1344,7 +1530,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13441530 .ptr_add,
13451531 .ptr_sub => try func.airPtrArithmetic(inst, tag),
13461532
1347 .rem,
13481533 .mod,
13491534 .div_float,
13501535 .div_floor,
......@@ -1373,7 +1558,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13731558 .shl_with_overflow => try func.airShlWithOverflow(inst),
13741559
13751560
1376 .add_sat => try func.airAddSat(inst),
13771561 .sub_sat => try func.airSubSat(inst),
13781562 .mul_sat => try func.airMulSat(inst),
13791563 .shl_sat => try func.airShlSat(inst),
......@@ -1440,8 +1624,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
14401624 .struct_field_val=> try func.airStructFieldVal(inst),
14411625 .float_from_int => try func.airFloatFromInt(inst),
14421626 .int_from_float => try func.airIntFromFloat(inst),
1443 .cmpxchg_strong => try func.airCmpxchg(inst),
1444 .cmpxchg_weak => try func.airCmpxchg(inst),
1627 .cmpxchg_strong => try func.airCmpxchg(inst, .strong),
1628 .cmpxchg_weak => try func.airCmpxchg(inst, .weak),
14451629 .atomic_rmw => try func.airAtomicRmw(inst),
14461630 .atomic_load => try func.airAtomicLoad(inst),
14471631 .memcpy => try func.airMemcpy(inst),
......@@ -1579,7 +1763,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
15791763 for (tracking.getRegs()) |reg| {
15801764 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
15811765 } else return std.debug.panic(
1582 \\%{} takes up these regs: {any}, however these regs {any}, don't use it
1766 \\%{} takes up these regs: {any}, however this regs {any}, don't use it
15831767 , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) });
15841768 }
15851769 }
......@@ -1657,7 +1841,7 @@ fn finishAir(
16571841}
16581842
16591843const FrameLayout = struct {
1660 stack_adjust: u32,
1844 stack_adjust: i12,
16611845 save_reg_list: Mir.RegisterList,
16621846};
16631847
......@@ -1671,10 +1855,7 @@ fn setFrameLoc(
16711855 const frame_i = @intFromEnum(frame_index);
16721856 if (aligned) {
16731857 const alignment: InternPool.Alignment = func.frame_allocs.items(.abi_align)[frame_i];
1674 offset.* = if (math.sign(offset.*) < 0)
1675 -1 * @as(i32, @intCast(alignment.backward(@intCast(@abs(offset.*)))))
1676 else
1677 @intCast(alignment.forward(@intCast(@abs(offset.*))));
1858 offset.* = math.sign(offset.*) * @as(i32, @intCast(alignment.backward(@intCast(@abs(offset.*)))));
16781859 }
16791860 func.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });
16801861 offset.* += func.frame_allocs.items(.abi_size)[frame_i];
......@@ -1717,8 +1898,8 @@ fn computeFrameLayout(func: *Func) !FrameLayout {
17171898 }
17181899 break :blk i;
17191900 };
1720 const saved_reg_size = save_reg_list.size();
17211901
1902 const saved_reg_size = save_reg_list.size();
17221903 frame_size[@intFromEnum(FrameIndex.spill_frame)] = @intCast(saved_reg_size);
17231904
17241905 // The total frame size is calculated by the amount of s registers you need to save * 8, as each
......@@ -1811,12 +1992,14 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
18111992 .signedness = .unsigned,
18121993 .bits = @intCast(ty.bitSize(pt)),
18131994 };
1995 assert(reg.class() == .int);
1996
18141997 const shift = math.cast(u6, 64 - int_info.bits % 64) orelse return;
18151998 switch (int_info.signedness) {
18161999 .signed => {
18172000 _ = try func.addInst(.{
18182001 .tag = .slli,
1819 .ops = .rri,
2002
18202003 .data = .{
18212004 .i_type = .{
18222005 .rd = reg,
......@@ -1827,7 +2010,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
18272010 });
18282011 _ = try func.addInst(.{
18292012 .tag = .srai,
1830 .ops = .rri,
2013
18312014 .data = .{
18322015 .i_type = .{
18332016 .rd = reg,
......@@ -1842,7 +2025,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
18422025 if (mask < 256) {
18432026 _ = try func.addInst(.{
18442027 .tag = .andi,
1845 .ops = .rri,
2028
18462029 .data = .{
18472030 .i_type = .{
18482031 .rd = reg,
......@@ -1854,7 +2037,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
18542037 } else {
18552038 _ = try func.addInst(.{
18562039 .tag = .slli,
1857 .ops = .rri,
2040
18582041 .data = .{
18592042 .i_type = .{
18602043 .rd = reg,
......@@ -1865,7 +2048,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
18652048 });
18662049 _ = try func.addInst(.{
18672050 .tag = .srli,
1868 .ops = .rri,
2051
18692052 .data = .{
18702053 .i_type = .{
18712054 .rd = reg,
......@@ -1879,15 +2062,6 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
18792062 }
18802063}
18812064
1882fn symbolIndex(func: *Func) !u32 {
1883 const pt = func.pt;
1884 const zcu = pt.zcu;
1885 const decl_index = zcu.funcOwnerDeclIndex(func.func_index);
1886 const elf_file = func.bin_file.cast(link.File.Elf).?;
1887 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
1888 return atom_index;
1889}
1890
18912065fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex {
18922066 const frame_allocs_slice = func.frame_allocs.slice();
18932067 const frame_size = frame_allocs_slice.items(.abi_size);
......@@ -2051,6 +2225,10 @@ pub fn spillInstruction(func: *Func, reg: Register, inst: Air.Inst.Index) !void
20512225 try tracking.trackSpill(func, inst);
20522226}
20532227
2228pub fn spillRegisters(func: *Func, comptime registers: []const Register) !void {
2229 inline for (registers) |reg| try func.register_manager.getKnownReg(reg, null);
2230}
2231
20542232/// Copies a value to a register without tracking the register. The register is not considered
20552233/// allocated. A second call to `copyToTmpRegister` may return the same register.
20562234/// This can have a side effect of spilling instructions to the stack to free up a register.
......@@ -2151,11 +2329,16 @@ fn airTrunc(func: *Func, inst: Air.Inst.Index) !void {
21512329 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
21522330 if (func.liveness.isUnused(inst))
21532331 return func.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2154
2332 // we assume no zeroext in the "Zig ABI", so it's fine to just not truncate it.
21552333 const operand = try func.resolveInst(ty_op.operand);
2156 _ = operand;
2157 return func.fail("TODO implement trunc for {}", .{func.target.cpu.arch});
2158 // return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2334
2335 // we can do it just to be safe, but this shouldn't be needed for no-runtime safety modes
2336 switch (operand) {
2337 .register => |reg| try func.truncateRegister(func.typeOf(ty_op.operand), reg),
2338 else => {},
2339 }
2340
2341 return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
21592342}
21602343
21612344fn airIntFromBool(func: *Func, inst: Air.Inst.Index) !void {
......@@ -2186,8 +2369,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
21862369 switch (ty.zigTypeTag(zcu)) {
21872370 .Bool => {
21882371 _ = try func.addInst(.{
2189 .tag = .pseudo,
2190 .ops = .pseudo_not,
2372 .tag = .pseudo_not,
21912373 .data = .{
21922374 .rr = .{
21932375 .rs = operand_reg,
......@@ -2205,7 +2387,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
22052387 32, 64 => {
22062388 _ = try func.addInst(.{
22072389 .tag = .xori,
2208 .ops = .rri,
22092390 .data = .{
22102391 .i_type = .{
22112392 .rd = dst_reg,
......@@ -2305,10 +2486,7 @@ fn binOp(
23052486 80, 128 => true,
23062487 else => unreachable,
23072488 };
2308 switch (air_tag) {
2309 .rem, .mod => {},
2310 else => if (!type_needs_libcall) break :libcall,
2311 }
2489 if (!type_needs_libcall) break :libcall;
23122490 return func.fail("binOp libcall runtime-float ops", .{});
23132491 }
23142492
......@@ -2367,7 +2545,6 @@ fn genBinOp(
23672545 const pt = func.pt;
23682546 const zcu = pt.zcu;
23692547 const bit_size = lhs_ty.bitSize(pt);
2370 assert(bit_size <= 64);
23712548
23722549 const is_unsigned = lhs_ty.isUnsignedInt(zcu);
23732550
......@@ -2384,16 +2561,30 @@ fn genBinOp(
23842561 .sub_wrap,
23852562 .mul,
23862563 .mul_wrap,
2564 .rem,
2565 .div_trunc,
23872566 => {
2388 if (!math.isPowerOfTwo(bit_size))
2389 return func.fail(
2390 "TODO: genBinOp {s} non-pow 2, found {}",
2391 .{ @tagName(tag), bit_size },
2392 );
2567 switch (tag) {
2568 .rem,
2569 .div_trunc,
2570 => {
2571 if (!math.isPowerOfTwo(bit_size)) {
2572 try func.truncateRegister(lhs_ty, lhs_reg);
2573 try func.truncateRegister(rhs_ty, rhs_reg);
2574 }
2575 },
2576 else => {
2577 if (!math.isPowerOfTwo(bit_size))
2578 return func.fail(
2579 "TODO: genBinOp verify {s} non-pow 2, found {}",
2580 .{ @tagName(tag), bit_size },
2581 );
2582 },
2583 }
23932584
23942585 switch (lhs_ty.zigTypeTag(zcu)) {
23952586 .Int => {
2396 const mir_tag: Mir.Inst.Tag = switch (tag) {
2587 const mnem: Mnemonic = switch (tag) {
23972588 .add, .add_wrap => switch (bit_size) {
23982589 8, 16, 64 => .add,
23992590 32 => .addw,
......@@ -2409,12 +2600,19 @@ fn genBinOp(
24092600 32 => .mulw,
24102601 else => unreachable,
24112602 },
2603 .rem => switch (bit_size) {
2604 8, 16, 32 => if (is_unsigned) .remuw else .remw,
2605 else => if (is_unsigned) .remu else .rem,
2606 },
2607 .div_trunc => switch (bit_size) {
2608 8, 16, 32 => if (is_unsigned) .divuw else .divw,
2609 else => if (is_unsigned) .divu else .div,
2610 },
24122611 else => unreachable,
24132612 };
24142613
24152614 _ = try func.addInst(.{
2416 .tag = mir_tag,
2417 .ops = .rrr,
2615 .tag = mnem,
24182616 .data = .{
24192617 .r_type = .{
24202618 .rd = dst_reg,
......@@ -2423,17 +2621,9 @@ fn genBinOp(
24232621 },
24242622 },
24252623 });
2426
2427 // truncate when the instruction is larger than the bit size.
2428 switch (bit_size) {
2429 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2430 32 => {}, // addw/subw affects the first 32-bits
2431 64 => {}, // add/sub affects the entire register
2432 else => unreachable,
2433 }
24342624 },
24352625 .Float => {
2436 const mir_tag: Mir.Inst.Tag = switch (tag) {
2626 const mir_tag: Mnemonic = switch (tag) {
24372627 .add => switch (bit_size) {
24382628 32 => .fadds,
24392629 64 => .faddd,
......@@ -2449,12 +2639,11 @@ fn genBinOp(
24492639 64 => .fmuld,
24502640 else => unreachable,
24512641 },
2452 else => unreachable,
2642 else => return func.fail("TODO: genBinOp {s} Float", .{@tagName(tag)}),
24532643 };
24542644
24552645 _ = try func.addInst(.{
24562646 .tag = mir_tag,
2457 .ops = .rrr,
24582647 .data = .{
24592648 .r_type = .{
24602649 .rd = dst_reg,
......@@ -2470,7 +2659,7 @@ fn genBinOp(
24702659
24712660 const child_ty = lhs_ty.childType(zcu);
24722661
2473 const mir_tag: Mir.Inst.Tag = switch (tag) {
2662 const mir_tag: Mnemonic = switch (tag) {
24742663 .add => switch (child_ty.zigTypeTag(zcu)) {
24752664 .Int => .vaddvv,
24762665 .Float => .vfaddvv,
......@@ -2481,6 +2670,11 @@ fn genBinOp(
24812670 .Float => .vfsubvv,
24822671 else => unreachable,
24832672 },
2673 .mul => switch (child_ty.zigTypeTag(zcu)) {
2674 .Int => .vmulvv,
2675 .Float => .vfmulvv,
2676 else => unreachable,
2677 },
24842678 else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}),
24852679 };
24862680
......@@ -2490,7 +2684,7 @@ fn genBinOp(
24902684 16 => .@"16",
24912685 32 => .@"32",
24922686 64 => .@"64",
2493 else => unreachable,
2687 else => return func.fail("TODO: genBinOp > 64 bit elements, found {d}", .{elem_size}),
24942688 },
24952689 .vlmul = .m1,
24962690 .vma = true,
......@@ -2499,7 +2693,6 @@ fn genBinOp(
24992693
25002694 _ = try func.addInst(.{
25012695 .tag = mir_tag,
2502 .ops = .rrr,
25032696 .data = .{
25042697 .r_type = .{
25052698 .rd = dst_reg,
......@@ -2513,6 +2706,53 @@ fn genBinOp(
25132706 }
25142707 },
25152708
2709 .add_sat,
2710 => {
2711 if (bit_size != 64 or !is_unsigned)
2712 return func.fail("TODO: genBinOp ty: {}", .{lhs_ty.fmt(pt)});
2713
2714 const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg });
2715 const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg);
2716 defer func.register_manager.unlockReg(tmp_lock);
2717
2718 _ = try func.addInst(.{
2719 .tag = .add,
2720 .data = .{ .r_type = .{
2721 .rd = tmp_reg,
2722 .rs1 = rhs_reg,
2723 .rs2 = lhs_reg,
2724 } },
2725 });
2726
2727 _ = try func.addInst(.{
2728 .tag = .sltu,
2729 .data = .{ .r_type = .{
2730 .rd = dst_reg,
2731 .rs1 = tmp_reg,
2732 .rs2 = lhs_reg,
2733 } },
2734 });
2735
2736 // neg dst_reg, dst_reg
2737 _ = try func.addInst(.{
2738 .tag = .sub,
2739 .data = .{ .r_type = .{
2740 .rd = dst_reg,
2741 .rs1 = .zero,
2742 .rs2 = dst_reg,
2743 } },
2744 });
2745
2746 _ = try func.addInst(.{
2747 .tag = .@"or",
2748 .data = .{ .r_type = .{
2749 .rd = dst_reg,
2750 .rs1 = dst_reg,
2751 .rs2 = tmp_reg,
2752 } },
2753 });
2754 },
2755
25162756 .ptr_add,
25172757 .ptr_sub,
25182758 => {
......@@ -2523,14 +2763,14 @@ fn genBinOp(
25232763
25242764 // RISC-V has no immediate mul, so we copy the size to a temporary register
25252765 const elem_size = lhs_ty.elemType2(zcu).abiSize(pt);
2526 const elem_size_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = elem_size });
2766 const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });
25272767
25282768 try func.genBinOp(
25292769 .mul,
25302770 tmp_mcv,
25312771 rhs_ty,
25322772 .{ .register = elem_size_reg },
2533 Type.usize,
2773 Type.u64,
25342774 tmp_reg,
25352775 );
25362776
......@@ -2541,9 +2781,9 @@ fn genBinOp(
25412781 else => unreachable,
25422782 },
25432783 lhs_mcv,
2544 Type.usize, // we know it's a pointer, so it'll be usize.
2784 Type.u64, // we know it's a pointer, so it'll be usize.
25452785 tmp_mcv,
2546 Type.usize,
2786 Type.u64,
25472787 dst_reg,
25482788 );
25492789 },
......@@ -2559,7 +2799,6 @@ fn genBinOp(
25592799 .bit_or, .bool_or => .@"or",
25602800 else => unreachable,
25612801 },
2562 .ops = .rrr,
25632802 .data = .{
25642803 .r_type = .{
25652804 .rd = dst_reg,
......@@ -2577,18 +2816,23 @@ fn genBinOp(
25772816 }
25782817 },
25792818
2580 .div_trunc,
2819 .shr,
2820 .shr_exact,
2821 .shl,
2822 .shl_exact,
25812823 => {
2582 if (!math.isPowerOfTwo(bit_size))
2583 return func.fail(
2584 "TODO: genBinOp {s} non-pow 2, found {}",
2585 .{ @tagName(tag), bit_size },
2586 );
2824 if (bit_size > 64) return func.fail("TODO: genBinOp shift > 64 bits, {}", .{bit_size});
2825 try func.truncateRegister(rhs_ty, rhs_reg);
25872826
2588 const mir_tag: Mir.Inst.Tag = switch (tag) {
2589 .div_trunc => switch (bit_size) {
2590 8, 16, 32 => if (is_unsigned) .divuw else .divw,
2591 64 => if (is_unsigned) .divu else .div,
2827 const mir_tag: Mnemonic = switch (tag) {
2828 .shl, .shl_exact => switch (bit_size) {
2829 1...31, 33...64 => .sll,
2830 32 => .sllw,
2831 else => unreachable,
2832 },
2833 .shr, .shr_exact => switch (bit_size) {
2834 1...31, 33...64 => .srl,
2835 32 => .srlw,
25922836 else => unreachable,
25932837 },
25942838 else => unreachable,
......@@ -2596,71 +2840,12 @@ fn genBinOp(
25962840
25972841 _ = try func.addInst(.{
25982842 .tag = mir_tag,
2599 .ops = .rrr,
2600 .data = .{
2601 .r_type = .{
2602 .rd = dst_reg,
2603 .rs1 = lhs_reg,
2604 .rs2 = rhs_reg,
2605 },
2606 },
2607 });
2608
2609 if (!is_unsigned) {
2610 // truncate when the instruction is larger than the bit size.
2611 switch (bit_size) {
2612 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2613 32 => {}, // divw affects the first 32-bits
2614 64 => {}, // div affects the entire register
2615 else => unreachable,
2616 }
2617 }
2618 },
2619
2620 .shr,
2621 .shr_exact,
2622 .shl,
2623 .shl_exact,
2624 => {
2625 if (!math.isPowerOfTwo(bit_size))
2626 return func.fail(
2627 "TODO: genBinOp {s} non-pow 2, found {}",
2628 .{ @tagName(tag), bit_size },
2629 );
2630
2631 // it's important that the shift amount is exact
2632 try func.truncateRegister(rhs_ty, rhs_reg);
2633
2634 const mir_tag: Mir.Inst.Tag = switch (tag) {
2635 .shl, .shl_exact => switch (bit_size) {
2636 8, 16, 64 => .sll,
2637 32 => .sllw,
2638 else => unreachable,
2639 },
2640 .shr, .shr_exact => switch (bit_size) {
2641 8, 16, 64 => .srl,
2642 32 => .srlw,
2643 else => unreachable,
2644 },
2645 else => unreachable,
2646 };
2647
2648 _ = try func.addInst(.{
2649 .tag = mir_tag,
2650 .ops = .rrr,
26512843 .data = .{ .r_type = .{
26522844 .rd = dst_reg,
26532845 .rs1 = lhs_reg,
26542846 .rs2 = rhs_reg,
26552847 } },
26562848 });
2657
2658 switch (bit_size) {
2659 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2660 32 => {},
2661 64 => {},
2662 else => unreachable,
2663 }
26642849 },
26652850
26662851 // TODO: move the isel logic out of lower and into here.
......@@ -2671,9 +2856,14 @@ fn genBinOp(
26712856 .cmp_gt,
26722857 .cmp_gte,
26732858 => {
2859 assert(lhs_reg.class() == rhs_reg.class());
2860 if (lhs_reg.class() == .int) {
2861 try func.truncateRegister(lhs_ty, lhs_reg);
2862 try func.truncateRegister(rhs_ty, rhs_reg);
2863 }
2864
26742865 _ = try func.addInst(.{
2675 .tag = .pseudo,
2676 .ops = .pseudo_compare,
2866 .tag = .pseudo_compare,
26772867 .data = .{
26782868 .compare = .{
26792869 .op = switch (tag) {
......@@ -2719,60 +2909,60 @@ fn genBinOp(
27192909 // a1, s0 was -1, flipping all the bits in a2 and effectively restoring a0. If a0 was greater than or equal to a1,
27202910 // s0 was 0, leaving a2 unchanged as a0.
27212911 .min, .max => {
2722 const int_info = lhs_ty.intInfo(zcu);
2912 switch (lhs_ty.zigTypeTag(zcu)) {
2913 .Int => {
2914 const int_info = lhs_ty.intInfo(zcu);
27232915
2724 const mask_reg, const mask_lock = try func.allocReg(.int);
2725 defer func.register_manager.unlockReg(mask_lock);
2916 const mask_reg, const mask_lock = try func.allocReg(.int);
2917 defer func.register_manager.unlockReg(mask_lock);
27262918
2727 _ = try func.addInst(.{
2728 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
2729 .ops = .rrr,
2730 .data = .{ .r_type = .{
2731 .rd = mask_reg,
2732 .rs1 = lhs_reg,
2733 .rs2 = rhs_reg,
2734 } },
2735 });
2919 _ = try func.addInst(.{
2920 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
2921 .data = .{ .r_type = .{
2922 .rd = mask_reg,
2923 .rs1 = lhs_reg,
2924 .rs2 = rhs_reg,
2925 } },
2926 });
27362927
2737 _ = try func.addInst(.{
2738 .tag = .sub,
2739 .ops = .rrr,
2740 .data = .{ .r_type = .{
2741 .rd = mask_reg,
2742 .rs1 = .zero,
2743 .rs2 = mask_reg,
2744 } },
2745 });
2928 _ = try func.addInst(.{
2929 .tag = .sub,
2930 .data = .{ .r_type = .{
2931 .rd = mask_reg,
2932 .rs1 = .zero,
2933 .rs2 = mask_reg,
2934 } },
2935 });
27462936
2747 _ = try func.addInst(.{
2748 .tag = .xor,
2749 .ops = .rrr,
2750 .data = .{ .r_type = .{
2751 .rd = dst_reg,
2752 .rs1 = lhs_reg,
2753 .rs2 = rhs_reg,
2754 } },
2755 });
2937 _ = try func.addInst(.{
2938 .tag = .xor,
2939 .data = .{ .r_type = .{
2940 .rd = dst_reg,
2941 .rs1 = lhs_reg,
2942 .rs2 = rhs_reg,
2943 } },
2944 });
27562945
2757 _ = try func.addInst(.{
2758 .tag = .@"and",
2759 .ops = .rrr,
2760 .data = .{ .r_type = .{
2761 .rd = mask_reg,
2762 .rs1 = dst_reg,
2763 .rs2 = mask_reg,
2764 } },
2765 });
2946 _ = try func.addInst(.{
2947 .tag = .@"and",
2948 .data = .{ .r_type = .{
2949 .rd = mask_reg,
2950 .rs1 = dst_reg,
2951 .rs2 = mask_reg,
2952 } },
2953 });
27662954
2767 _ = try func.addInst(.{
2768 .tag = .xor,
2769 .ops = .rrr,
2770 .data = .{ .r_type = .{
2771 .rd = dst_reg,
2772 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
2773 .rs2 = mask_reg,
2774 } },
2775 });
2955 _ = try func.addInst(.{
2956 .tag = .xor,
2957 .data = .{ .r_type = .{
2958 .rd = dst_reg,
2959 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
2960 .rs2 = mask_reg,
2961 } },
2962 });
2963 },
2964 else => |t| return func.fail("TODO: genBinOp min/max for {s}", .{@tagName(t)}),
2965 }
27762966 },
27772967 else => return func.fail("TODO: genBinOp {}", .{tag}),
27782968 }
......@@ -2791,12 +2981,14 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27912981 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
27922982 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
27932983
2984 const rhs_ty = func.typeOf(extra.rhs);
2985 const lhs_ty = func.typeOf(extra.lhs);
2986
27942987 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2795 const ty = func.typeOf(extra.lhs);
2796 switch (ty.zigTypeTag(zcu)) {
2988 switch (lhs_ty.zigTypeTag(zcu)) {
27972989 .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}),
27982990 .Int => {
2799 const int_info = ty.intInfo(zcu);
2991 const int_info = lhs_ty.intInfo(zcu);
28002992
28012993 const tuple_ty = func.typeOfIndex(inst);
28022994 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
......@@ -2805,26 +2997,29 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
28052997 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
28062998 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
28072999
2808 const add_result_reg = try func.copyToTmpRegister(ty, add_result);
2809 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2810 defer func.register_manager.unlockReg(add_result_reg_lock);
2811
28123000 try func.genSetMem(
28133001 .{ .frame = offset.index },
28143002 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2815 ty,
3003 lhs_ty,
28163004 add_result,
28173005 );
28183006
3007 const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result);
3008 const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg);
3009 defer func.register_manager.unlockReg(trunc_reg_lock);
3010
28193011 const overflow_reg, const overflow_lock = try func.allocReg(.int);
28203012 defer func.register_manager.unlockReg(overflow_lock);
28213013
3014 // if the result isn't equal after truncating it to the given type,
3015 // an overflow must have happened.
3016 try func.truncateRegister(lhs_ty, trunc_reg);
28223017 try func.genBinOp(
28233018 .cmp_neq,
2824 .{ .register = add_result_reg },
2825 ty,
2826 .{ .register = add_result_reg },
2827 ty,
3019 add_result,
3020 lhs_ty,
3021 .{ .register = trunc_reg },
3022 rhs_ty,
28283023 overflow_reg,
28293024 );
28303025
......@@ -2837,7 +3032,68 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
28373032
28383033 break :result result_mcv;
28393034 } else {
2840 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
3035 const rhs_mcv = try func.resolveInst(extra.rhs);
3036 const lhs_mcv = try func.resolveInst(extra.lhs);
3037
3038 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv);
3039 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv);
3040 defer {
3041 if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
3042 if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
3043 }
3044
3045 try func.truncateRegister(rhs_ty, rhs_reg);
3046 try func.truncateRegister(lhs_ty, lhs_reg);
3047
3048 const dest_reg, const dest_lock = try func.allocReg(.int);
3049 defer func.register_manager.unlockReg(dest_lock);
3050
3051 _ = try func.addInst(.{
3052 .tag = .add,
3053 .data = .{ .r_type = .{
3054 .rs1 = rhs_reg,
3055 .rs2 = lhs_reg,
3056 .rd = dest_reg,
3057 } },
3058 });
3059
3060 try func.truncateRegister(func.typeOfIndex(inst), dest_reg);
3061 const add_result: MCValue = .{ .register = dest_reg };
3062
3063 try func.genSetMem(
3064 .{ .frame = offset.index },
3065 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
3066 lhs_ty,
3067 add_result,
3068 );
3069
3070 const trunc_reg = try func.copyToTmpRegister(lhs_ty, add_result);
3071 const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg);
3072 defer func.register_manager.unlockReg(trunc_reg_lock);
3073
3074 const overflow_reg, const overflow_lock = try func.allocReg(.int);
3075 defer func.register_manager.unlockReg(overflow_lock);
3076
3077 // if the result isn't equal after truncating it to the given type,
3078 // an overflow must have happened.
3079 try func.truncateRegister(lhs_ty, trunc_reg);
3080 try func.genBinOp(
3081 .cmp_neq,
3082 add_result,
3083 lhs_ty,
3084 .{ .register = trunc_reg },
3085 rhs_ty,
3086 overflow_reg,
3087 );
3088
3089 try func.genSetMem(
3090 .{ .frame = offset.index },
3091 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),
3092 Type.u1,
3093 .{ .register = overflow_reg },
3094 );
3095
3096 break :result result_mcv;
28413097 }
28423098 },
28433099 else => unreachable,
......@@ -2890,7 +3146,7 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
28903146 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs);
28913147 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
28923148
2893 const overflow_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = 0 });
3149 const overflow_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = 0 });
28943150
28953151 const overflow_lock = func.register_manager.lockRegAssumeUnused(overflow_reg);
28963152 defer func.register_manager.unlockReg(overflow_lock);
......@@ -2899,7 +3155,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
28993155 .unsigned => {
29003156 _ = try func.addInst(.{
29013157 .tag = .sltu,
2902 .ops = .rrr,
29033158 .data = .{ .r_type = .{
29043159 .rd = overflow_reg,
29053160 .rs1 = lhs_reg,
......@@ -2921,7 +3176,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
29213176 64 => {
29223177 _ = try func.addInst(.{
29233178 .tag = .slt,
2924 .ops = .rrr,
29253179 .data = .{ .r_type = .{
29263180 .rd = overflow_reg,
29273181 .rs1 = overflow_reg,
......@@ -2931,7 +3185,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
29313185
29323186 _ = try func.addInst(.{
29333187 .tag = .slt,
2934 .ops = .rrr,
29353188 .data = .{ .r_type = .{
29363189 .rd = rhs_reg,
29373190 .rs1 = rhs_reg,
......@@ -2941,7 +3194,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
29413194
29423195 _ = try func.addInst(.{
29433196 .tag = .xor,
2944 .ops = .rrr,
29453197 .data = .{ .r_type = .{
29463198 .rd = lhs_reg,
29473199 .rs1 = overflow_reg,
......@@ -2952,9 +3204,9 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
29523204 try func.genBinOp(
29533205 .cmp_neq,
29543206 .{ .register = overflow_reg },
2955 Type.usize,
3207 Type.u64,
29563208 .{ .register = rhs_reg },
2957 Type.usize,
3209 Type.u64,
29583210 overflow_reg,
29593211 );
29603212
......@@ -3017,61 +3269,34 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
30173269 switch (lhs_ty.zigTypeTag(zcu)) {
30183270 else => |x| return func.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}),
30193271 .Int => {
3020 assert(lhs_ty.eql(rhs_ty, zcu));
3021 const int_info = lhs_ty.intInfo(zcu);
3022 switch (int_info.bits) {
3023 1...32 => {
3024 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
3025 if (int_info.signedness == .unsigned) {
3026 switch (int_info.bits) {
3027 1...8 => {
3028 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
3029
3030 const add_reg, const add_lock = try func.promoteReg(lhs_ty, lhs);
3031 defer if (add_lock) |lock| func.register_manager.unlockReg(lock);
3032
3033 const overflow_reg, const overflow_lock = try func.allocReg(.int);
3034 defer func.register_manager.unlockReg(overflow_lock);
3035
3036 _ = try func.addInst(.{
3037 .tag = .andi,
3038 .ops = .rri,
3039 .data = .{ .i_type = .{
3040 .rd = overflow_reg,
3041 .rs1 = add_reg,
3042 .imm12 = Immediate.s(max_val),
3043 } },
3044 });
3045
3046 try func.genBinOp(
3047 .cmp_neq,
3048 .{ .register = overflow_reg },
3049 lhs_ty,
3050 .{ .register = add_reg },
3051 lhs_ty,
3052 overflow_reg,
3053 );
3054
3055 try func.genCopy(
3056 lhs_ty,
3057 result_mcv.offset(overflow_off),
3058 .{ .register = overflow_reg },
3059 );
3060
3061 break :result result_mcv;
3062 },
3063
3064 else => return func.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}),
3065 }
3066 } else {
3067 return func.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{});
3068 }
3069 } else {
3070 return func.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{});
3071 }
3072 },
3073 else => return func.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}),
3074 }
3272 if (std.debug.runtime_safety) assert(lhs_ty.eql(rhs_ty, zcu));
3273
3274 const trunc_reg = try func.copyToTmpRegister(lhs_ty, .{ .register = dest_reg });
3275 const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg);
3276 defer func.register_manager.unlockReg(trunc_reg_lock);
3277
3278 const overflow_reg, const overflow_lock = try func.allocReg(.int);
3279 defer func.register_manager.unlockReg(overflow_lock);
3280
3281 // if the result isn't equal after truncating it to the given type,
3282 // an overflow must have happened.
3283 try func.truncateRegister(func.typeOf(extra.lhs), trunc_reg);
3284 try func.genBinOp(
3285 .cmp_neq,
3286 .{ .register = dest_reg },
3287 lhs_ty,
3288 .{ .register = trunc_reg },
3289 rhs_ty,
3290 overflow_reg,
3291 );
3292
3293 try func.genCopy(
3294 lhs_ty,
3295 result_mcv.offset(overflow_off),
3296 .{ .register = overflow_reg },
3297 );
3298
3299 break :result result_mcv;
30753300 },
30763301 }
30773302 };
......@@ -3085,12 +3310,6 @@ fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
30853310 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
30863311}
30873312
3088fn airAddSat(func: *Func, inst: Air.Inst.Index) !void {
3089 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3090 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airAddSat", .{});
3091 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3092}
3093
30943313fn airSubSat(func: *Func, inst: Air.Inst.Index) !void {
30953314 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
30963315 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSubSat", .{});
......@@ -3300,19 +3519,21 @@ fn airWrapOptional(func: *Func, inst: Air.Inst.Index) !void {
33003519 };
33013520 defer if (pl_lock) |lock| func.register_manager.unlockReg(lock);
33023521
3303 const opt_mcv = try func.allocRegOrMem(opt_ty, inst, true);
3522 const opt_mcv = try func.allocRegOrMem(opt_ty, inst, false);
33043523 try func.genCopy(pl_ty, opt_mcv, pl_mcv);
33053524
33063525 if (!same_repr) {
33073526 const pl_abi_size: i32 = @intCast(pl_ty.abiSize(pt));
33083527 switch (opt_mcv) {
3309 .load_frame => |frame_addr| try func.genSetMem(
3310 .{ .frame = frame_addr.index },
3311 frame_addr.off + pl_abi_size,
3312 Type.u8,
3313 .{ .immediate = 1 },
3314 ),
3315 .register => return func.fail("TODO: airWrapOption opt_mcv register", .{}),
3528 .load_frame => |frame_addr| {
3529 try func.genCopy(pl_ty, opt_mcv, pl_mcv);
3530 try func.genSetMem(
3531 .{ .frame = frame_addr.index },
3532 frame_addr.off + pl_abi_size,
3533 Type.u8,
3534 .{ .immediate = 1 },
3535 );
3536 },
33163537 else => unreachable,
33173538 }
33183539 }
......@@ -3454,7 +3675,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
34543675 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
34553676
34563677 const dst_mcv = try func.allocRegOrMem(ty, inst, true);
3457 try func.genCopy(Type.usize, dst_mcv, len_mcv);
3678 try func.genCopy(Type.u64, dst_mcv, len_mcv);
34583679 break :result dst_mcv;
34593680 },
34603681 .register_pair => |pair| {
......@@ -3463,7 +3684,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
34633684 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
34643685
34653686 const dst_mcv = try func.allocRegOrMem(ty, inst, true);
3466 try func.genCopy(Type.usize, dst_mcv, len_mcv);
3687 try func.genCopy(Type.u64, dst_mcv, len_mcv);
34673688 break :result dst_mcv;
34683689 },
34693690 else => return func.fail("TODO airSliceLen for {}", .{src_mcv}),
......@@ -3474,14 +3695,28 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
34743695
34753696fn airPtrSliceLenPtr(func: *Func, inst: Air.Inst.Index) !void {
34763697 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3477 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_slice_len_ptr for {}", .{func.target.cpu.arch});
3698 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3699 const src_mcv = try func.resolveInst(ty_op.operand);
3700
3701 const dst_reg, const dst_lock = try func.allocReg(.int);
3702 defer func.register_manager.unlockReg(dst_lock);
3703 const dst_mcv: MCValue = .{ .register = dst_reg };
3704
3705 try func.genCopy(Type.u64, dst_mcv, src_mcv.offset(8));
3706 break :result dst_mcv;
3707 };
34783708 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
34793709}
34803710
34813711fn airPtrSlicePtrPtr(func: *Func, inst: Air.Inst.Index) !void {
34823712 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3483 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_slice_ptr_ptr for {}", .{func.target.cpu.arch});
3484 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3713
3714 const opt_mcv = try func.resolveInst(ty_op.operand);
3715 const dst_mcv = if (func.reuseOperand(inst, ty_op.operand, 0, opt_mcv))
3716 opt_mcv
3717 else
3718 try func.copyToNewRegister(inst, opt_mcv);
3719 return func.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
34853720}
34863721
34873722fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void {
......@@ -3538,11 +3773,10 @@ fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
35383773
35393774 const addr_reg, const addr_lock = try func.allocReg(.int);
35403775 defer func.register_manager.unlockReg(addr_lock);
3541 try func.genSetReg(Type.usize, addr_reg, slice_mcv);
3776 try func.genSetReg(Type.u64, addr_reg, slice_mcv);
35423777
35433778 _ = try func.addInst(.{
35443779 .tag = .add,
3545 .ops = .rrr,
35463780 .data = .{ .r_type = .{
35473781 .rd = addr_reg,
35483782 .rs1 = addr_reg,
......@@ -3576,12 +3810,12 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
35763810 .register => {
35773811 const frame_index = try func.allocFrameIndex(FrameAlloc.initType(array_ty, pt));
35783812 try func.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv);
3579 try func.genSetReg(Type.usize, addr_reg, .{ .lea_frame = .{ .index = frame_index } });
3813 try func.genSetReg(Type.u64, addr_reg, .{ .lea_frame = .{ .index = frame_index } });
35803814 },
35813815 .load_frame => |frame_addr| {
3582 try func.genSetReg(Type.usize, addr_reg, .{ .lea_frame = frame_addr });
3816 try func.genSetReg(Type.u64, addr_reg, .{ .lea_frame = frame_addr });
35833817 },
3584 else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()),
3818 else => try func.genSetReg(Type.u64, addr_reg, array_mcv.address()),
35853819 }
35863820
35873821 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
......@@ -3602,11 +3836,10 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
36023836 // we can do a shortcut here where we don't need a vslicedown
36033837 // and can just copy to the frame index.
36043838 if (!(index_mcv == .immediate and index_mcv.immediate == 0)) {
3605 const index_reg = try func.copyToTmpRegister(Type.usize, index_mcv);
3839 const index_reg = try func.copyToTmpRegister(Type.u64, index_mcv);
36063840
36073841 _ = try func.addInst(.{
36083842 .tag = .vslidedownvx,
3609 .ops = .rrr,
36103843 .data = .{ .r_type = .{
36113844 .rd = src_reg,
36123845 .rs1 = index_reg,
......@@ -3624,7 +3857,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
36243857 defer func.register_manager.unlockReg(offset_lock);
36253858 _ = try func.addInst(.{
36263859 .tag = .add,
3627 .ops = .rrr,
36283860 .data = .{ .r_type = .{
36293861 .rd = addr_reg,
36303862 .rs1 = addr_reg,
......@@ -3640,8 +3872,55 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
36403872
36413873fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
36423874 const is_volatile = false; // TODO
3875 const pt = func.pt;
3876 const zcu = pt.zcu;
36433877 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3644 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_elem_val for {}", .{func.target.cpu.arch});
3878 const base_ptr_ty = func.typeOf(bin_op.lhs);
3879
3880 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {
3881 const elem_ty = base_ptr_ty.elemType2(zcu);
3882 if (!elem_ty.hasRuntimeBitsIgnoreComptime(pt)) break :result .none;
3883
3884 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);
3885 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
3886 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3887 else => null,
3888 };
3889 defer if (base_ptr_lock) |lock| func.register_manager.unlockReg(lock);
3890
3891 const index_mcv = try func.resolveInst(bin_op.rhs);
3892 const index_lock: ?RegisterLock = switch (index_mcv) {
3893 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3894 else => null,
3895 };
3896 defer if (index_lock) |lock| func.register_manager.unlockReg(lock);
3897
3898 const elem_ptr_reg = if (base_ptr_mcv.isRegister() and func.liveness.operandDies(inst, 0))
3899 base_ptr_mcv.register
3900 else
3901 try func.copyToTmpRegister(base_ptr_ty, base_ptr_mcv);
3902 const elem_ptr_lock = func.register_manager.lockRegAssumeUnused(elem_ptr_reg);
3903 defer func.register_manager.unlockReg(elem_ptr_lock);
3904
3905 try func.genBinOp(
3906 .ptr_add,
3907 base_ptr_mcv,
3908 base_ptr_ty,
3909 index_mcv,
3910 Type.u64,
3911 elem_ptr_reg,
3912 );
3913
3914 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
3915 const dst_lock = switch (dst_mcv) {
3916 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3917 else => null,
3918 };
3919 defer if (dst_lock) |lock| func.register_manager.unlockReg(lock);
3920
3921 try func.load(dst_mcv, .{ .register = elem_ptr_reg }, base_ptr_ty);
3922 break :result dst_mcv;
3923 };
36453924 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
36463925}
36473926
......@@ -3651,10 +3930,14 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
36513930 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
36523931 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
36533932
3654 const result = result: {
3933 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
36553934 const elem_ptr_ty = func.typeOfIndex(inst);
36563935 const base_ptr_ty = func.typeOf(extra.lhs);
36573936
3937 if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {
3938 @panic("audit");
3939 }
3940
36583941 const base_ptr_mcv = try func.resolveInst(extra.lhs);
36593942 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
36603943 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
......@@ -3662,16 +3945,6 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
36623945 };
36633946 defer if (base_ptr_lock) |lock| func.register_manager.unlockReg(lock);
36643947
3665 if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {
3666 break :result if (func.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv))
3667 base_ptr_mcv
3668 else
3669 try func.copyToNewRegister(inst, base_ptr_mcv);
3670 }
3671
3672 const elem_ty = base_ptr_ty.elemType2(zcu);
3673 const elem_abi_size = elem_ty.abiSize(pt);
3674 const index_ty = func.typeOf(extra.rhs);
36753948 const index_mcv = try func.resolveInst(extra.rhs);
36763949 const index_lock: ?RegisterLock = switch (index_mcv) {
36773950 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
......@@ -3679,10 +3952,6 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
36793952 };
36803953 defer if (index_lock) |lock| func.register_manager.unlockReg(lock);
36813954
3682 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size);
3683 const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
3684 defer func.register_manager.unlockReg(offset_reg_lock);
3685
36863955 const result_reg, const result_lock = try func.allocReg(.int);
36873956 defer func.register_manager.unlockReg(result_lock);
36883957
......@@ -3690,13 +3959,14 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
36903959 .ptr_add,
36913960 base_ptr_mcv,
36923961 base_ptr_ty,
3693 .{ .register = offset_reg },
3694 Type.usize,
3962 index_mcv,
3963 Type.u64,
36953964 result_reg,
36963965 );
36973966
36983967 break :result MCValue{ .register = result_reg };
36993968 };
3969
37003970 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
37013971}
37023972
......@@ -3729,7 +3999,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
37293999 defer func.register_manager.unlockReg(result_lock);
37304000
37314001 switch (frame_mcv) {
3732 .load_frame => |frame_addr| {
4002 .load_frame => {
37334003 if (tag_abi_size <= 8) {
37344004 const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
37354005 @intCast(layout.payload_size)
......@@ -3739,7 +4009,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
37394009 try func.genCopy(
37404010 tag_ty,
37414011 .{ .register = result_reg },
3742 .{ .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off } },
4012 frame_mcv.offset(off),
37434013 );
37444014 } else {
37454015 return func.fail(
......@@ -3756,7 +4026,57 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
37564026
37574027fn airClz(func: *Func, inst: Air.Inst.Index) !void {
37584028 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3759 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airClz for {}", .{func.target.cpu.arch});
4029 const operand = try func.resolveInst(ty_op.operand);
4030 const ty = func.typeOf(ty_op.operand);
4031
4032 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4033 const src_reg, const src_lock = try func.promoteReg(ty, operand);
4034 defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
4035
4036 const dst_reg: Register = if (func.reuseOperand(
4037 inst,
4038 ty_op.operand,
4039 0,
4040 operand,
4041 ) and operand == .register)
4042 operand.register
4043 else
4044 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
4045
4046 const bit_size = ty.bitSize(func.pt);
4047 if (!math.isPowerOfTwo(bit_size)) try func.truncateRegister(ty, src_reg);
4048
4049 if (bit_size > 64) {
4050 return func.fail("TODO: airClz > 64 bits, found {d}", .{bit_size});
4051 }
4052
4053 _ = try func.addInst(.{
4054 .tag = switch (bit_size) {
4055 32 => .clzw,
4056 else => .clz,
4057 },
4058 .data = .{
4059 .r_type = .{
4060 .rs2 = .zero, // rs2 is 0 filled in the spec
4061 .rs1 = src_reg,
4062 .rd = dst_reg,
4063 },
4064 },
4065 });
4066
4067 if (!(bit_size == 32 or bit_size == 64)) {
4068 _ = try func.addInst(.{
4069 .tag = .addi,
4070 .data = .{ .i_type = .{
4071 .rd = dst_reg,
4072 .rs1 = dst_reg,
4073 .imm12 = Immediate.s(-@as(i12, @intCast(64 - bit_size % 64))),
4074 } },
4075 });
4076 }
4077
4078 break :result .{ .register = dst_reg };
4079 };
37604080 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
37614081}
37624082
......@@ -3767,14 +4087,44 @@ fn airCtz(func: *Func, inst: Air.Inst.Index) !void {
37674087}
37684088
37694089fn airPopcount(func: *Func, inst: Air.Inst.Index) !void {
3770 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3771 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airPopcount for {}", .{func.target.cpu.arch});
3772 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3773}
3774
3775fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
3776 const pt = func.pt;
3777 const zcu = pt.zcu;
4090 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4091 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4092 const pt = func.pt;
4093
4094 const operand = try func.resolveInst(ty_op.operand);
4095 const src_ty = func.typeOf(ty_op.operand);
4096 const operand_reg, const operand_lock = try func.promoteReg(src_ty, operand);
4097 defer if (operand_lock) |lock| func.register_manager.unlockReg(lock);
4098
4099 const dst_reg, const dst_lock = try func.allocReg(.int);
4100 defer func.register_manager.unlockReg(dst_lock);
4101
4102 const bit_size = src_ty.bitSize(pt);
4103 switch (bit_size) {
4104 32, 64 => {},
4105 1...31, 33...63 => try func.truncateRegister(src_ty, operand_reg),
4106 else => return func.fail("TODO: airPopcount > 64 bits", .{}),
4107 }
4108
4109 _ = try func.addInst(.{
4110 .tag = if (bit_size <= 32) .cpopw else .cpop,
4111 .data = .{
4112 .r_type = .{
4113 .rd = dst_reg,
4114 .rs1 = operand_reg,
4115 .rs2 = @enumFromInt(0b00010), // this is the cpop funct5
4116 },
4117 },
4118 });
4119
4120 break :result .{ .register = dst_reg };
4121 };
4122 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4123}
4124
4125fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
4126 const pt = func.pt;
4127 const zcu = pt.zcu;
37784128 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
37794129 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
37804130 const ty = func.typeOf(ty_op.operand);
......@@ -3785,6 +4135,13 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
37854135 .Int => if (ty.zigTypeTag(zcu) == .Vector) {
37864136 return func.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});
37874137 } else {
4138 const int_info = scalar_ty.intInfo(zcu);
4139 const int_bits = int_info.bits;
4140 switch (int_bits) {
4141 32, 64 => {},
4142 else => return func.fail("TODO: airAbs Int size {d}", .{int_bits}),
4143 }
4144
37884145 const return_mcv = try func.copyToNewRegister(inst, operand);
37894146 const operand_reg = return_mcv.register;
37904147
......@@ -3792,18 +4149,20 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
37924149 defer func.register_manager.unlockReg(temp_lock);
37934150
37944151 _ = try func.addInst(.{
3795 .tag = .srai,
3796 .ops = .rri,
4152 .tag = switch (int_bits) {
4153 32 => .sraiw,
4154 64 => .srai,
4155 else => unreachable,
4156 },
37974157 .data = .{ .i_type = .{
37984158 .rd = temp_reg,
37994159 .rs1 = operand_reg,
3800 .imm12 = Immediate.u(63),
4160 .imm12 = Immediate.u(int_bits - 1),
38014161 } },
38024162 });
38034163
38044164 _ = try func.addInst(.{
38054165 .tag = .xor,
3806 .ops = .rrr,
38074166 .data = .{ .r_type = .{
38084167 .rd = operand_reg,
38094168 .rs1 = operand_reg,
......@@ -3812,8 +4171,11 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
38124171 });
38134172
38144173 _ = try func.addInst(.{
3815 .tag = .sub,
3816 .ops = .rrr,
4174 .tag = switch (int_bits) {
4175 32 => .subw,
4176 64 => .sub,
4177 else => unreachable,
4178 },
38174179 .data = .{ .r_type = .{
38184180 .rd = operand_reg,
38194181 .rs1 = operand_reg,
......@@ -3825,14 +4187,14 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
38254187 },
38264188 .Float => {
38274189 const float_bits = scalar_ty.floatBits(zcu.getTarget());
3828 switch (float_bits) {
4190 const mnem: Mnemonic = switch (float_bits) {
38294191 16 => return func.fail("TODO: airAbs 16-bit float", .{}),
3830 32 => {},
3831 64 => {},
4192 32 => .fsgnjxs,
4193 64 => .fsgnjxd,
38324194 80 => return func.fail("TODO: airAbs 80-bit float", .{}),
38334195 128 => return func.fail("TODO: airAbs 128-bit float", .{}),
38344196 else => unreachable,
3835 }
4197 };
38364198
38374199 const return_mcv = try func.copyToNewRegister(inst, operand);
38384200 const operand_reg = return_mcv.register;
......@@ -3840,13 +4202,12 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
38404202 assert(operand_reg.class() == .float);
38414203
38424204 _ = try func.addInst(.{
3843 .tag = .pseudo,
3844 .ops = .pseudo_fabs,
4205 .tag = mnem,
38454206 .data = .{
3846 .fabs = .{
4207 .r_type = .{
38474208 .rd = operand_reg,
3848 .rs = operand_reg,
3849 .bits = float_bits,
4209 .rs1 = operand_reg,
4210 .rs2 = operand_reg,
38504211 },
38514212 },
38524213 });
......@@ -3869,54 +4230,56 @@ fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void {
38694230 const ty = func.typeOf(ty_op.operand);
38704231 const operand = try func.resolveInst(ty_op.operand);
38714232
3872 const int_bits = ty.intInfo(zcu).bits;
4233 switch (ty.zigTypeTag(zcu)) {
4234 .Int => {
4235 const int_bits = ty.intInfo(zcu).bits;
38734236
3874 // bytes are no-op
3875 if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) {
3876 return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
3877 }
4237 // bytes are no-op
4238 if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) {
4239 return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
4240 }
38784241
3879 const dest_mcv = try func.copyToNewRegister(inst, operand);
3880 const dest_reg = dest_mcv.register;
4242 const dest_mcv = try func.copyToNewRegister(inst, operand);
4243 const dest_reg = dest_mcv.register;
38814244
3882 switch (int_bits) {
3883 16 => {
3884 const temp_reg, const temp_lock = try func.allocReg(.int);
3885 defer func.register_manager.unlockReg(temp_lock);
4245 switch (int_bits) {
4246 16 => {
4247 const temp_reg, const temp_lock = try func.allocReg(.int);
4248 defer func.register_manager.unlockReg(temp_lock);
38864249
3887 _ = try func.addInst(.{
3888 .tag = .srli,
3889 .ops = .rri,
3890 .data = .{ .i_type = .{
3891 .imm12 = Immediate.s(8),
3892 .rd = temp_reg,
3893 .rs1 = dest_reg,
3894 } },
3895 });
4250 _ = try func.addInst(.{
4251 .tag = .srli,
4252 .data = .{ .i_type = .{
4253 .imm12 = Immediate.s(8),
4254 .rd = temp_reg,
4255 .rs1 = dest_reg,
4256 } },
4257 });
38964258
3897 _ = try func.addInst(.{
3898 .tag = .slli,
3899 .ops = .rri,
3900 .data = .{ .i_type = .{
3901 .imm12 = Immediate.s(8),
3902 .rd = dest_reg,
3903 .rs1 = dest_reg,
3904 } },
3905 });
3906 _ = try func.addInst(.{
3907 .tag = .@"or",
3908 .ops = .rri,
3909 .data = .{ .r_type = .{
3910 .rd = dest_reg,
3911 .rs1 = dest_reg,
3912 .rs2 = temp_reg,
3913 } },
3914 });
4259 _ = try func.addInst(.{
4260 .tag = .slli,
4261 .data = .{ .i_type = .{
4262 .imm12 = Immediate.s(8),
4263 .rd = dest_reg,
4264 .rs1 = dest_reg,
4265 } },
4266 });
4267 _ = try func.addInst(.{
4268 .tag = .@"or",
4269 .data = .{ .r_type = .{
4270 .rd = dest_reg,
4271 .rs1 = dest_reg,
4272 .rs2 = temp_reg,
4273 } },
4274 });
4275 },
4276 else => return func.fail("TODO: {d} bits for airByteSwap", .{int_bits}),
4277 }
4278
4279 break :result dest_mcv;
39154280 },
3916 else => return func.fail("TODO: {d} bits for airByteSwap", .{int_bits}),
4281 else => return func.fail("TODO: airByteSwap {}", .{ty.fmt(pt)}),
39174282 }
3918
3919 break :result dest_mcv;
39204283 };
39214284 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
39224285}
......@@ -3960,7 +4323,6 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
39604323 .sqrt => {
39614324 _ = try func.addInst(.{
39624325 .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts,
3963 .ops = .rrr,
39644326 .data = .{
39654327 .r_type = .{
39664328 .rd = dst_reg,
......@@ -3970,6 +4332,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
39704332 },
39714333 });
39724334 },
4335
39734336 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
39744337 }
39754338 },
......@@ -4054,9 +4417,15 @@ fn airLoad(func: *Func, inst: Air.Inst.Index) !void {
40544417 const elem_size = elem_ty.abiSize(pt);
40554418
40564419 const dst_mcv: MCValue = blk: {
4057 // Pointer is 8 bytes, and if the element is more than that, we cannot reuse it.
4058 if (elem_size <= 8 and func.reuseOperand(inst, ty_op.operand, 0, ptr)) {
4059 // The MCValue that holds the pointer can be re-used as the value.
4420 // The MCValue that holds the pointer can be re-used as the value.
4421 // - "ptr" is 8 bytes, and if the element is more than that, we cannot reuse it.
4422 //
4423 // - "ptr" will be stored in an integer register, so the type that we're gonna
4424 // load into it must also be a type that can be inside of an integer register
4425 if (elem_size <= 8 and
4426 (if (ptr == .register) func.typeRegClass(elem_ty) == ptr.register.class() else true) and
4427 func.reuseOperand(inst, ty_op.operand, 0, ptr))
4428 {
40604429 break :blk ptr;
40614430 } else {
40624431 break :blk try func.allocRegOrMem(elem_ty, inst, true);
......@@ -4090,12 +4459,14 @@ fn load(func: *Func, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro
40904459 .register_offset,
40914460 .lea_frame,
40924461 .lea_symbol,
4462 .lea_tlv,
40934463 => try func.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
40944464
40954465 .memory,
40964466 .indirect,
40974467 .load_symbol,
40984468 .load_frame,
4469 .load_tlv,
40994470 => {
41004471 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
41014472 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -4117,15 +4488,16 @@ fn airStore(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
41174488 const ptr = try func.resolveInst(bin_op.lhs);
41184489 const value = try func.resolveInst(bin_op.rhs);
41194490 const ptr_ty = func.typeOf(bin_op.lhs);
4120 const value_ty = func.typeOf(bin_op.rhs);
41214491
4122 try func.store(ptr, value, ptr_ty, value_ty);
4492 try func.store(ptr, value, ptr_ty);
41234493
41244494 return func.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
41254495}
41264496
41274497/// Loads `value` into the "payload" of `pointer`.
4128fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty: Type) !void {
4498fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type) !void {
4499 const zcu = func.pt.zcu;
4500 const src_ty = ptr_ty.childType(zcu);
41294501 log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) });
41304502
41314503 switch (ptr_mcv) {
......@@ -4141,12 +4513,14 @@ fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty:
41414513 .register_offset,
41424514 .lea_symbol,
41434515 .lea_frame,
4516 .lea_tlv,
41444517 => try func.genCopy(src_ty, ptr_mcv.deref(), src_mcv),
41454518
41464519 .memory,
41474520 .indirect,
41484521 .load_symbol,
41494522 .load_frame,
4523 .load_tlv,
41504524 => {
41514525 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
41524526 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -4154,7 +4528,7 @@ fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty:
41544528
41554529 try func.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
41564530 },
4157 .air_ref => |ptr_ref| try func.store(try func.resolveInst(ptr_ref), src_mcv, ptr_ty, src_ty),
4531 .air_ref => |ptr_ref| try func.store(try func.resolveInst(ptr_ref), src_mcv, ptr_ty),
41584532 }
41594533}
41604534
......@@ -4176,17 +4550,14 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
41764550 const zcu = pt.zcu;
41774551 const ptr_field_ty = func.typeOfIndex(inst);
41784552 const ptr_container_ty = func.typeOf(operand);
4179 const ptr_container_ty_info = ptr_container_ty.ptrInfo(zcu);
41804553 const container_ty = ptr_container_ty.childType(zcu);
41814554
4182 const field_offset: i32 = if (zcu.typeToPackedStruct(container_ty)) |struct_obj|
4183 if (ptr_field_ty.ptrInfo(zcu).packed_offset.host_size == 0)
4184 @divExact(pt.structPackedFieldBitOffset(struct_obj, index) +
4185 ptr_container_ty_info.packed_offset.bit_offset, 8)
4186 else
4187 0
4188 else
4189 @intCast(container_ty.structFieldOffset(index, pt));
4555 const field_offset: i32 = switch (container_ty.containerLayout(zcu)) {
4556 .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, pt)),
4557 .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) +
4558 (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) -
4559 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
4560 };
41904561
41914562 const src_mcv = try func.resolveInst(operand);
41924563 const dst_mcv = if (switch (src_mcv) {
......@@ -4229,7 +4600,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
42294600 const dst_reg = if (field_off == 0)
42304601 (try func.copyToNewRegister(inst, src_mcv)).register
42314602 else
4232 try func.copyToTmpRegister(Type.usize, .{ .register = src_reg });
4603 try func.copyToTmpRegister(Type.u64, .{ .register = src_reg });
42334604
42344605 const dst_mcv: MCValue = .{ .register = dst_reg };
42354606 const dst_lock = func.register_manager.lockReg(dst_reg);
......@@ -4238,7 +4609,6 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
42384609 if (field_off > 0) {
42394610 _ = try func.addInst(.{
42404611 .tag = .srli,
4241 .ops = .rri,
42424612 .data = .{ .i_type = .{
42434613 .imm12 = Immediate.u(@intCast(field_off)),
42444614 .rd = dst_reg,
......@@ -4289,8 +4659,8 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
42894659
42904660 const hi_mcv =
42914661 dst_mcv.address().offset(@intCast(field_bit_size / 64 * 8)).deref();
4292 try func.genSetReg(Type.usize, tmp_reg, hi_mcv);
4293 try func.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg });
4662 try func.genSetReg(Type.u64, tmp_reg, hi_mcv);
4663 try func.genCopy(Type.u64, hi_mcv, .{ .register = tmp_reg });
42944664 }
42954665 break :result dst_mcv;
42964666 }
......@@ -4314,7 +4684,7 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
43144684 const zcu = pt.zcu;
43154685 const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg;
43164686 const ty = arg.ty.toType();
4317 const owner_decl = zcu.funcOwnerDeclIndex(func.func_index);
4687 const owner_decl = func.owner.getDecl(zcu);
43184688 if (arg.name == .none) return;
43194689 const name = func.air.nullTerminatedString(@intFromEnum(arg.name));
43204690
......@@ -4358,8 +4728,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void {
43584728fn airTrap(func: *Func) !void {
43594729 _ = try func.addInst(.{
43604730 .tag = .unimp,
4361 .ops = .none,
4362 .data = undefined,
4731 .data = .none,
43634732 });
43644733 return func.finishAirBookkeeping();
43654734}
......@@ -4367,21 +4736,20 @@ fn airTrap(func: *Func) !void {
43674736fn airBreakpoint(func: *Func) !void {
43684737 _ = try func.addInst(.{
43694738 .tag = .ebreak,
4370 .ops = .none,
4371 .data = undefined,
4739 .data = .none,
43724740 });
43734741 return func.finishAirBookkeeping();
43744742}
43754743
43764744fn airRetAddr(func: *Func, inst: Air.Inst.Index) !void {
43774745 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
4378 try func.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } });
4746 try func.genCopy(Type.u64, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } });
43794747 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
43804748}
43814749
43824750fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
43834751 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
4384 try func.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } });
4752 try func.genCopy(Type.u64, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } });
43854753 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
43864754}
43874755
......@@ -4396,15 +4764,11 @@ fn airFence(func: *Func, inst: Air.Inst.Index) !void {
43964764 };
43974765
43984766 _ = 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 },
4767 .tag = if (order == .acq_rel) .fencetso else .fence,
4768 .data = .{ .fence = .{
4769 .pred = pred,
4770 .succ = succ,
4771 } },
44084772 });
44094773 return func.finishAirBookkeeping();
44104774}
......@@ -4540,7 +4904,7 @@ fn genCall(
45404904 .indirect => |reg_off| {
45414905 const ret_ty = Type.fromInterned(fn_info.return_type);
45424906 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(ret_ty, pt));
4543 try func.genSetReg(Type.usize, reg_off.reg, .{
4907 try func.genSetReg(Type.u64, reg_off.reg, .{
45444908 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
45454909 });
45464910 call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } };
......@@ -4558,7 +4922,7 @@ fn genCall(
45584922 dst_reg,
45594923 src_arg,
45604924 ),
4561 .indirect => |reg_off| try func.genSetReg(Type.usize, reg_off.reg, .{
4925 .indirect => |reg_off| try func.genSetReg(Type.u64, reg_off.reg, .{
45624926 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
45634927 }),
45644928 else => return func.fail("TODO: genCall actual set {s}", .{@tagName(dst_arg)}),
......@@ -4586,10 +4950,9 @@ fn genCall(
45864950 if (func.mod.pic) {
45874951 return func.fail("TODO: genCall pic", .{});
45884952 } else {
4589 try func.genSetReg(Type.usize, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
4953 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
45904954 _ = try func.addInst(.{
45914955 .tag = .jalr,
4592 .ops = .rri,
45934956 .data = .{ .i_type = .{
45944957 .rd = .ra,
45954958 .rs1 = .ra,
......@@ -4603,18 +4966,17 @@ fn genCall(
46034966 const owner_decl = zcu.declPtr(extern_func.decl);
46044967 const lib_name = extern_func.lib_name.toSlice(&zcu.intern_pool);
46054968 const decl_name = owner_decl.name.toSlice(&zcu.intern_pool);
4606 const atom_index = try func.symbolIndex();
4969 const atom_index = try func.owner.getSymbolIndex(func);
46074970
4608 if (func.bin_file.cast(link.File.Elf)) |elf_file| {
4609 _ = try func.addInst(.{
4610 .tag = .pseudo,
4611 .ops = .pseudo_extern_fn_reloc,
4612 .data = .{ .reloc = .{
4613 .atom_index = atom_index,
4614 .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),
4615 } },
4616 });
4617 } else unreachable; // not a valid riscv64 format
4971 const elf_file = func.bin_file.cast(link.File.Elf).?;
4972 _ = try func.addInst(.{
4973 .tag = .pseudo_extern_fn_reloc,
4974 .data = .{ .reloc = .{
4975 .register = .ra,
4976 .atom_index = atom_index,
4977 .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),
4978 } },
4979 });
46184980 },
46194981 else => return func.fail("TODO implement calling bitcasted functions", .{}),
46204982 }
......@@ -4622,11 +4984,10 @@ fn genCall(
46224984 assert(func.typeOf(callee).zigTypeTag(zcu) == .Pointer);
46234985 const addr_reg, const addr_lock = try func.allocReg(.int);
46244986 defer func.register_manager.unlockReg(addr_lock);
4625 try func.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });
4987 try func.genSetReg(Type.u64, addr_reg, .{ .air_ref = callee });
46264988
46274989 _ = try func.addInst(.{
46284990 .tag = .jalr,
4629 .ops = .rri,
46304991 .data = .{ .i_type = .{
46314992 .rd = .ra,
46324993 .rs1 = addr_reg,
......@@ -4638,6 +4999,10 @@ fn genCall(
46384999 .lib => return func.fail("TODO: lib func calls", .{}),
46395000 }
46405001
5002 // reset the vector settings as they might have changed in the function
5003 func.avl = null;
5004 func.vtype = null;
5005
46415006 return call_info.return_value.short;
46425007}
46435008
......@@ -4683,7 +5048,7 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
46835048 const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg);
46845049 defer func.register_manager.unlockReg(lock);
46855050
4686 try func.genSetReg(Type.usize, reg_off.reg, func.ret_mcv.long);
5051 try func.genSetReg(Type.u64, reg_off.reg, func.ret_mcv.long);
46875052 try func.genSetMem(
46885053 .{ .reg = reg_off.reg },
46895054 reg_off.off,
......@@ -4699,9 +5064,11 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
46995064
47005065 // Just add space for an instruction, reloced this later
47015066 const index = try func.addInst(.{
4702 .tag = .pseudo,
4703 .ops = .pseudo_j,
4704 .data = .{ .inst = undefined },
5067 .tag = .pseudo_j,
5068 .data = .{ .j_type = .{
5069 .rd = .zero,
5070 .inst = undefined,
5071 } },
47055072 });
47065073
47075074 try func.exitlude_jump_relocs.append(func.gpa, index);
......@@ -4723,9 +5090,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void {
47235090
47245091 // Just add space for an instruction, reloced this later
47255092 const index = try func.addInst(.{
4726 .tag = .pseudo,
4727 .ops = .pseudo_j,
4728 .data = .{ .inst = undefined },
5093 .tag = .pseudo_j,
5094 .data = .{ .j_type = .{
5095 .rd = .zero,
5096 .inst = undefined,
5097 } },
47295098 });
47305099
47315100 try func.exitlude_jump_relocs.append(func.gpa, index);
......@@ -4751,14 +5120,14 @@ fn airCmp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
47515120 .Enum => lhs_ty.intTagType(zcu),
47525121 .Int => lhs_ty,
47535122 .Bool => Type.u1,
4754 .Pointer => Type.usize,
5123 .Pointer => Type.u64,
47555124 .ErrorSet => Type.anyerror,
47565125 .Optional => blk: {
47575126 const payload_ty = lhs_ty.optionalChild(zcu);
47585127 if (!payload_ty.hasRuntimeBitsIgnoreComptime(pt)) {
47595128 break :blk Type.u1;
47605129 } else if (lhs_ty.isPtrLikeOptional(zcu)) {
4761 break :blk Type.usize;
5130 break :blk Type.u64;
47625131 } else {
47635132 return func.fail("TODO riscv cmp non-pointer optionals", .{});
47645133 }
......@@ -4805,8 +5174,7 @@ fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void {
48055174 const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
48065175
48075176 _ = try func.addInst(.{
4808 .tag = .pseudo,
4809 .ops = .pseudo_dbg_line_column,
5177 .tag = .pseudo_dbg_line_column,
48105178 .data = .{ .pseudo_dbg_line_column = .{
48115179 .line = dbg_stmt.line,
48125180 .column = dbg_stmt.column,
......@@ -4868,7 +5236,7 @@ fn genVarDbgInfo(
48685236 break :blk .nop;
48695237 },
48705238 };
4871 try dw.genVarDbgInfo(name, ty, zcu.funcOwnerDeclIndex(func.func_index), is_ptr, loc);
5239 try dw.genVarDbgInfo(name, ty, func.owner.getDecl(zcu), is_ptr, loc);
48725240 },
48735241 .plan9 => {},
48745242 .none => {},
......@@ -4924,7 +5292,6 @@ fn condBr(func: *Func, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {
49245292
49255293 return try func.addInst(.{
49265294 .tag = .beq,
4927 .ops = .rr_inst,
49285295 .data = .{
49295296 .b_type = .{
49305297 .rs1 = cond_reg,
......@@ -4955,19 +5322,18 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
49555322 .dead,
49565323 .undef,
49575324 .immediate,
4958 .register_pair,
49595325 .register_offset,
49605326 .lea_frame,
49615327 .lea_symbol,
49625328 .reserved_frame,
49635329 .air_ref,
4964 => return func.fail("TODO: hmm {}", .{opt_mcv}),
5330 .register_pair,
5331 => unreachable,
49655332
49665333 .register => |opt_reg| {
49675334 if (some_info.off == 0) {
49685335 _ = try func.addInst(.{
4969 .tag = .pseudo,
4970 .ops = .pseudo_compare,
5336 .tag = .pseudo_compare,
49715337 .data = .{
49725338 .compare = .{
49735339 .op = .eq,
......@@ -4984,9 +5350,27 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
49845350 return return_mcv;
49855351 }
49865352 assert(some_info.ty.ip_index == .bool_type);
4987 const opt_abi_size: u32 = @intCast(opt_ty.abiSize(pt));
4988 _ = opt_abi_size;
4989 return func.fail("TODO: isNull some_info.off != 0 register", .{});
5353 const bit_offset: u7 = @intCast(some_info.off * 8);
5354
5355 try func.genBinOp(
5356 .shr,
5357 .{ .register = opt_reg },
5358 Type.u64,
5359 .{ .immediate = bit_offset },
5360 Type.u8,
5361 return_reg,
5362 );
5363 try func.truncateRegister(Type.u8, return_reg);
5364 try func.genBinOp(
5365 .cmp_eq,
5366 .{ .register = return_reg },
5367 Type.u64,
5368 .{ .immediate = 0 },
5369 Type.u8,
5370 return_reg,
5371 );
5372
5373 return return_mcv;
49905374 },
49915375
49925376 .load_frame => {
......@@ -4998,8 +5382,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
49985382 defer func.register_manager.unlockReg(opt_reg_lock);
49995383
50005384 _ = try func.addInst(.{
5001 .tag = .pseudo,
5002 .ops = .pseudo_compare,
5385 .tag = .pseudo_compare,
50035386 .data = .{
50045387 .compare = .{
50055388 .op = .eq,
......@@ -5048,8 +5431,7 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void {
50485431 assert(result == .register);
50495432
50505433 _ = try func.addInst(.{
5051 .tag = .pseudo,
5052 .ops = .pseudo_not,
5434 .tag = .pseudo_not,
50535435 .data = .{
50545436 .rr = .{
50555437 .rd = result.register,
......@@ -5181,8 +5563,7 @@ fn isNonErr(func: *Func, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
51815563 switch (is_err_res) {
51825564 .register => |reg| {
51835565 _ = try func.addInst(.{
5184 .tag = .pseudo,
5185 .ops = .pseudo_not,
5566 .tag = .pseudo_not,
51865567 .data = .{
51875568 .rr = .{
51885569 .rd = reg,
......@@ -5249,11 +5630,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
52495630/// Send control flow to the `index` of `func.code`.
52505631fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index {
52515632 return func.addInst(.{
5252 .tag = .pseudo,
5253 .ops = .pseudo_j,
5254 .data = .{
5633 .tag = .pseudo_j,
5634 .data = .{ .j_type = .{
5635 .rd = .zero,
52555636 .inst = index,
5256 },
5637 } },
52575638 });
52585639}
52595640
......@@ -5296,7 +5677,6 @@ fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) !
52965677
52975678fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
52985679 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5299 const condition = try func.resolveInst(pl_op.operand);
53005680 const condition_ty = func.typeOf(pl_op.operand);
53015681 const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload);
53025682 var extra_index: usize = switch_br.end;
......@@ -5304,6 +5684,8 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
53045684 const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1);
53055685 defer func.gpa.free(liveness.deaths);
53065686
5687 const condition = try func.resolveInst(pl_op.operand);
5688
53075689 // If the condition dies here in this switch instruction, process
53085690 // that death now instead of later as this has an effect on
53095691 // whether it needs to be spilled in the branches
......@@ -5326,9 +5708,14 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
53265708 defer func.gpa.free(relocs);
53275709
53285710 for (items, relocs, 0..) |item, *reloc, i| {
5329 // switch branches must be comptime-known, so this is stored in an immediate
53305711 const item_mcv = try func.resolveInst(item);
53315712
5713 const cond_lock = switch (condition) {
5714 .register => func.register_manager.lockRegAssumeUnused(condition.register),
5715 else => null,
5716 };
5717 defer if (cond_lock) |lock| func.register_manager.unlockReg(lock);
5718
53325719 const cmp_reg, const cmp_lock = try func.allocReg(.int);
53335720 defer func.register_manager.unlockReg(cmp_lock);
53345721
......@@ -5343,8 +5730,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
53435730
53445731 if (!(i < relocs.len - 1)) {
53455732 _ = try func.addInst(.{
5346 .tag = .pseudo,
5347 .ops = .pseudo_not,
5733 .tag = .pseudo_not,
53485734 .data = .{ .rr = .{
53495735 .rd = cmp_reg,
53505736 .rs = cmp_reg,
......@@ -5391,18 +5777,14 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
53915777
53925778fn performReloc(func: *Func, inst: Mir.Inst.Index) void {
53935779 const tag = func.mir_instructions.items(.tag)[inst];
5394 const ops = func.mir_instructions.items(.ops)[inst];
53955780 const target: Mir.Inst.Index = @intCast(func.mir_instructions.len);
53965781
53975782 switch (tag) {
5398 .bne,
53995783 .beq,
5784 .bne,
54005785 => func.mir_instructions.items(.data)[inst].b_type.inst = target,
54015786 .jal => func.mir_instructions.items(.data)[inst].j_type.inst = target,
5402 .pseudo => switch (ops) {
5403 .pseudo_j => func.mir_instructions.items(.data)[inst].inst = target,
5404 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(ops)}),
5405 },
5787 .pseudo_j => func.mir_instructions.items(.data)[inst].j_type.inst = target,
54065788 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(tag)}),
54075789 }
54085790}
......@@ -5489,7 +5871,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
54895871
54905872 _ = try func.addInst(.{
54915873 .tag = if (tag == .bool_or) .@"or" else .@"and",
5492 .ops = .rrr,
54935874 .data = .{ .r_type = .{
54945875 .rd = result_reg,
54955876 .rs1 = lhs_reg,
......@@ -5501,7 +5882,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
55015882 if (func.wantSafety()) {
55025883 _ = try func.addInst(.{
55035884 .tag = .andi,
5504 .ops = .rri,
55055885 .data = .{ .i_type = .{
55065886 .rd = result_reg,
55075887 .rs1 = result_reg,
......@@ -5518,7 +5898,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
55185898fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
55195899 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
55205900 const extra = func.air.extraData(Air.Asm, ty_pl.payload);
5521 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
55225901 const clobbers_len: u31 = @truncate(extra.data.flags);
55235902 var extra_i: usize = extra.end;
55245903 const outputs: []const Air.Inst.Ref =
......@@ -5527,87 +5906,444 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
55275906 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);
55285907 extra_i += inputs.len;
55295908
5530 const dead = !is_volatile and func.liveness.isUnused(inst);
5531 const result: MCValue = if (dead) .unreach else result: {
5532 if (outputs.len > 1) {
5533 return func.fail("TODO implement codegen for asm with more than 1 output", .{});
5534 }
5909 var result: MCValue = .none;
5910 var args = std.ArrayList(MCValue).init(func.gpa);
5911 try args.ensureTotalCapacity(outputs.len + inputs.len);
5912 defer {
5913 for (args.items) |arg| if (arg.getReg()) |reg| func.register_manager.unlockReg(.{
5914 .tracked_index = RegisterManager.indexOfRegIntoTracked(reg) orelse continue,
5915 });
5916 args.deinit();
5917 }
5918 var arg_map = std.StringHashMap(u8).init(func.gpa);
5919 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
5920 defer arg_map.deinit();
5921
5922 var outputs_extra_i = extra_i;
5923 for (outputs) |output| {
5924 const extra_bytes = mem.sliceAsBytes(func.air.extra[extra_i..]);
5925 const constraint = mem.sliceTo(mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
5926 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5927 // This equation accounts for the fact that even if we have exactly 4 bytes
5928 // for the string, we still use the next u32 for the null terminator.
5929 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5930
5931 const is_read = switch (constraint[0]) {
5932 '=' => false,
5933 '+' => read: {
5934 if (output == .none) return func.fail(
5935 "read-write constraint unsupported for asm result: '{s}'",
5936 .{constraint},
5937 );
5938 break :read true;
5939 },
5940 else => return func.fail("invalid constraint: '{s}'", .{constraint}),
5941 };
5942 const is_early_clobber = constraint[1] == '&';
5943 const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];
5944 const arg_mcv: MCValue = arg_mcv: {
5945 const arg_maybe_reg: ?Register = if (mem.eql(u8, rest, "m"))
5946 if (output != .none) null else return func.fail(
5947 "memory constraint unsupported for asm result: '{s}'",
5948 .{constraint},
5949 )
5950 else if (mem.startsWith(u8, rest, "{") and mem.endsWith(u8, rest, "}"))
5951 parseRegName(rest["{".len .. rest.len - "}".len]) orelse
5952 return func.fail("invalid register constraint: '{s}'", .{constraint})
5953 else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {
5954 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;
5955 if (index >= args.items.len) return func.fail("constraint out of bounds: '{s}'", .{
5956 constraint,
5957 });
5958 break :arg_mcv args.items[index];
5959 } else return func.fail("invalid constraint: '{s}'", .{constraint});
5960 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
5961 const ptr_mcv = try func.resolveInst(output);
5962 switch (ptr_mcv) {
5963 .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
5964 break :arg ptr_mcv.deref(),
5965 .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(),
5966 else => {},
5967 }
5968 break :arg .{ .indirect = .{ .reg = try func.copyToTmpRegister(Type.usize, ptr_mcv) } };
5969 };
5970 };
5971 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
5972 _ = func.register_manager.lockReg(reg);
5973 };
5974 if (!mem.eql(u8, name, "_"))
5975 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
5976 args.appendAssumeCapacity(arg_mcv);
5977 if (output == .none) result = arg_mcv;
5978 if (is_read) try func.load(arg_mcv, .{ .air_ref = output }, func.typeOf(output));
5979 }
55355980
5536 const output_constraint: ?[]const u8 = for (outputs) |output| {
5537 if (output != .none) {
5538 return func.fail("TODO implement codegen for non-expr asm", .{});
5981 for (inputs) |input| {
5982 const input_bytes = mem.sliceAsBytes(func.air.extra[extra_i..]);
5983 const constraint = mem.sliceTo(input_bytes, 0);
5984 const name = mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
5985 // This equation accounts for the fact that even if we have exactly 4 bytes
5986 // for the string, we still use the next u32 for the null terminator.
5987 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5988
5989 const ty = func.typeOf(input);
5990 const input_mcv = try func.resolveInst(input);
5991 const arg_mcv: MCValue = if (mem.eql(u8, constraint, "X"))
5992 input_mcv
5993 else if (mem.startsWith(u8, constraint, "{") and mem.endsWith(u8, constraint, "}")) arg: {
5994 const reg = parseRegName(constraint["{".len .. constraint.len - "}".len]) orelse
5995 return func.fail("invalid register constraint: '{s}'", .{constraint});
5996 try func.register_manager.getReg(reg, null);
5997 try func.genSetReg(ty, reg, input_mcv);
5998 break :arg .{ .register = reg };
5999 } else if (mem.eql(u8, constraint, "r")) arg: {
6000 switch (input_mcv) {
6001 .register => break :arg input_mcv,
6002 else => {},
55396003 }
5540 const extra_bytes = std.mem.sliceAsBytes(func.air.extra[extra_i..]);
5541 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
5542 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5543 // This equation accounts for the fact that even if we have exactly 4 bytes
5544 // for the string, we still use the next u32 for the null terminator.
5545 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5546
5547 break constraint;
5548 } else null;
6004 const temp_reg = try func.copyToTmpRegister(ty, input_mcv);
6005 break :arg .{ .register = temp_reg };
6006 } else return func.fail("invalid input constraint: '{s}'", .{constraint});
6007 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
6008 _ = func.register_manager.lockReg(reg);
6009 };
6010 if (!mem.eql(u8, name, "_"))
6011 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
6012 args.appendAssumeCapacity(arg_mcv);
6013 }
55496014
5550 for (inputs) |input| {
5551 const input_bytes = std.mem.sliceAsBytes(func.air.extra[extra_i..]);
5552 const constraint = std.mem.sliceTo(input_bytes, 0);
5553 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
6015 {
6016 var clobber_i: u32 = 0;
6017 while (clobber_i < clobbers_len) : (clobber_i += 1) {
6018 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
55546019 // This equation accounts for the fact that even if we have exactly 4 bytes
55556020 // for the string, we still use the next u32 for the null terminator.
5556 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
6021 extra_i += clobber.len / 4 + 1;
55576022
5558 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
5559 return func.fail("unrecognized asm input constraint: '{s}'", .{constraint});
6023 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
6024 // nothing really to do
6025 } else {
6026 try func.register_manager.getReg(parseRegName(clobber) orelse
6027 return func.fail("invalid clobber: '{s}'", .{clobber}), null);
55606028 }
5561 const reg_name = constraint[1 .. constraint.len - 1];
5562 const reg = parseRegName(reg_name) orelse
5563 return func.fail("unrecognized register: '{s}'", .{reg_name});
5564
5565 const arg_mcv = try func.resolveInst(input);
5566 try func.register_manager.getReg(reg, null);
5567 try func.genSetReg(func.typeOf(input), reg, arg_mcv);
55686029 }
6030 }
55696031
5570 {
5571 var clobber_i: u32 = 0;
5572 while (clobber_i < clobbers_len) : (clobber_i += 1) {
5573 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
5574 // This equation accounts for the fact that even if we have exactly 4 bytes
5575 // for the string, we still use the next u32 for the null terminator.
5576 extra_i += clobber.len / 4 + 1;
6032 const Label = struct {
6033 target: Mir.Inst.Index = undefined,
6034 pending_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
6035
6036 const Kind = enum { definition, reference };
6037
6038 fn isValid(kind: Kind, name: []const u8) bool {
6039 for (name, 0..) |c, i| switch (c) {
6040 else => return false,
6041 '$' => if (i == 0) return false,
6042 '.' => {},
6043 '0'...'9' => if (i == 0) switch (kind) {
6044 .definition => if (name.len != 1) return false,
6045 .reference => {
6046 if (name.len != 2) return false;
6047 switch (name[1]) {
6048 else => return false,
6049 'B', 'F', 'b', 'f' => {},
6050 }
6051 },
6052 },
6053 '@', 'A'...'Z', '_', 'a'...'z' => {},
6054 };
6055 return name.len > 0;
6056 }
6057 };
6058 var labels: std.StringHashMapUnmanaged(Label) = .{};
6059 defer {
6060 var label_it = labels.valueIterator();
6061 while (label_it.next()) |label| label.pending_relocs.deinit(func.gpa);
6062 labels.deinit(func.gpa);
6063 }
55776064
5578 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
5579 // nothing really to do
5580 } else {
5581 try func.register_manager.getReg(parseRegName(clobber) orelse
5582 return func.fail("invalid clobber: '{s}'", .{clobber}), null);
5583 }
6065 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];
6066 var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");
6067 next_line: while (line_it.next()) |line| {
6068 var mnem_it = mem.tokenizeAny(u8, line, " \t");
6069 const mnem_str = while (mnem_it.next()) |mnem_str| {
6070 if (mem.startsWith(u8, mnem_str, "#")) continue :next_line;
6071 if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;
6072 if (!mem.endsWith(u8, mnem_str, ":")) break mnem_str;
6073 const label_name = mnem_str[0 .. mnem_str.len - ":".len];
6074 if (!Label.isValid(.definition, label_name))
6075 return func.fail("invalid label: '{s}'", .{label_name});
6076
6077 const label_gop = try labels.getOrPut(func.gpa, label_name);
6078 if (!label_gop.found_existing) label_gop.value_ptr.* = .{} else {
6079 const anon = std.ascii.isDigit(label_name[0]);
6080 if (!anon and label_gop.value_ptr.pending_relocs.items.len == 0)
6081 return func.fail("redefined label: '{s}'", .{label_name});
6082 for (label_gop.value_ptr.pending_relocs.items) |pending_reloc|
6083 func.performReloc(pending_reloc);
6084 if (anon)
6085 label_gop.value_ptr.pending_relocs.clearRetainingCapacity()
6086 else
6087 label_gop.value_ptr.pending_relocs.clearAndFree(func.gpa);
55846088 }
5585 }
6089 label_gop.value_ptr.target = @intCast(func.mir_instructions.len);
6090 } else continue;
6091
6092 const instruction: union(enum) { mnem: Mnemonic, pseudo: Pseudo } =
6093 if (std.meta.stringToEnum(Mnemonic, mnem_str)) |mnem|
6094 .{ .mnem = mnem }
6095 else if (std.meta.stringToEnum(Pseudo, mnem_str)) |pseudo|
6096 .{ .pseudo = pseudo }
6097 else
6098 return func.fail("invalid mnem str '{s}'", .{mnem_str});
6099
6100 const Operand = union(enum) {
6101 none,
6102 reg: Register,
6103 imm: Immediate,
6104 inst: Mir.Inst.Index,
6105 sym: SymbolOffset,
6106 };
55866107
5587 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];
6108 var ops: [4]Operand = .{.none} ** 4;
6109 var last_op = false;
6110 var op_it = mem.splitAny(u8, mnem_it.rest(), ",(");
6111 next_op: for (&ops) |*op| {
6112 const op_str = while (!last_op) {
6113 const full_str = op_it.next() orelse break :next_op;
6114 const code_str = if (mem.indexOfScalar(u8, full_str, '#') orelse
6115 mem.indexOf(u8, full_str, "//")) |comment|
6116 code: {
6117 last_op = true;
6118 break :code full_str[0..comment];
6119 } else full_str;
6120 const trim_str = mem.trim(u8, code_str, " \t*");
6121 if (trim_str.len > 0) break trim_str;
6122 } else break;
6123
6124 if (parseRegName(op_str)) |reg| {
6125 op.* = .{ .reg = reg };
6126 } else if (std.fmt.parseInt(i12, op_str, 10)) |int| {
6127 op.* = .{ .imm = Immediate.s(int) };
6128 } else |_| if (mem.startsWith(u8, op_str, "%[")) {
6129 const mod_index = mem.indexOf(u8, op_str, "]@");
6130 const modifier = if (mod_index) |index|
6131 op_str[index + "]@".len ..]
6132 else
6133 "";
6134
6135 op.* = switch (args.items[
6136 arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse
6137 return func.fail("no matching constraint: '{s}'", .{op_str})
6138 ]) {
6139 .load_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: {
6140 assert(sym_off.off == 0);
6141 break :blk .{ .sym = sym_off };
6142 } else return func.fail("invalid modifier: '{s}'", .{modifier}),
6143 .register => |reg| if (modifier.len == 0)
6144 .{ .reg = reg }
6145 else
6146 return func.fail("invalid modified '{s}'", .{modifier}),
6147 else => return func.fail("invalid constraint: '{s}'", .{op_str}),
6148 };
6149 } else if (mem.endsWith(u8, op_str, ")")) {
6150 const reg = op_str[0 .. op_str.len - ")".len];
6151 const addr_reg = parseRegName(reg) orelse
6152 return func.fail("expected valid register, found '{s}'", .{reg});
6153
6154 op.* = .{ .reg = addr_reg };
6155 } else if (Label.isValid(.reference, op_str)) {
6156 const anon = std.ascii.isDigit(op_str[0]);
6157 const label_gop = try labels.getOrPut(func.gpa, op_str[0..if (anon) 1 else op_str.len]);
6158 if (!label_gop.found_existing) label_gop.value_ptr.* = .{};
6159 if (anon and (op_str[1] == 'b' or op_str[1] == 'B') and !label_gop.found_existing)
6160 return func.fail("undefined label: '{s}'", .{op_str});
6161 const pending_relocs = &label_gop.value_ptr.pending_relocs;
6162 if (if (anon)
6163 op_str[1] == 'f' or op_str[1] == 'F'
6164 else
6165 !label_gop.found_existing or pending_relocs.items.len > 0)
6166 try pending_relocs.append(func.gpa, @intCast(func.mir_instructions.len));
6167 op.* = .{ .inst = label_gop.value_ptr.target };
6168 } else return func.fail("invalid operand: '{s}'", .{op_str});
6169 } else if (op_it.next()) |op_str| return func.fail("extra operand: '{s}'", .{op_str});
6170
6171 switch (instruction) {
6172 .mnem => |mnem| {
6173 _ = (switch (ops[0]) {
6174 .none => try func.addInst(.{
6175 .tag = mnem,
6176 .data = .none,
6177 }),
6178 .reg => |reg1| switch (ops[1]) {
6179 .reg => |reg2| switch (ops[2]) {
6180 .imm => |imm1| try func.addInst(.{
6181 .tag = mnem,
6182 .data = .{ .i_type = .{
6183 .rd = reg1,
6184 .rs1 = reg2,
6185 .imm12 = imm1,
6186 } },
6187 }),
6188 else => error.InvalidInstruction,
6189 },
6190 .imm => |imm1| switch (ops[2]) {
6191 .reg => |reg2| switch (mnem) {
6192 .sd => try func.addInst(.{
6193 .tag = mnem,
6194 .data = .{ .i_type = .{
6195 .rd = reg2,
6196 .rs1 = reg1,
6197 .imm12 = imm1,
6198 } },
6199 }),
6200 .ld => try func.addInst(.{
6201 .tag = mnem,
6202 .data = .{ .i_type = .{
6203 .rd = reg1,
6204 .rs1 = reg2,
6205 .imm12 = imm1,
6206 } },
6207 }),
6208 else => error.InvalidInstruction,
6209 },
6210 else => error.InvalidInstruction,
6211 },
6212 .none => switch (mnem) {
6213 .jalr => try func.addInst(.{
6214 .tag = mnem,
6215 .data = .{ .i_type = .{
6216 .rd = .ra,
6217 .rs1 = reg1,
6218 .imm12 = Immediate.s(0),
6219 } },
6220 }),
6221 else => error.InvalidInstruction,
6222 },
6223 else => error.InvalidInstruction,
6224 },
6225 else => error.InvalidInstruction,
6226 }) catch |err| {
6227 switch (err) {
6228 error.InvalidInstruction => return func.fail(
6229 "invalid instruction: {s} {s} {s} {s} {s}",
6230 .{
6231 @tagName(mnem),
6232 @tagName(ops[0]),
6233 @tagName(ops[1]),
6234 @tagName(ops[2]),
6235 @tagName(ops[3]),
6236 },
6237 ),
6238 else => |e| return e,
6239 }
6240 };
6241 },
6242 .pseudo => |pseudo| {
6243 (@as(error{InvalidInstruction}!void, switch (pseudo) {
6244 .li => blk: {
6245 if (ops[0] != .reg or ops[1] != .imm) {
6246 break :blk error.InvalidInstruction;
6247 }
55886248
5589 if (std.meta.stringToEnum(Mir.Inst.Tag, asm_source)) |tag| {
5590 _ = try func.addInst(.{
5591 .tag = tag,
5592 .ops = .none,
5593 .data = undefined,
5594 });
5595 } else {
5596 return func.fail("TODO: asm_source {s}", .{asm_source});
5597 }
6249 const reg = ops[0].reg;
6250 const imm = ops[1].imm;
55986251
5599 if (output_constraint) |output| {
5600 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
5601 return func.fail("unrecognized asm output constraint: '{s}'", .{output});
5602 }
5603 const reg_name = output[2 .. output.len - 1];
5604 const reg = parseRegName(reg_name) orelse
5605 return func.fail("unrecognized register: '{s}'", .{reg_name});
5606 break :result .{ .register = reg };
5607 } else {
5608 break :result .{ .none = {} };
6252 try func.genSetReg(Type.usize, reg, .{ .immediate = imm.asBits(u64) });
6253 },
6254 .mv => blk: {
6255 if (ops[0] != .reg or ops[1] != .reg) {
6256 break :blk error.InvalidInstruction;
6257 }
6258
6259 const dst = ops[0].reg;
6260 const src = ops[1].reg;
6261
6262 if (dst.class() != .int or src.class() != .int) {
6263 return func.fail("pseudo instruction 'mv' only works on integer registers", .{});
6264 }
6265
6266 try func.genSetReg(Type.usize, dst, .{ .register = src });
6267 },
6268 .tail => blk: {
6269 if (ops[0] != .sym) {
6270 break :blk error.InvalidInstruction;
6271 }
6272
6273 const sym_offset = ops[0].sym;
6274 assert(sym_offset.off == 0);
6275
6276 const random_link_reg, const lock = try func.allocReg(.int);
6277 defer func.register_manager.unlockReg(lock);
6278
6279 _ = try func.addInst(.{
6280 .tag = .pseudo_extern_fn_reloc,
6281 .data = .{ .reloc = .{
6282 .register = random_link_reg,
6283 .atom_index = try func.owner.getSymbolIndex(func),
6284 .sym_index = sym_offset.sym,
6285 } },
6286 });
6287 },
6288 .ret => _ = try func.addInst(.{
6289 .tag = .jalr,
6290 .data = .{ .i_type = .{
6291 .rd = .zero,
6292 .rs1 = .ra,
6293 .imm12 = Immediate.s(0),
6294 } },
6295 }),
6296 .beqz => blk: {
6297 if (ops[0] != .reg or ops[1] != .inst) {
6298 break :blk error.InvalidInstruction;
6299 }
6300
6301 _ = try func.addInst(.{
6302 .tag = .beq,
6303 .data = .{ .b_type = .{
6304 .rs1 = ops[0].reg,
6305 .rs2 = .zero,
6306 .inst = ops[1].inst,
6307 } },
6308 });
6309 },
6310 })) catch |err| {
6311 switch (err) {
6312 error.InvalidInstruction => return func.fail(
6313 "invalid instruction: {s} {s} {s} {s} {s}",
6314 .{
6315 @tagName(pseudo),
6316 @tagName(ops[0]),
6317 @tagName(ops[1]),
6318 @tagName(ops[2]),
6319 @tagName(ops[3]),
6320 },
6321 ),
6322 else => |e| return e,
6323 }
6324 };
6325 },
56096326 }
5610 };
6327 }
6328
6329 var label_it = labels.iterator();
6330 while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)
6331 return func.fail("undefined label: '{s}'", .{label.key_ptr.*});
6332
6333 for (outputs, args.items[0..outputs.len]) |output, arg_mcv| {
6334 const extra_bytes = mem.sliceAsBytes(func.air.extra[outputs_extra_i..]);
6335 const constraint =
6336 mem.sliceTo(mem.sliceAsBytes(func.air.extra[outputs_extra_i..]), 0);
6337 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
6338 // This equation accounts for the fact that even if we have exactly 4 bytes
6339 // for the string, we still use the next u32 for the null terminator.
6340 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
6341
6342 if (output == .none) continue;
6343 if (arg_mcv != .register) continue;
6344 if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;
6345 try func.store(.{ .air_ref = output }, arg_mcv, func.typeOf(output));
6346 }
56116347
56126348 simple: {
56136349 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
......@@ -5668,12 +6404,19 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
56686404 ty,
56696405 src_mcv,
56706406 ),
6407 .load_tlv => {
6408 const addr_reg, const addr_lock = try func.allocReg(.int);
6409 defer func.register_manager.unlockReg(addr_lock);
6410
6411 try func.genSetReg(ty, addr_reg, dst_mcv.address());
6412 try func.genCopy(ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
6413 },
56716414 .memory => return func.fail("TODO: genCopy memory", .{}),
56726415 .register_pair => |dst_regs| {
56736416 const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) {
56746417 .register_pair, .memory, .indirect, .load_frame => null,
56756418 .load_symbol => src: {
5676 const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.usize, src_mcv.address());
6419 const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.u64, src_mcv.address());
56776420 errdefer func.register_manager.unlockReg(src_addr_lock);
56786421
56796422 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
......@@ -5725,14 +6468,23 @@ fn genInlineMemcpy(
57256468 const src = regs[2];
57266469 const dst = regs[3];
57276470
5728 try func.genSetReg(Type.usize, count, len);
5729 try func.genSetReg(Type.usize, src, src_ptr);
5730 try func.genSetReg(Type.usize, dst, dst_ptr);
6471 try func.genSetReg(Type.u64, count, len);
6472 try func.genSetReg(Type.u64, src, src_ptr);
6473 try func.genSetReg(Type.u64, dst, dst_ptr);
6474
6475 // if count is 0, there's nothing to copy
6476 _ = try func.addInst(.{
6477 .tag = .beq,
6478 .data = .{ .b_type = .{
6479 .rs1 = count,
6480 .rs2 = .zero,
6481 .inst = @intCast(func.mir_instructions.len + 9),
6482 } },
6483 });
57316484
57326485 // lb tmp, 0(src)
57336486 const first_inst = try func.addInst(.{
57346487 .tag = .lb,
5735 .ops = .rri,
57366488 .data = .{
57376489 .i_type = .{
57386490 .rd = tmp,
......@@ -5745,7 +6497,6 @@ fn genInlineMemcpy(
57456497 // sb tmp, 0(dst)
57466498 _ = try func.addInst(.{
57476499 .tag = .sb,
5748 .ops = .rri,
57496500 .data = .{
57506501 .i_type = .{
57516502 .rd = dst,
......@@ -5758,7 +6509,6 @@ fn genInlineMemcpy(
57586509 // dec count by 1
57596510 _ = try func.addInst(.{
57606511 .tag = .addi,
5761 .ops = .rri,
57626512 .data = .{
57636513 .i_type = .{
57646514 .rd = count,
......@@ -5771,7 +6521,6 @@ fn genInlineMemcpy(
57716521 // branch if count is 0
57726522 _ = try func.addInst(.{
57736523 .tag = .beq,
5774 .ops = .rr_inst,
57756524 .data = .{
57766525 .b_type = .{
57776526 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
......@@ -5784,7 +6533,6 @@ fn genInlineMemcpy(
57846533 // increment the pointers
57856534 _ = try func.addInst(.{
57866535 .tag = .addi,
5787 .ops = .rri,
57886536 .data = .{
57896537 .i_type = .{
57906538 .rd = src,
......@@ -5796,7 +6544,6 @@ fn genInlineMemcpy(
57966544
57976545 _ = try func.addInst(.{
57986546 .tag = .addi,
5799 .ops = .rri,
58006547 .data = .{
58016548 .i_type = .{
58026549 .rd = dst,
......@@ -5808,9 +6555,11 @@ fn genInlineMemcpy(
58086555
58096556 // jump back to start of loop
58106557 _ = try func.addInst(.{
5811 .tag = .pseudo,
5812 .ops = .pseudo_j,
5813 .data = .{ .inst = first_inst },
6558 .tag = .pseudo_j,
6559 .data = .{ .j_type = .{
6560 .rd = .zero,
6561 .inst = first_inst,
6562 } },
58146563 });
58156564}
58166565
......@@ -5828,14 +6577,13 @@ fn genInlineMemset(
58286577 const src = regs[1];
58296578 const dst = regs[2];
58306579
5831 try func.genSetReg(Type.usize, count, len);
5832 try func.genSetReg(Type.usize, src, src_value);
5833 try func.genSetReg(Type.usize, dst, dst_ptr);
6580 try func.genSetReg(Type.u64, count, len);
6581 try func.genSetReg(Type.u64, src, src_value);
6582 try func.genSetReg(Type.u64, dst, dst_ptr);
58346583
58356584 // sb src, 0(dst)
58366585 const first_inst = try func.addInst(.{
58376586 .tag = .sb,
5838 .ops = .rri,
58396587 .data = .{
58406588 .i_type = .{
58416589 .rd = dst,
......@@ -5848,7 +6596,6 @@ fn genInlineMemset(
58486596 // dec count by 1
58496597 _ = try func.addInst(.{
58506598 .tag = .addi,
5851 .ops = .rri,
58526599 .data = .{
58536600 .i_type = .{
58546601 .rd = count,
......@@ -5861,7 +6608,6 @@ fn genInlineMemset(
58616608 // branch if count is 0
58626609 _ = try func.addInst(.{
58636610 .tag = .beq,
5864 .ops = .rr_inst,
58656611 .data = .{
58666612 .b_type = .{
58676613 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
......@@ -5874,7 +6620,6 @@ fn genInlineMemset(
58746620 // increment the pointers
58756621 _ = try func.addInst(.{
58766622 .tag = .addi,
5877 .ops = .rri,
58786623 .data = .{
58796624 .i_type = .{
58806625 .rd = dst,
......@@ -5886,11 +6631,11 @@ fn genInlineMemset(
58866631
58876632 // jump back to start of loop
58886633 _ = try func.addInst(.{
5889 .tag = .pseudo,
5890 .ops = .pseudo_j,
5891 .data = .{
6634 .tag = .pseudo_j,
6635 .data = .{ .j_type = .{
6636 .rd = .zero,
58926637 .inst = first_inst,
5893 },
6638 } },
58946639 });
58956640}
58966641
......@@ -5936,7 +6681,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
59366681 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {
59376682 _ = try func.addInst(.{
59386683 .tag = .addi,
5939 .ops = .rri,
59406684 .data = .{ .i_type = .{
59416685 .rd = reg,
59426686 .rs1 = .zero,
......@@ -5950,7 +6694,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
59506694
59516695 _ = try func.addInst(.{
59526696 .tag = .lui,
5953 .ops = .ri,
59546697 .data = .{ .u_type = .{
59556698 .rd = reg,
59566699 .imm20 = Immediate.s(hi20),
......@@ -5958,7 +6701,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
59586701 });
59596702 _ = try func.addInst(.{
59606703 .tag = .addi,
5961 .ops = .rri,
59626704 .data = .{ .i_type = .{
59636705 .rd = reg,
59646706 .rs1 = reg,
......@@ -5981,7 +6723,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
59816723
59826724 _ = try func.addInst(.{
59836725 .tag = .slli,
5984 .ops = .rri,
59856726 .data = .{ .i_type = .{
59866727 .rd = reg,
59876728 .rs1 = reg,
......@@ -5991,7 +6732,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
59916732
59926733 _ = try func.addInst(.{
59936734 .tag = .add,
5994 .ops = .rrr,
59956735 .data = .{ .r_type = .{
59966736 .rd = reg,
59976737 .rs1 = reg,
......@@ -6028,15 +6768,16 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
60286768
60296769 // mv reg, src_reg
60306770 _ = try func.addInst(.{
6031 .tag = .pseudo,
6032 .ops = .pseudo_mv,
6771 .tag = .pseudo_mv,
60336772 .data = .{ .rr = .{
60346773 .rd = reg,
60356774 .rs = src_reg,
60366775 } },
60376776 });
60386777 },
6039 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
6778 // useful in cases like slice_ptr, which can easily reuse the operand
6779 // but we need to get only the pointer out.
6780 .register_pair => |pair| try func.genSetReg(ty, reg, .{ .register = pair[0] }),
60406781 .load_frame => |frame| {
60416782 if (reg.class() == .vector) {
60426783 // vectors don't support an offset memory load so we need to put the true
......@@ -6048,8 +6789,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
60486789 try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } });
60496790 } else {
60506791 _ = try func.addInst(.{
6051 .tag = .pseudo,
6052 .ops = .pseudo_load_rm,
6792 .tag = .pseudo_load_rm,
60536793 .data = .{ .rm = .{
60546794 .r = reg,
60556795 .m = .{
......@@ -6069,7 +6809,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
60696809
60706810 _ = try func.addInst(.{
60716811 .tag = .ld,
6072 .ops = .rri,
60736812 .data = .{ .i_type = .{
60746813 .rd = reg,
60756814 .rs1 = reg,
......@@ -6079,8 +6818,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
60796818 },
60806819 .lea_frame, .register_offset => {
60816820 _ = try func.addInst(.{
6082 .tag = .pseudo,
6083 .ops = .pseudo_lea_rm,
6821 .tag = .pseudo_lea_rm,
60846822 .data = .{
60856823 .rm = .{
60866824 .r = reg,
......@@ -6108,7 +6846,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
61086846 });
61096847 },
61106848 .indirect => |reg_off| {
6111 const load_tag: Mir.Inst.Tag = switch (reg.class()) {
6849 const load_tag: Mnemonic = switch (reg.class()) {
61126850 .float => switch (abi_size) {
61136851 1 => unreachable, // Zig does not support 8-bit floats
61146852 2 => return func.fail("TODO: genSetReg indirect 16-bit float", .{}),
......@@ -6147,8 +6885,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
61476885 });
61486886
61496887 _ = try func.addInst(.{
6150 .tag = .pseudo,
6151 .ops = .pseudo_load_rm,
6888 .tag = .pseudo_load_rm,
61526889 .data = .{ .rm = .{
61536890 .r = reg,
61546891 .m = .{
......@@ -6168,7 +6905,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
61686905
61696906 _ = try func.addInst(.{
61706907 .tag = load_tag,
6171 .ops = .rri,
61726908 .data = .{ .i_type = .{
61736909 .rd = reg,
61746910 .rs1 = reg_off.reg,
......@@ -6178,16 +6914,15 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
61786914 },
61796915 .lea_symbol => |sym_off| {
61806916 assert(sym_off.off == 0);
6181 const atom_index = try func.symbolIndex();
6917 const atom_index = try func.owner.getSymbolIndex(func);
61826918
61836919 _ = try func.addInst(.{
6184 .tag = .pseudo,
6185 .ops = .pseudo_load_symbol,
6186 .data = .{ .payload = try func.addExtra(Mir.LoadSymbolPayload{
6187 .register = reg.encodeId(),
6920 .tag = .pseudo_load_symbol,
6921 .data = .{ .reloc = .{
6922 .register = reg,
61886923 .atom_index = atom_index,
61896924 .sym_index = sym_off.sym,
6190 }) },
6925 } },
61916926 });
61926927 },
61936928 .load_symbol => {
......@@ -6197,6 +6932,25 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
61976932 try func.genSetReg(ty, addr_reg, src_mcv.address());
61986933 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
61996934 },
6935 .lea_tlv => |sym| {
6936 const atom_index = try func.owner.getSymbolIndex(func);
6937
6938 _ = try func.addInst(.{
6939 .tag = .pseudo_load_tlv,
6940 .data = .{ .reloc = .{
6941 .register = reg,
6942 .atom_index = atom_index,
6943 .sym_index = sym,
6944 } },
6945 });
6946 },
6947 .load_tlv => {
6948 const addr_reg, const addr_lock = try func.allocReg(.int);
6949 defer func.register_manager.unlockReg(addr_lock);
6950
6951 try func.genSetReg(ty, addr_reg, src_mcv.address());
6952 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
6953 },
62006954 .air_ref => |ref| try func.genSetReg(ty, reg, try func.resolveInst(ref)),
62016955 else => return func.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
62026956 }
......@@ -6216,7 +6970,6 @@ fn genSetMem(
62166970 const dst_ptr_mcv: MCValue = switch (base) {
62176971 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
62186972 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
6219 .reloc => |base_symbol| .{ .lea_symbol = .{ .sym = base_symbol.sym_index, .off = disp } },
62206973 };
62216974 switch (src_mcv) {
62226975 .none,
......@@ -6260,7 +7013,7 @@ fn genSetMem(
62607013 },
62617014 .register => |reg| {
62627015 if (reg.class() == .vector) {
6263 const addr_reg = try func.copyToTmpRegister(Type.usize, dst_ptr_mcv);
7016 const addr_reg = try func.copyToTmpRegister(Type.u64, dst_ptr_mcv);
62647017
62657018 const num_elem = ty.vectorLen(zcu);
62667019 const elem_size = ty.childType(zcu).bitSize(pt);
......@@ -6279,8 +7032,7 @@ fn genSetMem(
62797032 });
62807033
62817034 _ = try func.addInst(.{
6282 .tag = .pseudo,
6283 .ops = .pseudo_store_rm,
7035 .tag = .pseudo_store_rm,
62847036 .data = .{ .rm = .{
62857037 .r = reg,
62867038 .m = .{
......@@ -6319,8 +7071,7 @@ fn genSetMem(
63197071 }));
63207072 const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } };
63217073 _ = try func.addInst(.{
6322 .tag = .pseudo,
6323 .ops = .pseudo_store_rm,
7074 .tag = .pseudo_store_rm,
63247075 .data = .{ .rm = .{
63257076 .r = reg,
63267077 .m = .{
......@@ -6335,8 +7086,7 @@ fn genSetMem(
63357086 try func.genSetMem(base, disp, ty, frame_mcv);
63367087 try func.freeValue(frame_mcv);
63377088 } else _ = try func.addInst(.{
6338 .tag = .pseudo,
6339 .ops = .pseudo_store_rm,
7089 .tag = .pseudo_store_rm,
63407090 .data = .{ .rm = .{
63417091 .r = reg,
63427092 .m = .{
......@@ -6366,6 +7116,7 @@ fn genSetMem(
63667116 return func.genSetMem(base, disp, ty, .{ .register = reg });
63677117 },
63687118 .air_ref => |src_ref| try func.genSetMem(base, disp, ty, try func.resolveInst(src_ref)),
7119 else => return func.fail("TODO: genSetMem {s}", .{@tagName(src_mcv)}),
63697120 }
63707121}
63717122
......@@ -6398,7 +7149,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void {
63987149 const src_lock = if (src_mcv.getReg()) |reg| func.register_manager.lockReg(reg) else null;
63997150 defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
64007151
6401 const dst_mcv = if (dst_ty.abiSize(pt) <= src_ty.abiSize(pt) and
7152 const dst_mcv = if (dst_ty.abiSize(pt) <= src_ty.abiSize(pt) and src_mcv != .register_pair and
64027153 func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
64037154 const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true);
64047155 try func.genCopy(switch (math.order(dst_ty.abiSize(pt), src_ty.abiSize(pt))) {
......@@ -6437,7 +7188,7 @@ fn airArrayToSlice(func: *Func, inst: Air.Inst.Index) !void {
64377188 try func.genSetMem(
64387189 .{ .frame = frame_index },
64397190 @intCast(ptr_ty.abiSize(pt)),
6440 Type.usize,
7191 Type.u64,
64417192 .{ .immediate = array_len },
64427193 );
64437194
......@@ -6447,107 +7198,409 @@ fn airArrayToSlice(func: *Func, inst: Air.Inst.Index) !void {
64477198
64487199fn airFloatFromInt(func: *Func, inst: Air.Inst.Index) !void {
64497200 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6450 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airFloatFromInt for {}", .{
6451 func.target.cpu.arch,
6452 });
7201 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
7202 const pt = func.pt;
7203 const zcu = pt.zcu;
7204
7205 const operand = try func.resolveInst(ty_op.operand);
7206
7207 const src_ty = func.typeOf(ty_op.operand);
7208 const dst_ty = ty_op.ty.toType();
7209
7210 const src_reg, const src_lock = try func.promoteReg(src_ty, operand);
7211 defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
7212
7213 const is_unsigned = dst_ty.isUnsignedInt(zcu);
7214 const src_bits = src_ty.bitSize(pt);
7215 const dst_bits = dst_ty.bitSize(pt);
7216
7217 switch (src_bits) {
7218 32, 64 => {},
7219 else => try func.truncateRegister(src_ty, src_reg),
7220 }
7221
7222 const int_mod: Mir.FcvtOp = switch (src_bits) {
7223 8, 16, 32 => if (is_unsigned) .wu else .w,
7224 64 => if (is_unsigned) .lu else .l,
7225 else => return func.fail("TODO: airFloatFromInt src size: {d}", .{src_bits}),
7226 };
7227
7228 const float_mod: enum { s, d } = switch (dst_bits) {
7229 32 => .s,
7230 64 => .d,
7231 else => return func.fail("TODO: airFloatFromInt dst size {d}", .{dst_bits}),
7232 };
7233
7234 const dst_reg, const dst_lock = try func.allocReg(.int);
7235 defer func.register_manager.unlockReg(dst_lock);
7236
7237 _ = try func.addInst(.{
7238 .tag = switch (float_mod) {
7239 .s => switch (int_mod) {
7240 .l => .fcvtsl,
7241 .lu => .fcvtslu,
7242 .w => .fcvtsw,
7243 .wu => .fcvtswu,
7244 },
7245 .d => switch (int_mod) {
7246 .l => .fcvtdl,
7247 .lu => .fcvtdlu,
7248 .w => .fcvtdw,
7249 .wu => .fcvtdwu,
7250 },
7251 },
7252 .data = .{ .rr = .{
7253 .rd = dst_reg,
7254 .rs = src_reg,
7255 } },
7256 });
7257
7258 break :result .{ .register = dst_reg };
7259 };
64537260 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
64547261}
64557262
64567263fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void {
64577264 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6458 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airIntFromFloat for {}", .{
6459 func.target.cpu.arch,
6460 });
7265 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
7266 const pt = func.pt;
7267 const zcu = pt.zcu;
7268
7269 const operand = try func.resolveInst(ty_op.operand);
7270 const src_ty = func.typeOf(ty_op.operand);
7271 const dst_ty = ty_op.ty.toType();
7272
7273 const is_unsigned = dst_ty.isUnsignedInt(zcu);
7274 const src_bits = src_ty.bitSize(pt);
7275 const dst_bits = dst_ty.bitSize(pt);
7276
7277 const float_mod: enum { s, d } = switch (src_bits) {
7278 32 => .s,
7279 64 => .d,
7280 else => return func.fail("TODO: airIntFromFloat src size {d}", .{src_bits}),
7281 };
7282
7283 const int_mod: Mir.FcvtOp = switch (dst_bits) {
7284 32 => if (is_unsigned) .wu else .w,
7285 8, 16, 64 => if (is_unsigned) .lu else .l,
7286 else => return func.fail("TODO: airIntFromFloat dst size: {d}", .{dst_bits}),
7287 };
7288
7289 const src_reg, const src_lock = try func.promoteReg(src_ty, operand);
7290 defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
7291
7292 const dst_reg, const dst_lock = try func.allocReg(.int);
7293 defer func.register_manager.unlockReg(dst_lock);
7294
7295 _ = try func.addInst(.{
7296 .tag = switch (float_mod) {
7297 .s => switch (int_mod) {
7298 .l => .fcvtls,
7299 .lu => .fcvtlus,
7300 .w => .fcvtws,
7301 .wu => .fcvtwus,
7302 },
7303 .d => switch (int_mod) {
7304 .l => .fcvtld,
7305 .lu => .fcvtlud,
7306 .w => .fcvtwd,
7307 .wu => .fcvtwud,
7308 },
7309 },
7310 .data = .{ .rr = .{
7311 .rd = dst_reg,
7312 .rs = src_reg,
7313 } },
7314 });
7315
7316 break :result .{ .register = dst_reg };
7317 };
64617318 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
64627319}
64637320
6464fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {
7321fn airCmpxchg(func: *Func, inst: Air.Inst.Index, strength: enum { weak, strong }) !void {
7322 _ = strength; // TODO: do something with this
7323
7324 const pt = func.pt;
64657325 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6466 const extra = func.air.extraData(Air.Block, ty_pl.payload);
6467 _ = extra;
6468 return func.fail("TODO implement airCmpxchg for {}", .{
6469 func.target.cpu.arch,
7326 const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
7327
7328 const ptr_ty = func.typeOf(extra.ptr);
7329 const val_ty = func.typeOf(extra.expected_value);
7330 const val_abi_size: u32 = @intCast(val_ty.abiSize(pt));
7331
7332 switch (val_abi_size) {
7333 1, 2, 4, 8 => {},
7334 else => return func.fail("TODO: airCmpxchg Int size {}", .{val_abi_size}),
7335 }
7336
7337 const lr_order: struct { aq: Mir.Barrier, rl: Mir.Barrier } = switch (extra.successOrder()) {
7338 .unordered,
7339 => unreachable,
7340
7341 .monotonic,
7342 .release,
7343 => .{ .aq = .none, .rl = .none },
7344 .acquire,
7345 .acq_rel,
7346 => .{ .aq = .aq, .rl = .none },
7347 .seq_cst => .{ .aq = .aq, .rl = .rl },
7348 };
7349
7350 const sc_order: struct { aq: Mir.Barrier, rl: Mir.Barrier } = switch (extra.failureOrder()) {
7351 .unordered,
7352 .release,
7353 .acq_rel,
7354 => unreachable,
7355
7356 .monotonic,
7357 .acquire,
7358 .seq_cst,
7359 => switch (extra.successOrder()) {
7360 .release,
7361 .seq_cst,
7362 => .{ .aq = .none, .rl = .rl },
7363 else => .{ .aq = .none, .rl = .none },
7364 },
7365 };
7366
7367 const ptr_mcv = try func.resolveInst(extra.ptr);
7368 const ptr_reg, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv);
7369 defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock);
7370
7371 const exp_mcv = try func.resolveInst(extra.expected_value);
7372 const exp_reg, const exp_lock = try func.promoteReg(val_ty, exp_mcv);
7373 defer if (exp_lock) |lock| func.register_manager.unlockReg(lock);
7374 try func.truncateRegister(val_ty, exp_reg);
7375
7376 const new_mcv = try func.resolveInst(extra.new_value);
7377 const new_reg, const new_lock = try func.promoteReg(val_ty, new_mcv);
7378 defer if (new_lock) |lock| func.register_manager.unlockReg(lock);
7379 try func.truncateRegister(val_ty, new_reg);
7380
7381 const branch_reg, const branch_lock = try func.allocReg(.int);
7382 defer func.register_manager.unlockReg(branch_lock);
7383
7384 const fallthrough_reg, const fallthrough_lock = try func.allocReg(.int);
7385 defer func.register_manager.unlockReg(fallthrough_lock);
7386
7387 const jump_back = try func.addInst(.{
7388 .tag = if (val_ty.bitSize(pt) <= 32) .lrw else .lrd,
7389 .data = .{ .amo = .{
7390 .aq = lr_order.aq,
7391 .rl = lr_order.rl,
7392 .rd = branch_reg,
7393 .rs1 = ptr_reg,
7394 .rs2 = .zero,
7395 } },
64707396 });
6471 // return func.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
7397 try func.truncateRegister(val_ty, branch_reg);
7398
7399 const jump_forward = try func.addInst(.{
7400 .tag = .bne,
7401 .data = .{ .b_type = .{
7402 .rs1 = branch_reg,
7403 .rs2 = exp_reg,
7404 .inst = undefined,
7405 } },
7406 });
7407
7408 _ = try func.addInst(.{
7409 .tag = if (val_ty.bitSize(pt) <= 32) .scw else .scd,
7410 .data = .{ .amo = .{
7411 .aq = sc_order.aq,
7412 .rl = sc_order.rl,
7413 .rd = fallthrough_reg,
7414 .rs1 = ptr_reg,
7415 .rs2 = new_reg,
7416 } },
7417 });
7418 try func.truncateRegister(Type.bool, fallthrough_reg);
7419
7420 _ = try func.addInst(.{
7421 .tag = .bne,
7422 .data = .{ .b_type = .{
7423 .rs1 = fallthrough_reg,
7424 .rs2 = .zero,
7425 .inst = jump_back,
7426 } },
7427 });
7428
7429 func.performReloc(jump_forward);
7430
7431 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
7432 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, false);
7433
7434 const tmp_reg, const tmp_lock = try func.allocReg(.int);
7435 defer func.register_manager.unlockReg(tmp_lock);
7436
7437 try func.genBinOp(
7438 .cmp_neq,
7439 .{ .register = branch_reg },
7440 val_ty,
7441 .{ .register = exp_reg },
7442 val_ty,
7443 tmp_reg,
7444 );
7445
7446 try func.genCopy(val_ty, dst_mcv, .{ .register = branch_reg });
7447 try func.genCopy(
7448 Type.bool,
7449 dst_mcv.address().offset(@intCast(val_abi_size)).deref(),
7450 .{ .register = tmp_reg },
7451 );
7452
7453 break :result dst_mcv;
7454 };
7455
7456 return func.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
64727457}
64737458
64747459fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
64757460 const pt = func.pt;
7461 const zcu = pt.zcu;
64767462 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
64777463 const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data;
64787464
6479 const op = extra.op();
6480 const order = extra.ordering();
7465 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
7466 const op = extra.op();
7467 const order = extra.ordering();
64817468
6482 const ptr_ty = func.typeOf(pl_op.operand);
6483 const ptr_mcv = try func.resolveInst(pl_op.operand);
7469 const ptr_ty = func.typeOf(pl_op.operand);
7470 const ptr_mcv = try func.resolveInst(pl_op.operand);
64847471
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);
7472 const val_ty = func.typeOf(extra.operand);
7473 const val_size = val_ty.abiSize(pt);
7474 const val_mcv = try func.resolveInst(extra.operand);
64887475
6489 if (!math.isPowerOfTwo(val_size))
6490 return func.fail("TODO: airAtomicRmw non-pow 2", .{});
7476 if (!math.isPowerOfTwo(val_size))
7477 return func.fail("TODO: airAtomicRmw non-pow 2", .{});
64917478
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 }
7479 switch (val_ty.zigTypeTag(pt.zcu)) {
7480 .Enum, .Int => {},
7481 inline .Bool, .Float, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}),
7482 else => unreachable,
7483 }
64977484
6498 switch (val_size) {
6499 1, 2 => return func.fail("TODO: airAtomicRmw Int {}", .{val_size}),
6500 4, 8 => {},
6501 else => unreachable,
6502 }
7485 const method: enum { amo, loop } = switch (val_size) {
7486 1, 2 => .loop,
7487 4, 8 => .amo,
7488 else => unreachable,
7489 };
65037490
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);
7491 const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv);
7492 defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock);
65067493
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);
7494 const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv);
7495 defer if (val_lock) |lock| func.register_manager.unlockReg(lock);
65097496
6510 const result_mcv = try func.allocRegOrMem(val_ty, inst, true);
6511 assert(result_mcv == .register); // should fit into 8 bytes
7497 const result_mcv = try func.allocRegOrMem(val_ty, inst, true);
7498 assert(result_mcv == .register); // should fit into 8 bytes
7499 const result_reg = result_mcv.register;
65127500
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 };
7501 const aq, const rl = switch (order) {
7502 .unordered => unreachable,
7503 .monotonic => .{ false, false },
7504 .acquire => .{ true, false },
7505 .release => .{ false, true },
7506 .acq_rel => .{ true, true },
7507 .seq_cst => .{ true, true },
7508 };
65217509
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,
7510 switch (method) {
7511 .amo => {
7512 const is_d = val_ty.abiSize(pt) == 8;
7513 const is_un = val_ty.isUnsignedInt(zcu);
7514
7515 const mnem: Mnemonic = switch (op) {
7516 // zig fmt: off
7517 .Xchg => if (is_d) .amoswapd else .amoswapw,
7518 .Add => if (is_d) .amoaddd else .amoaddw,
7519 .And => if (is_d) .amoandd else .amoandw,
7520 .Or => if (is_d) .amoord else .amoorw,
7521 .Xor => if (is_d) .amoxord else .amoxorw,
7522 .Max => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw,
7523 .Min => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw,
7524 else => return func.fail("TODO: airAtomicRmw amo {s}", .{@tagName(op)}),
7525 // zig fmt: on
7526 };
7527
7528 _ = try func.addInst(.{
7529 .tag = mnem,
7530 .data = .{ .amo = .{
7531 .rd = result_reg,
7532 .rs1 = ptr_register,
7533 .rs2 = val_register,
7534 .aq = if (aq) .aq else .none,
7535 .rl = if (rl) .rl else .none,
7536 } },
7537 });
65417538 },
6542 .ty = val_ty,
6543 } },
6544 });
7539 .loop => {
7540 // where we'll jump back when the sc fails
7541 const jump_back = try func.addInst(.{
7542 .tag = .lrw,
7543 .data = .{ .amo = .{
7544 .rd = result_reg,
7545 .rs1 = ptr_register,
7546 .rs2 = .zero,
7547 .aq = if (aq) .aq else .none,
7548 .rl = if (rl) .rl else .none,
7549 } },
7550 });
7551
7552 const after_reg, const after_lock = try func.allocReg(.int);
7553 defer func.register_manager.unlockReg(after_lock);
7554
7555 switch (op) {
7556 .Add, .Sub => |tag| {
7557 _ = try func.genBinOp(
7558 switch (tag) {
7559 .Add => .add,
7560 .Sub => .sub,
7561 else => unreachable,
7562 },
7563 .{ .register = result_reg },
7564 val_ty,
7565 .{ .register = val_register },
7566 val_ty,
7567 after_reg,
7568 );
7569 },
7570
7571 else => return func.fail("TODO: airAtomicRmw loop {s}", .{@tagName(op)}),
7572 }
7573
7574 _ = try func.addInst(.{
7575 .tag = .scw,
7576 .data = .{ .amo = .{
7577 .rd = after_reg,
7578 .rs1 = ptr_register,
7579 .rs2 = after_reg,
7580 .aq = if (aq) .aq else .none,
7581 .rl = if (rl) .rl else .none,
7582 } },
7583 });
7584
7585 _ = try func.addInst(.{
7586 .tag = .bne,
7587 .data = .{ .b_type = .{
7588 .inst = jump_back,
7589 .rs1 = after_reg,
7590 .rs2 = .zero,
7591 } },
7592 });
7593 },
7594 }
7595 break :result result_mcv;
7596 };
65457597
6546 return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none });
7598 return func.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none });
65477599}
65487600
65497601fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
6550 const zcu = func.pt.zcu;
7602 const pt = func.pt;
7603 const zcu = pt.zcu;
65517604 const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
65527605 const order: std.builtin.AtomicOrder = atomic_load.order;
65537606
......@@ -6555,20 +7608,19 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
65557608 const elem_ty = ptr_ty.childType(zcu);
65567609 const ptr_mcv = try func.resolveInst(atomic_load.ptr);
65577610
7611 const bit_size = elem_ty.bitSize(pt);
7612 if (bit_size > 64) return func.fail("TODO: airAtomicStore > 64 bits", .{});
7613
65587614 const result_mcv = try func.allocRegOrMem(elem_ty, inst, true);
65597615 assert(result_mcv == .register); // should be less than 8 bytes
65607616
65617617 if (order == .seq_cst) {
65627618 _ = 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 },
7619 .tag = .fence,
7620 .data = .{ .fence = .{
7621 .pred = .rw,
7622 .succ = .rw,
7623 } },
65727624 });
65737625 }
65747626
......@@ -6581,15 +7633,11 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
65817633 // Make sure all previous reads happen before any reading or writing accurs.
65827634 .seq_cst, .acquire => {
65837635 _ = 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 },
7636 .tag = .fence,
7637 .data = .{ .fence = .{
7638 .pred = .r,
7639 .succ = .rw,
7640 } },
65937641 });
65947642 },
65957643 else => unreachable,
......@@ -6607,25 +7655,24 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr
66077655 const val_ty = func.typeOf(bin_op.rhs);
66087656 const val_mcv = try func.resolveInst(bin_op.rhs);
66097657
7658 const bit_size = val_ty.bitSize(func.pt);
7659 if (bit_size > 64) return func.fail("TODO: airAtomicStore > 64 bits", .{});
7660
66107661 switch (order) {
66117662 .unordered, .monotonic => {},
66127663 .release, .seq_cst => {
66137664 _ = 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 },
7665 .tag = .fence,
7666 .data = .{ .fence = .{
7667 .pred = .rw,
7668 .succ = .w,
7669 } },
66237670 });
66247671 },
66257672 else => unreachable,
66267673 }
66277674
6628 try func.store(ptr_mcv, val_mcv, ptr_ty, val_ty);
7675 try func.store(ptr_mcv, val_mcv, ptr_ty);
66297676 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
66307677}
66317678
......@@ -6689,15 +7736,15 @@ fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
66897736 const len = dst_ptr_ty.childType(zcu).arrayLen(zcu);
66907737
66917738 assert(len != 0); // prevented by Sema
6692 try func.store(dst_ptr, src_val, elem_ptr_ty, elem_ty);
7739 try func.store(dst_ptr, src_val, elem_ptr_ty);
66937740
66947741 const second_elem_ptr_reg, const second_elem_ptr_lock = try func.allocReg(.int);
66957742 defer func.register_manager.unlockReg(second_elem_ptr_lock);
66967743
66977744 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
66987745
6699 try func.genSetReg(Type.usize, second_elem_ptr_reg, .{ .register_offset = .{
6700 .reg = try func.copyToTmpRegister(Type.usize, dst_ptr),
7746 try func.genSetReg(Type.u64, second_elem_ptr_reg, .{ .register_offset = .{
7747 .reg = try func.copyToTmpRegister(Type.u64, dst_ptr),
67017748 .off = elem_abi_size,
67027749 } });
67037750
......@@ -6711,123 +7758,94 @@ fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
67117758}
67127759
67137760fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void {
6714 _ = inst;
6715 return func.fail("TODO implement airMemcpy for {}", .{func.target.cpu.arch});
6716}
6717
6718fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
6719 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
6720 const operand = try func.resolveInst(un_op);
6721 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else {
6722 _ = operand;
6723 return func.fail("TODO implement airTagName for riscv64", .{});
6724 };
6725 return func.finishAir(inst, result, .{ un_op, .none, .none });
6726}
6727
6728fn airErrorName(func: *Func, inst: Air.Inst.Index) !void {
67297761 const pt = func.pt;
67307762 const zcu = pt.zcu;
6731 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7763 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
67327764
6733 const err_ty = func.typeOf(un_op);
6734 const err_mcv = try func.resolveInst(un_op);
7765 const dst_ptr = try func.resolveInst(bin_op.lhs);
7766 const src_ptr = try func.resolveInst(bin_op.rhs);
67357767
6736 const err_reg = try func.copyToTmpRegister(err_ty, err_mcv);
6737 const err_lock = func.register_manager.lockRegAssumeUnused(err_reg);
6738 defer func.register_manager.unlockReg(err_lock);
7768 const dst_ty = func.typeOf(bin_op.lhs);
67397769
6740 const addr_reg, const addr_lock = try func.allocReg(.int);
6741 defer func.register_manager.unlockReg(addr_lock);
7770 const len_mcv: MCValue = switch (dst_ty.ptrSize(zcu)) {
7771 .Slice => len: {
7772 const len_reg, const len_lock = try func.allocReg(.int);
7773 defer func.register_manager.unlockReg(len_lock);
67427774
6743 // this is now the base address of the error name table
6744 const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, zcu);
6745 if (func.bin_file.cast(link.File.Elf)) |elf_file| {
6746 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
6747 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
6748 const sym = elf_file.symbol(sym_index);
6749 try func.genSetReg(Type.usize, addr_reg, .{ .load_symbol = .{ .sym = sym.esym_index } });
6750 } else {
6751 return func.fail("TODO: riscv non-elf", .{});
6752 }
7775 const elem_size = dst_ty.childType(zcu).abiSize(pt);
7776 try func.genBinOp(
7777 .mul,
7778 .{ .immediate = elem_size },
7779 Type.u64,
7780 dst_ptr.address().offset(8).deref(),
7781 Type.u64,
7782 len_reg,
7783 );
7784 break :len .{ .register = len_reg };
7785 },
7786 .One => len: {
7787 const array_ty = dst_ty.childType(zcu);
7788 break :len .{ .immediate = array_ty.arrayLen(zcu) * array_ty.childType(zcu).abiSize(pt) };
7789 },
7790 else => |size| return func.fail("TODO: airMemcpy size {s}", .{@tagName(size)}),
7791 };
7792 const len_lock: ?RegisterLock = switch (len_mcv) {
7793 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
7794 else => null,
7795 };
7796 defer if (len_lock) |lock| func.register_manager.unlockReg(lock);
67537797
6754 const start_reg, const start_lock = try func.allocReg(.int);
6755 defer func.register_manager.unlockReg(start_lock);
7798 try func.genInlineMemcpy(dst_ptr, src_ptr, len_mcv);
67567799
6757 const end_reg, const end_lock = try func.allocReg(.int);
6758 defer func.register_manager.unlockReg(end_lock);
7800 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
7801}
67597802
6760 // const tmp_reg, const tmp_lock = try func.allocReg(.int);
6761 // defer func.register_manager.unlockReg(tmp_lock);
7803fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
7804 const pt = func.pt;
7805 const zcu = pt.zcu;
67627806
6763 // we move the base address forward by the following formula: base + (errno * 8)
7807 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7808 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
7809 const enum_ty = func.typeOf(un_op);
67647810
6765 // shifting left by 4 is the same as multiplying by 8
6766 _ = try func.addInst(.{
6767 .tag = .slli,
6768 .ops = .rri,
6769 .data = .{ .i_type = .{
6770 .imm12 = Immediate.u(4),
6771 .rd = err_reg,
6772 .rs1 = err_reg,
6773 } },
6774 });
7811 // TODO: work out the bugs
7812 if (true) return func.fail("TODO: airTagName", .{});
67757813
6776 _ = try func.addInst(.{
6777 .tag = .add,
6778 .ops = .rrr,
6779 .data = .{ .r_type = .{
6780 .rd = addr_reg,
6781 .rs1 = addr_reg,
6782 .rs2 = err_reg,
6783 } },
6784 });
7814 const param_regs = abi.Registers.Integer.function_arg_regs;
7815 const dst_mcv = try func.allocRegOrMem(Type.u64, inst, false);
7816 try func.genSetReg(Type.u64, param_regs[0], dst_mcv.address());
67857817
6786 _ = try func.addInst(.{
6787 .tag = .pseudo,
6788 .ops = .pseudo_load_rm,
6789 .data = .{
6790 .rm = .{
6791 .r = start_reg,
6792 .m = .{
6793 .base = .{ .reg = addr_reg },
6794 .mod = .{ .size = .dword, .unsigned = true },
6795 },
6796 },
6797 },
6798 });
7818 const operand = try func.resolveInst(un_op);
7819 try func.genSetReg(enum_ty, param_regs[1], operand);
67997820
6800 _ = try func.addInst(.{
6801 .tag = .pseudo,
6802 .ops = .pseudo_load_rm,
6803 .data = .{
6804 .rm = .{
6805 .r = end_reg,
6806 .m = .{
6807 .base = .{ .reg = addr_reg },
6808 .mod = .{ .size = .dword, .unsigned = true },
6809 },
6810 },
6811 },
6812 });
7821 const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(zcu), zcu);
7822 const elf_file = func.bin_file.cast(link.File.Elf).?;
7823 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
7824 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
7825 const sym = elf_file.symbol(sym_index);
68137826
6814 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, false);
6815 const frame = dst_mcv.load_frame;
6816 try func.genSetMem(
6817 .{ .frame = frame.index },
6818 frame.off,
6819 Type.usize,
6820 .{ .register = start_reg },
6821 );
7827 if (func.mod.pic) {
7828 return func.fail("TODO: airTagName pic", .{});
7829 } else {
7830 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
7831 _ = try func.addInst(.{
7832 .tag = .jalr,
7833 .data = .{ .i_type = .{
7834 .rd = .ra,
7835 .rs1 = .ra,
7836 .imm12 = Immediate.s(0),
7837 } },
7838 });
7839 }
68227840
6823 try func.genSetMem(
6824 .{ .frame = frame.index },
6825 frame.off + 8,
6826 Type.usize,
6827 .{ .register = end_reg },
6828 );
7841 break :result dst_mcv;
7842 };
7843 return func.finishAir(inst, result, .{ un_op, .none, .none });
7844}
68297845
6830 return func.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
7846fn airErrorName(func: *Func, inst: Air.Inst.Index) !void {
7847 _ = inst;
7848 return func.fail("TODO: airErrorName", .{});
68317849}
68327850
68337851fn airSplat(func: *Func, inst: Air.Inst.Index) !void {
......@@ -7013,9 +8031,10 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
70138031
70148032fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
70158033 const pt = func.pt;
8034 const zcu = pt.zcu;
70168035 const gpa = func.gpa;
70178036
7018 const owner_decl_index = pt.zcu.funcOwnerDeclIndex(func.func_index);
8037 const owner_decl_index = func.owner.getDecl(zcu);
70198038 const lf = func.bin_file;
70208039 const src_loc = func.src_loc;
70218040
......@@ -7047,9 +8066,10 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
70478066 .none => .none,
70488067 .undef => unreachable,
70498068 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
8069 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
70508070 .immediate => |imm| .{ .immediate = imm },
70518071 .memory => |addr| .{ .memory = addr },
7052 .load_got, .load_direct, .load_tlv => {
8072 .load_got, .load_direct => {
70538073 return func.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});
70548074 },
70558075 },
src/arch/riscv64/Emit.zig+96-77
......@@ -40,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void {
4040 .source = start_offset,
4141 .target = target,
4242 .offset = 0,
43 .enc = std.meta.activeTag(lowered_inst.encoding.data),
43 .fmt = std.meta.activeTag(lowered_inst),
4444 }),
4545 .load_symbol_reloc => |symbol| {
4646 const is_obj_or_static_lib = switch (emit.lower.output_mode) {
......@@ -49,46 +49,70 @@ pub fn emitMir(emit: *Emit) Error!void {
4949 .Lib => emit.lower.link_mode == .static,
5050 };
5151
52 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
53 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
54 const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);
55 const sym = elf_file.symbol(sym_index);
56
57 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
58 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
59
60 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
61 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
62
63 hi_r_type = Elf.R_ZIG_GOT_HI20;
64 lo_r_type = Elf.R_ZIG_GOT_LO12;
65 }
66
67 try atom_ptr.addReloc(elf_file, .{
68 .r_offset = start_offset,
69 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,
70 .r_addend = 0,
71 });
72
73 try atom_ptr.addReloc(elf_file, .{
74 .r_offset = start_offset + 4,
75 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,
76 .r_addend = 0,
77 });
78 } else unreachable;
52 const elf_file = emit.bin_file.cast(link.File.Elf).?;
53
54 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
55 const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);
56 const sym = elf_file.symbol(sym_index);
57
58 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
59 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
60
61 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
62 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
63
64 hi_r_type = Elf.R_ZIG_GOT_HI20;
65 lo_r_type = Elf.R_ZIG_GOT_LO12;
66 }
67
68 try atom_ptr.addReloc(elf_file, .{
69 .r_offset = start_offset,
70 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,
71 .r_addend = 0,
72 });
73
74 try atom_ptr.addReloc(elf_file, .{
75 .r_offset = start_offset + 4,
76 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,
77 .r_addend = 0,
78 });
79 },
80 .load_tlv_reloc => |symbol| {
81 const elf_file = emit.bin_file.cast(link.File.Elf).?;
82
83 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
84
85 const R_RISCV = std.elf.R_RISCV;
86
87 try atom_ptr.addReloc(elf_file, .{
88 .r_offset = start_offset,
89 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_HI20),
90 .r_addend = 0,
91 });
92
93 try atom_ptr.addReloc(elf_file, .{
94 .r_offset = start_offset + 4,
95 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_ADD),
96 .r_addend = 0,
97 });
98
99 try atom_ptr.addReloc(elf_file, .{
100 .r_offset = start_offset + 8,
101 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_LO12_I),
102 .r_addend = 0,
103 });
79104 },
80105 .call_extern_fn_reloc => |symbol| {
81 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
82 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
106 const elf_file = emit.bin_file.cast(link.File.Elf).?;
107 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
83108
84 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
109 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
85110
86 try atom_ptr.addReloc(elf_file, .{
87 .r_offset = start_offset,
88 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
89 .r_addend = 0,
90 });
91 } else return emit.fail("TODO: call_extern_fn_reloc non-ELF", .{});
111 try atom_ptr.addReloc(elf_file, .{
112 .r_offset = start_offset,
113 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
114 .r_addend = 0,
115 });
92116 },
93117 };
94118 }
......@@ -98,40 +122,37 @@ pub fn emitMir(emit: *Emit) Error!void {
98122 const mir_inst = emit.lower.mir.instructions.get(mir_index);
99123 switch (mir_inst.tag) {
100124 else => unreachable,
101 .pseudo => switch (mir_inst.ops) {
102 else => unreachable,
103 .pseudo_dbg_prologue_end => {
104 switch (emit.debug_output) {
105 .dwarf => |dw| {
106 try dw.setPrologueEnd();
107 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
108 emit.prev_di_line, emit.prev_di_column,
109 });
110 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
111 },
112 .plan9 => {},
113 .none => {},
114 }
115 },
116 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
117 mir_inst.data.pseudo_dbg_line_column.line,
118 mir_inst.data.pseudo_dbg_line_column.column,
119 ),
120 .pseudo_dbg_epilogue_begin => {
121 switch (emit.debug_output) {
122 .dwarf => |dw| {
123 try dw.setEpilogueBegin();
124 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
125 emit.prev_di_line, emit.prev_di_column,
126 });
127 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
128 },
129 .plan9 => {},
130 .none => {},
131 }
132 },
133 .pseudo_dead => {},
125 .pseudo_dbg_prologue_end => {
126 switch (emit.debug_output) {
127 .dwarf => |dw| {
128 try dw.setPrologueEnd();
129 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
130 emit.prev_di_line, emit.prev_di_column,
131 });
132 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
133 },
134 .plan9 => {},
135 .none => {},
136 }
134137 },
138 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
139 mir_inst.data.pseudo_dbg_line_column.line,
140 mir_inst.data.pseudo_dbg_line_column.column,
141 ),
142 .pseudo_dbg_epilogue_begin => {
143 switch (emit.debug_output) {
144 .dwarf => |dw| {
145 try dw.setEpilogueBegin();
146 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
147 emit.prev_di_line, emit.prev_di_column,
148 });
149 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
150 },
151 .plan9 => {},
152 .none => {},
153 }
154 },
155 .pseudo_dead => {},
135156 }
136157 }
137158 }
......@@ -151,8 +172,8 @@ const Reloc = struct {
151172 target: Mir.Inst.Index,
152173 /// Offset of the relocation within the instruction.
153174 offset: u32,
154 /// Encoding of the instruction, used to determine how to modify it.
155 enc: Encoding.InstEnc,
175 /// Format of the instruction, used to determine how to modify it.
176 fmt: encoding.Lir.Format,
156177};
157178
158179fn fixupRelocs(emit: *Emit) Error!void {
......@@ -164,12 +185,10 @@ fn fixupRelocs(emit: *Emit) Error!void {
164185 const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source));
165186 const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4];
166187
167 log.debug("disp: {x}", .{disp});
168
169 switch (reloc.enc) {
188 switch (reloc.fmt) {
170189 .J => riscv_util.writeInstJ(code, @bitCast(disp)),
171190 .B => riscv_util.writeInstB(code, @bitCast(disp)),
172 else => return emit.fail("tried to reloc encoding type {s}", .{@tagName(reloc.enc)}),
191 else => return emit.fail("tried to reloc format type {s}", .{@tagName(reloc.fmt)}),
173192 }
174193 }
175194}
......@@ -209,5 +228,5 @@ const Emit = @This();
209228const Lower = @import("Lower.zig");
210229const Mir = @import("Mir.zig");
211230const riscv_util = @import("../../link/riscv.zig");
212const Encoding = @import("Encoding.zig");
213231const Elf = @import("../../link/Elf.zig");
232const encoding = @import("encoding.zig");
src/arch/riscv64/Encoding.zig deleted-1119
......@@ -1,1119 +0,0 @@
1mnemonic: Mnemonic,
2data: Data,
3
4const OpCode = enum(u7) {
5 LOAD = 0b0000011,
6 LOAD_FP = 0b0000111,
7 MISC_MEM = 0b0001111,
8 OP_IMM = 0b0010011,
9 AUIPC = 0b0010111,
10 OP_IMM_32 = 0b0011011,
11 STORE = 0b0100011,
12 STORE_FP = 0b0100111,
13 AMO = 0b0101111,
14 OP_V = 0b1010111,
15 OP = 0b0110011,
16 OP_32 = 0b0111011,
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,
26 JAL = 0b1101111,
27 SYSTEM = 0b1110011,
28 OP_64 = 0b1111011,
29 NONE = 0b00000000,
30};
31
32const FpFmt = enum(u2) {
33 /// 32-bit single-precision
34 S = 0b00,
35 /// 64-bit double-precision
36 D = 0b01,
37
38 // H = 0b10, unused in the G extension
39
40 /// 128-bit quad-precision
41 Q = 0b11,
42};
43
44const AmoWidth = enum(u3) {
45 W = 0b010,
46 D = 0b011,
47};
48
49const FenceMode = enum(u4) {
50 none = 0b0000,
51 tso = 0b1000,
52};
53
54const Enc = struct {
55 opcode: OpCode,
56
57 data: union(enum) {
58 /// funct3 + funct7
59 ff: struct {
60 funct3: u3,
61 funct7: u7,
62 },
63 amo: struct {
64 funct5: u5,
65 width: AmoWidth,
66 },
67 fence: struct {
68 funct3: u3,
69 fm: FenceMode,
70 },
71 /// funct5 + rm + fmt
72 fmt: struct {
73 funct5: u5,
74 rm: u3,
75 fmt: FpFmt,
76 },
77 /// funct3
78 f: struct {
79 funct3: u3,
80 },
81 /// typ + funct3 + has_5
82 sh: struct {
83 typ: u6,
84 funct3: u3,
85 has_5: bool,
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 },
100 /// U-type
101 none,
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 };
136};
137
138pub const Mnemonic = enum {
139 // base mnemonics
140
141 // I Type
142 ld,
143 lw,
144 lwu,
145 lh,
146 lhu,
147 lb,
148 lbu,
149
150 sltiu,
151 xori,
152 andi,
153
154 slli,
155 srli,
156 srai,
157
158 slliw,
159 srliw,
160 sraiw,
161
162 addi,
163 jalr,
164
165 vsetivli,
166 vsetvli,
167
168 // U Type
169 lui,
170 auipc,
171
172 // S Type
173 sd,
174 sw,
175 sh,
176 sb,
177
178 // J Type
179 jal,
180
181 // B Type
182 beq,
183
184 // R Type
185 add,
186 addw,
187 sub,
188 subw,
189 @"and",
190 @"or",
191 slt,
192 sltu,
193 xor,
194
195 sll,
196 srl,
197 sra,
198
199 sllw,
200 srlw,
201 sraw,
202
203 // System
204 ecall,
205 ebreak,
206 unimp,
207
208 csrrs,
209
210 // M extension
211 mul,
212 mulw,
213
214 mulh,
215 mulhu,
216 mulhsu,
217
218 div,
219 divu,
220
221 divw,
222 divuw,
223
224 rem,
225 remu,
226
227 remw,
228 remuw,
229
230 // F extension (32-bit float)
231 fadds,
232 fsubs,
233 fmuls,
234 fdivs,
235
236 fmins,
237 fmaxs,
238
239 fsqrts,
240
241 flw,
242 fsw,
243
244 feqs,
245 flts,
246 fles,
247
248 fsgnjns,
249 fsgnjxs,
250
251 // D extension (64-bit float)
252 faddd,
253 fsubd,
254 fmuld,
255 fdivd,
256
257 fmind,
258 fmaxd,
259
260 fsqrtd,
261
262 fld,
263 fsd,
264
265 feqd,
266 fltd,
267 fled,
268
269 fsgnjnd,
270 fsgnjxd,
271
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
324 pub fn encoding(mnem: Mnemonic) Enc {
325 return switch (mnem) {
326 // zig fmt: off
327
328 // OP
329
330 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
331 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
332
333 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
334 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
335 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
336
337 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
338 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
339
340 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
341 .mulh => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000001 } } },
342 .mulhsu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000001 } } },
343 .mulhu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000001 } } },
344
345 .div => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
346 .divu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
347
348 .rem => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
349 .remu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
350
351 .sll => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
352 .srl => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
353 .sra => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
354
355
356 // OP_IMM
357
358 .addi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b000 } } },
359 .andi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b111 } } },
360 .xori => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b100 } } },
361
362 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b011 } } },
363
364 .slli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = true } } },
365 .srli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
366 .srai => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
367
368
369 // OP_IMM_32
370
371 .slliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = false } } },
372 .srliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
373 .sraiw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
374
375
376 // OP_32
377
378 .addw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
379 .subw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
380 .mulw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
381
382 .divw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
383 .divuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
384
385 .remw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
386 .remuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
387
388 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
389 .srlw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
390 .sraw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
391
392
393 // OP_FP
394
395 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
396 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
397
398 .fsubs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .S, .rm = 0b111 } } },
399 .fsubd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .D, .rm = 0b111 } } },
400
401 .fmuls => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .S, .rm = 0b111 } } },
402 .fmuld => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .D, .rm = 0b111 } } },
403
404 .fdivs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .S, .rm = 0b111 } } },
405 .fdivd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .D, .rm = 0b111 } } },
406
407 .fmins => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b000 } } },
408 .fmind => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b000 } } },
409
410 .fmaxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b001 } } },
411 .fmaxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b001 } } },
412
413 .fsqrts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .S, .rm = 0b111 } } },
414 .fsqrtd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .D, .rm = 0b111 } } },
415
416 .fles => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b000 } } },
417 .fled => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b000 } } },
418
419 .flts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b001 } } },
420 .fltd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b001 } } },
421
422 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
423 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
424
425 .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
426 .fsgnjnd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
427
428 .fsgnjxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b0010} } },
429 .fsgnjxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b0010} } },
430
431
432 // LOAD
433
434 .lb => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b000 } } },
435 .lh => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b001 } } },
436 .lw => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b010 } } },
437 .ld => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b011 } } },
438 .lbu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b100 } } },
439 .lhu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b101 } } },
440 .lwu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b110 } } },
441
442
443 // STORE
444
445 .sb => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b000 } } },
446 .sh => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b001 } } },
447 .sw => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b010 } } },
448 .sd => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b011 } } },
449
450
451 // LOAD_FP
452
453 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
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 } } },
460
461
462 // STORE_FP
463
464 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
465 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
466
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 } } },
473
474 // JALR
475
476 .jalr => .{ .opcode = .JALR, .data = .{ .f = .{ .funct3 = 0b000 } } },
477
478
479 // LUI
480
481 .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
482
483
484 // AUIPC
485
486 .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
487
488
489 // JAL
490
491 .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
492
493
494 // BRANCH
495
496 .beq => .{ .opcode = .BRANCH, .data = .{ .f = .{ .funct3 = 0b000 } } },
497
498
499 // SYSTEM
500
501 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
502 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
503
504 .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } },
505
506
507 // NONE
508
509 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
510
511
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
558 // zig fmt: on
559 };
560 }
561};
562
563pub const InstEnc = enum {
564 R,
565 R4,
566 I,
567 S,
568 B,
569 U,
570 J,
571 fence,
572 amo,
573 system,
574
575 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
576 return switch (mnem) {
577 .addi,
578 .jalr,
579 .sltiu,
580 .xori,
581 .andi,
582
583 .slli,
584 .srli,
585 .srai,
586
587 .slliw,
588 .srliw,
589 .sraiw,
590
591 .ld,
592 .lw,
593 .lwu,
594 .lh,
595 .lhu,
596 .lb,
597 .lbu,
598
599 .flw,
600 .fld,
601
602 .csrrs,
603 .vsetivli,
604 .vsetvli,
605 => .I,
606
607 .lui,
608 .auipc,
609 => .U,
610
611 .sd,
612 .sw,
613 .sh,
614 .sb,
615
616 .fsd,
617 .fsw,
618 => .S,
619
620 .jal,
621 => .J,
622
623 .beq,
624 => .B,
625
626 .slt,
627 .sltu,
628
629 .sll,
630 .srl,
631 .sra,
632
633 .sllw,
634 .srlw,
635 .sraw,
636
637 .div,
638 .divu,
639 .divw,
640 .divuw,
641
642 .rem,
643 .remu,
644 .remw,
645 .remuw,
646
647 .xor,
648 .@"and",
649 .@"or",
650
651 .add,
652 .addw,
653
654 .sub,
655 .subw,
656
657 .mul,
658 .mulw,
659 .mulh,
660 .mulhu,
661 .mulhsu,
662
663 .fadds,
664 .faddd,
665
666 .fsubs,
667 .fsubd,
668
669 .fmuls,
670 .fmuld,
671
672 .fdivs,
673 .fdivd,
674
675 .fmins,
676 .fmind,
677
678 .fmaxs,
679 .fmaxd,
680
681 .fsqrts,
682 .fsqrtd,
683
684 .fles,
685 .fled,
686
687 .flts,
688 .fltd,
689
690 .feqs,
691 .feqd,
692
693 .fsgnjns,
694 .fsgnjnd,
695
696 .fsgnjxs,
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,
718 => .R,
719
720 .ecall,
721 .ebreak,
722 .unimp,
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,
749 };
750 }
751
752 pub fn opsList(enc: InstEnc) [5]std.meta.FieldEnum(Operand) {
753 return switch (enc) {
754 // zig fmt: off
755 .R => .{ .reg, .reg, .reg, .none, .none, },
756 .R4 => .{ .reg, .reg, .reg, .reg, .none, },
757 .I => .{ .reg, .reg, .imm, .none, .none, },
758 .S => .{ .reg, .reg, .imm, .none, .none, },
759 .B => .{ .reg, .reg, .imm, .none, .none, },
760 .U => .{ .reg, .imm, .none, .none, .none, },
761 .J => .{ .reg, .imm, .none, .none, .none, },
762 .system => .{ .none, .none, .none, .none, .none, },
763 .fence => .{ .barrier, .barrier, .none, .none, .none, },
764 .amo => .{ .reg, .reg, .reg, .barrier, .barrier },
765 // zig fmt: on
766 };
767 }
768};
769
770pub const Data = union(InstEnc) {
771 R: packed struct {
772 opcode: u7,
773 rd: u5,
774 funct3: u3,
775 rs1: u5,
776 rs2: u5,
777 funct7: u7,
778 },
779 R4: packed struct {
780 opcode: u7,
781 rd: u5,
782 funct3: u3,
783 rs1: u5,
784 rs2: u5,
785 funct2: u2,
786 rs3: u5,
787 },
788 I: packed struct {
789 opcode: u7,
790 rd: u5,
791 funct3: u3,
792 rs1: u5,
793 imm0_11: u12,
794 },
795 S: packed struct {
796 opcode: u7,
797 imm0_4: u5,
798 funct3: u3,
799 rs1: u5,
800 rs2: u5,
801 imm5_11: u7,
802 },
803 B: packed struct {
804 opcode: u7,
805 imm11: u1,
806 imm1_4: u4,
807 funct3: u3,
808 rs1: u5,
809 rs2: u5,
810 imm5_10: u6,
811 imm12: u1,
812 },
813 U: packed struct {
814 opcode: u7,
815 rd: u5,
816 imm12_31: u20,
817 },
818 J: packed struct {
819 opcode: u7,
820 rd: u5,
821 imm12_19: u8,
822 imm11: u1,
823 imm1_10: u10,
824 imm20: u1,
825 },
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 }
852
853 pub fn toU32(self: Data) u32 {
854 return switch (self) {
855 .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),
856 inline else => |v| @bitCast(v),
857 .system => unreachable,
858 };
859 }
860
861 pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data {
862 const inst_enc = InstEnc.fromMnemonic(mnem);
863 const enc = mnem.encoding();
864
865 // special mnemonics
866 switch (mnem) {
867 .ecall,
868 .ebreak,
869 .unimp,
870 => {
871 assert(ops.len == 0);
872 return .{
873 .I = .{
874 .rd = Register.zero.encodeId(),
875 .rs1 = Register.zero.encodeId(),
876 .imm0_11 = switch (mnem) {
877 .ecall => 0x000,
878 .ebreak => 0x001,
879 .unimp => 0x000,
880 else => unreachable,
881 },
882
883 .opcode = @intFromEnum(enc.opcode),
884 .funct3 = enc.data.f.funct3,
885 },
886 };
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 },
907 else => {},
908 }
909
910 switch (inst_enc) {
911 .R => {
912 assert(ops.len == 3);
913 return .{
914 .R = switch (enc.data) {
915 .ff => |ff| .{
916 .rd = ops[0].reg.encodeId(),
917 .rs1 = ops[1].reg.encodeId(),
918 .rs2 = ops[2].reg.encodeId(),
919
920 .opcode = @intFromEnum(enc.opcode),
921 .funct3 = ff.funct3,
922 .funct7 = ff.funct7,
923 },
924 .fmt => |fmt| .{
925 .rd = ops[0].reg.encodeId(),
926 .rs1 = ops[1].reg.encodeId(),
927 .rs2 = ops[2].reg.encodeId(),
928
929 .opcode = @intFromEnum(enc.opcode),
930 .funct3 = fmt.rm,
931 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
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 },
952 else => unreachable,
953 },
954 };
955 },
956 .S => {
957 assert(ops.len == 3);
958 const umm = ops[2].imm.asBits(u12);
959
960 return .{
961 .S = .{
962 .imm0_4 = @truncate(umm),
963 .rs1 = ops[0].reg.encodeId(),
964 .rs2 = ops[1].reg.encodeId(),
965 .imm5_11 = @truncate(umm >> 5),
966
967 .opcode = @intFromEnum(enc.opcode),
968 .funct3 = enc.data.f.funct3,
969 },
970 };
971 },
972 .I => {
973 assert(ops.len == 3);
974 return .{
975 .I = switch (enc.data) {
976 .f => |f| .{
977 .rd = ops[0].reg.encodeId(),
978 .rs1 = ops[1].reg.encodeId(),
979 .imm0_11 = ops[2].imm.asBits(u12),
980
981 .opcode = @intFromEnum(enc.opcode),
982 .funct3 = f.funct3,
983 },
984 .sh => |sh| .{
985 .rd = ops[0].reg.encodeId(),
986 .rs1 = ops[1].reg.encodeId(),
987 .imm0_11 = (@as(u12, sh.typ) << 6) |
988 if (sh.has_5) ops[2].imm.asBits(u6) else (@as(u6, 0) | ops[2].imm.asBits(u5)),
989
990 .opcode = @intFromEnum(enc.opcode),
991 .funct3 = sh.funct3,
992 },
993 else => unreachable,
994 },
995 };
996 },
997 .U => {
998 assert(ops.len == 2);
999 return .{
1000 .U = .{
1001 .rd = ops[0].reg.encodeId(),
1002 .imm12_31 = ops[1].imm.asBits(u20),
1003
1004 .opcode = @intFromEnum(enc.opcode),
1005 },
1006 };
1007 },
1008 .J => {
1009 assert(ops.len == 2);
1010
1011 const umm = ops[1].imm.asBits(u21);
1012 assert(umm % 4 == 0); // misaligned jump target
1013
1014 return .{
1015 .J = .{
1016 .rd = ops[0].reg.encodeId(),
1017 .imm1_10 = @truncate(umm >> 1),
1018 .imm11 = @truncate(umm >> 11),
1019 .imm12_19 = @truncate(umm >> 12),
1020 .imm20 = @truncate(umm >> 20),
1021
1022 .opcode = @intFromEnum(enc.opcode),
1023 },
1024 };
1025 },
1026 .B => {
1027 assert(ops.len == 3);
1028
1029 const umm = ops[2].imm.asBits(u13);
1030 assert(umm % 4 == 0); // misaligned branch target
1031
1032 return .{
1033 .B = .{
1034 .rs1 = ops[0].reg.encodeId(),
1035 .rs2 = ops[1].reg.encodeId(),
1036 .imm1_4 = @truncate(umm >> 1),
1037 .imm5_10 = @truncate(umm >> 5),
1038 .imm11 = @truncate(umm >> 11),
1039 .imm12 = @truncate(umm >> 12),
1040
1041 .opcode = @intFromEnum(enc.opcode),
1042 .funct3 = enc.data.f.funct3,
1043 },
1044 };
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;
1071
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 },
1088 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
1089 }
1090 }
1091};
1092
1093pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding {
1094 if (!verifyOps(mnem, ops)) return null;
1095
1096 return .{
1097 .mnemonic = mnem,
1098 .data = try Data.construct(mnem, ops),
1099 };
1100}
1101
1102fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {
1103 const inst_enc = InstEnc.fromMnemonic(mnem);
1104 const list = std.mem.sliceTo(&inst_enc.opsList(), .none);
1105 for (list, ops) |l, o| if (l != std.meta.activeTag(o)) return false;
1106 return true;
1107}
1108
1109const std = @import("std");
1110const assert = std.debug.assert;
1111const log = std.log.scoped(.encoding);
1112
1113const Encoding = @This();
1114const bits = @import("bits.zig");
1115const Register = bits.Register;
1116const encoder = @import("encoder.zig");
1117const Instruction = encoder.Instruction;
1118const Operand = Instruction.Operand;
1119const OperandEnum = std.meta.FieldEnum(Operand);
src/arch/riscv64/Lower.zig+451-474
......@@ -34,6 +34,8 @@ pub const Reloc = struct {
3434
3535 /// Relocs the lowered_inst_index and the next instruction.
3636 load_symbol_reloc: bits.Symbol,
37 /// Relocs the lowered_inst_index and the next two instructions.
38 load_tlv_reloc: bits.Symbol,
3739 /// Relocs the lowered_inst_index and the next instruction.
3840 call_extern_fn_reloc: bits.Symbol,
3941 };
......@@ -61,453 +63,418 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
6163 log.debug("lowerMir {}", .{inst});
6264 switch (inst.tag) {
6365 else => try lower.generic(inst),
64 .pseudo => switch (inst.ops) {
65 .pseudo_dbg_line_column,
66 .pseudo_dbg_epilogue_begin,
67 .pseudo_dbg_prologue_end,
68 .pseudo_dead,
69 => {},
70
71 .pseudo_load_rm, .pseudo_store_rm => {
72 const rm = inst.data.rm;
73
74 const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs)
75 rm.m.toFrameLoc(lower.mir)
76 else
77 .{ .base = .s0, .disp = 0 };
78
79 switch (inst.ops) {
80 .pseudo_load_rm => {
81 const dest_reg = rm.r;
82 const dest_reg_class = dest_reg.class();
83
84 const src_size = rm.m.mod.size;
85 const unsigned = rm.m.mod.unsigned;
86
87 const tag: Encoding.Mnemonic = switch (dest_reg_class) {
88 .int => switch (src_size) {
89 .byte => if (unsigned) .lbu else .lb,
90 .hword => if (unsigned) .lhu else .lh,
91 .word => if (unsigned) .lwu else .lw,
92 .dword => .ld,
93 },
94 .float => switch (src_size) {
95 .byte => unreachable, // Zig does not support 8-bit floats
96 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
97 .word => .flw,
98 .dword => .fld,
99 },
100 .vector => switch (src_size) {
101 .byte => .vle8v,
102 .hword => .vle32v,
103 .word => .vle32v,
104 .dword => .vle64v,
105 },
106 };
107
108 switch (dest_reg_class) {
109 .int, .float => {
110 try lower.emit(tag, &.{
111 .{ .reg = rm.r },
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 }
125 },
126 .pseudo_store_rm => {
127 const src_reg = rm.r;
128 const src_reg_class = src_reg.class();
129
130 const dest_size = rm.m.mod.size;
131
132 const tag: Encoding.Mnemonic = switch (src_reg_class) {
133 .int => switch (dest_size) {
134 .byte => .sb,
135 .hword => .sh,
136 .word => .sw,
137 .dword => .sd,
138 },
139 .float => switch (dest_size) {
140 .byte => unreachable, // Zig does not support 8-bit floats
141 .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}),
142 .word => .fsw,
143 .dword => .fsd,
144 },
145 .vector => switch (dest_size) {
146 .byte => .vse8v,
147 .hword => .vse16v,
148 .word => .vse32v,
149 .dword => .vse64v,
150 },
151 };
152
153 switch (src_reg_class) {
154 .int, .float => {
155 try lower.emit(tag, &.{
156 .{ .reg = frame_loc.base },
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 }
170 },
171 else => unreachable,
172 }
173 },
174
175 .pseudo_mv => {
176 const rr = inst.data.rr;
177
178 const dst_class = rr.rd.class();
179 const src_class = rr.rs.class();
180
181 switch (src_class) {
182 .float => switch (dst_class) {
183 .float => {
184 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
185 .{ .reg = rr.rd },
186 .{ .reg = rr.rs },
187 .{ .reg = rr.rs },
188 });
66 .pseudo_dbg_line_column,
67 .pseudo_dbg_epilogue_begin,
68 .pseudo_dbg_prologue_end,
69 .pseudo_dead,
70 => {},
71
72 .pseudo_load_rm, .pseudo_store_rm => {
73 const rm = inst.data.rm;
74
75 const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs)
76 rm.m.toFrameLoc(lower.mir)
77 else
78 .{ .base = .s0, .disp = 0 };
79
80 switch (inst.tag) {
81 .pseudo_load_rm => {
82 const dest_reg = rm.r;
83 const dest_reg_class = dest_reg.class();
84
85 const src_size = rm.m.mod.size;
86 const unsigned = rm.m.mod.unsigned;
87
88 const mnem: Mnemonic = switch (dest_reg_class) {
89 .int => switch (src_size) {
90 .byte => if (unsigned) .lbu else .lb,
91 .hword => if (unsigned) .lhu else .lh,
92 .word => if (unsigned) .lwu else .lw,
93 .dword => .ld,
18994 },
190 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),
191 },
192 .int => switch (dst_class) {
193 .int => {
194 try lower.emit(.addi, &.{
195 .{ .reg = rr.rd },
196 .{ .reg = rr.rs },
197 .{ .imm = Immediate.s(0) },
198 });
95 .float => switch (src_size) {
96 .byte => unreachable, // Zig does not support 8-bit floats
97 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
98 .word => .flw,
99 .dword => .fld,
199100 },
200 .vector => {
201 try lower.emit(.vmvvx, &.{
202 .{ .reg = rr.rd },
203 .{ .reg = rr.rs },
204 .{ .reg = .x0 },
101 .vector => switch (src_size) {
102 .byte => .vle8v,
103 .hword => .vle32v,
104 .word => .vle32v,
105 .dword => .vle64v,
106 },
107 };
108
109 switch (dest_reg_class) {
110 .int, .float => {
111 try lower.emit(mnem, &.{
112 .{ .reg = rm.r },
113 .{ .reg = frame_loc.base },
114 .{ .imm = Immediate.s(frame_loc.disp) },
205115 });
206116 },
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 },
117 .vector => {
118 assert(frame_loc.disp == 0);
119 try lower.emit(mnem, &.{
120 .{ .reg = rm.r },
121 .{ .reg = frame_loc.base },
213122 .{ .reg = .zero },
214 .{ .reg = rr.rs },
215123 });
216124 },
217 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),
218 },
219 }
220 },
221
222 .pseudo_j => {
223 try lower.emit(.jal, &.{
224 .{ .reg = .zero },
225 .{ .imm = lower.reloc(.{ .inst = inst.data.inst }) },
226 });
227 },
228
229 .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list),
230 .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list),
231
232 .pseudo_load_symbol => {
233 const payload = inst.data.payload;
234 const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data;
235 const dst_reg: bits.Register = @enumFromInt(data.register);
236 assert(dst_reg.class() == .int);
237
238 try lower.emit(.lui, &.{
239 .{ .reg = dst_reg },
240 .{ .imm = lower.reloc(.{
241 .load_symbol_reloc = .{
242 .atom_index = data.atom_index,
243 .sym_index = data.sym_index,
125 }
126 },
127 .pseudo_store_rm => {
128 const src_reg = rm.r;
129 const src_reg_class = src_reg.class();
130
131 const dest_size = rm.m.mod.size;
132
133 const mnem: Mnemonic = switch (src_reg_class) {
134 .int => switch (dest_size) {
135 .byte => .sb,
136 .hword => .sh,
137 .word => .sw,
138 .dword => .sd,
244139 },
245 }) },
246 });
247
248 // the above reloc implies this one
249 try lower.emit(.addi, &.{
250 .{ .reg = dst_reg },
251 .{ .reg = dst_reg },
252 .{ .imm = Immediate.s(0) },
253 });
254 },
255
256 .pseudo_lea_rm => {
257 const rm = inst.data.rm;
258 assert(rm.r.class() == .int);
259
260 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
261 rm.m.toFrameLoc(lower.mir)
262 else
263 .{ .base = .s0, .disp = 0 };
264
265 try lower.emit(.addi, &.{
266 .{ .reg = rm.r },
267 .{ .reg = frame.base },
268 .{ .imm = Immediate.s(frame.disp) },
269 });
270 },
271
272 .pseudo_fabs => {
273 const fabs = inst.data.fabs;
274 assert(fabs.rs.class() == .float and fabs.rd.class() == .float);
275
276 const mnem: Encoding.Mnemonic = switch (fabs.bits) {
277 16 => return lower.fail("TODO: airAbs Float 16", .{}),
278 32 => .fsgnjxs,
279 64 => .fsgnjxd,
280 80 => return lower.fail("TODO: airAbs Float 80", .{}),
281 128 => return lower.fail("TODO: airAbs Float 128", .{}),
282 else => unreachable,
283 };
284
285 try lower.emit(mnem, &.{
286 .{ .reg = fabs.rs },
287 .{ .reg = fabs.rd },
288 .{ .reg = fabs.rd },
289 });
290 },
291
292 .pseudo_compare => {
293 const compare = inst.data.compare;
294 const op = compare.op;
295
296 const rd = compare.rd;
297 const rs1 = compare.rs1;
298 const rs2 = compare.rs2;
299
300 const class = rs1.class();
301 const ty = compare.ty;
302 const size = std.math.ceilPowerOfTwo(u64, ty.bitSize(pt)) catch {
303 return lower.fail("pseudo_compare size {}", .{ty.bitSize(pt)});
304 };
305
306 const is_unsigned = ty.isUnsignedInt(pt.zcu);
307
308 const less_than: Encoding.Mnemonic = if (is_unsigned) .sltu else .slt;
309
310 switch (class) {
311 .int => switch (op) {
312 .eq => {
313 try lower.emit(.xor, &.{
314 .{ .reg = rd },
315 .{ .reg = rs1 },
316 .{ .reg = rs2 },
317 });
318
319 try lower.emit(.sltiu, &.{
320 .{ .reg = rd },
321 .{ .reg = rd },
322 .{ .imm = Immediate.s(1) },
323 });
140 .float => switch (dest_size) {
141 .byte => unreachable, // Zig does not support 8-bit floats
142 .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}),
143 .word => .fsw,
144 .dword => .fsd,
324145 },
325 .neq => {
326 try lower.emit(.xor, &.{
327 .{ .reg = rd },
328 .{ .reg = rs1 },
329 .{ .reg = rs2 },
330 });
331
332 try lower.emit(.sltu, &.{
333 .{ .reg = rd },
334 .{ .reg = .zero },
335 .{ .reg = rd },
336 });
146 .vector => switch (dest_size) {
147 .byte => .vse8v,
148 .hword => .vse16v,
149 .word => .vse32v,
150 .dword => .vse64v,
337151 },
338 .gt => {
339 try lower.emit(less_than, &.{
340 .{ .reg = rd },
341 .{ .reg = rs1 },
342 .{ .reg = rs2 },
152 };
153
154 switch (src_reg_class) {
155 .int, .float => {
156 try lower.emit(mnem, &.{
157 .{ .reg = frame_loc.base },
158 .{ .reg = rm.r },
159 .{ .imm = Immediate.s(frame_loc.disp) },
343160 });
344161 },
345 .gte => {
346 try lower.emit(less_than, &.{
347 .{ .reg = rd },
348 .{ .reg = rs1 },
349 .{ .reg = rs2 },
350 });
351
352 try lower.emit(.xori, &.{
353 .{ .reg = rd },
354 .{ .reg = rd },
355 .{ .imm = Immediate.s(1) },
356 });
357 },
358 .lt => {
359 try lower.emit(less_than, &.{
360 .{ .reg = rd },
361 .{ .reg = rs1 },
362 .{ .reg = rs2 },
162 .vector => {
163 assert(frame_loc.disp == 0);
164 try lower.emit(mnem, &.{
165 .{ .reg = rm.r },
166 .{ .reg = frame_loc.base },
167 .{ .reg = .zero },
363168 });
364169 },
365 .lte => {
366 try lower.emit(less_than, &.{
367 .{ .reg = rd },
368 .{ .reg = rs2 },
369 .{ .reg = rs1 },
370 });
170 }
171 },
172 else => unreachable,
173 }
174 },
371175
372 try lower.emit(.xori, &.{
373 .{ .reg = rd },
374 .{ .reg = rd },
375 .{ .imm = Immediate.s(1) },
376 });
377 },
176 .pseudo_mv => {
177 const rr = inst.data.rr;
178
179 const dst_class = rr.rd.class();
180 const src_class = rr.rs.class();
181
182 switch (src_class) {
183 .float => switch (dst_class) {
184 .float => {
185 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
186 .{ .reg = rr.rd },
187 .{ .reg = rr.rs },
188 .{ .reg = rr.rs },
189 });
378190 },
379 .float => switch (op) {
380 // eq
381 .eq => {
382 try lower.emit(if (size == 64) .feqd else .feqs, &.{
383 .{ .reg = rd },
384 .{ .reg = rs1 },
385 .{ .reg = rs2 },
386 });
387 },
388 // !(eq)
389 .neq => {
390 try lower.emit(if (size == 64) .feqd else .feqs, &.{
391 .{ .reg = rd },
392 .{ .reg = rs1 },
393 .{ .reg = rs2 },
394 });
395 try lower.emit(.xori, &.{
396 .{ .reg = rd },
397 .{ .reg = rd },
398 .{ .imm = Immediate.s(1) },
399 });
400 },
401 .lt => {
402 try lower.emit(if (size == 64) .fltd else .flts, &.{
403 .{ .reg = rd },
404 .{ .reg = rs1 },
405 .{ .reg = rs2 },
406 });
407 },
408 .lte => {
409 try lower.emit(if (size == 64) .fled else .fles, &.{
410 .{ .reg = rd },
411 .{ .reg = rs1 },
412 .{ .reg = rs2 },
413 });
414 },
415 .gt => {
416 try lower.emit(if (size == 64) .fltd else .flts, &.{
417 .{ .reg = rd },
418 .{ .reg = rs2 },
419 .{ .reg = rs1 },
420 });
421 },
422 .gte => {
423 try lower.emit(if (size == 64) .fled else .fles, &.{
424 .{ .reg = rd },
425 .{ .reg = rs2 },
426 .{ .reg = rs1 },
427 });
428 },
191 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),
192 },
193 .int => switch (dst_class) {
194 .int => {
195 try lower.emit(.addi, &.{
196 .{ .reg = rr.rd },
197 .{ .reg = rr.rs },
198 .{ .imm = Immediate.s(0) },
199 });
200 },
201 .vector => {
202 try lower.emit(.vmvvx, &.{
203 .{ .reg = rr.rd },
204 .{ .reg = rr.rs },
205 .{ .reg = .x0 },
206 });
207 },
208 .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}),
209 },
210 .vector => switch (dst_class) {
211 .int => {
212 try lower.emit(.vadcvv, &.{
213 .{ .reg = rr.rd },
214 .{ .reg = .zero },
215 .{ .reg = rr.rs },
216 });
217 },
218 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),
219 },
220 }
221 },
222
223 .pseudo_j => {
224 const j_type = inst.data.j_type;
225 try lower.emit(.jal, &.{
226 .{ .reg = j_type.rd },
227 .{ .imm = lower.reloc(.{ .inst = j_type.inst }) },
228 });
229 },
230
231 .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list),
232 .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list),
233
234 .pseudo_load_symbol => {
235 const payload = inst.data.reloc;
236 const dst_reg = payload.register;
237 assert(dst_reg.class() == .int);
238
239 try lower.emit(.lui, &.{
240 .{ .reg = dst_reg },
241 .{ .imm = lower.reloc(.{
242 .load_symbol_reloc = .{
243 .atom_index = payload.atom_index,
244 .sym_index = payload.sym_index,
245 },
246 }) },
247 });
248
249 // the reloc above implies this one
250 try lower.emit(.addi, &.{
251 .{ .reg = dst_reg },
252 .{ .reg = dst_reg },
253 .{ .imm = Immediate.s(0) },
254 });
255 },
256
257 .pseudo_load_tlv => {
258 const payload = inst.data.reloc;
259 const dst_reg = payload.register;
260 assert(dst_reg.class() == .int);
261
262 try lower.emit(.lui, &.{
263 .{ .reg = dst_reg },
264 .{ .imm = lower.reloc(.{
265 .load_tlv_reloc = .{
266 .atom_index = payload.atom_index,
267 .sym_index = payload.sym_index,
429268 },
430 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),
431 }
432 },
433
434 .pseudo_not => {
435 const rr = inst.data.rr;
436 assert(rr.rs.class() == .int and rr.rd.class() == .int);
437
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, &.{
446 .{ .reg = rr.rd },
447 .{ .reg = rr.rs },
448 .{ .imm = Immediate.s(1) },
449 });
450 },
451
452 .pseudo_extern_fn_reloc => {
453 const inst_reloc = inst.data.reloc;
454
455 try lower.emit(.auipc, &.{
456 .{ .reg = .ra },
457 .{ .imm = lower.reloc(
458 .{ .call_extern_fn_reloc = .{
459 .atom_index = inst_reloc.atom_index,
460 .sym_index = inst_reloc.sym_index,
461 } },
462 ) },
463 });
464
465 try lower.emit(.jalr, &.{
466 .{ .reg = .ra },
467 .{ .reg = .ra },
468 .{ .imm = Immediate.s(0) },
469 });
470 },
471
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
510 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
269 }) },
270 });
271
272 try lower.emit(.add, &.{
273 .{ .reg = dst_reg },
274 .{ .reg = dst_reg },
275 .{ .reg = .tp },
276 });
277
278 try lower.emit(.addi, &.{
279 .{ .reg = dst_reg },
280 .{ .reg = dst_reg },
281 .{ .imm = Immediate.s(0) },
282 });
283 },
284
285 .pseudo_lea_rm => {
286 const rm = inst.data.rm;
287 assert(rm.r.class() == .int);
288
289 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
290 rm.m.toFrameLoc(lower.mir)
291 else
292 .{ .base = .s0, .disp = 0 };
293
294 try lower.emit(.addi, &.{
295 .{ .reg = rm.r },
296 .{ .reg = frame.base },
297 .{ .imm = Immediate.s(frame.disp) },
298 });
299 },
300
301 .pseudo_compare => {
302 const compare = inst.data.compare;
303 const op = compare.op;
304
305 const rd = compare.rd;
306 const rs1 = compare.rs1;
307 const rs2 = compare.rs2;
308
309 const class = rs1.class();
310 const ty = compare.ty;
311 const size = std.math.ceilPowerOfTwo(u64, ty.bitSize(pt)) catch {
312 return lower.fail("pseudo_compare size {}", .{ty.bitSize(pt)});
313 };
314
315 const is_unsigned = ty.isUnsignedInt(pt.zcu);
316 const less_than: Mnemonic = if (is_unsigned) .sltu else .slt;
317
318 switch (class) {
319 .int => switch (op) {
320 .eq => {
321 try lower.emit(.xor, &.{
322 .{ .reg = rd },
323 .{ .reg = rs1 },
324 .{ .reg = rs2 },
325 });
326
327 try lower.emit(.sltiu, &.{
328 .{ .reg = rd },
329 .{ .reg = rd },
330 .{ .imm = Immediate.s(1) },
331 });
332 },
333 .neq => {
334 try lower.emit(.xor, &.{
335 .{ .reg = rd },
336 .{ .reg = rs1 },
337 .{ .reg = rs2 },
338 });
339
340 try lower.emit(.sltu, &.{
341 .{ .reg = rd },
342 .{ .reg = .zero },
343 .{ .reg = rd },
344 });
345 },
346 .gt => {
347 try lower.emit(less_than, &.{
348 .{ .reg = rd },
349 .{ .reg = rs2 },
350 .{ .reg = rs1 },
351 });
352 },
353 .gte => {
354 try lower.emit(less_than, &.{
355 .{ .reg = rd },
356 .{ .reg = rs1 },
357 .{ .reg = rs2 },
358 });
359 try lower.emit(.xori, &.{
360 .{ .reg = rd },
361 .{ .reg = rd },
362 .{ .imm = Immediate.s(1) },
363 });
364 },
365 .lt => {
366 try lower.emit(less_than, &.{
367 .{ .reg = rd },
368 .{ .reg = rs1 },
369 .{ .reg = rs2 },
370 });
371 },
372 .lte => {
373 try lower.emit(less_than, &.{
374 .{ .reg = rd },
375 .{ .reg = rs2 },
376 .{ .reg = rs1 },
377 });
378
379 try lower.emit(.xori, &.{
380 .{ .reg = rd },
381 .{ .reg = rd },
382 .{ .imm = Immediate.s(1) },
383 });
384 },
385 },
386 .float => switch (op) {
387 // eq
388 .eq => {
389 try lower.emit(if (size == 64) .feqd else .feqs, &.{
390 .{ .reg = rd },
391 .{ .reg = rs1 },
392 .{ .reg = rs2 },
393 });
394 },
395 // !(eq)
396 .neq => {
397 try lower.emit(if (size == 64) .feqd else .feqs, &.{
398 .{ .reg = rd },
399 .{ .reg = rs1 },
400 .{ .reg = rs2 },
401 });
402 try lower.emit(.xori, &.{
403 .{ .reg = rd },
404 .{ .reg = rd },
405 .{ .imm = Immediate.s(1) },
406 });
407 },
408 .lt => {
409 try lower.emit(if (size == 64) .fltd else .flts, &.{
410 .{ .reg = rd },
411 .{ .reg = rs1 },
412 .{ .reg = rs2 },
413 });
414 },
415 .lte => {
416 try lower.emit(if (size == 64) .fled else .fles, &.{
417 .{ .reg = rd },
418 .{ .reg = rs1 },
419 .{ .reg = rs2 },
420 });
421 },
422 .gt => {
423 try lower.emit(if (size == 64) .fltd else .flts, &.{
424 .{ .reg = rd },
425 .{ .reg = rs2 },
426 .{ .reg = rs1 },
427 });
428 },
429 .gte => {
430 try lower.emit(if (size == 64) .fled else .fles, &.{
431 .{ .reg = rd },
432 .{ .reg = rs2 },
433 .{ .reg = rs1 },
434 });
435 },
436 },
437 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),
438 }
439 },
440
441 .pseudo_not => {
442 const rr = inst.data.rr;
443 assert(rr.rs.class() == .int and rr.rd.class() == .int);
444
445 // mask out any other bits that aren't the boolean
446 try lower.emit(.andi, &.{
447 .{ .reg = rr.rs },
448 .{ .reg = rr.rs },
449 .{ .imm = Immediate.s(1) },
450 });
451
452 try lower.emit(.sltiu, &.{
453 .{ .reg = rr.rd },
454 .{ .reg = rr.rs },
455 .{ .imm = Immediate.s(1) },
456 });
457 },
458
459 .pseudo_extern_fn_reloc => {
460 const inst_reloc = inst.data.reloc;
461 const link_reg = inst_reloc.register;
462
463 try lower.emit(.auipc, &.{
464 .{ .reg = link_reg },
465 .{ .imm = lower.reloc(
466 .{ .call_extern_fn_reloc = .{
467 .atom_index = inst_reloc.atom_index,
468 .sym_index = inst_reloc.sym_index,
469 } },
470 ) },
471 });
472
473 try lower.emit(.jalr, &.{
474 .{ .reg = link_reg },
475 .{ .reg = link_reg },
476 .{ .imm = Immediate.s(0) },
477 });
511478 },
512479 }
513480
......@@ -518,49 +485,57 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
518485}
519486
520487fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
521 const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse {
522 return lower.fail("generic inst name '{s}' with op {s} doesn't match with a mnemonic", .{
523 @tagName(inst.tag),
524 @tagName(inst.ops),
525 });
526 };
527 try lower.emit(mnemonic, switch (inst.ops) {
488 const mnemonic = inst.tag;
489 try lower.emit(mnemonic, switch (inst.data) {
528490 .none => &.{},
529 .ri => &.{
530 .{ .reg = inst.data.u_type.rd },
531 .{ .imm = inst.data.u_type.imm20 },
491 .u_type => |u| &.{
492 .{ .reg = u.rd },
493 .{ .imm = u.imm20 },
494 },
495 .i_type => |i| &.{
496 .{ .reg = i.rd },
497 .{ .reg = i.rs1 },
498 .{ .imm = i.imm12 },
499 },
500 .rr => |rr| &.{
501 .{ .reg = rr.rd },
502 .{ .reg = rr.rs },
532503 },
533 .rr => &.{
534 .{ .reg = inst.data.rr.rd },
535 .{ .reg = inst.data.rr.rs },
504 .b_type => |b| &.{
505 .{ .reg = b.rs1 },
506 .{ .reg = b.rs2 },
507 .{ .imm = lower.reloc(.{ .inst = b.inst }) },
536508 },
537 .rri => &.{
538 .{ .reg = inst.data.i_type.rd },
539 .{ .reg = inst.data.i_type.rs1 },
540 .{ .imm = inst.data.i_type.imm12 },
509 .r_type => |r| &.{
510 .{ .reg = r.rd },
511 .{ .reg = r.rs1 },
512 .{ .reg = r.rs2 },
541513 },
542 .rr_inst => &.{
543 .{ .reg = inst.data.b_type.rs1 },
544 .{ .reg = inst.data.b_type.rs2 },
545 .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },
514 .csr => |csr| &.{
515 .{ .csr = csr.csr },
516 .{ .reg = csr.rs1 },
517 .{ .reg = csr.rd },
546518 },
547 .rrr => &.{
548 .{ .reg = inst.data.r_type.rd },
549 .{ .reg = inst.data.r_type.rs1 },
550 .{ .reg = inst.data.r_type.rs2 },
519 .amo => |amo| &.{
520 .{ .reg = amo.rd },
521 .{ .reg = amo.rs1 },
522 .{ .reg = amo.rs2 },
523 .{ .barrier = amo.rl },
524 .{ .barrier = amo.aq },
551525 },
552 .csr => &.{
553 .{ .csr = inst.data.csr.csr },
554 .{ .reg = inst.data.csr.rs1 },
555 .{ .reg = inst.data.csr.rd },
526 .fence => |fence| &.{
527 .{ .barrier = fence.succ },
528 .{ .barrier = fence.pred },
556529 },
557 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
530 else => return lower.fail("TODO: generic lower {s}", .{@tagName(inst.data)}),
558531 });
559532}
560533
561fn emit(lower: *Lower, mnemonic: Encoding.Mnemonic, ops: []const Instruction.Operand) !void {
562 lower.result_insts[lower.result_insts_len] =
563 try Instruction.new(mnemonic, ops);
534fn emit(lower: *Lower, mnemonic: Mnemonic, ops: []const Instruction.Operand) !void {
535 const lir = encoding.Lir.fromMnem(mnemonic);
536 const inst = Instruction.fromLir(lir, ops);
537
538 lower.result_insts[lower.result_insts_len] = inst;
564539 lower.result_insts_len += 1;
565540}
566541
......@@ -582,7 +557,7 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
582557 const reg = abi.Registers.all_preserved[i];
583558
584559 const reg_class = reg.class();
585 const load_inst: Encoding.Mnemonic, const store_inst: Encoding.Mnemonic = switch (reg_class) {
560 const load_inst: Mnemonic, const store_inst: Mnemonic = switch (reg_class) {
586561 .int => .{ .ld, .sd },
587562 .float => .{ .fld, .fsd },
588563 .vector => unreachable,
......@@ -620,20 +595,22 @@ fn hasFeature(lower: *Lower, feature: std.Target.riscv.Feature) bool {
620595}
621596
622597const Lower = @This();
623
624const abi = @import("abi.zig");
625const assert = std.debug.assert;
626const bits = @import("bits.zig");
627const encoder = @import("encoder.zig");
628const link = @import("../../link.zig");
629const Encoding = @import("Encoding.zig");
630598const std = @import("std");
599const assert = std.debug.assert;
631600const log = std.log.scoped(.lower);
632601
633const Air = @import("../../Air.zig");
634602const Allocator = std.mem.Allocator;
635603const ErrorMsg = Zcu.ErrorMsg;
636const Mir = @import("Mir.zig");
604
605const link = @import("../../link.zig");
606const Air = @import("../../Air.zig");
637607const Zcu = @import("../../Zcu.zig");
638const Instruction = encoder.Instruction;
608
609const Mir = @import("Mir.zig");
610const abi = @import("abi.zig");
611const bits = @import("bits.zig");
612const encoding = @import("encoding.zig");
613
614const Mnemonic = @import("mnem.zig").Mnemonic;
639615const Immediate = bits.Immediate;
616const Instruction = encoding.Instruction;
src/arch/riscv64/Mir.zig+19-281
......@@ -1,164 +1,17 @@
11//! Machine Intermediate Representation.
2//! This data is produced by RISCV64 Codegen or RISCV64 assembly parsing
3//! These instructions have a 1:1 correspondence with machine code instructions
4//! for the target. MIR can be lowered to source-annotated textual assembly code
5//! instructions, or it can be lowered to machine code.
6//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
7//! so that, for example, the smaller encodings of jump instructions can be used.
2//! This data is produced by CodeGen.zig
83
94instructions: std.MultiArrayList(Inst).Slice,
10/// The meaning of this data is determined by `Inst.Tag` value.
11extra: []const u32,
125frame_locs: std.MultiArrayList(FrameLoc).Slice,
136
147pub const Inst = struct {
15 tag: Tag,
8 tag: Mnemonic,
169 data: Data,
17 ops: Ops,
1810
19 /// The position of an MIR instruction within the `Mir` instructions array.
2011 pub const Index = u32;
2112
22 pub const Tag = enum(u16) {
23
24 // base extension
25 addi,
26 addiw,
27
28 jalr,
29 lui,
30
31 @"and",
32 andi,
33
34 xori,
35 xor,
36 @"or",
37
38 ebreak,
39 ecall,
40 unimp,
41
42 add,
43 addw,
44 sub,
45 subw,
46
47 sltu,
48 slt,
49
50 slli,
51 srli,
52 srai,
53
54 slliw,
55 srliw,
56 sraiw,
57
58 sll,
59 srl,
60 sra,
61
62 sllw,
63 srlw,
64 sraw,
65
66 jal,
67
68 beq,
69 bne,
70
71 nop,
72
73 ld,
74 lw,
75 lh,
76 lb,
77
78 sd,
79 sw,
80 sh,
81 sb,
82
83 // M extension
84 mul,
85 mulw,
86
87 div,
88 divu,
89 divw,
90 divuw,
91
92 rem,
93 remu,
94 remw,
95 remuw,
96
97 // F extension (32-bit float)
98 fadds,
99 fsubs,
100 fmuls,
101 fdivs,
102
103 fabss,
104
105 fmins,
106 fmaxs,
107
108 fsqrts,
109
110 flw,
111 fsw,
112
113 feqs,
114 flts,
115 fles,
116
117 // D extension (64-bit float)
118 faddd,
119 fsubd,
120 fmuld,
121 fdivd,
122
123 fabsd,
124
125 fmind,
126 fmaxd,
127
128 fsqrtd,
129
130 fld,
131 fsd,
132
133 feqd,
134 fltd,
135 fled,
136
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
150 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
151 /// assembly instruction.
152 pseudo,
153 };
154
155 /// All instructions have a 4-byte payload, which is contained within
156 /// this union. `Ops` determines which union field is active, as well as
157 /// how to interpret the data within.
158 pub const Data = union {
159 nop: void,
160 inst: Index,
161 payload: u32,
13 pub const Data = union(enum) {
14 none: void,
16215 r_type: struct {
16316 rd: Register,
16417 rs1: Register,
......@@ -188,10 +41,6 @@ pub const Inst = struct {
18841 rd: Register,
18942 inst: Inst.Index,
19043 },
191 pseudo_dbg_line_column: struct {
192 line: u32,
193 column: u32,
194 },
19544 rm: struct {
19645 r: Register,
19746 m: Memory,
......@@ -202,11 +51,6 @@ pub const Inst = struct {
20251 rd: Register,
20352 rs: Register,
20453 },
205 fabs: struct {
206 rd: Register,
207 rs: Register,
208 bits: u16,
209 },
21054 compare: struct {
21155 rd: Register,
21256 rs1: Register,
......@@ -222,16 +66,13 @@ pub const Inst = struct {
22266 ty: Type,
22367 },
22468 reloc: struct {
69 register: Register,
22570 atom_index: u32,
22671 sym_index: u32,
22772 },
22873 fence: struct {
22974 pred: Barrier,
23075 succ: Barrier,
231 fm: enum {
232 none,
233 tso,
234 },
23576 },
23677 amo: struct {
23778 rd: Register,
......@@ -239,123 +80,32 @@ pub const Inst = struct {
23980 rs2: Register,
24081 aq: Barrier,
24182 rl: Barrier,
242 op: AmoOp,
243 ty: Type,
24483 },
24584 csr: struct {
24685 csr: CSR,
24786 rs1: Register,
24887 rd: Register,
24988 },
250 };
251
252 pub const Ops = enum {
253 /// No data associated with this instruction (only mnemonic is used).
254 none,
255 /// Two registers
256 rr,
257 /// Three registers
258 rrr,
259
260 /// Two registers + immediate, uses the i_type payload.
261 rri,
262 //extern_fn_reloc/ Two registers + another instruction.
263 rr_inst,
264
265 /// Register + Memory
266 rm,
267
268 /// Register + Immediate
269 ri,
270
271 /// Another instruction.
272 inst,
273
274 /// Control and Status Register Instruction.
275 csr,
276
277 /// Pseudo-instruction that will generate a backpatched
278 /// function prologue.
279 pseudo_prologue,
280 /// Pseudo-instruction that will generate a backpatched
281 /// function epilogue
282 pseudo_epilogue,
283
284 /// Pseudo-instruction: End of prologue
285 pseudo_dbg_prologue_end,
286 /// Pseudo-instruction: Beginning of epilogue
287 pseudo_dbg_epilogue_begin,
288 /// Pseudo-instruction: Update debug line
289 pseudo_dbg_line_column,
290
291 /// Pseudo-instruction that loads from memory into a register.
292 ///
293 /// Uses `rm` payload.
294 pseudo_load_rm,
295 /// Pseudo-instruction that stores from a register into memory
296 ///
297 /// Uses `rm` payload.
298 pseudo_store_rm,
299
300 /// Pseudo-instruction that loads the address of memory into a register.
301 ///
302 /// Uses `rm` payload.
303 pseudo_lea_rm,
304
305 /// Jumps. Uses `inst` payload.
306 pseudo_j,
307
308 /// Floating point absolute value.
309 pseudo_fabs,
310
311 /// Dead inst, ignored by the emitter.
312 pseudo_dead,
313
314 /// Loads the address of a value that hasn't yet been allocated in memory.
315 ///
316 /// uses the Mir.LoadSymbolPayload payload.
317 pseudo_load_symbol,
318
319 /// Moves the value of rs1 to rd.
320 ///
321 /// uses the `rr` payload.
322 pseudo_mv,
323
324 pseudo_restore_regs,
325 pseudo_spill_regs,
326
327 pseudo_compare,
328
329 /// NOT operation on booleans. Does an `andi reg, reg, 1` to mask out any other bits from the boolean.
330 pseudo_not,
331
332 /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc
333 pseudo_extern_fn_reloc,
334
335 /// IORW, IORW
336 pseudo_fence,
337
338 /// Ordering, Src, Addr, Dest
339 pseudo_amo,
89 pseudo_dbg_line_column: struct {
90 line: u32,
91 column: u32,
92 },
34093 };
34194
34295 pub fn format(
34396 inst: Inst,
34497 comptime fmt: []const u8,
345 options: std.fmt.FormatOptions,
98 _: std.fmt.FormatOptions,
34699 writer: anytype,
347100 ) !void {
348101 assert(fmt.len == 0);
349 _ = options;
350
351 try writer.print("Tag: {s}, Ops: {s}", .{ @tagName(inst.tag), @tagName(inst.ops) });
102 try writer.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) });
352103 }
353104};
354105
355106pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
356107 mir.instructions.deinit(gpa);
357108 mir.frame_locs.deinit(gpa);
358 gpa.free(mir.extra);
359109 mir.* = undefined;
360110}
361111
......@@ -386,25 +136,12 @@ pub const AmoOp = enum(u5) {
386136 MIN,
387137};
388138
389/// Returns the requested data, as well as the new index which is at the start of the
390/// trailers for the object.
391pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
392 const fields = std.meta.fields(T);
393 var i: usize = index;
394 var result: T = undefined;
395 inline for (fields) |field| {
396 @field(result, field.name) = switch (field.type) {
397 u32 => mir.extra[i],
398 i32 => @as(i32, @bitCast(mir.extra[i])),
399 else => @compileError("bad field type"),
400 };
401 i += 1;
402 }
403 return .{
404 .data = result,
405 .end = i,
406 };
407}
139pub const FcvtOp = enum(u5) {
140 w = 0b00000,
141 wu = 0b00001,
142 l = 0b00010,
143 lu = 0b00011,
144};
408145
409146pub const LoadSymbolPayload = struct {
410147 register: u32,
......@@ -453,10 +190,10 @@ const Mir = @This();
453190const std = @import("std");
454191const builtin = @import("builtin");
455192const Type = @import("../../Type.zig");
193const bits = @import("bits.zig");
456194
457195const assert = std.debug.assert;
458196
459const bits = @import("bits.zig");
460197const Register = bits.Register;
461198const CSR = bits.CSR;
462199const Immediate = bits.Immediate;
......@@ -464,3 +201,4 @@ const Memory = bits.Memory;
464201const FrameIndex = bits.FrameIndex;
465202const FrameAddr = @import("CodeGen.zig").FrameAddr;
466203const IntegerBitSet = std.bit_set.IntegerBitSet;
204const Mnemonic = @import("mnem.zig").Mnemonic;
src/arch/riscv64/abi.zig+4-5
......@@ -125,10 +125,7 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass {
125125 result[0] = .integer;
126126 return result;
127127 }
128 result[0] = .integer;
129 if (ty.optionalChild(zcu).abiSize(pt) == 0) return result;
130 result[1] = .integer;
131 return result;
128 return memory_class;
132129 },
133130 .Int, .Enum, .ErrorSet => {
134131 const int_bits = ty.intInfo(pt.zcu).bits;
......@@ -167,7 +164,7 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass {
167164
168165 return memory_class;
169166 },
170 .Struct => {
167 .Struct, .Union => {
171168 const layout = ty.containerLayout(pt.zcu);
172169 const ty_size = ty.abiSize(pt);
173170
......@@ -200,6 +197,8 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass {
200197 result[0] = .integer;
201198 return result;
202199 }
200 // we should pass vector registers of size <= 128 through 2 integer registers
201 // but we haven't implemented seperating vector registers into register_pairs
203202 return memory_class;
204203 },
205204 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
src/arch/riscv64/bits.zig+2-6
......@@ -5,7 +5,6 @@ const testing = std.testing;
55const Target = std.Target;
66
77const Zcu = @import("../../Zcu.zig");
8const Encoding = @import("Encoding.zig");
98const Mir = @import("Mir.zig");
109const abi = @import("abi.zig");
1110
......@@ -16,7 +15,6 @@ pub const Memory = struct {
1615 pub const Base = union(enum) {
1716 reg: Register,
1817 frame: FrameIndex,
19 reloc: Symbol,
2018 };
2119
2220 pub const Mod = struct {
......@@ -83,7 +81,6 @@ pub const Memory = struct {
8381 .disp = base_loc.disp + offset,
8482 };
8583 },
86 .reloc => unreachable,
8784 }
8885 }
8986};
......@@ -193,7 +190,7 @@ pub const Register = enum(u8) {
193190 /// The goal of this function is to return the same ID for `zero` and `x0` but two
194191 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers
195192 /// and is repeated twice, once for the named version, once for the number version.
196 pub fn id(reg: Register) u8 {
193 pub fn id(reg: Register) std.math.IntFittingRange(0, @typeInfo(Register).Enum.fields.len) {
197194 const base = switch (@intFromEnum(reg)) {
198195 // zig fmt: off
199196 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),
......@@ -251,8 +248,7 @@ pub const FrameIndex = enum(u32) {
251248 /// This index referes to a frame dedicated to setting up args for function called
252249 /// in this function. Useful for aligning args separately.
253250 call_frame,
254 /// This index referes to the frame where callee saved registers are spilled and restore
255 /// from.
251 /// This index referes to the frame where callee saved registers are spilled and restored from.
256252 spill_frame,
257253 /// Other indices are used for local variable stack slots
258254 _,
src/arch/riscv64/encoder.zig deleted-80
......@@ -1,80 +0,0 @@
1pub const Instruction = struct {
2 encoding: Encoding,
3 ops: [5]Operand = .{.none} ** 5,
4
5 pub const Operand = union(enum) {
6 none,
7 reg: Register,
8 csr: CSR,
9 mem: Memory,
10 imm: Immediate,
11 barrier: Mir.Barrier,
12 };
13
14 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
15 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {
16 std.log.err("no encoding found for: {s} [{s} {s} {s} {s} {s}]", .{
17 @tagName(mnemonic),
18 @tagName(if (ops.len > 0) ops[0] else .none),
19 @tagName(if (ops.len > 1) ops[1] 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),
23 });
24 return error.InvalidInstruction;
25 };
26
27 var result_ops: [5]Operand = .{.none} ** 5;
28 @memcpy(result_ops[0..ops.len], ops);
29
30 return .{
31 .encoding = encoding,
32 .ops = result_ops,
33 };
34 }
35
36 pub fn encode(inst: Instruction, writer: anytype) !void {
37 try writer.writeInt(u32, inst.encoding.data.toU32(), .little);
38 }
39
40 pub fn format(
41 inst: Instruction,
42 comptime fmt: []const u8,
43 _: std.fmt.FormatOptions,
44 writer: anytype,
45 ) !void {
46 std.debug.assert(fmt.len == 0);
47
48 const encoding = inst.encoding;
49
50 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
51
52 var i: u32 = 0;
53 while (i < inst.ops.len and inst.ops[i] != .none) : (i += 1) {
54 if (i != inst.ops.len and i != 0) try writer.writeAll(", ");
55
56 switch (@as(Instruction.Operand, inst.ops[i])) {
57 .none => unreachable, // it's sliced out above
58 .reg => |reg| try writer.writeAll(@tagName(reg)),
59 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
60 .mem => try writer.writeAll("mem"),
61 .barrier => |barrier| try writer.writeAll(@tagName(barrier)),
62 .csr => |csr| try writer.writeAll(@tagName(csr)),
63 }
64 }
65 }
66};
67
68const std = @import("std");
69
70const Lower = @import("Lower.zig");
71const Mir = @import("Mir.zig");
72const bits = @import("bits.zig");
73const Encoding = @import("Encoding.zig");
74
75const Register = bits.Register;
76const CSR = bits.CSR;
77const Memory = bits.Memory;
78const Immediate = bits.Immediate;
79
80const log = std.log.scoped(.encode);
src/arch/riscv64/encoding.zig created+729
......@@ -0,0 +1,729 @@
1//! This file is responsible for going from MIR, which is emitted by CodeGen
2//! and converting it into Instructions, which can be used as needed.
3//!
4//! Here we encode how mnemonics relate to opcodes and where their operands go.
5
6/// Lower Instruction Representation
7///
8/// This format encodes a specific instruction, however it's still abstracted
9/// away from the true encoding it'll be in. It's meant to make the process of
10/// indicating unique encoding data easier.
11pub const Lir = struct {
12 opcode: OpCode,
13 format: Format,
14 data: Data,
15
16 pub const Format = enum {
17 R,
18 I,
19 S,
20 B,
21 U,
22 J,
23 extra,
24 };
25
26 const Data = union(enum) {
27 none,
28 f: struct { funct3: u3 },
29 ff: struct {
30 funct3: u3,
31 funct7: u7,
32 },
33 sh: struct {
34 typ: u6,
35 funct3: u3,
36 has_5: bool,
37 },
38
39 fmt: struct {
40 funct5: u5,
41 rm: u3,
42 fmt: FpFmt,
43 },
44 fcvt: struct {
45 funct5: u5,
46 rm: u3,
47 fmt: FpFmt,
48 width: Mir.FcvtOp,
49 },
50
51 vecls: struct {
52 width: VecWidth,
53 umop: Umop,
54 vm: bool,
55 mop: Mop,
56 mew: bool,
57 nf: u3,
58 },
59 vecmath: struct {
60 vm: bool,
61 funct6: u6,
62 funct3: VecType,
63 },
64
65 amo: struct {
66 funct5: u5,
67 width: AmoWidth,
68 },
69 fence: struct {
70 funct3: u3,
71 fm: FenceMode,
72 },
73
74 /// the mnemonic has some special properities that can't be handled in a generic fashion
75 extra: Mnemonic,
76 };
77
78 const OpCode = enum(u7) {
79 LOAD = 0b0000011,
80 LOAD_FP = 0b0000111,
81 MISC_MEM = 0b0001111,
82 OP_IMM = 0b0010011,
83 AUIPC = 0b0010111,
84 OP_IMM_32 = 0b0011011,
85 STORE = 0b0100011,
86 STORE_FP = 0b0100111,
87 AMO = 0b0101111,
88 OP_V = 0b1010111,
89 OP = 0b0110011,
90 OP_32 = 0b0111011,
91 LUI = 0b0110111,
92 MADD = 0b1000011,
93 MSUB = 0b1000111,
94 NMSUB = 0b1001011,
95 NMADD = 0b1001111,
96 OP_FP = 0b1010011,
97 OP_IMM_64 = 0b1011011,
98 BRANCH = 0b1100011,
99 JALR = 0b1100111,
100 JAL = 0b1101111,
101 SYSTEM = 0b1110011,
102 OP_64 = 0b1111011,
103 NONE = 0b00000000,
104 };
105
106 const FpFmt = enum(u2) {
107 /// 32-bit single-precision
108 S = 0b00,
109 /// 64-bit double-precision
110 D = 0b01,
111
112 // H = 0b10, unused in the G extension
113
114 /// 128-bit quad-precision
115 Q = 0b11,
116 };
117
118 const AmoWidth = enum(u3) {
119 W = 0b010,
120 D = 0b011,
121 };
122
123 const FenceMode = enum(u4) {
124 none = 0b0000,
125 tso = 0b1000,
126 };
127
128 const Mop = enum(u2) {
129 // zig fmt: off
130 unit = 0b00,
131 unord = 0b01,
132 stride = 0b10,
133 ord = 0b11,
134 // zig fmt: on
135 };
136
137 const Umop = enum(u5) {
138 // zig fmt: off
139 unit = 0b00000,
140 whole = 0b01000,
141 mask = 0b01011,
142 fault = 0b10000,
143 // zig fmt: on
144 };
145
146 const VecWidth = enum(u3) {
147 // zig fmt: off
148 @"8" = 0b000,
149 @"16" = 0b101,
150 @"32" = 0b110,
151 @"64" = 0b111,
152 // zig fmt: on
153 };
154
155 const VecType = enum(u3) {
156 OPIVV = 0b000,
157 OPFVV = 0b001,
158 OPMVV = 0b010,
159 OPIVI = 0b011,
160 OPIVX = 0b100,
161 OPFVF = 0b101,
162 OPMVX = 0b110,
163 };
164
165 pub fn fromMnem(mnem: Mnemonic) Lir {
166 return switch (mnem) {
167 // zig fmt: off
168
169 // OP
170 .add => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
171 .sub => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
172
173 .@"and" => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
174 .@"or" => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
175 .xor => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
176
177 .sltu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
178 .slt => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
179
180 .mul => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
181 .mulh => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000001 } } },
182 .mulhsu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000001 } } },
183 .mulhu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000001 } } },
184
185 .div => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
186 .divu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
187
188 .rem => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
189 .remu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
190
191 .sll => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
192 .srl => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
193 .sra => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
194
195
196 // OP_IMM
197
198 .addi => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } },
199 .andi => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b111 } } },
200 .xori => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b100 } } },
201
202 .sltiu => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b011 } } },
203
204 .slli => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = true } } },
205 .srli => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
206 .srai => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
207
208 .clz => .{ .opcode = .OP_IMM, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
209 .cpop => .{ .opcode = .OP_IMM, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
210
211 // OP_IMM_32
212
213 .slliw => .{ .opcode = .OP_IMM_32, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = false } } },
214 .srliw => .{ .opcode = .OP_IMM_32, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
215 .sraiw => .{ .opcode = .OP_IMM_32, .format = .I, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
216
217 .clzw => .{ .opcode = .OP_IMM_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
218 .cpopw => .{ .opcode = .OP_IMM_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
219
220 // OP_32
221
222 .addw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
223 .subw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
224 .mulw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
225
226 .divw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
227 .divuw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
228
229 .remw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
230 .remuw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
231
232 .sllw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
233 .srlw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
234 .sraw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
235
236
237 // OP_FP
238
239 .fadds => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
240 .faddd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
241
242 .fsubs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .S, .rm = 0b111 } } },
243 .fsubd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .D, .rm = 0b111 } } },
244
245 .fmuls => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .S, .rm = 0b111 } } },
246 .fmuld => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .D, .rm = 0b111 } } },
247
248 .fdivs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .S, .rm = 0b111 } } },
249 .fdivd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .D, .rm = 0b111 } } },
250
251 .fmins => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b000 } } },
252 .fmind => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b000 } } },
253
254 .fmaxs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b001 } } },
255 .fmaxd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b001 } } },
256
257 .fsqrts => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .S, .rm = 0b111 } } },
258 .fsqrtd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .D, .rm = 0b111 } } },
259
260 .fles => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b000 } } },
261 .fled => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b000 } } },
262
263 .flts => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b001 } } },
264 .fltd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b001 } } },
265
266 .feqs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
267 .feqd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
268
269 .fsgnjns => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
270 .fsgnjnd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
271
272 .fsgnjxs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b010 } } },
273 .fsgnjxd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b010 } } },
274
275 .fcvtws => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .w } } },
276 .fcvtwus => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .wu } } },
277 .fcvtls => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .l } } },
278 .fcvtlus => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .lu } } },
279
280 .fcvtwd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .w } } },
281 .fcvtwud => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .wu } } },
282 .fcvtld => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .l } } },
283 .fcvtlud => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .lu } } },
284
285 .fcvtsw => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .w } } },
286 .fcvtswu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .wu } } },
287 .fcvtsl => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .l } } },
288 .fcvtslu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .S, .rm = 0b111, .width = .lu } } },
289
290 .fcvtdw => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .w } } },
291 .fcvtdwu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .wu } } },
292 .fcvtdl => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .l } } },
293 .fcvtdlu => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11010, .fmt = .D, .rm = 0b111, .width = .lu } } },
294
295 // LOAD
296
297 .lb => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } },
298 .lh => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b001 } } },
299 .lw => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b010 } } },
300 .ld => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b011 } } },
301 .lbu => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b100 } } },
302 .lhu => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b101 } } },
303 .lwu => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b110 } } },
304
305
306 // STORE
307
308 .sb => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b000 } } },
309 .sh => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b001 } } },
310 .sw => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b010 } } },
311 .sd => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b011 } } },
312
313
314 // LOAD_FP
315
316 .flw => .{ .opcode = .LOAD_FP, .format = .I, .data = .{ .f = .{ .funct3 = 0b010 } } },
317 .fld => .{ .opcode = .LOAD_FP, .format = .I, .data = .{ .f = .{ .funct3 = 0b011 } } },
318
319 .vle8v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
320 .vle16v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
321 .vle32v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
322 .vle64v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
323
324
325 // STORE_FP
326
327 .fsw => .{ .opcode = .STORE_FP, .format = .S, .data = .{ .f = .{ .funct3 = 0b010 } } },
328 .fsd => .{ .opcode = .STORE_FP, .format = .S, .data = .{ .f = .{ .funct3 = 0b011 } } },
329
330 .vse8v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
331 .vse16v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
332 .vse32v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
333 .vse64v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
334
335 // JALR
336
337 .jalr => .{ .opcode = .JALR, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } },
338
339
340 // LUI
341
342 .lui => .{ .opcode = .LUI, .format = .U, .data = .{ .none = {} } },
343
344
345 // AUIPC
346
347 .auipc => .{ .opcode = .AUIPC, .format = .U, .data = .{ .none = {} } },
348
349
350 // JAL
351
352 .jal => .{ .opcode = .JAL, .format = .J, .data = .{ .none = {} } },
353
354
355 // BRANCH
356
357 .beq => .{ .opcode = .BRANCH, .format = .B, .data = .{ .f = .{ .funct3 = 0b000 } } },
358 .bne => .{ .opcode = .BRANCH, .format = .B, .data = .{ .f = .{ .funct3 = 0b001 } } },
359
360
361 // SYSTEM
362
363 .ecall => .{ .opcode = .SYSTEM, .format = .extra, .data = .{ .extra = .ecall } },
364 .ebreak => .{ .opcode = .SYSTEM, .format = .extra, .data = .{ .extra = .ebreak } },
365
366 .csrrs => .{ .opcode = .SYSTEM, .format = .I, .data = .{ .f = .{ .funct3 = 0b010 } } },
367
368
369 // NONE
370
371 .unimp => .{ .opcode = .NONE, .format = .extra, .data = .{ .extra = .unimp } },
372
373
374 // MISC_MEM
375
376 .fence => .{ .opcode = .MISC_MEM, .format = .I, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } },
377 .fencetso => .{ .opcode = .MISC_MEM, .format = .I, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } },
378
379
380 // AMO
381
382 .amoaddw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } },
383 .amoswapw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } },
384 .lrw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00010 } } },
385 .scw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00011 } } },
386 .amoxorw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } },
387 .amoandw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } },
388 .amoorw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } },
389 .amominw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } },
390 .amomaxw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } },
391 .amominuw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } },
392 .amomaxuw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } },
393
394
395 .amoaddd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } },
396 .amoswapd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } },
397 .lrd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00010 } } },
398 .scd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00011 } } },
399 .amoxord => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } },
400 .amoandd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } },
401 .amoord => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } },
402 .amomind => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } },
403 .amomaxd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } },
404 .amominud => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
405 .amomaxud => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
406
407 // OP_V
408 .vsetivli => .{ .opcode = .OP_V, .format = .I, .data = .{ .f = .{ .funct3 = 0b111 } } },
409 .vsetvli => .{ .opcode = .OP_V, .format = .I, .data = .{ .f = .{ .funct3 = 0b111 } } },
410 .vaddvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
411 .vsubvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },
412 .vmulvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b100101, .funct3 = .OPIVV } } },
413
414 .vfaddvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPFVV } } },
415 .vfsubvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPFVV } } },
416 .vfmulvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b100100, .funct3 = .OPFVV } } },
417
418 .vadcvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
419 .vmvvx => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },
420
421 .vslidedownvx => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b001111, .funct3 = .OPIVX } } },
422
423
424 .pseudo_prologue,
425 .pseudo_epilogue,
426 .pseudo_dbg_prologue_end,
427 .pseudo_dbg_epilogue_begin,
428 .pseudo_dbg_line_column,
429 .pseudo_load_rm,
430 .pseudo_store_rm,
431 .pseudo_lea_rm,
432 .pseudo_j,
433 .pseudo_dead,
434 .pseudo_load_symbol,
435 .pseudo_load_tlv,
436 .pseudo_mv,
437 .pseudo_restore_regs,
438 .pseudo_spill_regs,
439 .pseudo_compare,
440 .pseudo_not,
441 .pseudo_extern_fn_reloc,
442 .nop,
443 => std.debug.panic("lir: didn't catch pseudo {s}", .{@tagName(mnem)}),
444 // zig fmt: on
445 };
446 }
447};
448
449/// This is the final form of the instruction. Lir is transformed into
450/// this, which is then bitcast into a u32.
451pub const Instruction = union(Lir.Format) {
452 R: packed struct(u32) {
453 opcode: u7,
454 rd: u5,
455 funct3: u3,
456 rs1: u5,
457 rs2: u5,
458 funct7: u7,
459 },
460 I: packed struct(u32) {
461 opcode: u7,
462 rd: u5,
463 funct3: u3,
464 rs1: u5,
465 imm0_11: u12,
466 },
467 S: packed struct(u32) {
468 opcode: u7,
469 imm0_4: u5,
470 funct3: u3,
471 rs1: u5,
472 rs2: u5,
473 imm5_11: u7,
474 },
475 B: packed struct(u32) {
476 opcode: u7,
477 imm11: u1,
478 imm1_4: u4,
479 funct3: u3,
480 rs1: u5,
481 rs2: u5,
482 imm5_10: u6,
483 imm12: u1,
484 },
485 U: packed struct(u32) {
486 opcode: u7,
487 rd: u5,
488 imm12_31: u20,
489 },
490 J: packed struct(u32) {
491 opcode: u7,
492 rd: u5,
493 imm12_19: u8,
494 imm11: u1,
495 imm1_10: u10,
496 imm20: u1,
497 },
498 extra: u32,
499
500 comptime {
501 for (std.meta.fields(Instruction)) |field| {
502 assert(@bitSizeOf(field.type) == 32);
503 }
504 }
505
506 pub const Operand = union(enum) {
507 none,
508 reg: Register,
509 csr: CSR,
510 mem: Memory,
511 imm: Immediate,
512 barrier: Mir.Barrier,
513 };
514
515 pub fn toU32(inst: Instruction) u32 {
516 return switch (inst) {
517 inline else => |v| @bitCast(v),
518 };
519 }
520
521 pub fn encode(inst: Instruction, writer: anytype) !void {
522 try writer.writeInt(u32, inst.toU32(), .little);
523 }
524
525 pub fn fromLir(lir: Lir, ops: []const Operand) Instruction {
526 const opcode: u7 = @intFromEnum(lir.opcode);
527
528 switch (lir.format) {
529 .R => {
530 return .{
531 .R = switch (lir.data) {
532 .ff => |ff| .{
533 .rd = ops[0].reg.encodeId(),
534 .rs1 = ops[1].reg.encodeId(),
535 .rs2 = ops[2].reg.encodeId(),
536
537 .opcode = opcode,
538 .funct3 = ff.funct3,
539 .funct7 = ff.funct7,
540 },
541 .fmt => |fmt| .{
542 .rd = ops[0].reg.encodeId(),
543 .rs1 = ops[1].reg.encodeId(),
544 .rs2 = ops[2].reg.encodeId(),
545
546 .opcode = opcode,
547 .funct3 = fmt.rm,
548 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
549 },
550 .fcvt => |fcvt| .{
551 .rd = ops[0].reg.encodeId(),
552 .rs1 = ops[1].reg.encodeId(),
553 .rs2 = @intFromEnum(fcvt.width),
554
555 .opcode = opcode,
556 .funct3 = fcvt.rm,
557 .funct7 = (@as(u7, fcvt.funct5) << 2) | @intFromEnum(fcvt.fmt),
558 },
559 .vecls => |vec| .{
560 .rd = ops[0].reg.encodeId(),
561 .rs1 = ops[1].reg.encodeId(),
562
563 .rs2 = @intFromEnum(vec.umop),
564
565 .opcode = opcode,
566 .funct3 = @intFromEnum(vec.width),
567 .funct7 = (@as(u7, vec.nf) << 4) | (@as(u7, @intFromBool(vec.mew)) << 3) | (@as(u7, @intFromEnum(vec.mop)) << 1) | @intFromBool(vec.vm),
568 },
569 .vecmath => |vec| .{
570 .rd = ops[0].reg.encodeId(),
571 .rs1 = ops[1].reg.encodeId(),
572 .rs2 = ops[2].reg.encodeId(),
573
574 .opcode = opcode,
575 .funct3 = @intFromEnum(vec.funct3),
576 .funct7 = (@as(u7, vec.funct6) << 1) | @intFromBool(vec.vm),
577 },
578 .amo => |amo| .{
579 .rd = ops[0].reg.encodeId(),
580 .rs1 = ops[1].reg.encodeId(),
581 .rs2 = ops[2].reg.encodeId(),
582
583 .opcode = opcode,
584 .funct3 = @intFromEnum(amo.width),
585 .funct7 = @as(u7, amo.funct5) << 2 |
586 @as(u7, @intFromBool(ops[3].barrier == .rl)) << 1 |
587 @as(u7, @intFromBool(ops[4].barrier == .aq)),
588 },
589 else => unreachable,
590 },
591 };
592 },
593 .S => {
594 assert(ops.len == 3);
595 const umm = ops[2].imm.asBits(u12);
596 return .{
597 .S = .{
598 .imm0_4 = @truncate(umm),
599 .rs1 = ops[0].reg.encodeId(),
600 .rs2 = ops[1].reg.encodeId(),
601 .imm5_11 = @truncate(umm >> 5),
602
603 .opcode = opcode,
604 .funct3 = lir.data.f.funct3,
605 },
606 };
607 },
608 .I => {
609 return .{
610 .I = switch (lir.data) {
611 .f => |f| .{
612 .rd = ops[0].reg.encodeId(),
613 .rs1 = ops[1].reg.encodeId(),
614 .imm0_11 = ops[2].imm.asBits(u12),
615
616 .opcode = opcode,
617 .funct3 = f.funct3,
618 },
619 .sh => |sh| .{
620 .rd = ops[0].reg.encodeId(),
621 .rs1 = ops[1].reg.encodeId(),
622 .imm0_11 = (@as(u12, sh.typ) << 6) |
623 if (sh.has_5) ops[2].imm.asBits(u6) else (@as(u6, 0) | ops[2].imm.asBits(u5)),
624
625 .opcode = opcode,
626 .funct3 = sh.funct3,
627 },
628 .fence => |fence| .{
629 .rd = 0,
630 .rs1 = 0,
631 .funct3 = 0,
632 .imm0_11 = (@as(u12, @intFromEnum(fence.fm)) << 8) |
633 (@as(u12, @intFromEnum(ops[1].barrier)) << 4) |
634 @as(u12, @intFromEnum(ops[0].barrier)),
635 .opcode = opcode,
636 },
637 else => unreachable,
638 },
639 };
640 },
641 .U => {
642 assert(ops.len == 2);
643 return .{
644 .U = .{
645 .rd = ops[0].reg.encodeId(),
646 .imm12_31 = ops[1].imm.asBits(u20),
647
648 .opcode = opcode,
649 },
650 };
651 },
652 .J => {
653 assert(ops.len == 2);
654
655 const umm = ops[1].imm.asBits(u21);
656 // the RISC-V spec says the target index of a jump
657 // must be a multiple of 2
658 assert(umm % 2 == 0);
659
660 return .{
661 .J = .{
662 .rd = ops[0].reg.encodeId(),
663 .imm1_10 = @truncate(umm >> 1),
664 .imm11 = @truncate(umm >> 11),
665 .imm12_19 = @truncate(umm >> 12),
666 .imm20 = @truncate(umm >> 20),
667
668 .opcode = opcode,
669 },
670 };
671 },
672 .B => {
673 assert(ops.len == 3);
674
675 const umm = ops[2].imm.asBits(u13);
676 // the RISC-V spec says the target index of a branch
677 // must be a multiple of 2
678 assert(umm % 2 == 0);
679
680 return .{
681 .B = .{
682 .rs1 = ops[0].reg.encodeId(),
683 .rs2 = ops[1].reg.encodeId(),
684 .imm1_4 = @truncate(umm >> 1),
685 .imm5_10 = @truncate(umm >> 5),
686 .imm11 = @truncate(umm >> 11),
687 .imm12 = @truncate(umm >> 12),
688
689 .opcode = opcode,
690 .funct3 = lir.data.f.funct3,
691 },
692 };
693 },
694 .extra => {
695 assert(ops.len == 0);
696
697 return .{
698 .I = .{
699 .rd = Register.zero.encodeId(),
700 .rs1 = Register.zero.encodeId(),
701 .imm0_11 = switch (lir.data.extra) {
702 .ecall => 0x000,
703 .ebreak => 0x001,
704 .unimp => 0x000,
705 else => unreachable,
706 },
707
708 .opcode = opcode,
709 .funct3 = 0b000,
710 },
711 };
712 },
713 }
714 }
715};
716
717const std = @import("std");
718const assert = std.debug.assert;
719const log = std.log.scoped(.format);
720
721const bits = @import("bits.zig");
722const Mir = @import("Mir.zig");
723const Mnemonic = @import("mnem.zig").Mnemonic;
724const Lower = @import("Lower.zig");
725
726const Register = bits.Register;
727const CSR = bits.CSR;
728const Memory = bits.Memory;
729const Immediate = bits.Immediate;
src/arch/riscv64/mnem.zig created+257
......@@ -0,0 +1,257 @@
1pub const Mnemonic = enum(u16) {
2 // Arithmetics
3 addi,
4 add,
5 addw,
6
7 sub,
8 subw,
9
10 // Bits
11 xori,
12 xor,
13 @"or",
14
15 @"and",
16 andi,
17
18 slt,
19 sltu,
20 sltiu,
21
22 slli,
23 srli,
24 srai,
25
26 slliw,
27 srliw,
28 sraiw,
29
30 sll,
31 srl,
32 sra,
33
34 sllw,
35 srlw,
36 sraw,
37
38 // Control Flow
39 jalr,
40 jal,
41
42 beq,
43 bne,
44
45 // Memory
46 lui,
47 auipc,
48
49 ld,
50 lw,
51 lh,
52 lb,
53 lbu,
54 lhu,
55 lwu,
56
57 sd,
58 sw,
59 sh,
60 sb,
61
62 // System
63 ebreak,
64 ecall,
65 unimp,
66 nop,
67
68 // M extension
69 mul,
70 mulh,
71 mulhu,
72 mulhsu,
73 mulw,
74
75 div,
76 divu,
77 divw,
78 divuw,
79
80 rem,
81 remu,
82 remw,
83 remuw,
84
85 // F extension (32-bit float)
86 fadds,
87 fsubs,
88 fmuls,
89 fdivs,
90
91 fmins,
92 fmaxs,
93
94 fsqrts,
95
96 flw,
97 fsw,
98
99 feqs,
100 flts,
101 fles,
102
103 // D extension (64-bit float)
104 faddd,
105 fsubd,
106 fmuld,
107 fdivd,
108
109 fmind,
110 fmaxd,
111
112 fsqrtd,
113
114 fld,
115 fsd,
116
117 feqd,
118 fltd,
119 fled,
120
121 fcvtws,
122 fcvtwus,
123 fcvtls,
124 fcvtlus,
125
126 fcvtwd,
127 fcvtwud,
128 fcvtld,
129 fcvtlud,
130
131 fcvtsw,
132 fcvtswu,
133 fcvtsl,
134 fcvtslu,
135
136 fcvtdw,
137 fcvtdwu,
138 fcvtdl,
139 fcvtdlu,
140
141 fsgnjns,
142 fsgnjnd,
143
144 fsgnjxs,
145 fsgnjxd,
146
147 // Zicsr Extension Instructions
148 csrrs,
149
150 // V Extension Instructions
151 vsetvli,
152 vsetivli,
153 vaddvv,
154 vfaddvv,
155 vsubvv,
156 vfsubvv,
157 vmulvv,
158 vfmulvv,
159 vslidedownvx,
160
161 vle8v,
162 vle16v,
163 vle32v,
164 vle64v,
165
166 vse8v,
167 vse16v,
168 vse32v,
169 vse64v,
170
171 vadcvv,
172 vmvvx,
173
174 // Zbb Extension Instructions
175 clz,
176 clzw,
177 cpop,
178 cpopw,
179
180 // A Extension Instructions
181 fence,
182 fencetso,
183
184 lrw,
185 scw,
186 amoswapw,
187 amoaddw,
188 amoandw,
189 amoorw,
190 amoxorw,
191 amomaxw,
192 amominw,
193 amomaxuw,
194 amominuw,
195
196 lrd,
197 scd,
198 amoswapd,
199 amoaddd,
200 amoandd,
201 amoord,
202 amoxord,
203 amomaxd,
204 amomind,
205 amomaxud,
206 amominud,
207
208 // Pseudo-instructions. Used for anything that isn't 1:1 with an
209 // assembly instruction.
210
211 /// Pseudo-instruction that will generate a backpatched
212 /// function prologue.
213 pseudo_prologue,
214 /// Pseudo-instruction that will generate a backpatched
215 /// function epilogue
216 pseudo_epilogue,
217
218 /// Pseudo-instruction: End of prologue
219 pseudo_dbg_prologue_end,
220 /// Pseudo-instruction: Beginning of epilogue
221 pseudo_dbg_epilogue_begin,
222 /// Pseudo-instruction: Update debug line
223 pseudo_dbg_line_column,
224
225 /// Pseudo-instruction that loads from memory into a register.
226 pseudo_load_rm,
227 /// Pseudo-instruction that stores from a register into memory
228 pseudo_store_rm,
229 /// Pseudo-instruction that loads the address of memory into a register.
230 pseudo_lea_rm,
231 /// Jumps. Uses `inst` payload.
232 pseudo_j,
233 /// Dead inst, ignored by the emitter.
234 pseudo_dead,
235 /// Loads the address of a value that hasn't yet been allocated in memory.
236 pseudo_load_symbol,
237 /// Loads the address of a TLV.
238 pseudo_load_tlv,
239
240 /// Moves the value of rs1 to rd.
241 pseudo_mv,
242
243 pseudo_restore_regs,
244 pseudo_spill_regs,
245
246 pseudo_compare,
247 pseudo_not,
248 pseudo_extern_fn_reloc,
249};
250
251pub const Pseudo = enum(u8) {
252 li,
253 mv,
254 tail,
255 beqz,
256 ret,
257};
src/codegen.zig+3-1
......@@ -106,7 +106,9 @@ pub fn generateLazyFunction(
106106 const target = namespace.fileScope(zcu).mod.resolved_target.result;
107107 switch (target_util.zigBackend(target, false)) {
108108 else => unreachable,
109 inline .stage2_x86_64 => |backend| {
109 inline .stage2_x86_64,
110 .stage2_riscv64,
111 => |backend| {
110112 dev.check(devFeatureForBackend(backend));
111113 return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output);
112114 },
src/link/riscv.zig+7-33
......@@ -25,47 +25,27 @@ pub fn writeAddend(
2525}
2626
2727pub fn writeInstU(code: *[4]u8, value: u32) void {
28 var data = Encoding.Data{
29 .U = mem.bytesToValue(std.meta.TagPayload(
30 Encoding.Data,
31 Encoding.Data.U,
32 ), code),
33 };
28 var data: Instruction = .{ .U = mem.bytesToValue(std.meta.TagPayload(Instruction, .U), code) };
3429 const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800);
3530 data.U.imm12_31 = bitSlice(compensated, 31, 12);
3631 mem.writeInt(u32, code, data.toU32(), .little);
3732}
3833
3934pub fn writeInstI(code: *[4]u8, value: u32) void {
40 var data = Encoding.Data{
41 .I = mem.bytesToValue(std.meta.TagPayload(
42 Encoding.Data,
43 Encoding.Data.I,
44 ), code),
45 };
35 var data: Instruction = .{ .I = mem.bytesToValue(std.meta.TagPayload(Instruction, .I), code) };
4636 data.I.imm0_11 = bitSlice(value, 11, 0);
4737 mem.writeInt(u32, code, data.toU32(), .little);
4838}
4939
5040pub fn writeInstS(code: *[4]u8, value: u32) void {
51 var data = Encoding.Data{
52 .S = mem.bytesToValue(std.meta.TagPayload(
53 Encoding.Data,
54 Encoding.Data.S,
55 ), code),
56 };
41 var data: Instruction = .{ .S = mem.bytesToValue(std.meta.TagPayload(Instruction, .S), code) };
5742 data.S.imm0_4 = bitSlice(value, 4, 0);
5843 data.S.imm5_11 = bitSlice(value, 11, 5);
5944 mem.writeInt(u32, code, data.toU32(), .little);
6045}
6146
6247pub fn writeInstJ(code: *[4]u8, value: u32) void {
63 var data = Encoding.Data{
64 .J = mem.bytesToValue(std.meta.TagPayload(
65 Encoding.Data,
66 Encoding.Data.J,
67 ), code),
68 };
48 var data: Instruction = .{ .J = mem.bytesToValue(std.meta.TagPayload(Instruction, .J), code) };
6949 data.J.imm1_10 = bitSlice(value, 10, 1);
7050 data.J.imm11 = bitSlice(value, 11, 11);
7151 data.J.imm12_19 = bitSlice(value, 19, 12);
......@@ -74,12 +54,7 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void {
7454}
7555
7656pub fn writeInstB(code: *[4]u8, value: u32) void {
77 var data = Encoding.Data{
78 .B = mem.bytesToValue(std.meta.TagPayload(
79 Encoding.Data,
80 Encoding.Data.B,
81 ), code),
82 };
57 var data: Instruction = .{ .B = mem.bytesToValue(std.meta.TagPayload(Instruction, .B), code) };
8358 data.B.imm1_4 = bitSlice(value, 4, 1);
8459 data.B.imm5_10 = bitSlice(value, 10, 5);
8560 data.B.imm11 = bitSlice(value, 11, 11);
......@@ -109,9 +84,8 @@ pub const RiscvEflags = packed struct(u32) {
10984 _unused: u8,
11085};
11186
112const encoder = @import("../arch/riscv64/encoder.zig");
113const Encoding = @import("../arch/riscv64/Encoding.zig");
11487const mem = std.mem;
11588const std = @import("std");
11689
117pub const Instruction = encoder.Instruction;
90const encoding = @import("../arch/riscv64/encoding.zig");
91const Instruction = encoding.Instruction;
test/behavior/abs.zig+1
......@@ -6,6 +6,7 @@ test "@abs integers" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
910
1011 try comptime testAbsIntegers();
1112 try testAbsIntegers();
test/behavior/align.zig-3
......@@ -16,7 +16,6 @@ test "global variable alignment" {
1616}
1717
1818test "large alignment of local constant" {
19 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2221 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
......@@ -26,7 +25,6 @@ test "large alignment of local constant" {
2625}
2726
2827test "slicing array of length 1 can not assume runtime index is always zero" {
29 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3230 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
......@@ -511,7 +509,6 @@ test "read 128-bit field from default aligned struct in global memory" {
511509}
512510
513511test "struct field explicit alignment" {
514 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
515512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
516513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
517514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/array.zig-20
......@@ -22,7 +22,6 @@ test "arrays" {
2222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2625
2726 var array: [5]u32 = undefined;
2827
......@@ -160,7 +159,6 @@ test "array len field" {
160159test "array with sentinels" {
161160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
164162
165163 const S = struct {
166164 fn doTheTest(is_ct: bool) !void {
......@@ -532,7 +530,6 @@ test "sentinel element count towards the ABI size calculation" {
532530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
533531 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
536533
537534 const S = struct {
538535 fn doTheTest() !void {
......@@ -614,7 +611,6 @@ test "type coercion of pointer to anon struct literal to pointer to array" {
614611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
615612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
616613 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
617 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
618614
619615 const S = struct {
620616 const U = union {
......@@ -667,7 +663,6 @@ test "array init of container level array variable" {
667663 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
668664 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
669665 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
670 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
671666
672667 const S = struct {
673668 var pair: [2]usize = .{ 1, 2 };
......@@ -688,8 +683,6 @@ test "array init of container level array variable" {
688683}
689684
690685test "runtime initialized sentinel-terminated array literal" {
691 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
692
693686 var c: u16 = 300;
694687 _ = &c;
695688 const f = &[_:0x9999]u16{c};
......@@ -776,8 +769,6 @@ test "array init with no result pointer sets field result types" {
776769}
777770
778771test "runtime side-effects in comptime-known array init" {
779 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
780
781772 var side_effects: u4 = 0;
782773 const init = [4]u4{
783774 blk: {
......@@ -802,8 +793,6 @@ test "runtime side-effects in comptime-known array init" {
802793}
803794
804795test "slice initialized through reference to anonymous array init provides result types" {
805 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
806
807796 var my_u32: u32 = 123;
808797 var my_u64: u64 = 456;
809798 _ = .{ &my_u32, &my_u64 };
......@@ -817,8 +806,6 @@ test "slice initialized through reference to anonymous array init provides resul
817806}
818807
819808test "sentinel-terminated slice initialized through reference to anonymous array init provides result types" {
820 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
821
822809 var my_u32: u32 = 123;
823810 var my_u64: u64 = 456;
824811 _ = .{ &my_u32, &my_u64 };
......@@ -869,8 +856,6 @@ test "many-item sentinel-terminated pointer initialized through reference to ano
869856}
870857
871858test "pointer to array initialized through reference to anonymous array init provides result types" {
872 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
873
874859 var my_u32: u32 = 123;
875860 var my_u64: u64 = 456;
876861 _ = .{ &my_u32, &my_u64 };
......@@ -884,8 +869,6 @@ test "pointer to array initialized through reference to anonymous array init pro
884869}
885870
886871test "pointer to sentinel-terminated array initialized through reference to anonymous array init provides result types" {
887 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
888
889872 var my_u32: u32 = 123;
890873 var my_u64: u64 = 456;
891874 _ = .{ &my_u32, &my_u64 };
......@@ -912,7 +895,6 @@ test "copied array element doesn't alias source" {
912895 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
913896 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
914897 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
915 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
916898
917899 var x: [10][10]u32 = undefined;
918900
......@@ -925,7 +907,6 @@ test "copied array element doesn't alias source" {
925907
926908test "array initialized with string literal" {
927909 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
928 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
929910
930911 const S = struct {
931912 a: u32,
......@@ -993,7 +974,6 @@ test "accessing multidimensional global array at comptime" {
993974 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
994975 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
995976 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
996 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
997977
998978 const S = struct {
999979 const array = [_][]const []const u8{
test/behavior/atomics.zig-5
......@@ -15,7 +15,6 @@ test "cmpxchg" {
1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1616 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1717 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1918
2019 try testCmpxchg();
2120 try comptime testCmpxchg();
......@@ -108,7 +107,6 @@ test "cmpxchg with ignored result" {
108107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
110109 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
112110
113111 var x: i32 = 1234;
114112
......@@ -153,7 +151,6 @@ test "cmpxchg on a global variable" {
153151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
154152 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155153 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
156 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
157154
158155 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
159156 // https://github.com/ziglang/zig/issues/10627
......@@ -169,7 +166,6 @@ test "atomic load and rmw with enum" {
169166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
170167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
171168 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
172 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
173169
174170 const Value = enum(u8) { a, b, c };
175171 var x = Value.a;
......@@ -205,7 +201,6 @@ test "atomicrmw with floats" {
205201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
207203 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
208 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
209204
210205 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
211206 // https://github.com/ziglang/zig/issues/10627
test/behavior/basic.zig-17
......@@ -16,8 +16,6 @@ test "empty function with comments" {
1616}
1717
1818test "truncate" {
19 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20
2119 try expect(testTruncate(0x10fd) == 0xfd);
2220 comptime assert(testTruncate(0x10fd) == 0xfd);
2321}
......@@ -27,7 +25,6 @@ fn testTruncate(x: u32) u8 {
2725
2826test "truncate to non-power-of-two integers" {
2927 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3128
3229 try testTrunc(u32, u1, 0b10101, 0b1);
3330 try testTrunc(u32, u1, 0b10110, 0b0);
......@@ -45,7 +42,6 @@ test "truncate to non-power-of-two integers from 128-bit" {
4542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4744 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4945
5046 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
5147 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00);
......@@ -224,7 +220,6 @@ const OpaqueB = opaque {};
224220test "opaque types" {
225221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
226222 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
227 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
228223
229224 try expect(*OpaqueA != *OpaqueB);
230225
......@@ -376,7 +371,6 @@ test "take address of parameter" {
376371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
377372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
378373 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
379 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
380374
381375 try testTakeAddressOfParameter(12.34);
382376}
......@@ -401,7 +395,6 @@ test "array 2D const double ptr" {
401395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
402396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
404 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
405398
406399 const rect_2d_vertexes = [_][1]f32{
407400 [_]f32{1.0},
......@@ -414,7 +407,6 @@ test "array 2D const double ptr with offset" {
414407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
415408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
416409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
417 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
418410
419411 const rect_2d_vertexes = [_][2]f32{
420412 [_]f32{ 3.0, 4.239 },
......@@ -427,7 +419,6 @@ test "array 3D const double ptr with offset" {
427419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
428420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
429421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
430 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
431422
432423 const rect_3d_vertexes = [_][2][2]f32{
433424 [_][2]f32{
......@@ -622,7 +613,6 @@ var global_ptr = &gdt[0];
622613
623614test "global constant is loaded with a runtime-known index" {
624615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
626616
627617 const S = struct {
628618 fn doTheTest() !void {
......@@ -641,7 +631,6 @@ test "global constant is loaded with a runtime-known index" {
641631
642632test "multiline string literal is null terminated" {
643633 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
644 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
645634
646635 const s1 =
647636 \\one
......@@ -656,7 +645,6 @@ test "string escapes" {
656645 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
657646 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
658647 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
659 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
660648
661649 try expectEqualStrings("\"", "\x22");
662650 try expectEqualStrings("\'", "\x27");
......@@ -789,7 +777,6 @@ test "discarding the result of various expressions" {
789777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
790778 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
791779 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
793780
794781 const S = struct {
795782 fn foo() !u32 {
......@@ -1072,7 +1059,6 @@ test "returning an opaque type from a function" {
10721059test "orelse coercion as function argument" {
10731060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10741061 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1075 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10761062
10771063 const Loc = struct { start: i32 = -1 };
10781064 const Container = struct {
......@@ -1186,8 +1172,6 @@ fn testUnsignedCmp(comptime T: type) !void {
11861172}
11871173
11881174test "integer compare <= 64 bits" {
1189 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1190
11911175 inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
11921176 try testUnsignedCmp(T);
11931177 try comptime testUnsignedCmp(T);
......@@ -1324,7 +1308,6 @@ test "break out of block based on comptime known values" {
13241308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13251309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13261310 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1327 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13281311
13291312 const S = struct {
13301313 const source = "A-";
test/behavior/bit_shifting.zig-1
......@@ -65,7 +65,6 @@ test "sharded table" {
6565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6767 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
68 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6968
7069 // realistic 16-way sharding
7170 try testShardedTable(u32, 4, 8);
test/behavior/bitcast.zig-3
......@@ -10,7 +10,6 @@ const native_endian = builtin.target.cpu.arch.endian();
1010
1111test "@bitCast iX -> uX (32, 64)" {
1212 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1413
1514 const bit_values = [_]usize{ 32, 64 };
1615
......@@ -165,7 +164,6 @@ test "@bitCast packed structs at runtime and comptime" {
165164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167166 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
168 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
169167
170168 const Full = packed struct {
171169 number: u16,
......@@ -491,7 +489,6 @@ test "@bitCast of packed struct of bools all true" {
491489 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
492490 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
493491 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
495492
496493 const P = packed struct {
497494 b0: bool,
test/behavior/call.zig-2
......@@ -342,7 +342,6 @@ test "inline call preserves tail call" {
342342test "inline call doesn't re-evaluate non generic struct" {
343343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
344344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
345 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
346345
347346 const S = struct {
348347 fn foo(f: struct { a: u8, b: u8 }) !void {
......@@ -441,7 +440,6 @@ test "non-anytype generic parameters provide result type" {
441440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
442441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
443442 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
444 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
445443
446444 const S = struct {
447445 fn f(comptime T: type, y: T) !void {
test/behavior/cast.zig-22
......@@ -24,7 +24,6 @@ test "peer type resolution: ?T and T" {
2424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2827
2928 try expect(peerTypeTAndOptionalT(true, false).? == 0);
3029 try expect(peerTypeTAndOptionalT(false, false).? == 3);
......@@ -104,7 +103,6 @@ test "@floatFromInt" {
104103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
105104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
106105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
107 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
108106
109107 const S = struct {
110108 fn doTheTest() !void {
......@@ -163,7 +161,6 @@ test "@intFromFloat" {
163161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
164162 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
165163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
167164
168165 try testIntFromFloats();
169166 try comptime testIntFromFloats();
......@@ -303,7 +300,6 @@ test "peer result null and comptime_int" {
303300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
305302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
307303
308304 const S = struct {
309305 fn blah(n: i32) ?i32 {
......@@ -372,7 +368,6 @@ test "return u8 coercing into ?u32 return type" {
372368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
373369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
374370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
376371
377372 const S = struct {
378373 fn doTheTest() !void {
......@@ -450,7 +445,6 @@ test "implicitly cast from T to anyerror!?T" {
450445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
451446 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
452447 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
454448
455449 try castToOptionalTypeError(1);
456450 try comptime castToOptionalTypeError(1);
......@@ -602,7 +596,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
602596test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
603597 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
604598 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
605 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
606599
607600 const window_name = [1][*]const u8{"window name"};
608601 const x: [*]const ?[*]const u8 = &window_name;
......@@ -668,7 +661,6 @@ test "@floatCast cast down" {
668661test "peer type resolution: unreachable, error set, unreachable" {
669662 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
670663 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
671 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
672664
673665 const Error = error{
674666 FileDescriptorAlreadyPresentInSet,
......@@ -763,7 +755,6 @@ test "peer type resolution: error union and error set" {
763755 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764756 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
765757 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
766 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
767758
768759 const a: error{Three} = undefined;
769760 const b: error{ One, Two }!u32 = undefined;
......@@ -957,7 +948,6 @@ test "peer cast [:x]T to [*:x]T" {
957948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
958949 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
959950 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
960 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
961951
962952 const S = struct {
963953 fn doTheTest() !void {
......@@ -1023,7 +1013,6 @@ test "variable initialization uses result locations properly with regards to the
10231013test "cast between C pointer with different but compatible types" {
10241014 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10251015 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1026 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10271016
10281017 const S = struct {
10291018 fn foo(arg: [*]c_ushort) u16 {
......@@ -1219,7 +1208,6 @@ test "implicitly cast from [N]T to ?[]const T" {
12191208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12201209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12211210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12231211
12241212 try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
12251213 comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
......@@ -1544,7 +1532,6 @@ test "cast typed undefined to int" {
15441532
15451533test "implicit cast from [:0]T to [*c]T" {
15461534 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1547 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15481535
15491536 var a: [:0]const u8 = "foo";
15501537 _ = &a;
......@@ -1753,7 +1740,6 @@ test "peer type resolution: array and vector with same child type" {
17531740 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17541741 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17551742 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1756 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17571743
17581744 var arr: [2]u32 = .{ 0, 1 };
17591745 var vec: @Vector(2, u32) = .{ 2, 3 };
......@@ -1845,7 +1831,6 @@ test "peer type resolution: three-way resolution combines error set and optional
18451831 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18461832 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18471833 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1848 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18491834
18501835 const E = error{Foo};
18511836 var a: E = error.Foo;
......@@ -1913,7 +1898,6 @@ test "peer type resolution: optional fixed-width int and comptime_int" {
19131898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19141899 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19151900 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1916 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19171901
19181902 var a: ?i32 = 42;
19191903 _ = &a;
......@@ -1960,7 +1944,6 @@ test "peer type resolution: vector and tuple" {
19601944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19611945 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
19621946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1963 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19641947
19651948 var vec: @Vector(3, i32) = .{ 1, 2, 3 };
19661949 _ = &vec;
......@@ -1985,7 +1968,6 @@ test "peer type resolution: vector and array and tuple" {
19851968 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19861969 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
19871970 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1988 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19891971
19901972 var vec: @Vector(2, i8) = .{ 10, 20 };
19911973 var arr: [2]i8 = .{ 30, 40 };
......@@ -2094,7 +2076,6 @@ test "peer type resolution: many compatible pointers" {
20942076 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20952077 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20962078 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
2097 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20982079
20992080 var buf = "foo-3".*;
21002081
......@@ -2216,7 +2197,6 @@ test "peer type resolution: pointer attributes are combined correctly" {
22162197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22172198 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22182199 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2219 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22202200
22212201 var buf_a align(4) = "foo".*;
22222202 var buf_b align(4) = "bar".*;
......@@ -2277,7 +2257,6 @@ test "cast builtins can wrap result in optional" {
22772257 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22782258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22792259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22812260
22822261 const S = struct {
22832262 const MyEnum = enum(u32) { _ };
......@@ -2586,7 +2565,6 @@ test "result information is preserved through many nested structures" {
25862565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25872566 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25882567 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2589 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
25902568
25912569 const S = struct {
25922570 fn doTheTest() !void {
test/behavior/cast_int.zig-2
......@@ -35,8 +35,6 @@ test "coerce i8 to i32 and @intCast back" {
3535}
3636
3737test "coerce non byte-sized integers accross 32bits boundary" {
38 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
39
4038 {
4139 var v: u21 = 6417;
4240 _ = &v;
test/behavior/defer.zig+2-1
......@@ -53,7 +53,6 @@ test "return variable while defer expression in scope to modify it" {
5353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5555 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5756
5857 const S = struct {
5958 fn doTheTest() !void {
......@@ -116,6 +115,7 @@ test "errdefer with payload" {
116115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118117 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
119119
120120 const S = struct {
121121 fn foo() !i32 {
......@@ -138,6 +138,7 @@ test "reference to errdefer payload" {
138138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140140 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
141142
142143 const S = struct {
143144 fn foo() !i32 {
test/behavior/destructure.zig-2
......@@ -23,8 +23,6 @@ test "simple destructure" {
2323}
2424
2525test "destructure with comptime syntax" {
26 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
27
2826 const S = struct {
2927 fn doTheTest() !void {
3028 {
test/behavior/enum.zig-6
......@@ -618,7 +618,6 @@ test "enum with specified tag values" {
618618test "non-exhaustive enum" {
619619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620620 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
621 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
622621
623622 const S = struct {
624623 const E = enum(u8) { a, b, _ };
......@@ -934,7 +933,6 @@ const Bar = enum { A, B, C, D };
934933test "enum literal casting to error union with payload enum" {
935934 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
936935 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
937 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
938936
939937 var bar: error{B}!Bar = undefined;
940938 bar = .B; // should never cast to the error set
......@@ -1076,7 +1074,6 @@ test "enum literal casting to optional" {
10761074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10771075 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10781076 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1079 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10801077
10811078 var bar: ?Bar = undefined;
10821079 bar = .B;
......@@ -1105,7 +1102,6 @@ test "bit field access with enum fields" {
11051102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11061103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11071104 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1108 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11091105
11101106 var data = bit_field_1;
11111107 try expect(getA(&data) == A.Two);
......@@ -1223,8 +1219,6 @@ test "enum tag from a local variable" {
12231219}
12241220
12251221test "auto-numbered enum with signed tag type" {
1226 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1227
12281222 const E = enum(i32) { a, b };
12291223
12301224 try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a));
test/behavior/error.zig-10
......@@ -319,7 +319,6 @@ test "error inference with an empty set" {
319319
320320test "error union peer type resolution" {
321321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
323322
324323 try testErrorUnionPeerTypeResolution(1);
325324}
......@@ -403,7 +402,6 @@ test "nested error union function call in optional unwrap" {
403402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
405404 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
406 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
407405
408406 const S = struct {
409407 const Foo = struct {
......@@ -450,7 +448,6 @@ test "nested error union function call in optional unwrap" {
450448test "return function call to error set from error union function" {
451449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
454451
455452 const S = struct {
456453 fn errorable() anyerror!i32 {
......@@ -469,7 +466,6 @@ test "optional error set is the same size as error set" {
469466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
470467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
471468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
472 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
473469
474470 comptime assert(@sizeOf(?anyerror) == @sizeOf(anyerror));
475471 comptime assert(@alignOf(?anyerror) == @alignOf(anyerror));
......@@ -917,7 +913,6 @@ test "field access of anyerror results in smaller error set" {
917913test "optional error union return type" {
918914 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
919915 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
920 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
921916
922917 const S = struct {
923918 fn foo() ?anyerror!u32 {
......@@ -932,7 +927,6 @@ test "optional error union return type" {
932927test "optional error set return type" {
933928 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
934929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
935 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
936930
937931 const E = error{ A, B };
938932 const S = struct {
......@@ -946,8 +940,6 @@ test "optional error set return type" {
946940}
947941
948942test "optional error set function parameter" {
949 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
950
951943 const S = struct {
952944 fn doTheTest(a: ?anyerror) !void {
953945 try std.testing.expect(a.? == error.OutOfMemory);
......@@ -977,7 +969,6 @@ test "returning an error union containing a type with no runtime bits" {
977969test "try used in recursive function with inferred error set" {
978970 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
979971 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
980 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
981972 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
982973
983974 const Value = union(enum) {
......@@ -1079,7 +1070,6 @@ test "result location initialization of error union with OPV payload" {
10791070 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10801071 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10811072 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1082 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10831073
10841074 const S = struct {
10851075 x: u0,
test/behavior/eval.zig-1
......@@ -782,7 +782,6 @@ test "array concatenation peer resolves element types - pointer" {
782782 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
783783 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
784784 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
785 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
786785
787786 var a = [2]u3{ 1, 7 };
788787 var b = [3]u8{ 200, 225, 255 };
test/behavior/floatop.zig-1
......@@ -134,7 +134,6 @@ test "cmp f16" {
134134test "cmp f32/f64" {
135135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
136136 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
137 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
138137
139138 try testCmp(f32);
140139 try comptime testCmp(f32);
test/behavior/fn.zig-2
......@@ -181,7 +181,6 @@ test "function with complex callconv and return type expressions" {
181181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
182182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
185184
186185 try expect(fComplexCallconvRet(3).x == 9);
187186}
......@@ -451,7 +450,6 @@ test "implicit cast function to function ptr" {
451450test "method call with optional and error union first param" {
452451 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
453452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
454 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
455453
456454 const S = struct {
457455 x: i32 = 1234,
test/behavior/for.zig-4
......@@ -112,7 +112,6 @@ test "for with null and T peer types and inferred result location type" {
112112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
113113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
116115
117116 const S = struct {
118117 fn doTheTest(slice: []const u8) !void {
......@@ -154,7 +153,6 @@ test "for loop with pointer elem var" {
154153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
155154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
156155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
158156
159157 const source = "abcdefg";
160158 var target: [source.len]u8 = undefined;
......@@ -228,7 +226,6 @@ test "else continue outer for" {
228226
229227test "for loop with else branch" {
230228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
231 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
232229
233230 {
234231 var x = [_]u32{ 1, 2 };
......@@ -489,7 +486,6 @@ test "inferred alloc ptr of for loop" {
489486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
491488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
493489
494490 {
495491 var cond = false;
test/behavior/generics.zig-6
......@@ -19,7 +19,6 @@ fn checkSize(comptime T: type) usize {
1919test "simple generic fn" {
2020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2322
2423 try expect(max(i32, 3, -1) == 3);
2524 try expect(max(u8, 1, 100) == 100);
......@@ -56,7 +55,6 @@ test "fn with comptime args" {
5655 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5756 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5857 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
59 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6058
6159 try expect(gimmeTheBigOne(1234, 5678) == 5678);
6260 try expect(shouldCallSameInstance(34, 12) == 34);
......@@ -67,7 +65,6 @@ test "anytype params" {
6765 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6866 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6967 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7168
7269 try expect(max_i32(12, 34) == 34);
7370 try expect(max_f64(1.2, 3.4) == 3.4);
......@@ -404,8 +401,6 @@ test "generic struct as parameter type" {
404401}
405402
406403test "slice as parameter type" {
407 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
408
409404 const S = struct {
410405 fn internComptimeString(comptime str: []const u8) *const []const u8 {
411406 return &struct {
......@@ -503,7 +498,6 @@ test "union in struct captures argument" {
503498test "function argument tuple used as struct field" {
504499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
505500 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
507501
508502 const S = struct {
509503 fn DeleagateWithContext(comptime Function: type) type {
test/behavior/globals.zig-1
......@@ -18,7 +18,6 @@ test "store to global vector" {
1818 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2221
2322 try expect(vpos[1] == 0.0);
2423 vpos = @Vector(2, f32){ 0.0, 1.0 };
test/behavior/if.zig-6
......@@ -82,7 +82,6 @@ test "const result loc, runtime if cond, else unreachable" {
8282test "if copies its payload" {
8383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8685
8786 const S = struct {
8887 fn doTheTest() !void {
......@@ -119,7 +118,6 @@ test "if peer expressions inferred optional type" {
119118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
120119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
121120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
123121
124122 var self: []const u8 = "abcdef";
125123 var index: usize = 0;
......@@ -147,8 +145,6 @@ test "if-else expression with runtime condition result location is inferred opti
147145}
148146
149147test "result location with inferred type ends up being pointer to comptime_int" {
150 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
151
152148 var a: ?u32 = 1234;
153149 var b: u32 = 2000;
154150 _ = .{ &a, &b };
......@@ -194,8 +190,6 @@ test "if value shouldn't be load-elided if used later (structs)" {
194190}
195191
196192test "if value shouldn't be load-elided if used later (optionals)" {
197 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
198
199193 var a: ?i32 = 1;
200194 var b: ?i32 = 1;
201195
test/behavior/math.zig-9
......@@ -65,7 +65,6 @@ test "@clz" {
6565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6767 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6968
7069 try testClz();
7170 try comptime testClz();
......@@ -663,8 +662,6 @@ fn rem(comptime T: type, a: T, b: T) T {
663662}
664663
665664test "unsigned wrapping" {
666 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
667
668665 try testUnsignedWrappingEval(maxInt(u32));
669666 try comptime testUnsignedWrappingEval(maxInt(u32));
670667}
......@@ -676,8 +673,6 @@ fn testUnsignedWrappingEval(x: u32) !void {
676673}
677674
678675test "signed wrapping" {
679 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
680
681676 try testSignedWrappingEval(maxInt(i32));
682677 try comptime testSignedWrappingEval(maxInt(i32));
683678}
......@@ -725,7 +720,6 @@ fn negateWrap(comptime T: type, x: T) T {
725720test "unsigned 64-bit division" {
726721 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
727722 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
728 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
729723
730724 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
731725 // https://github.com/ziglang/zig/issues/16846
......@@ -838,7 +832,6 @@ test "@addWithOverflow" {
838832 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
839833 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
840834 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
841 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
842835
843836 try testAddWithOverflow(u8, 250, 100, 94, 1);
844837 try testAddWithOverflow(u8, 100, 150, 250, 0);
......@@ -899,7 +892,6 @@ test "@addWithOverflow > 64 bits" {
899892test "small int addition" {
900893 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
901894 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
902 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
903895
904896 var x: u2 = 0;
905897 try expect(x == 0);
......@@ -927,7 +919,6 @@ fn testMulWithOverflow(comptime T: type, a: T, b: T, mul: T, bit: u1) !void {
927919test "basic @mulWithOverflow" {
928920 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
929921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
930 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
931922
932923 try testMulWithOverflow(u8, 86, 3, 2, 1);
933924 try testMulWithOverflow(u8, 85, 3, 255, 0);
test/behavior/memcpy.zig-4
......@@ -7,7 +7,6 @@ test "memcpy and memset intrinsics" {
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 try testMemcpyMemset();
1312 try comptime testMemcpyMemset();
......@@ -29,7 +28,6 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
2928 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3331
3432 try testMemcpyBothSinglePtrArrayOneIsNullTerminated();
3533 try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated();
......@@ -50,7 +48,6 @@ test "@memcpy dest many pointer" {
5048 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5451
5552 try testMemcpyDestManyPtr();
5653 try comptime testMemcpyDestManyPtr();
......@@ -73,7 +70,6 @@ test "@memcpy slice" {
7370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7471 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7572 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7773
7874 try testMemcpySlice();
7975 try comptime testMemcpySlice();
test/behavior/null.zig-3
......@@ -53,7 +53,6 @@ test "maybe return" {
5353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5555 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5756
5857 try maybeReturnImpl();
5958 try comptime maybeReturnImpl();
......@@ -73,7 +72,6 @@ fn foo(x: ?i32) ?bool {
7372test "test null runtime" {
7473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7574 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7775
7876 try testTestNullRuntime(null);
7977}
......@@ -188,7 +186,6 @@ test "unwrap optional which is field of global var" {
188186 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
189187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
192189
193190 struct_with_optional.field = null;
194191 if (struct_with_optional.field) |payload| {
test/behavior/optional.zig+1-9
......@@ -9,7 +9,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;
99test "passing an optional integer as a parameter" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1312
1413 const S = struct {
1514 fn entry() bool {
......@@ -134,7 +133,6 @@ test "nested optional field in struct" {
134133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
136135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
138136
139137 const S2 = struct {
140138 y: u8,
......@@ -260,7 +258,6 @@ test "unwrap function call with optional pointer return value" {
260258test "nested orelse" {
261259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
263 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
264261
265262 const S = struct {
266263 fn entry() !void {
......@@ -287,7 +284,6 @@ test "nested orelse" {
287284test "self-referential struct through a slice of optional" {
288285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
289286 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
290 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
291287
292288 const S = struct {
293289 const Node = struct {
......@@ -344,7 +340,6 @@ test "0-bit child type coerced to optional return ptr result location" {
344340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
345341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
346342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
347 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
348343
349344 const S = struct {
350345 fn doTheTest() !void {
......@@ -535,7 +530,6 @@ test "Optional slice size is optimized" {
535530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
536531 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
537532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
538 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
539533
540534 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
541535 var a: ?[]const u8 = null;
......@@ -549,7 +543,6 @@ test "Optional slice passed to function" {
549543 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550544 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
551545 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
552 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
553546
554547 const S = struct {
555548 fn foo(a: ?[]const u8) !void {
......@@ -566,7 +559,6 @@ test "Optional slice passed to function" {
566559test "peer type resolution in nested if expressions" {
567560 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
568561 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
569 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
570562
571563 const Thing = struct { n: i32 };
572564 var a = false;
......@@ -594,6 +586,7 @@ test "cast slice to const slice nested in error union and optional" {
594586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595587 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
596588 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
589 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
597590
598591 const S = struct {
599592 fn inner() !?[]u8 {
......@@ -632,7 +625,6 @@ test "result location initialization of optional with OPV payload" {
632625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
633626 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
634627 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
635 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
636628
637629 const S = struct {
638630 x: u0,
test/behavior/packed-struct.zig-11
......@@ -258,7 +258,6 @@ test "nested packed struct unaligned" {
258258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
259259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
261 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
262261 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
263262
264263 const S1 = packed struct {
......@@ -331,7 +330,6 @@ test "byte-aligned field pointer offsets" {
331330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
332331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
333332 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
335333
336334 const S = struct {
337335 const A = packed struct {
......@@ -434,7 +432,6 @@ test "nested packed struct field pointers" {
434432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
435433 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
436434 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access
437 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
438435 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
439436
440437 const S2 = packed struct {
......@@ -962,7 +959,6 @@ test "pointer to container level packed struct field" {
962959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
963960 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
964961 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
965 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
966962
967963 const S = packed struct(u32) {
968964 test_bit: bool,
......@@ -1008,8 +1004,6 @@ test "bitcast back and forth" {
10081004}
10091005
10101006test "field access of packed struct smaller than its abi size inside struct initialized with rls" {
1011 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1012
10131007 // Originally reported at https://github.com/ziglang/zig/issues/14200
10141008 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10151009
......@@ -1028,8 +1022,6 @@ test "field access of packed struct smaller than its abi size inside struct init
10281022}
10291023
10301024test "modify nested packed struct aligned field" {
1031 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1032
10331025 // Originally reported at https://github.com/ziglang/zig/issues/14632
10341026 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10351027 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -1096,7 +1088,6 @@ test "packed struct used as part of anon decl name" {
10961088 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10971089 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10981090 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1099 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11001091
11011092 const S = packed struct { a: u0 = 0 };
11021093 var a: u8 = 0;
......@@ -1164,7 +1155,6 @@ test "assignment to non-byte-aligned field in packed struct" {
11641155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11651156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11661157 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1167 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11681158
11691159 const Frame = packed struct {
11701160 num: u20,
......@@ -1275,7 +1265,6 @@ test "2-byte packed struct argument in C calling convention" {
12751265 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
12761266 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
12771267 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1278 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12791268
12801269 const S = packed struct(u16) {
12811270 x: u15 = 0,
test/behavior/packed-union.zig-2
......@@ -8,7 +8,6 @@ test "flags in packed union" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
1312 try testFlagsInPackedUnion();
1413 try comptime testFlagsInPackedUnion();
......@@ -51,7 +50,6 @@ test "flags in packed union at offset" {
5150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
5352 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5553
5654 try testFlagsInPackedUnionAtOffset();
5755 try comptime testFlagsInPackedUnionAtOffset();
test/behavior/pointers.zig+1-5
......@@ -125,7 +125,6 @@ test "initialize const optional C pointer to null" {
125125
126126test "assigning integer to C pointer" {
127127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
129128
130129 var x: i32 = 0;
131130 var y: i32 = 1;
......@@ -143,7 +142,6 @@ test "assigning integer to C pointer" {
143142
144143test "C pointer comparison and arithmetic" {
145144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
147145
148146 const S = struct {
149147 fn doTheTest() !void {
......@@ -230,6 +228,7 @@ test "implicit cast error unions with non-optional to optional pointer" {
230228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
231229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
232230 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
231 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
233232
234233 const S = struct {
235234 fn doTheTest() !void {
......@@ -343,7 +342,6 @@ test "array initialization types" {
343342test "null terminated pointer" {
344343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
345344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
347345
348346 const S = struct {
349347 fn doTheTest() !void {
......@@ -517,7 +515,6 @@ test "element pointer to slice" {
517515test "element pointer arithmetic to slice" {
518516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
519517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
520 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
521518
522519 const S = struct {
523520 fn doTheTest() !void {
......@@ -572,7 +569,6 @@ test "ptrCast comptime known slice to C pointer" {
572569 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
573570 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
574571 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
575 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
576572
577573 const s: [:0]const u8 = "foo";
578574 var p: [*c]const u8 = @ptrCast(s);
test/behavior/popcount.zig-1
......@@ -8,7 +8,6 @@ test "@popCount integers" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
1312 try comptime testPopCountIntegers();
1413 try testPopCountIntegers();
test/behavior/slice.zig-6
......@@ -30,7 +30,6 @@ comptime {
3030
3131test "slicing" {
3232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3433
3534 var array: [20]i32 = undefined;
3635
......@@ -256,7 +255,6 @@ test "C pointer slice access" {
256255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
257256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
258257 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
259 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
260258
261259 var buf: [10]u32 = [1]u32{42} ** 10;
262260 const c_ptr = @as([*c]const u32, @ptrCast(&buf));
......@@ -836,7 +834,6 @@ test "global slice field access" {
836834 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
837835 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
838836 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
839 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
840837
841838 const S = struct {
842839 var slice: []const u8 = undefined;
......@@ -892,7 +889,6 @@ test "empty slice ptr is non null" {
892889test "slice decays to many pointer" {
893890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
894891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
895 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
896892
897893 var buf: [8]u8 = "abcdefg\x00".*;
898894 const p: [*:0]const u8 = buf[0..7 :0];
......@@ -903,7 +899,6 @@ test "write through pointer to optional slice arg" {
903899 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
904900 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
905901 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
906 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
907902
908903 const S = struct {
909904 fn bar(foo: *?[]const u8) !void {
......@@ -956,7 +951,6 @@ test "slicing slices gives correct result" {
956951 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
957952 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
958953 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
959 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
960954
961955 const foo = "1234";
962956 const bar = foo[0..4];
test/behavior/src.zig-3
......@@ -17,7 +17,6 @@ test "@src" {
1717 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2120
2221 try doTheTest();
2322}
......@@ -38,8 +37,6 @@ test "@src used as a comptime parameter" {
3837}
3938
4039test "@src in tuple passed to anytype function" {
41 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
42
4340 const S = struct {
4441 fn Foo(a: anytype) u32 {
4542 return a[0].line;
test/behavior/string_literals.zig-2
......@@ -34,7 +34,6 @@ const ptr_type_name: [*:0]const u8 = type_name;
3434test "@typeName() returns a string literal" {
3535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3636 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3837 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
3938
4039 try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name));
......@@ -65,7 +64,6 @@ fn testFnForSrc() std.builtin.SourceLocation {
6564test "@src() returns a struct containing 0-terminated string slices" {
6665 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6967
7068 const src = testFnForSrc();
7169 try std.testing.expect([:0]const u8 == @TypeOf(src.file));
test/behavior/struct.zig-19
......@@ -68,7 +68,6 @@ const SmallStruct = struct {
6868
6969test "lower unnamed constants" {
7070 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
71 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7271
7372 var foo = SmallStruct{ .a = 1, .b = 255 };
7473 try expect(foo.first() == 1);
......@@ -419,7 +418,6 @@ test "packed struct 24bits" {
419418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420419 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
421420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
422 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
423421 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
424422 if (comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; // TODO
425423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -506,7 +504,6 @@ test "packed struct fields are ordered from LSB to MSB" {
506504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
507505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508506 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
509 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
510507
511508 var all: u64 = 0x7765443322221111;
512509 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;
......@@ -527,7 +524,6 @@ test "implicit cast packed struct field to const ptr" {
527524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
528525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
529526 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
530 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
531527
532528 const LevelUpMove = packed struct {
533529 move_id: u9,
......@@ -593,7 +589,6 @@ test "bit field access" {
593589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594590 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
595591 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
596 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
597592
598593 var data = bit_field_1;
599594 try expect(getA(&data) == 1);
......@@ -650,7 +645,6 @@ test "packed array 24bits" {
650645 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
651646 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
652647 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
653 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
654648
655649 comptime {
656650 try expect(@sizeOf([9]Foo32Bits) == 9 * 4);
......@@ -718,7 +712,6 @@ test "pointer to packed struct member in a stack variable" {
718712 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
719713 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
720714 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
721 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
722715
723716 const S = packed struct {
724717 a: u2,
......@@ -1103,7 +1096,6 @@ test "packed struct with undefined initializers" {
11031096 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11041097 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11051098 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11071099
11081100 const S = struct {
11091101 const P = packed struct {
......@@ -1133,7 +1125,6 @@ test "packed struct with undefined initializers" {
11331125test "for loop over pointers to struct, getting field from struct pointer" {
11341126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11351127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1136 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11371128
11381129 const S = struct {
11391130 const Foo = struct {
......@@ -1243,7 +1234,6 @@ test "typed init through error unions and optionals" {
12431234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12441235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12451236 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1246 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12471237
12481238 const S = struct {
12491239 a: u32,
......@@ -1465,8 +1455,6 @@ test "struct field has a pointer to an aligned version of itself" {
14651455}
14661456
14671457test "struct has only one reference" {
1468 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1469
14701458 const S = struct {
14711459 fn optionalStructParam(_: ?struct { x: u8 }) void {}
14721460 fn errorUnionStructParam(_: error{}!struct { x: u8 }) void {}
......@@ -1573,7 +1561,6 @@ test "no dependency loop on optional field wrapped in generic function" {
15731561test "optional field init with tuple" {
15741562 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15751563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1576 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15771564
15781565 const S = struct {
15791566 a: ?struct { b: u32 },
......@@ -1588,7 +1575,6 @@ test "optional field init with tuple" {
15881575
15891576test "if inside struct init inside if" {
15901577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1591 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15921578
15931579 const MyStruct = struct { x: u32 };
15941580 const b: u32 = 5;
......@@ -1770,8 +1756,6 @@ test "struct init with no result pointer sets field result types" {
17701756}
17711757
17721758test "runtime side-effects in comptime-known struct init" {
1773 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1774
17751759 var side_effects: u4 = 0;
17761760 const S = struct { a: u4, b: u4, c: u4, d: u4 };
17771761 const init = S{
......@@ -1797,8 +1781,6 @@ test "runtime side-effects in comptime-known struct init" {
17971781}
17981782
17991783test "pointer to struct initialized through reference to anonymous initializer provides result types" {
1800 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1801
18021784 const S = struct { a: u8, b: u16, c: *const anyopaque };
18031785 var my_u16: u16 = 0xABCD;
18041786 _ = &my_u16;
......@@ -1995,7 +1977,6 @@ test "runtime call in nested initializer" {
19951977 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
19961978 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19971979 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1998 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19991980
20001981 const Holder = struct {
20011982 array: []const u8,
test/behavior/switch.zig+2-10
......@@ -316,7 +316,6 @@ test "switch on union with some prongs capturing" {
316316 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
317317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
318318 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
319 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
320319
321320 const X = union(enum) {
322321 a,
......@@ -427,6 +426,7 @@ test "else prong of switch on error set excludes other cases" {
427426 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
428427 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
429428 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
429 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
430430
431431 const S = struct {
432432 fn doTheTest() !void {
......@@ -462,6 +462,7 @@ test "switch prongs with error set cases make a new error set type for capture v
462462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
463463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
464464 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
465 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
465466
466467 const S = struct {
467468 fn doTheTest() !void {
......@@ -516,7 +517,6 @@ test "switch with null and T peer types and inferred result location type" {
516517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
517518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
518519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
520520
521521 const S = struct {
522522 fn doTheTest(c: u8) !void {
......@@ -537,7 +537,6 @@ test "switch prongs with cases with identical payload types" {
537537 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
538538 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
539539 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
540 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
541540
542541 const Union = union(enum) {
543542 A: usize,
......@@ -781,8 +780,6 @@ test "comptime inline switch" {
781780}
782781
783782test "switch capture peer type resolution" {
784 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
785
786783 const U = union(enum) {
787784 a: u32,
788785 b: u64,
......@@ -798,8 +795,6 @@ test "switch capture peer type resolution" {
798795}
799796
800797test "switch capture peer type resolution for in-memory coercible payloads" {
801 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
802
803798 const T1 = c_int;
804799 const T2 = @Type(@typeInfo(T1));
805800
......@@ -821,7 +816,6 @@ test "switch capture peer type resolution for in-memory coercible payloads" {
821816
822817test "switch pointer capture peer type resolution" {
823818 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
824 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
825819
826820 const T1 = c_int;
827821 const T2 = @Type(@typeInfo(T1));
......@@ -924,8 +918,6 @@ test "switch prong captures range" {
924918}
925919
926920test "prong with inline call to unreachable" {
927 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
928
929921 const U = union(enum) {
930922 void: void,
931923 bool: bool,
test/behavior/switch_prong_implicit_cast.zig-1
......@@ -18,7 +18,6 @@ test "switch prong implicit cast" {
1818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2221
2322 const result = switch (foo(2) catch unreachable) {
2423 FormValue.One => false,
test/behavior/threadlocal.zig-3
......@@ -6,7 +6,6 @@ test "thread local variable" {
66 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {
1110 .x86_64, .x86 => {},
1211 else => return error.SkipZigTest,
......@@ -29,7 +28,6 @@ test "pointer to thread local array" {
2928 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3029 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3331 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {
3432 .x86_64, .x86 => {},
3533 else => return error.SkipZigTest,
......@@ -47,7 +45,6 @@ test "reference a global threadlocal variable" {
4745 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
4846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4947 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5148 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {
5249 .x86_64, .x86 => {},
5350 else => return error.SkipZigTest,
test/behavior/try.zig+1
......@@ -51,6 +51,7 @@ test "`try`ing an if/else expression" {
5151 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5353 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5455
5556 const S = struct {
5657 fn getError() !void {
test/behavior/tuple.zig-5
......@@ -280,7 +280,6 @@ test "tuple in tuple passed to generic function" {
280280 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
281281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
282282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
283 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
284283
285284 const S = struct {
286285 fn pair(x: f32, y: f32) std.meta.Tuple(&.{ f32, f32 }) {
......@@ -300,7 +299,6 @@ test "coerce tuple to tuple" {
300299 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
301300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
302301 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
304302
305303 const T = std.meta.Tuple(&.{u8});
306304 const S = struct {
......@@ -315,7 +313,6 @@ test "tuple type with void field" {
315313 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
316314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
317315 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
318 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
319316
320317 const T = std.meta.Tuple(&[_]type{void});
321318 const x = T{{}};
......@@ -352,7 +349,6 @@ test "zero sized struct in tuple handled correctly" {
352349test "tuple type with void field and a runtime field" {
353350 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
354351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
355 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
356352
357353 const T = std.meta.Tuple(&[_]type{ usize, void });
358354 var t: T = .{ 5, {} };
......@@ -409,7 +405,6 @@ test "nested runtime conditionals in tuple initializer" {
409405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
410406 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
411407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
412 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
413408
414409 var data: u8 = 0;
415410 _ = &data;
test/behavior/tuple_declarations.zig-2
......@@ -7,7 +7,6 @@ const expectEqualStrings = testing.expectEqualStrings;
77test "tuple declaration type info" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 {
1312 const T = struct { comptime u32 align(2) = 1, []const u8 };
......@@ -36,7 +35,6 @@ test "tuple declaration type info" {
3635test "Tuple declaration usage" {
3736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4038
4139 const T = struct { u32, []const u8 };
4240 var t: T = .{ 1, "foo" };
test/behavior/type_info.zig-5
......@@ -565,8 +565,6 @@ test "StructField.is_comptime" {
565565}
566566
567567test "typeInfo resolves usingnamespace declarations" {
568 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
569
570568 const A = struct {
571569 pub const f1 = 42;
572570 };
......@@ -592,7 +590,6 @@ test "value from struct @typeInfo default_value can be loaded at comptime" {
592590test "@typeInfo decls and usingnamespace" {
593591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
594592 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
596593
597594 const A = struct {
598595 pub const x = 5;
......@@ -633,8 +630,6 @@ test "type info of tuple of string literal default value" {
633630}
634631
635632test "@typeInfo only contains pub decls" {
636 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
637
638633 const other = struct {
639634 const std = @import("std");
640635
test/behavior/typename.zig-8
......@@ -16,7 +16,6 @@ test "anon fn param" {
1616 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1717 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2019
2120 // https://github.com/ziglang/zig/issues/9339
2221 try expectEqualStringsIgnoreDigits(
......@@ -42,7 +41,6 @@ test "anon field init" {
4241 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4342 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4644 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
4745
4846 const Foo = .{
......@@ -69,7 +67,6 @@ test "basic" {
6967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7169 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7370
7471 try expectEqualStrings("i64", @typeName(i64));
7572 try expectEqualStrings("*usize", @typeName(*usize));
......@@ -91,7 +88,6 @@ test "top level decl" {
9188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9289 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9591 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
9692
9793 try expectEqualStrings(
......@@ -142,7 +138,6 @@ test "fn param" {
142138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
143139 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
146141 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
147142
148143 // https://github.com/ziglang/zig/issues/675
......@@ -223,7 +218,6 @@ test "local variable" {
223218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
224219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
225220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
226 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
227221 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
228222
229223 const Foo = struct { a: u32 };
......@@ -243,7 +237,6 @@ test "comptime parameters not converted to anytype in function type" {
243237 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
244238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
245239 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
246 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
247240
248241 const T = fn (fn (type) void, void) void;
249242 try expectEqualStrings("fn (comptime fn (comptime type) void, void) void", @typeName(T));
......@@ -253,7 +246,6 @@ test "anon name strategy used in sub expression" {
253246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
254247 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
255248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
257249 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
258250
259251 const S = struct {
test/behavior/union.zig-9
......@@ -100,7 +100,6 @@ const FooExtern = extern union {
100100test "basic extern unions" {
101101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
102102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104103
105104 var foo = FooExtern{ .int = 1 };
106105 try expect(foo.int == 1);
......@@ -172,7 +171,6 @@ test "constant tagged union with payload" {
172171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
173172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
176174
177175 var empty = TaggedUnionWithPayload{ .Empty = {} };
178176 var full = TaggedUnionWithPayload{ .Full = 13 };
......@@ -656,7 +654,6 @@ test "union(enum(u32)) with specified and unspecified tag values" {
656654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
657655 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
658656 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
659 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
660657
661658 comptime assert(Tag(Tag(MultipleChoice2)) == u32);
662659 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
......@@ -808,7 +805,6 @@ test "return union init with void payload" {
808805 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
809806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
810807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
811 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
812808
813809 const S = struct {
814810 fn entry() !void {
......@@ -971,7 +967,6 @@ test "function call result coerces from tagged union to the tag" {
971967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
972968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
973969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
974 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
975970
976971 const S = struct {
977972 const Arch = union(enum) {
......@@ -1136,7 +1131,6 @@ test "@unionInit on union with tag but no fields" {
11361131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11371132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11381133 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11401134
11411135 const S = struct {
11421136 const Type = enum(u8) { no_op = 105 };
......@@ -1700,7 +1694,6 @@ test "packed union field pointer has correct alignment" {
17001694
17011695test "union with 128 bit integer" {
17021696 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1703 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17041697
17051698 const ValueTag = enum { int, other };
17061699
......@@ -1917,7 +1910,6 @@ test "reinterpret packed union" {
19171910
19181911test "reinterpret packed union inside packed struct" {
19191912 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1920 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19211913
19221914 const U = packed union {
19231915 a: u7,
......@@ -2196,7 +2188,6 @@ test "copied union field doesn't alias source" {
21962188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21972189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21982190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2199 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22002191
22012192 const U = union(enum) {
22022193 array: [10]u32,
test/behavior/union_with_members.zig-1
......@@ -21,7 +21,6 @@ test "enum with members" {
2121 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2323 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2524
2625 const a = ET{ .SINT = -42 };
2726 const b = ET{ .UINT = 42 };
test/behavior/vector.zig+3-10
......@@ -102,7 +102,6 @@ test "vector float operators" {
102102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103103 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
104104 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
106105 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
107106
108107 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
......@@ -119,7 +118,7 @@ test "vector float operators" {
119118 try expectEqual(v + x, .{ 11, 22, 33, 44 });
120119 try expectEqual(v - x, .{ 9, 18, 27, 36 });
121120 try expectEqual(v * x, .{ 10, 40, 90, 160 });
122 try expectEqual(-x, .{ -1, -2, -3, -4 });
121 if (builtin.zig_backend != .stage2_riscv64) try expectEqual(-x, .{ -1, -2, -3, -4 });
123122 }
124123 };
125124
......@@ -129,6 +128,8 @@ test "vector float operators" {
129128 try S.doTheTest(f64);
130129 try comptime S.doTheTest(f64);
131130
131 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
132
132133 try S.doTheTest(f16);
133134 try comptime S.doTheTest(f16);
134135
......@@ -394,7 +395,6 @@ test "load vector elements via comptime index" {
394395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
395396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
398398
399399 const S = struct {
400400 fn doTheTest() !void {
......@@ -416,7 +416,6 @@ test "store vector elements via comptime index" {
416416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
417417 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
418418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
419 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
420419
421420 const S = struct {
422421 fn doTheTest() !void {
......@@ -444,7 +443,6 @@ test "load vector elements via runtime index" {
444443 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
445444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
446445 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
448446
449447 const S = struct {
450448 fn doTheTest() !void {
......@@ -467,7 +465,6 @@ test "store vector elements via runtime index" {
467465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
468466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
469467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
471468
472469 const S = struct {
473470 fn doTheTest() !void {
......@@ -1239,7 +1236,6 @@ test "loading the second vector from a slice of vectors" {
12391236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12401237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12411238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1242 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12431239
12441240 @setRuntimeSafety(false);
12451241 var small_bases = [2]@Vector(2, u8){
......@@ -1326,7 +1322,6 @@ test "zero multiplicand" {
13261322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13271323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13281324 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1329 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13301325
13311326 const zeros = @Vector(2, u32){ 0.0, 0.0 };
13321327 var ones = @Vector(2, u32){ 1.0, 1.0 };
......@@ -1487,7 +1482,6 @@ test "store vector with memset" {
14871482test "addition of vectors represented as strings" {
14881483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14891484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1490 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14911485
14921486 const V = @Vector(3, u8);
14931487 const foo: V = "foo".*;
......@@ -1514,7 +1508,6 @@ test "vector pointer is indexable" {
15141508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15151509 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
15161510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1517 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15181511
15191512 const V = @Vector(2, u32);
15201513
test/behavior/while.zig-5
......@@ -106,7 +106,6 @@ fn testBreakOuter() void {
106106test "while copies its payload" {
107107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
108108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
110109
111110 const S = struct {
112111 fn doTheTest() !void {
......@@ -208,7 +207,6 @@ test "while on optional with else result follow else prong" {
208207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
209208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
210209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
212210
213211 const result = while (returnNull()) |value| {
214212 break value;
......@@ -220,7 +218,6 @@ test "while on optional with else result follow break prong" {
220218 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
221219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
222220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
223 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
224221
225222 const result = while (returnOptional(10)) |value| {
226223 break value;
......@@ -293,7 +290,6 @@ test "while optional 2 break statements and an else" {
293290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
294291 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
295292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
297293
298294 const S = struct {
299295 fn entry(opt_t: ?bool, f: bool) !void {
......@@ -392,7 +388,6 @@ test "breaking from a loop in an if statement" {
392388 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
393389 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
396391
397392 const S = struct {
398393 fn retOpt() ?u32 {
test/tests.zig+1-1
......@@ -439,7 +439,7 @@ const test_targets = blk: {
439439 .target = std.Target.Query.parse(
440440 .{
441441 .arch_os_abi = "riscv64-linux-musl",
442 .cpu_features = "baseline+v",
442 .cpu_features = "baseline+v+zbb",
443443 },
444444 ) catch @panic("OOM"),
445445 .use_llvm = false,