| ... | @@ -928,6 +928,8 @@ fn binOpRegister( | ... | @@ -928,6 +928,8 @@ fn binOpRegister( |
| 928 | .sub => .sub, | 928 | .sub => .sub, |
| 929 | .cmp_eq => .cmp_eq, | 929 | .cmp_eq => .cmp_eq, |
| 930 | .cmp_gt => .cmp_gt, | 930 | .cmp_gt => .cmp_gt, |
| | 931 | .shl => .sllw, |
| | 932 | .shr => .srlw, |
| 931 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), | 933 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), |
| 932 | }; | 934 | }; |
| 933 | | 935 | |
| ... | @@ -947,6 +949,84 @@ fn binOpRegister( | ... | @@ -947,6 +949,84 @@ fn binOpRegister( |
| 947 | return MCValue{ .register = dest_reg }; | 949 | return MCValue{ .register = dest_reg }; |
| 948 | } | 950 | } |
| 949 | | 951 | |
| | 952 | /// Don't call this function directly. Use binOp instead. |
| | 953 | /// |
| | 954 | /// Call this function if rhs is an immediate. Generates I version of binops. |
| | 955 | /// |
| | 956 | /// Asserts that rhs is an immediate MCValue |
| | 957 | fn binOpImm( |
| | 958 | self: *Self, |
| | 959 | tag: Air.Inst.Tag, |
| | 960 | maybe_inst: ?Air.Inst.Index, |
| | 961 | lhs: MCValue, |
| | 962 | rhs: MCValue, |
| | 963 | lhs_ty: Type, |
| | 964 | rhs_ty: Type, |
| | 965 | ) !MCValue { |
| | 966 | _ = rhs_ty; |
| | 967 | assert(rhs == .immediate); |
| | 968 | |
| | 969 | const lhs_is_register = lhs == .register; |
| | 970 | |
| | 971 | const lhs_lock: ?RegisterLock = if (lhs_is_register) |
| | 972 | self.register_manager.lockReg(lhs.register) |
| | 973 | else |
| | 974 | null; |
| | 975 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| | 976 | |
| | 977 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| | 978 | |
| | 979 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| | 980 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { |
| | 981 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| | 982 | break :inst bin_op.lhs.toIndex().?; |
| | 983 | } else null; |
| | 984 | |
| | 985 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| | 986 | |
| | 987 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| | 988 | |
| | 989 | break :blk reg; |
| | 990 | }; |
| | 991 | const new_lhs_lock = self.register_manager.lockReg(lhs_reg); |
| | 992 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| | 993 | |
| | 994 | const dest_reg = if (maybe_inst) |inst| blk: { |
| | 995 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| | 996 | |
| | 997 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { |
| | 998 | break :blk lhs_reg; |
| | 999 | } else { |
| | 1000 | break :blk try self.register_manager.allocReg(inst, gp); |
| | 1001 | } |
| | 1002 | } else try self.register_manager.allocReg(null, gp); |
| | 1003 | |
| | 1004 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| | 1005 | |
| | 1006 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| | 1007 | .shl => .slli, |
| | 1008 | .shr => .srli, |
| | 1009 | else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}), |
| | 1010 | }; |
| | 1011 | |
| | 1012 | _ = try self.addInst(.{ |
| | 1013 | .tag = mir_tag, |
| | 1014 | .data = .{ |
| | 1015 | .i_type = .{ |
| | 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 | |
| 950 | /// For all your binary operation needs, this function will generate | 1030 | /// For all your binary operation needs, this function will generate |
| 951 | /// the corresponding Mir instruction(s). Returns the location of the | 1031 | /// the corresponding Mir instruction(s). Returns the location of the |
| 952 | /// result. | 1032 | /// result. |
| ... | @@ -989,8 +1069,10 @@ fn binOp( | ... | @@ -989,8 +1069,10 @@ fn binOp( |
| 989 | assert(lhs_ty.eql(rhs_ty, mod)); | 1069 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 990 | const int_info = lhs_ty.intInfo(mod); | 1070 | const int_info = lhs_ty.intInfo(mod); |
| 991 | if (int_info.bits <= 64) { | 1071 | if (int_info.bits <= 64) { |
| 992 | // TODO immediate operands | 1072 | if (rhs == .immediate) { |
| 993 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1073 | return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1074 | } |
| | 1075 | return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 994 | } else { | 1076 | } else { |
| 995 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1077 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 996 | } | 1078 | } |
| ... | @@ -1025,6 +1107,28 @@ fn binOp( | ... | @@ -1025,6 +1107,28 @@ fn binOp( |
| 1025 | else => unreachable, | 1107 | else => unreachable, |
| 1026 | } | 1108 | } |
| 1027 | }, | 1109 | }, |
| | 1110 | |
| | 1111 | // These instructions have unsymteric bit sizes. |
| | 1112 | .shr, |
| | 1113 | .shl, |
| | 1114 | => { |
| | 1115 | switch (lhs_ty.zigTypeTag(mod)) { |
| | 1116 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| | 1117 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 1118 | .Int => { |
| | 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 | }, |
| 1028 | else => unreachable, | 1132 | else => unreachable, |
| 1029 | } | 1133 | } |
| 1030 | } | 1134 | } |
| ... | @@ -1163,7 +1267,13 @@ fn airXor(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1163,7 +1267,13 @@ fn airXor(self: *Self, inst: Air.Inst.Index) !void { |
| 1163 | | 1267 | |
| 1164 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | 1268 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1165 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 1269 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 1166 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}); | 1270 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1271 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1272 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1273 | const lhs_ty = self.typeOf(bin_op.lhs); |
| | 1274 | const rhs_ty = self.typeOf(bin_op.rhs); |
| | 1275 | break :result try self.binOp(.shl, inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1276 | }; |
| 1167 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1277 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1168 | } | 1278 | } |
| 1169 | | 1279 | |
| ... | @@ -1426,7 +1536,11 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1426,7 +1536,11 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 1426 | | 1536 | |
| 1427 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | 1537 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1428 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 1538 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 1429 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch}); | 1539 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1540 | if (true) |
| | 1541 | return self.fail("TODO: airByteSwap", .{}); |
| | 1542 | break :result undefined; |
| | 1543 | }; |
| 1430 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1544 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1431 | } | 1545 | } |
| 1432 | | 1546 | |