authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-02 19:25:53-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-14 23:02:34-07:00
log571aa694fd150b9f76d78a6ac96c25163f46091a
tree46944915fe868cfb566fab2304c6f88a9995d6e1
parentf2301ba896bd522483e987ecebe72bdcd86705ba
signaturelock-open Commit is signed but in an unrecognized format.

riscv: vectors part 1


8 files changed, 551 insertions(+), 169 deletions(-)

src/arch/riscv64/CodeGen.zig+201-41
......@@ -37,6 +37,7 @@ const abi = @import("abi.zig");
3737const Lower = @import("Lower.zig");
3838
3939const Register = bits.Register;
40const CSR = bits.CSR;
4041const Immediate = bits.Immediate;
4142const Memory = bits.Memory;
4243const FrameIndex = bits.FrameIndex;
......@@ -87,6 +88,9 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},
8788/// across each runtime branch upon joining.
8889branch_stack: *std.ArrayList(Branch),
8990
91// The current bit length of vector registers.
92vec_len: u32,
93
9094// Key is the block instruction
9195blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
9296register_manager: RegisterManager = .{},
......@@ -747,6 +751,7 @@ pub fn generate(
747751 .end_di_line = func.rbrace_line,
748752 .end_di_column = func.rbrace_column,
749753 .scope_generation = 0,
754 .vec_len = 16 * 8, // TODO: set this per cpu
750755 };
751756 defer {
752757 function.frame_allocs.deinit(gpa);
......@@ -1040,10 +1045,60 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
10401045 return result;
10411046}
10421047
1048/// Returns a temporary register that contains the value of the `reg` csr.
1049///
1050/// Caller's duty to lock the return register is needed.
1051fn getCsr(func: *Func, csr: CSR) !Register {
1052 assert(func.hasFeature(.zicsr));
1053 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.usize));
1054 _ = try func.addInst(.{
1055 .tag = .csrrs,
1056 .ops = .csr,
1057 .data = .{
1058 .csr = .{
1059 .csr = csr,
1060 .rd = dst_reg,
1061 .rs1 = .x0,
1062 },
1063 },
1064 });
1065 return dst_reg;
1066}
1067
1068fn setVl(func: *Func, dst_reg: Register, avl: u5, options: bits.VType) !void {
1069 if (avl == 0) {
1070 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1071 _ = try func.addInst(.{
1072 .tag = .vsetvli,
1073 .ops = .rri,
1074 .data = .{ .i_type = .{
1075 .rd = dst_reg,
1076 .rs1 = .zero,
1077 .imm12 = Immediate.u(options_int),
1078 } },
1079 });
1080 } else {
1081 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));
1082 _ = try func.addInst(.{
1083 .tag = .vsetivli,
1084 .ops = .rri,
1085 .data = .{
1086 .i_type = .{
1087 .rd = dst_reg,
1088 .rs1 = @enumFromInt(avl),
1089 .imm12 = Immediate.u(options_int),
1090 },
1091 },
1092 });
1093 }
1094}
1095
10431096const required_features = [_]Target.riscv.Feature{
10441097 .d,
10451098 .m,
10461099 .a,
1100 .zicsr,
1101 .v,
10471102};
10481103
10491104fn gen(func: *Func) !void {
......@@ -1101,7 +1156,19 @@ fn gen(func: *Func) !void {
11011156 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);
11021157 const backpatch_fp_restore = try func.addPseudo(.pseudo_dead);
11031158 const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead);
1104 try func.addPseudoNone(.pseudo_ret);
1159
1160 // ret
1161 _ = try func.addInst(.{
1162 .tag = .jalr,
1163 .ops = .rri,
1164 .data = .{
1165 .i_type = .{
1166 .rd = .zero,
1167 .rs1 = .ra,
1168 .imm12 = Immediate.s(0),
1169 },
1170 },
1171 });
11051172
11061173 const frame_layout = try func.computeFrameLayout();
11071174 const need_save_reg = frame_layout.save_reg_list.count() > 0;
......@@ -1842,8 +1909,8 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass {
18421909 const zcu = pt.zcu;
18431910 return switch (ty.zigTypeTag(zcu)) {
18441911 .Float => .float,
1845 .Vector => @panic("TODO: typeRegClass for Vectors"),
1846 inline else => .int,
1912 .Vector => .vector,
1913 else => .int,
18471914 };
18481915}
18491916
......@@ -1852,7 +1919,7 @@ fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet
18521919 const zcu = pt.zcu;
18531920 return switch (ty.zigTypeTag(zcu)) {
18541921 .Float => abi.Registers.Float.general_purpose,
1855 .Vector => @panic("TODO: regGeneralClassForType for Vectors"),
1922 .Vector => abi.Registers.Vector.general_purpose,
18561923 else => abi.Registers.Integer.general_purpose,
18571924 };
18581925}
......@@ -1862,7 +1929,7 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
18621929 const zcu = pt.zcu;
18631930 return switch (ty.zigTypeTag(zcu)) {
18641931 .Float => abi.Registers.Float.temporary,
1865 .Vector => @panic("TODO: regTempClassForType for Vectors"),
1932 .Vector => abi.Registers.Vector.general_purpose, // there are no temporary vector registers
18661933 else => abi.Registers.Integer.temporary,
18671934 };
18681935}
......@@ -1870,20 +1937,19 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
18701937fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
18711938 const pt = func.pt;
18721939
1873 const abi_size = math.cast(u32, elem_ty.abiSize(pt)) orelse {
1874 return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)});
1940 const bit_size = elem_ty.bitSize(pt);
1941 const min_size: u64 = switch (elem_ty.zigTypeTag(pt.zcu)) {
1942 .Float => if (func.hasFeature(.d)) 64 else 32,
1943 .Vector => func.vec_len,
1944 else => 64,
18751945 };
18761946
1877 const min_size: u32 = switch (elem_ty.zigTypeTag(pt.zcu)) {
1878 .Float => 4,
1879 .Vector => @panic("allocRegOrMem Vector"),
1880 else => 8,
1881 };
1882
1883 if (reg_ok and abi_size <= min_size) {
1947 if (reg_ok and bit_size <= min_size) {
18841948 if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| {
18851949 return .{ .register = reg };
18861950 }
1951 } else if (reg_ok and elem_ty.zigTypeTag(pt.zcu) == .Vector) {
1952 return func.fail("did you forget to extend vector registers before allocating", .{});
18871953 }
18881954
18891955 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt));
......@@ -1896,10 +1962,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool
18961962fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {
18971963 if (reg_class == .float and !func.hasFeature(.f))
18981964 std.debug.panic("allocReg class == float where F isn't enabled", .{});
1965 if (reg_class == .vector and !func.hasFeature(.v))
1966 std.debug.panic("allocReg class == vector where V isn't enabled", .{});
18991967
19001968 const class = switch (reg_class) {
19011969 .int => abi.Registers.Integer.general_purpose,
19021970 .float => abi.Registers.Float.general_purpose,
1971 .vector => abi.Registers.Vector.general_purpose,
19031972 };
19041973
19051974 const reg = try func.register_manager.allocReg(null, class);
......@@ -1915,7 +1984,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi
19151984 return .{ op_reg, func.register_manager.lockReg(operand.register) };
19161985 }
19171986
1918 const reg, const lock = try func.allocReg(func.typeRegClass(ty));
1987 const class = func.typeRegClass(ty);
1988 const reg, const lock = try func.allocReg(class);
19191989 try func.genSetReg(ty, reg, operand);
19201990 return .{ reg, lock };
19211991}
......@@ -2372,6 +2442,42 @@ fn genBinOp(
23722442 },
23732443 });
23742444 },
2445 .Vector => {
2446 const mir_tag: Mir.Inst.Tag = switch (tag) {
2447 .add => .vaddvv,
2448 else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}),
2449 };
2450
2451 const num_elem: u5 = math.cast(u5, lhs_ty.vectorLen(zcu)) orelse {
2452 return func.fail("TODO: genBinOp use vsetvli for larger avl sizes", .{});
2453 };
2454 const elem_size = lhs_ty.childType(zcu).bitSize(pt);
2455
2456 try func.setVl(.zero, num_elem, .{
2457 .vlmul = .mf2,
2458 .vsew = switch (elem_size) {
2459 8 => .@"8",
2460 16 => .@"16",
2461 32 => .@"32",
2462 64 => .@"64",
2463 else => unreachable,
2464 },
2465 .vma = true,
2466 .vta = true,
2467 });
2468
2469 _ = try func.addInst(.{
2470 .tag = mir_tag,
2471 .ops = .rrr,
2472 .data = .{
2473 .r_type = .{
2474 .rd = dst_reg,
2475 .rs1 = lhs_reg,
2476 .rs2 = rhs_reg,
2477 },
2478 },
2479 });
2480 },
23752481 else => unreachable,
23762482 }
23772483 },
......@@ -3560,13 +3666,12 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
35603666}
35613667
35623668fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
3563 const zcu = func.bin_file.comp.module.?;
3564 const mod = func.bin_file.comp.module.?;
3669 const pt = func.pt;
35653670 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
35663671
35673672 const tag_ty = func.typeOfIndex(inst);
35683673 const union_ty = func.typeOf(ty_op.operand);
3569 const layout = union_ty.unionGetLayout(mod);
3674 const layout = union_ty.unionGetLayout(pt);
35703675
35713676 if (layout.tag_size == 0) {
35723677 return func.finishAir(inst, .none, .{ ty_op.operand, .none, .none });
......@@ -3577,7 +3682,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
35773682 const frame_mcv = try func.allocRegOrMem(union_ty, null, false);
35783683 try func.genCopy(union_ty, frame_mcv, operand);
35793684
3580 const tag_abi_size = tag_ty.abiSize(mod);
3685 const tag_abi_size = tag_ty.abiSize(pt);
35813686 const result_reg, const result_lock = try func.allocReg(.int);
35823687 defer func.register_manager.unlockReg(result_lock);
35833688
......@@ -3597,7 +3702,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
35973702 } else {
35983703 return func.fail(
35993704 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}",
3600 .{ frame_mcv, tag_ty.fmt(zcu) },
3705 .{ frame_mcv, tag_ty.fmt(pt) },
36013706 );
36023707 }
36033708 },
......@@ -3781,13 +3886,13 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void {
37813886}
37823887
37833888fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
3784 const zcu = func.bin_file.comp.module.?;
3889 const pt = func.pt;
37853890 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
37863891 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
37873892 const ty = func.typeOf(un_op);
37883893
37893894 const operand = try func.resolveInst(un_op);
3790 const operand_bit_size = ty.bitSize(zcu);
3895 const operand_bit_size = ty.bitSize(pt);
37913896
37923897 if (!math.isPowerOfTwo(operand_bit_size))
37933898 return func.fail("TODO: airUnaryMath non-pow 2", .{});
......@@ -3799,7 +3904,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
37993904 const dst_reg, const dst_lock = try func.allocReg(dst_class);
38003905 defer func.register_manager.unlockReg(dst_lock);
38013906
3802 switch (ty.zigTypeTag(zcu)) {
3907 switch (ty.zigTypeTag(pt.zcu)) {
38033908 .Float => {
38043909 assert(dst_class == .float);
38053910
......@@ -3833,7 +3938,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
38333938 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
38343939 }
38353940 },
3836 else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(zcu)}),
3941 else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}),
38373942 }
38383943
38393944 break :result MCValue{ .register = dst_reg };
......@@ -4510,7 +4615,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
45104615 .none => {},
45114616 .register,
45124617 .register_pair,
4513 => try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op }),
4618 => {
4619 if (ret_ty.isVector(zcu)) {
4620 const bit_size = ret_ty.totalVectorBits(pt);
4621
4622 // set the vtype to hold the entire vector's contents in a single element
4623 try func.setVl(.zero, 0, .{
4624 .vsew = switch (bit_size) {
4625 8 => .@"8",
4626 16 => .@"16",
4627 32 => .@"32",
4628 64 => .@"64",
4629 else => unreachable,
4630 },
4631 .vlmul = .m1,
4632 .vma = true,
4633 .vta = true,
4634 });
4635 }
4636
4637 try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op });
4638 },
45144639 .indirect => |reg_off| {
45154640 try func.register_manager.getReg(reg_off.reg, null);
45164641 const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg);
......@@ -5735,7 +5860,12 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
57355860 const zcu = pt.zcu;
57365861 const abi_size: u32 = @intCast(ty.abiSize(pt));
57375862
5738 if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size});
5863 const max_size: u32 = switch (reg.class()) {
5864 .int => 64,
5865 .float => if (func.hasFeature(.d)) 64 else 32,
5866 .vector => func.vec_len,
5867 };
5868 if (abi_size > max_size) return std.debug.panic("tried to set reg with size {}", .{abi_size});
57395869 const dst_reg_class = reg.class();
57405870
57415871 switch (src_mcv) {
......@@ -5835,13 +5965,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
58355965 if (src_reg.id() == reg.id())
58365966 return;
58375967
5838 const src_reg_class = src_reg.class();
5839
5840 if (src_reg_class == .float and dst_reg_class == .int) {
5841 // to move from float -> int, we use FMV.X.W
5842 return func.fail("TODO: genSetReg float -> int", .{});
5843 }
5844
58455968 // mv reg, src_reg
58465969 _ = try func.addInst(.{
58475970 .tag = .pseudo,
......@@ -5854,6 +5977,43 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
58545977 },
58555978 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
58565979 .load_frame => |frame| {
5980 if (reg.class() == .vector) {
5981 if (abi_size > 8)
5982 return func.fail("TODO: genSetReg vectors > 8", .{});
5983
5984 const temp_reg = try func.register_manager.allocReg(null, abi.Registers.Integer.temporary);
5985 const temp_lock = func.register_manager.lockRegAssumeUnused(temp_reg);
5986 defer func.register_manager.unlockReg(temp_lock);
5987
5988 try func.setVl(.zero, 1, .{
5989 .vsew = switch (abi_size) {
5990 1 => .@"8",
5991 2 => .@"16",
5992 4 => .@"32",
5993 8 => .@"64",
5994 else => unreachable,
5995 },
5996 .vlmul = .m1,
5997 .vma = true,
5998 .vta = true,
5999 });
6000
6001 try func.genCopy(ty, .{ .register = temp_reg }, .{ .load_frame = frame });
6002
6003 _ = try func.addInst(.{
6004 .tag = .pseudo,
6005 .ops = .pseudo_mv,
6006 .data = .{
6007 .rr = .{
6008 .rd = reg,
6009 .rs = temp_reg,
6010 },
6011 },
6012 });
6013
6014 return;
6015 }
6016
58576017 _ = try func.addInst(.{
58586018 .tag = .pseudo,
58596019 .ops = .pseudo_load_rm,
......@@ -6195,7 +6355,7 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {
61956355}
61966356
61976357fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
6198 const zcu = func.pt.zcu;
6358 const pt = func.pt;
61996359 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
62006360 const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data;
62016361
......@@ -6206,13 +6366,13 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
62066366 const ptr_mcv = try func.resolveInst(pl_op.operand);
62076367
62086368 const val_ty = func.typeOf(extra.operand);
6209 const val_size = val_ty.abiSize(func.pt);
6369 const val_size = val_ty.abiSize(pt);
62106370 const val_mcv = try func.resolveInst(extra.operand);
62116371
62126372 if (!math.isPowerOfTwo(val_size))
62136373 return func.fail("TODO: airAtomicRmw non-pow 2", .{});
62146374
6215 switch (val_ty.zigTypeTag(zcu)) {
6375 switch (val_ty.zigTypeTag(pt.zcu)) {
62166376 .Int => {},
62176377 inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}),
62186378 else => unreachable,
......@@ -6735,15 +6895,15 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
67356895}
67366896
67376897fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
6738 const zcu = func.pt.zcu;
6898 const pt = func.pt;
67396899 const gpa = func.gpa;
67406900
6741 const owner_decl_index = zcu.funcOwnerDeclIndex(func.func_index);
6901 const owner_decl_index = pt.zcu.funcOwnerDeclIndex(func.func_index);
67426902 const lf = func.bin_file;
67436903 const src_loc = func.src_loc;
67446904
6745 if (val.isUndef(zcu)) {
6746 const local_sym_index = lf.lowerUnnamedConst(func.pt, val, owner_decl_index) catch |err| {
6905 if (val.isUndef(pt.zcu)) {
6906 const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| {
67476907 const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)});
67486908 func.err_msg = msg;
67496909 return error.CodegenFail;
......@@ -6760,7 +6920,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
67606920
67616921 const result = try codegen.genTypedValue(
67626922 lf,
6763 func.pt,
6923 pt,
67646924 src_loc,
67656925 val,
67666926 owner_decl_index,
src/arch/riscv64/Encoding.zig+133-13
......@@ -11,6 +11,7 @@ const OpCode = enum(u7) {
1111 STORE = 0b0100011,
1212 STORE_FP = 0b0100111,
1313 AMO = 0b0101111,
14 OP_V = 0b1010111,
1415 OP = 0b0110011,
1516 OP_32 = 0b0111011,
1617 LUI = 0b0110111,
......@@ -83,9 +84,51 @@ const Enc = struct {
8384 funct3: u3,
8485 has_5: bool,
8586 },
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 },
86100 /// U-type
87101 none,
88102 },
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 @"32" = 0b110,
120 @"64" = 0b111,
121 };
122
123 const VecType = enum(u3) {
124 OPIVV = 0b000,
125 OPFVV = 0b001,
126 OPMVV = 0b010,
127 OPIVI = 0b011,
128 OPIVX = 0b100,
129 OPFVF = 0b101,
130 OPMVX = 0b110,
131 };
89132};
90133
91134pub const Mnemonic = enum {
......@@ -115,6 +158,9 @@ pub const Mnemonic = enum {
115158 addi,
116159 jalr,
117160
161 vsetivli,
162 vsetvli,
163
118164 // U Type
119165 lui,
120166 auipc,
......@@ -155,6 +201,8 @@ pub const Mnemonic = enum {
155201 ebreak,
156202 unimp,
157203
204 csrrs,
205
158206 // M extension
159207 mul,
160208 mulw,
......@@ -217,6 +265,17 @@ pub const Mnemonic = enum {
217265 fsgnjnd,
218266 fsgnjxd,
219267
268 // V Extension
269 vle32v,
270 vle64v,
271
272 vse32v,
273 vse64v,
274
275 vaddvv,
276 vadcxv,
277 vadcvx,
278
220279 // MISC
221280 fence,
222281 fencetso,
......@@ -373,6 +432,9 @@ pub const Mnemonic = enum {
373432
374433 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
375434 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
435
436 .vle32v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = true, .nf = 0b000 } } },
437 .vle64v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = true, .nf = 0b000 } } },
376438
377439
378440 // STORE_FP
......@@ -380,6 +442,8 @@ pub const Mnemonic = enum {
380442 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
381443 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
382444
445 .vse32v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = true, .nf = 0b000 } } },
446 .vse64v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = true, .nf = 0b000 } } },
383447
384448 // JALR
385449
......@@ -410,6 +474,8 @@ pub const Mnemonic = enum {
410474
411475 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
412476 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
477
478 .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } },
413479
414480
415481 // NONE
......@@ -449,7 +515,13 @@ pub const Mnemonic = enum {
449515 .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
450516 .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
451517
452
518 // OP_V
519 .vsetivli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
520 .vsetvli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
521 .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
522 .vadcxv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVX } } },
523 .vadcvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
524
453525 // zig fmt: on
454526 };
455527 }
......@@ -465,7 +537,6 @@ pub const InstEnc = enum {
465537 J,
466538 fence,
467539 amo,
468 /// extras that have unusual op counts
469540 system,
470541
471542 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
......@@ -494,6 +565,10 @@ pub const InstEnc = enum {
494565
495566 .flw,
496567 .fld,
568
569 .csrrs,
570 .vsetivli,
571 .vsetvli,
497572 => .I,
498573
499574 .lui,
......@@ -587,6 +662,14 @@ pub const InstEnc = enum {
587662
588663 .fsgnjxs,
589664 .fsgnjxd,
665
666 .vle32v,
667 .vle64v,
668 .vse32v,
669 .vse64v,
670 .vaddvv,
671 .vadcxv,
672 .vadcvx,
590673 => .R,
591674
592675 .ecall,
......@@ -757,6 +840,25 @@ pub const Data = union(InstEnc) {
757840 },
758841 };
759842 },
843 .csrrs => {
844 assert(ops.len == 3);
845
846 const csr = ops[0].csr;
847 const rs1 = ops[1].reg;
848 const rd = ops[2].reg;
849
850 return .{
851 .I = .{
852 .rd = rd.encodeId(),
853 .rs1 = rs1.encodeId(),
854
855 .imm0_11 = @intFromEnum(csr),
856
857 .opcode = @intFromEnum(enc.opcode),
858 .funct3 = enc.data.f.funct3,
859 },
860 };
861 },
760862 else => {},
761863 }
762864
......@@ -783,6 +885,25 @@ pub const Data = union(InstEnc) {
783885 .funct3 = fmt.rm,
784886 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
785887 },
888 .vecls => |vec| .{
889 .rd = ops[0].reg.encodeId(),
890 .rs1 = ops[1].reg.encodeId(),
891
892 .rs2 = @intFromEnum(vec.umop),
893
894 .opcode = @intFromEnum(enc.opcode),
895 .funct3 = @intFromEnum(vec.width),
896 .funct7 = (@as(u7, vec.nf) << 4) | (@as(u7, @intFromBool(vec.mew)) << 3) | (@as(u7, @intFromEnum(vec.mop)) << 1) | @intFromBool(vec.vm),
897 },
898 .vecmath => |vec| .{
899 .rd = ops[0].reg.encodeId(),
900 .rs1 = ops[1].reg.encodeId(),
901 .rs2 = ops[2].reg.encodeId(),
902
903 .opcode = @intFromEnum(enc.opcode),
904 .funct3 = @intFromEnum(vec.funct3),
905 .funct7 = (@as(u7, vec.funct6) << 1) | @intFromBool(vec.vm),
906 },
786907 else => unreachable,
787908 },
788909 };
......@@ -897,21 +1018,21 @@ pub const Data = union(InstEnc) {
8971018 .amo => {
8981019 assert(ops.len == 5);
8991020
900 const rd = ops[0];
901 const rs1 = ops[1];
902 const rs2 = ops[2];
903 const rl = ops[3];
904 const aq = ops[4];
1021 const rd = ops[0].reg;
1022 const rs1 = ops[1].reg;
1023 const rs2 = ops[2].reg;
1024 const rl = ops[3].barrier;
1025 const aq = ops[4].barrier;
9051026
9061027 return .{
9071028 .amo = .{
908 .rd = rd.reg.encodeId(),
909 .rs1 = rs1.reg.encodeId(),
910 .rs2 = rs2.reg.encodeId(),
1029 .rd = rd.encodeId(),
1030 .rs1 = rs1.encodeId(),
1031 .rs2 = rs2.encodeId(),
9111032
9121033 // TODO: https://github.com/ziglang/zig/issues/20113
913 .rl = if (rl.barrier == .rl) true else false,
914 .aq = if (aq.barrier == .aq) true else false,
1034 .rl = if (rl == .rl) true else false,
1035 .aq = if (aq == .aq) true else false,
9151036
9161037 .opcode = @intFromEnum(enc.opcode),
9171038 .funct3 = @intFromEnum(enc.data.amo.width),
......@@ -919,7 +1040,6 @@ pub const Data = union(InstEnc) {
9191040 },
9201041 };
9211042 },
922
9231043 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
9241044 }
9251045 }
src/arch/riscv64/Lower.zig+124-56
......@@ -80,58 +80,99 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
8080 .pseudo_load_rm => {
8181 const dest_reg = rm.r;
8282 const dest_reg_class = dest_reg.class();
83 const float = dest_reg_class == .float;
8483
8584 const src_size = rm.m.mod.size;
8685 const unsigned = rm.m.mod.unsigned;
8786
88 const tag: Encoding.Mnemonic = if (!float)
89 switch (src_size) {
87 const tag: Encoding.Mnemonic = switch (dest_reg_class) {
88 .int => switch (src_size) {
9089 .byte => if (unsigned) .lbu else .lb,
9190 .hword => if (unsigned) .lhu else .lh,
9291 .word => if (unsigned) .lwu else .lw,
9392 .dword => .ld,
94 }
95 else switch (src_size) {
96 .byte => unreachable, // Zig does not support 8-bit floats
97 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
98 .word => .flw,
99 .dword => .fld,
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,
102 .hword,
103 => return lower.fail(
104 "TODO: lowerMir pseudo_load_rm support {s} vector",
105 .{@tagName(src_size)},
106 ),
107 .word => .vle32v,
108 .dword => .vle64v,
109 },
100110 };
101111
102 try lower.emit(tag, &.{
103 .{ .reg = rm.r },
104 .{ .reg = frame_loc.base },
105 .{ .imm = Immediate.s(frame_loc.disp) },
106 });
112 switch (dest_reg_class) {
113 .int, .float => {
114 try lower.emit(tag, &.{
115 .{ .reg = rm.r },
116 .{ .reg = frame_loc.base },
117 .{ .imm = Immediate.s(frame_loc.disp) },
118 });
119 },
120 .vector => {
121 try lower.emit(tag, &.{
122 .{ .reg = rm.r },
123 .{ .reg = frame_loc.base },
124 .{ .reg = .x0 },
125 });
126 },
127 }
107128 },
108129 .pseudo_store_rm => {
109130 const src_reg = rm.r;
110131 const src_reg_class = src_reg.class();
111 const float = src_reg_class == .float;
112132
113 // TODO: do we actually need this? are all stores not usize?
114133 const dest_size = rm.m.mod.size;
115134
116 const tag: Encoding.Mnemonic = if (!float)
117 switch (dest_size) {
135 const tag: Encoding.Mnemonic = switch (src_reg_class) {
136 .int => switch (dest_size) {
118137 .byte => .sb,
119138 .hword => .sh,
120139 .word => .sw,
121140 .dword => .sd,
122 }
123 else switch (dest_size) {
124 .byte => unreachable, // Zig does not support 8-bit floats
125 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
126 .word => .fsw,
127 .dword => .fsd,
141 },
142 .float => switch (dest_size) {
143 .byte => unreachable, // Zig does not support 8-bit floats
144 .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}),
145 .word => .fsw,
146 .dword => .fsd,
147 },
148 .vector => switch (dest_size) {
149 .byte,
150 .hword,
151 => return lower.fail(
152 "TODO: lowerMir pseudo_load_rm support {s} vector",
153 .{@tagName(dest_size)},
154 ),
155 .word => .vse32v,
156 .dword => .vse64v,
157 },
128158 };
129159
130 try lower.emit(tag, &.{
131 .{ .reg = frame_loc.base },
132 .{ .reg = rm.r },
133 .{ .imm = Immediate.s(frame_loc.disp) },
134 });
160 switch (src_reg_class) {
161 .int, .float => {
162 try lower.emit(tag, &.{
163 .{ .reg = frame_loc.base },
164 .{ .reg = rm.r },
165 .{ .imm = Immediate.s(frame_loc.disp) },
166 });
167 },
168 .vector => {
169 try lower.emit(tag, &.{
170 .{ .reg = frame_loc.base },
171 .{ .reg = rm.r },
172 .{ .reg = .x0 },
173 });
174 },
175 }
135176 },
136177 else => unreachable,
137178 }
......@@ -143,34 +184,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
143184 const dst_class = rr.rd.class();
144185 const src_class = rr.rs.class();
145186
146 assert(dst_class == src_class);
147
148 switch (dst_class) {
149 .float => {
150 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
151 .{ .reg = rr.rd },
152 .{ .reg = rr.rs },
153 .{ .reg = rr.rs },
154 });
187 switch (src_class) {
188 .float => switch (dst_class) {
189 .float => {
190 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
191 .{ .reg = rr.rd },
192 .{ .reg = rr.rs },
193 .{ .reg = rr.rs },
194 });
195 },
196 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),
197 },
198 .int => switch (dst_class) {
199 .int => {
200 try lower.emit(.addi, &.{
201 .{ .reg = rr.rd },
202 .{ .reg = rr.rs },
203 .{ .imm = Immediate.s(0) },
204 });
205 },
206 .vector => {
207 try lower.emit(.vadcxv, &.{
208 .{ .reg = rr.rd },
209 .{ .reg = rr.rs },
210 .{ .reg = .zero },
211 });
212 },
213 .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}),
155214 },
156 .int => {
157 try lower.emit(.addi, &.{
158 .{ .reg = rr.rd },
159 .{ .reg = rr.rs },
160 .{ .imm = Immediate.s(0) },
161 });
215 .vector => switch (dst_class) {
216 .int => {
217 try lower.emit(.vadcvx, &.{
218 .{ .reg = rr.rd },
219 .{ .reg = rr.rs },
220 .{ .reg = .zero },
221 });
222 },
223 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),
162224 },
163225 }
164226 },
165227
166 .pseudo_ret => {
167 try lower.emit(.jalr, &.{
168 .{ .reg = .zero },
169 .{ .reg = .ra },
170 .{ .imm = Immediate.s(0) },
171 });
172 },
173
174228 .pseudo_j => {
175229 try lower.emit(.jal, &.{
176230 .{ .reg = .zero },
......@@ -209,7 +263,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
209263 const rm = inst.data.rm;
210264 assert(rm.r.class() == .int);
211265
212 const frame = rm.m.toFrameLoc(lower.mir);
266 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
267 rm.m.toFrameLoc(lower.mir)
268 else
269 .{ .base = .s0, .disp = 0 };
213270
214271 try lower.emit(.addi, &.{
215272 .{ .reg = rm.r },
......@@ -376,6 +433,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
376433 });
377434 },
378435 },
436 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),
379437 }
380438 },
381439
......@@ -497,6 +555,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
497555 .{ .reg = inst.data.r_type.rs1 },
498556 .{ .reg = inst.data.r_type.rs2 },
499557 },
558 .csr => &.{
559 .{ .csr = inst.data.csr.csr },
560 .{ .reg = inst.data.csr.rs1 },
561 .{ .reg = inst.data.csr.rd },
562 },
500563 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
501564 });
502565}
......@@ -523,17 +586,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
523586 while (it.next()) |i| {
524587 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));
525588 const reg = abi.Registers.all_preserved[i];
589
526590 const reg_class = reg.class();
527 const is_float_reg = reg_class == .float;
591 const load_inst: Encoding.Mnemonic, const store_inst: Encoding.Mnemonic = switch (reg_class) {
592 .int => .{ .ld, .sd },
593 .float => .{ .fld, .fsd },
594 .vector => unreachable,
595 };
528596
529597 if (spilling) {
530 try lower.emit(if (is_float_reg) .fsd else .sd, &.{
598 try lower.emit(store_inst, &.{
531599 .{ .reg = frame.base },
532600 .{ .reg = abi.Registers.all_preserved[i] },
533601 .{ .imm = Immediate.s(frame.disp + reg_i) },
534602 });
535603 } else {
536 try lower.emit(if (is_float_reg) .fld else .ld, &.{
604 try lower.emit(load_inst, &.{
537605 .{ .reg = abi.Registers.all_preserved[i] },
538606 .{ .reg = frame.base },
539607 .{ .imm = Immediate.s(frame.disp + reg_i) },
src/arch/riscv64/Mir.zig+19-51
......@@ -134,7 +134,16 @@ pub const Inst = struct {
134134 fltd,
135135 fled,
136136
137 /// A Extension Instructions
137 // Zicsr Extension Instructions
138 csrrs,
139
140 // V Extension Instructions
141 vsetvli,
142 vsetivli,
143 vsetvl,
144 vaddvv,
145
146 // A Extension Instructions
138147 amo,
139148
140149 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
......@@ -146,91 +155,57 @@ pub const Inst = struct {
146155 /// this union. `Ops` determines which union field is active, as well as
147156 /// how to interpret the data within.
148157 pub const Data = union {
149 /// No additional data
150 ///
151 /// Used by e.g. ebreak
152158 nop: void,
153 /// Another instruction.
154 ///
155 /// Used by e.g. b
156159 inst: Index,
157 /// Index into `extra`. Meaning of what can be found there is context-dependent.
158 ///
159 /// Used by e.g. load_memory
160160 payload: u32,
161
162161 r_type: struct {
163162 rd: Register,
164163 rs1: Register,
165164 rs2: Register,
166165 },
167
168166 i_type: struct {
169167 rd: Register,
170168 rs1: Register,
171169 imm12: Immediate,
172170 },
173
174171 s_type: struct {
175172 rs1: Register,
176173 rs2: Register,
177174 imm5: Immediate,
178175 imm7: Immediate,
179176 },
180
181177 b_type: struct {
182178 rs1: Register,
183179 rs2: Register,
184180 inst: Inst.Index,
185181 },
186
187182 u_type: struct {
188183 rd: Register,
189184 imm20: Immediate,
190185 },
191
192186 j_type: struct {
193187 rd: Register,
194188 inst: Inst.Index,
195189 },
196
197 /// Debug info: line and column
198 ///
199 /// Used by e.g. pseudo_dbg_line
200190 pseudo_dbg_line_column: struct {
201191 line: u32,
202192 column: u32,
203193 },
204
205 // Custom types to be lowered
206
207 /// Register + Memory
208194 rm: struct {
209195 r: Register,
210196 m: Memory,
211197 },
212
213198 reg_list: Mir.RegisterList,
214
215 /// A register
216 ///
217 /// Used by e.g. blr
218199 reg: Register,
219
220 /// Two registers
221 ///
222 /// Used by e.g. mv
223200 rr: struct {
224201 rd: Register,
225202 rs: Register,
226203 },
227
228204 fabs: struct {
229205 rd: Register,
230206 rs: Register,
231207 bits: u16,
232208 },
233
234209 compare: struct {
235210 rd: Register,
236211 rs1: Register,
......@@ -245,12 +220,10 @@ pub const Inst = struct {
245220 },
246221 ty: Type,
247222 },
248
249223 reloc: struct {
250224 atom_index: u32,
251225 sym_index: u32,
252226 },
253
254227 fence: struct {
255228 pred: Barrier,
256229 succ: Barrier,
......@@ -259,7 +232,6 @@ pub const Inst = struct {
259232 tso,
260233 },
261234 },
262
263235 amo: struct {
264236 rd: Register,
265237 rs1: Register,
......@@ -269,6 +241,11 @@ pub const Inst = struct {
269241 op: AmoOp,
270242 ty: Type,
271243 },
244 csr: struct {
245 csr: CSR,
246 rs1: Register,
247 rd: Register,
248 },
272249 };
273250
274251 pub const Ops = enum {
......@@ -293,6 +270,9 @@ pub const Inst = struct {
293270 /// Another instruction.
294271 inst,
295272
273 /// Control and Status Register Instruction.
274 csr,
275
296276 /// Pseudo-instruction that will generate a backpatched
297277 /// function prologue.
298278 pseudo_prologue,
......@@ -321,11 +301,6 @@ pub const Inst = struct {
321301 /// Uses `rm` payload.
322302 pseudo_lea_rm,
323303
324 /// Shorthand for returning, aka jumping to ra register.
325 ///
326 /// Uses nop payload.
327 pseudo_ret,
328
329304 /// Jumps. Uses `inst` payload.
330305 pseudo_j,
331306
......@@ -363,14 +338,6 @@ pub const Inst = struct {
363338 pseudo_amo,
364339 };
365340
366 // Make sure we don't accidentally make instructions bigger than expected.
367 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
368 // comptime {
369 // if (builtin.mode != .Debug) {
370 // assert(@sizeOf(Inst) == 8);
371 // }
372 // }
373
374341 pub fn format(
375342 inst: Inst,
376343 comptime fmt: []const u8,
......@@ -490,6 +457,7 @@ const assert = std.debug.assert;
490457
491458const bits = @import("bits.zig");
492459const Register = bits.Register;
460const CSR = bits.CSR;
493461const Immediate = bits.Immediate;
494462const Memory = bits.Memory;
495463const 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+41-1
......@@ -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) => 1024, // 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+3
......@@ -5,6 +5,7 @@ pub const Instruction = struct {
55 pub const Operand = union(enum) {
66 none,
77 reg: Register,
8 csr: CSR,
89 mem: Memory,
910 imm: Immediate,
1011 barrier: Mir.Barrier,
......@@ -58,6 +59,7 @@ pub const Instruction = struct {
5859 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
5960 .mem => try writer.writeAll("mem"),
6061 .barrier => |barrier| try writer.writeAll(@tagName(barrier)),
62 .csr => |csr| try writer.writeAll(@tagName(csr)),
6163 }
6264 }
6365 }
......@@ -71,6 +73,7 @@ const bits = @import("bits.zig");
7173const Encoding = @import("Encoding.zig");
7274
7375const Register = bits.Register;
76const CSR = bits.CSR;
7477const Memory = bits.Memory;
7578const Immediate = bits.Immediate;
7679
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 },