| ... | @@ -797,23 +797,57 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -797,23 +797,57 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 797 | } | 797 | } |
| 798 | | 798 | |
| 799 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 799 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| | 800 | const mod = self.bin_file.comp.module.?; |
| 800 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 801 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 801 | if (self.liveness.isUnused(inst)) | 802 | const src_ty = self.typeOf(ty_op.operand); |
| 802 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 803 | const dst_ty = self.typeOfIndex(inst); |
| 803 | | 804 | |
| 804 | const mod = self.bin_file.comp.module.?; | 805 | const result: MCValue = result: { |
| 805 | const operand_ty = self.typeOf(ty_op.operand); | 806 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 806 | const operand = try self.resolveInst(ty_op.operand); | | |
| 807 | const info_a = operand_ty.intInfo(mod); | | |
| 808 | const info_b = self.typeOfIndex(inst).intInfo(mod); | | |
| 809 | if (info_a.signedness != info_b.signedness) | | |
| 810 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); | | |
| 811 | | 807 | |
| 812 | if (info_a.bits == info_b.bits) | 808 | const src_int_info = src_ty.intInfo(mod); |
| 813 | return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); | 809 | const dst_int_info = dst_ty.intInfo(mod); |
| | 810 | const extend = switch (src_int_info.signedness) { |
| | 811 | .signed => dst_int_info, |
| | 812 | .unsigned => src_int_info, |
| | 813 | }.signedness; |
| 814 | | 814 | |
| 815 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); | 815 | _ = dst_abi_size; |
| 816 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 816 | _ = extend; |
| | 817 | |
| | 818 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| | 819 | |
| | 820 | const src_mcv = try self.resolveInst(ty_op.operand); |
| | 821 | |
| | 822 | const src_storage_bits: u16 = switch (src_mcv) { |
| | 823 | .register => 64, |
| | 824 | .stack_offset => src_int_info.bits, |
| | 825 | else => return self.fail("airIntCast from {s}", .{@tagName(src_mcv)}), |
| | 826 | }; |
| | 827 | |
| | 828 | const dst_mcv = if (dst_int_info.bits <= src_storage_bits and |
| | 829 | math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == |
| | 830 | math.divCeil(u32, src_storage_bits, 64) catch unreachable and |
| | 831 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| | 832 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 833 | try self.setValue(min_ty, dst_mcv, src_mcv); |
| | 834 | break :dst dst_mcv; |
| | 835 | }; |
| | 836 | |
| | 837 | if (dst_int_info.bits <= src_int_info.bits) { |
| | 838 | break :result dst_mcv; |
| | 839 | } |
| | 840 | |
| | 841 | if (dst_int_info.bits > 64 or src_int_info.bits > 64) { |
| | 842 | break :result null; // TODO |
| | 843 | } |
| | 844 | |
| | 845 | break :result dst_mcv; |
| | 846 | } orelse return self.fail("TODO implement airIntCast from {} to {}", .{ |
| | 847 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| | 848 | }); |
| | 849 | |
| | 850 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 817 | } | 851 | } |
| 818 | | 852 | |
| 819 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 853 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1080,7 +1114,9 @@ fn binOpImm( | ... | @@ -1080,7 +1114,9 @@ fn binOpImm( |
| 1080 | .shr => .srli, | 1114 | .shr => .srli, |
| 1081 | .cmp_gte => .cmp_imm_gte, | 1115 | .cmp_gte => .cmp_imm_gte, |
| 1082 | .cmp_eq => .cmp_imm_eq, | 1116 | .cmp_eq => .cmp_imm_eq, |
| | 1117 | .cmp_lte => .cmp_imm_lte, |
| 1083 | .add => .addi, | 1118 | .add => .addi, |
| | 1119 | .sub => .addiw, |
| 1084 | else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}), | 1120 | else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}), |
| 1085 | }; | 1121 | }; |
| 1086 | | 1122 | |
| ... | @@ -1090,6 +1126,7 @@ fn binOpImm( | ... | @@ -1090,6 +1126,7 @@ fn binOpImm( |
| 1090 | .srli, | 1126 | .srli, |
| 1091 | .addi, | 1127 | .addi, |
| 1092 | .cmp_imm_eq, | 1128 | .cmp_imm_eq, |
| | 1129 | .cmp_imm_lte, |
| 1093 | => { | 1130 | => { |
| 1094 | _ = try self.addInst(.{ | 1131 | _ = try self.addInst(.{ |
| 1095 | .tag = mir_tag, | 1132 | .tag = mir_tag, |
| ... | @@ -1102,6 +1139,18 @@ fn binOpImm( | ... | @@ -1102,6 +1139,18 @@ fn binOpImm( |
| 1102 | } }, | 1139 | } }, |
| 1103 | }); | 1140 | }); |
| 1104 | }, | 1141 | }, |
| | 1142 | .addiw => { |
| | 1143 | _ = try self.addInst(.{ |
| | 1144 | .tag = mir_tag, |
| | 1145 | .data = .{ .i_type = .{ |
| | 1146 | .rd = dest_reg, |
| | 1147 | .rs1 = lhs_reg, |
| | 1148 | .imm12 = -(math.cast(i12, rhs.immediate) orelse { |
| | 1149 | return self.fail("TODO: binOpImm larger than i12 i_type payload", .{}); |
| | 1150 | }), |
| | 1151 | } }, |
| | 1152 | }); |
| | 1153 | }, |
| 1105 | .cmp_imm_gte => { | 1154 | .cmp_imm_gte => { |
| 1106 | const imm_reg = try self.copyToTmpRegister(rhs_ty, .{ .immediate = rhs.immediate - 1 }); | 1155 | const imm_reg = try self.copyToTmpRegister(rhs_ty, .{ .immediate = rhs.immediate - 1 }); |
| 1107 | | 1156 | |
| ... | @@ -1146,7 +1195,16 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1146,7 +1195,16 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1146 | | 1195 | |
| 1147 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { | 1196 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 1148 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 1197 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 1149 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch}); | 1198 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1199 | // RISCV arthemtic instructions already wrap, so this is simply a sub binOp with |
| | 1200 | // no overflow checks. |
| | 1201 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1202 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1203 | const lhs_ty = self.typeOf(bin_op.lhs); |
| | 1204 | const rhs_ty = self.typeOf(bin_op.rhs); |
| | 1205 | |
| | 1206 | break :result try self.binOp(.sub, inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1207 | }; |
| 1150 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1208 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1151 | } | 1209 | } |
| 1152 | | 1210 | |
| ... | @@ -3441,3 +3499,7 @@ fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | ... | @@ -3441,3 +3499,7 @@ fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { |
| 3441 | const mod = self.bin_file.comp.module.?; | 3499 | const mod = self.bin_file.comp.module.?; |
| 3442 | return self.air.typeOfIndex(inst, &mod.intern_pool); | 3500 | return self.air.typeOfIndex(inst, &mod.intern_pool); |
| 3443 | } | 3501 | } |
| | 3502 | |
| | 3503 | fn hasFeature(self: *Self, feature: Target.riscv.Feature) bool { |
| | 3504 | return Target.riscv.featureSetHas(self.target.cpu.features, feature); |
| | 3505 | } |