| ... | ... | @@ -928,6 +928,8 @@ fn binOpRegister( |
| 928 | 928 | .sub => .sub, |
| 929 | 929 | .cmp_eq => .cmp_eq, |
| 930 | 930 | .cmp_gt => .cmp_gt, |
| 931 | .shl => .sllw, |
| 932 | .shr => .srlw, |
| 931 | 933 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), |
| 932 | 934 | }; |
| 933 | 935 | |
| ... | ... | @@ -947,6 +949,84 @@ fn binOpRegister( |
| 947 | 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 | 1030 | /// For all your binary operation needs, this function will generate |
| 951 | 1031 | /// the corresponding Mir instruction(s). Returns the location of the |
| 952 | 1032 | /// result. |
| ... | ... | @@ -989,8 +1069,10 @@ fn binOp( |
| 989 | 1069 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 990 | 1070 | const int_info = lhs_ty.intInfo(mod); |
| 991 | 1071 | if (int_info.bits <= 64) { |
| 992 | | // TODO immediate operands |
| 993 | | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1072 | if (rhs == .immediate) { |
| 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 | 1076 | } else { |
| 995 | 1077 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 996 | 1078 | } |
| ... | ... | @@ -1025,6 +1107,28 @@ fn binOp( |
| 1025 | 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 | 1132 | else => unreachable, |
| 1029 | 1133 | } |
| 1030 | 1134 | } |
| ... | ... | @@ -1163,7 +1267,13 @@ fn airXor(self: *Self, inst: Air.Inst.Index) !void { |
| 1163 | 1267 | |
| 1164 | 1268 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1165 | 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 | 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 | 1536 | |
| 1427 | 1537 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1428 | 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 | 1544 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1431 | 1545 | } |
| 1432 | 1546 | |