| ... | ... | @@ -797,23 +797,57 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 797 | 797 | } |
| 798 | 798 | |
| 799 | 799 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 800 | const mod = self.bin_file.comp.module.?; |
| 800 | 801 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 801 | | if (self.liveness.isUnused(inst)) |
| 802 | | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 802 | const src_ty = self.typeOf(ty_op.operand); |
| 803 | const dst_ty = self.typeOfIndex(inst); |
| 803 | 804 | |
| 804 | | const mod = self.bin_file.comp.module.?; |
| 805 | | const operand_ty = self.typeOf(ty_op.operand); |
| 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", .{}); |
| 805 | const result: MCValue = result: { |
| 806 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 811 | 807 | |
| 812 | | if (info_a.bits == info_b.bits) |
| 813 | | return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); |
| 808 | const src_int_info = src_ty.intInfo(mod); |
| 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}); |
| 816 | | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 815 | _ = dst_abi_size; |
| 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 | 853 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1080,7 +1114,9 @@ fn binOpImm( |
| 1080 | 1114 | .shr => .srli, |
| 1081 | 1115 | .cmp_gte => .cmp_imm_gte, |
| 1082 | 1116 | .cmp_eq => .cmp_imm_eq, |
| 1117 | .cmp_lte => .cmp_imm_lte, |
| 1083 | 1118 | .add => .addi, |
| 1119 | .sub => .addiw, |
| 1084 | 1120 | else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}), |
| 1085 | 1121 | }; |
| 1086 | 1122 | |
| ... | ... | @@ -1090,6 +1126,7 @@ fn binOpImm( |
| 1090 | 1126 | .srli, |
| 1091 | 1127 | .addi, |
| 1092 | 1128 | .cmp_imm_eq, |
| 1129 | .cmp_imm_lte, |
| 1093 | 1130 | => { |
| 1094 | 1131 | _ = try self.addInst(.{ |
| 1095 | 1132 | .tag = mir_tag, |
| ... | ... | @@ -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 | 1154 | .cmp_imm_gte => { |
| 1106 | 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 | 1195 | |
| 1147 | 1196 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 1148 | 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 | 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 | 3499 | const mod = self.bin_file.comp.module.?; |
| 3442 | 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 | } |