| ... | ... | @@ -141,7 +141,7 @@ pub fn deinit(self: *FuncGen) void { |
| 141 | 141 | self.switch_dispatch_info.deinit(gpa); |
| 142 | 142 | } |
| 143 | 143 | |
| 144 | | fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !Builder.Value { |
| 144 | fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) Allocator.Error!Builder.Value { |
| 145 | 145 | const gpa = self.gpa; |
| 146 | 146 | const gop = try self.func_inst_table.getOrPut(gpa, inst); |
| 147 | 147 | if (gop.found_existing) return gop.value_ptr.*; |
| ... | ... | @@ -151,7 +151,7 @@ fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !Builder.Value { |
| 151 | 151 | return llvm_val.toValue(); |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | | fn resolveValue(self: *FuncGen, val: Value) Error!Builder.Constant { |
| 154 | fn resolveValue(self: *FuncGen, val: Value) Allocator.Error!Builder.Constant { |
| 155 | 155 | const o = self.object; |
| 156 | 156 | const pt = self.pt; |
| 157 | 157 | const zcu = pt.zcu; |
| ... | ... | @@ -177,9 +177,7 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air |
| 177 | 177 | .poi => if (self.fuzz) |*fuzz| { |
| 178 | 178 | const poi_index = fuzz.pcs.items.len; |
| 179 | 179 | const base_ptr = fuzz.counters_variable.toValue(&o.builder); |
| 180 | | const ptr = if (poi_index == 0) base_ptr else try self.wip.gep(.inbounds, .i8, base_ptr, &.{ |
| 181 | | try o.builder.intValue(.i32, poi_index), |
| 182 | | }, ""); |
| 180 | const ptr = try self.ptraddConst(base_ptr, poi_index); |
| 183 | 181 | const one = try o.builder.intValue(.i8, 1); |
| 184 | 182 | _ = try self.wip.atomicrmw(.normal, .add, ptr, one, self.sync_scope, .monotonic, .default, ""); |
| 185 | 183 | |
| ... | ... | @@ -704,8 +702,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 704 | 702 | const llvm_ty = try o.builder.structType(.normal, llvm_types); |
| 705 | 703 | try llvm_args.ensureUnusedCapacity(it.types_len); |
| 706 | 704 | for (llvm_types, 0..) |field_ty, i| { |
| 707 | | const alignment = |
| 708 | | Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); |
| 705 | const alignment: Builder.Alignment = .fromByteUnits(@divExact(target.ptrBitWidth(), 8)); |
| 709 | 706 | const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, ""); |
| 710 | 707 | const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, ""); |
| 711 | 708 | llvm_args.appendAssumeCapacity(loaded); |
| ... | ... | @@ -1153,10 +1150,8 @@ fn cmp( |
| 1153 | 1150 | } |
| 1154 | 1151 | // We need to emit instructions to check for equality/inequality |
| 1155 | 1152 | // of optionals that are not pointers. |
| 1156 | | const is_by_ref = isByRef(scalar_ty, zcu); |
| 1157 | | const opt_llvm_ty = try o.lowerType(pt, scalar_ty); |
| 1158 | | const lhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, lhs, is_by_ref, .normal); |
| 1159 | | const rhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, rhs, is_by_ref, .normal); |
| 1153 | const lhs_non_null = try self.optCmpNull(.ne, scalar_ty, lhs, .normal); |
| 1154 | const rhs_non_null = try self.optCmpNull(.ne, scalar_ty, rhs, .normal); |
| 1160 | 1155 | const llvm_i2 = try o.builder.intType(2); |
| 1161 | 1156 | const lhs_non_null_i2 = try self.wip.cast(.zext, lhs_non_null, llvm_i2, ""); |
| 1162 | 1157 | const rhs_non_null_i2 = try self.wip.cast(.zext, rhs_non_null, llvm_i2, ""); |
| ... | ... | @@ -1186,8 +1181,8 @@ fn cmp( |
| 1186 | 1181 | _ = try self.wip.br(end_block); |
| 1187 | 1182 | |
| 1188 | 1183 | self.wip.cursor = .{ .block = both_pl_block }; |
| 1189 | | const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true); |
| 1190 | | const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true); |
| 1184 | const lhs_payload = try self.optPayloadHandle(lhs, scalar_ty, true); |
| 1185 | const rhs_payload = try self.optPayloadHandle(rhs, scalar_ty, true); |
| 1191 | 1186 | const payload_cmp = try self.cmp(fast, op, payload_ty, lhs_payload, rhs_payload); |
| 1192 | 1187 | _ = try self.wip.br(end_block); |
| 1193 | 1188 | const both_pl_block_end = self.wip.cursor.block; |
| ... | ... | @@ -1392,12 +1387,10 @@ fn lowerSwitchDispatch( |
| 1392 | 1387 | try o.lowerType(pt, .usize), |
| 1393 | 1388 | "", |
| 1394 | 1389 | ); |
| 1395 | | const target_ptr_ptr = try self.wip.gep( |
| 1396 | | .inbounds, |
| 1397 | | .ptr, |
| 1390 | const target_ptr_ptr = try self.ptraddScaled( |
| 1398 | 1391 | jmp_table.table.toValue(), |
| 1399 | | &.{table_index}, |
| 1400 | | "", |
| 1392 | table_index, |
| 1393 | Type.usize.abiSize(zcu), |
| 1401 | 1394 | ); |
| 1402 | 1395 | const target_ptr = try self.wip.load(.normal, .ptr, target_ptr_ptr, .default, ""); |
| 1403 | 1396 | |
| ... | ... | @@ -1580,7 +1573,7 @@ fn airTry(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value { |
| 1580 | 1573 | const body = unwrapped_try.else_body; |
| 1581 | 1574 | const err_union_ty = self.typeOf(unwrapped_try.error_union); |
| 1582 | 1575 | const is_unused = self.liveness.isUnused(inst); |
| 1583 | | return lowerTry(self, err_union, body, err_union_ty, false, .none, false, is_unused, err_cold); |
| 1576 | return lowerTry(self, err_union, body, err_union_ty, false, .none, is_unused, err_cold); |
| 1584 | 1577 | } |
| 1585 | 1578 | |
| 1586 | 1579 | fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value { |
| ... | ... | @@ -1594,7 +1587,7 @@ fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Valu |
| 1594 | 1587 | |
| 1595 | 1588 | self.maybeMarkAllowZeroAccess(self.typeOf(unwrapped_try.error_union_ptr).ptrInfo(zcu)); |
| 1596 | 1589 | |
| 1597 | | return lowerTry(self, err_union_ptr, body, err_union_ty, true, err_union_ptr_ty.ptrAlignment(zcu), true, is_unused, err_cold); |
| 1590 | return lowerTry(self, err_union_ptr, body, err_union_ty, true, err_union_ptr_ty.ptrAlignment(zcu), is_unused, err_cold); |
| 1598 | 1591 | } |
| 1599 | 1592 | |
| 1600 | 1593 | fn lowerTry( |
| ... | ... | @@ -1604,7 +1597,6 @@ fn lowerTry( |
| 1604 | 1597 | err_union_ty: Type, |
| 1605 | 1598 | operand_is_ptr: bool, |
| 1606 | 1599 | operand_ptr_align: InternPool.Alignment, |
| 1607 | | can_elide_load: bool, |
| 1608 | 1600 | is_unused: bool, |
| 1609 | 1601 | err_cold: bool, |
| 1610 | 1602 | ) !Builder.Value { |
| ... | ... | @@ -1613,7 +1605,6 @@ fn lowerTry( |
| 1613 | 1605 | const zcu = pt.zcu; |
| 1614 | 1606 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 1615 | 1607 | const payload_has_bits = payload_ty.hasRuntimeBits(zcu); |
| 1616 | | const err_union_llvm_ty = try o.lowerType(pt, err_union_ty); |
| 1617 | 1608 | const error_type = try o.errorIntType(pt); |
| 1618 | 1609 | |
| 1619 | 1610 | const err_set_align: InternPool.Alignment, const payload_align: InternPool.Alignment = if (operand_is_ptr) .{ |
| ... | ... | @@ -1632,19 +1623,17 @@ fn lowerTry( |
| 1632 | 1623 | else |
| 1633 | 1624 | err_union; |
| 1634 | 1625 | } |
| 1635 | | const err_field_index = try errUnionErrorFieldIndex(payload_ty, pt); |
| 1636 | | if (operand_is_ptr or isByRef(err_union_ty, zcu)) { |
| 1637 | | const err_field_ptr = |
| 1638 | | try fg.wip.gepStruct(err_union_llvm_ty, err_union, err_field_index, ""); |
| 1639 | | break :loaded try fg.wip.load( |
| 1640 | | if (operand_is_ptr) access_kind else .normal, |
| 1641 | | error_type, |
| 1642 | | err_field_ptr, |
| 1643 | | err_set_align.toLlvm(), |
| 1644 | | "", |
| 1645 | | ); |
| 1646 | | } |
| 1647 | | break :loaded try fg.wip.extractValue(err_union, &.{err_field_index}, ""); |
| 1626 | |
| 1627 | assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload has no bits |
| 1628 | const offset = codegen.errUnionErrorOffset(payload_ty, zcu); |
| 1629 | const err_field_ptr = try fg.ptraddConst(err_union, offset); |
| 1630 | break :loaded try fg.wip.load( |
| 1631 | if (operand_is_ptr) access_kind else .normal, |
| 1632 | error_type, |
| 1633 | err_field_ptr, |
| 1634 | err_set_align.toLlvm(), |
| 1635 | "", |
| 1636 | ); |
| 1648 | 1637 | }; |
| 1649 | 1638 | const zero = try o.builder.intValue(error_type, 0); |
| 1650 | 1639 | const is_err = try fg.wip.icmp(.ne, loaded, zero, ""); |
| ... | ... | @@ -1661,21 +1650,15 @@ fn lowerTry( |
| 1661 | 1650 | } |
| 1662 | 1651 | if (is_unused) return .none; |
| 1663 | 1652 | if (!payload_has_bits) return if (operand_is_ptr) err_union else .none; |
| 1664 | | const offset = try errUnionPayloadFieldIndex(payload_ty, pt); |
| 1653 | assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload has no bits |
| 1654 | const payload_ptr = try fg.ptraddConst(err_union, codegen.errUnionPayloadOffset(payload_ty, zcu)); |
| 1665 | 1655 | if (operand_is_ptr) { |
| 1666 | | return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); |
| 1667 | | } else if (isByRef(err_union_ty, zcu)) { |
| 1668 | | const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); |
| 1669 | | if (isByRef(payload_ty, zcu)) { |
| 1670 | | if (can_elide_load) |
| 1671 | | return payload_ptr; |
| 1672 | | |
| 1673 | | return fg.loadByRef(payload_ptr, payload_ty, payload_align.toLlvm(), .normal); |
| 1674 | | } |
| 1675 | | const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; |
| 1676 | | return fg.wip.load(.normal, load_ty, payload_ptr, payload_align.toLlvm(), ""); |
| 1656 | return payload_ptr; |
| 1657 | } else if (isByRef(payload_ty, zcu)) { |
| 1658 | return fg.loadByRef(payload_ptr, payload_ty, payload_align.toLlvm(), .normal); |
| 1659 | } else { |
| 1660 | return fg.wip.load(.normal, try o.lowerType(pt, payload_ty), payload_ptr, payload_align.toLlvm(), ""); |
| 1677 | 1661 | } |
| 1678 | | return fg.wip.extractValue(err_union, &.{offset}, ""); |
| 1679 | 1662 | } |
| 1680 | 1663 | |
| 1681 | 1664 | fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) !void { |
| ... | ... | @@ -1950,12 +1933,7 @@ fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 1950 | 1933 | const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(zcu)); |
| 1951 | 1934 | const slice_llvm_ty = try o.lowerType(pt, self.typeOfIndex(inst)); |
| 1952 | 1935 | const operand = try self.resolveInst(ty_op.operand); |
| 1953 | | if (!array_ty.hasRuntimeBits(zcu)) |
| 1954 | | return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, ""); |
| 1955 | | const ptr = try self.wip.gep(.inbounds, try o.lowerType(pt, array_ty), operand, &.{ |
| 1956 | | try o.builder.intValue(llvm_usize, 0), try o.builder.intValue(llvm_usize, 0), |
| 1957 | | }, ""); |
| 1958 | | return self.wip.buildAggregate(slice_llvm_ty, &.{ ptr, len }, ""); |
| 1936 | return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, ""); |
| 1959 | 1937 | } |
| 1960 | 1938 | |
| 1961 | 1939 | fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -2126,20 +2104,14 @@ fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: u32) !Builder.Valu |
| 2126 | 2104 | return self.wip.extractValue(operand, &.{index}, ""); |
| 2127 | 2105 | } |
| 2128 | 2106 | |
| 2129 | | fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !Builder.Value { |
| 2130 | | const o = self.object; |
| 2131 | | const pt = self.pt; |
| 2132 | | const zcu = pt.zcu; |
| 2107 | fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: u1) !Builder.Value { |
| 2108 | const zcu = self.pt.zcu; |
| 2133 | 2109 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2134 | 2110 | const slice_ptr = try self.resolveInst(ty_op.operand); |
| 2135 | | const slice_ptr_ty = self.typeOf(ty_op.operand); |
| 2136 | | const slice_llvm_ty = try o.lowerType(pt, slice_ptr_ty.childType(zcu)); |
| 2137 | | |
| 2138 | | return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, ""); |
| 2111 | return self.ptraddConst(slice_ptr, index * Type.usize.abiSize(zcu)); |
| 2139 | 2112 | } |
| 2140 | 2113 | |
| 2141 | 2114 | fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2142 | | const o = self.object; |
| 2143 | 2115 | const pt = self.pt; |
| 2144 | 2116 | const zcu = pt.zcu; |
| 2145 | 2117 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -2149,9 +2121,8 @@ fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2149 | 2121 | const slice_info = slice_ty.ptrInfo(zcu); |
| 2150 | 2122 | assert(slice_info.flags.size == .slice); |
| 2151 | 2123 | const elem_ty: Type = .fromInterned(slice_info.child); |
| 2152 | | const llvm_elem_ty = try o.lowerType(pt, elem_ty); |
| 2153 | 2124 | const base_ptr = try self.wip.extractValue(slice, &.{0}, ""); |
| 2154 | | const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, ""); |
| 2125 | const ptr = try self.ptraddScaled(base_ptr, index, elem_ty.abiSize(zcu)); |
| 2155 | 2126 | const elem_align = slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu)); |
| 2156 | 2127 | const access_kind: Builder.MemoryAccessKind = if (slice_info.flags.is_volatile) .@"volatile" else .normal; |
| 2157 | 2128 | self.maybeMarkAllowZeroAccess(slice_info); |
| ... | ... | @@ -2163,7 +2134,6 @@ fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2163 | 2134 | } |
| 2164 | 2135 | |
| 2165 | 2136 | fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2166 | | const o = self.object; |
| 2167 | 2137 | const pt = self.pt; |
| 2168 | 2138 | const zcu = pt.zcu; |
| 2169 | 2139 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -2172,13 +2142,11 @@ fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2172 | 2142 | |
| 2173 | 2143 | const slice = try self.resolveInst(bin_op.lhs); |
| 2174 | 2144 | const index = try self.resolveInst(bin_op.rhs); |
| 2175 | | const llvm_elem_ty = try o.lowerType(pt, slice_ty.childType(zcu)); |
| 2176 | 2145 | const base_ptr = try self.wip.extractValue(slice, &.{0}, ""); |
| 2177 | | return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, ""); |
| 2146 | return self.ptraddScaled(base_ptr, index, slice_ty.childType(zcu).abiSize(zcu)); |
| 2178 | 2147 | } |
| 2179 | 2148 | |
| 2180 | 2149 | fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2181 | | const o = self.object; |
| 2182 | 2150 | const pt = self.pt; |
| 2183 | 2151 | const zcu = pt.zcu; |
| 2184 | 2152 | |
| ... | ... | @@ -2186,16 +2154,12 @@ fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2186 | 2154 | const array_ty = self.typeOf(bin_op.lhs); |
| 2187 | 2155 | const array_llvm_val = try self.resolveInst(bin_op.lhs); |
| 2188 | 2156 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2189 | | const array_llvm_ty = try o.lowerType(pt, array_ty); |
| 2190 | 2157 | const elem_ty = array_ty.childType(zcu); |
| 2191 | 2158 | if (isByRef(array_ty, zcu)) { |
| 2192 | | const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &.{ |
| 2193 | | try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), |
| 2194 | | rhs, |
| 2195 | | }, ""); |
| 2159 | const elem_ptr = try self.ptraddScaled(array_llvm_val, rhs, elem_ty.abiSize(zcu)); |
| 2196 | 2160 | if (isByRef(elem_ty, zcu)) { |
| 2197 | | const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); |
| 2198 | | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 2161 | const elem_align = elem_ty.abiAlignment(zcu).toLlvm(); |
| 2162 | return self.loadByRef(elem_ptr, elem_ty, elem_align, .normal); |
| 2199 | 2163 | } else { |
| 2200 | 2164 | return self.loadTruncate(.normal, elem_ty, elem_ptr, .default); |
| 2201 | 2165 | } |
| ... | ... | @@ -2206,16 +2170,14 @@ fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2206 | 2170 | } |
| 2207 | 2171 | |
| 2208 | 2172 | fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2209 | | const o = self.object; |
| 2210 | 2173 | const pt = self.pt; |
| 2211 | 2174 | const zcu = pt.zcu; |
| 2212 | 2175 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2213 | 2176 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2214 | 2177 | const elem_ty = ptr_ty.indexableElem(zcu); |
| 2215 | | const llvm_elem_ty = try o.lowerType(pt, elem_ty); |
| 2216 | 2178 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 2217 | 2179 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2218 | | const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{rhs}, ""); |
| 2180 | const ptr = try self.ptraddScaled(base_ptr, rhs, elem_ty.abiSize(zcu)); |
| 2219 | 2181 | if (isByRef(elem_ty, zcu)) { |
| 2220 | 2182 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| 2221 | 2183 | const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); |
| ... | ... | @@ -2228,7 +2190,6 @@ fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2228 | 2190 | } |
| 2229 | 2191 | |
| 2230 | 2192 | fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2231 | | const o = self.object; |
| 2232 | 2193 | const pt = self.pt; |
| 2233 | 2194 | const zcu = pt.zcu; |
| 2234 | 2195 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -2243,8 +2204,7 @@ fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2243 | 2204 | const elem_ptr = ty_pl.ty.toType(); |
| 2244 | 2205 | if (elem_ptr.ptrInfo(zcu).flags.vector_index != .none) return base_ptr; |
| 2245 | 2206 | |
| 2246 | | const llvm_elem_ty = try o.lowerType(pt, elem_ty); |
| 2247 | | return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{rhs}, ""); |
| 2207 | return self.ptraddScaled(base_ptr, rhs, elem_ty.abiSize(zcu)); |
| 2248 | 2208 | } |
| 2249 | 2209 | |
| 2250 | 2210 | fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -2276,86 +2236,59 @@ fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 2276 | 2236 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); |
| 2277 | 2237 | const field_index = struct_field.field_index; |
| 2278 | 2238 | const field_ty = struct_ty.fieldType(field_index, zcu); |
| 2279 | | if (!field_ty.hasRuntimeBits(zcu)) return .none; |
| 2239 | assert(field_ty.hasRuntimeBits(zcu)); |
| 2280 | 2240 | |
| 2281 | 2241 | if (!isByRef(struct_ty, zcu)) { |
| 2242 | // All auto/extern struct/union types are by-ref, unless they have no runtime bits, in which |
| 2243 | // case we shouldn't be seeing this instruction to begin with. Therefore we must be dealing |
| 2244 | // with a `packed struct` or `packed union`. |
| 2245 | assert(struct_ty.containerLayout(zcu) == .@"packed"); |
| 2282 | 2246 | assert(!isByRef(field_ty, zcu)); |
| 2283 | | switch (struct_ty.zigTypeTag(zcu)) { |
| 2284 | | .@"struct" => switch (struct_ty.containerLayout(zcu)) { |
| 2285 | | .@"packed" => { |
| 2286 | | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 2287 | | const bit_offset = zcu.structPackedFieldBitOffset(struct_type, field_index); |
| 2288 | | const containing_int = struct_llvm_val; |
| 2289 | | const shift_amt = |
| 2290 | | try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset); |
| 2291 | | const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, ""); |
| 2292 | | const elem_llvm_ty = try o.lowerType(pt, field_ty); |
| 2293 | | if (field_ty.zigTypeTag(zcu) == .float or field_ty.zigTypeTag(zcu) == .vector) { |
| 2294 | | const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); |
| 2295 | | const truncated_int = |
| 2296 | | try self.wip.cast(.trunc, shifted_value, same_size_int, ""); |
| 2297 | | return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, ""); |
| 2298 | | } |
| 2299 | | return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, ""); |
| 2300 | | }, |
| 2301 | | else => { |
| 2302 | | const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?; |
| 2303 | | return self.wip.extractValue(struct_llvm_val, &.{llvm_field_index}, ""); |
| 2304 | | }, |
| 2305 | | }, |
| 2306 | | .@"union" => { |
| 2307 | | assert(struct_ty.containerLayout(zcu) == .@"packed"); |
| 2308 | | const containing_int = struct_llvm_val; |
| 2309 | | const elem_llvm_ty = try o.lowerType(pt, field_ty); |
| 2310 | | if (field_ty.zigTypeTag(zcu) == .float or field_ty.zigTypeTag(zcu) == .vector) { |
| 2311 | | const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); |
| 2312 | | const truncated_int = |
| 2313 | | try self.wip.cast(.trunc, containing_int, same_size_int, ""); |
| 2314 | | return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, ""); |
| 2315 | | } |
| 2316 | | return self.wip.cast(.trunc, containing_int, elem_llvm_ty, ""); |
| 2247 | const field_int_val: Builder.Value = switch (struct_ty.zigTypeTag(zcu)) { |
| 2248 | .@"struct" => field_int_val: { |
| 2249 | const llvm_field_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(zcu))); |
| 2250 | const bit_offset = zcu.structPackedFieldBitOffset( |
| 2251 | zcu.intern_pool.loadStructType(struct_ty.toIntern()), |
| 2252 | field_index, |
| 2253 | ); |
| 2254 | const shift_bits = try o.builder.intValue(struct_llvm_val.typeOfWip(&self.wip), bit_offset); |
| 2255 | const shifted = try self.wip.bin(.lshr, struct_llvm_val, shift_bits, ""); |
| 2256 | break :field_int_val try self.wip.cast(.trunc, shifted, llvm_field_int_ty, ""); |
| 2317 | 2257 | }, |
| 2258 | .@"union" => struct_llvm_val, |
| 2318 | 2259 | else => unreachable, |
| 2260 | }; |
| 2261 | switch (field_ty.zigTypeTag(zcu)) { |
| 2262 | else => unreachable, // not packable |
| 2263 | .void => unreachable, // opv bug in sema |
| 2264 | .int, .bool, .@"enum", .@"struct", .@"union" => { |
| 2265 | // Represented as integers, so already done |
| 2266 | return field_int_val; |
| 2267 | }, |
| 2268 | .float => { |
| 2269 | // bitcast int->float |
| 2270 | return self.wip.cast(.bitcast, field_int_val, try o.lowerType(pt, field_ty), ""); |
| 2271 | }, |
| 2319 | 2272 | } |
| 2320 | 2273 | } |
| 2321 | 2274 | |
| 2322 | | switch (struct_ty.zigTypeTag(zcu)) { |
| 2323 | | .@"struct" => { |
| 2324 | | const layout = struct_ty.containerLayout(zcu); |
| 2325 | | assert(layout != .@"packed"); |
| 2326 | | const struct_llvm_ty = try o.lowerType(pt, struct_ty); |
| 2327 | | const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?; |
| 2328 | | const field_ptr = |
| 2329 | | try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field_index, ""); |
| 2330 | | const explicit_alignment = struct_ty.explicitFieldAlignment(field_index, zcu); |
| 2331 | | const field_ptr_ty = try pt.ptrType(.{ |
| 2332 | | .child = field_ty.toIntern(), |
| 2333 | | .flags = .{ .alignment = explicit_alignment }, |
| 2334 | | }); |
| 2335 | | if (isByRef(field_ty, zcu)) { |
| 2336 | | const alignment = switch (explicit_alignment) { |
| 2337 | | .none => field_ty.abiAlignment(zcu), |
| 2338 | | else => |a| a, |
| 2339 | | }; |
| 2340 | | return self.loadByRef(field_ptr, field_ty, alignment.toLlvm(), .normal); |
| 2341 | | } else { |
| 2342 | | return self.load(field_ptr, field_ptr_ty); |
| 2343 | | } |
| 2344 | | }, |
| 2345 | | .@"union" => { |
| 2346 | | const union_llvm_ty = try o.lowerType(pt, struct_ty); |
| 2347 | | const layout = struct_ty.unionGetLayout(zcu); |
| 2348 | | const payload_index = @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)); |
| 2349 | | const field_ptr = |
| 2350 | | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 2351 | | const payload_alignment = layout.payload_align.toLlvm(); |
| 2352 | | if (isByRef(field_ty, zcu)) { |
| 2353 | | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| 2354 | | } else { |
| 2355 | | return self.loadTruncate(.normal, field_ty, field_ptr, payload_alignment); |
| 2356 | | } |
| 2357 | | }, |
| 2275 | const offset: u64 = switch (struct_ty.zigTypeTag(zcu)) { |
| 2276 | .@"struct" => struct_ty.structFieldOffset(field_index, zcu), |
| 2277 | .@"union" => struct_ty.unionGetLayout(zcu).payloadOffset(), |
| 2358 | 2278 | else => unreachable, |
| 2279 | }; |
| 2280 | |
| 2281 | const struct_ptr_align = struct_ty.abiAlignment(zcu); |
| 2282 | const field_ptr = try self.ptraddConst(struct_llvm_val, offset); |
| 2283 | const field_ptr_align: InternPool.Alignment = switch (offset) { |
| 2284 | 0 => struct_ptr_align, |
| 2285 | else => struct_ptr_align.minStrict(.fromLog2Units(@ctz(offset))), |
| 2286 | }; |
| 2287 | |
| 2288 | if (isByRef(field_ty, zcu)) { |
| 2289 | return self.loadByRef(field_ptr, field_ty, field_ptr_align.toLlvm(), .normal); |
| 2290 | } else { |
| 2291 | return self.loadTruncate(.normal, field_ty, field_ptr, field_ptr_align.toLlvm()); |
| 2359 | 2292 | } |
| 2360 | 2293 | } |
| 2361 | 2294 | |
| ... | ... | @@ -2964,8 +2897,7 @@ fn airIsNonNull( |
| 2964 | 2897 | return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), ""); |
| 2965 | 2898 | } |
| 2966 | 2899 | |
| 2967 | | const is_by_ref = operand_is_ptr or isByRef(optional_ty, zcu); |
| 2968 | | return self.optCmpNull(cond, optional_llvm_ty, operand, is_by_ref, access_kind); |
| 2900 | return self.optCmpNull(cond, optional_ty, operand, access_kind); |
| 2969 | 2901 | } |
| 2970 | 2902 | |
| 2971 | 2903 | fn airIsErr( |
| ... | ... | @@ -3006,40 +2938,23 @@ fn airIsErr( |
| 3006 | 2938 | operand; |
| 3007 | 2939 | return self.wip.icmp(cond, loaded, zero, ""); |
| 3008 | 2940 | } |
| 2941 | assert(isByRef(err_union_ty, zcu)); // error unions with runtime bits are always by-ref |
| 3009 | 2942 | |
| 3010 | | const err_field_index = try errUnionErrorFieldIndex(payload_ty, pt); |
| 3011 | | |
| 3012 | | const loaded = if (operand_is_ptr or isByRef(err_union_ty, zcu)) loaded: { |
| 3013 | | const err_union_llvm_ty = try o.lowerType(pt, err_union_ty); |
| 3014 | | const err_alignment = if (operand_is_ptr) |
| 3015 | | operand_ty.ptrAlignment(zcu).minStrict(Type.anyerror.abiAlignment(zcu)) |
| 3016 | | else |
| 3017 | | .none; |
| 3018 | | const err_field_ptr = |
| 3019 | | try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, ""); |
| 3020 | | break :loaded try self.wip.load(access_kind, error_type, err_field_ptr, err_alignment.toLlvm(), ""); |
| 3021 | | } else try self.wip.extractValue(operand, &.{err_field_index}, ""); |
| 2943 | const err_align = if (operand_is_ptr) |
| 2944 | operand_ty.ptrAlignment(zcu).minStrict(Type.anyerror.abiAlignment(zcu)) |
| 2945 | else |
| 2946 | .none; |
| 2947 | const err_field_ptr = try self.ptraddConst(operand, codegen.errUnionErrorOffset(payload_ty, zcu)); |
| 2948 | const loaded = try self.wip.load(access_kind, error_type, err_field_ptr, err_align.toLlvm(), ""); |
| 3022 | 2949 | return self.wip.icmp(cond, loaded, zero, ""); |
| 3023 | 2950 | } |
| 3024 | 2951 | |
| 3025 | | fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3026 | | const o = self.object; |
| 3027 | | const pt = self.pt; |
| 3028 | | const zcu = pt.zcu; |
| 2952 | fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { |
| 3029 | 2953 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3030 | 2954 | const operand = try self.resolveInst(ty_op.operand); |
| 3031 | | const optional_ty = self.typeOf(ty_op.operand).childType(zcu); |
| 3032 | | const payload_ty = optional_ty.optionalChild(zcu); |
| 3033 | | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 3034 | | // We have a pointer to a zero-bit value and we need to return |
| 3035 | | // a pointer to a zero-bit value. |
| 3036 | | return operand; |
| 3037 | | } |
| 3038 | | if (optional_ty.optionalReprIsPayload(zcu)) { |
| 3039 | | // The payload and the optional are the same value. |
| 3040 | | return operand; |
| 3041 | | } |
| 3042 | | return self.wip.gepStruct(try o.lowerType(pt, optional_ty), operand, 0, ""); |
| 2955 | // If `Type.optionalReprIsPayload`, then the address should be the same. Otherwise, optional |
| 2956 | // layouts always put the payload at offset 0, so... the address should still be the same. |
| 2957 | return operand; |
| 3043 | 2958 | } |
| 3044 | 2959 | |
| 3045 | 2960 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3072,9 +2987,9 @@ fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value |
| 3072 | 2987 | return operand; |
| 3073 | 2988 | } |
| 3074 | 2989 | |
| 3075 | | // First set the non-null bit. |
| 3076 | | const optional_llvm_ty = try o.lowerType(pt, optional_ty); |
| 3077 | | const non_null_ptr = try self.wip.gepStruct(optional_llvm_ty, operand, 1, ""); |
| 2990 | // First set the non-null bit. It's always immediately after the payload (no padding) because it |
| 2991 | // has alignment 1. |
| 2992 | const non_null_ptr = try self.ptraddConst(operand, payload_ty.abiSize(zcu)); |
| 3078 | 2993 | |
| 3079 | 2994 | self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu)); |
| 3080 | 2995 | |
| ... | ... | @@ -3084,11 +2999,10 @@ fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value |
| 3084 | 2999 | // Then return the payload pointer (only if it's used). |
| 3085 | 3000 | if (self.liveness.isUnused(inst)) return .none; |
| 3086 | 3001 | |
| 3087 | | return self.wip.gepStruct(optional_llvm_ty, operand, 0, ""); |
| 3002 | return operand; // payload is at offset 0 |
| 3088 | 3003 | } |
| 3089 | 3004 | |
| 3090 | 3005 | fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3091 | | const o = self.object; |
| 3092 | 3006 | const pt = self.pt; |
| 3093 | 3007 | const zcu = pt.zcu; |
| 3094 | 3008 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -3102,8 +3016,7 @@ fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3102 | 3016 | return operand; |
| 3103 | 3017 | } |
| 3104 | 3018 | |
| 3105 | | const opt_llvm_ty = try o.lowerType(pt, optional_ty); |
| 3106 | | return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, false); |
| 3019 | return self.optPayloadHandle(operand, optional_ty, false); |
| 3107 | 3020 | } |
| 3108 | 3021 | |
| 3109 | 3022 | fn airErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index, operand_is_ptr: bool) !Builder.Value { |
| ... | ... | @@ -3120,20 +3033,18 @@ fn airErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index, operand_is_ptr: bool |
| 3120 | 3033 | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 3121 | 3034 | return if (operand_is_ptr) operand else .none; |
| 3122 | 3035 | } |
| 3123 | | const offset = try errUnionPayloadFieldIndex(payload_ty, pt); |
| 3124 | | const err_union_llvm_ty = try o.lowerType(pt, err_union_ty); |
| 3036 | const payload_ptr = try self.ptraddConst(operand, codegen.errUnionPayloadOffset(payload_ty, zcu)); |
| 3125 | 3037 | if (operand_is_ptr) { |
| 3126 | | return self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 3127 | | } else if (isByRef(err_union_ty, zcu)) { |
| 3128 | | const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm(); |
| 3129 | | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 3130 | | if (isByRef(payload_ty, zcu)) { |
| 3131 | | return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 3132 | | } |
| 3133 | | const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; |
| 3038 | return payload_ptr; |
| 3039 | } |
| 3040 | assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload lacks runtime bits |
| 3041 | const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm(); |
| 3042 | if (isByRef(payload_ty, zcu)) { |
| 3043 | return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 3044 | } else { |
| 3045 | const payload_llvm_ty = try o.lowerType(pt, payload_ty); |
| 3134 | 3046 | return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); |
| 3135 | 3047 | } |
| 3136 | | return self.wip.extractValue(operand, &.{offset}, ""); |
| 3137 | 3048 | } |
| 3138 | 3049 | |
| 3139 | 3050 | fn airErrUnionErr( |
| ... | ... | @@ -3169,17 +3080,18 @@ fn airErrUnionErr( |
| 3169 | 3080 | return self.wip.load(access_kind, error_type, operand, operand_ty.ptrAlignment(zcu).toLlvm(), ""); |
| 3170 | 3081 | } |
| 3171 | 3082 | |
| 3172 | | const offset = try errUnionErrorFieldIndex(payload_ty, pt); |
| 3083 | assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload lacks runtime bits |
| 3173 | 3084 | |
| 3174 | | if (operand_is_ptr or isByRef(err_union_ty, zcu)) { |
| 3175 | | if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); |
| 3085 | if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); |
| 3176 | 3086 | |
| 3177 | | const err_union_llvm_ty = try o.lowerType(pt, err_union_ty); |
| 3178 | | const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 3179 | | return self.wip.load(access_kind, error_type, err_field_ptr, .default, ""); |
| 3180 | | } |
| 3087 | const err_align: InternPool.Alignment = a: { |
| 3088 | const err_abi_align = Type.anyerror.abiAlignment(zcu); |
| 3089 | if (!operand_is_ptr) break :a err_abi_align; |
| 3090 | break :a err_abi_align.minStrict(operand_ty.ptrAlignment(zcu)); |
| 3091 | }; |
| 3181 | 3092 | |
| 3182 | | return self.wip.extractValue(operand, &.{offset}, ""); |
| 3093 | const err_field_ptr = try self.ptraddConst(operand, codegen.errUnionErrorOffset(payload_ty, zcu)); |
| 3094 | return self.wip.load(access_kind, error_type, err_field_ptr, err_align.toLlvm(), ""); |
| 3183 | 3095 | } |
| 3184 | 3096 | |
| 3185 | 3097 | fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3198,27 +3110,18 @@ fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value |
| 3198 | 3110 | const access_kind: Builder.MemoryAccessKind = |
| 3199 | 3111 | if (err_union_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 3200 | 3112 | |
| 3201 | | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 3202 | | self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu)); |
| 3203 | | _ = try self.wip.store(access_kind, non_error_val, operand, err_union_ptr_align.toLlvm()); |
| 3204 | | return operand; |
| 3205 | | } |
| 3206 | | const err_union_llvm_ty = try o.lowerType(pt, err_union_ty); |
| 3207 | | { |
| 3208 | | self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu)); |
| 3113 | self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu)); |
| 3209 | 3114 | |
| 3210 | | const err_int_ty = try pt.errorIntType(); |
| 3211 | | const error_alignment = err_int_ty.abiAlignment(zcu).minStrict(err_union_ptr_align).toLlvm(); |
| 3212 | | const error_offset = try errUnionErrorFieldIndex(payload_ty, pt); |
| 3115 | { |
| 3116 | const error_align = Type.anyerror.abiAlignment(zcu).minStrict(err_union_ptr_align).toLlvm(); |
| 3213 | 3117 | // First set the non-error value. |
| 3214 | | const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, ""); |
| 3215 | | _ = try self.wip.store(access_kind, non_error_val, non_null_ptr, error_alignment); |
| 3118 | const error_ptr = try self.ptraddConst(operand, codegen.errUnionErrorOffset(payload_ty, zcu)); |
| 3119 | _ = try self.wip.store(access_kind, non_error_val, error_ptr, error_align); |
| 3216 | 3120 | } |
| 3121 | |
| 3217 | 3122 | // Then return the payload pointer (only if it is used). |
| 3218 | 3123 | if (self.liveness.isUnused(inst)) return .none; |
| 3219 | | |
| 3220 | | const payload_offset = try errUnionPayloadFieldIndex(payload_ty, pt); |
| 3221 | | return self.wip.gepStruct(err_union_llvm_ty, operand, payload_offset, ""); |
| 3124 | return self.ptraddConst(operand, codegen.errUnionPayloadOffset(payload_ty, zcu)); |
| 3222 | 3125 | } |
| 3223 | 3126 | |
| 3224 | 3127 | fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3233,7 +3136,6 @@ fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3233 | 3136 | } |
| 3234 | 3137 | |
| 3235 | 3138 | fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3236 | | const o = self.object; |
| 3237 | 3139 | const pt = self.pt; |
| 3238 | 3140 | const zcu = pt.zcu; |
| 3239 | 3141 | |
| ... | ... | @@ -3241,15 +3143,20 @@ fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !Builder.Val |
| 3241 | 3143 | const struct_ty = ty_pl.ty.toType(); |
| 3242 | 3144 | const field_index = ty_pl.payload; |
| 3243 | 3145 | |
| 3244 | | const struct_llvm_ty = try o.lowerType(pt, struct_ty); |
| 3245 | | const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?; |
| 3246 | 3146 | assert(self.err_ret_trace != .none); |
| 3247 | | const field_ptr = try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field_index, ""); |
| 3248 | | const field_alignment = struct_ty.explicitFieldAlignment(field_index, zcu); |
| 3147 | |
| 3249 | 3148 | const field_ty = struct_ty.fieldType(field_index, zcu); |
| 3149 | const field_offset = struct_ty.structFieldOffset(field_index, zcu); |
| 3150 | const field_align = switch (field_offset) { |
| 3151 | 0 => struct_ty.abiAlignment(zcu), |
| 3152 | else => struct_ty.abiAlignment(zcu).minStrict(.fromLog2Units(@ctz(field_offset))), |
| 3153 | }; |
| 3154 | |
| 3155 | const field_ptr = try self.ptraddConst(self.err_ret_trace, field_offset); |
| 3156 | |
| 3250 | 3157 | const field_ptr_ty = try pt.ptrType(.{ |
| 3251 | 3158 | .child = field_ty.toIntern(), |
| 3252 | | .flags = .{ .alignment = field_alignment }, |
| 3159 | .flags = .{ .alignment = field_align }, |
| 3253 | 3160 | }); |
| 3254 | 3161 | return self.load(field_ptr, field_ptr_ty); |
| 3255 | 3162 | } |
| ... | ... | @@ -3290,25 +3197,23 @@ fn airWrapOptional(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.V |
| 3290 | 3197 | const operand = try self.resolveInst(ty_op.operand); |
| 3291 | 3198 | const optional_ty = self.typeOfIndex(inst); |
| 3292 | 3199 | if (optional_ty.optionalReprIsPayload(zcu)) return operand; |
| 3200 | assert(isByRef(optional_ty, zcu)); // optionals with runtime bits are by-ref unless `optionalReprIsPayload` |
| 3293 | 3201 | const llvm_optional_ty = try o.lowerType(pt, optional_ty); |
| 3294 | | if (isByRef(optional_ty, zcu)) { |
| 3295 | | const directReturn = self.isNextRet(body_tail); |
| 3296 | | const optional_ptr = if (directReturn) |
| 3297 | | self.ret_ptr |
| 3298 | | else brk: { |
| 3299 | | const alignment = optional_ty.abiAlignment(zcu).toLlvm(); |
| 3300 | | const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment); |
| 3301 | | break :brk optional_ptr; |
| 3302 | | }; |
| 3202 | const optional_ptr = if (self.isNextRet(body_tail)) |
| 3203 | self.ret_ptr |
| 3204 | else brk: { |
| 3205 | const alignment = optional_ty.abiAlignment(zcu).toLlvm(); |
| 3206 | const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment); |
| 3207 | break :brk optional_ptr; |
| 3208 | }; |
| 3303 | 3209 | |
| 3304 | | const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, ""); |
| 3305 | | const payload_ptr_ty = try pt.singleMutPtrType(payload_ty); |
| 3306 | | try self.store(payload_ptr, payload_ptr_ty, operand, .none); |
| 3307 | | const non_null_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 1, ""); |
| 3308 | | _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default); |
| 3309 | | return optional_ptr; |
| 3310 | | } |
| 3311 | | return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, ""); |
| 3210 | const payload_ptr = optional_ptr; // payload always at offset 0 |
| 3211 | const payload_ptr_ty = try pt.singleMutPtrType(payload_ty); |
| 3212 | try self.store(payload_ptr, payload_ptr_ty, operand, .none); |
| 3213 | // Non-null bit immediately after payload (no padding because the bit has alignment 1). |
| 3214 | const non_null_ptr = try self.ptraddConst(optional_ptr, payload_ty.abiSize(zcu)); |
| 3215 | _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default); |
| 3216 | return optional_ptr; |
| 3312 | 3217 | } |
| 3313 | 3218 | |
| 3314 | 3219 | fn airWrapErrUnionPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3321,34 +3226,25 @@ fn airWrapErrUnionPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Bu |
| 3321 | 3226 | const operand = try self.resolveInst(ty_op.operand); |
| 3322 | 3227 | const payload_ty = self.typeOf(ty_op.operand); |
| 3323 | 3228 | assert(payload_ty.hasRuntimeBits(zcu)); |
| 3229 | assert(isByRef(err_un_ty, zcu)); // error unions with runtime bits are always by-ref |
| 3324 | 3230 | const ok_err_code = try o.builder.intValue(try o.errorIntType(pt), 0); |
| 3325 | 3231 | const err_un_llvm_ty = try o.lowerType(pt, err_un_ty); |
| 3326 | 3232 | |
| 3327 | | const payload_offset = try errUnionPayloadFieldIndex(payload_ty, pt); |
| 3328 | | const error_offset = try errUnionErrorFieldIndex(payload_ty, pt); |
| 3329 | | if (isByRef(err_un_ty, zcu)) { |
| 3330 | | const directReturn = self.isNextRet(body_tail); |
| 3331 | | const result_ptr = if (directReturn) |
| 3332 | | self.ret_ptr |
| 3333 | | else brk: { |
| 3334 | | const alignment = err_un_ty.abiAlignment(pt.zcu).toLlvm(); |
| 3335 | | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 3336 | | break :brk result_ptr; |
| 3337 | | }; |
| 3233 | const result_ptr = if (self.isNextRet(body_tail)) |
| 3234 | self.ret_ptr |
| 3235 | else brk: { |
| 3236 | const alignment = err_un_ty.abiAlignment(pt.zcu).toLlvm(); |
| 3237 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 3238 | break :brk result_ptr; |
| 3239 | }; |
| 3338 | 3240 | |
| 3339 | | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 3340 | | const err_int_ty = try pt.errorIntType(); |
| 3341 | | const error_alignment = err_int_ty.abiAlignment(pt.zcu).toLlvm(); |
| 3342 | | _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); |
| 3343 | | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 3344 | | const payload_ptr_ty = try pt.singleMutPtrType(payload_ty); |
| 3345 | | try self.store(payload_ptr, payload_ptr_ty, operand, .none); |
| 3346 | | return result_ptr; |
| 3347 | | } |
| 3348 | | var fields: [2]Builder.Value = undefined; |
| 3349 | | fields[payload_offset] = operand; |
| 3350 | | fields[error_offset] = ok_err_code; |
| 3351 | | return self.wip.buildAggregate(err_un_llvm_ty, &fields, ""); |
| 3241 | const err_ptr = try self.ptraddConst(result_ptr, codegen.errUnionErrorOffset(payload_ty, zcu)); |
| 3242 | const error_alignment = Type.anyerror.abiAlignment(pt.zcu).toLlvm(); |
| 3243 | _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); |
| 3244 | const payload_ptr = try self.ptraddConst(result_ptr, codegen.errUnionPayloadOffset(payload_ty, zcu)); |
| 3245 | const payload_ptr_ty = try pt.singleMutPtrType(payload_ty); |
| 3246 | try self.store(payload_ptr, payload_ptr_ty, operand, .none); |
| 3247 | return result_ptr; |
| 3352 | 3248 | } |
| 3353 | 3249 | |
| 3354 | 3250 | fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3361,35 +3257,26 @@ fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builde |
| 3361 | 3257 | const payload_ty = err_un_ty.errorUnionPayload(zcu); |
| 3362 | 3258 | const operand = try self.resolveInst(ty_op.operand); |
| 3363 | 3259 | if (!payload_ty.hasRuntimeBits(zcu)) return operand; |
| 3260 | assert(isByRef(err_un_ty, zcu)); // error unions with runtime bits are always by-ref |
| 3364 | 3261 | const err_un_llvm_ty = try o.lowerType(pt, err_un_ty); |
| 3365 | 3262 | |
| 3366 | | const payload_offset = try errUnionPayloadFieldIndex(payload_ty, pt); |
| 3367 | | const error_offset = try errUnionErrorFieldIndex(payload_ty, pt); |
| 3368 | | if (isByRef(err_un_ty, zcu)) { |
| 3369 | | const directReturn = self.isNextRet(body_tail); |
| 3370 | | const result_ptr = if (directReturn) |
| 3371 | | self.ret_ptr |
| 3372 | | else brk: { |
| 3373 | | const alignment = err_un_ty.abiAlignment(zcu).toLlvm(); |
| 3374 | | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 3375 | | break :brk result_ptr; |
| 3376 | | }; |
| 3377 | | |
| 3378 | | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 3379 | | const err_int_ty = try pt.errorIntType(); |
| 3380 | | const error_alignment = err_int_ty.abiAlignment(zcu).toLlvm(); |
| 3381 | | _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); |
| 3382 | | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 3383 | | const payload_ptr_ty = try pt.singleMutPtrType(payload_ty); |
| 3384 | | // TODO store undef to payload_ptr |
| 3385 | | _ = payload_ptr; |
| 3386 | | _ = payload_ptr_ty; |
| 3387 | | return result_ptr; |
| 3388 | | } |
| 3263 | const result_ptr = if (self.isNextRet(body_tail)) |
| 3264 | self.ret_ptr |
| 3265 | else brk: { |
| 3266 | const alignment = err_un_ty.abiAlignment(zcu).toLlvm(); |
| 3267 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 3268 | break :brk result_ptr; |
| 3269 | }; |
| 3389 | 3270 | |
| 3390 | | // TODO set payload bytes to undef |
| 3391 | | const undef = try o.builder.undefValue(err_un_llvm_ty); |
| 3392 | | return self.wip.insertValue(undef, operand, &.{error_offset}, ""); |
| 3271 | const err_ptr = try self.ptraddConst(result_ptr, codegen.errUnionErrorOffset(payload_ty, zcu)); |
| 3272 | const error_alignment = Type.anyerror.abiAlignment(zcu).toLlvm(); |
| 3273 | _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); |
| 3274 | const payload_ptr = try self.ptraddConst(result_ptr, codegen.errUnionPayloadOffset(payload_ty, zcu)); |
| 3275 | const payload_ptr_ty = try pt.singleMutPtrType(payload_ty); |
| 3276 | // TODO store undef to payload_ptr |
| 3277 | _ = payload_ptr; |
| 3278 | _ = payload_ptr_ty; |
| 3279 | return result_ptr; |
| 3393 | 3280 | } |
| 3394 | 3281 | |
| 3395 | 3282 | fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3804,26 +3691,18 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) !Bui |
| 3804 | 3691 | } |
| 3805 | 3692 | |
| 3806 | 3693 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3807 | | const o = self.object; |
| 3808 | | const pt = self.pt; |
| 3809 | | const zcu = pt.zcu; |
| 3694 | const zcu = self.pt.zcu; |
| 3810 | 3695 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3811 | 3696 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3812 | | const ptr = try self.resolveInst(bin_op.lhs); |
| 3813 | | const offset = try self.resolveInst(bin_op.rhs); |
| 3697 | const ptr_or_slice = try self.resolveInst(bin_op.lhs); |
| 3698 | const index = try self.resolveInst(bin_op.rhs); |
| 3814 | 3699 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3815 | | const llvm_elem_ty = try o.lowerType(pt, ptr_ty.childType(zcu)); |
| 3816 | | switch (ptr_ty.ptrSize(zcu)) { |
| 3817 | | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 3818 | | .one => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{ |
| 3819 | | try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), offset, |
| 3820 | | }, ""), |
| 3821 | | .c, .many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{offset}, ""), |
| 3822 | | .slice => { |
| 3823 | | const base = try self.wip.extractValue(ptr, &.{0}, ""); |
| 3824 | | return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{offset}, ""); |
| 3825 | | }, |
| 3826 | | } |
| 3700 | const elem_ty = ptr_ty.indexableElem(zcu); |
| 3701 | const ptr = switch (ptr_ty.ptrSize(zcu)) { |
| 3702 | .one, .many, .c => ptr_or_slice, |
| 3703 | .slice => try self.wip.extractValue(ptr_or_slice, &.{0}, ""), |
| 3704 | }; |
| 3705 | return self.ptraddScaled(ptr, index, elem_ty.abiSize(zcu)); |
| 3827 | 3706 | } |
| 3828 | 3707 | |
| 3829 | 3708 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -3832,22 +3711,18 @@ fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 3832 | 3711 | const zcu = pt.zcu; |
| 3833 | 3712 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3834 | 3713 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3835 | | const ptr = try self.resolveInst(bin_op.lhs); |
| 3836 | | const offset = try self.resolveInst(bin_op.rhs); |
| 3837 | | const negative_offset = try self.wip.neg(offset, ""); |
| 3714 | const ptr_or_slice = try self.resolveInst(bin_op.lhs); |
| 3715 | const llvm_usize_ty = try o.lowerType(pt, .usize); |
| 3838 | 3716 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3839 | | const llvm_elem_ty = try o.lowerType(pt, ptr_ty.childType(zcu)); |
| 3840 | | switch (ptr_ty.ptrSize(zcu)) { |
| 3841 | | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 3842 | | .one => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{ |
| 3843 | | try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), negative_offset, |
| 3844 | | }, ""), |
| 3845 | | .c, .many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{negative_offset}, ""), |
| 3846 | | .slice => { |
| 3847 | | const base = try self.wip.extractValue(ptr, &.{0}, ""); |
| 3848 | | return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{negative_offset}, ""); |
| 3849 | | }, |
| 3850 | | } |
| 3717 | const elem_ty = ptr_ty.indexableElem(zcu); |
| 3718 | const ptr = switch (ptr_ty.ptrSize(zcu)) { |
| 3719 | .one, .many, .c => ptr_or_slice, |
| 3720 | .slice => try self.wip.extractValue(ptr_or_slice, &.{0}, ""), |
| 3721 | }; |
| 3722 | const scale_val = try o.builder.intValue(llvm_usize_ty, -@as(i65, elem_ty.abiSize(zcu))); |
| 3723 | const positive_index = try self.resolveInst(bin_op.rhs); |
| 3724 | const negative_offset = try self.wip.bin(.@"mul nsw", positive_index, scale_val, ""); |
| 3725 | return self.ptradd(ptr, negative_offset); |
| 3851 | 3726 | } |
| 3852 | 3727 | |
| 3853 | 3728 | fn airOverflow( |
| ... | ... | @@ -3868,6 +3743,7 @@ fn airOverflow( |
| 3868 | 3743 | const lhs_ty = self.typeOf(extra.lhs); |
| 3869 | 3744 | const scalar_ty = lhs_ty.scalarType(zcu); |
| 3870 | 3745 | const inst_ty = self.typeOfIndex(inst); |
| 3746 | assert(isByRef(inst_ty, zcu)); // auto structs are by-ref |
| 3871 | 3747 | |
| 3872 | 3748 | const intrinsic = if (scalar_ty.isSignedInt(zcu)) signed_intrinsic else unsigned_intrinsic; |
| 3873 | 3749 | const llvm_inst_ty = try o.lowerType(pt, inst_ty); |
| ... | ... | @@ -3878,28 +3754,22 @@ fn airOverflow( |
| 3878 | 3754 | const result_val = try self.wip.extractValue(results, &.{0}, ""); |
| 3879 | 3755 | const overflow_bit = try self.wip.extractValue(results, &.{1}, ""); |
| 3880 | 3756 | |
| 3881 | | const result_index = o.llvmFieldIndex(inst_ty, 0).?; |
| 3882 | | const overflow_index = o.llvmFieldIndex(inst_ty, 1).?; |
| 3757 | const result_alignment = inst_ty.abiAlignment(zcu).toLlvm(); |
| 3758 | const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment); |
| 3883 | 3759 | |
| 3884 | | if (isByRef(inst_ty, zcu)) { |
| 3885 | | const result_alignment = inst_ty.abiAlignment(zcu).toLlvm(); |
| 3886 | | const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment); |
| 3887 | | { |
| 3888 | | const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, ""); |
| 3889 | | _ = try self.wip.store(.normal, result_val, field_ptr, result_alignment); |
| 3890 | | } |
| 3891 | | { |
| 3892 | | const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, overflow_index, ""); |
| 3893 | | _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1)); |
| 3894 | | } |
| 3760 | { |
| 3761 | // Store to 'result: IntType' field |
| 3762 | const field_ptr = try self.ptraddConst(alloca_inst, inst_ty.structFieldOffset(0, zcu)); |
| 3763 | _ = try self.wip.store(.normal, result_val, field_ptr, lhs_ty.abiAlignment(zcu).toLlvm()); |
| 3764 | } |
| 3895 | 3765 | |
| 3896 | | return alloca_inst; |
| 3766 | { |
| 3767 | // Store to 'overflow: u1' field |
| 3768 | const field_ptr = try self.ptraddConst(alloca_inst, inst_ty.structFieldOffset(1, zcu)); |
| 3769 | _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1)); |
| 3897 | 3770 | } |
| 3898 | 3771 | |
| 3899 | | var fields: [2]Builder.Value = undefined; |
| 3900 | | fields[result_index] = result_val; |
| 3901 | | fields[overflow_index] = overflow_bit; |
| 3902 | | return self.wip.buildAggregate(llvm_inst_ty, &fields, ""); |
| 3772 | return alloca_inst; |
| 3903 | 3773 | } |
| 3904 | 3774 | |
| 3905 | 3775 | fn buildElementwiseCall( |
| ... | ... | @@ -4227,6 +4097,7 @@ fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 4227 | 4097 | const lhs_scalar_ty = lhs_ty.scalarType(zcu); |
| 4228 | 4098 | |
| 4229 | 4099 | const dest_ty = self.typeOfIndex(inst); |
| 4100 | assert(isByRef(dest_ty, zcu)); // auto structs are by-ref |
| 4230 | 4101 | const llvm_dest_ty = try o.lowerType(pt, dest_ty); |
| 4231 | 4102 | |
| 4232 | 4103 | const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(pt, lhs_ty), ""); |
| ... | ... | @@ -4239,27 +4110,22 @@ fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 4239 | 4110 | |
| 4240 | 4111 | const overflow_bit = try self.wip.icmp(.ne, lhs, reconstructed, ""); |
| 4241 | 4112 | |
| 4242 | | const result_index = o.llvmFieldIndex(dest_ty, 0).?; |
| 4243 | | const overflow_index = o.llvmFieldIndex(dest_ty, 1).?; |
| 4113 | const result_alignment = dest_ty.abiAlignment(zcu).toLlvm(); |
| 4114 | const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment); |
| 4244 | 4115 | |
| 4245 | | if (isByRef(dest_ty, zcu)) { |
| 4246 | | const result_alignment = dest_ty.abiAlignment(zcu).toLlvm(); |
| 4247 | | const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment); |
| 4248 | | { |
| 4249 | | const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, ""); |
| 4250 | | _ = try self.wip.store(.normal, result, field_ptr, result_alignment); |
| 4251 | | } |
| 4252 | | { |
| 4253 | | const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, ""); |
| 4254 | | _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1)); |
| 4255 | | } |
| 4256 | | return alloca_inst; |
| 4116 | { |
| 4117 | // Store to 'result: IntType' field |
| 4118 | const field_ptr = try self.ptraddConst(alloca_inst, dest_ty.structFieldOffset(0, zcu)); |
| 4119 | _ = try self.wip.store(.normal, result, field_ptr, lhs_ty.abiAlignment(zcu).toLlvm()); |
| 4257 | 4120 | } |
| 4258 | 4121 | |
| 4259 | | var fields: [2]Builder.Value = undefined; |
| 4260 | | fields[result_index] = result; |
| 4261 | | fields[overflow_index] = overflow_bit; |
| 4262 | | return self.wip.buildAggregate(llvm_dest_ty, &fields, ""); |
| 4122 | { |
| 4123 | // Store to 'overflow: u1' field |
| 4124 | const field_ptr = try self.ptraddConst(alloca_inst, dest_ty.structFieldOffset(1, zcu)); |
| 4125 | _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1)); |
| 4126 | } |
| 4127 | |
| 4128 | return alloca_inst; |
| 4263 | 4129 | } |
| 4264 | 4130 | |
| 4265 | 4131 | fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -4678,7 +4544,8 @@ fn bitCast(self: *FuncGen, operand: Builder.Value, operand_ty: Type, inst_ty: Ty |
| 4678 | 4544 | } |
| 4679 | 4545 | |
| 4680 | 4546 | if (operand_ty.zigTypeTag(zcu) == .vector and inst_ty.zigTypeTag(zcu) == .array) { |
| 4681 | | const elem_ty = operand_ty.childType(zcu); |
| 4547 | const elem_ty = inst_ty.childType(zcu); |
| 4548 | assert(elem_ty.toIntern() == operand_scalar_ty.toIntern()); |
| 4682 | 4549 | if (!result_is_ref) { |
| 4683 | 4550 | return self.todo("implement bitcast vector to non-ref array", .{}); |
| 4684 | 4551 | } |
| ... | ... | @@ -4690,22 +4557,19 @@ fn bitCast(self: *FuncGen, operand: Builder.Value, operand_ty: Type, inst_ty: Ty |
| 4690 | 4557 | } else { |
| 4691 | 4558 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| 4692 | 4559 | // a simple bitcast will not work, and we fall back to extractelement. |
| 4693 | | const llvm_usize = try o.lowerType(pt, Type.usize); |
| 4694 | | const usize_zero = try o.builder.intValue(llvm_usize, 0); |
| 4560 | const elem_size = elem_ty.abiSize(zcu); |
| 4695 | 4561 | const vector_len = operand_ty.arrayLen(zcu); |
| 4696 | 4562 | var i: u64 = 0; |
| 4697 | 4563 | while (i < vector_len) : (i += 1) { |
| 4698 | | const elem_ptr = try self.wip.gep(.inbounds, llvm_dest_ty, array_ptr, &.{ |
| 4699 | | usize_zero, try o.builder.intValue(llvm_usize, i), |
| 4700 | | }, ""); |
| 4701 | | const elem = |
| 4702 | | try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), ""); |
| 4703 | | _ = try self.wip.store(.normal, elem, elem_ptr, .default); |
| 4564 | const arr_elem_ptr = try self.ptraddConst(array_ptr, i * elem_size); |
| 4565 | const vec_elem = try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), ""); |
| 4566 | _ = try self.wip.store(.normal, vec_elem, arr_elem_ptr, .default); |
| 4704 | 4567 | } |
| 4705 | 4568 | } |
| 4706 | 4569 | return array_ptr; |
| 4707 | 4570 | } else if (operand_ty.zigTypeTag(zcu) == .array and inst_ty.zigTypeTag(zcu) == .vector) { |
| 4708 | 4571 | const elem_ty = operand_ty.childType(zcu); |
| 4572 | assert(elem_ty.toIntern() == inst_scalar_ty.toIntern()); |
| 4709 | 4573 | const llvm_vector_ty = try o.lowerType(pt, inst_ty); |
| 4710 | 4574 | if (!operand_is_ref) return self.todo("implement bitcast non-ref array to vector", .{}); |
| 4711 | 4575 | |
| ... | ... | @@ -4718,20 +4582,15 @@ fn bitCast(self: *FuncGen, operand: Builder.Value, operand_ty: Type, inst_ty: Ty |
| 4718 | 4582 | } else { |
| 4719 | 4583 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| 4720 | 4584 | // a simple bitcast will not work, and we fall back to extractelement. |
| 4721 | | const array_llvm_ty = try o.lowerType(pt, operand_ty); |
| 4722 | 4585 | const elem_llvm_ty = try o.lowerType(pt, elem_ty); |
| 4723 | | const llvm_usize = try o.lowerType(pt, Type.usize); |
| 4724 | | const usize_zero = try o.builder.intValue(llvm_usize, 0); |
| 4586 | const elem_size = elem_ty.abiSize(zcu); |
| 4725 | 4587 | const vector_len = operand_ty.arrayLen(zcu); |
| 4726 | 4588 | var vector = try o.builder.poisonValue(llvm_vector_ty); |
| 4727 | 4589 | var i: u64 = 0; |
| 4728 | 4590 | while (i < vector_len) : (i += 1) { |
| 4729 | | const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, operand, &.{ |
| 4730 | | usize_zero, try o.builder.intValue(llvm_usize, i), |
| 4731 | | }, ""); |
| 4732 | | const elem = try self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, ""); |
| 4733 | | vector = |
| 4734 | | try self.wip.insertElement(vector, elem, try o.builder.intValue(.i32, i), ""); |
| 4591 | const arr_elem_ptr = try self.ptraddConst(operand, i * elem_size); |
| 4592 | const arr_elem = try self.wip.load(.normal, elem_llvm_ty, arr_elem_ptr, .default, ""); |
| 4593 | vector = try self.wip.insertElement(vector, arr_elem, try o.builder.intValue(.i32, i), ""); |
| 4735 | 4594 | } |
| 4736 | 4595 | return vector; |
| 4737 | 4596 | } |
| ... | ... | @@ -5066,10 +4925,23 @@ fn airCmpxchg( |
| 5066 | 4925 | return self.wip.select(.normal, success_bit, zero, payload, ""); |
| 5067 | 4926 | } |
| 5068 | 4927 | |
| 4928 | assert(isByRef(optional_ty, zcu)); |
| 4929 | |
| 5069 | 4930 | comptime assert(optional_layout_version == 3); |
| 5070 | 4931 | |
| 5071 | 4932 | const non_null_bit = try self.wip.not(success_bit, ""); |
| 5072 | | return buildOptional(self, optional_ty, payload, non_null_bit); |
| 4933 | |
| 4934 | const payload_align = operand_ty.abiAlignment(zcu).toLlvm(); |
| 4935 | const alloca_inst = try self.buildAlloca(try o.lowerType(pt, optional_ty), payload_align); |
| 4936 | |
| 4937 | // Payload is always the first field at offset 0, so address is `alloca_inst` |
| 4938 | _ = try self.wip.store(.normal, payload, alloca_inst, payload_align); |
| 4939 | |
| 4940 | // Non-null bit is after payload with no padding because it has alignment 1 |
| 4941 | const non_null_ptr = try self.ptraddConst(alloca_inst, operand_ty.abiSize(zcu)); |
| 4942 | _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, comptime .fromByteUnits(1)); |
| 4943 | |
| 4944 | return alloca_inst; |
| 5073 | 4945 | } |
| 5074 | 4946 | |
| 5075 | 4947 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | ... | @@ -5315,13 +5187,15 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value |
| 5315 | 5187 | const end_block = try self.wip.block(1, "InlineMemsetEnd"); |
| 5316 | 5188 | |
| 5317 | 5189 | const llvm_usize_ty = try o.lowerType(pt, Type.usize); |
| 5318 | | const len = switch (ptr_ty.ptrSize(zcu)) { |
| 5319 | | .slice => try self.wip.extractValue(dest_slice, &.{1}, ""), |
| 5320 | | .one => try o.builder.intValue(llvm_usize_ty, ptr_ty.childType(zcu).arrayLen(zcu)), |
| 5190 | const end_ptr = switch (ptr_ty.ptrSize(zcu)) { |
| 5191 | .slice => try self.ptraddScaled( |
| 5192 | dest_ptr, |
| 5193 | try self.wip.extractValue(dest_slice, &.{1}, ""), |
| 5194 | elem_abi_size, |
| 5195 | ), |
| 5196 | .one => try self.ptraddConst(dest_ptr, ptr_ty.childType(zcu).abiSize(zcu)), |
| 5321 | 5197 | .many, .c => unreachable, |
| 5322 | 5198 | }; |
| 5323 | | const elem_llvm_ty = try o.lowerType(pt, elem_ty); |
| 5324 | | const end_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, dest_ptr, &.{len}, ""); |
| 5325 | 5199 | _ = try self.wip.br(loop_block); |
| 5326 | 5200 | |
| 5327 | 5201 | self.wip.cursor = .{ .block = loop_block }; |
| ... | ... | @@ -5343,9 +5217,7 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value |
| 5343 | 5217 | self.disable_intrinsics, |
| 5344 | 5218 | ); |
| 5345 | 5219 | } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align); |
| 5346 | | const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{ |
| 5347 | | try o.builder.intValue(llvm_usize_ty, 1), |
| 5348 | | }, ""); |
| 5220 | const next_ptr = try self.ptraddConst(it_ptr.toValue(), elem_abi_size); |
| 5349 | 5221 | _ = try self.wip.br(loop_block); |
| 5350 | 5222 | |
| 5351 | 5223 | self.wip.cursor = .{ .block = end_block }; |
| ... | ... | @@ -5408,14 +5280,13 @@ fn airMemmove(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 5408 | 5280 | } |
| 5409 | 5281 | |
| 5410 | 5282 | fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 5411 | | const o = self.object; |
| 5412 | 5283 | const pt = self.pt; |
| 5413 | 5284 | const zcu = pt.zcu; |
| 5414 | 5285 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 5415 | 5286 | const un_ptr_ty = self.typeOf(bin_op.lhs); |
| 5416 | 5287 | const un_ty = un_ptr_ty.childType(zcu); |
| 5417 | 5288 | const layout = un_ty.unionGetLayout(zcu); |
| 5418 | | if (layout.tag_size == 0) return .none; |
| 5289 | assert(layout.tag_size != 0); |
| 5419 | 5290 | |
| 5420 | 5291 | const access_kind: Builder.MemoryAccessKind = |
| 5421 | 5292 | if (un_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| ... | ... | @@ -5429,8 +5300,7 @@ fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 5429 | 5300 | _ = try self.wip.store(access_kind, new_tag, union_ptr, union_ptr_align.toLlvm()); |
| 5430 | 5301 | return .none; |
| 5431 | 5302 | } |
| 5432 | | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 5433 | | const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(pt, un_ty), union_ptr, tag_index, ""); |
| 5303 | const tag_field_ptr = try self.ptraddConst(union_ptr, layout.tagOffset()); |
| 5434 | 5304 | const tag_ptr_align: InternPool.Alignment = switch (layout.tagOffset()) { |
| 5435 | 5305 | 0 => union_ptr_align, |
| 5436 | 5306 | else => |off| .minStrict(union_ptr_align, .fromLog2Units(@ctz(off))), |
| ... | ... | @@ -5446,20 +5316,20 @@ fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 5446 | 5316 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5447 | 5317 | const un_ty = self.typeOf(ty_op.operand); |
| 5448 | 5318 | const layout = un_ty.unionGetLayout(zcu); |
| 5449 | | if (layout.tag_size == 0) return .none; |
| 5450 | | const union_handle = try self.resolveInst(ty_op.operand); |
| 5319 | assert(layout.tag_size != 0); |
| 5320 | const union_ptr = try self.resolveInst(ty_op.operand); |
| 5451 | 5321 | if (isByRef(un_ty, zcu)) { |
| 5452 | 5322 | const llvm_un_ty = try o.lowerType(pt, un_ty); |
| 5453 | 5323 | if (layout.payload_size == 0) |
| 5454 | | return self.wip.load(.normal, llvm_un_ty, union_handle, .default, ""); |
| 5324 | return self.wip.load(.normal, llvm_un_ty, union_ptr, .default, ""); |
| 5455 | 5325 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 5456 | | const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, ""); |
| 5326 | const tag_field_ptr = try self.ptraddConst(union_ptr, layout.tagOffset()); |
| 5457 | 5327 | const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index]; |
| 5458 | 5328 | return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, ""); |
| 5459 | 5329 | } else { |
| 5460 | | if (layout.payload_size == 0) return union_handle; |
| 5330 | if (layout.payload_size == 0) return union_ptr; |
| 5461 | 5331 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 5462 | | return self.wip.extractValue(union_handle, &.{tag_index}, ""); |
| 5332 | return self.wip.extractValue(union_ptr, &.{tag_index}, ""); |
| 5463 | 5333 | } |
| 5464 | 5334 | } |
| 5465 | 5335 | |
| ... | ... | @@ -5646,19 +5516,18 @@ fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 5646 | 5516 | fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 5647 | 5517 | const o = self.object; |
| 5648 | 5518 | const pt = self.pt; |
| 5519 | const zcu = pt.zcu; |
| 5649 | 5520 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 5650 | 5521 | const operand = try self.resolveInst(un_op); |
| 5651 | 5522 | const slice_ty = self.typeOfIndex(inst); |
| 5652 | 5523 | const slice_llvm_ty = try o.lowerType(pt, slice_ty); |
| 5653 | 5524 | |
| 5654 | 5525 | // If operand is small (e.g. `u8`), then signedness becomes a problem -- GEP always treats the index as signed. |
| 5655 | | const extended_operand = try self.wip.conv(.unsigned, operand, try o.lowerType(pt, .usize), ""); |
| 5526 | const operand_usize = try self.wip.conv(.unsigned, operand, try o.lowerType(pt, .usize), ""); |
| 5656 | 5527 | |
| 5657 | 5528 | const error_name_table_ptr = try self.getErrorNameTable(); |
| 5658 | | const error_name_table = |
| 5659 | | try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, ""); |
| 5660 | | const error_name_ptr = |
| 5661 | | try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{extended_operand}, ""); |
| 5529 | const error_name_table = try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, ""); |
| 5530 | const error_name_ptr = try self.ptraddScaled(error_name_table, operand_usize, slice_ty.abiSize(zcu)); |
| 5662 | 5531 | return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, ""); |
| 5663 | 5532 | } |
| 5664 | 5533 | |
| ... | ... | @@ -6074,8 +5943,9 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 6074 | 5943 | } |
| 6075 | 5944 | return vector; |
| 6076 | 5945 | }, |
| 6077 | | .@"struct" => { |
| 6078 | | if (zcu.typeToPackedStruct(result_ty)) |struct_type| { |
| 5946 | .@"struct" => switch (result_ty.containerLayout(zcu)) { |
| 5947 | .@"packed" => { |
| 5948 | const struct_type = ip.loadStructType(result_ty.toIntern()); |
| 6079 | 5949 | const backing_int_ty: Type = .fromInterned(struct_type.packed_backing_int_type); |
| 6080 | 5950 | const big_bits = backing_int_ty.bitSize(zcu); |
| 6081 | 5951 | const int_ty = try o.builder.intType(@intCast(big_bits)); |
| ... | ... | @@ -6100,69 +5970,68 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 6100 | 5970 | running_bits += ty_bit_size; |
| 6101 | 5971 | } |
| 6102 | 5972 | return running_int; |
| 6103 | | } |
| 6104 | | |
| 6105 | | assert(result_ty.containerLayout(zcu) != .@"packed"); |
| 6106 | | |
| 6107 | | if (isByRef(result_ty, zcu)) { |
| 5973 | }, |
| 5974 | .auto, .@"extern" => { |
| 5975 | assert(isByRef(result_ty, zcu)); |
| 6108 | 5976 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 6109 | 5977 | // even if we fully populate the fields. |
| 6110 | | const alignment = result_ty.abiAlignment(zcu).toLlvm(); |
| 6111 | | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); |
| 6112 | | |
| 6113 | | for (elements, 0..) |elem, i| { |
| 6114 | | if ((try result_ty.structFieldValueComptime(pt, i)) != null) continue; |
| 6115 | | |
| 6116 | | const llvm_elem = try self.resolveInst(elem); |
| 6117 | | const llvm_i = o.llvmFieldIndex(result_ty, i).?; |
| 6118 | | const field_ptr = try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, ""); |
| 6119 | | |
| 6120 | | const field_ptr_ty = try pt.ptrType(.{ |
| 6121 | | .child = self.typeOf(elem).toIntern(), |
| 6122 | | .flags = .{ |
| 6123 | | .alignment = result_ty.explicitFieldAlignment(i, zcu), |
| 6124 | | }, |
| 6125 | | }); |
| 6126 | | try self.store(field_ptr, field_ptr_ty, llvm_elem, .none); |
| 6127 | | } |
| 5978 | const struct_align = result_ty.abiAlignment(zcu); |
| 5979 | const alloca_inst = try self.buildAlloca(llvm_result_ty, struct_align.toLlvm()); |
| 6128 | 5980 | |
| 6129 | | return alloca_inst; |
| 6130 | | } else { |
| 6131 | | var result = try o.builder.poisonValue(llvm_result_ty); |
| 6132 | | for (elements, 0..) |elem, i| { |
| 6133 | | if ((try result_ty.structFieldValueComptime(pt, i)) != null) continue; |
| 5981 | for (elements, 0..) |elem, field_index| { |
| 5982 | if (result_ty.structFieldIsComptime(field_index, zcu)) continue; |
| 5983 | const field_ty = result_ty.fieldType(field_index, zcu); |
| 5984 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 5985 | const offset = result_ty.structFieldOffset(field_index, zcu); |
| 5986 | const field_ptr = try self.ptraddConst(alloca_inst, offset); |
| 5987 | const field_ptr_align: InternPool.Alignment = switch (offset) { |
| 5988 | 0 => struct_align, |
| 5989 | else => struct_align.minStrict(.fromLog2Units(@ctz(offset))), |
| 5990 | }; |
| 6134 | 5991 | |
| 6135 | | const llvm_elem = try self.resolveInst(elem); |
| 6136 | | const llvm_i = o.llvmFieldIndex(result_ty, i).?; |
| 6137 | | result = try self.wip.insertValue(result, llvm_elem, &.{llvm_i}, ""); |
| 5992 | const llvm_field_val = try self.resolveInst(elem); |
| 5993 | |
| 5994 | if (isByRef(field_ty, zcu)) { |
| 5995 | _ = try self.wip.callMemCpy( |
| 5996 | field_ptr, |
| 5997 | field_ptr_align.toLlvm(), |
| 5998 | llvm_field_val, |
| 5999 | field_ty.abiAlignment(zcu).toLlvm(), |
| 6000 | try o.builder.intValue(try o.lowerType(pt, .usize), field_ty.abiSize(zcu)), |
| 6001 | .normal, |
| 6002 | self.disable_intrinsics, |
| 6003 | ); |
| 6004 | } else { |
| 6005 | _ = try self.wip.store( |
| 6006 | .normal, |
| 6007 | llvm_field_val, |
| 6008 | field_ptr, |
| 6009 | field_ptr_align.toLlvm(), |
| 6010 | ); |
| 6011 | } |
| 6138 | 6012 | } |
| 6139 | | return result; |
| 6140 | | } |
| 6013 | |
| 6014 | return alloca_inst; |
| 6015 | }, |
| 6141 | 6016 | }, |
| 6142 | 6017 | .array => { |
| 6143 | 6018 | assert(isByRef(result_ty, zcu)); |
| 6144 | 6019 | |
| 6145 | | const llvm_usize = try o.lowerType(pt, Type.usize); |
| 6146 | | const usize_zero = try o.builder.intValue(llvm_usize, 0); |
| 6147 | 6020 | const alignment = result_ty.abiAlignment(zcu).toLlvm(); |
| 6148 | 6021 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); |
| 6149 | 6022 | |
| 6150 | 6023 | const array_info = result_ty.arrayInfo(zcu); |
| 6151 | | const elem_ptr_ty = try pt.ptrType(.{ |
| 6152 | | .child = array_info.elem_type.toIntern(), |
| 6153 | | }); |
| 6024 | const elem_ptr_ty = try pt.singleConstPtrType(array_info.elem_type); |
| 6025 | |
| 6026 | const elem_size = array_info.elem_type.abiSize(zcu); |
| 6154 | 6027 | |
| 6155 | 6028 | for (elements, 0..) |elem, i| { |
| 6156 | | const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{ |
| 6157 | | usize_zero, try o.builder.intValue(llvm_usize, i), |
| 6158 | | }, ""); |
| 6029 | const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * i); |
| 6159 | 6030 | const llvm_elem = try self.resolveInst(elem); |
| 6160 | 6031 | try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .none); |
| 6161 | 6032 | } |
| 6162 | 6033 | if (array_info.sentinel) |sent_val| { |
| 6163 | | const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{ |
| 6164 | | usize_zero, try o.builder.intValue(llvm_usize, array_info.len), |
| 6165 | | }, ""); |
| 6034 | const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * array_info.len); |
| 6166 | 6035 | const llvm_elem = try self.resolveValue(sent_val); |
| 6167 | 6036 | try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none); |
| 6168 | 6037 | } |
| ... | ... | @@ -6188,95 +6057,30 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 6188 | 6057 | |
| 6189 | 6058 | const layout = Type.getUnionLayout(union_obj, zcu); |
| 6190 | 6059 | |
| 6191 | | const tag_int_val = blk: { |
| 6192 | | const tag_ty = union_ty.unionTagTypeHypothetical(zcu); |
| 6193 | | const tag_val = try pt.enumValueFieldIndex(tag_ty, extra.field_index); |
| 6194 | | break :blk tag_val.intFromEnum(zcu); |
| 6195 | | }; |
| 6196 | | if (layout.payload_size == 0) { |
| 6197 | | if (layout.tag_size == 0) { |
| 6198 | | return .none; |
| 6199 | | } |
| 6200 | | assert(!isByRef(union_ty, zcu)); |
| 6201 | | var big_int_space: Value.BigIntSpace = undefined; |
| 6202 | | const tag_big_int = tag_int_val.toBigInt(&big_int_space, zcu); |
| 6203 | | return try o.builder.bigIntValue(union_llvm_ty, tag_big_int); |
| 6204 | | } |
| 6060 | assert(layout.payload_size != 0); // otherwise the value would be comptime-known |
| 6205 | 6061 | assert(isByRef(union_ty, zcu)); |
| 6206 | | // The llvm type of the alloca will be the named LLVM union type, and will not |
| 6207 | | // necessarily match the format that we need, depending on which tag is active. |
| 6208 | | // We must construct the correct unnamed struct type here, in order to then set |
| 6209 | | // the fields appropriately. |
| 6062 | |
| 6210 | 6063 | const alignment = layout.abi_align.toLlvm(); |
| 6211 | 6064 | const result_ptr = try self.buildAlloca(union_llvm_ty, alignment); |
| 6212 | 6065 | const llvm_payload = try self.resolveInst(extra.init); |
| 6213 | 6066 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]); |
| 6214 | | const field_llvm_ty = try o.lowerType(pt, field_ty); |
| 6215 | | const field_size = field_ty.abiSize(zcu); |
| 6216 | | const field_align = union_ty.explicitFieldAlignment(extra.field_index, zcu); |
| 6217 | | const llvm_usize = try o.lowerType(pt, Type.usize); |
| 6218 | | const usize_zero = try o.builder.intValue(llvm_usize, 0); |
| 6219 | | |
| 6220 | 6067 | assert(field_ty.hasRuntimeBits(zcu)); |
| 6221 | 6068 | |
| 6222 | | const llvm_union_ty = t: { |
| 6223 | | const payload_ty = p: { |
| 6224 | | if (field_size == layout.payload_size) { |
| 6225 | | break :p field_llvm_ty; |
| 6226 | | } |
| 6227 | | const padding_len = layout.payload_size - field_size; |
| 6228 | | break :p try o.builder.structType(.@"packed", &.{ |
| 6229 | | field_llvm_ty, try o.builder.arrayType(padding_len, .i8), |
| 6230 | | }); |
| 6231 | | }; |
| 6232 | | if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty}); |
| 6233 | | const tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type)); |
| 6234 | | var fields: [3]Builder.Type = undefined; |
| 6235 | | var fields_len: usize = 2; |
| 6236 | | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 6237 | | fields = .{ tag_ty, payload_ty, undefined }; |
| 6238 | | } else { |
| 6239 | | fields = .{ payload_ty, tag_ty, undefined }; |
| 6240 | | } |
| 6241 | | if (layout.padding != 0) { |
| 6242 | | fields[fields_len] = try o.builder.arrayType(layout.padding, .i8); |
| 6243 | | fields_len += 1; |
| 6244 | | } |
| 6245 | | break :t try o.builder.structType(.normal, fields[0..fields_len]); |
| 6246 | | }; |
| 6247 | | |
| 6248 | | // Now we follow the layout as expressed above with GEP instructions to set the |
| 6249 | | // tag and the payload. |
| 6250 | | const field_ptr_ty = try pt.ptrType(.{ |
| 6251 | | .child = field_ty.toIntern(), |
| 6252 | | .flags = .{ .alignment = field_align }, |
| 6253 | | }); |
| 6254 | | if (layout.tag_size == 0) { |
| 6255 | | const indices = [3]Builder.Value{ usize_zero, .@"0", .@"0" }; |
| 6256 | | const len: usize = if (field_size == layout.payload_size) 2 else 3; |
| 6257 | | const field_ptr = |
| 6258 | | try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], ""); |
| 6259 | | try self.store(field_ptr, field_ptr_ty, llvm_payload, .none); |
| 6260 | | return result_ptr; |
| 6261 | | } |
| 6262 | | |
| 6263 | 6069 | { |
| 6264 | | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); |
| 6265 | | const indices: [3]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, payload_index), .@"0" }; |
| 6266 | | const len: usize = if (field_size == layout.payload_size) 2 else 3; |
| 6267 | | const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], ""); |
| 6268 | | try self.store(field_ptr, field_ptr_ty, llvm_payload, .none); |
| 6070 | const payload_ptr_ty = try pt.ptrType(.{ |
| 6071 | .child = field_ty.toIntern(), |
| 6072 | .flags = .{ .alignment = layout.payload_align }, |
| 6073 | }); |
| 6074 | const payload_ptr = try self.ptraddConst(result_ptr, layout.payloadOffset()); |
| 6075 | try self.store(payload_ptr, payload_ptr_ty, llvm_payload, .none); |
| 6269 | 6076 | } |
| 6270 | | { |
| 6271 | | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 6272 | | const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) }; |
| 6273 | | const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, ""); |
| 6274 | | const tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type)); |
| 6275 | | var big_int_space: Value.BigIntSpace = undefined; |
| 6276 | | const tag_big_int = tag_int_val.toBigInt(&big_int_space, zcu); |
| 6277 | | const llvm_tag = try o.builder.bigIntValue(tag_ty, tag_big_int); |
| 6278 | | const tag_alignment = Type.fromInterned(union_obj.enum_tag_type).abiAlignment(zcu).toLlvm(); |
| 6279 | | _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment); |
| 6077 | |
| 6078 | if (layout.tag_size != 0) { |
| 6079 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); |
| 6080 | const tag_val = try pt.enumValueFieldIndex(tag_ty, extra.field_index); |
| 6081 | const llvm_tag_val = try o.lowerValue(pt, tag_val.toIntern()); |
| 6082 | const tag_ptr = try self.ptraddConst(result_ptr, layout.tagOffset()); |
| 6083 | _ = try self.wip.store(.normal, llvm_tag_val.toValue(), tag_ptr, layout.tag_align.toLlvm()); |
| 6280 | 6084 | } |
| 6281 | 6085 | |
| 6282 | 6086 | return result_ptr; |
| ... | ... | @@ -6369,7 +6173,6 @@ fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 6369 | 6173 | } |
| 6370 | 6174 | |
| 6371 | 6175 | fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 6372 | | const o = self.object; |
| 6373 | 6176 | const pt = self.pt; |
| 6374 | 6177 | const target = pt.zcu.getTarget(); |
| 6375 | 6178 | |
| ... | ... | @@ -6387,11 +6190,8 @@ fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 6387 | 6190 | |
| 6388 | 6191 | // Load the work_group_* member from the struct as u16. |
| 6389 | 6192 | // Just treat the dispatch pointer as an array of u16 to keep things simple. |
| 6390 | | const workgroup_size_ptr = try self.wip.gep(.inbounds, .i16, dispatch_ptr, &.{ |
| 6391 | | try o.builder.intValue(try o.lowerType(pt, Type.usize), 2 + dimension), |
| 6392 | | }, ""); |
| 6393 | | const workgroup_size_alignment = comptime Builder.Alignment.fromByteUnits(2); |
| 6394 | | return self.wip.load(.normal, .i16, workgroup_size_ptr, workgroup_size_alignment, ""); |
| 6193 | const workgroup_size_ptr = try self.ptraddConst(dispatch_ptr, (2 + dimension) * 2); |
| 6194 | return self.wip.load(.normal, .i16, workgroup_size_ptr, comptime .fromByteUnits(2), ""); |
| 6395 | 6195 | }, |
| 6396 | 6196 | .nvptx, .nvptx64 => { |
| 6397 | 6197 | return self.workIntrinsic(dimension, 1, "nvvm.read.ptx.sreg.ntid"); |
| ... | ... | @@ -6435,88 +6235,45 @@ fn getErrorNameTable(self: *FuncGen) Allocator.Error!Builder.Variable.Index { |
| 6435 | 6235 | return variable_index; |
| 6436 | 6236 | } |
| 6437 | 6237 | |
| 6438 | | /// Assumes the optional is not pointer-like and payload has bits. |
| 6238 | /// Assumes that `Type.optionalReprIsPayload` is `false` for `opt_ty` and that the payload has bits. |
| 6439 | 6239 | fn optCmpNull( |
| 6440 | 6240 | self: *FuncGen, |
| 6441 | 6241 | cond: Builder.IntegerCondition, |
| 6442 | | opt_llvm_ty: Builder.Type, |
| 6443 | | opt_handle: Builder.Value, |
| 6444 | | is_by_ref: bool, |
| 6242 | opt_ty: Type, |
| 6243 | opt_ptr: Builder.Value, |
| 6445 | 6244 | access_kind: Builder.MemoryAccessKind, |
| 6446 | 6245 | ) Allocator.Error!Builder.Value { |
| 6447 | | const o = self.object; |
| 6448 | | const field = b: { |
| 6449 | | if (is_by_ref) { |
| 6450 | | const field_ptr = try self.wip.gepStruct(opt_llvm_ty, opt_handle, 1, ""); |
| 6451 | | break :b try self.wip.load(access_kind, .i8, field_ptr, .default, ""); |
| 6452 | | } |
| 6453 | | break :b try self.wip.extractValue(opt_handle, &.{1}, ""); |
| 6454 | | }; |
| 6246 | const zcu = self.pt.zcu; |
| 6247 | assert(isByRef(opt_ty, zcu)); |
| 6455 | 6248 | comptime assert(optional_layout_version == 3); |
| 6456 | | |
| 6457 | | return self.wip.icmp(cond, field, try o.builder.intValue(.i8, 0), ""); |
| 6249 | // Non-null bit is always after the payload, with no padding because it has alignment 1. |
| 6250 | const non_null_ptr = try self.ptraddConst(opt_ptr, opt_ty.optionalChild(zcu).abiSize(zcu)); |
| 6251 | const non_null = try self.wip.load(access_kind, .i8, non_null_ptr, .default, ""); |
| 6252 | return self.wip.icmp(cond, non_null, try self.object.builder.intValue(.i8, 0), ""); |
| 6458 | 6253 | } |
| 6459 | 6254 | |
| 6460 | | /// Assumes the optional is not pointer-like and payload has bits. |
| 6255 | /// Assumes that `Type.optionalReprIsPayload` is `false` for `opt_ty` and that the payload has bits. |
| 6461 | 6256 | fn optPayloadHandle( |
| 6462 | 6257 | fg: *FuncGen, |
| 6463 | | opt_llvm_ty: Builder.Type, |
| 6464 | | opt_handle: Builder.Value, |
| 6258 | opt_ptr: Builder.Value, |
| 6465 | 6259 | opt_ty: Type, |
| 6466 | 6260 | can_elide_load: bool, |
| 6467 | 6261 | ) !Builder.Value { |
| 6468 | 6262 | const pt = fg.pt; |
| 6469 | 6263 | const zcu = pt.zcu; |
| 6264 | assert(isByRef(opt_ty, zcu)); |
| 6470 | 6265 | const payload_ty = opt_ty.optionalChild(zcu); |
| 6471 | 6266 | |
| 6472 | | if (isByRef(opt_ty, zcu)) { |
| 6473 | | // We have a pointer and we need to return a pointer to the first field. |
| 6474 | | const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, ""); |
| 6475 | | |
| 6476 | | const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm(); |
| 6477 | | if (isByRef(payload_ty, zcu)) { |
| 6478 | | if (can_elide_load) |
| 6479 | | return payload_ptr; |
| 6267 | // Payload is first field so always at the same address as the optional itself. |
| 6268 | const payload_ptr = opt_ptr; |
| 6480 | 6269 | |
| 6481 | | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 6482 | | } |
| 6483 | | return fg.loadTruncate(.normal, payload_ty, payload_ptr, payload_alignment); |
| 6484 | | } |
| 6485 | | |
| 6486 | | assert(!isByRef(payload_ty, zcu)); |
| 6487 | | return fg.wip.extractValue(opt_handle, &.{0}, ""); |
| 6488 | | } |
| 6489 | | |
| 6490 | | fn buildOptional( |
| 6491 | | self: *FuncGen, |
| 6492 | | optional_ty: Type, |
| 6493 | | payload: Builder.Value, |
| 6494 | | non_null_bit: Builder.Value, |
| 6495 | | ) !Builder.Value { |
| 6496 | | const o = self.object; |
| 6497 | | const pt = self.pt; |
| 6498 | | const zcu = pt.zcu; |
| 6499 | | const optional_llvm_ty = try o.lowerType(pt, optional_ty); |
| 6500 | | const non_null_field = try self.wip.cast(.zext, non_null_bit, .i8, ""); |
| 6501 | | |
| 6502 | | if (isByRef(optional_ty, zcu)) { |
| 6503 | | const payload_alignment = optional_ty.abiAlignment(pt.zcu).toLlvm(); |
| 6504 | | const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment); |
| 6505 | | |
| 6506 | | { |
| 6507 | | const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 0, ""); |
| 6508 | | _ = try self.wip.store(.normal, payload, field_ptr, payload_alignment); |
| 6509 | | } |
| 6510 | | { |
| 6511 | | const non_null_alignment = comptime Builder.Alignment.fromByteUnits(1); |
| 6512 | | const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 1, ""); |
| 6513 | | _ = try self.wip.store(.normal, non_null_field, field_ptr, non_null_alignment); |
| 6514 | | } |
| 6515 | | |
| 6516 | | return alloca_inst; |
| 6270 | const payload_align = payload_ty.abiAlignment(zcu).toLlvm(); |
| 6271 | if (isByRef(payload_ty, zcu)) { |
| 6272 | if (can_elide_load) return payload_ptr; |
| 6273 | return fg.loadByRef(payload_ptr, payload_ty, payload_align, .normal); |
| 6274 | } else { |
| 6275 | return fg.loadTruncate(.normal, payload_ty, payload_ptr, payload_align); |
| 6517 | 6276 | } |
| 6518 | | |
| 6519 | | return self.wip.buildAggregate(optional_llvm_ty, &.{ payload, non_null_field }, ""); |
| 6520 | 6277 | } |
| 6521 | 6278 | |
| 6522 | 6279 | fn fieldPtr( |
| ... | ... | @@ -6525,7 +6282,6 @@ fn fieldPtr( |
| 6525 | 6282 | aggregate_ptr_ty: Type, |
| 6526 | 6283 | field_index: u32, |
| 6527 | 6284 | ) !Builder.Value { |
| 6528 | | const o = self.object; |
| 6529 | 6285 | const pt = self.pt; |
| 6530 | 6286 | const zcu = pt.zcu; |
| 6531 | 6287 | const aggregate_ty = aggregate_ptr_ty.childType(zcu); |
| ... | ... | @@ -6534,35 +6290,12 @@ fn fieldPtr( |
| 6534 | 6290 | // bit offset is represented in the pointer *type*. |
| 6535 | 6291 | return aggregate_ptr; |
| 6536 | 6292 | } |
| 6537 | | switch (aggregate_ty.zigTypeTag(zcu)) { |
| 6538 | | .@"struct" => { |
| 6539 | | if (!aggregate_ty.hasRuntimeBits(zcu)) { |
| 6540 | | return aggregate_ptr; |
| 6541 | | } |
| 6542 | | const struct_llvm_ty = try o.lowerType(pt, aggregate_ty); |
| 6543 | | if (o.llvmFieldIndex(aggregate_ty, field_index)) |llvm_field_index| { |
| 6544 | | return self.wip.gepStruct(struct_llvm_ty, aggregate_ptr, llvm_field_index, ""); |
| 6545 | | } else { |
| 6546 | | // If we found no index then this means this is a zero sized field at the |
| 6547 | | // end of the struct. Treat our struct pointer as an array of two and get |
| 6548 | | // the index to the element at index `1` to get a pointer to the end of |
| 6549 | | // the struct. |
| 6550 | | const llvm_index = try o.builder.intValue( |
| 6551 | | try o.lowerType(pt, Type.usize), |
| 6552 | | @intFromBool(aggregate_ty.hasRuntimeBits(zcu)), |
| 6553 | | ); |
| 6554 | | return self.wip.gep(.inbounds, struct_llvm_ty, aggregate_ptr, &.{llvm_index}, ""); |
| 6555 | | } |
| 6556 | | }, |
| 6557 | | .@"union" => { |
| 6558 | | const layout = aggregate_ty.unionGetLayout(zcu); |
| 6559 | | if (layout.payload_size == 0) return aggregate_ptr; |
| 6560 | | const payload_index = @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)); |
| 6561 | | const union_llvm_ty = try o.lowerType(pt, aggregate_ty); |
| 6562 | | return self.wip.gepStruct(union_llvm_ty, aggregate_ptr, payload_index, ""); |
| 6563 | | }, |
| 6293 | const offset: u64 = switch (aggregate_ty.zigTypeTag(zcu)) { |
| 6294 | .@"struct" => aggregate_ty.structFieldOffset(field_index, zcu), |
| 6295 | .@"union" => aggregate_ty.unionGetLayout(zcu).payloadOffset(), |
| 6564 | 6296 | else => unreachable, |
| 6565 | | } |
| 6297 | }; |
| 6298 | return self.ptraddConst(aggregate_ptr, offset); |
| 6566 | 6299 | } |
| 6567 | 6300 | |
| 6568 | 6301 | /// Load a value and, if needed, mask out padding bits for non byte-sized integer values. |
| ... | ... | @@ -6828,11 +6561,8 @@ fn valgrindClientRequest( |
| 6828 | 6561 | break :a array_ptr; |
| 6829 | 6562 | } else fg.valgrind_client_request_array; |
| 6830 | 6563 | const array_elements = [_]Builder.Value{ request, a1, a2, a3, a4, a5 }; |
| 6831 | | const zero = try o.builder.intValue(llvm_usize, 0); |
| 6832 | 6564 | for (array_elements, 0..) |elem, i| { |
| 6833 | | const elem_ptr = try fg.wip.gep(.inbounds, array_llvm_ty, array_ptr, &.{ |
| 6834 | | zero, try o.builder.intValue(llvm_usize, i), |
| 6835 | | }, ""); |
| 6565 | const elem_ptr = try fg.ptraddConst(array_ptr, i * Type.usize.abiSize(zcu)); |
| 6836 | 6566 | _ = try fg.wip.store(.normal, elem, elem_ptr, usize_alignment); |
| 6837 | 6567 | } |
| 6838 | 6568 | |
| ... | ... | @@ -7605,13 +7335,8 @@ pub fn buildAllocaInner( |
| 7605 | 7335 | |
| 7606 | 7336 | /// This is the one source of truth for whether a type is passed around as an LLVM pointer, |
| 7607 | 7337 | /// or as an LLVM value. |
| 7608 | | pub fn isByRef(ty: Type, zcu: *Zcu) bool { |
| 7609 | | // For tuples and structs, if there are more than this many non-void |
| 7610 | | // fields, then we make it byref, otherwise byval. |
| 7611 | | const max_fields_byval = 0; |
| 7612 | | const ip = &zcu.intern_pool; |
| 7613 | | |
| 7614 | | switch (ty.zigTypeTag(zcu)) { |
| 7338 | pub fn isByRef(ty: Type, zcu: *const Zcu) bool { |
| 7339 | return switch (ty.zigTypeTag(zcu)) { |
| 7615 | 7340 | .type, |
| 7616 | 7341 | .comptime_int, |
| 7617 | 7342 | .comptime_float, |
| ... | ... | @@ -7632,62 +7357,24 @@ pub fn isByRef(ty: Type, zcu: *Zcu) bool { |
| 7632 | 7357 | .@"enum", |
| 7633 | 7358 | .vector, |
| 7634 | 7359 | .@"anyframe", |
| 7635 | | => return false, |
| 7636 | | |
| 7637 | | .array, .frame => return ty.hasRuntimeBits(zcu), |
| 7638 | | .@"struct" => { |
| 7639 | | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 7640 | | .tuple_type => |tuple| { |
| 7641 | | var count: usize = 0; |
| 7642 | | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| { |
| 7643 | | if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; |
| 7644 | | |
| 7645 | | count += 1; |
| 7646 | | if (count > max_fields_byval) return true; |
| 7647 | | if (isByRef(Type.fromInterned(field_ty), zcu)) return true; |
| 7648 | | } |
| 7649 | | return false; |
| 7650 | | }, |
| 7651 | | .struct_type => ip.loadStructType(ty.toIntern()), |
| 7652 | | else => unreachable, |
| 7653 | | }; |
| 7360 | => false, |
| 7654 | 7361 | |
| 7655 | | // Packed structs are represented to LLVM as integers. |
| 7656 | | if (struct_type.layout == .@"packed") return false; |
| 7657 | | |
| 7658 | | const field_types = struct_type.field_types.get(ip); |
| 7659 | | var it = struct_type.iterateRuntimeOrder(ip); |
| 7660 | | var count: usize = 0; |
| 7661 | | while (it.next()) |field_index| { |
| 7662 | | count += 1; |
| 7663 | | if (count > max_fields_byval) return true; |
| 7664 | | const field_ty = Type.fromInterned(field_types[field_index]); |
| 7665 | | if (isByRef(field_ty, zcu)) return true; |
| 7666 | | } |
| 7667 | | return false; |
| 7362 | .array, |
| 7363 | .error_union, |
| 7364 | .frame, |
| 7365 | => ty.hasRuntimeBits(zcu), |
| 7366 | |
| 7367 | .optional => ty.hasRuntimeBits(zcu) and !ty.optionalReprIsPayload(zcu), |
| 7368 | |
| 7369 | .@"struct" => switch (ty.containerLayout(zcu)) { |
| 7370 | .@"packed" => false, |
| 7371 | .auto, .@"extern" => ty.hasRuntimeBits(zcu), |
| 7668 | 7372 | }, |
| 7669 | 7373 | .@"union" => switch (ty.containerLayout(zcu)) { |
| 7670 | | .@"packed" => return false, |
| 7671 | | else => return ty.hasRuntimeBits(zcu) and !ty.unionHasAllZeroBitFieldTypes(zcu), |
| 7672 | | }, |
| 7673 | | .error_union => { |
| 7674 | | const payload_ty = ty.errorUnionPayload(zcu); |
| 7675 | | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 7676 | | return false; |
| 7677 | | } |
| 7678 | | return true; |
| 7374 | .@"packed" => false, |
| 7375 | else => ty.hasRuntimeBits(zcu) and !ty.unionHasAllZeroBitFieldTypes(zcu), |
| 7679 | 7376 | }, |
| 7680 | | .optional => { |
| 7681 | | const payload_ty = ty.optionalChild(zcu); |
| 7682 | | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 7683 | | return false; |
| 7684 | | } |
| 7685 | | if (ty.optionalReprIsPayload(zcu)) { |
| 7686 | | return false; |
| 7687 | | } |
| 7688 | | return true; |
| 7689 | | }, |
| 7690 | | } |
| 7377 | }; |
| 7691 | 7378 | } |
| 7692 | 7379 | |
| 7693 | 7380 | /// If the operand type of an atomic operation is not byte sized we need to |
| ... | ... | @@ -7713,16 +7400,27 @@ fn getAtomicAbiType(fg: *const FuncGen, ty: Type, is_rmw_xchg: bool) Allocator.E |
| 7713 | 7400 | } |
| 7714 | 7401 | } |
| 7715 | 7402 | |
| 7716 | | fn errUnionPayloadFieldIndex(payload_ty: Type, pt: Zcu.PerThread) !u1 { |
| 7717 | | const zcu = pt.zcu; |
| 7718 | | const err_int_ty = try pt.errorIntType(); |
| 7719 | | return @intFromBool(err_int_ty.abiAlignment(zcu).compare(.gt, payload_ty.abiAlignment(zcu))); |
| 7403 | fn ptraddConst(fg: *FuncGen, ptr: Builder.Value, offset: u64) Allocator.Error!Builder.Value { |
| 7404 | if (offset == 0) return ptr; |
| 7405 | const llvm_usize_ty = try fg.object.lowerType(fg.pt, .usize); |
| 7406 | const offset_val = try fg.object.builder.intValue(llvm_usize_ty, offset); |
| 7407 | return fg.ptradd(ptr, offset_val); |
| 7720 | 7408 | } |
| 7721 | | |
| 7722 | | fn errUnionErrorFieldIndex(payload_ty: Type, pt: Zcu.PerThread) !u1 { |
| 7723 | | const zcu = pt.zcu; |
| 7724 | | const err_int_ty = try pt.errorIntType(); |
| 7725 | | return @intFromBool(err_int_ty.abiAlignment(zcu).compare(.lte, payload_ty.abiAlignment(zcu))); |
| 7409 | fn ptraddScaled(fg: *FuncGen, ptr: Builder.Value, index: Builder.Value, scale: u64) Allocator.Error!Builder.Value { |
| 7410 | switch (scale) { |
| 7411 | 0 => return ptr, |
| 7412 | 1 => return fg.ptradd(ptr, index), |
| 7413 | else => { |
| 7414 | const o = fg.object; |
| 7415 | const llvm_usize_ty = try o.lowerType(fg.pt, .usize); |
| 7416 | const scale_val = try o.builder.intValue(llvm_usize_ty, scale); |
| 7417 | const offset = try fg.wip.bin(.@"mul nuw", index, scale_val, ""); |
| 7418 | return fg.ptradd(ptr, offset); |
| 7419 | }, |
| 7420 | } |
| 7421 | } |
| 7422 | fn ptradd(fg: *FuncGen, ptr: Builder.Value, offset: Builder.Value) Allocator.Error!Builder.Value { |
| 7423 | return fg.wip.gep(.inbounds, .i8, ptr, &.{offset}, ""); |
| 7726 | 7424 | } |
| 7727 | 7425 | |
| 7728 | 7426 | fn compilerRtIntBits(bits: u16) ?u16 { |
| ... | ... | @@ -8128,6 +7826,7 @@ const Package = @import("../../Package.zig"); |
| 8128 | 7826 | const InternPool = @import("../../InternPool.zig"); |
| 8129 | 7827 | const Value = @import("../../Value.zig"); |
| 8130 | 7828 | const Type = @import("../../Type.zig"); |
| 7829 | const codegen = @import("../../codegen.zig"); |
| 8131 | 7830 | |
| 8132 | 7831 | const target_util = @import("../../target.zig"); |
| 8133 | 7832 | const libcFloatPrefix = target_util.libcFloatPrefix; |