| author | |
| committer | |
| log | 571aa694fd150b9f76d78a6ac96c25163f46091a |
| tree | 46944915fe868cfb566fab2304c6f88a9995d6e1 |
| parent | f2301ba896bd522483e987ecebe72bdcd86705ba |
| signature |
8 files changed, 551 insertions(+), 169 deletions(-)
src/arch/riscv64/CodeGen.zig+201-41| ... | @@ -37,6 +37,7 @@ const abi = @import("abi.zig"); | ... | @@ -37,6 +37,7 @@ const abi = @import("abi.zig"); |
| 37 | const Lower = @import("Lower.zig"); | 37 | const Lower = @import("Lower.zig"); |
| 38 | 38 | ||
| 39 | const Register = bits.Register; | 39 | const Register = bits.Register; |
| 40 | const CSR = bits.CSR; | ||
| 40 | const Immediate = bits.Immediate; | 41 | const Immediate = bits.Immediate; |
| 41 | const Memory = bits.Memory; | 42 | const Memory = bits.Memory; |
| 42 | const FrameIndex = bits.FrameIndex; | 43 | const FrameIndex = bits.FrameIndex; |
| ... | @@ -87,6 +88,9 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{}, | ... | @@ -87,6 +88,9 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{}, |
| 87 | /// across each runtime branch upon joining. | 88 | /// across each runtime branch upon joining. |
| 88 | branch_stack: *std.ArrayList(Branch), | 89 | branch_stack: *std.ArrayList(Branch), |
| 89 | 90 | ||
| 91 | // The current bit length of vector registers. | ||
| 92 | vec_len: u32, | ||
| 93 | |||
| 90 | // Key is the block instruction | 94 | // Key is the block instruction |
| 91 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, | 95 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, |
| 92 | register_manager: RegisterManager = .{}, | 96 | register_manager: RegisterManager = .{}, |
| ... | @@ -747,6 +751,7 @@ pub fn generate( | ... | @@ -747,6 +751,7 @@ pub fn generate( |
| 747 | .end_di_line = func.rbrace_line, | 751 | .end_di_line = func.rbrace_line, |
| 748 | .end_di_column = func.rbrace_column, | 752 | .end_di_column = func.rbrace_column, |
| 749 | .scope_generation = 0, | 753 | .scope_generation = 0, |
| 754 | .vec_len = 16 * 8, // TODO: set this per cpu | ||
| 750 | }; | 755 | }; |
| 751 | defer { | 756 | defer { |
| 752 | function.frame_allocs.deinit(gpa); | 757 | function.frame_allocs.deinit(gpa); |
| ... | @@ -1040,10 +1045,60 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 { | ... | @@ -1040,10 +1045,60 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 { |
| 1040 | return result; | 1045 | return result; |
| 1041 | } | 1046 | } |
| 1042 | 1047 | ||
| 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. | ||
| 1051 | fn 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 | |||
| 1068 | fn 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 | |||
| 1043 | const required_features = [_]Target.riscv.Feature{ | 1096 | const required_features = [_]Target.riscv.Feature{ |
| 1044 | .d, | 1097 | .d, |
| 1045 | .m, | 1098 | .m, |
| 1046 | .a, | 1099 | .a, |
| 1100 | .zicsr, | ||
| 1101 | .v, | ||
| 1047 | }; | 1102 | }; |
| 1048 | 1103 | ||
| 1049 | fn gen(func: *Func) !void { | 1104 | fn gen(func: *Func) !void { |
| ... | @@ -1101,7 +1156,19 @@ fn gen(func: *Func) !void { | ... | @@ -1101,7 +1156,19 @@ fn gen(func: *Func) !void { |
| 1101 | const backpatch_ra_restore = try func.addPseudo(.pseudo_dead); | 1156 | const backpatch_ra_restore = try func.addPseudo(.pseudo_dead); |
| 1102 | const backpatch_fp_restore = try func.addPseudo(.pseudo_dead); | 1157 | const backpatch_fp_restore = try func.addPseudo(.pseudo_dead); |
| 1103 | const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead); | 1158 | 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 | }); | ||
| 1105 | 1172 | ||
| 1106 | const frame_layout = try func.computeFrameLayout(); | 1173 | const frame_layout = try func.computeFrameLayout(); |
| 1107 | const need_save_reg = frame_layout.save_reg_list.count() > 0; | 1174 | const need_save_reg = frame_layout.save_reg_list.count() > 0; |
| ... | @@ -1842,8 +1909,8 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass { | ... | @@ -1842,8 +1909,8 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass { |
| 1842 | const zcu = pt.zcu; | 1909 | const zcu = pt.zcu; |
| 1843 | return switch (ty.zigTypeTag(zcu)) { | 1910 | return switch (ty.zigTypeTag(zcu)) { |
| 1844 | .Float => .float, | 1911 | .Float => .float, |
| 1845 | .Vector => @panic("TODO: typeRegClass for Vectors"), | 1912 | .Vector => .vector, |
| 1846 | inline else => .int, | 1913 | else => .int, |
| 1847 | }; | 1914 | }; |
| 1848 | } | 1915 | } |
| 1849 | 1916 | ||
| ... | @@ -1852,7 +1919,7 @@ fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet | ... | @@ -1852,7 +1919,7 @@ fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet |
| 1852 | const zcu = pt.zcu; | 1919 | const zcu = pt.zcu; |
| 1853 | return switch (ty.zigTypeTag(zcu)) { | 1920 | return switch (ty.zigTypeTag(zcu)) { |
| 1854 | .Float => abi.Registers.Float.general_purpose, | 1921 | .Float => abi.Registers.Float.general_purpose, |
| 1855 | .Vector => @panic("TODO: regGeneralClassForType for Vectors"), | 1922 | .Vector => abi.Registers.Vector.general_purpose, |
| 1856 | else => abi.Registers.Integer.general_purpose, | 1923 | else => abi.Registers.Integer.general_purpose, |
| 1857 | }; | 1924 | }; |
| 1858 | } | 1925 | } |
| ... | @@ -1862,7 +1929,7 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { | ... | @@ -1862,7 +1929,7 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { |
| 1862 | const zcu = pt.zcu; | 1929 | const zcu = pt.zcu; |
| 1863 | return switch (ty.zigTypeTag(zcu)) { | 1930 | return switch (ty.zigTypeTag(zcu)) { |
| 1864 | .Float => abi.Registers.Float.temporary, | 1931 | .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 |
| 1866 | else => abi.Registers.Integer.temporary, | 1933 | else => abi.Registers.Integer.temporary, |
| 1867 | }; | 1934 | }; |
| 1868 | } | 1935 | } |
| ... | @@ -1870,20 +1937,19 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { | ... | @@ -1870,20 +1937,19 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { |
| 1870 | fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { | 1937 | fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1871 | const pt = func.pt; | 1938 | const pt = func.pt; |
| 1872 | 1939 | ||
| 1873 | const abi_size = math.cast(u32, elem_ty.abiSize(pt)) orelse { | 1940 | const bit_size = elem_ty.bitSize(pt); |
| 1874 | return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(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, | ||
| 1875 | }; | 1945 | }; |
| 1876 | 1946 | ||
| 1877 | const min_size: u32 = switch (elem_ty.zigTypeTag(pt.zcu)) { | 1947 | if (reg_ok and bit_size <= min_size) { |
| 1878 | .Float => 4, | ||
| 1879 | .Vector => @panic("allocRegOrMem Vector"), | ||
| 1880 | else => 8, | ||
| 1881 | }; | ||
| 1882 | |||
| 1883 | if (reg_ok and abi_size <= min_size) { | ||
| 1884 | if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| { | 1948 | if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| { |
| 1885 | return .{ .register = reg }; | 1949 | return .{ .register = reg }; |
| 1886 | } | 1950 | } |
| 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", .{}); | ||
| 1887 | } | 1953 | } |
| 1888 | 1954 | ||
| 1889 | const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt)); | 1955 | 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 | ... | @@ -1896,10 +1962,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool |
| 1896 | fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } { | 1962 | fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } { |
| 1897 | if (reg_class == .float and !func.hasFeature(.f)) | 1963 | if (reg_class == .float and !func.hasFeature(.f)) |
| 1898 | std.debug.panic("allocReg class == float where F isn't enabled", .{}); | 1964 | 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", .{}); | ||
| 1899 | 1967 | ||
| 1900 | const class = switch (reg_class) { | 1968 | const class = switch (reg_class) { |
| 1901 | .int => abi.Registers.Integer.general_purpose, | 1969 | .int => abi.Registers.Integer.general_purpose, |
| 1902 | .float => abi.Registers.Float.general_purpose, | 1970 | .float => abi.Registers.Float.general_purpose, |
| 1971 | .vector => abi.Registers.Vector.general_purpose, | ||
| 1903 | }; | 1972 | }; |
| 1904 | 1973 | ||
| 1905 | const reg = try func.register_manager.allocReg(null, class); | 1974 | const reg = try func.register_manager.allocReg(null, class); |
| ... | @@ -1915,7 +1984,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi | ... | @@ -1915,7 +1984,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi |
| 1915 | return .{ op_reg, func.register_manager.lockReg(operand.register) }; | 1984 | return .{ op_reg, func.register_manager.lockReg(operand.register) }; |
| 1916 | } | 1985 | } |
| 1917 | 1986 | ||
| 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); | ||
| 1919 | try func.genSetReg(ty, reg, operand); | 1989 | try func.genSetReg(ty, reg, operand); |
| 1920 | return .{ reg, lock }; | 1990 | return .{ reg, lock }; |
| 1921 | } | 1991 | } |
| ... | @@ -2372,6 +2442,42 @@ fn genBinOp( | ... | @@ -2372,6 +2442,42 @@ fn genBinOp( |
| 2372 | }, | 2442 | }, |
| 2373 | }); | 2443 | }); |
| 2374 | }, | 2444 | }, |
| 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 | }, | ||
| 2375 | else => unreachable, | 2481 | else => unreachable, |
| 2376 | } | 2482 | } |
| 2377 | }, | 2483 | }, |
| ... | @@ -3560,13 +3666,12 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3560,13 +3666,12 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3560 | } | 3666 | } |
| 3561 | 3667 | ||
| 3562 | fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | 3668 | fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3563 | const zcu = func.bin_file.comp.module.?; | 3669 | const pt = func.pt; |
| 3564 | const mod = func.bin_file.comp.module.?; | ||
| 3565 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3670 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3566 | 3671 | ||
| 3567 | const tag_ty = func.typeOfIndex(inst); | 3672 | const tag_ty = func.typeOfIndex(inst); |
| 3568 | const union_ty = func.typeOf(ty_op.operand); | 3673 | const union_ty = func.typeOf(ty_op.operand); |
| 3569 | const layout = union_ty.unionGetLayout(mod); | 3674 | const layout = union_ty.unionGetLayout(pt); |
| 3570 | 3675 | ||
| 3571 | if (layout.tag_size == 0) { | 3676 | if (layout.tag_size == 0) { |
| 3572 | return func.finishAir(inst, .none, .{ ty_op.operand, .none, .none }); | 3677 | return func.finishAir(inst, .none, .{ ty_op.operand, .none, .none }); |
| ... | @@ -3577,7 +3682,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3577,7 +3682,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3577 | const frame_mcv = try func.allocRegOrMem(union_ty, null, false); | 3682 | const frame_mcv = try func.allocRegOrMem(union_ty, null, false); |
| 3578 | try func.genCopy(union_ty, frame_mcv, operand); | 3683 | try func.genCopy(union_ty, frame_mcv, operand); |
| 3579 | 3684 | ||
| 3580 | const tag_abi_size = tag_ty.abiSize(mod); | 3685 | const tag_abi_size = tag_ty.abiSize(pt); |
| 3581 | const result_reg, const result_lock = try func.allocReg(.int); | 3686 | const result_reg, const result_lock = try func.allocReg(.int); |
| 3582 | defer func.register_manager.unlockReg(result_lock); | 3687 | defer func.register_manager.unlockReg(result_lock); |
| 3583 | 3688 | ||
| ... | @@ -3597,7 +3702,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3597,7 +3702,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3597 | } else { | 3702 | } else { |
| 3598 | return func.fail( | 3703 | return func.fail( |
| 3599 | "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}", | 3704 | "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) }, |
| 3601 | ); | 3706 | ); |
| 3602 | } | 3707 | } |
| 3603 | }, | 3708 | }, |
| ... | @@ -3781,13 +3886,13 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3781,13 +3886,13 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void { |
| 3781 | } | 3886 | } |
| 3782 | 3887 | ||
| 3783 | fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 3888 | fn 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; |
| 3785 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 3890 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 3786 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 3891 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 3787 | const ty = func.typeOf(un_op); | 3892 | const ty = func.typeOf(un_op); |
| 3788 | 3893 | ||
| 3789 | const operand = try func.resolveInst(un_op); | 3894 | const operand = try func.resolveInst(un_op); |
| 3790 | const operand_bit_size = ty.bitSize(zcu); | 3895 | const operand_bit_size = ty.bitSize(pt); |
| 3791 | 3896 | ||
| 3792 | if (!math.isPowerOfTwo(operand_bit_size)) | 3897 | if (!math.isPowerOfTwo(operand_bit_size)) |
| 3793 | return func.fail("TODO: airUnaryMath non-pow 2", .{}); | 3898 | 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 { | ... | @@ -3799,7 +3904,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3799 | const dst_reg, const dst_lock = try func.allocReg(dst_class); | 3904 | const dst_reg, const dst_lock = try func.allocReg(dst_class); |
| 3800 | defer func.register_manager.unlockReg(dst_lock); | 3905 | defer func.register_manager.unlockReg(dst_lock); |
| 3801 | 3906 | ||
| 3802 | switch (ty.zigTypeTag(zcu)) { | 3907 | switch (ty.zigTypeTag(pt.zcu)) { |
| 3803 | .Float => { | 3908 | .Float => { |
| 3804 | assert(dst_class == .float); | 3909 | assert(dst_class == .float); |
| 3805 | 3910 | ||
| ... | @@ -3833,7 +3938,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -3833,7 +3938,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3833 | else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}), | 3938 | else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}), |
| 3834 | } | 3939 | } |
| 3835 | }, | 3940 | }, |
| 3836 | else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(zcu)}), | 3941 | else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}), |
| 3837 | } | 3942 | } |
| 3838 | 3943 | ||
| 3839 | break :result MCValue{ .register = dst_reg }; | 3944 | break :result MCValue{ .register = dst_reg }; |
| ... | @@ -4510,7 +4615,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -4510,7 +4615,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { |
| 4510 | .none => {}, | 4615 | .none => {}, |
| 4511 | .register, | 4616 | .register, |
| 4512 | .register_pair, | 4617 | .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 | }, | ||
| 4514 | .indirect => |reg_off| { | 4639 | .indirect => |reg_off| { |
| 4515 | try func.register_manager.getReg(reg_off.reg, null); | 4640 | try func.register_manager.getReg(reg_off.reg, null); |
| 4516 | const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg); | 4641 | 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! | ... | @@ -5735,7 +5860,12 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5735 | const zcu = pt.zcu; | 5860 | const zcu = pt.zcu; |
| 5736 | const abi_size: u32 = @intCast(ty.abiSize(pt)); | 5861 | const abi_size: u32 = @intCast(ty.abiSize(pt)); |
| 5737 | 5862 | ||
| 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}); | ||
| 5739 | const dst_reg_class = reg.class(); | 5869 | const dst_reg_class = reg.class(); |
| 5740 | 5870 | ||
| 5741 | switch (src_mcv) { | 5871 | switch (src_mcv) { |
| ... | @@ -5835,13 +5965,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5835,13 +5965,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5835 | if (src_reg.id() == reg.id()) | 5965 | if (src_reg.id() == reg.id()) |
| 5836 | return; | 5966 | return; |
| 5837 | 5967 | ||
| 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 | |||
| 5845 | // mv reg, src_reg | 5968 | // mv reg, src_reg |
| 5846 | _ = try func.addInst(.{ | 5969 | _ = try func.addInst(.{ |
| 5847 | .tag = .pseudo, | 5970 | .tag = .pseudo, |
| ... | @@ -5854,6 +5977,43 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5854,6 +5977,43 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5854 | }, | 5977 | }, |
| 5855 | .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}), | 5978 | .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}), |
| 5856 | .load_frame => |frame| { | 5979 | .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 | |||
| 5857 | _ = try func.addInst(.{ | 6017 | _ = try func.addInst(.{ |
| 5858 | .tag = .pseudo, | 6018 | .tag = .pseudo, |
| 5859 | .ops = .pseudo_load_rm, | 6019 | .ops = .pseudo_load_rm, |
| ... | @@ -6195,7 +6355,7 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6195,7 +6355,7 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void { |
| 6195 | } | 6355 | } |
| 6196 | 6356 | ||
| 6197 | fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { | 6357 | fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { |
| 6198 | const zcu = func.pt.zcu; | 6358 | const pt = func.pt; |
| 6199 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; | 6359 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 6200 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 6360 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 6201 | 6361 | ||
| ... | @@ -6206,13 +6366,13 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6206,13 +6366,13 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { |
| 6206 | const ptr_mcv = try func.resolveInst(pl_op.operand); | 6366 | const ptr_mcv = try func.resolveInst(pl_op.operand); |
| 6207 | 6367 | ||
| 6208 | const val_ty = func.typeOf(extra.operand); | 6368 | const val_ty = func.typeOf(extra.operand); |
| 6209 | const val_size = val_ty.abiSize(func.pt); | 6369 | const val_size = val_ty.abiSize(pt); |
| 6210 | const val_mcv = try func.resolveInst(extra.operand); | 6370 | const val_mcv = try func.resolveInst(extra.operand); |
| 6211 | 6371 | ||
| 6212 | if (!math.isPowerOfTwo(val_size)) | 6372 | if (!math.isPowerOfTwo(val_size)) |
| 6213 | return func.fail("TODO: airAtomicRmw non-pow 2", .{}); | 6373 | return func.fail("TODO: airAtomicRmw non-pow 2", .{}); |
| 6214 | 6374 | ||
| 6215 | switch (val_ty.zigTypeTag(zcu)) { | 6375 | switch (val_ty.zigTypeTag(pt.zcu)) { |
| 6216 | .Int => {}, | 6376 | .Int => {}, |
| 6217 | inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}), | 6377 | inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}), |
| 6218 | else => unreachable, | 6378 | else => unreachable, |
| ... | @@ -6735,15 +6895,15 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking { | ... | @@ -6735,15 +6895,15 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking { |
| 6735 | } | 6895 | } |
| 6736 | 6896 | ||
| 6737 | fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { | 6897 | fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { |
| 6738 | const zcu = func.pt.zcu; | 6898 | const pt = func.pt; |
| 6739 | const gpa = func.gpa; | 6899 | const gpa = func.gpa; |
| 6740 | 6900 | ||
| 6741 | const owner_decl_index = zcu.funcOwnerDeclIndex(func.func_index); | 6901 | const owner_decl_index = pt.zcu.funcOwnerDeclIndex(func.func_index); |
| 6742 | const lf = func.bin_file; | 6902 | const lf = func.bin_file; |
| 6743 | const src_loc = func.src_loc; | 6903 | const src_loc = func.src_loc; |
| 6744 | 6904 | ||
| 6745 | if (val.isUndef(zcu)) { | 6905 | if (val.isUndef(pt.zcu)) { |
| 6746 | const local_sym_index = lf.lowerUnnamedConst(func.pt, val, owner_decl_index) catch |err| { | 6906 | const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| { |
| 6747 | const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)}); | 6907 | const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)}); |
| 6748 | func.err_msg = msg; | 6908 | func.err_msg = msg; |
| 6749 | return error.CodegenFail; | 6909 | return error.CodegenFail; |
| ... | @@ -6760,7 +6920,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { | ... | @@ -6760,7 +6920,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { |
| 6760 | 6920 | ||
| 6761 | const result = try codegen.genTypedValue( | 6921 | const result = try codegen.genTypedValue( |
| 6762 | lf, | 6922 | lf, |
| 6763 | func.pt, | 6923 | pt, |
| 6764 | src_loc, | 6924 | src_loc, |
| 6765 | val, | 6925 | val, |
| 6766 | owner_decl_index, | 6926 | owner_decl_index, |
src/arch/riscv64/Encoding.zig+133-13| ... | @@ -11,6 +11,7 @@ const OpCode = enum(u7) { | ... | @@ -11,6 +11,7 @@ const OpCode = enum(u7) { |
| 11 | STORE = 0b0100011, | 11 | STORE = 0b0100011, |
| 12 | STORE_FP = 0b0100111, | 12 | STORE_FP = 0b0100111, |
| 13 | AMO = 0b0101111, | 13 | AMO = 0b0101111, |
| 14 | OP_V = 0b1010111, | ||
| 14 | OP = 0b0110011, | 15 | OP = 0b0110011, |
| 15 | OP_32 = 0b0111011, | 16 | OP_32 = 0b0111011, |
| 16 | LUI = 0b0110111, | 17 | LUI = 0b0110111, |
| ... | @@ -83,9 +84,51 @@ const Enc = struct { | ... | @@ -83,9 +84,51 @@ const Enc = struct { |
| 83 | funct3: u3, | 84 | funct3: u3, |
| 84 | has_5: bool, | 85 | has_5: bool, |
| 85 | }, | 86 | }, |
| 87 | vecls: struct { | ||
| 88 | width: VecWidth, | ||
| 89 | umop: Umop, | ||
| 90 | vm: bool, | ||
| 91 | mop: Mop, | ||
| 92 | mew: bool, | ||
| 93 | nf: u3, | ||
| 94 | }, | ||
| 95 | vecmath: struct { | ||
| 96 | vm: bool, | ||
| 97 | funct6: u6, | ||
| 98 | funct3: VecType, | ||
| 99 | }, | ||
| 86 | /// U-type | 100 | /// U-type |
| 87 | none, | 101 | none, |
| 88 | }, | 102 | }, |
| 103 | |||
| 104 | const Mop = enum(u2) { | ||
| 105 | unit = 0b00, | ||
| 106 | unord = 0b01, | ||
| 107 | stride = 0b10, | ||
| 108 | ord = 0b11, | ||
| 109 | }; | ||
| 110 | |||
| 111 | const Umop = enum(u5) { | ||
| 112 | unit = 0b00000, | ||
| 113 | whole = 0b01000, | ||
| 114 | mask = 0b01011, | ||
| 115 | fault = 0b10000, | ||
| 116 | }; | ||
| 117 | |||
| 118 | const VecWidth = enum(u3) { | ||
| 119 | @"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 | }; | ||
| 89 | }; | 132 | }; |
| 90 | 133 | ||
| 91 | pub const Mnemonic = enum { | 134 | pub const Mnemonic = enum { |
| ... | @@ -115,6 +158,9 @@ pub const Mnemonic = enum { | ... | @@ -115,6 +158,9 @@ pub const Mnemonic = enum { |
| 115 | addi, | 158 | addi, |
| 116 | jalr, | 159 | jalr, |
| 117 | 160 | ||
| 161 | vsetivli, | ||
| 162 | vsetvli, | ||
| 163 | |||
| 118 | // U Type | 164 | // U Type |
| 119 | lui, | 165 | lui, |
| 120 | auipc, | 166 | auipc, |
| ... | @@ -155,6 +201,8 @@ pub const Mnemonic = enum { | ... | @@ -155,6 +201,8 @@ pub const Mnemonic = enum { |
| 155 | ebreak, | 201 | ebreak, |
| 156 | unimp, | 202 | unimp, |
| 157 | 203 | ||
| 204 | csrrs, | ||
| 205 | |||
| 158 | // M extension | 206 | // M extension |
| 159 | mul, | 207 | mul, |
| 160 | mulw, | 208 | mulw, |
| ... | @@ -217,6 +265,17 @@ pub const Mnemonic = enum { | ... | @@ -217,6 +265,17 @@ pub const Mnemonic = enum { |
| 217 | fsgnjnd, | 265 | fsgnjnd, |
| 218 | fsgnjxd, | 266 | fsgnjxd, |
| 219 | 267 | ||
| 268 | // V Extension | ||
| 269 | vle32v, | ||
| 270 | vle64v, | ||
| 271 | |||
| 272 | vse32v, | ||
| 273 | vse64v, | ||
| 274 | |||
| 275 | vaddvv, | ||
| 276 | vadcxv, | ||
| 277 | vadcvx, | ||
| 278 | |||
| 220 | // MISC | 279 | // MISC |
| 221 | fence, | 280 | fence, |
| 222 | fencetso, | 281 | fencetso, |
| ... | @@ -373,6 +432,9 @@ pub const Mnemonic = enum { | ... | @@ -373,6 +432,9 @@ pub const Mnemonic = enum { |
| 373 | 432 | ||
| 374 | .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, | 433 | .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, |
| 375 | .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, | 434 | .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 } } }, | ||
| 376 | 438 | ||
| 377 | 439 | ||
| 378 | // STORE_FP | 440 | // STORE_FP |
| ... | @@ -380,6 +442,8 @@ pub const Mnemonic = enum { | ... | @@ -380,6 +442,8 @@ pub const Mnemonic = enum { |
| 380 | .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, | 442 | .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, |
| 381 | .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, | 443 | .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, |
| 382 | 444 | ||
| 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 } } }, | ||
| 383 | 447 | ||
| 384 | // JALR | 448 | // JALR |
| 385 | 449 | ||
| ... | @@ -410,6 +474,8 @@ pub const Mnemonic = enum { | ... | @@ -410,6 +474,8 @@ pub const Mnemonic = enum { |
| 410 | 474 | ||
| 411 | .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, | 475 | .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, |
| 412 | .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, | 476 | .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, |
| 477 | |||
| 478 | .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } }, | ||
| 413 | 479 | ||
| 414 | 480 | ||
| 415 | // NONE | 481 | // NONE |
| ... | @@ -449,7 +515,13 @@ pub const Mnemonic = enum { | ... | @@ -449,7 +515,13 @@ pub const Mnemonic = enum { |
| 449 | .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } }, | 515 | .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } }, |
| 450 | .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } }, | 516 | .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } }, |
| 451 | 517 | ||
| 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 | |||
| 453 | // zig fmt: on | 525 | // zig fmt: on |
| 454 | }; | 526 | }; |
| 455 | } | 527 | } |
| ... | @@ -465,7 +537,6 @@ pub const InstEnc = enum { | ... | @@ -465,7 +537,6 @@ pub const InstEnc = enum { |
| 465 | J, | 537 | J, |
| 466 | fence, | 538 | fence, |
| 467 | amo, | 539 | amo, |
| 468 | /// extras that have unusual op counts | ||
| 469 | system, | 540 | system, |
| 470 | 541 | ||
| 471 | pub fn fromMnemonic(mnem: Mnemonic) InstEnc { | 542 | pub fn fromMnemonic(mnem: Mnemonic) InstEnc { |
| ... | @@ -494,6 +565,10 @@ pub const InstEnc = enum { | ... | @@ -494,6 +565,10 @@ pub const InstEnc = enum { |
| 494 | 565 | ||
| 495 | .flw, | 566 | .flw, |
| 496 | .fld, | 567 | .fld, |
| 568 | |||
| 569 | .csrrs, | ||
| 570 | .vsetivli, | ||
| 571 | .vsetvli, | ||
| 497 | => .I, | 572 | => .I, |
| 498 | 573 | ||
| 499 | .lui, | 574 | .lui, |
| ... | @@ -587,6 +662,14 @@ pub const InstEnc = enum { | ... | @@ -587,6 +662,14 @@ pub const InstEnc = enum { |
| 587 | 662 | ||
| 588 | .fsgnjxs, | 663 | .fsgnjxs, |
| 589 | .fsgnjxd, | 664 | .fsgnjxd, |
| 665 | |||
| 666 | .vle32v, | ||
| 667 | .vle64v, | ||
| 668 | .vse32v, | ||
| 669 | .vse64v, | ||
| 670 | .vaddvv, | ||
| 671 | .vadcxv, | ||
| 672 | .vadcvx, | ||
| 590 | => .R, | 673 | => .R, |
| 591 | 674 | ||
| 592 | .ecall, | 675 | .ecall, |
| ... | @@ -757,6 +840,25 @@ pub const Data = union(InstEnc) { | ... | @@ -757,6 +840,25 @@ pub const Data = union(InstEnc) { |
| 757 | }, | 840 | }, |
| 758 | }; | 841 | }; |
| 759 | }, | 842 | }, |
| 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 | }, | ||
| 760 | else => {}, | 862 | else => {}, |
| 761 | } | 863 | } |
| 762 | 864 | ||
| ... | @@ -783,6 +885,25 @@ pub const Data = union(InstEnc) { | ... | @@ -783,6 +885,25 @@ pub const Data = union(InstEnc) { |
| 783 | .funct3 = fmt.rm, | 885 | .funct3 = fmt.rm, |
| 784 | .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt), | 886 | .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt), |
| 785 | }, | 887 | }, |
| 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 | }, | ||
| 786 | else => unreachable, | 907 | else => unreachable, |
| 787 | }, | 908 | }, |
| 788 | }; | 909 | }; |
| ... | @@ -897,21 +1018,21 @@ pub const Data = union(InstEnc) { | ... | @@ -897,21 +1018,21 @@ pub const Data = union(InstEnc) { |
| 897 | .amo => { | 1018 | .amo => { |
| 898 | assert(ops.len == 5); | 1019 | assert(ops.len == 5); |
| 899 | 1020 | ||
| 900 | const rd = ops[0]; | 1021 | const rd = ops[0].reg; |
| 901 | const rs1 = ops[1]; | 1022 | const rs1 = ops[1].reg; |
| 902 | const rs2 = ops[2]; | 1023 | const rs2 = ops[2].reg; |
| 903 | const rl = ops[3]; | 1024 | const rl = ops[3].barrier; |
| 904 | const aq = ops[4]; | 1025 | const aq = ops[4].barrier; |
| 905 | 1026 | ||
| 906 | return .{ | 1027 | return .{ |
| 907 | .amo = .{ | 1028 | .amo = .{ |
| 908 | .rd = rd.reg.encodeId(), | 1029 | .rd = rd.encodeId(), |
| 909 | .rs1 = rs1.reg.encodeId(), | 1030 | .rs1 = rs1.encodeId(), |
| 910 | .rs2 = rs2.reg.encodeId(), | 1031 | .rs2 = rs2.encodeId(), |
| 911 | 1032 | ||
| 912 | // TODO: https://github.com/ziglang/zig/issues/20113 | 1033 | // TODO: https://github.com/ziglang/zig/issues/20113 |
| 913 | .rl = if (rl.barrier == .rl) true else false, | 1034 | .rl = if (rl == .rl) true else false, |
| 914 | .aq = if (aq.barrier == .aq) true else false, | 1035 | .aq = if (aq == .aq) true else false, |
| 915 | 1036 | ||
| 916 | .opcode = @intFromEnum(enc.opcode), | 1037 | .opcode = @intFromEnum(enc.opcode), |
| 917 | .funct3 = @intFromEnum(enc.data.amo.width), | 1038 | .funct3 = @intFromEnum(enc.data.amo.width), |
| ... | @@ -919,7 +1040,6 @@ pub const Data = union(InstEnc) { | ... | @@ -919,7 +1040,6 @@ pub const Data = union(InstEnc) { |
| 919 | }, | 1040 | }, |
| 920 | }; | 1041 | }; |
| 921 | }, | 1042 | }, |
| 922 | |||
| 923 | else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), | 1043 | else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), |
| 924 | } | 1044 | } |
| 925 | } | 1045 | } |
src/arch/riscv64/Lower.zig+124-56| ... | @@ -80,58 +80,99 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { | ... | @@ -80,58 +80,99 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { |
| 80 | .pseudo_load_rm => { | 80 | .pseudo_load_rm => { |
| 81 | const dest_reg = rm.r; | 81 | const dest_reg = rm.r; |
| 82 | const dest_reg_class = dest_reg.class(); | 82 | const dest_reg_class = dest_reg.class(); |
| 83 | const float = dest_reg_class == .float; | ||
| 84 | 83 | ||
| 85 | const src_size = rm.m.mod.size; | 84 | const src_size = rm.m.mod.size; |
| 86 | const unsigned = rm.m.mod.unsigned; | 85 | const unsigned = rm.m.mod.unsigned; |
| 87 | 86 | ||
| 88 | const tag: Encoding.Mnemonic = if (!float) | 87 | const tag: Encoding.Mnemonic = switch (dest_reg_class) { |
| 89 | switch (src_size) { | 88 | .int => switch (src_size) { |
| 90 | .byte => if (unsigned) .lbu else .lb, | 89 | .byte => if (unsigned) .lbu else .lb, |
| 91 | .hword => if (unsigned) .lhu else .lh, | 90 | .hword => if (unsigned) .lhu else .lh, |
| 92 | .word => if (unsigned) .lwu else .lw, | 91 | .word => if (unsigned) .lwu else .lw, |
| 93 | .dword => .ld, | 92 | .dword => .ld, |
| 94 | } | 93 | }, |
| 95 | else switch (src_size) { | 94 | .float => switch (src_size) { |
| 96 | .byte => unreachable, // Zig does not support 8-bit floats | 95 | .byte => unreachable, // Zig does not support 8-bit floats |
| 97 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), | 96 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), |
| 98 | .word => .flw, | 97 | .word => .flw, |
| 99 | .dword => .fld, | 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 | }, | ||
| 100 | }; | 110 | }; |
| 101 | 111 | ||
| 102 | try lower.emit(tag, &.{ | 112 | switch (dest_reg_class) { |
| 103 | .{ .reg = rm.r }, | 113 | .int, .float => { |
| 104 | .{ .reg = frame_loc.base }, | 114 | try lower.emit(tag, &.{ |
| 105 | .{ .imm = Immediate.s(frame_loc.disp) }, | 115 | .{ .reg = rm.r }, |
| 106 | }); | 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 | } | ||
| 107 | }, | 128 | }, |
| 108 | .pseudo_store_rm => { | 129 | .pseudo_store_rm => { |
| 109 | const src_reg = rm.r; | 130 | const src_reg = rm.r; |
| 110 | const src_reg_class = src_reg.class(); | 131 | const src_reg_class = src_reg.class(); |
| 111 | const float = src_reg_class == .float; | ||
| 112 | 132 | ||
| 113 | // TODO: do we actually need this? are all stores not usize? | ||
| 114 | const dest_size = rm.m.mod.size; | 133 | const dest_size = rm.m.mod.size; |
| 115 | 134 | ||
| 116 | const tag: Encoding.Mnemonic = if (!float) | 135 | const tag: Encoding.Mnemonic = switch (src_reg_class) { |
| 117 | switch (dest_size) { | 136 | .int => switch (dest_size) { |
| 118 | .byte => .sb, | 137 | .byte => .sb, |
| 119 | .hword => .sh, | 138 | .hword => .sh, |
| 120 | .word => .sw, | 139 | .word => .sw, |
| 121 | .dword => .sd, | 140 | .dword => .sd, |
| 122 | } | 141 | }, |
| 123 | else switch (dest_size) { | 142 | .float => switch (dest_size) { |
| 124 | .byte => unreachable, // Zig does not support 8-bit floats | 143 | .byte => unreachable, // Zig does not support 8-bit floats |
| 125 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), | 144 | .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}), |
| 126 | .word => .fsw, | 145 | .word => .fsw, |
| 127 | .dword => .fsd, | 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 | }, | ||
| 128 | }; | 158 | }; |
| 129 | 159 | ||
| 130 | try lower.emit(tag, &.{ | 160 | switch (src_reg_class) { |
| 131 | .{ .reg = frame_loc.base }, | 161 | .int, .float => { |
| 132 | .{ .reg = rm.r }, | 162 | try lower.emit(tag, &.{ |
| 133 | .{ .imm = Immediate.s(frame_loc.disp) }, | 163 | .{ .reg = frame_loc.base }, |
| 134 | }); | 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 | } | ||
| 135 | }, | 176 | }, |
| 136 | else => unreachable, | 177 | else => unreachable, |
| 137 | } | 178 | } |
| ... | @@ -143,34 +184,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { | ... | @@ -143,34 +184,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { |
| 143 | const dst_class = rr.rd.class(); | 184 | const dst_class = rr.rd.class(); |
| 144 | const src_class = rr.rs.class(); | 185 | const src_class = rr.rs.class(); |
| 145 | 186 | ||
| 146 | assert(dst_class == src_class); | 187 | switch (src_class) { |
| 147 | 188 | .float => switch (dst_class) { | |
| 148 | switch (dst_class) { | 189 | .float => { |
| 149 | .float => { | 190 | try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{ |
| 150 | try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{ | 191 | .{ .reg = rr.rd }, |
| 151 | .{ .reg = rr.rd }, | 192 | .{ .reg = rr.rs }, |
| 152 | .{ .reg = rr.rs }, | 193 | .{ .reg = rr.rs }, |
| 153 | .{ .reg = rr.rs }, | 194 | }); |
| 154 | }); | 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)}), | ||
| 155 | }, | 214 | }, |
| 156 | .int => { | 215 | .vector => switch (dst_class) { |
| 157 | try lower.emit(.addi, &.{ | 216 | .int => { |
| 158 | .{ .reg = rr.rd }, | 217 | try lower.emit(.vadcvx, &.{ |
| 159 | .{ .reg = rr.rs }, | 218 | .{ .reg = rr.rd }, |
| 160 | .{ .imm = Immediate.s(0) }, | 219 | .{ .reg = rr.rs }, |
| 161 | }); | 220 | .{ .reg = .zero }, |
| 221 | }); | ||
| 222 | }, | ||
| 223 | .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}), | ||
| 162 | }, | 224 | }, |
| 163 | } | 225 | } |
| 164 | }, | 226 | }, |
| 165 | 227 | ||
| 166 | .pseudo_ret => { | ||
| 167 | try lower.emit(.jalr, &.{ | ||
| 168 | .{ .reg = .zero }, | ||
| 169 | .{ .reg = .ra }, | ||
| 170 | .{ .imm = Immediate.s(0) }, | ||
| 171 | }); | ||
| 172 | }, | ||
| 173 | |||
| 174 | .pseudo_j => { | 228 | .pseudo_j => { |
| 175 | try lower.emit(.jal, &.{ | 229 | try lower.emit(.jal, &.{ |
| 176 | .{ .reg = .zero }, | 230 | .{ .reg = .zero }, |
| ... | @@ -209,7 +263,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { | ... | @@ -209,7 +263,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { |
| 209 | const rm = inst.data.rm; | 263 | const rm = inst.data.rm; |
| 210 | assert(rm.r.class() == .int); | 264 | assert(rm.r.class() == .int); |
| 211 | 265 | ||
| 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 }; | ||
| 213 | 270 | ||
| 214 | try lower.emit(.addi, &.{ | 271 | try lower.emit(.addi, &.{ |
| 215 | .{ .reg = rm.r }, | 272 | .{ .reg = rm.r }, |
| ... | @@ -376,6 +433,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { | ... | @@ -376,6 +433,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { |
| 376 | }); | 433 | }); |
| 377 | }, | 434 | }, |
| 378 | }, | 435 | }, |
| 436 | .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}), | ||
| 379 | } | 437 | } |
| 380 | }, | 438 | }, |
| 381 | 439 | ||
| ... | @@ -497,6 +555,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { | ... | @@ -497,6 +555,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 497 | .{ .reg = inst.data.r_type.rs1 }, | 555 | .{ .reg = inst.data.r_type.rs1 }, |
| 498 | .{ .reg = inst.data.r_type.rs2 }, | 556 | .{ .reg = inst.data.r_type.rs2 }, |
| 499 | }, | 557 | }, |
| 558 | .csr => &.{ | ||
| 559 | .{ .csr = inst.data.csr.csr }, | ||
| 560 | .{ .reg = inst.data.csr.rs1 }, | ||
| 561 | .{ .reg = inst.data.csr.rd }, | ||
| 562 | }, | ||
| 500 | else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), | 563 | else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), |
| 501 | }); | 564 | }); |
| 502 | } | 565 | } |
| ... | @@ -523,17 +586,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register | ... | @@ -523,17 +586,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register |
| 523 | while (it.next()) |i| { | 586 | while (it.next()) |i| { |
| 524 | const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame)); | 587 | const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame)); |
| 525 | const reg = abi.Registers.all_preserved[i]; | 588 | const reg = abi.Registers.all_preserved[i]; |
| 589 | |||
| 526 | const reg_class = reg.class(); | 590 | 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 | }; | ||
| 528 | 596 | ||
| 529 | if (spilling) { | 597 | if (spilling) { |
| 530 | try lower.emit(if (is_float_reg) .fsd else .sd, &.{ | 598 | try lower.emit(store_inst, &.{ |
| 531 | .{ .reg = frame.base }, | 599 | .{ .reg = frame.base }, |
| 532 | .{ .reg = abi.Registers.all_preserved[i] }, | 600 | .{ .reg = abi.Registers.all_preserved[i] }, |
| 533 | .{ .imm = Immediate.s(frame.disp + reg_i) }, | 601 | .{ .imm = Immediate.s(frame.disp + reg_i) }, |
| 534 | }); | 602 | }); |
| 535 | } else { | 603 | } else { |
| 536 | try lower.emit(if (is_float_reg) .fld else .ld, &.{ | 604 | try lower.emit(load_inst, &.{ |
| 537 | .{ .reg = abi.Registers.all_preserved[i] }, | 605 | .{ .reg = abi.Registers.all_preserved[i] }, |
| 538 | .{ .reg = frame.base }, | 606 | .{ .reg = frame.base }, |
| 539 | .{ .imm = Immediate.s(frame.disp + reg_i) }, | 607 | .{ .imm = Immediate.s(frame.disp + reg_i) }, |
src/arch/riscv64/Mir.zig+19-51| ... | @@ -134,7 +134,16 @@ pub const Inst = struct { | ... | @@ -134,7 +134,16 @@ pub const Inst = struct { |
| 134 | fltd, | 134 | fltd, |
| 135 | fled, | 135 | fled, |
| 136 | 136 | ||
| 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 | ||
| 138 | amo, | 147 | amo, |
| 139 | 148 | ||
| 140 | /// A pseudo-instruction. Used for anything that isn't 1:1 with an | 149 | /// A pseudo-instruction. Used for anything that isn't 1:1 with an |
| ... | @@ -146,91 +155,57 @@ pub const Inst = struct { | ... | @@ -146,91 +155,57 @@ pub const Inst = struct { |
| 146 | /// this union. `Ops` determines which union field is active, as well as | 155 | /// this union. `Ops` determines which union field is active, as well as |
| 147 | /// how to interpret the data within. | 156 | /// how to interpret the data within. |
| 148 | pub const Data = union { | 157 | pub const Data = union { |
| 149 | /// No additional data | ||
| 150 | /// | ||
| 151 | /// Used by e.g. ebreak | ||
| 152 | nop: void, | 158 | nop: void, |
| 153 | /// Another instruction. | ||
| 154 | /// | ||
| 155 | /// Used by e.g. b | ||
| 156 | inst: Index, | 159 | inst: Index, |
| 157 | /// Index into `extra`. Meaning of what can be found there is context-dependent. | ||
| 158 | /// | ||
| 159 | /// Used by e.g. load_memory | ||
| 160 | payload: u32, | 160 | payload: u32, |
| 161 | |||
| 162 | r_type: struct { | 161 | r_type: struct { |
| 163 | rd: Register, | 162 | rd: Register, |
| 164 | rs1: Register, | 163 | rs1: Register, |
| 165 | rs2: Register, | 164 | rs2: Register, |
| 166 | }, | 165 | }, |
| 167 | |||
| 168 | i_type: struct { | 166 | i_type: struct { |
| 169 | rd: Register, | 167 | rd: Register, |
| 170 | rs1: Register, | 168 | rs1: Register, |
| 171 | imm12: Immediate, | 169 | imm12: Immediate, |
| 172 | }, | 170 | }, |
| 173 | |||
| 174 | s_type: struct { | 171 | s_type: struct { |
| 175 | rs1: Register, | 172 | rs1: Register, |
| 176 | rs2: Register, | 173 | rs2: Register, |
| 177 | imm5: Immediate, | 174 | imm5: Immediate, |
| 178 | imm7: Immediate, | 175 | imm7: Immediate, |
| 179 | }, | 176 | }, |
| 180 | |||
| 181 | b_type: struct { | 177 | b_type: struct { |
| 182 | rs1: Register, | 178 | rs1: Register, |
| 183 | rs2: Register, | 179 | rs2: Register, |
| 184 | inst: Inst.Index, | 180 | inst: Inst.Index, |
| 185 | }, | 181 | }, |
| 186 | |||
| 187 | u_type: struct { | 182 | u_type: struct { |
| 188 | rd: Register, | 183 | rd: Register, |
| 189 | imm20: Immediate, | 184 | imm20: Immediate, |
| 190 | }, | 185 | }, |
| 191 | |||
| 192 | j_type: struct { | 186 | j_type: struct { |
| 193 | rd: Register, | 187 | rd: Register, |
| 194 | inst: Inst.Index, | 188 | inst: Inst.Index, |
| 195 | }, | 189 | }, |
| 196 | |||
| 197 | /// Debug info: line and column | ||
| 198 | /// | ||
| 199 | /// Used by e.g. pseudo_dbg_line | ||
| 200 | pseudo_dbg_line_column: struct { | 190 | pseudo_dbg_line_column: struct { |
| 201 | line: u32, | 191 | line: u32, |
| 202 | column: u32, | 192 | column: u32, |
| 203 | }, | 193 | }, |
| 204 | |||
| 205 | // Custom types to be lowered | ||
| 206 | |||
| 207 | /// Register + Memory | ||
| 208 | rm: struct { | 194 | rm: struct { |
| 209 | r: Register, | 195 | r: Register, |
| 210 | m: Memory, | 196 | m: Memory, |
| 211 | }, | 197 | }, |
| 212 | |||
| 213 | reg_list: Mir.RegisterList, | 198 | reg_list: Mir.RegisterList, |
| 214 | |||
| 215 | /// A register | ||
| 216 | /// | ||
| 217 | /// Used by e.g. blr | ||
| 218 | reg: Register, | 199 | reg: Register, |
| 219 | |||
| 220 | /// Two registers | ||
| 221 | /// | ||
| 222 | /// Used by e.g. mv | ||
| 223 | rr: struct { | 200 | rr: struct { |
| 224 | rd: Register, | 201 | rd: Register, |
| 225 | rs: Register, | 202 | rs: Register, |
| 226 | }, | 203 | }, |
| 227 | |||
| 228 | fabs: struct { | 204 | fabs: struct { |
| 229 | rd: Register, | 205 | rd: Register, |
| 230 | rs: Register, | 206 | rs: Register, |
| 231 | bits: u16, | 207 | bits: u16, |
| 232 | }, | 208 | }, |
| 233 | |||
| 234 | compare: struct { | 209 | compare: struct { |
| 235 | rd: Register, | 210 | rd: Register, |
| 236 | rs1: Register, | 211 | rs1: Register, |
| ... | @@ -245,12 +220,10 @@ pub const Inst = struct { | ... | @@ -245,12 +220,10 @@ pub const Inst = struct { |
| 245 | }, | 220 | }, |
| 246 | ty: Type, | 221 | ty: Type, |
| 247 | }, | 222 | }, |
| 248 | |||
| 249 | reloc: struct { | 223 | reloc: struct { |
| 250 | atom_index: u32, | 224 | atom_index: u32, |
| 251 | sym_index: u32, | 225 | sym_index: u32, |
| 252 | }, | 226 | }, |
| 253 | |||
| 254 | fence: struct { | 227 | fence: struct { |
| 255 | pred: Barrier, | 228 | pred: Barrier, |
| 256 | succ: Barrier, | 229 | succ: Barrier, |
| ... | @@ -259,7 +232,6 @@ pub const Inst = struct { | ... | @@ -259,7 +232,6 @@ pub const Inst = struct { |
| 259 | tso, | 232 | tso, |
| 260 | }, | 233 | }, |
| 261 | }, | 234 | }, |
| 262 | |||
| 263 | amo: struct { | 235 | amo: struct { |
| 264 | rd: Register, | 236 | rd: Register, |
| 265 | rs1: Register, | 237 | rs1: Register, |
| ... | @@ -269,6 +241,11 @@ pub const Inst = struct { | ... | @@ -269,6 +241,11 @@ pub const Inst = struct { |
| 269 | op: AmoOp, | 241 | op: AmoOp, |
| 270 | ty: Type, | 242 | ty: Type, |
| 271 | }, | 243 | }, |
| 244 | csr: struct { | ||
| 245 | csr: CSR, | ||
| 246 | rs1: Register, | ||
| 247 | rd: Register, | ||
| 248 | }, | ||
| 272 | }; | 249 | }; |
| 273 | 250 | ||
| 274 | pub const Ops = enum { | 251 | pub const Ops = enum { |
| ... | @@ -293,6 +270,9 @@ pub const Inst = struct { | ... | @@ -293,6 +270,9 @@ pub const Inst = struct { |
| 293 | /// Another instruction. | 270 | /// Another instruction. |
| 294 | inst, | 271 | inst, |
| 295 | 272 | ||
| 273 | /// Control and Status Register Instruction. | ||
| 274 | csr, | ||
| 275 | |||
| 296 | /// Pseudo-instruction that will generate a backpatched | 276 | /// Pseudo-instruction that will generate a backpatched |
| 297 | /// function prologue. | 277 | /// function prologue. |
| 298 | pseudo_prologue, | 278 | pseudo_prologue, |
| ... | @@ -321,11 +301,6 @@ pub const Inst = struct { | ... | @@ -321,11 +301,6 @@ pub const Inst = struct { |
| 321 | /// Uses `rm` payload. | 301 | /// Uses `rm` payload. |
| 322 | pseudo_lea_rm, | 302 | pseudo_lea_rm, |
| 323 | 303 | ||
| 324 | /// Shorthand for returning, aka jumping to ra register. | ||
| 325 | /// | ||
| 326 | /// Uses nop payload. | ||
| 327 | pseudo_ret, | ||
| 328 | |||
| 329 | /// Jumps. Uses `inst` payload. | 304 | /// Jumps. Uses `inst` payload. |
| 330 | pseudo_j, | 305 | pseudo_j, |
| 331 | 306 | ||
| ... | @@ -363,14 +338,6 @@ pub const Inst = struct { | ... | @@ -363,14 +338,6 @@ pub const Inst = struct { |
| 363 | pseudo_amo, | 338 | pseudo_amo, |
| 364 | }; | 339 | }; |
| 365 | 340 | ||
| 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 | |||
| 374 | pub fn format( | 341 | pub fn format( |
| 375 | inst: Inst, | 342 | inst: Inst, |
| 376 | comptime fmt: []const u8, | 343 | comptime fmt: []const u8, |
| ... | @@ -490,6 +457,7 @@ const assert = std.debug.assert; | ... | @@ -490,6 +457,7 @@ const assert = std.debug.assert; |
| 490 | 457 | ||
| 491 | const bits = @import("bits.zig"); | 458 | const bits = @import("bits.zig"); |
| 492 | const Register = bits.Register; | 459 | const Register = bits.Register; |
| 460 | const CSR = bits.CSR; | ||
| 493 | const Immediate = bits.Immediate; | 461 | const Immediate = bits.Immediate; |
| 494 | const Memory = bits.Memory; | 462 | const Memory = bits.Memory; |
| 495 | const FrameIndex = bits.FrameIndex; | 463 | const FrameIndex = bits.FrameIndex; |
src/arch/riscv64/abi.zig+24-2| ... | @@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass { | ... | @@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass { |
| 193 | } | 193 | } |
| 194 | return memory_class; | 194 | return memory_class; |
| 195 | }, | 195 | }, |
| 196 | .Vector => { | ||
| 197 | // we pass vectors through integer registers if they are small enough to fit. | ||
| 198 | const vec_bits = ty.totalVectorBits(pt); | ||
| 199 | if (vec_bits <= 64) { | ||
| 200 | result[0] = .integer; | ||
| 201 | return result; | ||
| 202 | } | ||
| 203 | return memory_class; | ||
| 204 | }, | ||
| 196 | else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}), | 205 | else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}), |
| 197 | } | 206 | } |
| 198 | } | 207 | } |
| ... | @@ -254,15 +263,15 @@ fn classifyStruct( | ... | @@ -254,15 +263,15 @@ fn classifyStruct( |
| 254 | } | 263 | } |
| 255 | } | 264 | } |
| 256 | 265 | ||
| 257 | const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs; | 266 | const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs ++ Registers.Vector.all_regs; |
| 258 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | 267 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); |
| 259 | 268 | ||
| 260 | // Register classes | ||
| 261 | const RegisterBitSet = RegisterManager.RegisterBitSet; | 269 | const RegisterBitSet = RegisterManager.RegisterBitSet; |
| 262 | 270 | ||
| 263 | pub const RegisterClass = enum { | 271 | pub const RegisterClass = enum { |
| 264 | int, | 272 | int, |
| 265 | float, | 273 | float, |
| 274 | vector, | ||
| 266 | }; | 275 | }; |
| 267 | 276 | ||
| 268 | pub const Registers = struct { | 277 | pub const Registers = struct { |
| ... | @@ -322,6 +331,19 @@ pub const Registers = struct { | ... | @@ -322,6 +331,19 @@ pub const Registers = struct { |
| 322 | 331 | ||
| 323 | pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs; | 332 | pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs; |
| 324 | }; | 333 | }; |
| 334 | |||
| 335 | pub const Vector = struct { | ||
| 336 | pub const general_purpose = initRegBitSet(Integer.all_regs.len + Float.all_regs.len, all_regs.len); | ||
| 337 | |||
| 338 | // zig fmt: off | ||
| 339 | pub const all_regs = [_]Register{ | ||
| 340 | .v0, .v1, .v2, .v3, .v4, .v5, .v6, .v7, | ||
| 341 | .v8, .v9, .v10, .v11, .v12, .v13, .v14, .v15, | ||
| 342 | .v16, .v17, .v18, .v19, .v20, .v21, .v22, .v23, | ||
| 343 | .v24, .v25, .v26, .v27, .v28, .v29, .v30, .v31, | ||
| 344 | }; | ||
| 345 | // zig fmt: on | ||
| 346 | }; | ||
| 325 | }; | 347 | }; |
| 326 | 348 | ||
| 327 | fn initRegBitSet(start: usize, length: usize) RegisterBitSet { | 349 | fn initRegBitSet(start: usize, length: usize) RegisterBitSet { |
src/arch/riscv64/bits.zig+41-1| ... | @@ -128,6 +128,12 @@ pub const Immediate = union(enum) { | ... | @@ -128,6 +128,12 @@ pub const Immediate = union(enum) { |
| 128 | } | 128 | } |
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | pub const CSR = enum(u12) { | ||
| 132 | vl = 0xC20, | ||
| 133 | vtype = 0xC21, | ||
| 134 | vlenb = 0xC22, | ||
| 135 | }; | ||
| 136 | |||
| 131 | pub const Register = enum(u8) { | 137 | pub const Register = enum(u8) { |
| 132 | // zig fmt: off | 138 | // zig fmt: off |
| 133 | 139 | ||
| ... | @@ -169,6 +175,13 @@ pub const Register = enum(u8) { | ... | @@ -169,6 +175,13 @@ pub const Register = enum(u8) { |
| 169 | f16, f17, f18, f19, f20, f21, f22, f23, | 175 | f16, f17, f18, f19, f20, f21, f22, f23, |
| 170 | f24, f25, f26, f27, f28, f29, f30, f31, | 176 | f24, f25, f26, f27, f28, f29, f30, f31, |
| 171 | 177 | ||
| 178 | |||
| 179 | // V extension registers | ||
| 180 | v0, v1, v2, v3, v4, v5, v6, v7, | ||
| 181 | v8, v9, v10, v11, v12, v13, v14, v15, | ||
| 182 | v16, v17, v18, v19, v20, v21, v22, v23, | ||
| 183 | v24, v25, v26, v27, v28, v29, v30, v31, | ||
| 184 | |||
| 172 | // zig fmt: on | 185 | // zig fmt: on |
| 173 | 186 | ||
| 174 | /// in RISC-V registers are stored as 5 bit IDs and a register can have | 187 | /// in RISC-V registers are stored as 5 bit IDs and a register can have |
| ... | @@ -180,11 +193,12 @@ pub const Register = enum(u8) { | ... | @@ -180,11 +193,12 @@ pub const Register = enum(u8) { |
| 180 | /// The goal of this function is to return the same ID for `zero` and `x0` but two | 193 | /// The goal of this function is to return the same ID for `zero` and `x0` but two |
| 181 | /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers | 194 | /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers |
| 182 | /// and is repeated twice, once for the named version, once for the number version. | 195 | /// and is repeated twice, once for the named version, once for the number version. |
| 183 | pub fn id(reg: Register) u7 { | 196 | pub fn id(reg: Register) u8 { |
| 184 | const base = switch (@intFromEnum(reg)) { | 197 | const base = switch (@intFromEnum(reg)) { |
| 185 | // zig fmt: off | 198 | // zig fmt: off |
| 186 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero), | 199 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero), |
| 187 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0), | 200 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0), |
| 201 | @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => @intFromEnum(Register.v0), | ||
| 188 | else => unreachable, | 202 | else => unreachable, |
| 189 | // zig fmt: on | 203 | // zig fmt: on |
| 190 | }; | 204 | }; |
| ... | @@ -207,6 +221,7 @@ pub const Register = enum(u8) { | ... | @@ -207,6 +221,7 @@ pub const Register = enum(u8) { |
| 207 | // zig fmt: off | 221 | // zig fmt: off |
| 208 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64, | 222 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64, |
| 209 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32, | 223 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32, |
| 224 | @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => 1024, // TODO: look at suggestVectorSize | ||
| 210 | else => unreachable, | 225 | else => unreachable, |
| 211 | // zig fmt: on | 226 | // zig fmt: on |
| 212 | }; | 227 | }; |
| ... | @@ -217,6 +232,7 @@ pub const Register = enum(u8) { | ... | @@ -217,6 +232,7 @@ pub const Register = enum(u8) { |
| 217 | // zig fmt: off | 232 | // zig fmt: off |
| 218 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int, | 233 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int, |
| 219 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float, | 234 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float, |
| 235 | @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => .vector, | ||
| 220 | else => unreachable, | 236 | else => unreachable, |
| 221 | // zig fmt: on | 237 | // zig fmt: on |
| 222 | }; | 238 | }; |
| ... | @@ -272,3 +288,27 @@ pub const Symbol = struct { | ... | @@ -272,3 +288,27 @@ pub const Symbol = struct { |
| 272 | /// Index into the linker's symbol table. | 288 | /// Index into the linker's symbol table. |
| 273 | sym_index: u32, | 289 | sym_index: u32, |
| 274 | }; | 290 | }; |
| 291 | |||
| 292 | pub const VType = packed struct(u8) { | ||
| 293 | vlmul: VlMul, | ||
| 294 | vsew: VSew, | ||
| 295 | vta: bool, | ||
| 296 | vma: bool, | ||
| 297 | }; | ||
| 298 | |||
| 299 | const VSew = enum(u3) { | ||
| 300 | @"8" = 0b000, | ||
| 301 | @"16" = 0b001, | ||
| 302 | @"32" = 0b010, | ||
| 303 | @"64" = 0b011, | ||
| 304 | }; | ||
| 305 | |||
| 306 | const 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 { | ... | @@ -5,6 +5,7 @@ pub const Instruction = struct { |
| 5 | pub const Operand = union(enum) { | 5 | pub const Operand = union(enum) { |
| 6 | none, | 6 | none, |
| 7 | reg: Register, | 7 | reg: Register, |
| 8 | csr: CSR, | ||
| 8 | mem: Memory, | 9 | mem: Memory, |
| 9 | imm: Immediate, | 10 | imm: Immediate, |
| 10 | barrier: Mir.Barrier, | 11 | barrier: Mir.Barrier, |
| ... | @@ -58,6 +59,7 @@ pub const Instruction = struct { | ... | @@ -58,6 +59,7 @@ pub const Instruction = struct { |
| 58 | .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}), | 59 | .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}), |
| 59 | .mem => try writer.writeAll("mem"), | 60 | .mem => try writer.writeAll("mem"), |
| 60 | .barrier => |barrier| try writer.writeAll(@tagName(barrier)), | 61 | .barrier => |barrier| try writer.writeAll(@tagName(barrier)), |
| 62 | .csr => |csr| try writer.writeAll(@tagName(csr)), | ||
| 61 | } | 63 | } |
| 62 | } | 64 | } |
| 63 | } | 65 | } |
| ... | @@ -71,6 +73,7 @@ const bits = @import("bits.zig"); | ... | @@ -71,6 +73,7 @@ const bits = @import("bits.zig"); |
| 71 | const Encoding = @import("Encoding.zig"); | 73 | const Encoding = @import("Encoding.zig"); |
| 72 | 74 | ||
| 73 | const Register = bits.Register; | 75 | const Register = bits.Register; |
| 76 | const CSR = bits.CSR; | ||
| 74 | const Memory = bits.Memory; | 77 | const Memory = bits.Memory; |
| 75 | const Immediate = bits.Immediate; | 78 | const Immediate = bits.Immediate; |
| 76 | 79 |
test/tests.zig+6-5| ... | @@ -436,11 +436,12 @@ const test_targets = blk: { | ... | @@ -436,11 +436,12 @@ const test_targets = blk: { |
| 436 | //}, | 436 | //}, |
| 437 | 437 | ||
| 438 | .{ | 438 | .{ |
| 439 | .target = .{ | 439 | .target = std.Target.Query.parse( |
| 440 | .cpu_arch = .riscv64, | 440 | .{ |
| 441 | .os_tag = .linux, | 441 | .arch_os_abi = "riscv64-linux-musl", |
| 442 | .abi = .musl, | 442 | .cpu_features = "baseline+v", |
| 443 | }, | 443 | }, |
| 444 | ) catch @panic("OOM"), | ||
| 444 | .use_llvm = false, | 445 | .use_llvm = false, |
| 445 | .use_lld = false, | 446 | .use_lld = false, |
| 446 | }, | 447 | }, |