diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 7765064634..e90c0ad5e4 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", .{}); @@ -2238,10 +2245,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 +2323,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 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 @@ -2448,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); } @@ -2460,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 }); @@ -3157,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, @@ -3177,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( diff --git a/test/stage2/arm.zig b/test/stage2/arm.zig index d8417e2f78..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; + \\} + , + "", + ); } { @@ -704,4 +733,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 + \\ + , + ); + } }