Commit f8163f7eaf

joachimschmidt557 <joachim.schmidt557@outlook.com>
2021-12-31 12:21:59
stage2 ARM: implement airCall for function pointers
1 parent b100e2e
Changed files (2)
src
arch
test
stage2
src/arch/arm/CodeGen.zig
@@ -2238,10 +2238,16 @@ fn airFence(self: *Self) !void {
 
 fn airCall(self: *Self, inst: Air.Inst.Index) !void {
     const pl_op = self.air.instructions.items(.data)[inst].pl_op;
-    const fn_ty = self.air.typeOf(pl_op.operand);
     const callee = pl_op.operand;
     const extra = self.air.extraData(Air.Call, pl_op.payload);
     const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+    const ty = self.air.typeOf(callee);
+
+    const fn_ty = switch (ty.zigTypeTag()) {
+        .Fn => ty,
+        .Pointer => ty.childType(),
+        else => unreachable,
+    };
 
     var info = try self.resolveCallingConventionValues(fn_ty);
     defer info.deinit(self);
@@ -2310,39 +2316,42 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
                     unreachable;
 
                 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
-
-                // TODO: add Instruction.supportedOn
-                // function for ARM
-                if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
-                    _ = try self.addInst(.{
-                        .tag = .blx,
-                        .cond = .al,
-                        .data = .{ .reg = .lr },
-                    });
-                } else {
-                    return self.fail("TODO fix blx emulatio for ARM <v5", .{});
-                    // _ = try self.addInst(.{
-                    //     .tag = .mov,
-                    //     .cond = .al,
-                    //     .data = .{ .rr_op = .{
-                    //         .rd = .lr,
-                    //         .rn = .r0,
-                    //         .op = Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none),
-                    //     } },
-                    // });
-                    // _ = try self.addInst(.{
-                    //     .tag = .bx,
-                    //     .cond = .al,
-                    //     .data = .{ .reg = .lr },
-                    // });
-                }
             } else if (func_value.castTag(.extern_fn)) |_| {
                 return self.fail("TODO implement calling extern functions", .{});
             } else {
                 return self.fail("TODO implement calling bitcasted functions", .{});
             }
         } else {
-            return self.fail("TODO implement calling runtime known function pointer", .{});
+            assert(ty.zigTypeTag() == .Pointer);
+            const mcv = try self.resolveInst(callee);
+
+            try self.genSetReg(Type.initTag(.usize), .lr, mcv);
+        }
+
+        // TODO: add Instruction.supportedOn
+        // function for ARM
+        if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
+            _ = try self.addInst(.{
+                .tag = .blx,
+                .cond = .al,
+                .data = .{ .reg = .lr },
+            });
+        } else {
+            return self.fail("TODO fix blx emulation for ARM <v5", .{});
+            // _ = try self.addInst(.{
+            //     .tag = .mov,
+            //     .cond = .al,
+            //     .data = .{ .rr_op = .{
+            //         .rd = .lr,
+            //         .rn = .r0,
+            //         .op = Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none),
+            //     } },
+            // });
+            // _ = try self.addInst(.{
+            //     .tag = .bx,
+            //     .cond = .al,
+            //     .data = .{ .reg = .lr },
+            // });
         }
     } else if (self.bin_file.cast(link.File.MachO)) |_| {
         unreachable; // unsupported architecture for MachO
test/stage2/arm.zig
@@ -704,4 +704,52 @@ pub fn addCases(ctx: *TestContext) !void {
             "",
         );
     }
+
+    {
+        var case = ctx.exe("function pointers", linux_arm);
+        case.addCompareOutput(
+            \\const PrintFn = fn () void;
+            \\
+            \\pub fn main() void {
+            \\    var printFn: PrintFn = stopSayingThat;
+            \\    var i: u32 = 0;
+            \\    while (i < 4) : (i += 1) printFn();
+            \\
+            \\    printFn = moveEveryZig;
+            \\    printFn();
+            \\}
+            \\
+            \\fn stopSayingThat() void {
+            \\    asm volatile ("svc #0"
+            \\        :
+            \\        : [number] "{r7}" (4),
+            \\          [arg1] "{r0}" (1),
+            \\          [arg2] "{r1}" (@ptrToInt("Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n")),
+            \\          [arg3] "{r2}" ("Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n".len),
+            \\        : "memory"
+            \\    );
+            \\    return;
+            \\}
+            \\
+            \\fn moveEveryZig() void {
+            \\    asm volatile ("svc #0"
+            \\        :
+            \\        : [number] "{r7}" (4),
+            \\          [arg1] "{r0}" (1),
+            \\          [arg2] "{r1}" (@ptrToInt("All your codebase are belong to us\n")),
+            \\          [arg3] "{r2}" ("All your codebase are belong to us\n".len),
+            \\        : "memory"
+            \\    );
+            \\    return;
+            \\}
+        ,
+            \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
+            \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
+            \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
+            \\Hello, my name is Inigo Montoya; you killed my father, prepare to die.
+            \\All your codebase are belong to us
+            \\
+            ,
+        );
+    }
 }