authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-22 20:14:10-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
log5e010b6deac7ad34f0cd06d507fc468fd98f9abc
treed331bfc3ab68221d9e8f569d8b30f0e3374491d5
parent63bbf665538d927bd56646e063821e31577f83f5

riscv: reorganize `binOp` and implement `cmp_imm_gte` MIR

this was an annoying one to do, as there is no (to my knowledge) myriad sequence that will allow us to do `gte` compares with an immediate without allocating a register. RISC-V provides a single instruction to do compares, that being `lt`, and so you need to use more than one for other variants, but in this case, i believe you need to allocate a register.

3 files changed, 210 insertions(+), 162 deletions(-)

src/arch/riscv64/CodeGen.zig+159-139
...@@ -850,6 +850,122 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -850,6 +850,122 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
850 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });850 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
851}851}
852852
853fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
854 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
855 const lhs = try self.resolveInst(bin_op.lhs);
856 const rhs = try self.resolveInst(bin_op.rhs);
857 const lhs_ty = self.typeOf(bin_op.lhs);
858 const rhs_ty = self.typeOf(bin_op.rhs);
859
860 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
861 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
862}
863
864/// For all your binary operation needs, this function will generate
865/// the corresponding Mir instruction(s). Returns the location of the
866/// result.
867///
868/// If the binary operation itself happens to be an Air instruction,
869/// pass the corresponding index in the inst parameter. That helps
870/// this function do stuff like reusing operands.
871///
872/// This function does not do any lowering to Mir itself, but instead
873/// looks at the lhs and rhs and determines which kind of lowering
874/// would be best suitable and then delegates the lowering to other
875/// functions.
876///
877/// `maybe_inst` **needs** to be a bin_op, make sure of that.
878fn binOp(
879 self: *Self,
880 tag: Air.Inst.Tag,
881 maybe_inst: ?Air.Inst.Index,
882 lhs: MCValue,
883 rhs: MCValue,
884 lhs_ty: Type,
885 rhs_ty: Type,
886) InnerError!MCValue {
887 const mod = self.bin_file.comp.module.?;
888 switch (tag) {
889 // Arithmetic operations on integers and floats
890 .add,
891 .sub,
892 .cmp_eq,
893 .cmp_neq,
894 .cmp_gt,
895 .cmp_gte,
896 .cmp_lt,
897 .cmp_lte,
898 => {
899 switch (lhs_ty.zigTypeTag(mod)) {
900 .Float => return self.fail("TODO binary operations on floats", .{}),
901 .Vector => return self.fail("TODO binary operations on vectors", .{}),
902 .Int => {
903 assert(lhs_ty.eql(rhs_ty, mod));
904 const int_info = lhs_ty.intInfo(mod);
905 if (int_info.bits <= 64) {
906 if (rhs == .immediate) {
907 return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
908 }
909 return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
910 } else {
911 return self.fail("TODO binary operations on int with bits > 64", .{});
912 }
913 },
914 else => unreachable,
915 }
916 },
917 .ptr_add,
918 .ptr_sub,
919 => {
920 switch (lhs_ty.zigTypeTag(mod)) {
921 .Pointer => {
922 const ptr_ty = lhs_ty;
923 const elem_ty = switch (ptr_ty.ptrSize(mod)) {
924 .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type
925 else => ptr_ty.childType(mod),
926 };
927 const elem_size = elem_ty.abiSize(mod);
928
929 if (elem_size == 1) {
930 const base_tag: Air.Inst.Tag = switch (tag) {
931 .ptr_add => .add,
932 .ptr_sub => .sub,
933 else => unreachable,
934 };
935
936 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
937 } else {
938 return self.fail("TODO ptr_add with elem_size > 1", .{});
939 }
940 },
941 else => unreachable,
942 }
943 },
944
945 // These instructions have unsymteric bit sizes on RHS and LHS.
946 .shr,
947 .shl,
948 => {
949 switch (lhs_ty.zigTypeTag(mod)) {
950 .Float => return self.fail("TODO binary operations on floats", .{}),
951 .Vector => return self.fail("TODO binary operations on vectors", .{}),
952 .Int => {
953 const int_info = lhs_ty.intInfo(mod);
954 if (int_info.bits <= 64) {
955 if (rhs == .immediate) {
956 return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
957 }
958 return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
959 } else {
960 return self.fail("TODO binary operations on int with bits > 64", .{});
961 }
962 },
963 else => unreachable,
964 }
965 },
966 else => unreachable,
967 }
968}
853/// Don't call this function directly. Use binOp instead.969/// Don't call this function directly. Use binOp instead.
854///970///
855/// Calling this function signals an intention to generate a Mir971/// Calling this function signals an intention to generate a Mir
...@@ -963,7 +1079,6 @@ fn binOpImm(...@@ -963,7 +1079,6 @@ fn binOpImm(
963 lhs_ty: Type,1079 lhs_ty: Type,
964 rhs_ty: Type,1080 rhs_ty: Type,
965) !MCValue {1081) !MCValue {
966 _ = rhs_ty;
967 assert(rhs == .immediate);1082 assert(rhs == .immediate);
9681083
969 const lhs_is_register = lhs == .register;1084 const lhs_is_register = lhs == .register;
...@@ -1006,142 +1121,44 @@ fn binOpImm(...@@ -1006,142 +1121,44 @@ fn binOpImm(
1006 const mir_tag: Mir.Inst.Tag = switch (tag) {1121 const mir_tag: Mir.Inst.Tag = switch (tag) {
1007 .shl => .slli,1122 .shl => .slli,
1008 .shr => .srli,1123 .shr => .srli,
1124 .cmp_gte => .cmp_imm_gte,
1009 else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}),1125 else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}),
1010 };1126 };
10111127
1012 _ = try self.addInst(.{1128 // apply some special operations needed
1013 .tag = mir_tag,1129 switch (mir_tag) {
1014 .data = .{1130 .slli,
1015 .i_type = .{1131 .srli,
1016 .rd = dest_reg,
1017 .rs1 = lhs_reg,
1018 .imm12 = math.cast(i12, rhs.immediate) orelse {
1019 return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
1020 },
1021 },
1022 },
1023 });
1024
1025 // generate the struct for OF checks
1026
1027 return MCValue{ .register = dest_reg };
1028}
1029
1030/// For all your binary operation needs, this function will generate
1031/// the corresponding Mir instruction(s). Returns the location of the
1032/// result.
1033///
1034/// If the binary operation itself happens to be an Air instruction,
1035/// pass the corresponding index in the inst parameter. That helps
1036/// this function do stuff like reusing operands.
1037///
1038/// This function does not do any lowering to Mir itself, but instead
1039/// looks at the lhs and rhs and determines which kind of lowering
1040/// would be best suitable and then delegates the lowering to other
1041/// functions.
1042///
1043/// `maybe_inst` **needs** to be a bin_op, make sure of that.
1044fn binOp(
1045 self: *Self,
1046 tag: Air.Inst.Tag,
1047 maybe_inst: ?Air.Inst.Index,
1048 lhs: MCValue,
1049 rhs: MCValue,
1050 lhs_ty: Type,
1051 rhs_ty: Type,
1052) InnerError!MCValue {
1053 const mod = self.bin_file.comp.module.?;
1054 switch (tag) {
1055 // Arithmetic operations on integers and floats
1056 .add,
1057 .sub,
1058 .cmp_eq,
1059 .cmp_neq,
1060 .cmp_gt,
1061 .cmp_gte,
1062 .cmp_lt,
1063 .cmp_lte,
1064 => {1132 => {
1065 switch (lhs_ty.zigTypeTag(mod)) {1133 _ = try self.addInst(.{
1066 .Float => return self.fail("TODO binary operations on floats", .{}),1134 .tag = mir_tag,
1067 .Vector => return self.fail("TODO binary operations on vectors", .{}),1135 .data = .{ .i_type = .{
1068 .Int => {1136 .rd = dest_reg,
1069 assert(lhs_ty.eql(rhs_ty, mod));1137 .rs1 = lhs_reg,
1070 const int_info = lhs_ty.intInfo(mod);1138 .imm12 = math.cast(i12, rhs.immediate) orelse {
1071 if (int_info.bits <= 64) {1139 return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
1072 if (rhs == .immediate) {1140 },
1073 return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1141 } },
1074 }1142 });
1075 return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1076 } else {
1077 return self.fail("TODO binary operations on int with bits > 64", .{});
1078 }
1079 },
1080 else => unreachable,
1081 }
1082 },
1083 .ptr_add,
1084 .ptr_sub,
1085 => {
1086 switch (lhs_ty.zigTypeTag(mod)) {
1087 .Pointer => {
1088 const ptr_ty = lhs_ty;
1089 const elem_ty = switch (ptr_ty.ptrSize(mod)) {
1090 .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type
1091 else => ptr_ty.childType(mod),
1092 };
1093 const elem_size = elem_ty.abiSize(mod);
1094
1095 if (elem_size == 1) {
1096 const base_tag: Air.Inst.Tag = switch (tag) {
1097 .ptr_add => .add,
1098 .ptr_sub => .sub,
1099 else => unreachable,
1100 };
1101
1102 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1103 } else {
1104 return self.fail("TODO ptr_add with elem_size > 1", .{});
1105 }
1106 },
1107 else => unreachable,
1108 }
1109 },1143 },
1144 .cmp_imm_gte => {
1145 const imm_reg = try self.copyToTmpRegister(rhs_ty, .{ .immediate = rhs.immediate - 1 });
11101146
1111 // These instructions have unsymteric bit sizes.1147 _ = try self.addInst(.{
1112 .shr,1148 .tag = mir_tag,
1113 .shl,1149 .data = .{ .r_type = .{
1114 => {1150 .rd = dest_reg,
1115 switch (lhs_ty.zigTypeTag(mod)) {1151 .rs1 = imm_reg,
1116 .Float => return self.fail("TODO binary operations on floats", .{}),1152 .rs2 = lhs_reg,
1117 .Vector => return self.fail("TODO binary operations on vectors", .{}),1153 } },
1118 .Int => {1154 });
1119 const int_info = lhs_ty.intInfo(mod);
1120 if (int_info.bits <= 64) {
1121 if (rhs == .immediate) {
1122 return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1123 }
1124 return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1125 } else {
1126 return self.fail("TODO binary operations on int with bits > 64", .{});
1127 }
1128 },
1129 else => unreachable,
1130 }
1131 },1155 },
1132 else => unreachable,1156 else => unreachable,
1133 }1157 }
1134}
11351158
1136fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1159 // generate the struct for overflow checks
1137 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
1138 const lhs = try self.resolveInst(bin_op.lhs);
1139 const rhs = try self.resolveInst(bin_op.rhs);
1140 const lhs_ty = self.typeOf(bin_op.lhs);
1141 const rhs_ty = self.typeOf(bin_op.rhs);
11421160
1143 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1161 return MCValue{ .register = dest_reg };
1144 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1145}1162}
11461163
1147fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1164fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
...@@ -2101,8 +2118,12 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2101,8 +2118,12 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2101 const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);2118 const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
2102 const liveness_condbr = self.liveness.getCondBr(inst);2119 const liveness_condbr = self.liveness.getCondBr(inst);
21032120
2104 // A branch to the false section. Uses beq2121 const cond_reg = try self.register_manager.allocReg(inst, gp);
2105 const reloc = try self.condBr(cond_ty, cond);2122 const cond_reg_lock = self.register_manager.lockRegAssumeUnused(cond_reg);
2123 defer self.register_manager.unlockReg(cond_reg_lock);
2124
2125 // A branch to the false section. Uses bne
2126 const reloc = try self.condBr(cond_ty, cond, cond_reg);
21062127
2107 // If the condition dies here in this condbr instruction, process2128 // If the condition dies here in this condbr instruction, process
2108 // that death now instead of later as this has an effect on2129 // that death now instead of later as this has an effect on
...@@ -2233,19 +2254,14 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2233,19 +2254,14 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2233 }2254 }
2234}2255}
22352256
2236fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {2257fn condBr(self: *Self, cond_ty: Type, condition: MCValue, cond_reg: Register) !Mir.Inst.Index {
2237 _ = cond_ty;2258 try self.genSetReg(cond_ty, cond_reg, condition);
2238
2239 const reg = switch (condition) {
2240 .register => |r| r,
2241 else => try self.copyToTmpRegister(Type.bool, condition),
2242 };
22432259
2244 return try self.addInst(.{2260 return try self.addInst(.{
2245 .tag = .bne,2261 .tag = .bne,
2246 .data = .{2262 .data = .{
2247 .b_type = .{2263 .b_type = .{
2248 .rs1 = reg,2264 .rs1 = cond_reg,
2249 .rs2 = .zero,2265 .rs2 = .zero,
2250 .inst = undefined,2266 .inst = undefined,
2251 },2267 },
...@@ -2739,6 +2755,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner...@@ -2739,6 +2755,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner
2739 } else return self.fail("TODO genSetStack for {s}", .{@tagName(self.bin_file.tag)});2755 } else return self.fail("TODO genSetStack for {s}", .{@tagName(self.bin_file.tag)});
2740 };2756 };
27412757
2758 // setup the src pointer
2742 _ = try self.addInst(.{2759 _ = try self.addInst(.{
2743 .tag = .load_symbol,2760 .tag = .load_symbol,
2744 .data = .{2761 .data = .{
...@@ -2789,7 +2806,7 @@ fn genInlineMemcpy(...@@ -2789,7 +2806,7 @@ fn genInlineMemcpy(
27892806
2790 // compare count to length2807 // compare count to length
2791 const compare_inst = try self.addInst(.{2808 const compare_inst = try self.addInst(.{
2792 .tag = .cmp_gt,2809 .tag = .cmp_eq,
2793 .data = .{ .r_type = .{2810 .data = .{ .r_type = .{
2794 .rd = tmp,2811 .rd = tmp,
2795 .rs1 = count,2812 .rs1 = count,
...@@ -2861,9 +2878,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!...@@ -2861,9 +2878,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!
2861 } },2878 } },
2862 });2879 });
2863 } else {2880 } else {
2881 // TODO: use a more advanced myriad seq to do this without a reg.
2882 // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L224
2883
2864 const temp = try self.register_manager.allocReg(null, gp);2884 const temp = try self.register_manager.allocReg(null, gp);
2865 const maybe_temp_lock = self.register_manager.lockReg(temp);2885 const temp_lock = self.register_manager.lockRegAssumeUnused(temp);
2866 defer if (maybe_temp_lock) |temp_lock| self.register_manager.unlockReg(temp_lock);2886 defer self.register_manager.unlockReg(temp_lock);
28672887
2868 const lo32: i32 = @truncate(x);2888 const lo32: i32 = @truncate(x);
2869 const carry: i32 = if (lo32 < 0) 1 else 0;2889 const carry: i32 = if (lo32 < 0) 1 else 0;
src/arch/riscv64/Emit.zig+39-20
...@@ -59,6 +59,7 @@ pub fn emitMir(...@@ -59,6 +59,7 @@ pub fn emitMir(
5959
60 .cmp_eq => try emit.mirRType(inst),60 .cmp_eq => try emit.mirRType(inst),
61 .cmp_gt => try emit.mirRType(inst),61 .cmp_gt => try emit.mirRType(inst),
62 .cmp_imm_gte => try emit.mirRType(inst),
6263
63 .beq => try emit.mirBType(inst),64 .beq => try emit.mirBType(inst),
64 .bne => try emit.mirBType(inst),65 .bne => try emit.mirBType(inst),
...@@ -185,14 +186,27 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -185,14 +186,27 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
185 switch (tag) {186 switch (tag) {
186 .add => try emit.writeInstruction(Instruction.add(rd, rs1, rs2)),187 .add => try emit.writeInstruction(Instruction.add(rd, rs1, rs2)),
187 .sub => try emit.writeInstruction(Instruction.sub(rd, rs1, rs2)),188 .sub => try emit.writeInstruction(Instruction.sub(rd, rs1, rs2)),
188 .cmp_gt => try emit.writeInstruction(Instruction.slt(rd, rs1, rs2)),189 .cmp_gt => {
190 // rs1 > rs2
191 try emit.writeInstruction(Instruction.slt(rd, rs1, rs2));
192 },
189 .cmp_eq => {193 .cmp_eq => {
194 // rs1 == rs2
195
196 // if equal, write 0 to rd
190 try emit.writeInstruction(Instruction.xor(rd, rs1, rs2));197 try emit.writeInstruction(Instruction.xor(rd, rs1, rs2));
198 // if rd == 0, set rd to 1
191 try emit.writeInstruction(Instruction.sltiu(rd, rd, 1));199 try emit.writeInstruction(Instruction.sltiu(rd, rd, 1));
192 },200 },
193 .sllw => try emit.writeInstruction(Instruction.sllw(rd, rs1, rs2)),201 .sllw => try emit.writeInstruction(Instruction.sllw(rd, rs1, rs2)),
194 .srlw => try emit.writeInstruction(Instruction.srlw(rd, rs1, rs2)),202 .srlw => try emit.writeInstruction(Instruction.srlw(rd, rs1, rs2)),
195 .@"or" => try emit.writeInstruction(Instruction.@"or"(rd, rs1, rs2)),203 .@"or" => try emit.writeInstruction(Instruction.@"or"(rd, rs1, rs2)),
204 .cmp_imm_gte => {
205 // rd = rs1 >= imm12
206 // see the docstring for cmp_imm_gte to see why we use r_type here
207 try emit.writeInstruction(Instruction.slt(rd, rs1, rs2));
208 try emit.writeInstruction(Instruction.xori(rd, rd, 1));
209 },
196 else => unreachable,210 else => unreachable,
197 }211 }
198}212}
...@@ -220,30 +234,34 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -220,30 +234,34 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
220 const tag = emit.mir.instructions.items(.tag)[inst];234 const tag = emit.mir.instructions.items(.tag)[inst];
221 const i_type = emit.mir.instructions.items(.data)[inst].i_type;235 const i_type = emit.mir.instructions.items(.data)[inst].i_type;
222236
237 const rd = i_type.rd;
238 const rs1 = i_type.rs1;
239 const imm12 = i_type.imm12;
240
223 switch (tag) {241 switch (tag) {
224 .addi => try emit.writeInstruction(Instruction.addi(i_type.rd, i_type.rs1, i_type.imm12)),242 .addi => try emit.writeInstruction(Instruction.addi(rd, rs1, imm12)),
225 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),243 .jalr => try emit.writeInstruction(Instruction.jalr(rd, imm12, rs1)),
226244
227 .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),245 .ld => try emit.writeInstruction(Instruction.ld(rd, imm12, rs1)),
228 .lw => try emit.writeInstruction(Instruction.lw(i_type.rd, i_type.imm12, i_type.rs1)),246 .lw => try emit.writeInstruction(Instruction.lw(rd, imm12, rs1)),
229 .lh => try emit.writeInstruction(Instruction.lh(i_type.rd, i_type.imm12, i_type.rs1)),247 .lh => try emit.writeInstruction(Instruction.lh(rd, imm12, rs1)),
230 .lb => try emit.writeInstruction(Instruction.lb(i_type.rd, i_type.imm12, i_type.rs1)),248 .lb => try emit.writeInstruction(Instruction.lb(rd, imm12, rs1)),
231249
232 .sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)),250 .sd => try emit.writeInstruction(Instruction.sd(rd, imm12, rs1)),
233 .sw => try emit.writeInstruction(Instruction.sw(i_type.rd, i_type.imm12, i_type.rs1)),251 .sw => try emit.writeInstruction(Instruction.sw(rd, imm12, rs1)),
234 .sh => try emit.writeInstruction(Instruction.sh(i_type.rd, i_type.imm12, i_type.rs1)),252 .sh => try emit.writeInstruction(Instruction.sh(rd, imm12, rs1)),
235 .sb => try emit.writeInstruction(Instruction.sb(i_type.rd, i_type.imm12, i_type.rs1)),253 .sb => try emit.writeInstruction(Instruction.sb(rd, imm12, rs1)),
236254
237 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),255 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(rd, rs1, .sp)),
238256
239 .abs => {257 .abs => {
240 try emit.writeInstruction(Instruction.sraiw(i_type.rd, i_type.rs1, @intCast(i_type.imm12)));258 try emit.writeInstruction(Instruction.sraiw(rd, rs1, @intCast(imm12)));
241 try emit.writeInstruction(Instruction.xor(i_type.rs1, i_type.rs1, i_type.rd));259 try emit.writeInstruction(Instruction.xor(rs1, rs1, rd));
242 try emit.writeInstruction(Instruction.subw(i_type.rs1, i_type.rs1, i_type.rd));260 try emit.writeInstruction(Instruction.subw(rs1, rs1, rd));
243 },261 },
244262
245 .srli => try emit.writeInstruction(Instruction.srli(i_type.rd, i_type.rs1, @intCast(i_type.imm12))),263 .srli => try emit.writeInstruction(Instruction.srli(rd, rs1, @intCast(imm12))),
246 .slli => try emit.writeInstruction(Instruction.slli(i_type.rd, i_type.rs1, @intCast(i_type.imm12))),264 .slli => try emit.writeInstruction(Instruction.slli(rd, rs1, @intCast(imm12))),
247265
248 else => unreachable,266 else => unreachable,
249 }267 }
...@@ -471,12 +489,13 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {...@@ -471,12 +489,13 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
471 .dbg_prologue_end,489 .dbg_prologue_end,
472 => 0,490 => 0,
473491
474 .psuedo_epilogue => 12, // 3 * 4492 .psuedo_epilogue => 12,
475 .psuedo_prologue => 16, // 4 * 4493 .psuedo_prologue => 16,
476494
477 .abs => 12, // 3 * 4495 .abs => 12,
478496
479 .cmp_eq => 8,497 .cmp_eq => 8,
498 .cmp_imm_gte => 8,
480499
481 else => 4,500 else => 4,
482 };501 };
src/arch/riscv64/Mir.zig+12-3
...@@ -57,12 +57,21 @@ pub const Inst = struct {...@@ -57,12 +57,21 @@ pub const Inst = struct {
57 /// Jumps. Uses `inst` payload.57 /// Jumps. Uses `inst` payload.
58 j,58 j,
5959
60 // TODO: Maybe create a special data for compares that includes the ops60 // NOTE: Maybe create a special data for compares that includes the ops
61 /// Compare equal, uses r_type61 /// Register `==`, uses r_type
62 cmp_eq,62 cmp_eq,
63 /// Compare greater than, uses r_type63 /// Register `>`, uses r_type
64 cmp_gt,64 cmp_gt,
6565
66 /// Immediate `>=`, uses r_type
67 ///
68 /// Note: this uses r_type because RISC-V does not provide a good way
69 /// to do `>=` comparisons on immediates. Usually we would just subtract
70 /// 1 from the immediate and do a `>` comparison, however there is no `>`
71 /// register to immedate comparison in RISC-V. This leads us to need to
72 /// allocate a register for temporary use.
73 cmp_imm_gte,
74
66 /// Branch if equal Uses b_type75 /// Branch if equal Uses b_type
67 beq,76 beq,
68 /// Branch if not eql Uses b_type77 /// Branch if not eql Uses b_type