diff --git a/src/Air.zig b/src/Air.zig index 90d61dfa03caf2421dbb2b1bc91f813fad796533..11e7045da3e7cf21a06e44133aae7adeb006d4af 100644 --- a/src/Air.zig +++ b/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), diff --git a/src/Liveness.zig b/src/Liveness.zig index ac34bc4e029749a9c2bce94319e8e4bcf7429bc8..d47c7086ce5fabbffb889c6d9c7aed7ee9e2c256 100644 --- a/src/Liveness.zig +++ b/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, diff --git a/src/Sema.zig b/src/Sema.zig index de69cbe5da37a1a3f16131adfccd3bf39f156c38..ccea8377c8af74ea9652ae7791dfbe6b2295d074 100644 --- a/src/Sema.zig +++ b/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 }; diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index b58bad7a3cbb34017d8d16c4850b42727f80b95b..8c214f009111cc964bccfce9ef3aa6c3d7d8022e 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/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 { diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 177619682891f4d24a28545db1887062b2194b44..a6630cef42f1299d85a487c8b5c555ade63f853b 100644 --- a/src/arch/arm/CodeGen.zig +++ b/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 { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index ac5d914af103b131953fc2807d70ee6340d2a78a..a51b8b40cc59620dff2bccf70ddbddfcbdb51c2c 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/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 { diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 69a70d0d536a0a14730ad503046295380579b309..4f19aeca6b206907f33045af49a68ce15dfcc0ed 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/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. diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 3a6541ccd5d6e5b66983bdc6f0b1879cfea4e39b..f423671dcf6197eef8125a90dbe2525ebf053e7f 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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 { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 331673cc55d872fffbc4b2d5477d269677cabb0b..3e47637c763e57a0a295fc57453e610fa5948ce4 100644 --- a/src/codegen/c.zig +++ b/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; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6f2cc9bbd047e3f9bf9b88473c6af164a16dcdf2..ddd6e7c06b90db984ab5d20559c7fa9c030adc52 100644 --- a/src/codegen/llvm.zig +++ b/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, ¶ms, 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, ¶ms, 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 { diff --git a/src/print_air.zig b/src/print_air.zig index 5c6fdf47592e079ce92db046f38428f37b0d1ef3..ae6959e0fc53d0bff4aab69c1d5349e7ab899661 100644 --- a/src/print_air.zig +++ b/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,