Commit dd62d5941e

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-10-20 12:43:41
stage2 AArch64: move remaining operations out of binOp
1 parent 3800bb5
Changed files (1)
src
arch
aarch64
src/arch/aarch64/CodeGen.zig
@@ -1401,7 +1401,8 @@ fn allocRegs(
     for (read_args) |arg, i| {
         const mcv = try arg.bind.resolveToMcv(self);
         if (mcv == .register) {
-            arg.reg.* = mcv.register;
+            const raw_reg = mcv.register;
+            arg.reg.* = self.registerAlias(raw_reg, arg.ty);
         } else {
             const track_inst: ?Air.Inst.Index = switch (arg.bind) {
                 .inst => |inst| Air.refToIndex(inst).?,
@@ -1418,7 +1419,8 @@ fn allocRegs(
         const operand_mapping = reuse_metadata.?.operand_mapping;
         const arg = write_args[0];
         if (arg.bind == .reg) {
-            arg.reg.* = arg.bind.reg;
+            const raw_reg = arg.bind.reg;
+            arg.reg.* = self.registerAlias(raw_reg, arg.ty);
         } else {
             reuse_operand: for (read_args) |read_arg, i| {
                 if (read_arg.bind == .inst) {
@@ -1428,7 +1430,8 @@ fn allocRegs(
                         std.meta.eql(arg.class, read_arg.class) and
                         self.reuseOperand(inst, operand, operand_mapping[i], mcv))
                     {
-                        arg.reg.* = mcv.register;
+                        const raw_reg = mcv.register;
+                        arg.reg.* = self.registerAlias(raw_reg, arg.ty);
                         write_locks[0] = null;
                         reused_read_arg = i;
                         break :reuse_operand;
@@ -1443,7 +1446,8 @@ fn allocRegs(
     } else {
         for (write_args) |arg, i| {
             if (arg.bind == .reg) {
-                arg.reg.* = arg.bind.reg;
+                const raw_reg = arg.bind.reg;
+                arg.reg.* = self.registerAlias(raw_reg, arg.ty);
             } else {
                 const raw_reg = try self.register_manager.allocReg(null, arg.class);
                 arg.reg.* = self.registerAlias(raw_reg, arg.ty);
@@ -1887,189 +1891,6 @@ const BinOpMetadata = struct {
     rhs: Air.Inst.Ref,
 };
 
-/// For all your binary operation needs, this function will generate
-/// the corresponding Mir instruction(s). Returns the location of the
-/// result.
-///
-/// If the binary operation itself happens to be an Air instruction,
-/// pass the corresponding index in the inst parameter. That helps
-/// this function do stuff like reusing operands.
-///
-/// This function does not do any lowering to Mir itself, but instead
-/// looks at the lhs and rhs and determines which kind of lowering
-/// would be best suitable and then delegates the lowering to other
-/// functions.
-fn binOp(
-    self: *Self,
-    tag: Air.Inst.Tag,
-    lhs: MCValue,
-    rhs: MCValue,
-    lhs_ty: Type,
-    rhs_ty: Type,
-    metadata: ?BinOpMetadata,
-) InnerError!MCValue {
-    const mod = self.bin_file.options.module.?;
-    switch (tag) {
-        .addwrap,
-        .subwrap,
-        .mulwrap,
-        => {
-            const base_tag: Air.Inst.Tag = switch (tag) {
-                .addwrap => .add,
-                .subwrap => .sub,
-                .mulwrap => .mul,
-                else => unreachable,
-            };
-
-            const lhs_bind = if (metadata) |md|
-                ReadArg.Bind{ .inst = md.lhs }
-            else
-                ReadArg.Bind{ .mcv = lhs };
-            const rhs_bind = if (metadata) |md|
-                ReadArg.Bind{ .inst = md.rhs }
-            else
-                ReadArg.Bind{ .mcv = rhs };
-
-            // Generate an add/sub/mul
-            const maybe_inst: ?Air.Inst.Index = if (metadata) |md| md.inst else null;
-            const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
-
-            // Truncate if necessary
-            switch (lhs_ty.zigTypeTag()) {
-                .Vector => return self.fail("TODO binary operations on vectors", .{}),
-                .Int => {
-                    const int_info = lhs_ty.intInfo(self.target.*);
-                    if (int_info.bits <= 64) {
-                        const result_reg = result.register;
-                        try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
-                        return result;
-                    } else {
-                        return self.fail("TODO binary operations on integers > u64/i64", .{});
-                    }
-                },
-                else => unreachable,
-            }
-        },
-        .bit_and,
-        .bit_or,
-        .xor,
-        => {
-            switch (lhs_ty.zigTypeTag()) {
-                .Vector => return self.fail("TODO binary operations on vectors", .{}),
-                .Int => {
-                    assert(lhs_ty.eql(rhs_ty, mod));
-                    const int_info = lhs_ty.intInfo(self.target.*);
-                    if (int_info.bits <= 64) {
-                        // TODO implement bitwise operations with immediates
-                        const mir_tag: Mir.Inst.Tag = switch (tag) {
-                            .bit_and => .and_shifted_register,
-                            .bit_or => .orr_shifted_register,
-                            .xor => .eor_shifted_register,
-                            else => unreachable,
-                        };
-
-                        return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
-                    } else {
-                        return self.fail("TODO binary operations on int with bits > 64", .{});
-                    }
-                },
-                else => unreachable,
-            }
-        },
-        .shl_exact,
-        .shr_exact,
-        => {
-            switch (lhs_ty.zigTypeTag()) {
-                .Vector => return self.fail("TODO binary operations on vectors", .{}),
-                .Int => {
-                    const int_info = lhs_ty.intInfo(self.target.*);
-                    if (int_info.bits <= 64) {
-                        const rhs_immediate_ok = rhs == .immediate;
-
-                        const mir_tag_register: Mir.Inst.Tag = switch (tag) {
-                            .shl_exact => .lsl_register,
-                            .shr_exact => switch (int_info.signedness) {
-                                .signed => Mir.Inst.Tag.asr_register,
-                                .unsigned => Mir.Inst.Tag.lsr_register,
-                            },
-                            else => unreachable,
-                        };
-                        const mir_tag_immediate: Mir.Inst.Tag = switch (tag) {
-                            .shl_exact => .lsl_immediate,
-                            .shr_exact => switch (int_info.signedness) {
-                                .signed => Mir.Inst.Tag.asr_immediate,
-                                .unsigned => Mir.Inst.Tag.lsr_immediate,
-                            },
-                            else => unreachable,
-                        };
-
-                        if (rhs_immediate_ok) {
-                            return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata);
-                        } else {
-                            return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
-                        }
-                    } else {
-                        return self.fail("TODO binary operations on int with bits > 64", .{});
-                    }
-                },
-                else => unreachable,
-            }
-        },
-        .shl,
-        .shr,
-        => {
-            const base_tag: Air.Inst.Tag = switch (tag) {
-                .shl => .shl_exact,
-                .shr => .shr_exact,
-                else => unreachable,
-            };
-
-            // Generate a shl_exact/shr_exact
-            const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
-
-            // Truncate if necessary
-            switch (tag) {
-                .shr => return result,
-                .shl => switch (lhs_ty.zigTypeTag()) {
-                    .Vector => return self.fail("TODO binary operations on vectors", .{}),
-                    .Int => {
-                        const int_info = lhs_ty.intInfo(self.target.*);
-                        if (int_info.bits <= 64) {
-                            const result_reg = result.register;
-                            try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
-                            return result;
-                        } else {
-                            return self.fail("TODO binary operations on integers > u64/i64", .{});
-                        }
-                    },
-                    else => unreachable,
-                },
-                else => unreachable,
-            }
-        },
-        .bool_and,
-        .bool_or,
-        => {
-            switch (lhs_ty.zigTypeTag()) {
-                .Bool => {
-                    assert(lhs != .immediate); // should have been handled by Sema
-                    assert(rhs != .immediate); // should have been handled by Sema
-
-                    const mir_tag_register: Mir.Inst.Tag = switch (tag) {
-                        .bool_and => .and_shifted_register,
-                        .bool_or => .orr_shifted_register,
-                        else => unreachable,
-                    };
-
-                    return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
-                },
-                else => unreachable,
-            }
-        },
-        else => unreachable,
-    }
-}
-
 fn addSub(
     self: *Self,
     tag: Air.Inst.Tag,
@@ -2369,6 +2190,189 @@ fn modulo(
     }
 }
 
+fn wrappingArithmetic(
+    self: *Self,
+    tag: Air.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) InnerError!MCValue {
+    switch (lhs_ty.zigTypeTag()) {
+        .Vector => return self.fail("TODO binary operations on vectors", .{}),
+        .Int => {
+            const int_info = lhs_ty.intInfo(self.target.*);
+            if (int_info.bits <= 64) {
+                // Generate an add/sub/mul
+                const result: MCValue = switch (tag) {
+                    .addwrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
+                    .subwrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
+                    .mulwrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
+                    else => unreachable,
+                };
+
+                // Truncate if necessary
+                const result_reg = result.register;
+                try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
+                return result;
+            } else {
+                return self.fail("TODO binary operations on integers > u64/i64", .{});
+            }
+        },
+        else => unreachable,
+    }
+}
+
+fn bitwise(
+    self: *Self,
+    tag: Air.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) InnerError!MCValue {
+    const mod = self.bin_file.options.module.?;
+    switch (lhs_ty.zigTypeTag()) {
+        .Vector => return self.fail("TODO binary operations on vectors", .{}),
+        .Int => {
+            assert(lhs_ty.eql(rhs_ty, mod));
+            const int_info = lhs_ty.intInfo(self.target.*);
+            if (int_info.bits <= 64) {
+                // TODO implement bitwise operations with immediates
+                const mir_tag: Mir.Inst.Tag = switch (tag) {
+                    .bit_and => .and_shifted_register,
+                    .bit_or => .orr_shifted_register,
+                    .xor => .eor_shifted_register,
+                    else => unreachable,
+                };
+
+                return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
+            } else {
+                return self.fail("TODO binary operations on int with bits > 64", .{});
+            }
+        },
+        else => unreachable,
+    }
+}
+
+fn shiftExact(
+    self: *Self,
+    tag: Air.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) InnerError!MCValue {
+    _ = rhs_ty;
+
+    switch (lhs_ty.zigTypeTag()) {
+        .Vector => return self.fail("TODO binary operations on vectors", .{}),
+        .Int => {
+            const int_info = lhs_ty.intInfo(self.target.*);
+            if (int_info.bits <= 64) {
+                const rhs_immediate = try rhs_bind.resolveToImmediate(self);
+
+                const mir_tag_register: Mir.Inst.Tag = switch (tag) {
+                    .shl_exact => .lsl_register,
+                    .shr_exact => switch (int_info.signedness) {
+                        .signed => Mir.Inst.Tag.asr_register,
+                        .unsigned => Mir.Inst.Tag.lsr_register,
+                    },
+                    else => unreachable,
+                };
+                const mir_tag_immediate: Mir.Inst.Tag = switch (tag) {
+                    .shl_exact => .lsl_immediate,
+                    .shr_exact => switch (int_info.signedness) {
+                        .signed => Mir.Inst.Tag.asr_immediate,
+                        .unsigned => Mir.Inst.Tag.lsr_immediate,
+                    },
+                    else => unreachable,
+                };
+
+                if (rhs_immediate) |imm| {
+                    return try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, imm, lhs_ty, false, maybe_inst);
+                } else {
+                    // We intentionally pass lhs_ty here in order to
+                    // prevent using the 32-bit register alias when
+                    // lhs_ty is > 32 bits.
+                    return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, lhs_ty, maybe_inst);
+                }
+            } else {
+                return self.fail("TODO binary operations on int with bits > 64", .{});
+            }
+        },
+        else => unreachable,
+    }
+}
+
+fn shiftNormal(
+    self: *Self,
+    tag: Air.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) InnerError!MCValue {
+    switch (lhs_ty.zigTypeTag()) {
+        .Vector => return self.fail("TODO binary operations on vectors", .{}),
+        .Int => {
+            const int_info = lhs_ty.intInfo(self.target.*);
+            if (int_info.bits <= 64) {
+                // Generate a shl_exact/shr_exact
+                const result: MCValue = switch (tag) {
+                    .shl => try self.shiftExact(.shl_exact, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
+                    .shr => try self.shiftExact(.shr_exact, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
+                    else => unreachable,
+                };
+
+                // Truncate if necessary
+                switch (tag) {
+                    .shr => return result,
+                    .shl => {
+                        const result_reg = result.register;
+                        try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
+                        return result;
+                    },
+                    else => unreachable,
+                }
+            } else {
+                return self.fail("TODO binary operations on integers > u64/i64", .{});
+            }
+        },
+        else => unreachable,
+    }
+}
+
+fn booleanOp(
+    self: *Self,
+    tag: Air.Inst.Tag,
+    lhs_bind: ReadArg.Bind,
+    rhs_bind: ReadArg.Bind,
+    lhs_ty: Type,
+    rhs_ty: Type,
+    maybe_inst: ?Air.Inst.Index,
+) InnerError!MCValue {
+    switch (lhs_ty.zigTypeTag()) {
+        .Bool => {
+            assert((try lhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema
+            assert((try rhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema
+
+            const mir_tag_register: Mir.Inst.Tag = switch (tag) {
+                .bool_and => .and_shifted_register,
+                .bool_or => .orr_shifted_register,
+                else => unreachable,
+            };
+
+            return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
+        },
+        else => unreachable,
+    }
+}
+
 fn ptrArithmetic(
     self: *Self,
     tag: Air.Inst.Tag,
@@ -2441,16 +2445,24 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
 
             .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
 
-            else => blk: {
-                const lhs = try self.resolveInst(bin_op.lhs);
-                const rhs = try self.resolveInst(bin_op.rhs);
+            .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
 
-                break :blk try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
-                    .inst = inst,
-                    .lhs = bin_op.lhs,
-                    .rhs = bin_op.rhs,
-                });
-            },
+            .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .xor => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+
+            .shl_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .shr_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+
+            .shl => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .shr => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+
+            .bool_and => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+            .bool_or => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
+
+            else => unreachable,
         };
     };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });