Commit d5100dc815

Andrew Kelley <andrew@ziglang.org>
2022-02-28 21:38:33
stage2: fix frame_address AIR instruction
Various places were assuming different union tags. Now it is consistently a no-op instruction, just like the similar instruction ret_addr.
1 parent 90bce11
src/arch/aarch64/CodeGen.zig
@@ -579,7 +579,8 @@ 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(),
+            .ret_addr        => try self.airRetAddr(inst),
+            .frame_addr      => try self.airFrameAddress(inst),
             .fence           => try self.airFence(),
             .call            => try self.airCall(inst),
             .cond_br         => try self.airCondBr(inst),
@@ -670,8 +671,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .wrap_optional         => try self.airWrapOptional(inst),
             .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
             .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
-
-            .frame_address => try self.airFrameAddress(inst),
             // zig fmt: on
         }
 
@@ -1519,13 +1518,6 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
-fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
-    const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
-    const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
-    _ = extra;
-    return self.fail("TODO implement codegen airFrameAddress", .{});
-}
-
 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
     const ty_op = self.air.instructions.items(.data)[inst].ty_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch});
@@ -2187,8 +2179,14 @@ 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 airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airRetAddr for aarch64", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
+}
+
+fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress for aarch64", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
 }
 
 fn airFence(self: *Self) !void {
src/arch/arm/CodeGen.zig
@@ -565,7 +565,8 @@ 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(),
+            .ret_addr        => try self.airRetAddr(inst),
+            .frame_addr      => try self.airFrameAddress(inst),
             .fence           => try self.airFence(),
             .call            => try self.airCall(inst),
             .cond_br         => try self.airCondBr(inst),
@@ -656,8 +657,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .wrap_optional         => try self.airWrapOptional(inst),
             .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
             .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
-
-            .frame_address => try self.airFrameAddress(inst),
             // zig fmt: on
         }
 
@@ -1274,13 +1273,6 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
-fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
-    const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
-    const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress", .{});
-    return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
     const ty_op = self.air.instructions.items(.data)[inst].ty_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
@@ -2458,8 +2450,14 @@ 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 airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airRetAddr for arm", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
+}
+
+fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress for arm", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
 }
 
 fn airFence(self: *Self) !void {
src/arch/riscv64/CodeGen.zig
@@ -550,7 +550,8 @@ 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(),
+            .ret_addr        => try self.airRetAddr(inst),
+            .frame_addr      => try self.airFrameAddress(inst),
             .fence           => try self.airFence(),
             .call            => try self.airCall(inst),
             .cond_br         => try self.airCondBr(inst),
@@ -641,8 +642,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .wrap_optional         => try self.airWrapOptional(inst),
             .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
             .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
-
-            .frame_address => try self.airFrameAddress(inst),
             // zig fmt: on
         }
         if (std.debug.runtime_safety) {
@@ -1105,12 +1104,6 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
-fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
-    _ = self;
-    _ = inst;
-    return self.fail("TODO implement codegen airFrameAddress", .{});
-}
-
 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
     const ty_op = self.air.instructions.items(.data)[inst].ty_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch});
@@ -1446,8 +1439,14 @@ 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 airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airRetAddr for riscv64", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
+}
+
+fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress for riscv64", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
 }
 
 fn airFence(self: *Self) !void {
src/arch/wasm/CodeGen.zig
@@ -1683,6 +1683,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .assembly,
         .shl_sat,
         .ret_addr,
+        .frame_addr,
         .clz,
         .ctz,
         .popcount,
@@ -1726,7 +1727,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .error_name,
         .errunion_payload_ptr_set,
         .field_parent_ptr,
-        .frame_address,
 
         // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248
         // is implemented in the frontend before implementing them here in the wasm backend.
src/arch/x86_64/CodeGen.zig
@@ -662,7 +662,8 @@ 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(),
+            .ret_addr        => try self.airRetAddr(inst),
+            .frame_addr      => try self.airFrameAddress(inst),
             .fence           => try self.airFence(),
             .call            => try self.airCall(inst),
             .cond_br         => try self.airCondBr(inst),
@@ -753,8 +754,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .wrap_optional         => try self.airWrapOptional(inst),
             .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
             .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
-
-            .frame_address => try self.airFrameAddress(inst),
             // zig fmt: on
         }
 
@@ -1867,15 +1866,6 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
-fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
-    const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-    const result: MCValue = if (self.liveness.isUnused(inst))
-        .dead
-    else
-        return self.fail("TODO implement airFrameAddress for {}", .{self.target.cpu.arch});
-    return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
-}
-
 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
     const ty_op = self.air.instructions.items(.data)[inst].ty_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
@@ -3138,8 +3128,14 @@ 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 airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airRetAddr for x86_64", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
+}
+
+fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress for x86_64", .{});
+    return self.finishAir(inst, result, .{ .none, .none, .none });
 }
 
 fn airFence(self: *Self) !void {
src/codegen/c.zig
@@ -1588,7 +1588,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .arg      => airArg(f),
 
             .breakpoint => try airBreakpoint(f),
-            .ret_addr   => try airRetAddr(f),
+            .ret_addr   => try airRetAddr(f, inst),
+            .frame_addr => try airFrameAddress(f, inst),
             .unreach    => try airUnreach(f),
             .fence      => try airFence(f, inst),
 
@@ -1757,8 +1758,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .wrap_errunion_payload       => try airWrapErrUnionPay(f, inst),
             .wrap_errunion_err           => try airWrapErrUnionErr(f, inst),
             .errunion_payload_ptr_set    => try airErrUnionPayloadPtrSet(f, inst),
-
-            .frame_address => try airFrameAddress(f, inst),
             // zig fmt: on
         };
         switch (result_value) {
@@ -2719,12 +2718,20 @@ fn airBreakpoint(f: *Function) !CValue {
     return CValue.none;
 }
 
-fn airRetAddr(f: *Function) !CValue {
+fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
+    if (f.liveness.isUnused(inst)) return CValue.none;
     const local = try f.allocLocal(Type.usize, .Const);
     try f.object.writer().writeAll(" = zig_return_address();\n");
     return local;
 }
 
+fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
+    if (f.liveness.isUnused(inst)) return CValue.none;
+    const local = try f.allocLocal(Type.usize, .Const);
+    try f.object.writer().writeAll(" = zig_frame_address();\n");
+    return local;
+}
+
 fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
     const atomic_order = f.air.instructions.items(.data)[inst].fence;
     const writer = f.object.writer();
@@ -3200,11 +3207,6 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
     return f.fail("TODO: C backend: implement airErrUnionPayloadPtrSet", .{});
 }
 
-fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
-    _ = inst;
-    return f.fail("TODO: C backend: implement airFrameAddress", .{});
-}
-
 fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
     if (f.liveness.isUnused(inst))
         return CValue.none;
src/codegen/llvm.zig
@@ -2135,6 +2135,7 @@ pub const FuncGen = struct {
                 .switch_br      => try self.airSwitchBr(inst),
                 .breakpoint     => try self.airBreakpoint(inst),
                 .ret_addr       => try self.airRetAddr(inst),
+                .frame_addr     => try self.airFrameAddress(inst),
                 .call           => try self.airCall(inst),
                 .cond_br        => try self.airCondBr(inst),
                 .intcast        => try self.airIntCast(inst),
@@ -2214,8 +2215,6 @@ pub const FuncGen = struct {
                 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
                 .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
 
-                .frame_address => try self.airFrameAddress(inst),
-
                 .constant => unreachable,
                 .const_ty => unreachable,
                 .unreach  => self.airUnreach(inst),
@@ -3341,16 +3340,6 @@ pub const FuncGen = struct {
         return partial;
     }
 
-    fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
-        if (self.liveness.isUnused(inst)) return null;
-
-        const llvm_i32 = try self.dg.llvmType(Type.initTag(.i32));
-        const llvm_fn = self.getIntrinsic("llvm.frameaddress", &.{llvm_i32});
-        const ptr_val = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{llvm_i32.constNull()}, 1, .Fast, .Auto, "");
-        const llvm_usize = try self.dg.llvmType(Type.usize);
-        return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
-    }
-
     fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
         if (self.liveness.isUnused(inst)) return null;
 
@@ -4112,12 +4101,25 @@ pub const FuncGen = struct {
     }
 
     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);
+        if (self.liveness.isUnused(inst)) return null;
+
+        const llvm_i32 = self.context.intType(32);
         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, "");
+        const params = [_]*const llvm.Value{llvm_i32.constNull()};
+        const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
+        const llvm_usize = try self.dg.llvmType(Type.usize);
+        return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
+    }
+
+    fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+        if (self.liveness.isUnused(inst)) return null;
+
+        const llvm_i32 = self.context.intType(32);
+        const llvm_fn = self.getIntrinsic("llvm.frameaddress", &.{llvm_i32});
+        const params = [_]*const llvm.Value{llvm_i32.constNull()};
+        const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
+        const llvm_usize = try self.dg.llvmType(Type.usize);
+        return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
     }
 
     fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
src/Air.zig
@@ -218,6 +218,9 @@ pub const Inst = struct {
         /// Yields the return address of the current function.
         /// Uses the `no_op` field.
         ret_addr,
+        /// Implements @frameAddress builtin.
+        /// Uses the `no_op` field.
+        frame_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.
@@ -580,10 +583,6 @@ pub const Inst = struct {
         /// Uses the `ty_pl` field.
         field_parent_ptr,
 
-        /// Implements @frameAddress builtin.
-        /// Uses the `ty` field.
-        frame_address,
-
         pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
             return switch (op) {
                 .lt => .cmp_lt,
@@ -943,7 +942,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
         .ptrtoint,
         .slice_len,
         .ret_addr,
-        .frame_address,
+        .frame_addr,
         => return Type.initTag(.usize),
 
         .bool_to_int => return Type.initTag(.u1),
src/Liveness.zig
@@ -317,7 +317,7 @@ fn analyzeInst(
         .unreach,
         .fence,
         .ret_addr,
-        .frame_address,
+        .frame_addr,
         => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
 
         .not,
src/print_air.zig
@@ -171,13 +171,13 @@ const Writer = struct {
             .breakpoint,
             .unreach,
             .ret_addr,
+            .frame_addr,
             => try w.writeNoOp(s, inst),
 
             .const_ty,
             .alloc,
             .ret_ptr,
             .arg,
-            .frame_address,
             => try w.writeTy(s, inst),
 
             .not,
src/Sema.zig
@@ -9993,14 +9993,21 @@ 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) };
     try sema.requireRuntimeBlock(block, src);
     return try block.addNoOp(.ret_addr);
 }
 
+fn zirFrameAddress(
+    sema: *Sema,
+    block: *Block,
+    extended: Zir.Inst.Extended.InstData,
+) CompileError!Air.Inst.Ref {
+    const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
+    try sema.requireRuntimeBlock(block, src);
+    return try block.addNoOp(.frame_addr);
+}
+
 fn zirBuiltinSrc(
     sema: *Sema,
     block: *Block,
@@ -11889,16 +11896,6 @@ fn zirFrame(
     return sema.fail(block, src, "TODO: Sema.zirFrame", .{});
 }
 
-fn zirFrameAddress(
-    sema: *Sema,
-    block: *Block,
-    extended: Zir.Inst.Extended.InstData,
-) CompileError!Air.Inst.Ref {
-    const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
-    try sema.requireFunctionBlock(block, src);
-    return block.addTy(.frame_address, Type.@"usize");
-}
-
 fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };