Commit ddd2ef822f

Robin Voetter <robin@voetter.nl>
2021-12-18 06:11:46
stage2: @returnAddress()
1 parent 2f7e98c
src/arch/aarch64/CodeGen.zig
@@ -547,6 +547,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
                     .block           => try self.airBlock(inst),
                     .br              => try self.airBr(inst),
                     .breakpoint      => try self.airBreakpoint(),
+                    .ret_addr        => try self.airRetAddr(),
                     .fence           => try self.airFence(),
                     .call            => try self.airCall(inst),
                     .cond_br         => try self.airCondBr(inst),
@@ -1416,6 +1417,10 @@ fn airBreakpoint(self: *Self) !void {
     return self.finishAirBookkeeping();
 }
 
+fn airRetAddr(self: *Self) !void {
+    return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
+}
+
 fn airFence(self: *Self) !void {
     return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
     //return self.finishAirBookkeeping();
src/arch/arm/CodeGen.zig
@@ -545,6 +545,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
                     .block           => try self.airBlock(inst),
                     .br              => try self.airBr(inst),
                     .breakpoint      => try self.airBreakpoint(),
+                    .ret_addr        => try self.airRetAddr(),
                     .fence           => try self.airFence(),
                     .call            => try self.airCall(inst),
                     .cond_br         => try self.airCondBr(inst),
@@ -1850,6 +1851,10 @@ fn airBreakpoint(self: *Self) !void {
     return self.finishAirBookkeeping();
 }
 
+fn airRetAddr(self: *Self) !void {
+    return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
+}
+
 fn airFence(self: *Self) !void {
     return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
     //return self.finishAirBookkeeping();
src/arch/riscv64/CodeGen.zig
@@ -526,6 +526,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
                     .block           => try self.airBlock(inst),
                     .br              => try self.airBr(inst),
                     .breakpoint      => try self.airBreakpoint(),
+                    .ret_addr        => try self.airRetAddr(),
                     .fence           => try self.airFence(),
                     .call            => try self.airCall(inst),
                     .cond_br         => try self.airCondBr(inst),
@@ -1354,6 +1355,10 @@ fn airBreakpoint(self: *Self) !void {
     return self.finishAirBookkeeping();
 }
 
+fn airRetAddr(self: *Self) !void {
+    return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
+}
+
 fn airFence(self: *Self) !void {
     return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
     //return self.finishAirBookkeeping();
src/arch/x86_64/CodeGen.zig
@@ -579,6 +579,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
                     .block           => try self.airBlock(inst),
                     .br              => try self.airBr(inst),
                     .breakpoint      => try self.airBreakpoint(),
+                    .ret_addr        => try self.airRetAddr(),
                     .fence           => try self.airFence(),
                     .call            => try self.airCall(inst),
                     .cond_br         => try self.airCondBr(inst),
@@ -1839,6 +1840,10 @@ fn airBreakpoint(self: *Self) !void {
     return self.finishAirBookkeeping();
 }
 
+fn airRetAddr(self: *Self) !void {
+    return self.fail("TODO implement airRetAddr for {}", .{self.target.cpu.arch});
+}
+
 fn airFence(self: *Self) !void {
     return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
     //return self.finishAirBookkeeping();
src/codegen/c.zig
@@ -1125,6 +1125,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .arg      => airArg(f),
 
             .breakpoint => try airBreakpoint(f),
+            .ret_addr   => try airRetAddr(f),
             .unreach    => try airUnreach(f),
             .fence      => try airFence(f, inst),
 
@@ -2191,6 +2192,10 @@ fn airBreakpoint(f: *Function) !CValue {
     return CValue.none;
 }
 
+fn airRetAddr(f: *Function) !CValue {
+    return f.fail("TODO implement codegen for airRetAddr", .{});
+}
+
 fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
     const atomic_order = f.air.instructions.items(.data)[inst].fence;
     const writer = f.object.writer();
src/codegen/llvm.zig
@@ -1747,6 +1747,7 @@ pub const FuncGen = struct {
                 .br             => try self.airBr(inst),
                 .switch_br      => try self.airSwitchBr(inst),
                 .breakpoint     => try self.airBreakpoint(inst),
+                .ret_addr       => try self.airRetAddr(inst),
                 .call           => try self.airCall(inst),
                 .cond_br        => try self.airCondBr(inst),
                 .intcast        => try self.airIntCast(inst),
@@ -3550,6 +3551,15 @@ pub const FuncGen = struct {
         return null;
     }
 
+    fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+        _ = inst;
+        const i32_zero = self.context.intType(32).constNull();
+        const usize_llvm_ty = try self.dg.llvmType(Type.usize);
+        const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});
+        const ptr_val = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{i32_zero}, 1, .Fast, .Auto, "");
+        return self.builder.buildPtrToInt(ptr_val, usize_llvm_ty, "");
+    }
+
     fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
         const atomic_order = self.air.instructions.items(.data)[inst].fence;
         const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);
src/Air.zig
@@ -195,6 +195,9 @@ pub const Inst = struct {
         /// Lowers to a hardware trap instruction, or the next best thing.
         /// Result type is always void.
         breakpoint,
+        /// Yields the return address of the current function.
+        /// Uses the `no_op` field.
+        ret_addr,
         /// Function call.
         /// Result type is the return type of the function being called.
         /// Uses the `pl_op` field with the `Call` payload. operand is the callee.
@@ -785,6 +788,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
 
         .ptrtoint,
         .slice_len,
+        .ret_addr,
         => return Type.initTag(.usize),
 
         .bool_to_int => return Type.initTag(.u1),
src/Liveness.zig
@@ -281,6 +281,7 @@ fn analyzeInst(
         .dbg_stmt,
         .unreach,
         .fence,
+        .ret_addr,
         => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
 
         .not,
src/print_air.zig
@@ -159,6 +159,7 @@ const Writer = struct {
 
             .breakpoint,
             .unreach,
+            .ret_addr,
             => try w.writeNoOp(s, inst),
 
             .const_ty,
src/Sema.zig
@@ -8739,8 +8739,12 @@ fn zirRetAddr(
     block: *Block,
     extended: Zir.Inst.Extended.InstData,
 ) CompileError!Air.Inst.Ref {
+    const tracy = trace(@src());
+    defer tracy.end();
+
     const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
-    return sema.fail(block, src, "TODO: implement Sema.zirRetAddr", .{});
+    try sema.requireRuntimeBlock(block, src);
+    return try block.addNoOp(.ret_addr);
 }
 
 fn zirBuiltinSrc(