authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-23 16:18:10+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-11-01 20:43:27+01:00
logd2a5a36cabad5a9b44538e50e9288c3a968cb9f3
treee8ec8f0c4b2baf3d7e2ee0f80c214c47e1850f41
parent0d192ee9ef6a69ca4841b1932579b9178938a6d5
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement min/max


3 files changed, 115 insertions(+), 8 deletions(-)

src/arch/aarch64/CodeGen.zig+95-8
......@@ -539,8 +539,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
539539 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
540540 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
541541
542 .min => try self.airMin(inst),
543 .max => try self.airMax(inst),
542 .min => try self.airMinMax(inst),
543 .max => try self.airMinMax(inst),
544544
545545 .add_sat => try self.airAddSat(inst),
546546 .sub_sat => try self.airSubSat(inst),
......@@ -1234,15 +1234,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
12341234 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12351235}
12361236
1237fn airMin(self: *Self, inst: Air.Inst.Index) !void {
1238 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1239 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch});
1240 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1237fn minMax(
1238 self: *Self,
1239 tag: Air.Inst.Tag,
1240 lhs_bind: ReadArg.Bind,
1241 rhs_bind: ReadArg.Bind,
1242 lhs_ty: Type,
1243 rhs_ty: Type,
1244 maybe_inst: ?Air.Inst.Index,
1245) !MCValue {
1246 switch (lhs_ty.zigTypeTag()) {
1247 .Float => return self.fail("TODO ARM min/max on floats", .{}),
1248 .Vector => return self.fail("TODO ARM min/max on vectors", .{}),
1249 .Int => {
1250 const mod = self.bin_file.options.module.?;
1251 assert(lhs_ty.eql(rhs_ty, mod));
1252 const int_info = lhs_ty.intInfo(self.target.*);
1253 if (int_info.bits <= 64) {
1254 var lhs_reg: Register = undefined;
1255 var rhs_reg: Register = undefined;
1256 var dest_reg: Register = undefined;
1257
1258 const read_args = [_]ReadArg{
1259 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1260 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
1261 };
1262 const write_args = [_]WriteArg{
1263 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1264 };
1265 try self.allocRegs(
1266 &read_args,
1267 &write_args,
1268 if (maybe_inst) |inst| .{
1269 .corresponding_inst = inst,
1270 .operand_mapping = &.{ 0, 1 },
1271 } else null,
1272 );
1273
1274 // lhs == reg should have been checked by airMinMax
1275 assert(lhs_reg != rhs_reg); // see note above
1276
1277 _ = try self.addInst(.{
1278 .tag = .cmp_shifted_register,
1279 .data = .{ .rr_imm6_shift = .{
1280 .rn = lhs_reg,
1281 .rm = rhs_reg,
1282 .imm6 = 0,
1283 .shift = .lsl,
1284 } },
1285 });
1286
1287 const cond_choose_lhs: Condition = switch (tag) {
1288 .max => switch (int_info.signedness) {
1289 .signed => Condition.gt,
1290 .unsigned => Condition.hi,
1291 },
1292 .min => switch (int_info.signedness) {
1293 .signed => Condition.lt,
1294 .unsigned => Condition.cc,
1295 },
1296 else => unreachable,
1297 };
1298
1299 _ = try self.addInst(.{
1300 .tag = .csel,
1301 .data = .{ .rrr_cond = .{
1302 .rd = dest_reg,
1303 .rn = lhs_reg,
1304 .rm = rhs_reg,
1305 .cond = cond_choose_lhs,
1306 } },
1307 });
1308
1309 return MCValue{ .register = dest_reg };
1310 } else {
1311 return self.fail("TODO ARM min/max on integers > u32/i32", .{});
1312 }
1313 },
1314 else => unreachable,
1315 }
12411316}
12421317
1243fn airMax(self: *Self, inst: Air.Inst.Index) !void {
1318fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
1319 const tag = self.air.instructions.items(.tag)[inst];
12441320 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1245 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch});
1321 const lhs_ty = self.air.typeOf(bin_op.lhs);
1322 const rhs_ty = self.air.typeOf(bin_op.rhs);
1323
1324 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1325 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1326 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1327
1328 const lhs = try self.resolveInst(bin_op.lhs);
1329 if (bin_op.lhs == bin_op.rhs) break :result lhs;
1330
1331 break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
1332 };
12461333 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12471334}
12481335
src/arch/aarch64/Emit.zig+9
......@@ -131,6 +131,7 @@ pub fn emitMir(
131131 .subs_extended_register => try emit.mirAddSubtractExtendedRegister(inst),
132132 .cmp_extended_register => try emit.mirAddSubtractExtendedRegister(inst),
133133
134 .csel => try emit.mirConditionalSelect(inst),
134135 .cset => try emit.mirConditionalSelect(inst),
135136
136137 .dbg_line => try emit.mirDbgLine(inst),
......@@ -804,6 +805,14 @@ fn mirAddSubtractExtendedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
804805fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
805806 const tag = emit.mir.instructions.items(.tag)[inst];
806807 switch (tag) {
808 .csel => {
809 const rrr_cond = emit.mir.instructions.items(.data)[inst].rrr_cond;
810 const rd = rrr_cond.rd;
811 const rn = rrr_cond.rn;
812 const rm = rrr_cond.rm;
813 const cond = rrr_cond.cond;
814 try emit.writeInstruction(Instruction.csel(rd, rn, rm, cond));
815 },
807816 .cset => {
808817 const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;
809818 const zr: Register = switch (r_cond.rd.size()) {
src/arch/aarch64/Mir.zig+11
......@@ -62,6 +62,8 @@ pub const Inst = struct {
6262 cmp_shifted_register,
6363 /// Compare (extended register)
6464 cmp_extended_register,
65 /// Conditional Select
66 csel,
6567 /// Conditional set
6668 cset,
6769 /// Pseudo-instruction: End of prologue
......@@ -387,6 +389,15 @@ pub const Inst = struct {
387389 rn: Register,
388390 rm: Register,
389391 },
392 /// Three registers and a condition
393 ///
394 /// Used by e.g. csel
395 rrr_cond: struct {
396 rd: Register,
397 rn: Register,
398 rm: Register,
399 cond: bits.Instruction.Condition,
400 },
390401 /// Three registers and a shift (shift type and 6-bit amount)
391402 ///
392403 /// Used by e.g. add_shifted_register