| ... | ... | @@ -1098,7 +1098,14 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1098 | 1098 | |
| 1099 | 1099 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1100 | 1100 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1101 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch}); |
| 1101 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1102 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 1103 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1104 | const mcv = try self.resolveInst(ty_op.operand); |
| 1105 | if (!payload_ty.hasRuntimeBits()) break :result mcv; |
| 1106 | |
| 1107 | return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); |
| 1108 | }; |
| 1102 | 1109 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1103 | 1110 | } |
| 1104 | 1111 | |
| ... | ... | @@ -1644,20 +1651,31 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | 1651 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1645 | 1652 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1646 | 1653 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1647 | | return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index); |
| 1654 | const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index); |
| 1655 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 1648 | 1656 | } |
| 1649 | 1657 | |
| 1650 | 1658 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1651 | 1659 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1652 | | return self.structFieldPtr(ty_op.operand, ty_op.ty, index); |
| 1660 | const result = try self.structFieldPtr(inst, ty_op.operand, index); |
| 1661 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1653 | 1662 | } |
| 1654 | | fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void { |
| 1655 | | _ = self; |
| 1656 | | _ = operand; |
| 1657 | | _ = ty; |
| 1658 | | _ = index; |
| 1659 | | return self.fail("TODO implement codegen struct_field_ptr", .{}); |
| 1660 | | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); |
| 1663 | |
| 1664 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 1665 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 1666 | const mcv = try self.resolveInst(operand); |
| 1667 | const struct_ty = self.air.typeOf(operand).childType(); |
| 1668 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 1669 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| 1670 | const struct_field_ty = struct_ty.structFieldType(index); |
| 1671 | const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); |
| 1672 | switch (mcv) { |
| 1673 | .ptr_stack_offset => |off| { |
| 1674 | break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size }; |
| 1675 | }, |
| 1676 | else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}), |
| 1677 | } |
| 1678 | }; |
| 1661 | 1679 | } |
| 1662 | 1680 | |
| 1663 | 1681 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1754,10 +1772,16 @@ fn airFence(self: *Self) !void { |
| 1754 | 1772 | |
| 1755 | 1773 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1756 | 1774 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1757 | | const fn_ty = self.air.typeOf(pl_op.operand); |
| 1758 | 1775 | const callee = pl_op.operand; |
| 1759 | 1776 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1760 | 1777 | const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| 1778 | const ty = self.air.typeOf(callee); |
| 1779 | |
| 1780 | const fn_ty = switch (ty.zigTypeTag()) { |
| 1781 | .Fn => ty, |
| 1782 | .Pointer => ty.childType(), |
| 1783 | else => unreachable, |
| 1784 | }; |
| 1761 | 1785 | |
| 1762 | 1786 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 1763 | 1787 | defer info.deinit(self); |
| ... | ... | @@ -1821,7 +1845,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1821 | 1845 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1822 | 1846 | } |
| 1823 | 1847 | } else { |
| 1824 | | return self.fail("TODO implement calling runtime known function pointer", .{}); |
| 1848 | assert(ty.zigTypeTag() == .Pointer); |
| 1849 | const mcv = try self.resolveInst(callee); |
| 1850 | try self.genSetReg(Type.initTag(.usize), .x30, mcv); |
| 1851 | |
| 1852 | _ = try self.addInst(.{ |
| 1853 | .tag = .blr, |
| 1854 | .data = .{ .reg = .x30 }, |
| 1855 | }); |
| 1825 | 1856 | } |
| 1826 | 1857 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 1827 | 1858 | for (info.args) |mc_arg, arg_i| { |
| ... | ... | @@ -2008,12 +2039,23 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2008 | 2039 | |
| 2009 | 2040 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2010 | 2041 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2042 | |
| 2011 | 2043 | if (self.liveness.isUnused(inst)) |
| 2012 | 2044 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2045 | |
| 2013 | 2046 | const ty = self.air.typeOf(bin_op.lhs); |
| 2014 | | assert(ty.eql(self.air.typeOf(bin_op.rhs))); |
| 2015 | | if (ty.zigTypeTag() == .ErrorSet) |
| 2016 | | return self.fail("TODO implement cmp for errors", .{}); |
| 2047 | |
| 2048 | if (ty.abiSize(self.target.*) > 8) { |
| 2049 | return self.fail("TODO cmp for types with size > 8", .{}); |
| 2050 | } |
| 2051 | |
| 2052 | const signedness: std.builtin.Signedness = blk: { |
| 2053 | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 2054 | if (ty.zigTypeTag() != .Int) break :blk .unsigned; |
| 2055 | |
| 2056 | // incase of an actual integer, we emit the correct signedness |
| 2057 | break :blk ty.intInfo(self.target.*).signedness; |
| 2058 | }; |
| 2017 | 2059 | |
| 2018 | 2060 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2019 | 2061 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -2089,9 +2131,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2089 | 2131 | else => unreachable, |
| 2090 | 2132 | } |
| 2091 | 2133 | |
| 2092 | | break :result switch (ty.isSignedInt()) { |
| 2093 | | true => MCValue{ .compare_flags_signed = op }, |
| 2094 | | false => MCValue{ .compare_flags_unsigned = op }, |
| 2134 | break :result switch (signedness) { |
| 2135 | .signed => MCValue{ .compare_flags_signed = op }, |
| 2136 | .unsigned => MCValue{ .compare_flags_unsigned = op }, |
| 2095 | 2137 | }; |
| 2096 | 2138 | }; |
| 2097 | 2139 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |