authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-22 19:54:53+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-22 20:16:05-07:00
log95e166b2e1609e93b472324c91b2d360abd595c2
tree213f1b4de830a286f8553c2b413ab11dc89fd926
parent62529a291bd41eccbafeda602d7efcb4ec946939

stage2 ARM: implement min, max for integers <= 32 bits


1 files changed, 112 insertions(+), 8 deletions(-)

src/arch/arm/CodeGen.zig+112-8
...@@ -535,8 +535,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -535,8 +535,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
535 .mod => try self.airMod(inst),535 .mod => try self.airMod(inst),
536 .shl, .shl_exact => try self.airBinOp(inst),536 .shl, .shl_exact => try self.airBinOp(inst),
537 .shl_sat => try self.airShlSat(inst),537 .shl_sat => try self.airShlSat(inst),
538 .min => try self.airMin(inst),538 .min => try self.airMinMax(inst),
539 .max => try self.airMax(inst),539 .max => try self.airMinMax(inst),
540 .slice => try self.airSlice(inst),540 .slice => try self.airSlice(inst),
541541
542 .sqrt,542 .sqrt,
...@@ -1140,15 +1140,119 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1140,15 +1140,119 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1140 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1140 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1141}1141}
11421142
1143fn airMin(self: *Self, inst: Air.Inst.Index) !void {1143fn minMax(
1144 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1144 self: *Self,
1145 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch});1145 tag: Air.Inst.Tag,
1146 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1146 maybe_inst: ?Air.Inst.Index,
1147 lhs: MCValue,
1148 rhs: MCValue,
1149 lhs_ty: Type,
1150 rhs_ty: Type,
1151) !MCValue {
1152 switch (lhs_ty.zigTypeTag()) {
1153 .Float => return self.fail("TODO ARM min/max on floats", .{}),
1154 .Vector => return self.fail("TODO ARM min/max on vectors", .{}),
1155 .Int => {
1156 assert(lhs_ty.eql(rhs_ty));
1157 const int_info = lhs_ty.intInfo(self.target.*);
1158 if (int_info.bits <= 32) {
1159 const lhs_is_register = lhs == .register;
1160 const rhs_is_register = rhs == .register;
1161
1162 const lhs_reg = switch (lhs) {
1163 .register => |r| r,
1164 else => try self.copyToTmpRegister(lhs_ty, lhs),
1165 };
1166 self.register_manager.freezeRegs(&.{lhs_reg});
1167 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1168
1169 const rhs_reg = switch (rhs) {
1170 .register => |r| r,
1171 else => try self.copyToTmpRegister(rhs_ty, rhs),
1172 };
1173 self.register_manager.freezeRegs(&.{rhs_reg});
1174 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
1175
1176 const dest_reg = if (maybe_inst) |inst| blk: {
1177 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1178
1179 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1180 break :blk lhs_reg;
1181 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1182 break :blk rhs_reg;
1183 } else {
1184 break :blk try self.register_manager.allocReg(inst);
1185 }
1186 } else try self.register_manager.allocReg(null);
1187
1188 // lhs == reg should have been checked by airMinMax
1189 //
1190 // By guaranteeing lhs != rhs, we guarantee (dst !=
1191 // lhs) or (dst != rhs), which is a property we use to
1192 // omit generating one instruction when we reuse a
1193 // register.
1194 assert(lhs_reg != rhs_reg); // see note above
1195
1196 _ = try self.binOpRegister(.cmp_eq, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty);
1197
1198 const cond_choose_lhs: Condition = switch (tag) {
1199 .max => switch (int_info.signedness) {
1200 .signed => Condition.gt,
1201 .unsigned => Condition.hi,
1202 },
1203 .min => switch (int_info.signedness) {
1204 .signed => Condition.lt,
1205 .unsigned => Condition.cc,
1206 },
1207 else => unreachable,
1208 };
1209 const cond_choose_rhs = cond_choose_lhs.negate();
1210
1211 if (dest_reg != lhs_reg) {
1212 _ = try self.addInst(.{
1213 .tag = .mov,
1214 .cond = cond_choose_lhs,
1215 .data = .{ .rr_op = .{
1216 .rd = dest_reg,
1217 .rn = .r0,
1218 .op = Instruction.Operand.reg(lhs_reg, Instruction.Operand.Shift.none),
1219 } },
1220 });
1221 }
1222 if (dest_reg != rhs_reg) {
1223 _ = try self.addInst(.{
1224 .tag = .mov,
1225 .cond = cond_choose_rhs,
1226 .data = .{ .rr_op = .{
1227 .rd = dest_reg,
1228 .rn = .r0,
1229 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
1230 } },
1231 });
1232 }
1233
1234 return MCValue{ .register = dest_reg };
1235 } else {
1236 return self.fail("TODO ARM min/max on integers > u32/i32", .{});
1237 }
1238 },
1239 else => unreachable,
1240 }
1147}1241}
11481242
1149fn airMax(self: *Self, inst: Air.Inst.Index) !void {1243fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
1244 const tag = self.air.instructions.items(.tag)[inst];
1150 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1245 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1151 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch});1246 const lhs = try self.resolveInst(bin_op.lhs);
1247 const rhs = try self.resolveInst(bin_op.rhs);
1248 const lhs_ty = self.air.typeOf(bin_op.lhs);
1249 const rhs_ty = self.air.typeOf(bin_op.rhs);
1250
1251 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1252 if (bin_op.lhs == bin_op.rhs) break :result lhs;
1253
1254 break :result try self.minMax(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1255 };
1152 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1256 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1153}1257}
11541258