| ... | @@ -1098,7 +1098,14 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1098,7 +1098,14 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1098 | | 1098 | |
| 1099 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | 1099 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1100 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,20 +1651,31 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { | 1651 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1645 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1652 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1646 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 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 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | 1658 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1651 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 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 { | 1663 | |
| 1655 | _ = self; | 1664 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 1656 | _ = operand; | 1665 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 1657 | _ = ty; | 1666 | const mcv = try self.resolveInst(operand); |
| 1658 | _ = index; | 1667 | const struct_ty = self.air.typeOf(operand).childType(); |
| 1659 | return self.fail("TODO implement codegen struct_field_ptr", .{}); | 1668 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 1660 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); | 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 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 1681 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1754,10 +1772,16 @@ fn airFence(self: *Self) !void { | ... | @@ -1754,10 +1772,16 @@ fn airFence(self: *Self) !void { |
| 1754 | | 1772 | |
| 1755 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | 1773 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1756 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 1774 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1757 | const fn_ty = self.air.typeOf(pl_op.operand); | | |
| 1758 | const callee = pl_op.operand; | 1775 | const callee = pl_op.operand; |
| 1759 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 1776 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1760 | const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 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 | var info = try self.resolveCallingConventionValues(fn_ty); | 1786 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 1763 | defer info.deinit(self); | 1787 | defer info.deinit(self); |
| ... | @@ -1821,7 +1845,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1821,7 +1845,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1821 | return self.fail("TODO implement calling bitcasted functions", .{}); | 1845 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1822 | } | 1846 | } |
| 1823 | } else { | 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 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 1857 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 1827 | for (info.args) |mc_arg, arg_i| { | 1858 | for (info.args) |mc_arg, arg_i| { |
| ... | @@ -2008,12 +2039,23 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2008,12 +2039,23 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2008 | | 2039 | |
| 2009 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 2040 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2010 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2041 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 2042 | |
| 2011 | if (self.liveness.isUnused(inst)) | 2043 | if (self.liveness.isUnused(inst)) |
| 2012 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 2044 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 2045 | |
| 2013 | const ty = self.air.typeOf(bin_op.lhs); | 2046 | const ty = self.air.typeOf(bin_op.lhs); |
| 2014 | assert(ty.eql(self.air.typeOf(bin_op.rhs))); | 2047 | |
| 2015 | if (ty.zigTypeTag() == .ErrorSet) | 2048 | if (ty.abiSize(self.target.*) > 8) { |
| 2016 | return self.fail("TODO implement cmp for errors", .{}); | 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 | const lhs = try self.resolveInst(bin_op.lhs); | 2060 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2019 | const rhs = try self.resolveInst(bin_op.rhs); | 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,9 +2131,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2089 | else => unreachable, | 2131 | else => unreachable, |
| 2090 | } | 2132 | } |
| 2091 | | 2133 | |
| 2092 | break :result switch (ty.isSignedInt()) { | 2134 | break :result switch (signedness) { |
| 2093 | true => MCValue{ .compare_flags_signed = op }, | 2135 | .signed => MCValue{ .compare_flags_signed = op }, |
| 2094 | false => MCValue{ .compare_flags_unsigned = op }, | 2136 | .unsigned => MCValue{ .compare_flags_unsigned = op }, |
| 2095 | }; | 2137 | }; |
| 2096 | }; | 2138 | }; |
| 2097 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2139 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |