Commit 8b24c783c5

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-08-04 21:05:11
stage2 AArch64: implement basic integer division
1 parent dcb236a
Changed files (4)
src/arch/aarch64/bits.zig
@@ -1698,6 +1698,14 @@ pub const Instruction = union(enum) {
 
     // Data processing (2 source)
 
+    pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction {
+        return dataProcessing2Source(0b0, 0b000010, rd, rn, rm);
+    }
+
+    pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction {
+        return dataProcessing2Source(0b0, 0b000011, rd, rn, rm);
+    }
+
     pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
         return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
     }
src/arch/aarch64/CodeGen.zig
@@ -561,33 +561,38 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
 
         switch (air_tags[inst]) {
             // zig fmt: off
-            .add       => try self.airBinOp(inst, .add),
-            .addwrap   => try self.airBinOp(inst, .addwrap),
-            .sub       => try self.airBinOp(inst, .sub),
-            .subwrap   => try self.airBinOp(inst, .subwrap),
-            .mul       => try self.airBinOp(inst, .mul),
-            .mulwrap   => try self.airBinOp(inst, .mulwrap),
-            .shl       => try self.airBinOp(inst, .shl),
-            .shl_exact => try self.airBinOp(inst, .shl_exact),
-            .bool_and  => try self.airBinOp(inst, .bool_and),
-            .bool_or   => try self.airBinOp(inst, .bool_or),
-            .bit_and   => try self.airBinOp(inst, .bit_and),
-            .bit_or    => try self.airBinOp(inst, .bit_or),
-            .xor       => try self.airBinOp(inst, .xor),
-            .shr       => try self.airBinOp(inst, .shr),
-            .shr_exact => try self.airBinOp(inst, .shr_exact),
-
-            .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
-            .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
+            .add             => try self.airBinOp(inst, .add),
+            .addwrap         => try self.airBinOp(inst, .addwrap),
+            .sub             => try self.airBinOp(inst, .sub),
+            .subwrap         => try self.airBinOp(inst, .subwrap),
+            .mul             => try self.airBinOp(inst, .mul),
+            .mulwrap         => try self.airBinOp(inst, .mulwrap),
+            .shl             => try self.airBinOp(inst, .shl),
+            .shl_exact       => try self.airBinOp(inst, .shl_exact),
+            .bool_and        => try self.airBinOp(inst, .bool_and),
+            .bool_or         => try self.airBinOp(inst, .bool_or),
+            .bit_and         => try self.airBinOp(inst, .bit_and),
+            .bit_or          => try self.airBinOp(inst, .bit_or),
+            .xor             => try self.airBinOp(inst, .xor),
+            .shr             => try self.airBinOp(inst, .shr),
+            .shr_exact       => try self.airBinOp(inst, .shr_exact),
+            .div_float       => try self.airBinOp(inst, .div_float),
+            .div_trunc       => try self.airBinOp(inst, .div_trunc),
+            .div_floor       => try self.airBinOp(inst, .div_floor),
+            .div_exact       => try self.airBinOp(inst, .div_exact),
+            .rem             => try self.airBinOp(inst, .rem),
+            .mod             => try self.airBinOp(inst, .mod),
+
+            .ptr_add         => try self.airPtrArithmetic(inst, .ptr_add),
+            .ptr_sub         => try self.airPtrArithmetic(inst, .ptr_sub),
+
+            .min             => try self.airMin(inst),
+            .max             => try self.airMax(inst),
 
             .add_sat         => try self.airAddSat(inst),
             .sub_sat         => try self.airSubSat(inst),
             .mul_sat         => try self.airMulSat(inst),
-            .rem             => try self.airRem(inst),
-            .mod             => try self.airMod(inst),
             .shl_sat         => try self.airShlSat(inst),
-            .min             => try self.airMin(inst),
-            .max             => try self.airMax(inst),
             .slice           => try self.airSlice(inst),
 
             .sqrt,
@@ -612,8 +617,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .mul_with_overflow => try self.airMulWithOverflow(inst),
             .shl_with_overflow => try self.airShlWithOverflow(inst),
 
-            .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
-
             .cmp_lt  => try self.airCmp(inst, .lt),
             .cmp_lte => try self.airCmp(inst, .lte),
             .cmp_eq  => try self.airCmp(inst, .eq),
@@ -1391,6 +1394,8 @@ fn binOpRegister(
         .lsl_register,
         .asr_register,
         .lsr_register,
+        .sdiv,
+        .udiv,
         => .{ .rrr = .{
             .rd = dest_reg,
             .rn = lhs_reg,
@@ -1629,6 +1634,67 @@ fn binOp(
                 else => unreachable,
             }
         },
+        .div_float => {
+            switch (lhs_ty.zigTypeTag()) {
+                .Float => return self.fail("TODO div_float", .{}),
+                .Vector => return self.fail("TODO div_float on vectors", .{}),
+                else => unreachable,
+            }
+        },
+        .div_trunc, .div_floor, .div_exact => {
+            switch (lhs_ty.zigTypeTag()) {
+                .Float => return self.fail("TODO div on floats", .{}),
+                .Vector => return self.fail("TODO div on vectors", .{}),
+                .Int => {
+                    assert(lhs_ty.eql(rhs_ty, mod));
+                    const int_info = lhs_ty.intInfo(self.target.*);
+                    if (int_info.bits <= 64) {
+                        switch (int_info.signedness) {
+                            .signed => {
+                                switch (tag) {
+                                    .div_trunc, .div_exact => {
+                                        // TODO optimize integer division by constants
+                                        return try self.binOpRegister(.sdiv, lhs, rhs, lhs_ty, rhs_ty, metadata);
+                                    },
+                                    .div_floor => return self.fail("TODO div_floor on signed integers", .{}),
+                                    else => unreachable,
+                                }
+                            },
+                            .unsigned => {
+                                // TODO optimize integer division by constants
+                                return try self.binOpRegister(.udiv, lhs, rhs, lhs_ty, rhs_ty, metadata);
+                            },
+                        }
+                    } else {
+                        return self.fail("TODO integer division for ints with bits > 64", .{});
+                    }
+                },
+                else => unreachable,
+            }
+        },
+        .rem, .mod => {
+            switch (lhs_ty.zigTypeTag()) {
+                .Float => return self.fail("TODO rem/mod on floats", .{}),
+                .Vector => return self.fail("TODO rem/mod on vectors", .{}),
+                .Int => {
+                    assert(lhs_ty.eql(rhs_ty, mod));
+                    const int_info = lhs_ty.intInfo(self.target.*);
+                    if (int_info.bits <= 32) {
+                        switch (int_info.signedness) {
+                            .signed => {
+                                return self.fail("TODO rem/mod on signed integers", .{});
+                            },
+                            .unsigned => {
+                                return self.fail("TODO rem/mod on unsigned integers", .{});
+                            },
+                        }
+                    } else {
+                        return self.fail("TODO rem/mod for integers with bits > 64", .{});
+                    }
+                },
+                else => unreachable,
+            }
+        },
         .addwrap,
         .subwrap,
         .mulwrap,
@@ -2300,24 +2366,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
 }
 
-fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
-    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
-    return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
-fn airRem(self: *Self, inst: Air.Inst.Index) !void {
-    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch});
-    return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
-fn airMod(self: *Self, inst: Air.Inst.Index) !void {
-    const bin_op = self.air.instructions.items(.data)[inst].bin_op;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mod for {}", .{self.target.cpu.arch});
-    return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
 fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
     const bin_op = self.air.instructions.items(.data)[inst].bin_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
src/arch/aarch64/Emit.zig
@@ -91,9 +91,11 @@ pub fn emitMir(
             .sub_immediate => try emit.mirAddSubtractImmediate(inst),
             .subs_immediate => try emit.mirAddSubtractImmediate(inst),
 
-            .asr_register => try emit.mirShiftRegister(inst),
-            .lsl_register => try emit.mirShiftRegister(inst),
-            .lsr_register => try emit.mirShiftRegister(inst),
+            .asr_register => try emit.mirDataProcessing2Source(inst),
+            .lsl_register => try emit.mirDataProcessing2Source(inst),
+            .lsr_register => try emit.mirDataProcessing2Source(inst),
+            .sdiv => try emit.mirDataProcessing2Source(inst),
+            .udiv => try emit.mirDataProcessing2Source(inst),
 
             .asr_immediate => try emit.mirShiftImmediate(inst),
             .lsl_immediate => try emit.mirShiftImmediate(inst),
@@ -520,7 +522,7 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
     }
 }
 
-fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
+fn mirDataProcessing2Source(emit: *Emit, inst: Mir.Inst.Index) !void {
     const tag = emit.mir.instructions.items(.tag)[inst];
     const rrr = emit.mir.instructions.items(.data)[inst].rrr;
     const rd = rrr.rd;
@@ -531,6 +533,8 @@ fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
         .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)),
         .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)),
         .lsr_register => try emit.writeInstruction(Instruction.lsrRegister(rd, rn, rm)),
+        .sdiv => try emit.writeInstruction(Instruction.sdiv(rd, rn, rm)),
+        .udiv => try emit.writeInstruction(Instruction.udiv(rd, rn, rm)),
         else => unreachable,
     }
 }
src/arch/aarch64/Mir.zig
@@ -164,6 +164,8 @@ pub const Inst = struct {
         ret,
         /// Signed bitfield extract
         sbfx,
+        /// Signed divide
+        sdiv,
         /// Signed multiply high
         smulh,
         /// Signed multiply long
@@ -212,6 +214,8 @@ pub const Inst = struct {
         tst_immediate,
         /// Unsigned bitfield extract
         ubfx,
+        /// Unsigned divide
+        udiv,
         /// Unsigned multiply high
         umulh,
         /// Unsigned multiply long