authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-02 02:41:14-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-14 23:02:35-07:00
log5a2c547fc1eedcec52e9e7259449d9a093e21ab1
tree31d0e7a34098171e408ab7d38c77bddfef959cf4
parent09e9812086073d9e8ebfe6f61c227f1ab5859f40
signature Commit is signed but in an unrecognized format.

riscv: vectors part 3


10 files changed, 193 insertions(+), 148 deletions(-)

lib/std/start.zig+20-1
...@@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn {...@@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn {
221 }221 }
222 break :ret root.main();222 break :ret root.main();
223 },223 },
224 else => @compileError("expected return type of main to be 'void', 'noreturn', 'u8'"),224 .ErrorUnion => ret: {
225 const result = root.main() catch {
226 const stderr = std.io.getStdErr().writer();
227 stderr.writeAll("failed with error\n") catch {
228 @panic("failed to print when main returned error");
229 };
230 break :ret 1;
231 };
232 switch (@typeInfo(@TypeOf(result))) {
233 .Void => break :ret 0,
234 .Int => |info| {
235 if (info.bits != 8 or info.signedness == .signed) {
236 @compileError(bad_main_ret);
237 }
238 return result;
239 },
240 else => @compileError(bad_main_ret),
241 }
242 },
243 else => @compileError(bad_main_ret),
225 });244 });
226}245}
227246
src/arch/riscv64/CodeGen.zig+131-116
...@@ -88,8 +88,9 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},...@@ -88,8 +88,9 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},
88/// across each runtime branch upon joining.88/// across each runtime branch upon joining.
89branch_stack: *std.ArrayList(Branch),89branch_stack: *std.ArrayList(Branch),
9090
91// The current bit length of vector registers.91// Currently set vector properties, null means they haven't been set yet in the function.
92vec_len: u32,92avl: ?u64,
93vtype: ?bits.VType,
9394
94// Key is the block instruction95// Key is the block instruction
95blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},96blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
...@@ -751,7 +752,8 @@ pub fn generate(...@@ -751,7 +752,8 @@ pub fn generate(
751 .end_di_line = func.rbrace_line,752 .end_di_line = func.rbrace_line,
752 .end_di_column = func.rbrace_column,753 .end_di_column = func.rbrace_column,
753 .scope_generation = 0,754 .scope_generation = 0,
754 .vec_len = 16 * 8, // TODO: set this per cpu755 .avl = null,
756 .vtype = null,
755 };757 };
756 defer {758 defer {
757 function.frame_allocs.deinit(gpa);759 function.frame_allocs.deinit(gpa);
...@@ -1064,8 +1066,17 @@ fn getCsr(func: *Func, csr: CSR) !Register {...@@ -1064,8 +1066,17 @@ fn getCsr(func: *Func, csr: CSR) !Register {
1064 return dst_reg;1066 return dst_reg;
1065}1067}
10661068
1067fn setVl(func: *Func, dst_reg: Register, avl: u5, options: bits.VType) !void {1069fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
1070 if (func.avl == avl) if (func.vtype) |vtype| {
1071 // it's already set, we don't need to do anything
1072 if (@as(u8, @bitCast(vtype)) == @as(u8, @bitCast(options))) return;
1073 };
1074
1075 func.avl = avl;
1076 func.vtype = options;
1077
1068 if (avl == 0) {1078 if (avl == 0) {
1079 // the caller means to do "vsetvli zero, zero ..." which keeps the avl to whatever it was before
1069 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));1080 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1070 _ = try func.addInst(.{1081 _ = try func.addInst(.{
1071 .tag = .vsetvli,1082 .tag = .vsetvli,
...@@ -1077,18 +1088,33 @@ fn setVl(func: *Func, dst_reg: Register, avl: u5, options: bits.VType) !void {...@@ -1077,18 +1088,33 @@ fn setVl(func: *Func, dst_reg: Register, avl: u5, options: bits.VType) !void {
1077 } },1088 } },
1078 });1089 });
1079 } else {1090 } else {
1080 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));1091 // if the avl can fit into u5 we can use vsetivli otherwise use vsetvli
1081 _ = try func.addInst(.{1092 if (avl <= std.math.maxInt(u5)) {
1082 .tag = .vsetivli,1093 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));
1083 .ops = .rri,1094 _ = try func.addInst(.{
1084 .data = .{1095 .tag = .vsetivli,
1085 .i_type = .{1096 .ops = .rri,
1097 .data = .{
1098 .i_type = .{
1099 .rd = dst_reg,
1100 .rs1 = @enumFromInt(avl),
1101 .imm12 = Immediate.u(options_int),
1102 },
1103 },
1104 });
1105 } else {
1106 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1107 const temp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = avl });
1108 _ = try func.addInst(.{
1109 .tag = .vsetvli,
1110 .ops = .rri,
1111 .data = .{ .i_type = .{
1086 .rd = dst_reg,1112 .rd = dst_reg,
1087 .rs1 = @enumFromInt(avl),1113 .rs1 = temp_reg,
1088 .imm12 = Immediate.u(options_int),1114 .imm12 = Immediate.u(options_int),
1089 },1115 } },
1090 },1116 });
1091 });1117 }
1092 }1118 }
1093}1119}
10941120
...@@ -1939,7 +1965,7 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool...@@ -1939,7 +1965,7 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool
1939 const bit_size = elem_ty.bitSize(pt);1965 const bit_size = elem_ty.bitSize(pt);
1940 const min_size: u64 = switch (elem_ty.zigTypeTag(pt.zcu)) {1966 const min_size: u64 = switch (elem_ty.zigTypeTag(pt.zcu)) {
1941 .Float => if (func.hasFeature(.d)) 64 else 32,1967 .Float => if (func.hasFeature(.d)) 64 else 32,
1942 .Vector => func.vec_len,1968 .Vector => 256, // TODO: calculate it from avl * vsew
1943 else => 64,1969 else => 64,
1944 };1970 };
19451971
...@@ -2293,7 +2319,11 @@ fn binOp(...@@ -2293,7 +2319,11 @@ fn binOp(
2293 return func.fail("binOp libcall runtime-float ops", .{});2319 return func.fail("binOp libcall runtime-float ops", .{});
2294 }2320 }
22952321
2296 if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{});2322 // don't have support for certain sizes of addition
2323 switch (lhs_ty.zigTypeTag(pt.zcu)) {
2324 .Vector => {}, // works differently and fails in a different place
2325 else => if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{}),
2326 }
22972327
2298 const lhs_mcv = try func.resolveInst(lhs_air);2328 const lhs_mcv = try func.resolveInst(lhs_air);
2299 const rhs_mcv = try func.resolveInst(rhs_air);2329 const rhs_mcv = try func.resolveInst(rhs_air);
...@@ -2442,17 +2472,25 @@ fn genBinOp(...@@ -2442,17 +2472,25 @@ fn genBinOp(
2442 });2472 });
2443 },2473 },
2444 .Vector => {2474 .Vector => {
2475 const num_elem = lhs_ty.vectorLen(zcu);
2476 const elem_size = lhs_ty.childType(zcu).bitSize(pt);
2477
2478 const child_ty = lhs_ty.childType(zcu);
2479
2445 const mir_tag: Mir.Inst.Tag = switch (tag) {2480 const mir_tag: Mir.Inst.Tag = switch (tag) {
2446 .add => .vaddvv,2481 .add => switch (child_ty.zigTypeTag(zcu)) {
2447 .sub => .vsubvv,2482 .Int => .vaddvv,
2483 .Float => .vfaddvv,
2484 else => unreachable,
2485 },
2486 .sub => switch (child_ty.zigTypeTag(zcu)) {
2487 .Int => .vsubvv,
2488 .Float => .vfsubvv,
2489 else => unreachable,
2490 },
2448 else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}),2491 else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}),
2449 };2492 };
24502493
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, .{2494 try func.setVl(.zero, num_elem, .{
2457 .vsew = switch (elem_size) {2495 .vsew = switch (elem_size) {
2458 8 => .@"8",2496 8 => .@"8",
...@@ -2761,78 +2799,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -2761,78 +2799,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2761 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;2799 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
27622800
2763 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {2801 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2764 const lhs_ty = func.typeOf(extra.lhs);2802 const ty = func.typeOf(extra.lhs);
27652803 switch (ty.zigTypeTag(zcu)) {
2766 const int_info = lhs_ty.intInfo(zcu);2804 .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}),
27672805 .Int => {
2768 const tuple_ty = func.typeOfIndex(inst);2806 const int_info = ty.intInfo(zcu);
2769 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2770 const offset = result_mcv.load_frame;
27712807
2772 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {2808 const tuple_ty = func.typeOfIndex(inst);
2773 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);2809 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2774 const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result);2810 const offset = result_mcv.load_frame;
2775 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2776 defer func.register_manager.unlockReg(add_result_reg_lock);
27772811
2778 const shift_amount: u6 = @intCast(Type.usize.bitSize(pt) - int_info.bits);2812 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2813 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
27792814
2780 const shift_reg, const shift_lock = try func.allocReg(.int);2815 const add_result_reg = try func.copyToTmpRegister(ty, add_result);
2781 defer func.register_manager.unlockReg(shift_lock);2816 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2817 defer func.register_manager.unlockReg(add_result_reg_lock);
27822818
2783 _ = try func.addInst(.{2819 try func.genSetMem(
2784 .tag = .slli,2820 .{ .frame = offset.index },
2785 .ops = .rri,2821 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2786 .data = .{2822 ty,
2787 .i_type = .{2823 add_result,
2788 .rd = shift_reg,2824 );
2789 .rs1 = add_result_reg,
2790 .imm12 = Immediate.u(shift_amount),
2791 },
2792 },
2793 });
2794
2795 _ = try func.addInst(.{
2796 .tag = if (int_info.signedness == .unsigned) .srli else .srai,
2797 .ops = .rri,
2798 .data = .{
2799 .i_type = .{
2800 .rd = shift_reg,
2801 .rs1 = shift_reg,
2802 .imm12 = Immediate.u(shift_amount),
2803 },
2804 },
2805 });
2806
2807 try func.genSetMem(
2808 .{ .frame = offset.index },
2809 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))),
2810 lhs_ty,
2811 add_result,
2812 );
28132825
2814 const overflow_reg, const overflow_lock = try func.allocReg(.int);2826 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2815 defer func.register_manager.unlockReg(overflow_lock);2827 defer func.register_manager.unlockReg(overflow_lock);
28162828
2817 try func.genBinOp(2829 try func.genBinOp(
2818 .cmp_neq,2830 .cmp_neq,
2819 .{ .register = shift_reg },2831 .{ .register = add_result_reg },
2820 lhs_ty,2832 ty,
2821 .{ .register = add_result_reg },2833 .{ .register = add_result_reg },
2822 lhs_ty,2834 ty,
2823 overflow_reg,2835 overflow_reg,
2824 );2836 );
28252837
2826 try func.genSetMem(2838 try func.genSetMem(
2827 .{ .frame = offset.index },2839 .{ .frame = offset.index },
2828 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),2840 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))),
2829 Type.u1,2841 Type.u1,
2830 .{ .register = overflow_reg },2842 .{ .register = overflow_reg },
2831 );2843 );
28322844
2833 break :result result_mcv;2845 break :result result_mcv;
2834 } else {2846 } else {
2835 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});2847 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
2848 }
2849 },
2850 else => unreachable,
2836 }2851 }
2837 };2852 };
28382853
...@@ -5519,8 +5534,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -5519,8 +5534,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
5519 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);5534 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);
5520 extra_i += inputs.len;5535 extra_i += inputs.len;
55215536
5522 log.debug("airAsm input: {any}", .{inputs});
5523
5524 const dead = !is_volatile and func.liveness.isUnused(inst);5537 const dead = !is_volatile and func.liveness.isUnused(inst);
5525 const result: MCValue = if (dead) .unreach else result: {5538 const result: MCValue = if (dead) .unreach else result: {
5526 if (outputs.len > 1) {5539 if (outputs.len > 1) {
...@@ -5897,7 +5910,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -5897,7 +5910,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
5897 const max_size: u32 = switch (reg.class()) {5910 const max_size: u32 = switch (reg.class()) {
5898 .int => 64,5911 .int => 64,
5899 .float => if (func.hasFeature(.d)) 64 else 32,5912 .float => if (func.hasFeature(.d)) 64 else 32,
5900 .vector => func.vec_len,5913 .vector => 64, // TODO: calculate it from avl * vsew
5901 };5914 };
5902 if (abi_size > max_size) return std.debug.panic("tried to set reg with size {}", .{abi_size});5915 if (abi_size > max_size) return std.debug.panic("tried to set reg with size {}", .{abi_size});
5903 const dst_reg_class = reg.class();5916 const dst_reg_class = reg.class();
...@@ -6033,6 +6046,8 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6033,6 +6046,8 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6033 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),6046 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
6034 .load_frame => |frame| {6047 .load_frame => |frame| {
6035 if (reg.class() == .vector) {6048 if (reg.class() == .vector) {
6049 // vectors don't support an offset memory load so we need to put the true
6050 // address into a register before loading from it.
6036 const addr_reg, const addr_lock = try func.allocReg(.int);6051 const addr_reg, const addr_lock = try func.allocReg(.int);
6037 defer func.register_manager.unlockReg(addr_lock);6052 defer func.register_manager.unlockReg(addr_lock);
60386053
...@@ -6073,28 +6088,30 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6073,28 +6088,30 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6073 _ = try func.addInst(.{6088 _ = try func.addInst(.{
6074 .tag = .pseudo,6089 .tag = .pseudo,
6075 .ops = .pseudo_lea_rm,6090 .ops = .pseudo_lea_rm,
6076 .data = .{ .rm = .{6091 .data = .{
6077 .r = reg,6092 .rm = .{
6078 .m = switch (src_mcv) {6093 .r = reg,
6079 .register_offset => |reg_off| .{6094 .m = switch (src_mcv) {
6080 .base = .{ .reg = reg_off.reg },6095 .register_offset => |reg_off| .{
6081 .mod = .{6096 .base = .{ .reg = reg_off.reg },
6082 .size = func.memSize(ty),6097 .mod = .{
6083 .disp = reg_off.off,6098 .size = .byte, // the size doesn't matter
6084 .unsigned = false,6099 .disp = reg_off.off,
6100 .unsigned = false,
6101 },
6085 },6102 },
6086 },6103 .lea_frame => |frame| .{
6087 .lea_frame => |frame| .{6104 .base = .{ .frame = frame.index },
6088 .base = .{ .frame = frame.index },6105 .mod = .{
6089 .mod = .{6106 .size = .byte, // the size doesn't matter
6090 .size = func.memSize(ty),6107 .disp = frame.off,
6091 .disp = frame.off,6108 .unsigned = false,
6092 .unsigned = false,6109 },
6093 },6110 },
6111 else => unreachable,
6094 },6112 },
6095 else => unreachable,
6096 },6113 },
6097 } },6114 },
6098 });6115 });
6099 },6116 },
6100 .indirect => |reg_off| {6117 .indirect => |reg_off| {
...@@ -6119,9 +6136,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6119,9 +6136,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6119 // There is no vector instruction for loading with an offset to a base register,6136 // There is no vector instruction for loading with an offset to a base register,
6120 // so we need to get an offset register containing the address of the vector first6137 // so we need to get an offset register containing the address of the vector first
6121 // and load from it.6138 // and load from it.
6122 const len: u5 = math.cast(u5, ty.vectorLen(zcu)) orelse {6139 const len = ty.vectorLen(zcu);
6123 return func.fail("TODO: genSetReg load_frame -> vec reg, vector length doesn't fit into imm avl", .{});
6124 };
6125 const elem_ty = ty.childType(zcu);6140 const elem_ty = ty.childType(zcu);
6126 const elem_size = elem_ty.abiSize(pt);6141 const elem_size = elem_ty.abiSize(pt);
61276142
...@@ -6202,6 +6217,8 @@ fn genSetMem(...@@ -6202,6 +6217,8 @@ fn genSetMem(
6202 src_mcv: MCValue,6217 src_mcv: MCValue,
6203) InnerError!void {6218) InnerError!void {
6204 const pt = func.pt;6219 const pt = func.pt;
6220 const zcu = pt.zcu;
6221
6205 const abi_size: u32 = @intCast(ty.abiSize(pt));6222 const abi_size: u32 = @intCast(ty.abiSize(pt));
6206 const dst_ptr_mcv: MCValue = switch (base) {6223 const dst_ptr_mcv: MCValue = switch (base) {
6207 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },6224 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
...@@ -6252,10 +6269,8 @@ fn genSetMem(...@@ -6252,10 +6269,8 @@ fn genSetMem(
6252 if (reg.class() == .vector) {6269 if (reg.class() == .vector) {
6253 const addr_reg = try func.copyToTmpRegister(Type.usize, dst_ptr_mcv);6270 const addr_reg = try func.copyToTmpRegister(Type.usize, dst_ptr_mcv);
62546271
6255 const num_elem: u5 = math.cast(u5, ty.vectorLen(pt.zcu)) orelse {6272 const num_elem = ty.vectorLen(zcu);
6256 return func.fail("TODO: genBinOp use vsetvli for larger avl sizes", .{});6273 const elem_size = ty.childType(zcu).bitSize(pt);
6257 };
6258 const elem_size = ty.childType(pt.zcu).bitSize(pt);
62596274
6260 try func.setVl(.zero, num_elem, .{6275 try func.setVl(.zero, num_elem, .{
6261 .vsew = switch (elem_size) {6276 .vsew = switch (elem_size) {
...@@ -6279,7 +6294,7 @@ fn genSetMem(...@@ -6279,7 +6294,7 @@ fn genSetMem(
6279 .base = .{ .reg = addr_reg },6294 .base = .{ .reg = addr_reg },
6280 .mod = .{6295 .mod = .{
6281 .disp = 0,6296 .disp = 0,
6282 .size = func.memSize(ty.childType(pt.zcu)),6297 .size = func.memSize(ty.childType(zcu)),
6283 .unsigned = false,6298 .unsigned = false,
6284 },6299 },
6285 },6300 },
src/arch/riscv64/Encoding.zig+10
...@@ -285,6 +285,9 @@ pub const Mnemonic = enum {...@@ -285,6 +285,9 @@ pub const Mnemonic = enum {
285 vaddvv,285 vaddvv,
286 vsubvv,286 vsubvv,
287287
288 vfaddvv,
289 vfsubvv,
290
288 vadcvv,291 vadcvv,
289292
290 vmvvx,293 vmvvx,
...@@ -316,6 +319,8 @@ pub const Mnemonic = enum {...@@ -316,6 +319,8 @@ pub const Mnemonic = enum {
316 amomaxud,319 amomaxud,
317 amominud,320 amominud,
318321
322 // TODO: Q extension
323
319 pub fn encoding(mnem: Mnemonic) Enc {324 pub fn encoding(mnem: Mnemonic) Enc {
320 return switch (mnem) {325 return switch (mnem) {
321 // zig fmt: off326 // zig fmt: off
...@@ -542,6 +547,9 @@ pub const Mnemonic = enum {...@@ -542,6 +547,9 @@ pub const Mnemonic = enum {
542 .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },547 .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
543 .vsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },548 .vsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },
544 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
545 .vadcvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },553 .vadcvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
546 .vmvvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },554 .vmvvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },
547555
...@@ -702,6 +710,8 @@ pub const InstEnc = enum {...@@ -702,6 +710,8 @@ pub const InstEnc = enum {
702710
703 .vaddvv,711 .vaddvv,
704 .vsubvv,712 .vsubvv,
713 .vfaddvv,
714 .vfsubvv,
705 .vadcvv,715 .vadcvv,
706 .vmvvx,716 .vmvvx,
707 .vslidedownvx,717 .vslidedownvx,
src/arch/riscv64/Mir.zig+2-3
...@@ -142,12 +142,11 @@ pub const Inst = struct {...@@ -142,12 +142,11 @@ pub const Inst = struct {
142 vsetivli,142 vsetivli,
143 vsetvl,143 vsetvl,
144 vaddvv,144 vaddvv,
145 vfaddvv,
145 vsubvv,146 vsubvv,
147 vfsubvv,
146 vslidedownvx,148 vslidedownvx,
147149
148 // A Extension Instructions
149 amo,
150
151 /// A pseudo-instruction. Used for anything that isn't 1:1 with an150 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
152 /// assembly instruction.151 /// assembly instruction.
153 pseudo,152 pseudo,
src/arch/riscv64/bits.zig+2-2
...@@ -41,7 +41,7 @@ pub const Memory = struct {...@@ -41,7 +41,7 @@ pub const Memory = struct {
41 2...2 => .hword,41 2...2 => .hword,
42 3...4 => .word,42 3...4 => .word,
43 5...8 => .dword,43 5...8 => .dword,
44 else => unreachable,44 else => std.debug.panic("fromByteSize {}", .{size}),
45 };45 };
46 }46 }
4747
...@@ -221,7 +221,7 @@ pub const Register = enum(u8) {...@@ -221,7 +221,7 @@ pub const Register = enum(u8) {
221 // zig fmt: off221 // zig fmt: off
222 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,222 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
223 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,223 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,
224 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => 1024, // TODO: look at suggestVectorSize224 @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => 256, // TODO: look at suggestVectorSize
225 else => unreachable,225 else => unreachable,
226 // zig fmt: on226 // zig fmt: on
227 };227 };
test/behavior/byteswap.zig-1
...@@ -100,7 +100,6 @@ test "@byteSwap vectors u8" {...@@ -100,7 +100,6 @@ test "@byteSwap vectors u8" {
100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104103
105 try comptime vector8();104 try comptime vector8();
106 try vector8();105 try vector8();
test/behavior/cast.zig-1
...@@ -1985,7 +1985,6 @@ test "peer type resolution: vector and array and tuple" {...@@ -1985,7 +1985,6 @@ test "peer type resolution: vector and array and tuple" {
1985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1986 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1986 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1987 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1987 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1988 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19891988
1990 var vec: @Vector(2, i8) = .{ 10, 20 };1989 var vec: @Vector(2, i8) = .{ 10, 20 };
1991 var arr: [2]i8 = .{ 30, 40 };1990 var arr: [2]i8 = .{ 30, 40 };
test/behavior/globals.zig-1
...@@ -18,7 +18,6 @@ test "store to global vector" {...@@ -18,7 +18,6 @@ test "store to global vector" {
18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2221
23 try expect(vpos[1] == 0.0);22 try expect(vpos[1] == 0.0);
24 vpos = @Vector(2, f32){ 0.0, 1.0 };23 vpos = @Vector(2, f32){ 0.0, 1.0 };
test/behavior/sizeof_and_typeof.zig-2
...@@ -19,8 +19,6 @@ test "@sizeOf on compile-time types" {...@@ -19,8 +19,6 @@ test "@sizeOf on compile-time types" {
19}19}
2020
21test "@TypeOf() with multiple arguments" {21test "@TypeOf() with multiple arguments" {
22 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
23
24 {22 {
25 var var_1: u32 = undefined;23 var var_1: u32 = undefined;
26 var var_2: u8 = undefined;24 var var_2: u8 = undefined;
test/behavior/vector.zig+28-21
...@@ -97,7 +97,6 @@ test "vector int operators" {...@@ -97,7 +97,6 @@ test "vector int operators" {
9797
98test "vector float operators" {98test "vector float operators" {
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -105,21 +104,34 @@ test "vector float operators" {...@@ -105,21 +104,34 @@ test "vector float operators" {
105 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;104 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
107106
108 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {107 const S = struct {
109 const S = struct {108 fn doTheTest(T: type) !void {
110 fn doTheTest() !void {109 var v: @Vector(4, T) = .{ 10, 20, 30, 40 };
111 var v: @Vector(4, T) = [4]T{ 10, 20, 30, 40 };110 var x: @Vector(4, T) = .{ 1, 2, 3, 4 };
112 var x: @Vector(4, T) = [4]T{ 1, 2, 3, 4 };111 _ = .{ &v, &x };
113 _ = .{ &v, &x };112 try expectEqual(v + x, .{ 11, 22, 33, 44 });
114 try expect(mem.eql(T, &@as([4]T, v + x), &[4]T{ 11, 22, 33, 44 }));113 try expectEqual(v - x, .{ 9, 18, 27, 36 });
115 try expect(mem.eql(T, &@as([4]T, v - x), &[4]T{ 9, 18, 27, 36 }));114 try expectEqual(v * x, .{ 10, 40, 90, 160 });
116 try expect(mem.eql(T, &@as([4]T, v * x), &[4]T{ 10, 40, 90, 160 }));115 try expectEqual(-x, .{ -1, -2, -3, -4 });
117 try expect(mem.eql(T, &@as([4]T, -x), &[4]T{ -1, -2, -3, -4 }));116 }
118 }117 };
119 };118
120 try S.doTheTest();119 try S.doTheTest(f32);
121 try comptime S.doTheTest();120 try comptime S.doTheTest(f32);
122 }121
122 try S.doTheTest(f64);
123 try comptime S.doTheTest(f64);
124
125 try S.doTheTest(f16);
126 try comptime S.doTheTest(f16);
127
128 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
129
130 try S.doTheTest(f80);
131 try comptime S.doTheTest(f80);
132
133 try S.doTheTest(f128);
134 try comptime S.doTheTest(f128);
123}135}
124136
125test "vector bit operators" {137test "vector bit operators" {
...@@ -1228,7 +1240,6 @@ test "loading the second vector from a slice of vectors" {...@@ -1228,7 +1240,6 @@ test "loading the second vector from a slice of vectors" {
1228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1231 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12321243
1233 @setRuntimeSafety(false);1244 @setRuntimeSafety(false);
1234 var small_bases = [2]@Vector(2, u8){1245 var small_bases = [2]@Vector(2, u8){
...@@ -1245,7 +1256,6 @@ test "array of vectors is copied" {...@@ -1245,7 +1256,6 @@ test "array of vectors is copied" {
1245 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1248 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12491259
1250 const Vec3 = @Vector(3, i32);1260 const Vec3 = @Vector(3, i32);
1251 var points = [_]Vec3{1261 var points = [_]Vec3{
...@@ -1316,7 +1326,6 @@ test "zero multiplicand" {...@@ -1316,7 +1326,6 @@ test "zero multiplicand" {
1316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1318 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1319 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13201329
1321 const zeros = @Vector(2, u32){ 0.0, 0.0 };1330 const zeros = @Vector(2, u32){ 0.0, 0.0 };
1322 var ones = @Vector(2, u32){ 1.0, 1.0 };1331 var ones = @Vector(2, u32){ 1.0, 1.0 };
...@@ -1411,7 +1420,6 @@ test "store to vector in slice" {...@@ -1411,7 +1420,6 @@ test "store to vector in slice" {
1411 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1420 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1412 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;1422 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
1414 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14151423
1416 var v = [_]@Vector(3, f32){1424 var v = [_]@Vector(3, f32){
1417 .{ 1, 1, 1 },1425 .{ 1, 1, 1 },
...@@ -1478,7 +1486,6 @@ test "store vector with memset" {...@@ -1478,7 +1486,6 @@ test "store vector with memset" {
1478test "addition of vectors represented as strings" {1486test "addition of vectors represented as strings" {
1479 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1488 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1481 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14821489
1483 const V = @Vector(3, u8);1490 const V = @Vector(3, u8);
1484 const foo: V = "foo".*;1491 const foo: V = "foo".*;