From f8163f7eaf45fa2b53a1f5ceac35088ad7d73e45 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Fri, 31 Dec 2021 12:21:59 +0100 Subject: [PATCH 1/3] stage2 ARM: implement airCall for function pointers --- src/arch/arm/CodeGen.zig | 65 +++++++++++++++++++++++----------------- test/stage2/arm.zig | 48 +++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 7765064634..a607ce54fd 100644 --- a/src/arch/arm/CodeGen.zig +++ b/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 Date: Fri, 31 Dec 2021 17:33:08 +0100 Subject: [PATCH 2/3] stage2 ARM: implement airUnwrapErrErr + airCmp for error sets --- src/arch/arm/CodeGen.zig | 52 +++++++++++++++++++++++++--------------- test/stage2/arm.zig | 29 ++++++++++++++++++++++ 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index a607ce54fd..d1c7c7ecf0 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -1099,15 +1099,22 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { fn airUnwrapErrErr(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 unwrap error union error for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const error_union_ty = self.air.typeOf(ty_op.operand); + const payload_ty = error_union_ty.errorUnionPayload(); + const mcv = try self.resolveInst(ty_op.operand); + if (!payload_ty.hasCodeGenBits()) break :result mcv; + + return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airUnwrapErrPayload(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: { - const err_ty = self.air.typeOf(ty_op.operand); - const payload_ty = err_ty.errorUnionPayload(); + const error_union_ty = self.air.typeOf(ty_op.operand); + const payload_ty = error_union_ty.errorUnionPayload(); if (!payload_ty.hasCodeGenBits()) break :result MCValue.none; return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); @@ -2411,19 +2418,26 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; - if (self.liveness.isUnused(inst)) - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - const ty = self.air.typeOf(bin_op.lhs); - assert(ty.eql(self.air.typeOf(bin_op.rhs))); - if (ty.zigTypeTag() == .ErrorSet) - return self.fail("TODO implement cmp for errors", .{}); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.air.typeOf(bin_op.lhs); - try self.spillCompareFlagsIfOccupied(); - self.compare_flags_inst = inst; + if (lhs_ty.abiSize(self.target.*) > 4) { + return self.fail("TODO cmp for types with size > 4", .{}); + } + + const signedness: std.builtin.Signedness = blk: { + // by default we tell the operand type is unsigned (i.e. bools and enum values) + if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned; + + // incase of an actual integer, we emit the correct signedness + break :blk lhs_ty.intInfo(self.target.*).signedness; + }; + + try self.spillCompareFlagsIfOccupied(); + self.compare_flags_inst = inst; - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - const result: MCValue = result: { const lhs_is_register = lhs == .register; const rhs_is_register = rhs == .register; // lhs should always be a register @@ -2457,11 +2471,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { // Move the operands to the newly allocated registers const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; if (lhs_mcv == .register and !lhs_is_register) { - try self.genSetReg(ty, lhs_mcv.register, lhs); + try self.genSetReg(lhs_ty, lhs_mcv.register, lhs); branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.lhs).?, lhs); } if (rhs_mcv == .register and !rhs_is_register) { - try self.genSetReg(ty, rhs_mcv.register, rhs); + try self.genSetReg(lhs_ty, rhs_mcv.register, rhs); branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs); } @@ -2469,9 +2483,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { // The signedness of the integer does not matter for the cmp instruction try self.genArmBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq, undefined); - break :result switch (ty.isSignedInt()) { - true => MCValue{ .compare_flags_signed = op }, - false => MCValue{ .compare_flags_unsigned = op }, + break :result switch (signedness) { + .signed => MCValue{ .compare_flags_signed = op }, + .unsigned => MCValue{ .compare_flags_unsigned = op }, }; }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); diff --git a/test/stage2/arm.zig b/test/stage2/arm.zig index 9739c0553a..e76847f58a 100644 --- a/test/stage2/arm.zig +++ b/test/stage2/arm.zig @@ -636,6 +636,35 @@ pub fn addCases(ctx: *TestContext) !void { , "Hello, World!\n", ); + + case.addCompareOutput( + \\pub fn main() void { + \\ foo() catch |err| { + \\ assert(err == error.Foo); + \\ assert(err != error.Bar); + \\ assert(err != error.Baz); + \\ }; + \\ bar() catch |err| { + \\ assert(err != error.Foo); + \\ assert(err == error.Bar); + \\ assert(err != error.Baz); + \\ }; + \\} + \\ + \\fn assert(ok: bool) void { + \\ if (!ok) unreachable; + \\} + \\ + \\fn foo() anyerror!void { + \\ return error.Foo; + \\} + \\ + \\fn bar() anyerror!void { + \\ return error.Bar; + \\} + , + "", + ); } { From a722e1fc0bcbae55c6a143ece9f20db8a3212818 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Sat, 1 Jan 2022 12:51:29 +0100 Subject: [PATCH 3/3] stage2 codegen: Add generateSymbol for optional stub --- src/arch/arm/CodeGen.zig | 13 +++++++------ src/codegen.zig | 8 ++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index d1c7c7ecf0..e90c0ad5e4 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -3180,17 +3180,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro // TODO optimize the register allocation const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{}); const src_reg = regs[0]; - const dst_reg = regs[2]; + const dst_reg = regs[1]; const len_reg = regs[2]; const count_reg = regs[3]; const tmp_reg = regs[4]; - // add src_reg, fp, #off - const src_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(off)) |x| x else { + // sub src_reg, fp, #off + const adj_src_offset = off + @intCast(u32, ty.abiSize(self.target.*)); + const src_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_src_offset)) |x| x else { return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); }; _ = try self.addInst(.{ - .tag = .add, + .tag = .sub, .cond = .al, .data = .{ .rr_op = .{ .rd = src_reg, @@ -3200,8 +3201,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro }); // sub dst_reg, fp, #stack_offset - const adj_stack_offset = stack_offset + @intCast(u32, ty.abiSize(self.target.*)); - const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_stack_offset)) |x| x else { + const adj_dst_offset = stack_offset + @intCast(u32, ty.abiSize(self.target.*)); + const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_dst_offset)) |x| x else { return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); }; _ = try self.addInst(.{ diff --git a/src/codegen.zig b/src/codegen.zig index fdbdb7d5c1..9de13ee657 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -400,6 +400,14 @@ pub fn generateSymbol( return Result{ .appended = {} }; }, + .Optional => { + // TODO generateSymbol for optionals + const target = bin_file.options.target; + const abi_size = try math.cast(usize, typed_value.ty.abiSize(target)); + try code.writer().writeByteNTimes(0xaa, abi_size); + + return Result{ .appended = {} }; + }, else => |t| { return Result{ .fail = try ErrorMsg.create(