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

Merge pull request #20474 from Rexicon226/riscv

more RISC-V backend progress

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

lib/std/simd.zig+32-4
......@@ -1,7 +1,7 @@
11//! SIMD (Single Instruction; Multiple Data) convenience functions.
22//!
33//! May offer a potential boost in performance on some targets by performing
4//! the same operations on multiple elements at once.
4//! the same operation on multiple elements at once.
55//!
66//! Some functions are known to not work on MIPS.
77
......@@ -10,7 +10,6 @@ const builtin = @import("builtin");
1010
1111pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) ?comptime_int {
1212 // This is guesswork, if you have better suggestions can add it or edit the current here
13 // This can run in comptime only, but stage 1 fails at it, stage 2 can understand it
1413 const element_bit_size = @max(8, std.math.ceilPowerOfTwo(u16, @bitSizeOf(T)) catch unreachable);
1514 const vector_bit_size: u16 = blk: {
1615 if (cpu.arch.isX86()) {
......@@ -37,8 +36,37 @@ pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu)
3736 // the 2048 bits or using just 64 per vector or something in between
3837 if (std.Target.mips.featureSetHas(cpu.features, std.Target.mips.Feature.mips3d)) break :blk 64;
3938 } else if (cpu.arch.isRISCV()) {
40 // in risc-v the Vector Extension allows configurable vector sizes, but a standard size of 128 is a safe estimate
41 if (std.Target.riscv.featureSetHas(cpu.features, .v)) break :blk 128;
39 // In RISC-V Vector Registers are length agnostic so there's no good way to determine the best size.
40 // The usual vector length in most RISC-V cpus is 256 bits, however it can get to multiple kB.
41 if (std.Target.riscv.featureSetHas(cpu.features, .v)) {
42 var vec_bit_length: u32 = 256;
43 if (std.Target.riscv.featureSetHas(cpu.features, .zvl32b)) {
44 vec_bit_length = 32;
45 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl64b)) {
46 vec_bit_length = 64;
47 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl128b)) {
48 vec_bit_length = 128;
49 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl256b)) {
50 vec_bit_length = 256;
51 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl512b)) {
52 vec_bit_length = 512;
53 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl1024b)) {
54 vec_bit_length = 1024;
55 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl2048b)) {
56 vec_bit_length = 2048;
57 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl4096b)) {
58 vec_bit_length = 4096;
59 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl8192b)) {
60 vec_bit_length = 8192;
61 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl16384b)) {
62 vec_bit_length = 16384;
63 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl32768b)) {
64 vec_bit_length = 32768;
65 } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl65536b)) {
66 vec_bit_length = 65536;
67 }
68 break :blk vec_bit_length;
69 }
4270 } else if (cpu.arch.isSPARC()) {
4371 // TODO: Test Sparc capability to handle bigger vectors
4472 // In theory Sparc have 32 registers of 64 bits which can use in parallel
lib/std/start.zig+20-1
......@@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn {
221221 }
222222 break :ret root.main();
223223 },
224 else => @compileError("expected return type of main to be 'void', 'noreturn', 'u8'"),
224 .ErrorUnion => ret: {
225 const result = root.main() catch {
226 const stderr = std.io.getStdErr().writer();
227 stderr.writeAll("failed with error\n") catch {
228 @panic("failed to print when main returned error");
229 };
230 break :ret 1;
231 };
232 switch (@typeInfo(@TypeOf(result))) {
233 .Void => break :ret 0,
234 .Int => |info| {
235 if (info.bits != 8 or info.signedness == .signed) {
236 @compileError(bad_main_ret);
237 }
238 return result;
239 },
240 else => @compileError(bad_main_ret),
241 }
242 },
243 else => @compileError(bad_main_ret),
225244 });
226245}
227246
src/arch/riscv64/CodeGen.zig+830-239
......@@ -1,8 +1,12 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const build_options = @import("build_options");
4
35const mem = std.mem;
46const math = std.math;
57const assert = std.debug.assert;
8const Allocator = mem.Allocator;
9
610const Air = @import("../../Air.zig");
711const Mir = @import("Mir.zig");
812const Emit = @import("Emit.zig");
......@@ -14,18 +18,16 @@ const Zcu = @import("../../Zcu.zig");
1418const Package = @import("../../Package.zig");
1519const InternPool = @import("../../InternPool.zig");
1620const Compilation = @import("../../Compilation.zig");
21const trace = @import("../../tracy.zig").trace;
22const codegen = @import("../../codegen.zig");
23
1724const ErrorMsg = Zcu.ErrorMsg;
1825const Target = std.Target;
19const Allocator = mem.Allocator;
20const trace = @import("../../tracy.zig").trace;
21const DW = std.dwarf;
22const leb128 = std.leb;
26
2327const log = std.log.scoped(.riscv_codegen);
2428const tracking_log = std.log.scoped(.tracking);
2529const verbose_tracking_log = std.log.scoped(.verbose_tracking);
2630const wip_mir_log = std.log.scoped(.wip_mir);
27const build_options = @import("build_options");
28const codegen = @import("../../codegen.zig");
2931const Alignment = InternPool.Alignment;
3032
3133const CodeGenError = codegen.CodeGenError;
......@@ -37,6 +39,7 @@ const abi = @import("abi.zig");
3739const Lower = @import("Lower.zig");
3840
3941const Register = bits.Register;
42const CSR = bits.CSR;
4043const Immediate = bits.Immediate;
4144const Memory = bits.Memory;
4245const FrameIndex = bits.FrameIndex;
......@@ -45,15 +48,16 @@ const RegisterLock = RegisterManager.RegisterLock;
4548
4649const InnerError = CodeGenError || error{OutOfRegisters};
4750
48gpa: Allocator,
4951pt: Zcu.PerThread,
5052air: Air,
51mod: *Package.Module,
5253liveness: Liveness,
54zcu: *Zcu,
5355bin_file: *link.File,
56gpa: Allocator,
57
58mod: *Package.Module,
5459target: *const std.Target,
5560func_index: InternPool.Index,
56code: *std.ArrayList(u8),
5761debug_output: DebugInfoOutput,
5862err_msg: ?*ErrorMsg,
5963args: []MCValue,
......@@ -62,9 +66,7 @@ fn_type: Type,
6266arg_index: usize,
6367src_loc: Zcu.LazySrcLoc,
6468
65/// MIR Instructions
6669mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
67/// MIR extra data
6870mir_extra: std.ArrayListUnmanaged(u32) = .{},
6971
7072/// Byte offset within the source file of the ending curly.
......@@ -87,6 +89,10 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},
8789/// across each runtime branch upon joining.
8890branch_stack: *std.ArrayList(Branch),
8991
92// Currently set vector properties, null means they haven't been set yet in the function.
93avl: ?u64,
94vtype: ?bits.VType,
95
9096// Key is the block instruction
9197blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
9298register_manager: RegisterManager = .{},
......@@ -117,8 +123,9 @@ const MCValue = union(enum) {
117123 /// No more references to this value remain.
118124 /// The payload is the value of scope_generation at the point where the death occurred
119125 dead: u32,
120 /// The value is undefined.
121 undef,
126 /// The value is undefined. Contains a symbol index to an undefined constant. Null means
127 /// set the undefined value via immediate instead of a load.
128 undef: ?u32,
122129 /// A pointer-sized integer that fits in a register.
123130 /// If the type is a pointer, this is the pointer address in virtual address space.
124131 immediate: u64,
......@@ -725,16 +732,16 @@ pub fn generate(
725732 }
726733 try branch_stack.append(.{});
727734
728 var function = Func{
735 var function: Func = .{
729736 .gpa = gpa,
730737 .air = air,
731738 .pt = pt,
732739 .mod = mod,
740 .zcu = zcu,
741 .bin_file = bin_file,
733742 .liveness = liveness,
734743 .target = target,
735 .bin_file = bin_file,
736744 .func_index = func_index,
737 .code = code,
738745 .debug_output = debug_output,
739746 .err_msg = null,
740747 .args = undefined, // populated after `resolveCallingConventionValues`
......@@ -746,6 +753,8 @@ pub fn generate(
746753 .end_di_line = func.rbrace_line,
747754 .end_di_column = func.rbrace_column,
748755 .scope_generation = 0,
756 .avl = null,
757 .vtype = null,
749758 };
750759 defer {
751760 function.frame_allocs.deinit(gpa);
......@@ -817,7 +826,7 @@ pub fn generate(
817826 else => |e| return e,
818827 };
819828
820 var mir = Mir{
829 var mir: Mir = .{
821830 .instructions = function.mir_instructions.toOwnedSlice(),
822831 .extra = try function.mir_extra.toOwnedSlice(gpa),
823832 .frame_locs = function.frame_locs.toOwnedSlice(),
......@@ -825,7 +834,6 @@ pub fn generate(
825834 defer mir.deinit(gpa);
826835
827836 var emit: Emit = .{
828 .bin_file = bin_file,
829837 .lower = .{
830838 .pt = pt,
831839 .allocator = gpa,
......@@ -836,6 +844,7 @@ pub fn generate(
836844 .link_mode = comp.config.link_mode,
837845 .pic = mod.pic,
838846 },
847 .bin_file = bin_file,
839848 .debug_output = debug_output,
840849 .code = code,
841850 .prev_di_pc = 0,
......@@ -896,7 +905,7 @@ fn formatWipMir(
896905 .pic = comp.root_mod.pic,
897906 };
898907 var first = true;
899 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
908 for ((lower.lowerMir(data.inst, .{ .allow_frame_locs = false }) catch |err| switch (err) {
900909 error.LowerFail => {
901910 defer {
902911 lower.err_msg.?.deinit(data.func.gpa);
......@@ -924,7 +933,7 @@ fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir)
924933}
925934
926935const FormatDeclData = struct {
927 mod: *Zcu,
936 zcu: *Zcu,
928937 decl_index: InternPool.DeclIndex,
929938};
930939fn formatDecl(
......@@ -933,11 +942,11 @@ fn formatDecl(
933942 _: std.fmt.FormatOptions,
934943 writer: anytype,
935944) @TypeOf(writer).Error!void {
936 try writer.print("{}", .{data.mod.declPtr(data.decl_index).fqn.fmt(&data.mod.intern_pool)});
945 try writer.print("{}", .{data.zcu.declPtr(data.decl_index).fqn.fmt(&data.zcu.intern_pool)});
937946}
938947fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
939948 return .{ .data = .{
940 .mod = func.pt.zcu,
949 .zcu = func.zcu,
941950 .decl_index = decl_index,
942951 } };
943952}
......@@ -989,13 +998,9 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
989998 .pseudo_dbg_prologue_end,
990999 .pseudo_dbg_line_column,
9911000 .pseudo_dbg_epilogue_begin,
992 .pseudo_store_rm,
993 .pseudo_load_rm,
994 .pseudo_lea_rm,
995 .pseudo_mv,
9961001 .pseudo_dead,
9971002 => false,
998 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}) else wip_mir_log.debug(" | uses-mem", .{});
1003 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)});
9991004 return result_index;
10001005}
10011006
......@@ -1042,9 +1047,84 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
10421047 return result;
10431048}
10441049
1050/// Returns a temporary register that contains the value of the `reg` csr.
1051///
1052/// Caller's duty to lock the return register is needed.
1053fn getCsr(func: *Func, csr: CSR) !Register {
1054 assert(func.hasFeature(.zicsr));
1055 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.usize));
1056 _ = try func.addInst(.{
1057 .tag = .csrrs,
1058 .ops = .csr,
1059 .data = .{
1060 .csr = .{
1061 .csr = csr,
1062 .rd = dst_reg,
1063 .rs1 = .x0,
1064 },
1065 },
1066 });
1067 return dst_reg;
1068}
1069
1070fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
1071 if (func.avl == avl) if (func.vtype) |vtype| {
1072 // it's already set, we don't need to do anything
1073 if (@as(u8, @bitCast(vtype)) == @as(u8, @bitCast(options))) return;
1074 };
1075
1076 func.avl = avl;
1077 func.vtype = options;
1078
1079 if (avl == 0) {
1080 // the caller means to do "vsetvli zero, zero ..." which keeps the avl to whatever it was before
1081 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1082 _ = try func.addInst(.{
1083 .tag = .vsetvli,
1084 .ops = .rri,
1085 .data = .{ .i_type = .{
1086 .rd = dst_reg,
1087 .rs1 = .zero,
1088 .imm12 = Immediate.u(options_int),
1089 } },
1090 });
1091 } else {
1092 // if the avl can fit into u5 we can use vsetivli otherwise use vsetvli
1093 if (avl <= std.math.maxInt(u5)) {
1094 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));
1095 _ = try func.addInst(.{
1096 .tag = .vsetivli,
1097 .ops = .rri,
1098 .data = .{
1099 .i_type = .{
1100 .rd = dst_reg,
1101 .rs1 = @enumFromInt(avl),
1102 .imm12 = Immediate.u(options_int),
1103 },
1104 },
1105 });
1106 } else {
1107 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1108 const temp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = avl });
1109 _ = try func.addInst(.{
1110 .tag = .vsetvli,
1111 .ops = .rri,
1112 .data = .{ .i_type = .{
1113 .rd = dst_reg,
1114 .rs1 = temp_reg,
1115 .imm12 = Immediate.u(options_int),
1116 } },
1117 });
1118 }
1119 }
1120}
1121
10451122const required_features = [_]Target.riscv.Feature{
10461123 .d,
10471124 .m,
1125 .a,
1126 .zicsr,
1127 .v,
10481128};
10491129
10501130fn gen(func: *Func) !void {
......@@ -1102,7 +1182,19 @@ fn gen(func: *Func) !void {
11021182 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);
11031183 const backpatch_fp_restore = try func.addPseudo(.pseudo_dead);
11041184 const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead);
1105 try func.addPseudoNone(.pseudo_ret);
1185
1186 // ret
1187 _ = try func.addInst(.{
1188 .tag = .jalr,
1189 .ops = .rri,
1190 .data = .{
1191 .i_type = .{
1192 .rd = .zero,
1193 .rs1 = .ra,
1194 .imm12 = Immediate.s(0),
1195 },
1196 },
1197 });
11061198
11071199 const frame_layout = try func.computeFrameLayout();
11081200 const need_save_reg = frame_layout.save_reg_list.count() > 0;
......@@ -1273,7 +1365,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
12731365 .round,
12741366 .trunc_float,
12751367 .neg,
1276 => try func.airUnaryMath(inst),
1368 => try func.airUnaryMath(inst, tag),
12771369
12781370 .add_with_overflow => try func.airAddWithOverflow(inst),
12791371 .sub_with_overflow => try func.airSubWithOverflow(inst),
......@@ -1319,7 +1411,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13191411 .breakpoint => try func.airBreakpoint(),
13201412 .ret_addr => try func.airRetAddr(inst),
13211413 .frame_addr => try func.airFrameAddress(inst),
1322 .fence => try func.airFence(),
1414 .fence => try func.airFence(inst),
13231415 .cond_br => try func.airCondBr(inst),
13241416 .dbg_stmt => try func.airDbgStmt(inst),
13251417 .fptrunc => try func.airFptrunc(inst),
......@@ -1631,7 +1723,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout {
16311723
16321724 // The total frame size is calculated by the amount of s registers you need to save * 8, as each
16331725 // register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s0
1634 // register. Finally we align the frame size to the align of the base pointer.
1726 // register. Finally we align the frame size to the alignment of the base pointer.
16351727 const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)];
16361728 const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)];
16371729 const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)];
......@@ -1791,14 +1883,9 @@ fn symbolIndex(func: *Func) !u32 {
17911883 const pt = func.pt;
17921884 const zcu = pt.zcu;
17931885 const decl_index = zcu.funcOwnerDeclIndex(func.func_index);
1794 return switch (func.bin_file.tag) {
1795 .elf => blk: {
1796 const elf_file = func.bin_file.cast(link.File.Elf).?;
1797 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
1798 break :blk atom_index;
1799 },
1800 else => return func.fail("TODO symbolIndex {s}", .{@tagName(func.bin_file.tag)}),
1801 };
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;
18021889}
18031890
18041891fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex {
......@@ -1843,48 +1930,44 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass {
18431930 const zcu = pt.zcu;
18441931 return switch (ty.zigTypeTag(zcu)) {
18451932 .Float => .float,
1846 .Vector => @panic("TODO: typeRegClass for Vectors"),
1847 inline else => .int,
1933 .Vector => .vector,
1934 else => .int,
18481935 };
18491936}
18501937
18511938fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
1852 const pt = func.pt;
1853 const zcu = pt.zcu;
1854 return switch (ty.zigTypeTag(zcu)) {
1939 return switch (ty.zigTypeTag(func.pt.zcu)) {
18551940 .Float => abi.Registers.Float.general_purpose,
1856 .Vector => @panic("TODO: regGeneralClassForType for Vectors"),
1941 .Vector => abi.Registers.Vector.general_purpose,
18571942 else => abi.Registers.Integer.general_purpose,
18581943 };
18591944}
18601945
18611946fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
1862 const pt = func.pt;
1863 const zcu = pt.zcu;
1864 return switch (ty.zigTypeTag(zcu)) {
1947 return switch (ty.zigTypeTag(func.pt.zcu)) {
18651948 .Float => abi.Registers.Float.temporary,
1866 .Vector => @panic("TODO: regTempClassForType for Vectors"),
1949 .Vector => abi.Registers.Vector.general_purpose, // there are no temporary vector registers
18671950 else => abi.Registers.Integer.temporary,
18681951 };
18691952}
18701953
18711954fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
18721955 const pt = func.pt;
1956 const zcu = pt.zcu;
18731957
1874 const abi_size = math.cast(u32, elem_ty.abiSize(pt)) orelse {
1875 return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)});
1876 };
1877
1878 const min_size: u32 = switch (elem_ty.zigTypeTag(pt.zcu)) {
1879 .Float => 4,
1880 .Vector => @panic("allocRegOrMem Vector"),
1881 else => 8,
1958 const bit_size = elem_ty.bitSize(pt);
1959 const min_size: u64 = switch (elem_ty.zigTypeTag(zcu)) {
1960 .Float => if (func.hasFeature(.d)) 64 else 32,
1961 .Vector => 256, // TODO: calculate it from avl * vsew
1962 else => 64,
18821963 };
18831964
1884 if (reg_ok and abi_size <= min_size) {
1965 if (reg_ok and bit_size <= min_size) {
18851966 if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| {
18861967 return .{ .register = reg };
18871968 }
1969 } else if (reg_ok and elem_ty.zigTypeTag(zcu) == .Vector) {
1970 return func.fail("did you forget to extend vector registers before allocating", .{});
18881971 }
18891972
18901973 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt));
......@@ -1897,10 +1980,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool
18971980fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {
18981981 if (reg_class == .float and !func.hasFeature(.f))
18991982 std.debug.panic("allocReg class == float where F isn't enabled", .{});
1983 if (reg_class == .vector and !func.hasFeature(.v))
1984 std.debug.panic("allocReg class == vector where V isn't enabled", .{});
19001985
19011986 const class = switch (reg_class) {
19021987 .int => abi.Registers.Integer.general_purpose,
19031988 .float => abi.Registers.Float.general_purpose,
1989 .vector => abi.Registers.Vector.general_purpose,
19041990 };
19051991
19061992 const reg = try func.register_manager.allocReg(null, class);
......@@ -1916,7 +2002,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi
19162002 return .{ op_reg, func.register_manager.lockReg(operand.register) };
19172003 }
19182004
1919 const reg, const lock = try func.allocReg(func.typeRegClass(ty));
2005 const class = func.typeRegClass(ty);
2006 const reg, const lock = try func.allocReg(class);
19202007 try func.genSetReg(ty, reg, operand);
19212008 return .{ reg, lock };
19222009}
......@@ -2087,19 +2174,17 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
20872174 const operand = try func.resolveInst(ty_op.operand);
20882175 const ty = func.typeOf(ty_op.operand);
20892176
2090 switch (ty.zigTypeTag(zcu)) {
2091 .Bool => {
2092 const operand_reg = blk: {
2093 if (operand == .register) break :blk operand.register;
2094 break :blk try func.copyToTmpRegister(ty, operand);
2095 };
2177 const operand_reg, const operand_lock = try func.promoteReg(ty, operand);
2178 defer if (operand_lock) |lock| func.register_manager.unlockReg(lock);
20962179
2097 const dst_reg: Register =
2098 if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
2099 operand.register
2100 else
2101 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
2180 const dst_reg: Register =
2181 if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
2182 operand.register
2183 else
2184 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
21022185
2186 switch (ty.zigTypeTag(zcu)) {
2187 .Bool => {
21032188 _ = try func.addInst(.{
21042189 .tag = .pseudo,
21052190 .ops = .pseudo_not,
......@@ -2110,12 +2195,34 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
21102195 },
21112196 },
21122197 });
2198 },
2199 .Int => {
2200 const size = ty.bitSize(pt);
2201 if (!math.isPowerOfTwo(size))
2202 return func.fail("TODO: airNot non-pow 2 int size", .{});
21132203
2114 break :result .{ .register = dst_reg };
2204 switch (size) {
2205 32, 64 => {
2206 _ = try func.addInst(.{
2207 .tag = .xori,
2208 .ops = .rri,
2209 .data = .{
2210 .i_type = .{
2211 .rd = dst_reg,
2212 .rs1 = operand_reg,
2213 .imm12 = Immediate.s(-1),
2214 },
2215 },
2216 });
2217 },
2218 8, 16 => return func.fail("TODO: airNot 8 or 16, {}", .{size}),
2219 else => unreachable,
2220 }
21152221 },
2116 .Int => return func.fail("TODO: airNot ints", .{}),
21172222 else => unreachable,
21182223 }
2224
2225 break :result .{ .register = dst_reg };
21192226 };
21202227 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
21212228}
......@@ -2205,7 +2312,11 @@ fn binOp(
22052312 return func.fail("binOp libcall runtime-float ops", .{});
22062313 }
22072314
2208 if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{});
2315 // don't have support for certain sizes of addition
2316 switch (lhs_ty.zigTypeTag(pt.zcu)) {
2317 .Vector => {}, // works differently and fails in a different place
2318 else => if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{}),
2319 }
22092320
22102321 const lhs_mcv = try func.resolveInst(lhs_air);
22112322 const rhs_mcv = try func.resolveInst(rhs_air);
......@@ -2353,6 +2464,51 @@ fn genBinOp(
23532464 },
23542465 });
23552466 },
2467 .Vector => {
2468 const num_elem = lhs_ty.vectorLen(zcu);
2469 const elem_size = lhs_ty.childType(zcu).bitSize(pt);
2470
2471 const child_ty = lhs_ty.childType(zcu);
2472
2473 const mir_tag: Mir.Inst.Tag = switch (tag) {
2474 .add => switch (child_ty.zigTypeTag(zcu)) {
2475 .Int => .vaddvv,
2476 .Float => .vfaddvv,
2477 else => unreachable,
2478 },
2479 .sub => switch (child_ty.zigTypeTag(zcu)) {
2480 .Int => .vsubvv,
2481 .Float => .vfsubvv,
2482 else => unreachable,
2483 },
2484 else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}),
2485 };
2486
2487 try func.setVl(.zero, num_elem, .{
2488 .vsew = switch (elem_size) {
2489 8 => .@"8",
2490 16 => .@"16",
2491 32 => .@"32",
2492 64 => .@"64",
2493 else => unreachable,
2494 },
2495 .vlmul = .m1,
2496 .vma = true,
2497 .vta = true,
2498 });
2499
2500 _ = try func.addInst(.{
2501 .tag = mir_tag,
2502 .ops = .rrr,
2503 .data = .{
2504 .r_type = .{
2505 .rd = dst_reg,
2506 .rs1 = rhs_reg,
2507 .rs2 = lhs_reg,
2508 },
2509 },
2510 });
2511 },
23562512 else => unreachable,
23572513 }
23582514 },
......@@ -2636,78 +2792,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
26362792 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
26372793
26382794 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2639 const lhs_ty = func.typeOf(extra.lhs);
2640
2641 const int_info = lhs_ty.intInfo(zcu);
2642
2643 const tuple_ty = func.typeOfIndex(inst);
2644 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2645 const offset = result_mcv.load_frame;
2646
2647 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2648 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
2649 const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result);
2650 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2651 defer func.register_manager.unlockReg(add_result_reg_lock);
2795 const ty = func.typeOf(extra.lhs);
2796 switch (ty.zigTypeTag(zcu)) {
2797 .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}),
2798 .Int => {
2799 const int_info = ty.intInfo(zcu);
26522800
2653 const shift_amount: u6 = @intCast(Type.usize.bitSize(pt) - int_info.bits);
2801 const tuple_ty = func.typeOfIndex(inst);
2802 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2803 const offset = result_mcv.load_frame;
26542804
2655 const shift_reg, const shift_lock = try func.allocReg(.int);
2656 defer func.register_manager.unlockReg(shift_lock);
2805 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2806 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
26572807
2658 _ = try func.addInst(.{
2659 .tag = .slli,
2660 .ops = .rri,
2661 .data = .{
2662 .i_type = .{
2663 .rd = shift_reg,
2664 .rs1 = add_result_reg,
2665 .imm12 = Immediate.u(shift_amount),
2666 },
2667 },
2668 });
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);
26692811
2670 _ = try func.addInst(.{
2671 .tag = if (int_info.signedness == .unsigned) .srli else .srai,
2672 .ops = .rri,
2673 .data = .{
2674 .i_type = .{
2675 .rd = shift_reg,
2676 .rs1 = shift_reg,
2677 .imm12 = Immediate.u(shift_amount),
2678 },
2679 },
2680 });
2681
2682 try func.genSetMem(
2683 .{ .frame = offset.index },
2684 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2685 lhs_ty,
2686 add_result,
2687 );
2812 try func.genSetMem(
2813 .{ .frame = offset.index },
2814 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2815 ty,
2816 add_result,
2817 );
26882818
2689 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2690 defer func.register_manager.unlockReg(overflow_lock);
2819 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2820 defer func.register_manager.unlockReg(overflow_lock);
26912821
2692 try func.genBinOp(
2693 .cmp_neq,
2694 .{ .register = shift_reg },
2695 lhs_ty,
2696 .{ .register = add_result_reg },
2697 lhs_ty,
2698 overflow_reg,
2699 );
2822 try func.genBinOp(
2823 .cmp_neq,
2824 .{ .register = add_result_reg },
2825 ty,
2826 .{ .register = add_result_reg },
2827 ty,
2828 overflow_reg,
2829 );
27002830
2701 try func.genSetMem(
2702 .{ .frame = offset.index },
2703 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),
2704 Type.u1,
2705 .{ .register = overflow_reg },
2706 );
2831 try func.genSetMem(
2832 .{ .frame = offset.index },
2833 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),
2834 Type.u1,
2835 .{ .register = overflow_reg },
2836 );
27072837
2708 break :result result_mcv;
2709 } else {
2710 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
2838 break :result result_mcv;
2839 } else {
2840 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
2841 }
2842 },
2843 else => unreachable,
27112844 }
27122845 };
27132846
......@@ -3229,7 +3362,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
32293362 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, pt));
32303363 const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, pt));
32313364 const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, pt));
3232 try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef);
3365 try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .{ .undef = null });
32333366 const operand = try func.resolveInst(ty_op.operand);
32343367 try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand);
32353368 break :result .{ .load_frame = .{ .index = frame_index } };
......@@ -3451,20 +3584,54 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
34513584 else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()),
34523585 }
34533586
3587 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
3588
3589 if (array_ty.isVector(zcu)) {
3590 // we need to load the vector, vslidedown to get the element we want
3591 // and store that element at in a load frame.
3592
3593 const src_reg, const src_lock = try func.allocReg(.vector);
3594 defer func.register_manager.unlockReg(src_lock);
3595
3596 // load the vector into a temporary register
3597 try func.genCopy(array_ty, .{ .register = src_reg }, .{ .indirect = .{ .reg = addr_reg } });
3598
3599 // we need to construct a 1xbitSize vector because of how lane splitting works in RISC-V
3600 const single_ty = try pt.vectorType(.{ .child = elem_ty.toIntern(), .len = 1 });
3601
3602 // we can do a shortcut here where we don't need a vslicedown
3603 // and can just copy to the frame index.
3604 if (!(index_mcv == .immediate and index_mcv.immediate == 0)) {
3605 const index_reg = try func.copyToTmpRegister(Type.usize, index_mcv);
3606
3607 _ = try func.addInst(.{
3608 .tag = .vslidedownvx,
3609 .ops = .rrr,
3610 .data = .{ .r_type = .{
3611 .rd = src_reg,
3612 .rs1 = index_reg,
3613 .rs2 = src_reg,
3614 } },
3615 });
3616 }
3617
3618 try func.genCopy(single_ty, dst_mcv, .{ .register = src_reg });
3619 break :result dst_mcv;
3620 }
3621
34543622 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size);
34553623 const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
34563624 defer func.register_manager.unlockReg(offset_lock);
3457
3458 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
34593625 _ = try func.addInst(.{
34603626 .tag = .add,
34613627 .ops = .rrr,
34623628 .data = .{ .r_type = .{
34633629 .rd = addr_reg,
3464 .rs1 = offset_reg,
3465 .rs2 = addr_reg,
3630 .rs1 = addr_reg,
3631 .rs2 = offset_reg,
34663632 } },
34673633 });
3634
34683635 try func.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
34693636 break :result dst_mcv;
34703637 };
......@@ -3541,9 +3708,50 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
35413708}
35423709
35433710fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
3711 const pt = func.pt;
35443712 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3545 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airGetUnionTag for {}", .{func.target.cpu.arch});
3546 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3713
3714 const tag_ty = func.typeOfIndex(inst);
3715 const union_ty = func.typeOf(ty_op.operand);
3716 const layout = union_ty.unionGetLayout(pt);
3717
3718 if (layout.tag_size == 0) {
3719 return func.finishAir(inst, .none, .{ ty_op.operand, .none, .none });
3720 }
3721
3722 const operand = try func.resolveInst(ty_op.operand);
3723
3724 const frame_mcv = try func.allocRegOrMem(union_ty, null, false);
3725 try func.genCopy(union_ty, frame_mcv, operand);
3726
3727 const tag_abi_size = tag_ty.abiSize(pt);
3728 const result_reg, const result_lock = try func.allocReg(.int);
3729 defer func.register_manager.unlockReg(result_lock);
3730
3731 switch (frame_mcv) {
3732 .load_frame => |frame_addr| {
3733 if (tag_abi_size <= 8) {
3734 const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
3735 @intCast(layout.payload_size)
3736 else
3737 0;
3738
3739 try func.genCopy(
3740 tag_ty,
3741 .{ .register = result_reg },
3742 .{ .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off } },
3743 );
3744 } else {
3745 return func.fail(
3746 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}",
3747 .{ frame_mcv, tag_ty.fmt(pt) },
3748 );
3749 }
3750 },
3751 else => return func.fail("TODO: airGetUnionTag {s}", .{@tagName(operand)}),
3752 }
3753
3754 return func.finishAir(inst, .{ .register = result_reg }, .{ ty_op.operand, .none, .none });
35473755}
35483756
35493757fn airClz(func: *Func, inst: Air.Inst.Index) !void {
......@@ -3719,13 +3927,65 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void {
37193927 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
37203928}
37213929
3722fn airUnaryMath(func: *Func, inst: Air.Inst.Index) !void {
3723 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
3930fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
3931 const pt = func.pt;
37243932 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3725 const result: MCValue = if (func.liveness.isUnused(inst))
3726 .unreach
3727 else
3728 return func.fail("TODO implementairUnaryMath {s} for {}", .{ @tagName(tag), func.target.cpu.arch });
3933 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3934 const ty = func.typeOf(un_op);
3935
3936 const operand = try func.resolveInst(un_op);
3937 const operand_bit_size = ty.bitSize(pt);
3938
3939 if (!math.isPowerOfTwo(operand_bit_size))
3940 return func.fail("TODO: airUnaryMath non-pow 2", .{});
3941
3942 const operand_reg, const operand_lock = try func.promoteReg(ty, operand);
3943 defer if (operand_lock) |lock| func.register_manager.unlockReg(lock);
3944
3945 const dst_class = func.typeRegClass(ty);
3946 const dst_reg, const dst_lock = try func.allocReg(dst_class);
3947 defer func.register_manager.unlockReg(dst_lock);
3948
3949 switch (ty.zigTypeTag(pt.zcu)) {
3950 .Float => {
3951 assert(dst_class == .float);
3952
3953 switch (operand_bit_size) {
3954 16, 80, 128 => return func.fail("TODO: airUnaryMath Float bit-size {}", .{operand_bit_size}),
3955 32, 64 => {},
3956 else => unreachable,
3957 }
3958
3959 switch (tag) {
3960 .sqrt => {
3961 _ = try func.addInst(.{
3962 .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts,
3963 .ops = .rrr,
3964 .data = .{
3965 .r_type = .{
3966 .rd = dst_reg,
3967 .rs1 = operand_reg,
3968 .rs2 = .f0, // unused, spec says it's 0
3969 },
3970 },
3971 });
3972 },
3973 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
3974 }
3975 },
3976 .Int => {
3977 assert(dst_class == .int);
3978
3979 switch (tag) {
3980 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
3981 }
3982 },
3983 else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}),
3984 }
3985
3986 break :result MCValue{ .register = dst_reg };
3987 };
3988
37293989 return func.finishAir(inst, result, .{ un_op, .none, .none });
37303990}
37313991
......@@ -3987,6 +4247,10 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
39874247 });
39884248 }
39894249
4250 if (field_off == 0) {
4251 try func.truncateRegister(field_ty, dst_reg);
4252 }
4253
39904254 break :result if (field_off == 0) dst_mcv else try func.copyToNewRegister(inst, dst_mcv);
39914255 },
39924256 .load_frame => {
......@@ -4121,9 +4385,28 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
41214385 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
41224386}
41234387
4124fn airFence(func: *Func) !void {
4125 return func.fail("TODO implement fence() for {}", .{func.target.cpu.arch});
4126 //return func.finishAirBookkeeping();
4388fn airFence(func: *Func, inst: Air.Inst.Index) !void {
4389 const order = func.air.instructions.items(.data)[@intFromEnum(inst)].fence;
4390 const pred: Mir.Barrier, const succ: Mir.Barrier = switch (order) {
4391 .unordered, .monotonic => unreachable,
4392 .acquire => .{ .r, .rw },
4393 .release => .{ .rw, .r },
4394 .acq_rel => .{ .rw, .rw },
4395 .seq_cst => .{ .rw, .rw },
4396 };
4397
4398 _ = try func.addInst(.{
4399 .tag = .pseudo,
4400 .ops = .pseudo_fence,
4401 .data = .{
4402 .fence = .{
4403 .pred = pred,
4404 .succ = succ,
4405 .fm = if (order == .acq_rel) .tso else .none,
4406 },
4407 },
4408 });
4409 return func.finishAirBookkeeping();
41274410}
41284411
41294412fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
......@@ -4374,7 +4657,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
43744657 .none => {},
43754658 .register,
43764659 .register_pair,
4377 => try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op }),
4660 => {
4661 if (ret_ty.isVector(zcu)) {
4662 const bit_size = ret_ty.totalVectorBits(pt);
4663
4664 // set the vtype to hold the entire vector's contents in a single element
4665 try func.setVl(.zero, 0, .{
4666 .vsew = switch (bit_size) {
4667 8 => .@"8",
4668 16 => .@"16",
4669 32 => .@"32",
4670 64 => .@"64",
4671 else => unreachable,
4672 },
4673 .vlmul = .m1,
4674 .vma = true,
4675 .vta = true,
4676 });
4677 }
4678
4679 try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op });
4680 },
43784681 .indirect => |reg_off| {
43794682 try func.register_manager.getReg(reg_off.reg, null);
43804683 const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg);
......@@ -5224,8 +5527,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
52245527 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);
52255528 extra_i += inputs.len;
52265529
5227 log.debug("airAsm input: {any}", .{inputs});
5228
52295530 const dead = !is_volatile and func.liveness.isUnused(inst);
52305531 const result: MCValue = if (dead) .unreach else result: {
52315532 if (outputs.len > 1) {
......@@ -5599,18 +5900,34 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
55995900 const zcu = pt.zcu;
56005901 const abi_size: u32 = @intCast(ty.abiSize(pt));
56015902
5602 if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size});
5603
5903 const max_size: u32 = switch (reg.class()) {
5904 .int => 64,
5905 .float => if (func.hasFeature(.d)) 64 else 32,
5906 .vector => 64, // TODO: calculate it from avl * vsew
5907 };
5908 if (abi_size > max_size) return std.debug.panic("tried to set reg with size {}", .{abi_size});
56045909 const dst_reg_class = reg.class();
56055910
56065911 switch (src_mcv) {
5607 .dead => unreachable,
5608 .unreach, .none => return, // Nothing to do.
5609 .undef => {
5912 .unreach,
5913 .none,
5914 .dead,
5915 => unreachable,
5916 .undef => |sym_index| {
56105917 if (!func.wantSafety())
5611 return; // The already existing value will do just fine.
5612 // Write the debug undefined value.
5613 return func.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
5918 return;
5919
5920 if (sym_index) |index| {
5921 return func.genSetReg(ty, reg, .{ .load_symbol = .{ .sym = index } });
5922 }
5923
5924 switch (abi_size) {
5925 1 => return func.genSetReg(ty, reg, .{ .immediate = 0xAA }),
5926 2 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAA }),
5927 3...4 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAAAAAA }),
5928 5...8 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAAAAAAAAAAAAAA }),
5929 else => unreachable,
5930 }
56145931 },
56155932 .immediate => |unsigned_x| {
56165933 assert(dst_reg_class == .int);
......@@ -5688,11 +6005,25 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
56886005 if (src_reg.id() == reg.id())
56896006 return;
56906007
5691 const src_reg_class = src_reg.class();
5692
5693 if (src_reg_class == .float and dst_reg_class == .int) {
5694 // to move from float -> int, we use FMV.X.W
5695 return func.fail("TODO: genSetReg float -> int", .{});
6008 // there is no instruction for loading the contents of a vector register
6009 // into an integer register, however we can cheat a bit by setting the element
6010 // size to the total size of the vector, and vmv.x.s will work then
6011 if (src_reg.class() == .vector) {
6012 try func.setVl(.zero, 0, .{
6013 .vsew = switch (ty.totalVectorBits(pt)) {
6014 8 => .@"8",
6015 16 => .@"16",
6016 32 => .@"32",
6017 64 => .@"64",
6018 else => |vec_bits| return func.fail("TODO: genSetReg vec -> {s} bits {d}", .{
6019 @tagName(reg.class()),
6020 vec_bits,
6021 }),
6022 },
6023 .vlmul = .m1,
6024 .vta = true,
6025 .vma = true,
6026 });
56966027 }
56976028
56986029 // mv reg, src_reg
......@@ -5707,21 +6038,31 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
57076038 },
57086039 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
57096040 .load_frame => |frame| {
5710 _ = try func.addInst(.{
5711 .tag = .pseudo,
5712 .ops = .pseudo_load_rm,
5713 .data = .{ .rm = .{
5714 .r = reg,
5715 .m = .{
5716 .base = .{ .frame = frame.index },
5717 .mod = .{
5718 .size = func.memSize(ty),
5719 .unsigned = ty.isUnsignedInt(zcu),
5720 .disp = frame.off,
6041 if (reg.class() == .vector) {
6042 // vectors don't support an offset memory load so we need to put the true
6043 // address into a register before loading from it.
6044 const addr_reg, const addr_lock = try func.allocReg(.int);
6045 defer func.register_manager.unlockReg(addr_lock);
6046
6047 try func.genCopy(ty, .{ .register = addr_reg }, src_mcv.address());
6048 try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } });
6049 } else {
6050 _ = try func.addInst(.{
6051 .tag = .pseudo,
6052 .ops = .pseudo_load_rm,
6053 .data = .{ .rm = .{
6054 .r = reg,
6055 .m = .{
6056 .base = .{ .frame = frame.index },
6057 .mod = .{
6058 .size = func.memSize(ty),
6059 .unsigned = ty.isUnsignedInt(zcu),
6060 .disp = frame.off,
6061 },
57216062 },
5722 },
5723 } },
5724 });
6063 } },
6064 });
6065 }
57256066 },
57266067 .memory => |addr| {
57276068 try func.genSetReg(ty, reg, .{ .immediate = addr });
......@@ -5740,45 +6081,89 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
57406081 _ = try func.addInst(.{
57416082 .tag = .pseudo,
57426083 .ops = .pseudo_lea_rm,
5743 .data = .{ .rm = .{
5744 .r = reg,
5745 .m = switch (src_mcv) {
5746 .register_offset => |reg_off| .{
5747 .base = .{ .reg = reg_off.reg },
5748 .mod = .{
5749 .size = func.memSize(ty),
5750 .disp = reg_off.off,
5751 .unsigned = false,
6084 .data = .{
6085 .rm = .{
6086 .r = reg,
6087 .m = switch (src_mcv) {
6088 .register_offset => |reg_off| .{
6089 .base = .{ .reg = reg_off.reg },
6090 .mod = .{
6091 .size = .byte, // the size doesn't matter
6092 .disp = reg_off.off,
6093 .unsigned = false,
6094 },
57526095 },
5753 },
5754 .lea_frame => |frame| .{
5755 .base = .{ .frame = frame.index },
5756 .mod = .{
5757 .size = func.memSize(ty),
5758 .disp = frame.off,
5759 .unsigned = false,
6096 .lea_frame => |frame| .{
6097 .base = .{ .frame = frame.index },
6098 .mod = .{
6099 .size = .byte, // the size doesn't matter
6100 .disp = frame.off,
6101 .unsigned = false,
6102 },
57606103 },
6104 else => unreachable,
57616105 },
5762 else => unreachable,
57636106 },
5764 } },
6107 },
57656108 });
57666109 },
57676110 .indirect => |reg_off| {
5768 const float_class = dst_reg_class == .float;
6111 const load_tag: Mir.Inst.Tag = switch (reg.class()) {
6112 .float => switch (abi_size) {
6113 1 => unreachable, // Zig does not support 8-bit floats
6114 2 => return func.fail("TODO: genSetReg indirect 16-bit float", .{}),
6115 4 => .flw,
6116 8 => .fld,
6117 else => return std.debug.panic("TODO: genSetReg for float size {d}", .{abi_size}),
6118 },
6119 .int => switch (abi_size) {
6120 1 => .lb,
6121 2 => .lh,
6122 4 => .lw,
6123 8 => .ld,
6124 else => return std.debug.panic("TODO: genSetReg for int size {d}", .{abi_size}),
6125 },
6126 .vector => {
6127 assert(reg_off.off == 0);
6128
6129 // There is no vector instruction for loading with an offset to a base register,
6130 // so we need to get an offset register containing the address of the vector first
6131 // and load from it.
6132 const len = ty.vectorLen(zcu);
6133 const elem_ty = ty.childType(zcu);
6134 const elem_size = elem_ty.abiSize(pt);
6135
6136 try func.setVl(.zero, len, .{
6137 .vsew = switch (elem_size) {
6138 1 => .@"8",
6139 2 => .@"16",
6140 4 => .@"32",
6141 8 => .@"64",
6142 else => unreachable,
6143 },
6144 .vlmul = .m1,
6145 .vma = true,
6146 .vta = true,
6147 });
57696148
5770 const load_tag: Mir.Inst.Tag = switch (abi_size) {
5771 1 => if (float_class)
5772 unreachable // Zig does not support 8-bit floats
5773 else
5774 .lb,
5775 2 => if (float_class)
5776 return func.fail("TODO: genSetReg indirect 16-bit float", .{})
5777 else
5778 .lh,
5779 4 => if (float_class) .flw else .lw,
5780 8 => if (float_class) .fld else .ld,
5781 else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}),
6149 _ = try func.addInst(.{
6150 .tag = .pseudo,
6151 .ops = .pseudo_load_rm,
6152 .data = .{ .rm = .{
6153 .r = reg,
6154 .m = .{
6155 .base = .{ .reg = reg_off.reg },
6156 .mod = .{
6157 .size = func.memSize(elem_ty),
6158 .unsigned = false,
6159 .disp = 0,
6160 },
6161 },
6162 } },
6163 });
6164
6165 return;
6166 },
57826167 };
57836168
57846169 _ = try func.addInst(.{
......@@ -5793,7 +6178,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
57936178 },
57946179 .lea_symbol => |sym_off| {
57956180 assert(sym_off.off == 0);
5796
57976181 const atom_index = try func.symbolIndex();
57986182
57996183 _ = try func.addInst(.{
......@@ -5826,6 +6210,8 @@ fn genSetMem(
58266210 src_mcv: MCValue,
58276211) InnerError!void {
58286212 const pt = func.pt;
6213 const zcu = pt.zcu;
6214
58296215 const abi_size: u32 = @intCast(ty.abiSize(pt));
58306216 const dst_ptr_mcv: MCValue = switch (base) {
58316217 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
......@@ -5838,11 +6224,17 @@ fn genSetMem(
58386224 .dead,
58396225 .reserved_frame,
58406226 => unreachable,
5841 .undef => try func.genInlineMemset(
5842 dst_ptr_mcv,
5843 src_mcv,
5844 .{ .immediate = abi_size },
5845 ),
6227 .undef => |sym_index| {
6228 if (sym_index) |index| {
6229 return func.genSetMem(base, disp, ty, .{ .load_symbol = .{ .sym = index } });
6230 }
6231
6232 try func.genInlineMemset(
6233 dst_ptr_mcv,
6234 src_mcv,
6235 .{ .immediate = abi_size },
6236 );
6237 },
58466238 .register_offset,
58476239 .memory,
58486240 .indirect,
......@@ -5853,12 +6245,12 @@ fn genSetMem(
58536245 => switch (abi_size) {
58546246 0 => {},
58556247 1, 2, 4, 8 => {
5856 // no matter what type, it should use an integer register
5857 const src_reg = try func.copyToTmpRegister(Type.usize, src_mcv);
5858 const src_lock = func.register_manager.lockRegAssumeUnused(src_reg);
6248 const reg = try func.register_manager.allocReg(null, abi.Registers.Integer.temporary);
6249 const src_lock = func.register_manager.lockRegAssumeUnused(reg);
58596250 defer func.register_manager.unlockReg(src_lock);
58606251
5861 try func.genSetMem(base, disp, ty, .{ .register = src_reg });
6252 try func.genSetReg(ty, reg, src_mcv);
6253 try func.genSetMem(base, disp, ty, .{ .register = reg });
58626254 },
58636255 else => try func.genInlineMemcpy(
58646256 dst_ptr_mcv,
......@@ -5867,6 +6259,44 @@ fn genSetMem(
58676259 ),
58686260 },
58696261 .register => |reg| {
6262 if (reg.class() == .vector) {
6263 const addr_reg = try func.copyToTmpRegister(Type.usize, dst_ptr_mcv);
6264
6265 const num_elem = ty.vectorLen(zcu);
6266 const elem_size = ty.childType(zcu).bitSize(pt);
6267
6268 try func.setVl(.zero, num_elem, .{
6269 .vsew = switch (elem_size) {
6270 8 => .@"8",
6271 16 => .@"16",
6272 32 => .@"32",
6273 64 => .@"64",
6274 else => unreachable,
6275 },
6276 .vlmul = .m1,
6277 .vma = true,
6278 .vta = true,
6279 });
6280
6281 _ = try func.addInst(.{
6282 .tag = .pseudo,
6283 .ops = .pseudo_store_rm,
6284 .data = .{ .rm = .{
6285 .r = reg,
6286 .m = .{
6287 .base = .{ .reg = addr_reg },
6288 .mod = .{
6289 .disp = 0,
6290 .size = func.memSize(ty.childType(zcu)),
6291 .unsigned = false,
6292 },
6293 },
6294 } },
6295 });
6296
6297 return;
6298 }
6299
58706300 const mem_size = switch (base) {
58716301 .frame => |base_fi| mem_size: {
58726302 assert(disp >= 0);
......@@ -6042,19 +6472,161 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {
60426472}
60436473
60446474fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
6045 _ = inst;
6046 return func.fail("TODO implement airCmpxchg for {}", .{func.target.cpu.arch});
6475 const pt = func.pt;
6476 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6477 const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data;
6478
6479 const op = extra.op();
6480 const order = extra.ordering();
6481
6482 const ptr_ty = func.typeOf(pl_op.operand);
6483 const ptr_mcv = try func.resolveInst(pl_op.operand);
6484
6485 const val_ty = func.typeOf(extra.operand);
6486 const val_size = val_ty.abiSize(pt);
6487 const val_mcv = try func.resolveInst(extra.operand);
6488
6489 if (!math.isPowerOfTwo(val_size))
6490 return func.fail("TODO: airAtomicRmw non-pow 2", .{});
6491
6492 switch (val_ty.zigTypeTag(pt.zcu)) {
6493 .Int => {},
6494 inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}),
6495 else => unreachable,
6496 }
6497
6498 switch (val_size) {
6499 1, 2 => return func.fail("TODO: airAtomicRmw Int {}", .{val_size}),
6500 4, 8 => {},
6501 else => unreachable,
6502 }
6503
6504 const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv);
6505 defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock);
6506
6507 const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv);
6508 defer if (val_lock) |lock| func.register_manager.unlockReg(lock);
6509
6510 const result_mcv = try func.allocRegOrMem(val_ty, inst, true);
6511 assert(result_mcv == .register); // should fit into 8 bytes
6512
6513 const aq, const rl = switch (order) {
6514 .unordered => unreachable,
6515 .monotonic => .{ false, false },
6516 .acquire => .{ true, false },
6517 .release => .{ false, true },
6518 .acq_rel => .{ true, true },
6519 .seq_cst => .{ true, true },
6520 };
6521
6522 _ = try func.addInst(.{
6523 .tag = .pseudo,
6524 .ops = .pseudo_amo,
6525 .data = .{ .amo = .{
6526 .rd = result_mcv.register,
6527 .rs1 = ptr_register,
6528 .rs2 = val_register,
6529 .aq = if (aq) .aq else .none,
6530 .rl = if (rl) .rl else .none,
6531 .op = switch (op) {
6532 .Xchg => .SWAP,
6533 .Add => .ADD,
6534 .Sub => return func.fail("TODO: airAtomicRmw SUB", .{}),
6535 .And => .AND,
6536 .Nand => return func.fail("TODO: airAtomicRmw NAND", .{}),
6537 .Or => .OR,
6538 .Xor => .XOR,
6539 .Max => .MAX,
6540 .Min => .MIN,
6541 },
6542 .ty = val_ty,
6543 } },
6544 });
6545
6546 return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none });
60476547}
60486548
60496549fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
6050 _ = inst;
6051 return func.fail("TODO implement airAtomicLoad for {}", .{func.target.cpu.arch});
6550 const zcu = func.pt.zcu;
6551 const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
6552 const order: std.builtin.AtomicOrder = atomic_load.order;
6553
6554 const ptr_ty = func.typeOf(atomic_load.ptr);
6555 const elem_ty = ptr_ty.childType(zcu);
6556 const ptr_mcv = try func.resolveInst(atomic_load.ptr);
6557
6558 const result_mcv = try func.allocRegOrMem(elem_ty, inst, true);
6559 assert(result_mcv == .register); // should be less than 8 bytes
6560
6561 if (order == .seq_cst) {
6562 _ = try func.addInst(.{
6563 .tag = .pseudo,
6564 .ops = .pseudo_fence,
6565 .data = .{
6566 .fence = .{
6567 .pred = .rw,
6568 .succ = .rw,
6569 .fm = .none,
6570 },
6571 },
6572 });
6573 }
6574
6575 try func.load(result_mcv, ptr_mcv, ptr_ty);
6576
6577 switch (order) {
6578 // Don't guarnetee other memory operations to be ordered after the load.
6579 .unordered => {},
6580 .monotonic => {},
6581 // Make sure all previous reads happen before any reading or writing accurs.
6582 .seq_cst, .acquire => {
6583 _ = try func.addInst(.{
6584 .tag = .pseudo,
6585 .ops = .pseudo_fence,
6586 .data = .{
6587 .fence = .{
6588 .pred = .r,
6589 .succ = .rw,
6590 .fm = .none,
6591 },
6592 },
6593 });
6594 },
6595 else => unreachable,
6596 }
6597
6598 return func.finishAir(inst, result_mcv, .{ atomic_load.ptr, .none, .none });
60526599}
60536600
60546601fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
6055 _ = inst;
6056 _ = order;
6057 return func.fail("TODO implement airAtomicStore for {}", .{func.target.cpu.arch});
6602 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6603
6604 const ptr_ty = func.typeOf(bin_op.lhs);
6605 const ptr_mcv = try func.resolveInst(bin_op.lhs);
6606
6607 const val_ty = func.typeOf(bin_op.rhs);
6608 const val_mcv = try func.resolveInst(bin_op.rhs);
6609
6610 switch (order) {
6611 .unordered, .monotonic => {},
6612 .release, .seq_cst => {
6613 _ = try func.addInst(.{
6614 .tag = .pseudo,
6615 .ops = .pseudo_fence,
6616 .data = .{
6617 .fence = .{
6618 .pred = .rw,
6619 .succ = .w,
6620 .fm = .none,
6621 },
6622 },
6623 });
6624 },
6625 else => unreachable,
6626 }
6627
6628 try func.store(ptr_mcv, val_mcv, ptr_ty, val_ty);
6629 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
60586630}
60596631
60606632fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
......@@ -6441,18 +7013,39 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
64417013
64427014fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
64437015 const pt = func.pt;
6444 const zcu = pt.zcu;
7016 const gpa = func.gpa;
7017
7018 const owner_decl_index = pt.zcu.funcOwnerDeclIndex(func.func_index);
7019 const lf = func.bin_file;
7020 const src_loc = func.src_loc;
7021
7022 if (val.isUndef(pt.zcu)) {
7023 const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| {
7024 const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)});
7025 func.err_msg = msg;
7026 return error.CodegenFail;
7027 };
7028 switch (lf.tag) {
7029 .elf => {
7030 const elf_file = lf.cast(link.File.Elf).?;
7031 const local = elf_file.symbol(local_sym_index);
7032 return MCValue{ .undef = local.esym_index };
7033 },
7034 else => unreachable,
7035 }
7036 }
7037
64457038 const result = try codegen.genTypedValue(
6446 func.bin_file,
7039 lf,
64477040 pt,
6448 func.src_loc,
7041 src_loc,
64497042 val,
6450 zcu.funcOwnerDeclIndex(func.func_index),
7043 owner_decl_index,
64517044 );
64527045 const mcv: MCValue = switch (result) {
64537046 .mcv => |mcv| switch (mcv) {
64547047 .none => .none,
6455 .undef => .undef,
7048 .undef => unreachable,
64567049 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
64577050 .immediate => |imm| .{ .immediate = imm },
64587051 .memory => |addr| .{ .memory = addr },
......@@ -6670,9 +7263,7 @@ fn parseRegName(name: []const u8) ?Register {
66707263}
66717264
66727265fn typeOf(func: *Func, inst: Air.Inst.Ref) Type {
6673 const pt = func.pt;
6674 const zcu = pt.zcu;
6675 return func.air.typeOf(inst, &zcu.intern_pool);
7266 return func.air.typeOf(inst, &func.pt.zcu.intern_pool);
66767267}
66777268
66787269fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type {
src/arch/riscv64/Emit.zig+2-2
......@@ -26,7 +26,7 @@ pub fn emitMir(emit: *Emit) Error!void {
2626 mir_index,
2727 @intCast(emit.code.items.len),
2828 );
29 const lowered = try emit.lower.lowerMir(mir_index);
29 const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true });
3030 var lowered_relocs = lowered.relocs;
3131 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
3232 const start_offset: u32 = @intCast(emit.code.items.len);
......@@ -75,7 +75,7 @@ pub fn emitMir(emit: *Emit) Error!void {
7575 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,
7676 .r_addend = 0,
7777 });
78 } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{});
78 } else unreachable;
7979 },
8080 .call_extern_fn_reloc => |symbol| {
8181 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
src/arch/riscv64/Encoding.zig+376-40
......@@ -2,37 +2,55 @@ mnemonic: Mnemonic,
22data: Data,
33
44const OpCode = enum(u7) {
5 OP = 0b0110011,
5 LOAD = 0b0000011,
6 LOAD_FP = 0b0000111,
7 MISC_MEM = 0b0001111,
68 OP_IMM = 0b0010011,
9 AUIPC = 0b0010111,
710 OP_IMM_32 = 0b0011011,
8 OP_32 = 0b0111011,
9
10 BRANCH = 0b1100011,
11 LOAD = 0b0000011,
1211 STORE = 0b0100011,
13 SYSTEM = 0b1110011,
14
15 OP_FP = 0b1010011,
16 LOAD_FP = 0b0000111,
1712 STORE_FP = 0b0100111,
18
19 JALR = 0b1100111,
20 AUIPC = 0b0010111,
13 AMO = 0b0101111,
14 OP_V = 0b1010111,
15 OP = 0b0110011,
16 OP_32 = 0b0111011,
2117 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,
2226 JAL = 0b1101111,
23 NONE = 0b0000000,
27 SYSTEM = 0b1110011,
28 OP_64 = 0b1111011,
29 NONE = 0b00000000,
2430};
2531
26const Fmt = enum(u2) {
32const FpFmt = enum(u2) {
2733 /// 32-bit single-precision
2834 S = 0b00,
2935 /// 64-bit double-precision
3036 D = 0b01,
31 _reserved = 0b10,
37
38 // H = 0b10, unused in the G extension
39
3240 /// 128-bit quad-precision
3341 Q = 0b11,
3442};
3543
44const AmoWidth = enum(u3) {
45 W = 0b010,
46 D = 0b011,
47};
48
49const FenceMode = enum(u4) {
50 none = 0b0000,
51 tso = 0b1000,
52};
53
3654const Enc = struct {
3755 opcode: OpCode,
3856
......@@ -42,11 +60,19 @@ const Enc = struct {
4260 funct3: u3,
4361 funct7: u7,
4462 },
63 amo: struct {
64 funct5: u5,
65 width: AmoWidth,
66 },
67 fence: struct {
68 funct3: u3,
69 fm: FenceMode,
70 },
4571 /// funct5 + rm + fmt
4672 fmt: struct {
4773 funct5: u5,
4874 rm: u3,
49 fmt: Fmt,
75 fmt: FpFmt,
5076 },
5177 /// funct3
5278 f: struct {
......@@ -58,9 +84,55 @@ const Enc = struct {
5884 funct3: u3,
5985 has_5: bool,
6086 },
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 },
61100 /// U-type
62101 none,
63102 },
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 };
64136};
65137
66138pub const Mnemonic = enum {
......@@ -90,6 +162,9 @@ pub const Mnemonic = enum {
90162 addi,
91163 jalr,
92164
165 vsetivli,
166 vsetvli,
167
93168 // U Type
94169 lui,
95170 auipc,
......@@ -130,6 +205,8 @@ pub const Mnemonic = enum {
130205 ebreak,
131206 unimp,
132207
208 csrrs,
209
133210 // M extension
134211 mul,
135212 mulw,
......@@ -192,6 +269,58 @@ pub const Mnemonic = enum {
192269 fsgnjnd,
193270 fsgnjxd,
194271
272 // V Extension
273 vle8v,
274 vle16v,
275 vle32v,
276 vle64v,
277
278 vse8v,
279 vse16v,
280 vse32v,
281 vse64v,
282
283 vsoxei8v,
284
285 vaddvv,
286 vsubvv,
287
288 vfaddvv,
289 vfsubvv,
290
291 vadcvv,
292
293 vmvvx,
294
295 vslidedownvx,
296
297 // MISC
298 fence,
299 fencetso,
300
301 // AMO
302 amoswapw,
303 amoaddw,
304 amoandw,
305 amoorw,
306 amoxorw,
307 amomaxw,
308 amominw,
309 amomaxuw,
310 amominuw,
311
312 amoswapd,
313 amoaddd,
314 amoandd,
315 amoord,
316 amoxord,
317 amomaxd,
318 amomind,
319 amomaxud,
320 amominud,
321
322 // TODO: Q extension
323
195324 pub fn encoding(mnem: Mnemonic) Enc {
196325 return switch (mnem) {
197326 // zig fmt: off
......@@ -322,14 +451,25 @@ pub const Mnemonic = enum {
322451 // LOAD_FP
323452
324453 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
325 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
454 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
455
456 .vle8v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
457 .vle16v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
458 .vle32v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
459 .vle64v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
326460
327461
328462 // STORE_FP
329463
330 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
331 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
464 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
465 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
332466
467 .vse8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
468 .vse16v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
469 .vse32v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
470 .vse64v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
471
472 .vsoxei8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .ord, .mew = false, .nf = 0b000 } } },
333473
334474 // JALR
335475
......@@ -360,6 +500,8 @@ pub const Mnemonic = enum {
360500
361501 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
362502 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
503
504 .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } },
363505
364506
365507 // NONE
......@@ -367,6 +509,52 @@ pub const Mnemonic = enum {
367509 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
368510
369511
512 // MISC_MEM
513
514 .fence => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } },
515 .fencetso => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } },
516
517
518 // AMO
519
520 .amoaddw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } },
521 .amoswapw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } },
522 // LR.W
523 // SC.W
524 .amoxorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } },
525 .amoandw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } },
526 .amoorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } },
527 .amominw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } },
528 .amomaxw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } },
529 .amominuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } },
530 .amomaxuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } },
531
532 .amoaddd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } },
533 .amoswapd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } },
534 // LR.D
535 // SC.D
536 .amoxord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } },
537 .amoandd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } },
538 .amoord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } },
539 .amomind => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } },
540 .amomaxd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } },
541 .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
542 .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
543
544 // OP_V
545 .vsetivli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
546 .vsetvli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
547 .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
548 .vsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },
549
550 .vfaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPFVV } } },
551 .vfsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPFVV } } },
552
553 .vadcvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
554 .vmvvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },
555
556 .vslidedownvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b001111, .funct3 = .OPIVX } } },
557
370558 // zig fmt: on
371559 };
372560 }
......@@ -380,8 +568,8 @@ pub const InstEnc = enum {
380568 B,
381569 U,
382570 J,
383
384 /// extras that have unusual op counts
571 fence,
572 amo,
385573 system,
386574
387575 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
......@@ -410,6 +598,10 @@ pub const InstEnc = enum {
410598
411599 .flw,
412600 .fld,
601
602 .csrrs,
603 .vsetivli,
604 .vsetvli,
413605 => .I,
414606
415607 .lui,
......@@ -503,26 +695,73 @@ pub const InstEnc = enum {
503695
504696 .fsgnjxs,
505697 .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,
506718 => .R,
507719
508720 .ecall,
509721 .ebreak,
510722 .unimp,
511723 => .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,
512749 };
513750 }
514751
515 pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {
752 pub fn opsList(enc: InstEnc) [5]std.meta.FieldEnum(Operand) {
516753 return switch (enc) {
517754 // zig fmt: off
518 .R => .{ .reg, .reg, .reg, .none },
519 .R4 => .{ .reg, .reg, .reg, .reg },
520 .I => .{ .reg, .reg, .imm, .none },
521 .S => .{ .reg, .reg, .imm, .none },
522 .B => .{ .reg, .reg, .imm, .none },
523 .U => .{ .reg, .imm, .none, .none },
524 .J => .{ .reg, .imm, .none, .none },
525 .system => .{ .none, .none, .none, .none },
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 },
526765 // zig fmt: on
527766 };
528767 }
......@@ -584,20 +823,38 @@ pub const Data = union(InstEnc) {
584823 imm1_10: u10,
585824 imm20: u1,
586825 },
587 system: void,
826 fence: packed struct {
827 opcode: u7,
828 rd: u5 = 0,
829 funct3: u3,
830 rs1: u5 = 0,
831 succ: u4,
832 pred: u4,
833 fm: u4,
834 },
835 amo: packed struct {
836 opcode: u7,
837 rd: u5,
838 funct3: u3,
839 rs1: u5,
840 rs2: u5,
841 rl: bool,
842 aq: bool,
843 funct5: u5,
844 },
845 system: u32,
846
847 comptime {
848 for (std.meta.fields(Data)) |field| {
849 assert(@bitSizeOf(field.type) == 32);
850 }
851 }
588852
589853 pub fn toU32(self: Data) u32 {
590854 return switch (self) {
591 // zig fmt: off
592 .R => |v| @bitCast(v),
593 .R4 => |v| @bitCast(v),
594 .I => |v| @bitCast(v),
595 .S => |v| @bitCast(v),
596 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),
597 .U => |v| @bitCast(v),
598 .J => |v| @bitCast(v),
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),
599857 .system => unreachable,
600 // zig fmt: on
601858 };
602859 }
603860
......@@ -628,6 +885,25 @@ pub const Data = union(InstEnc) {
628885 },
629886 };
630887 },
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 },
631907 else => {},
632908 }
633909
......@@ -654,6 +930,25 @@ pub const Data = union(InstEnc) {
654930 .funct3 = fmt.rm,
655931 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
656932 },
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 },
657952 else => unreachable,
658953 },
659954 };
......@@ -748,7 +1043,48 @@ pub const Data = union(InstEnc) {
7481043 },
7491044 };
7501045 },
1046 .fence => {
1047 assert(ops.len == 2);
1048
1049 const succ = ops[0].barrier;
1050 const pred = ops[1].barrier;
1051
1052 return .{
1053 .fence = .{
1054 .succ = @intFromEnum(succ),
1055 .pred = @intFromEnum(pred),
1056
1057 .opcode = @intFromEnum(enc.opcode),
1058 .funct3 = enc.data.fence.funct3,
1059 .fm = @intFromEnum(enc.data.fence.fm),
1060 },
1061 };
1062 },
1063 .amo => {
1064 assert(ops.len == 5);
1065
1066 const rd = ops[0].reg;
1067 const rs1 = ops[1].reg;
1068 const rs2 = ops[2].reg;
1069 const rl = ops[3].barrier;
1070 const aq = ops[4].barrier;
7511071
1072 return .{
1073 .amo = .{
1074 .rd = rd.encodeId(),
1075 .rs1 = rs1.encodeId(),
1076 .rs2 = rs2.encodeId(),
1077
1078 // TODO: https://github.com/ziglang/zig/issues/20113
1079 .rl = if (rl == .rl) true else false,
1080 .aq = if (aq == .aq) true else false,
1081
1082 .opcode = @intFromEnum(enc.opcode),
1083 .funct3 = @intFromEnum(enc.data.amo.width),
1084 .funct5 = enc.data.amo.funct5,
1085 },
1086 };
1087 },
7521088 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
7531089 }
7541090 }
src/arch/riscv64/Lower.zig+171-59
......@@ -40,7 +40,9 @@ pub const Reloc = struct {
4040};
4141
4242/// The returned slice is overwritten by the next call to lowerMir.
43pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
43pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
44 allow_frame_locs: bool,
45}) Error!struct {
4446 insts: []const Instruction,
4547 relocs: []const Reloc,
4648} {
......@@ -69,64 +71,102 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
6971 .pseudo_load_rm, .pseudo_store_rm => {
7072 const rm = inst.data.rm;
7173
72 const frame_loc = rm.m.toFrameLoc(lower.mir);
74 const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs)
75 rm.m.toFrameLoc(lower.mir)
76 else
77 .{ .base = .s0, .disp = 0 };
7378
7479 switch (inst.ops) {
7580 .pseudo_load_rm => {
7681 const dest_reg = rm.r;
7782 const dest_reg_class = dest_reg.class();
78 const float = dest_reg_class == .float;
7983
8084 const src_size = rm.m.mod.size;
8185 const unsigned = rm.m.mod.unsigned;
8286
83 const tag: Encoding.Mnemonic = if (!float)
84 switch (src_size) {
87 const tag: Encoding.Mnemonic = switch (dest_reg_class) {
88 .int => switch (src_size) {
8589 .byte => if (unsigned) .lbu else .lb,
8690 .hword => if (unsigned) .lhu else .lh,
8791 .word => if (unsigned) .lwu else .lw,
8892 .dword => .ld,
89 }
90 else switch (src_size) {
91 .byte => unreachable, // Zig does not support 8-bit floats
92 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
93 .word => .flw,
94 .dword => .fld,
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 },
95106 };
96107
97 try lower.emit(tag, &.{
98 .{ .reg = rm.r },
99 .{ .reg = frame_loc.base },
100 .{ .imm = Immediate.s(frame_loc.disp) },
101 });
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 }
102125 },
103126 .pseudo_store_rm => {
104127 const src_reg = rm.r;
105128 const src_reg_class = src_reg.class();
106 const float = src_reg_class == .float;
107129
108 // TODO: do we actually need this? are all stores not usize?
109130 const dest_size = rm.m.mod.size;
110131
111 const tag: Encoding.Mnemonic = if (!float)
112 switch (dest_size) {
132 const tag: Encoding.Mnemonic = switch (src_reg_class) {
133 .int => switch (dest_size) {
113134 .byte => .sb,
114135 .hword => .sh,
115136 .word => .sw,
116137 .dword => .sd,
117 }
118 else switch (dest_size) {
119 .byte => unreachable, // Zig does not support 8-bit floats
120 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
121 .word => .fsw,
122 .dword => .fsd,
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 },
123151 };
124152
125 try lower.emit(tag, &.{
126 .{ .reg = frame_loc.base },
127 .{ .reg = rm.r },
128 .{ .imm = Immediate.s(frame_loc.disp) },
129 });
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 }
130170 },
131171 else => unreachable,
132172 }
......@@ -138,34 +178,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
138178 const dst_class = rr.rd.class();
139179 const src_class = rr.rs.class();
140180
141 assert(dst_class == src_class);
142
143 switch (dst_class) {
144 .float => {
145 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
146 .{ .reg = rr.rd },
147 .{ .reg = rr.rs },
148 .{ .reg = rr.rs },
149 });
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 });
189 },
190 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),
150191 },
151 .int => {
152 try lower.emit(.addi, &.{
153 .{ .reg = rr.rd },
154 .{ .reg = rr.rs },
155 .{ .imm = Immediate.s(0) },
156 });
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 });
199 },
200 .vector => {
201 try lower.emit(.vmvvx, &.{
202 .{ .reg = rr.rd },
203 .{ .reg = rr.rs },
204 .{ .reg = .x0 },
205 });
206 },
207 .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}),
208 },
209 .vector => switch (dst_class) {
210 .int => {
211 try lower.emit(.vadcvv, &.{
212 .{ .reg = rr.rd },
213 .{ .reg = .zero },
214 .{ .reg = rr.rs },
215 });
216 },
217 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),
157218 },
158219 }
159220 },
160221
161 .pseudo_ret => {
162 try lower.emit(.jalr, &.{
163 .{ .reg = .zero },
164 .{ .reg = .ra },
165 .{ .imm = Immediate.s(0) },
166 });
167 },
168
169222 .pseudo_j => {
170223 try lower.emit(.jal, &.{
171224 .{ .reg = .zero },
......@@ -204,7 +257,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
204257 const rm = inst.data.rm;
205258 assert(rm.r.class() == .int);
206259
207 const frame = rm.m.toFrameLoc(lower.mir);
260 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
261 rm.m.toFrameLoc(lower.mir)
262 else
263 .{ .base = .s0, .disp = 0 };
208264
209265 try lower.emit(.addi, &.{
210266 .{ .reg = rm.r },
......@@ -371,6 +427,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
371427 });
372428 },
373429 },
430 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),
374431 }
375432 },
376433
......@@ -378,7 +435,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
378435 const rr = inst.data.rr;
379436 assert(rr.rs.class() == .int and rr.rd.class() == .int);
380437
381 try lower.emit(.xori, &.{
438 // mask out any other bits that aren't the boolean
439 try lower.emit(.andi, &.{
440 .{ .reg = rr.rs },
441 .{ .reg = rr.rs },
442 .{ .imm = Immediate.s(1) },
443 });
444
445 try lower.emit(.sltiu, &.{
382446 .{ .reg = rr.rd },
383447 .{ .reg = rr.rs },
384448 .{ .imm = Immediate.s(1) },
......@@ -405,6 +469,44 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
405469 });
406470 },
407471
472 .pseudo_amo => {
473 const amo = inst.data.amo;
474 const is_d = amo.ty.abiSize(pt) == 8;
475 const is_un = amo.ty.isUnsignedInt(pt.zcu);
476
477 const mnem: Encoding.Mnemonic = switch (amo.op) {
478 // zig fmt: off
479 .SWAP => if (is_d) .amoswapd else .amoswapw,
480 .ADD => if (is_d) .amoaddd else .amoaddw,
481 .AND => if (is_d) .amoandd else .amoandw,
482 .OR => if (is_d) .amoord else .amoorw,
483 .XOR => if (is_d) .amoxord else .amoxorw,
484 .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw,
485 .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw,
486 // zig fmt: on
487 };
488
489 try lower.emit(mnem, &.{
490 .{ .reg = inst.data.amo.rd },
491 .{ .reg = inst.data.amo.rs1 },
492 .{ .reg = inst.data.amo.rs2 },
493 .{ .barrier = inst.data.amo.rl },
494 .{ .barrier = inst.data.amo.aq },
495 });
496 },
497
498 .pseudo_fence => {
499 const fence = inst.data.fence;
500
501 try lower.emit(switch (fence.fm) {
502 .tso => .fencetso,
503 .none => .fence,
504 }, &.{
505 .{ .barrier = fence.succ },
506 .{ .barrier = fence.pred },
507 });
508 },
509
408510 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
409511 },
410512 }
......@@ -447,6 +549,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
447549 .{ .reg = inst.data.r_type.rs1 },
448550 .{ .reg = inst.data.r_type.rs2 },
449551 },
552 .csr => &.{
553 .{ .csr = inst.data.csr.csr },
554 .{ .reg = inst.data.csr.rs1 },
555 .{ .reg = inst.data.csr.rd },
556 },
450557 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
451558 });
452559}
......@@ -473,17 +580,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
473580 while (it.next()) |i| {
474581 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));
475582 const reg = abi.Registers.all_preserved[i];
583
476584 const reg_class = reg.class();
477 const is_float_reg = reg_class == .float;
585 const load_inst: Encoding.Mnemonic, const store_inst: Encoding.Mnemonic = switch (reg_class) {
586 .int => .{ .ld, .sd },
587 .float => .{ .fld, .fsd },
588 .vector => unreachable,
589 };
478590
479591 if (spilling) {
480 try lower.emit(if (is_float_reg) .fsd else .sd, &.{
592 try lower.emit(store_inst, &.{
481593 .{ .reg = frame.base },
482594 .{ .reg = abi.Registers.all_preserved[i] },
483595 .{ .imm = Immediate.s(frame.disp + reg_i) },
484596 });
485597 } else {
486 try lower.emit(if (is_float_reg) .fld else .ld, &.{
598 try lower.emit(load_inst, &.{
487599 .{ .reg = abi.Registers.all_preserved[i] },
488600 .{ .reg = frame.base },
489601 .{ .imm = Immediate.s(frame.disp + reg_i) },
src/arch/riscv64/Mir.zig+70-48
......@@ -31,6 +31,7 @@ pub const Inst = struct {
3131 @"and",
3232 andi,
3333
34 xori,
3435 xor,
3536 @"or",
3637
......@@ -133,6 +134,19 @@ pub const Inst = struct {
133134 fltd,
134135 fled,
135136
137 // Zicsr Extension Instructions
138 csrrs,
139
140 // V Extension Instructions
141 vsetvli,
142 vsetivli,
143 vsetvl,
144 vaddvv,
145 vfaddvv,
146 vsubvv,
147 vfsubvv,
148 vslidedownvx,
149
136150 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
137151 /// assembly instruction.
138152 pseudo,
......@@ -142,91 +156,57 @@ pub const Inst = struct {
142156 /// this union. `Ops` determines which union field is active, as well as
143157 /// how to interpret the data within.
144158 pub const Data = union {
145 /// No additional data
146 ///
147 /// Used by e.g. ebreak
148159 nop: void,
149 /// Another instruction.
150 ///
151 /// Used by e.g. b
152160 inst: Index,
153 /// Index into `extra`. Meaning of what can be found there is context-dependent.
154 ///
155 /// Used by e.g. load_memory
156161 payload: u32,
157
158162 r_type: struct {
159163 rd: Register,
160164 rs1: Register,
161165 rs2: Register,
162166 },
163
164167 i_type: struct {
165168 rd: Register,
166169 rs1: Register,
167170 imm12: Immediate,
168171 },
169
170172 s_type: struct {
171173 rs1: Register,
172174 rs2: Register,
173175 imm5: Immediate,
174176 imm7: Immediate,
175177 },
176
177178 b_type: struct {
178179 rs1: Register,
179180 rs2: Register,
180181 inst: Inst.Index,
181182 },
182
183183 u_type: struct {
184184 rd: Register,
185185 imm20: Immediate,
186186 },
187
188187 j_type: struct {
189188 rd: Register,
190189 inst: Inst.Index,
191190 },
192
193 /// Debug info: line and column
194 ///
195 /// Used by e.g. pseudo_dbg_line
196191 pseudo_dbg_line_column: struct {
197192 line: u32,
198193 column: u32,
199194 },
200
201 // Custom types to be lowered
202
203 /// Register + Memory
204195 rm: struct {
205196 r: Register,
206197 m: Memory,
207198 },
208
209199 reg_list: Mir.RegisterList,
210
211 /// A register
212 ///
213 /// Used by e.g. blr
214200 reg: Register,
215
216 /// Two registers
217 ///
218 /// Used by e.g. mv
219201 rr: struct {
220202 rd: Register,
221203 rs: Register,
222204 },
223
224205 fabs: struct {
225206 rd: Register,
226207 rs: Register,
227208 bits: u16,
228209 },
229
230210 compare: struct {
231211 rd: Register,
232212 rs1: Register,
......@@ -241,11 +221,32 @@ pub const Inst = struct {
241221 },
242222 ty: Type,
243223 },
244
245224 reloc: struct {
246225 atom_index: u32,
247226 sym_index: u32,
248227 },
228 fence: struct {
229 pred: Barrier,
230 succ: Barrier,
231 fm: enum {
232 none,
233 tso,
234 },
235 },
236 amo: struct {
237 rd: Register,
238 rs1: Register,
239 rs2: Register,
240 aq: Barrier,
241 rl: Barrier,
242 op: AmoOp,
243 ty: Type,
244 },
245 csr: struct {
246 csr: CSR,
247 rs1: Register,
248 rd: Register,
249 },
249250 };
250251
251252 pub const Ops = enum {
......@@ -270,6 +271,9 @@ pub const Inst = struct {
270271 /// Another instruction.
271272 inst,
272273
274 /// Control and Status Register Instruction.
275 csr,
276
273277 /// Pseudo-instruction that will generate a backpatched
274278 /// function prologue.
275279 pseudo_prologue,
......@@ -298,11 +302,6 @@ pub const Inst = struct {
298302 /// Uses `rm` payload.
299303 pseudo_lea_rm,
300304
301 /// Shorthand for returning, aka jumping to ra register.
302 ///
303 /// Uses nop payload.
304 pseudo_ret,
305
306305 /// Jumps. Uses `inst` payload.
307306 pseudo_j,
308307
......@@ -326,19 +325,19 @@ pub const Inst = struct {
326325 pseudo_spill_regs,
327326
328327 pseudo_compare,
328
329 /// NOT operation on booleans. Does an `andi reg, reg, 1` to mask out any other bits from the boolean.
329330 pseudo_not,
330331
331332 /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc
332333 pseudo_extern_fn_reloc,
333 };
334334
335 // Make sure we don't accidentally make instructions bigger than expected.
336 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
337 // comptime {
338 // if (builtin.mode != .Debug) {
339 // assert(@sizeOf(Inst) == 8);
340 // }
341 // }
335 /// IORW, IORW
336 pseudo_fence,
337
338 /// Ordering, Src, Addr, Dest
339 pseudo_amo,
340 };
342341
343342 pub fn format(
344343 inst: Inst,
......@@ -365,6 +364,28 @@ pub const FrameLoc = struct {
365364 disp: i32,
366365};
367366
367pub const Barrier = enum(u4) {
368 // Fence
369 w = 0b0001,
370 r = 0b0010,
371 rw = 0b0011,
372
373 // Amo
374 none,
375 aq,
376 rl,
377};
378
379pub const AmoOp = enum(u5) {
380 SWAP,
381 ADD,
382 AND,
383 OR,
384 XOR,
385 MAX,
386 MIN,
387};
388
368389/// Returns the requested data, as well as the new index which is at the start of the
369390/// trailers for the object.
370391pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
......@@ -437,6 +458,7 @@ const assert = std.debug.assert;
437458
438459const bits = @import("bits.zig");
439460const Register = bits.Register;
461const CSR = bits.CSR;
440462const Immediate = bits.Immediate;
441463const Memory = bits.Memory;
442464const FrameIndex = bits.FrameIndex;
src/arch/riscv64/abi.zig+24-2
......@@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass {
193193 }
194194 return memory_class;
195195 },
196 .Vector => {
197 // we pass vectors through integer registers if they are small enough to fit.
198 const vec_bits = ty.totalVectorBits(pt);
199 if (vec_bits <= 64) {
200 result[0] = .integer;
201 return result;
202 }
203 return memory_class;
204 },
196205 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
197206 }
198207}
......@@ -254,15 +263,15 @@ fn classifyStruct(
254263 }
255264}
256265
257const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs;
266const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs ++ Registers.Vector.all_regs;
258267pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
259268
260// Register classes
261269const RegisterBitSet = RegisterManager.RegisterBitSet;
262270
263271pub const RegisterClass = enum {
264272 int,
265273 float,
274 vector,
266275};
267276
268277pub const Registers = struct {
......@@ -322,6 +331,19 @@ pub const Registers = struct {
322331
323332 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
324333 };
334
335 pub const Vector = struct {
336 pub const general_purpose = initRegBitSet(Integer.all_regs.len + Float.all_regs.len, all_regs.len);
337
338 // zig fmt: off
339 pub const all_regs = [_]Register{
340 .v0, .v1, .v2, .v3, .v4, .v5, .v6, .v7,
341 .v8, .v9, .v10, .v11, .v12, .v13, .v14, .v15,
342 .v16, .v17, .v18, .v19, .v20, .v21, .v22, .v23,
343 .v24, .v25, .v26, .v27, .v28, .v29, .v30, .v31,
344 };
345 // zig fmt: on
346 };
325347};
326348
327349fn initRegBitSet(start: usize, length: usize) RegisterBitSet {
src/arch/riscv64/bits.zig+42-2
......@@ -41,7 +41,7 @@ pub const Memory = struct {
4141 2...2 => .hword,
4242 3...4 => .word,
4343 5...8 => .dword,
44 else => unreachable,
44 else => std.debug.panic("fromByteSize {}", .{size}),
4545 };
4646 }
4747
......@@ -128,6 +128,12 @@ pub const Immediate = union(enum) {
128128 }
129129};
130130
131pub const CSR = enum(u12) {
132 vl = 0xC20,
133 vtype = 0xC21,
134 vlenb = 0xC22,
135};
136
131137pub const Register = enum(u8) {
132138 // zig fmt: off
133139
......@@ -169,6 +175,13 @@ pub const Register = enum(u8) {
169175 f16, f17, f18, f19, f20, f21, f22, f23,
170176 f24, f25, f26, f27, f28, f29, f30, f31,
171177
178
179 // V extension registers
180 v0, v1, v2, v3, v4, v5, v6, v7,
181 v8, v9, v10, v11, v12, v13, v14, v15,
182 v16, v17, v18, v19, v20, v21, v22, v23,
183 v24, v25, v26, v27, v28, v29, v30, v31,
184
172185 // zig fmt: on
173186
174187 /// in RISC-V registers are stored as 5 bit IDs and a register can have
......@@ -180,11 +193,12 @@ pub const Register = enum(u8) {
180193 /// The goal of this function is to return the same ID for `zero` and `x0` but two
181194 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers
182195 /// and is repeated twice, once for the named version, once for the number version.
183 pub fn id(reg: Register) u7 {
196 pub fn id(reg: Register) u8 {
184197 const base = switch (@intFromEnum(reg)) {
185198 // zig fmt: off
186199 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),
187200 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0),
201 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => @intFromEnum(Register.v0),
188202 else => unreachable,
189203 // zig fmt: on
190204 };
......@@ -207,6 +221,7 @@ pub const Register = enum(u8) {
207221 // zig fmt: off
208222 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
209223 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,
224 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => 256, // TODO: look at suggestVectorSize
210225 else => unreachable,
211226 // zig fmt: on
212227 };
......@@ -217,6 +232,7 @@ pub const Register = enum(u8) {
217232 // zig fmt: off
218233 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int,
219234 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float,
235 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => .vector,
220236 else => unreachable,
221237 // zig fmt: on
222238 };
......@@ -272,3 +288,27 @@ pub const Symbol = struct {
272288 /// Index into the linker's symbol table.
273289 sym_index: u32,
274290};
291
292pub const VType = packed struct(u8) {
293 vlmul: VlMul,
294 vsew: VSew,
295 vta: bool,
296 vma: bool,
297};
298
299const VSew = enum(u3) {
300 @"8" = 0b000,
301 @"16" = 0b001,
302 @"32" = 0b010,
303 @"64" = 0b011,
304};
305
306const VlMul = enum(u3) {
307 mf8 = 0b101,
308 mf4 = 0b110,
309 mf2 = 0b111,
310 m1 = 0b000,
311 m2 = 0b001,
312 m4 = 0b010,
313 m8 = 0b011,
314};
src/arch/riscv64/encoder.zig+11-4
......@@ -1,26 +1,30 @@
11pub const Instruction = struct {
22 encoding: Encoding,
3 ops: [3]Operand = .{.none} ** 3,
3 ops: [5]Operand = .{.none} ** 5,
44
55 pub const Operand = union(enum) {
66 none,
77 reg: Register,
8 csr: CSR,
89 mem: Memory,
910 imm: Immediate,
11 barrier: Mir.Barrier,
1012 };
1113
1214 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
1315 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {
14 std.log.err("no encoding found for: {s} [{s} {s} {s}]", .{
16 std.log.err("no encoding found for: {s} [{s} {s} {s} {s} {s}]", .{
1517 @tagName(mnemonic),
1618 @tagName(if (ops.len > 0) ops[0] else .none),
1719 @tagName(if (ops.len > 1) ops[1] else .none),
1820 @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),
1923 });
2024 return error.InvalidInstruction;
2125 };
2226
23 var result_ops: [3]Operand = .{.none} ** 3;
27 var result_ops: [5]Operand = .{.none} ** 5;
2428 @memcpy(result_ops[0..ops.len], ops);
2529
2630 return .{
......@@ -53,7 +57,9 @@ pub const Instruction = struct {
5357 .none => unreachable, // it's sliced out above
5458 .reg => |reg| try writer.writeAll(@tagName(reg)),
5559 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
56 .mem => unreachable, // there is no "mem" operand in the actual instructions
60 .mem => try writer.writeAll("mem"),
61 .barrier => |barrier| try writer.writeAll(@tagName(barrier)),
62 .csr => |csr| try writer.writeAll(@tagName(csr)),
5763 }
5864 }
5965 }
......@@ -67,6 +73,7 @@ const bits = @import("bits.zig");
6773const Encoding = @import("Encoding.zig");
6874
6975const Register = bits.Register;
76const CSR = bits.CSR;
7077const Memory = bits.Memory;
7178const Immediate = bits.Immediate;
7279
src/arch/x86_64/Lower.zig+2
......@@ -65,6 +65,8 @@ pub const Reloc = struct {
6565 };
6666};
6767
68const Options = struct { allow_frame_locs: bool };
69
6870/// The returned slice is overwritten by the next call to lowerMir.
6971pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
7072 insts: []const Instruction,
src/codegen.zig+2-1
......@@ -987,8 +987,9 @@ pub fn genTypedValue(
987987
988988 log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)});
989989
990 if (val.isUndef(zcu))
990 if (val.isUndef(zcu)) {
991991 return GenResult.mcv(.undef);
992 }
992993
993994 const owner_decl = zcu.declPtr(owner_decl_index);
994995 const namespace = zcu.namespacePtr(owner_decl.src_namespace);
src/link/Elf/ZigObject.zig+11-7
......@@ -540,8 +540,8 @@ inline fn isGlobal(index: Symbol.Index) bool {
540540
541541pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
542542 const actual_index = index & symbol_mask;
543 if (isGlobal(index)) return self.global_symbols.items[actual_index];
544 return self.local_symbols.items[actual_index];
543 if (isGlobal(index)) return self.globals()[actual_index];
544 return self.locals()[actual_index];
545545}
546546
547547pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
......@@ -1334,11 +1334,15 @@ fn lowerConst(
13341334
13351335 const sym_index = try self.addAtom(elf_file);
13361336
1337 const res = try codegen.generateSymbol(&elf_file.base, pt, src_loc, val, &code_buffer, .{
1338 .none = {},
1339 }, .{
1340 .parent_atom_index = sym_index,
1341 });
1337 const res = try codegen.generateSymbol(
1338 &elf_file.base,
1339 pt,
1340 src_loc,
1341 val,
1342 &code_buffer,
1343 .{ .none = {} },
1344 .{ .parent_atom_index = sym_index },
1345 );
13421346 const code = switch (res) {
13431347 .ok => code_buffer.items,
13441348 .fail => |em| return .{ .fail = em },
test/behavior/array.zig-2
......@@ -580,7 +580,6 @@ test "type coercion of anon struct literal to array" {
580580 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
581581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
582582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
583 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
584583
585584 const S = struct {
586585 const U = union {
......@@ -1011,7 +1010,6 @@ test "union that needs padding bytes inside an array" {
10111010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10121011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10131012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1014 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10151013
10161014 const B = union(enum) {
10171015 D: u8,
test/behavior/atomics.zig-17
......@@ -42,7 +42,6 @@ test "fence" {
4242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4444 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4645
4746 var x: i32 = 1234;
4847 @fence(.seq_cst);
......@@ -188,21 +187,6 @@ test "atomic store" {
188187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
189188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
190189 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
192
193 var x: u32 = 0;
194 @atomicStore(u32, &x, 1, .seq_cst);
195 try expect(@atomicLoad(u32, &x, .seq_cst) == 1);
196 @atomicStore(u32, &x, 12345678, .seq_cst);
197 try expect(@atomicLoad(u32, &x, .seq_cst) == 12345678);
198}
199
200test "atomic store comptime" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
205 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
206190
207191 try comptime testAtomicStore();
208192 try testAtomicStore();
......@@ -451,7 +435,6 @@ test "return @atomicStore, using it as a void value" {
451435 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
453437 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
454 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
455438
456439 const S = struct {
457440 const A = struct {
test/behavior/bitcast.zig-2
......@@ -192,7 +192,6 @@ test "@bitCast packed structs at runtime and comptime" {
192192test "@bitCast extern structs at runtime and comptime" {
193193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
196195
197196 const Full = extern struct {
198197 number: u16,
......@@ -227,7 +226,6 @@ test "bitcast packed struct to integer and back" {
227226 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
228227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
229228 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
231229
232230 const LevelUpMove = packed struct {
233231 move_id: u9,
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
......@@ -11,7 +11,6 @@ test {
1111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1313 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1514
1615 var val: u8 = undefined;
1716 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered));
test/behavior/enum.zig-1
......@@ -908,7 +908,6 @@ test "enum literal casting to tagged union" {
908908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
909909 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910910 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
911 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
912911
913912 const Arch = union(enum) {
914913 x86_64,
test/behavior/error.zig-1
......@@ -535,7 +535,6 @@ test "return result loc as peer result loc in inferred error set function" {
535535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
536536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
538 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
539538
540539 const S = struct {
541540 fn doTheTest() !void {
test/behavior/eval.zig-2
......@@ -395,7 +395,6 @@ test "return 0 from function that has u0 return type" {
395395test "statically initialized struct" {
396396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
397397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
399398
400399 st_init_str_foo.x += 1;
401400 try expect(st_init_str_foo.x == 14);
......@@ -446,7 +445,6 @@ test "binary math operator in partially inlined function" {
446445 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447446 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448447 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
450448
451449 var s: [4]u32 = undefined;
452450 var b: [16]u8 = undefined;
test/behavior/floatop.zig-1
......@@ -281,7 +281,6 @@ test "@sqrt f32/f64" {
281281 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
282282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
283283 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
285284
286285 try testSqrt(f32);
287286 try comptime testSqrt(f32);
test/behavior/inline_switch.zig-1
......@@ -49,7 +49,6 @@ test "inline switch unions" {
4949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5050 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5352
5453 var x: U = .a;
5554 _ = &x;
test/behavior/math.zig-1
......@@ -1269,7 +1269,6 @@ test "@subWithOverflow" {
12691269 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12701270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12711271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12731272
12741273 {
12751274 var a: u8 = 1;
test/behavior/optional.zig-1
......@@ -397,7 +397,6 @@ test "array of optional unaligned types" {
397397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
399399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
400 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
401400
402401 const Enum = enum { one, two, three };
403402
test/behavior/packed-struct.zig-1
......@@ -785,7 +785,6 @@ test "nested packed struct field access test" {
785785test "nested packed struct at non-zero offset" {
786786 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
787787 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
788 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
789788
790789 const Pair = packed struct(u24) {
791790 a: u16 = 0,
test/behavior/reflection.zig-1
......@@ -28,7 +28,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
2828test "reflection: @field" {
2929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3030 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3231
3332 var f = Foo{
3433 .one = 42,
test/behavior/struct.zig-3
......@@ -875,7 +875,6 @@ test "packed struct field passed to generic function" {
875875test "anonymous struct literal syntax" {
876876 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
877877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
878 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
879878
880879 const S = struct {
881880 const Point = struct {
......@@ -985,7 +984,6 @@ test "struct with union field" {
985984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
986985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
987986 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
988 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
989987
990988 const Value = struct {
991989 ref: u32 = 2,
......@@ -1368,7 +1366,6 @@ test "store to comptime field" {
13681366test "struct field init value is size of the struct" {
13691367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13701368 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1371 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13721369
13731370 const namespace = struct {
13741371 const S = extern struct {
test/behavior/switch.zig-2
......@@ -256,7 +256,6 @@ test "switch on enum using pointer capture" {
256256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
257257 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
258258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
259 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
260259
261260 try testSwitchEnumPtrCapture();
262261 try comptime testSwitchEnumPtrCapture();
......@@ -693,7 +692,6 @@ test "switch capture copies its payload" {
693692 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
694693 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
695694 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
696 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
697695
698696 const S = struct {
699697 fn doTheTest() !void {
test/behavior/this.zig-1
......@@ -27,7 +27,6 @@ test "this refer to module call private fn" {
2727test "this refer to container" {
2828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3130
3231 var pt: Point(i32) = undefined;
3332 pt.x = 12;
test/behavior/tuple.zig-1
......@@ -131,7 +131,6 @@ test "tuple initializer for var" {
131131test "array-like initializer for tuple types" {
132132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
133133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
135134
136135 const T = @Type(.{
137136 .Struct = .{
test/behavior/type.zig-1
......@@ -383,7 +383,6 @@ test "Type.Union" {
383383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
384384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
385385 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
386 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
387386
388387 const Untagged = @Type(.{
389388 .Union = .{
test/behavior/union.zig-23
......@@ -43,7 +43,6 @@ test "basic unions" {
4343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4746
4847 var foo = Foo{ .int = 1 };
4948 try expect(foo.int == 1);
......@@ -276,7 +275,6 @@ test "comparison between union and enum literal" {
276275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
277276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
278277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
280278
281279 try testComparison();
282280 try comptime testComparison();
......@@ -292,7 +290,6 @@ test "cast union to tag type of union" {
292290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
293291 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
296293
297294 try testCastUnionToTag();
298295 try comptime testCastUnionToTag();
......@@ -314,7 +311,6 @@ test "cast tag type of union to union" {
314311 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
315312 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
316313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
317 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
318314
319315 var x: Value2 = Letter2.B;
320316 _ = &x;
......@@ -331,7 +327,6 @@ test "implicit cast union to its tag type" {
331327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
332328 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
333329 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
335330
336331 var x: Value2 = Letter2.B;
337332 _ = &x;
......@@ -353,7 +348,6 @@ test "constant packed union" {
353348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
354349 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
355350 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
356 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
357351
358352 try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }});
359353}
......@@ -503,7 +497,6 @@ test "initialize global array of union" {
503497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
504498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
505499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
507500
508501 glbl_array[1] = FooUnion{ .U1 = 2 };
509502 glbl_array[0] = FooUnion{ .U0 = 1 };
......@@ -515,7 +508,6 @@ test "update the tag value for zero-sized unions" {
515508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
516509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
517510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
519511
520512 const S = union(enum) {
521513 U0: void,
......@@ -636,7 +628,6 @@ test "tagged union with all void fields but a meaningful tag" {
636628 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
637629 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
638630 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
640631
641632 const S = struct {
642633 const B = union(enum) {
......@@ -758,7 +749,6 @@ test "@intFromEnum works on unions" {
758749 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
759750 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
760751 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
761 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
762752
763753 const Bar = union(enum) {
764754 A: bool,
......@@ -874,7 +864,6 @@ test "@unionInit can modify a union type" {
874864 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
875865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
876866 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
877 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
878867
879868 const UnionInitEnum = union(enum) {
880869 Boolean: bool,
......@@ -898,7 +887,6 @@ test "@unionInit can modify a pointer value" {
898887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
899888 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
900889 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
901 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
902890
903891 const UnionInitEnum = union(enum) {
904892 Boolean: bool,
......@@ -1089,7 +1077,6 @@ test "switching on non exhaustive union" {
10891077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10901078 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10911079 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1092 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10931080
10941081 const S = struct {
10951082 const E = enum(u8) {
......@@ -1199,7 +1186,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel
11991186 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12001187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12011188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1202 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12031189
12041190 const T = struct {
12051191 const U = union(enum) {
......@@ -1352,7 +1338,6 @@ test "noreturn field in union" {
13521338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13531339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13541340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1355 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13561341
13571342 const U = union(enum) {
13581343 a: u32,
......@@ -1434,7 +1419,6 @@ test "union field ptr - zero sized payload" {
14341419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14351420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14361421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1437 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14381422
14391423 const U = union {
14401424 foo: void,
......@@ -1449,7 +1433,6 @@ test "union field ptr - zero sized field" {
14491433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14501434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14511435 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14531436
14541437 const U = union {
14551438 foo: void,
......@@ -1589,7 +1572,6 @@ test "reinterpreting enum value inside packed union" {
15891572
15901573test "access the tag of a global tagged union" {
15911574 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1592 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15931575
15941576 const U = union(enum) {
15951577 a,
......@@ -1601,7 +1583,6 @@ test "access the tag of a global tagged union" {
16011583
16021584test "coerce enum literal to union in result loc" {
16031585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1604 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16051586
16061587 const U = union(enum) {
16071588 a,
......@@ -1864,7 +1845,6 @@ test "reinterpret extern union" {
18641845
18651846test "reinterpret packed union" {
18661847 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1867 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18681848
18691849 const U = packed union {
18701850 foo: u8,
......@@ -2044,7 +2024,6 @@ test "extern union initialized via reintepreted struct field initializer" {
20442024
20452025test "packed union initialized via reintepreted struct field initializer" {
20462026 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20482027
20492028 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20502029
......@@ -2065,7 +2044,6 @@ test "packed union initialized via reintepreted struct field initializer" {
20652044
20662045test "store of comptime reinterpreted memory to extern union" {
20672046 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2068 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20692047
20702048 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20712049
......@@ -2088,7 +2066,6 @@ test "store of comptime reinterpreted memory to extern union" {
20882066
20892067test "store of comptime reinterpreted memory to packed union" {
20902068 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2091 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20922069
20932070 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20942071
test/behavior/vector.zig+28-19
......@@ -97,29 +97,40 @@ test "vector int operators" {
9797
9898test "vector float operators" {
9999 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
101100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104103 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
105104 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
106105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
107107
108 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
109 const S = struct {
110 fn doTheTest() !void {
111 var v: @Vector(4, T) = [4]T{ 10, 20, 30, 40 };
112 var x: @Vector(4, T) = [4]T{ 1, 2, 3, 4 };
113 _ = .{ &v, &x };
114 try expect(mem.eql(T, &@as([4]T, v + x), &[4]T{ 11, 22, 33, 44 }));
115 try expect(mem.eql(T, &@as([4]T, v - x), &[4]T{ 9, 18, 27, 36 }));
116 try expect(mem.eql(T, &@as([4]T, v * x), &[4]T{ 10, 40, 90, 160 }));
117 try expect(mem.eql(T, &@as([4]T, -x), &[4]T{ -1, -2, -3, -4 }));
118 }
119 };
120 try S.doTheTest();
121 try comptime S.doTheTest();
122 }
108 const S = struct {
109 fn doTheTest(T: type) !void {
110 var v: @Vector(4, T) = .{ 10, 20, 30, 40 };
111 var x: @Vector(4, T) = .{ 1, 2, 3, 4 };
112 _ = .{ &v, &x };
113 try expectEqual(v + x, .{ 11, 22, 33, 44 });
114 try expectEqual(v - x, .{ 9, 18, 27, 36 });
115 try expectEqual(v * x, .{ 10, 40, 90, 160 });
116 try expectEqual(-x, .{ -1, -2, -3, -4 });
117 }
118 };
119
120 try S.doTheTest(f32);
121 try comptime S.doTheTest(f32);
122
123 try S.doTheTest(f64);
124 try comptime S.doTheTest(f64);
125
126 try S.doTheTest(f16);
127 try comptime S.doTheTest(f16);
128
129 try S.doTheTest(f80);
130 try comptime S.doTheTest(f80);
131
132 try S.doTheTest(f128);
133 try comptime S.doTheTest(f128);
123134}
124135
125136test "vector bit operators" {
......@@ -1245,7 +1256,6 @@ test "array of vectors is copied" {
12451256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12461257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12471258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1248 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12491259
12501260 const Vec3 = @Vector(3, i32);
12511261 var points = [_]Vec3{
......@@ -1316,6 +1326,7 @@ test "zero multiplicand" {
13161326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13171327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13181328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1329 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13191330
13201331 const zeros = @Vector(2, u32){ 0.0, 0.0 };
13211332 var ones = @Vector(2, u32){ 1.0, 1.0 };
......@@ -1410,7 +1421,6 @@ test "store to vector in slice" {
14101421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14111422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14121423 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
1413 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14141424
14151425 var v = [_]@Vector(3, f32){
14161426 .{ 1, 1, 1 },
......@@ -1608,7 +1618,6 @@ test "@reduce on bool vector" {
16081618test "bitcast vector to array of smaller vectors" {
16091619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16101620 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1611 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16121621
16131622 const u8x32 = @Vector(32, u8);
16141623 const u8x64 = @Vector(64, u8);
test/tests.zig+6-5
......@@ -436,11 +436,12 @@ const test_targets = blk: {
436436 //},
437437
438438 .{
439 .target = .{
440 .cpu_arch = .riscv64,
441 .os_tag = .linux,
442 .abi = .musl,
443 },
439 .target = std.Target.Query.parse(
440 .{
441 .arch_os_abi = "riscv64-linux-musl",
442 .cpu_features = "baseline+v",
443 },
444 ) catch @panic("OOM"),
444445 .use_llvm = false,
445446 .use_lld = false,
446447 },