authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-01 18:24:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-01 18:24:00-07:00
log6f303c01f3e06fe8203563065ea32537f6eff456
treec1e85221ff40bfd5be043a6f7429e2b3e4d94024
parent8878f085dccaf9efe89a04b458205fddc215e095

LLVM: add extra padding to structs and tuples sometimes

* Sema: resolve type fully when emitting an alloc AIR instruction to avoid tripping assertion for checking struct field alignment. * LLVM backend: keep a reference to the LLVM target data alive during lowering so that we can ask LLVM what it thinks the ABI alignment and size of LLVM types are. We need this in order to lower tuples and structs so that we can put in extra padding bytes when Zig disagrees with LLVM about the size or alignment of something. * LLVM backend: make the LLVM struct type packed that contains the most aligned union field and the padding. This prevents the struct from being too big according to LLVM. In the future, we may want to consider instead emitting unions in a "flat" manner; putting the tag, most aligned union field, and padding all in the same struct field space. * LLVM backend: make structs with 2 or fewer fields return isByRef=false. This results in more efficient codegen. This required lowering of bitcast to sometimes store the struct into an alloca, ptrcast, and then load because LLVM does not allow bitcasting structs. * enable more passing behavior tests.

15 files changed, 327 insertions(+), 133 deletions(-)

src/Sema.zig+2-2
...@@ -2439,7 +2439,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -2439,7 +2439,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
2439 .@"addrspace" = target_util.defaultAddressSpace(target, .local),2439 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
2440 });2440 });
2441 try sema.requireRuntimeBlock(block, var_decl_src);2441 try sema.requireRuntimeBlock(block, var_decl_src);
2442 try sema.resolveTypeLayout(block, ty_src, var_ty);2442 try sema.resolveTypeFully(block, ty_src, var_ty);
2443 return block.addTy(.alloc, ptr_type);2443 return block.addTy(.alloc, ptr_type);
2444}2444}
24452445
...@@ -2461,7 +2461,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -2461,7 +2461,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2461 .@"addrspace" = target_util.defaultAddressSpace(target, .local),2461 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
2462 });2462 });
2463 try sema.requireRuntimeBlock(block, var_decl_src);2463 try sema.requireRuntimeBlock(block, var_decl_src);
2464 try sema.resolveTypeLayout(block, ty_src, var_ty);2464 try sema.resolveTypeFully(block, ty_src, var_ty);
2465 return block.addTy(.alloc, ptr_type);2465 return block.addTy(.alloc, ptr_type);
2466}2466}
24672467
src/codegen/llvm.zig+278-99
...@@ -160,6 +160,7 @@ pub const Object = struct {...@@ -160,6 +160,7 @@ pub const Object = struct {
160 llvm_module: *const llvm.Module,160 llvm_module: *const llvm.Module,
161 context: *const llvm.Context,161 context: *const llvm.Context,
162 target_machine: *const llvm.TargetMachine,162 target_machine: *const llvm.TargetMachine,
163 target_data: *const llvm.TargetData,
163 /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,164 /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,
164 /// but that has some downsides:165 /// but that has some downsides:
165 /// * we have to compute the fully qualified name every time we want to do the lookup166 /// * we have to compute the fully qualified name every time we want to do the lookup
...@@ -258,7 +259,7 @@ pub const Object = struct {...@@ -258,7 +259,7 @@ pub const Object = struct {
258 errdefer target_machine.dispose();259 errdefer target_machine.dispose();
259260
260 const target_data = target_machine.createTargetDataLayout();261 const target_data = target_machine.createTargetDataLayout();
261 defer target_data.dispose();262 errdefer target_data.dispose();
262263
263 llvm_module.setModuleDataLayout(target_data);264 llvm_module.setModuleDataLayout(target_data);
264265
...@@ -266,6 +267,7 @@ pub const Object = struct {...@@ -266,6 +267,7 @@ pub const Object = struct {
266 .llvm_module = llvm_module,267 .llvm_module = llvm_module,
267 .context = context,268 .context = context,
268 .target_machine = target_machine,269 .target_machine = target_machine,
270 .target_data = target_data,
269 .decl_map = .{},271 .decl_map = .{},
270 .type_map = .{},272 .type_map = .{},
271 .type_map_arena = std.heap.ArenaAllocator.init(gpa),273 .type_map_arena = std.heap.ArenaAllocator.init(gpa),
...@@ -274,6 +276,7 @@ pub const Object = struct {...@@ -274,6 +276,7 @@ pub const Object = struct {
274 }276 }
275277
276 pub fn deinit(self: *Object, gpa: Allocator) void {278 pub fn deinit(self: *Object, gpa: Allocator) void {
279 self.target_data.dispose();
277 self.target_machine.dispose();280 self.target_machine.dispose();
278 self.llvm_module.dispose();281 self.llvm_module.dispose();
279 self.context.dispose();282 self.context.dispose();
...@@ -955,20 +958,55 @@ pub const DeclGen = struct {...@@ -955,20 +958,55 @@ pub const DeclGen = struct {
955 // reference, we need to copy it here.958 // reference, we need to copy it here.
956 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());959 gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
957960
958 if (t.castTag(.tuple)) |tuple| {961 if (t.isTuple()) {
962 const tuple = t.tupleFields();
959 const llvm_struct_ty = dg.context.structCreateNamed("");963 const llvm_struct_ty = dg.context.structCreateNamed("");
960 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls964 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
961965
962 const types = tuple.data.types;966 var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
963 const values = tuple.data.values;
964 var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, types.len);
965 defer llvm_field_types.deinit(gpa);967 defer llvm_field_types.deinit(gpa);
966968
967 for (types) |field_ty, i| {969 try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
968 const field_val = values[i];970
971 // We need to insert extra padding if LLVM's isn't enough.
972 var zig_offset: u64 = 0;
973 var llvm_offset: u64 = 0;
974 var zig_big_align: u32 = 0;
975 var llvm_big_align: u32 = 0;
976
977 for (tuple.types) |field_ty, i| {
978 const field_val = tuple.values[i];
969 if (field_val.tag() != .unreachable_value) continue;979 if (field_val.tag() != .unreachable_value) continue;
970980
971 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field_ty));981 const field_align = field_ty.abiAlignment(target);
982 zig_big_align = @maximum(zig_big_align, field_align);
983 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align);
984
985 const field_llvm_ty = try dg.llvmType(field_ty);
986 const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty);
987 llvm_big_align = @maximum(llvm_big_align, field_llvm_align);
988 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align);
989
990 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
991 if (padding_len > 0) {
992 const llvm_array_ty = dg.context.intType(8).arrayType(padding_len);
993 try llvm_field_types.append(gpa, llvm_array_ty);
994 llvm_offset = zig_offset;
995 }
996 try llvm_field_types.append(gpa, field_llvm_ty);
997
998 llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty);
999 zig_offset += field_ty.abiSize(target);
1000 }
1001 {
1002 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, zig_big_align);
1003 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, llvm_big_align);
1004 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
1005 if (padding_len > 0) {
1006 const llvm_array_ty = dg.context.intType(8).arrayType(padding_len);
1007 try llvm_field_types.append(gpa, llvm_array_ty);
1008 llvm_offset = zig_offset;
1009 }
972 }1010 }
9731011
974 llvm_struct_ty.structSetBody(1012 llvm_struct_ty.structSetBody(
...@@ -998,12 +1036,49 @@ pub const DeclGen = struct {...@@ -998,12 +1036,49 @@ pub const DeclGen = struct {
9981036
999 assert(struct_obj.haveFieldTypes());1037 assert(struct_obj.haveFieldTypes());
10001038
1001 var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, struct_obj.fields.count());1039 var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
1002 defer llvm_field_types.deinit(gpa);1040 defer llvm_field_types.deinit(gpa);
10031041
1042 try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count());
1043
1044 // We need to insert extra padding if LLVM's isn't enough.
1045 var zig_offset: u64 = 0;
1046 var llvm_offset: u64 = 0;
1047 var zig_big_align: u32 = 0;
1048 var llvm_big_align: u32 = 0;
1049
1004 for (struct_obj.fields.values()) |field| {1050 for (struct_obj.fields.values()) |field| {
1005 if (!field.ty.hasRuntimeBits()) continue;1051 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
1006 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));1052
1053 const field_align = field.normalAlignment(target);
1054 zig_big_align = @maximum(zig_big_align, field_align);
1055 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align);
1056
1057 const field_llvm_ty = try dg.llvmType(field.ty);
1058 const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty);
1059 llvm_big_align = @maximum(llvm_big_align, field_llvm_align);
1060 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align);
1061
1062 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
1063 if (padding_len > 0) {
1064 const llvm_array_ty = dg.context.intType(8).arrayType(padding_len);
1065 try llvm_field_types.append(gpa, llvm_array_ty);
1066 llvm_offset = zig_offset;
1067 }
1068 try llvm_field_types.append(gpa, field_llvm_ty);
1069
1070 llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty);
1071 zig_offset += field.ty.abiSize(target);
1072 }
1073 {
1074 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, zig_big_align);
1075 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, llvm_big_align);
1076 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
1077 if (padding_len > 0) {
1078 const llvm_array_ty = dg.context.intType(8).arrayType(padding_len);
1079 try llvm_field_types.append(gpa, llvm_array_ty);
1080 llvm_offset = zig_offset;
1081 }
1007 }1082 }
10081083
1009 llvm_struct_ty.structSetBody(1084 llvm_struct_ty.structSetBody(
...@@ -1050,7 +1125,7 @@ pub const DeclGen = struct {...@@ -1050,7 +1125,7 @@ pub const DeclGen = struct {
1050 llvm_aligned_field_ty,1125 llvm_aligned_field_ty,
1051 dg.context.intType(8).arrayType(padding_len),1126 dg.context.intType(8).arrayType(padding_len),
1052 };1127 };
1053 break :t dg.context.structType(&fields, fields.len, .False);1128 break :t dg.context.structType(&fields, fields.len, .True);
1054 };1129 };
10551130
1056 if (layout.tag_size == 0) {1131 if (layout.tag_size == 0) {
...@@ -1461,9 +1536,9 @@ pub const DeclGen = struct {...@@ -1461,9 +1536,9 @@ pub const DeclGen = struct {
1461 const field_vals = tv.val.castTag(.@"struct").?.data;1536 const field_vals = tv.val.castTag(.@"struct").?.data;
1462 const gpa = dg.gpa;1537 const gpa = dg.gpa;
1463 const struct_obj = tv.ty.castTag(.@"struct").?.data;1538 const struct_obj = tv.ty.castTag(.@"struct").?.data;
1539 const target = dg.module.getTarget();
14641540
1465 if (struct_obj.layout == .Packed) {1541 if (struct_obj.layout == .Packed) {
1466 const target = dg.module.getTarget();
1467 const big_bits = struct_obj.packedIntegerBits(target);1542 const big_bits = struct_obj.packedIntegerBits(target);
1468 const int_llvm_ty = dg.context.intType(big_bits);1543 const int_llvm_ty = dg.context.intType(big_bits);
1469 const fields = struct_obj.fields.values();1544 const fields = struct_obj.fields.values();
...@@ -1497,19 +1572,56 @@ pub const DeclGen = struct {...@@ -1497,19 +1572,56 @@ pub const DeclGen = struct {
1497 var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count);1572 var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count);
1498 defer llvm_fields.deinit(gpa);1573 defer llvm_fields.deinit(gpa);
14991574
1575 // These are used to detect where the extra padding fields are so that we
1576 // can initialize them with undefined.
1577 var zig_offset: u64 = 0;
1578 var llvm_offset: u64 = 0;
1579 var zig_big_align: u32 = 0;
1580 var llvm_big_align: u32 = 0;
1581
1500 var need_unnamed = false;1582 var need_unnamed = false;
1501 for (field_vals) |field_val, i| {1583 for (struct_obj.fields.values()) |field, i| {
1502 const field_ty = tv.ty.structFieldType(i);1584 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
1503 if (!field_ty.hasRuntimeBits()) continue;1585
1586 const field_align = field.normalAlignment(target);
1587 zig_big_align = @maximum(zig_big_align, field_align);
1588 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align);
1589
1590 const field_llvm_ty = try dg.llvmType(field.ty);
1591 const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty);
1592 llvm_big_align = @maximum(llvm_big_align, field_llvm_align);
1593 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align);
1594
1595 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
1596 if (padding_len > 0) {
1597 const llvm_array_ty = dg.context.intType(8).arrayType(padding_len);
1598 // TODO make this and all other padding elsewhere in debug
1599 // builds be 0xaa not undef.
1600 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
1601 llvm_offset = zig_offset;
1602 }
15041603
1505 const field_llvm_val = try dg.genTypedValue(.{1604 const field_llvm_val = try dg.genTypedValue(.{
1506 .ty = field_ty,1605 .ty = field.ty,
1507 .val = field_val,1606 .val = field_vals[i],
1508 });1607 });
15091608
1510 need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val);1609 need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val);
15111610
1512 llvm_fields.appendAssumeCapacity(field_llvm_val);1611 llvm_fields.appendAssumeCapacity(field_llvm_val);
1612
1613 llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty);
1614 zig_offset += field.ty.abiSize(target);
1615 }
1616 {
1617 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, zig_big_align);
1618 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, llvm_big_align);
1619 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
1620 if (padding_len > 0) {
1621 const llvm_array_ty = dg.context.intType(8).arrayType(padding_len);
1622 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
1623 llvm_offset = zig_offset;
1624 }
1513 }1625 }
15141626
1515 if (need_unnamed) {1627 if (need_unnamed) {
...@@ -1556,7 +1668,7 @@ pub const DeclGen = struct {...@@ -1556,7 +1668,7 @@ pub const DeclGen = struct {
1556 const fields: [2]*const llvm.Value = .{1668 const fields: [2]*const llvm.Value = .{
1557 field, dg.context.intType(8).arrayType(padding_len).getUndef(),1669 field, dg.context.intType(8).arrayType(padding_len).getUndef(),
1558 };1670 };
1559 break :p dg.context.constStruct(&fields, fields.len, .False);1671 break :p dg.context.constStruct(&fields, fields.len, .True);
1560 };1672 };
15611673
1562 // In this case we must make an unnamed struct because LLVM does1674 // In this case we must make an unnamed struct because LLVM does
...@@ -1741,7 +1853,7 @@ pub const DeclGen = struct {...@@ -1741,7 +1853,7 @@ pub const DeclGen = struct {
1741 },1853 },
1742 .Struct => {1854 .Struct => {
1743 var ty_buf: Type.Payload.Pointer = undefined;1855 var ty_buf: Type.Payload.Pointer = undefined;
1744 const llvm_field_index = llvmFieldIndex(parent.ty, field_index, target, &ty_buf).?;1856 const llvm_field_index = dg.llvmFieldIndex(parent.ty, field_index, &ty_buf).?;
1745 const indices: [2]*const llvm.Value = .{1857 const indices: [2]*const llvm.Value = .{
1746 llvm_u32.constInt(0, .False),1858 llvm_u32.constInt(0, .False),
1747 llvm_u32.constInt(llvm_field_index, .False),1859 llvm_u32.constInt(llvm_field_index, .False),
...@@ -1972,6 +2084,107 @@ pub const DeclGen = struct {...@@ -1972,6 +2084,107 @@ pub const DeclGen = struct {
1972 return null;2084 return null;
1973 }2085 }
1974 }2086 }
2087
2088 /// Take into account 0 bit fields and padding. Returns null if an llvm
2089 /// field could not be found.
2090 /// This only happens if you want the field index of a zero sized field at
2091 /// the end of the struct.
2092 fn llvmFieldIndex(
2093 dg: *DeclGen,
2094 ty: Type,
2095 field_index: u32,
2096 ptr_pl_buf: *Type.Payload.Pointer,
2097 ) ?c_uint {
2098 const target = dg.module.getTarget();
2099
2100 // Detects where we inserted extra padding fields so that we can skip
2101 // over them in this function.
2102 var zig_offset: u64 = 0;
2103 var llvm_offset: u64 = 0;
2104 var zig_big_align: u32 = 0;
2105 var llvm_big_align: u32 = 0;
2106
2107 if (ty.isTuple()) {
2108 const tuple = ty.tupleFields();
2109 var llvm_field_index: c_uint = 0;
2110 for (tuple.types) |field_ty, i| {
2111 if (tuple.values[i].tag() != .unreachable_value) continue;
2112
2113 const field_align = field_ty.abiAlignment(target);
2114 zig_big_align = @maximum(zig_big_align, field_align);
2115 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align);
2116
2117 // assert no error because we have already seen a successful
2118 // llvmType on this field.
2119 const field_llvm_ty = dg.llvmType(field_ty) catch unreachable;
2120 const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty);
2121 llvm_big_align = @maximum(llvm_big_align, field_llvm_align);
2122 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align);
2123
2124 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
2125 if (padding_len > 0) {
2126 llvm_field_index += 1;
2127 llvm_offset = zig_offset;
2128 }
2129
2130 if (field_index == i) {
2131 ptr_pl_buf.* = .{
2132 .data = .{
2133 .pointee_type = field_ty,
2134 .@"align" = field_align,
2135 .@"addrspace" = .generic,
2136 },
2137 };
2138 return llvm_field_index;
2139 }
2140
2141 llvm_field_index += 1;
2142 llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty);
2143 zig_offset += field_ty.abiSize(target);
2144 }
2145 return null;
2146 }
2147 assert(ty.containerLayout() != .Packed);
2148
2149 var llvm_field_index: c_uint = 0;
2150 for (ty.structFields().values()) |field, i| {
2151 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
2152
2153 const field_align = field.normalAlignment(target);
2154 zig_big_align = @maximum(zig_big_align, field_align);
2155 zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align);
2156
2157 // assert no error because we have already seen a successful llvmType on this field.
2158 const field_llvm_ty = dg.llvmType(field.ty) catch unreachable;
2159 const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty);
2160 llvm_big_align = @maximum(llvm_big_align, field_llvm_align);
2161 llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align);
2162
2163 const padding_len = @intCast(c_uint, zig_offset - llvm_offset);
2164 if (padding_len > 0) {
2165 llvm_field_index += 1;
2166 llvm_offset = zig_offset;
2167 }
2168
2169 if (field_index == i) {
2170 ptr_pl_buf.* = .{
2171 .data = .{
2172 .pointee_type = field.ty,
2173 .@"align" = field_align,
2174 .@"addrspace" = .generic,
2175 },
2176 };
2177 return llvm_field_index;
2178 }
2179
2180 llvm_field_index += 1;
2181 llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty);
2182 zig_offset += field.ty.abiSize(target);
2183 } else {
2184 // We did not find an llvm field that corresponds to this zig field.
2185 return null;
2186 }
2187 }
1975};2188};
19762189
1977pub const FuncGen = struct {2190pub const FuncGen = struct {
...@@ -2850,7 +3063,7 @@ pub const FuncGen = struct {...@@ -2850,7 +3063,7 @@ pub const FuncGen = struct {
2850 },3063 },
2851 else => {3064 else => {
2852 var ptr_ty_buf: Type.Payload.Pointer = undefined;3065 var ptr_ty_buf: Type.Payload.Pointer = undefined;
2853 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;3066 const llvm_field_index = self.dg.llvmFieldIndex(struct_ty, field_index, &ptr_ty_buf).?;
2854 return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");3067 return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");
2855 },3068 },
2856 },3069 },
...@@ -2865,7 +3078,7 @@ pub const FuncGen = struct {...@@ -2865,7 +3078,7 @@ pub const FuncGen = struct {
2865 .Struct => {3078 .Struct => {
2866 assert(struct_ty.containerLayout() != .Packed);3079 assert(struct_ty.containerLayout() != .Packed);
2867 var ptr_ty_buf: Type.Payload.Pointer = undefined;3080 var ptr_ty_buf: Type.Payload.Pointer = undefined;
2868 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;3081 const llvm_field_index = self.dg.llvmFieldIndex(struct_ty, field_index, &ptr_ty_buf).?;
2869 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");3082 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
2870 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);3083 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
2871 return self.load(field_ptr, field_ptr_ty);3084 return self.load(field_ptr, field_ptr_ty);
...@@ -3916,6 +4129,7 @@ pub const FuncGen = struct {...@@ -3916,6 +4129,7 @@ pub const FuncGen = struct {
3916 const operand_is_ref = isByRef(operand_ty);4129 const operand_is_ref = isByRef(operand_ty);
3917 const result_is_ref = isByRef(inst_ty);4130 const result_is_ref = isByRef(inst_ty);
3918 const llvm_dest_ty = try self.dg.llvmType(inst_ty);4131 const llvm_dest_ty = try self.dg.llvmType(inst_ty);
4132 const target = self.dg.module.getTarget();
39194133
3920 if (operand_is_ref and result_is_ref) {4134 if (operand_is_ref and result_is_ref) {
3921 // They are both pointers; just do a bitcast on the pointers :)4135 // They are both pointers; just do a bitcast on the pointers :)
...@@ -3927,7 +4141,6 @@ pub const FuncGen = struct {...@@ -3927,7 +4141,6 @@ pub const FuncGen = struct {
3927 }4141 }
39284142
3929 if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) {4143 if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) {
3930 const target = self.dg.module.getTarget();
3931 const elem_ty = operand_ty.childType();4144 const elem_ty = operand_ty.childType();
3932 if (!result_is_ref) {4145 if (!result_is_ref) {
3933 return self.dg.todo("implement bitcast vector to non-ref array", .{});4146 return self.dg.todo("implement bitcast vector to non-ref array", .{});
...@@ -3957,7 +4170,6 @@ pub const FuncGen = struct {...@@ -3957,7 +4170,6 @@ pub const FuncGen = struct {
3957 }4170 }
3958 return array_ptr;4171 return array_ptr;
3959 } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {4172 } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {
3960 const target = self.dg.module.getTarget();
3961 const elem_ty = operand_ty.childType();4173 const elem_ty = operand_ty.childType();
3962 const llvm_vector_ty = try self.dg.llvmType(inst_ty);4174 const llvm_vector_ty = try self.dg.llvmType(inst_ty);
3963 if (!operand_is_ref) {4175 if (!operand_is_ref) {
...@@ -3998,18 +4210,39 @@ pub const FuncGen = struct {...@@ -3998,18 +4210,39 @@ pub const FuncGen = struct {
3998 if (operand_is_ref) {4210 if (operand_is_ref) {
3999 // Bitcast the operand pointer, then load.4211 // Bitcast the operand pointer, then load.
4000 const casted_ptr = self.builder.buildBitCast(operand, llvm_dest_ty.pointerType(0), "");4212 const casted_ptr = self.builder.buildBitCast(operand, llvm_dest_ty.pointerType(0), "");
4001 return self.builder.buildLoad(casted_ptr, "");4213 const load_inst = self.builder.buildLoad(casted_ptr, "");
4214 load_inst.setAlignment(operand_ty.abiAlignment(target));
4215 return load_inst;
4002 }4216 }
40034217
4004 if (result_is_ref) {4218 if (result_is_ref) {
4005 // Bitcast the result pointer, then store.4219 // Bitcast the result pointer, then store.
4220 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
4006 const result_ptr = self.buildAlloca(llvm_dest_ty);4221 const result_ptr = self.buildAlloca(llvm_dest_ty);
4222 result_ptr.setAlignment(alignment);
4007 const operand_llvm_ty = try self.dg.llvmType(operand_ty);4223 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
4008 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");4224 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
4009 _ = self.builder.buildStore(operand, casted_ptr);4225 const store_inst = self.builder.buildStore(operand, casted_ptr);
4226 store_inst.setAlignment(alignment);
4010 return result_ptr;4227 return result_ptr;
4011 }4228 }
40124229
4230 if (llvm_dest_ty.getTypeKind() == .Struct) {
4231 // Both our operand and our result are values, not pointers,
4232 // but LLVM won't let us bitcast struct values.
4233 // Therefore, we store operand to bitcasted alloca, then load for result.
4234 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
4235 const result_ptr = self.buildAlloca(llvm_dest_ty);
4236 result_ptr.setAlignment(alignment);
4237 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
4238 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
4239 const store_inst = self.builder.buildStore(operand, casted_ptr);
4240 store_inst.setAlignment(alignment);
4241 const load_inst = self.builder.buildLoad(result_ptr, "");
4242 load_inst.setAlignment(alignment);
4243 return load_inst;
4244 }
4245
4013 return self.builder.buildBitCast(operand, llvm_dest_ty, "");4246 return self.builder.buildBitCast(operand, llvm_dest_ty, "");
4014 }4247 }
40154248
...@@ -5009,9 +5242,8 @@ pub const FuncGen = struct {...@@ -5009,9 +5242,8 @@ pub const FuncGen = struct {
5009 return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");5242 return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");
5010 },5243 },
5011 else => {5244 else => {
5012 const target = self.dg.module.getTarget();
5013 var ty_buf: Type.Payload.Pointer = undefined;5245 var ty_buf: Type.Payload.Pointer = undefined;
5014 if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {5246 if (self.dg.llvmFieldIndex(struct_ty, field_index, &ty_buf)) |llvm_field_index| {
5015 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");5247 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
5016 } else {5248 } else {
5017 // If we found no index then this means this is a zero sized field at the5249 // If we found no index then this means this is a zero sized field at the
...@@ -5422,63 +5654,6 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca...@@ -5422,63 +5654,6 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
5422 };5654 };
5423}5655}
54245656
5425/// Take into account 0 bit fields. Returns null if an llvm field could not be found. This only
5426/// happens if you want the field index of a zero sized field at the end of the struct.
5427fn llvmFieldIndex(
5428 ty: Type,
5429 field_index: u32,
5430 target: std.Target,
5431 ptr_pl_buf: *Type.Payload.Pointer,
5432) ?c_uint {
5433 if (ty.castTag(.tuple)) |payload| {
5434 const values = payload.data.values;
5435 var llvm_field_index: c_uint = 0;
5436 for (values) |val, i| {
5437 if (val.tag() != .unreachable_value) {
5438 continue;
5439 }
5440 if (field_index > i) {
5441 llvm_field_index += 1;
5442 continue;
5443 }
5444 const field_ty = payload.data.types[i];
5445 ptr_pl_buf.* = .{
5446 .data = .{
5447 .pointee_type = field_ty,
5448 .@"align" = field_ty.abiAlignment(target),
5449 .@"addrspace" = .generic,
5450 },
5451 };
5452 return llvm_field_index;
5453 }
5454 return null;
5455 }
5456 const struct_obj = ty.castTag(.@"struct").?.data;
5457 assert(struct_obj.layout != .Packed);
5458
5459 var llvm_field_index: c_uint = 0;
5460 for (struct_obj.fields.values()) |field, i| {
5461 if (!field.ty.hasRuntimeBits())
5462 continue;
5463 if (field_index > i) {
5464 llvm_field_index += 1;
5465 continue;
5466 }
5467
5468 ptr_pl_buf.* = .{
5469 .data = .{
5470 .pointee_type = field.ty,
5471 .@"align" = field.normalAlignment(target),
5472 .@"addrspace" = .generic,
5473 },
5474 };
5475 return llvm_field_index;
5476 } else {
5477 // We did not find an llvm field that corresponds to this zig field.
5478 return null;
5479 }
5480}
5481
5482fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {5657fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
5483 switch (fn_info.cc) {5658 switch (fn_info.cc) {
5484 .Unspecified, .Inline => return isByRef(fn_info.return_type),5659 .Unspecified, .Inline => return isByRef(fn_info.return_type),
...@@ -5497,7 +5672,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool...@@ -5497,7 +5672,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
5497}5672}
54985673
5499fn isByRef(ty: Type) bool {5674fn isByRef(ty: Type) bool {
5500 // For tuples (and TODO structs), if there are more than this many non-void5675 // For tuples and structs, if there are more than this many non-void
5501 // fields, then we make it byref, otherwise byval.5676 // fields, then we make it byref, otherwise byval.
5502 const max_fields_byval = 2;5677 const max_fields_byval = 2;
55035678
...@@ -5529,24 +5704,28 @@ fn isByRef(ty: Type) bool {...@@ -5529,24 +5704,28 @@ fn isByRef(ty: Type) bool {
5529 .Struct => {5704 .Struct => {
5530 // Packed structs are represented to LLVM as integers.5705 // Packed structs are represented to LLVM as integers.
5531 if (ty.containerLayout() == .Packed) return false;5706 if (ty.containerLayout() == .Packed) return false;
55325707 if (ty.isTuple()) {
5533 if (!ty.hasRuntimeBits()) return false;5708 const tuple = ty.tupleFields();
5534 if (ty.castTag(.tuple)) |tuple| {
5535 var count: usize = 0;5709 var count: usize = 0;
5536 for (tuple.data.values) |field_val, i| {5710 for (tuple.values) |field_val, i| {
5537 if (field_val.tag() != .unreachable_value) continue;5711 if (field_val.tag() != .unreachable_value) continue;
5712
5538 count += 1;5713 count += 1;
5539 if (count > max_fields_byval) {5714 if (count > max_fields_byval) return true;
5540 return true;5715 if (isByRef(tuple.types[i])) return true;
5541 }
5542 const field_ty = tuple.data.types[i];
5543 if (isByRef(field_ty)) {
5544 return true;
5545 }
5546 }5716 }
5547 return false;5717 return false;
5548 }5718 }
5549 return true;5719 var count: usize = 0;
5720 const fields = ty.structFields();
5721 for (fields.values()) |field| {
5722 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
5723
5724 count += 1;
5725 if (count > max_fields_byval) return true;
5726 if (isByRef(field.ty)) return true;
5727 }
5728 return false;
5550 },5729 },
5551 .Union => return ty.hasRuntimeBits(),5730 .Union => return ty.hasRuntimeBits(),
5552 .ErrorUnion => return isByRef(ty.errorUnionPayload()),5731 .ErrorUnion => return isByRef(ty.errorUnionPayload()),
src/codegen/llvm/bindings.zig+6
...@@ -916,6 +916,12 @@ pub const TargetMachine = opaque {...@@ -916,6 +916,12 @@ pub const TargetMachine = opaque {
916pub const TargetData = opaque {916pub const TargetData = opaque {
917 pub const dispose = LLVMDisposeTargetData;917 pub const dispose = LLVMDisposeTargetData;
918 extern fn LLVMDisposeTargetData(*const TargetData) void;918 extern fn LLVMDisposeTargetData(*const TargetData) void;
919
920 pub const ABISizeOfType = LLVMABISizeOfType;
921 extern fn LLVMABISizeOfType(TD: *const TargetData, Ty: *const Type) c_ulonglong;
922
923 pub const ABIAlignmentOfType = LLVMABIAlignmentOfType;
924 extern fn LLVMABIAlignmentOfType(TD: *const TargetData, Ty: *const Type) c_uint;
919};925};
920926
921pub const CodeModel = enum(c_int) {927pub const CodeModel = enum(c_int) {
src/type.zig+1-1
...@@ -4400,7 +4400,7 @@ pub const Type = extern union {...@@ -4400,7 +4400,7 @@ pub const Type = extern union {
4400 };4400 };
44014401
4402 /// Get an iterator that iterates over all the struct field, returning the field and4402 /// Get an iterator that iterates over all the struct field, returning the field and
4403 /// offset of that field. Asserts that the type is a none packed struct.4403 /// offset of that field. Asserts that the type is a non-packed struct.
4404 pub fn iterateStructOffsets(ty: Type, target: Target) StructOffsetIterator {4404 pub fn iterateStructOffsets(ty: Type, target: Target) StructOffsetIterator {
4405 const struct_obj = ty.castTag(.@"struct").?.data;4405 const struct_obj = ty.castTag(.@"struct").?.data;
4406 assert(struct_obj.haveLayout());4406 assert(struct_obj.haveLayout());
test/behavior/basic.zig-2
...@@ -778,8 +778,6 @@ extern var opaque_extern_var: opaque {};...@@ -778,8 +778,6 @@ extern var opaque_extern_var: opaque {};
778var var_to_export: u32 = 42;778var var_to_export: u32 = 42;
779779
780test "lazy typeInfo value as generic parameter" {780test "lazy typeInfo value as generic parameter" {
781 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
782
783 const S = struct {781 const S = struct {
784 fn foo(args: anytype) void {782 fn foo(args: anytype) void {
785 _ = args;783 _ = args;
test/behavior/bugs/394.zig+1-1
...@@ -10,7 +10,7 @@ const S = struct {...@@ -10,7 +10,7 @@ const S = struct {
10const expect = @import("std").testing.expect;10const expect = @import("std").testing.expect;
11const builtin = @import("builtin");11const builtin = @import("builtin");
1212
13test "bug 394 fixed" {13test "fixed" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/for.zig+7-2
...@@ -157,7 +157,9 @@ test "2 break statements and an else" {...@@ -157,7 +157,9 @@ test "2 break statements and an else" {
157}157}
158158
159test "for loop with pointer elem var" {159test "for loop with pointer elem var" {
160 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO160 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
161163
162 const source = "abcdefg";164 const source = "abcdefg";
163 var target: [source.len]u8 = undefined;165 var target: [source.len]u8 = undefined;
...@@ -199,7 +201,10 @@ test "for copies its payload" {...@@ -199,7 +201,10 @@ test "for copies its payload" {
199}201}
200202
201test "for on slice with allowzero ptr" {203test "for on slice with allowzero ptr" {
202 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO204 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
203208
204 const S = struct {209 const S = struct {
205 fn doTheTest(slice: []const u8) !void {210 fn doTheTest(slice: []const u8) !void {
test/behavior/if.zig-2
...@@ -106,8 +106,6 @@ test "if copies its payload" {...@@ -106,8 +106,6 @@ test "if copies its payload" {
106}106}
107107
108test "if prongs cast to expected type instead of peer type resolution" {108test "if prongs cast to expected type instead of peer type resolution" {
109 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
110
111 const S = struct {109 const S = struct {
112 fn doTheTest(f: bool) !void {110 fn doTheTest(f: bool) !void {
113 var x: i32 = 0;111 var x: i32 = 0;
test/behavior/optional.zig+12-8
...@@ -251,7 +251,9 @@ test "coerce an anon struct literal to optional struct" {...@@ -251,7 +251,9 @@ test "coerce an anon struct literal to optional struct" {
251}251}
252252
253test "0-bit child type coerced to optional return ptr result location" {253test "0-bit child type coerced to optional return ptr result location" {
254 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO254 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
255257
256 const S = struct {258 const S = struct {
257 fn doTheTest() !void {259 fn doTheTest() !void {
...@@ -300,7 +302,9 @@ test "0-bit child type coerced to optional" {...@@ -300,7 +302,9 @@ test "0-bit child type coerced to optional" {
300}302}
301303
302test "array of optional unaligned types" {304test "array of optional unaligned types" {
303 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO305 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
306 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
307 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
304308
305 const Enum = enum { one, two, three };309 const Enum = enum { one, two, three };
306310
...@@ -320,15 +324,15 @@ test "array of optional unaligned types" {...@@ -320,15 +324,15 @@ test "array of optional unaligned types" {
320324
321 // The index must be a runtime value325 // The index must be a runtime value
322 var i: usize = 0;326 var i: usize = 0;
323 try expectEqual(Enum.one, values[i].?.Num);327 try expect(Enum.one == values[i].?.Num);
324 i += 1;328 i += 1;
325 try expectEqual(Enum.two, values[i].?.Num);329 try expect(Enum.two == values[i].?.Num);
326 i += 1;330 i += 1;
327 try expectEqual(Enum.three, values[i].?.Num);331 try expect(Enum.three == values[i].?.Num);
328 i += 1;332 i += 1;
329 try expectEqual(Enum.one, values[i].?.Num);333 try expect(Enum.one == values[i].?.Num);
330 i += 1;334 i += 1;
331 try expectEqual(Enum.two, values[i].?.Num);335 try expect(Enum.two == values[i].?.Num);
332 i += 1;336 i += 1;
333 try expectEqual(Enum.three, values[i].?.Num);337 try expect(Enum.three == values[i].?.Num);
334}338}
test/behavior/ptrcast.zig+5-1
...@@ -41,7 +41,11 @@ fn testReinterpretBytesAsExternStruct() !void {...@@ -41,7 +41,11 @@ fn testReinterpretBytesAsExternStruct() !void {
41}41}
4242
43test "reinterpret struct field at comptime" {43test "reinterpret struct field at comptime" {
44 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4549
46 const numNative = comptime Bytes.init(0x12345678);50 const numNative = comptime Bytes.init(0x12345678);
47 if (native_endian != .Little) {51 if (native_endian != .Little) {
test/behavior/reflection.zig-2
...@@ -5,8 +5,6 @@ const mem = std.mem;...@@ -5,8 +5,6 @@ const mem = std.mem;
5const reflection = @This();5const reflection = @This();
66
7test "reflection: function return type, var args, and param types" {7test "reflection: function return type, var args, and param types" {
8 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
9
10 comptime {8 comptime {
11 const info = @typeInfo(@TypeOf(dummy)).Fn;9 const info = @typeInfo(@TypeOf(dummy)).Fn;
12 try expect(info.return_type.? == i32);10 try expect(info.return_type.? == i32);
test/behavior/sizeof_and_typeof.zig-4
...@@ -180,8 +180,6 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" {...@@ -180,8 +180,6 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" {
180}180}
181181
182test "@TypeOf() has no runtime side effects" {182test "@TypeOf() has no runtime side effects" {
183 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
184
185 const S = struct {183 const S = struct {
186 fn foo(comptime T: type, ptr: *T) T {184 fn foo(comptime T: type, ptr: *T) T {
187 ptr.* += 1;185 ptr.* += 1;
...@@ -195,8 +193,6 @@ test "@TypeOf() has no runtime side effects" {...@@ -195,8 +193,6 @@ test "@TypeOf() has no runtime side effects" {
195}193}
196194
197test "branching logic inside @TypeOf" {195test "branching logic inside @TypeOf" {
198 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
199
200 const S = struct {196 const S = struct {
201 var data: i32 = 0;197 var data: i32 = 0;
202 fn foo() anyerror!i32 {198 fn foo() anyerror!i32 {
test/behavior/struct.zig+6-2
...@@ -857,7 +857,9 @@ test "fn with C calling convention returns struct by value" {...@@ -857,7 +857,9 @@ test "fn with C calling convention returns struct by value" {
857}857}
858858
859test "non-packed struct with u128 entry in union" {859test "non-packed struct with u128 entry in union" {
860 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO860 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
861 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
862 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
861863
862 const U = union(enum) {864 const U = union(enum) {
863 Num: u128,865 Num: u128,
...@@ -952,7 +954,9 @@ test "fully anonymous struct" {...@@ -952,7 +954,9 @@ test "fully anonymous struct" {
952}954}
953955
954test "fully anonymous list literal" {956test "fully anonymous list literal" {
955 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO957 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
958 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
956960
957 const S = struct {961 const S = struct {
958 fn doTheTest() !void {962 fn doTheTest() !void {
test/behavior/type.zig-4
...@@ -138,8 +138,6 @@ test "Type.Array" {...@@ -138,8 +138,6 @@ test "Type.Array" {
138}138}
139139
140test "@Type create slice with null sentinel" {140test "@Type create slice with null sentinel" {
141 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
142
143 const Slice = @Type(TypeInfo{141 const Slice = @Type(TypeInfo{
144 .Pointer = .{142 .Pointer = .{
145 .size = .Slice,143 .size = .Slice,
...@@ -156,8 +154,6 @@ test "@Type create slice with null sentinel" {...@@ -156,8 +154,6 @@ test "@Type create slice with null sentinel" {
156}154}
157155
158test "@Type picks up the sentinel value from TypeInfo" {156test "@Type picks up the sentinel value from TypeInfo" {
159 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
160
161 try testTypes(&[_]type{157 try testTypes(&[_]type{
162 [11:0]u8, [4:10]u8,158 [11:0]u8, [4:10]u8,
163 [*:0]u8, [*:0]const u8,159 [*:0]u8, [*:0]const u8,
test/behavior/var_args.zig+9-3
...@@ -13,7 +13,9 @@ fn add(args: anytype) i32 {...@@ -13,7 +13,9 @@ fn add(args: anytype) i32 {
13}13}
1414
15test "add arbitrary args" {15test "add arbitrary args" {
16 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1719
18 try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);20 try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
19 try expect(add(.{@as(i32, 1234)}) == 1234);21 try expect(add(.{@as(i32, 1234)}) == 1234);
...@@ -34,7 +36,9 @@ test "send void arg to var args" {...@@ -34,7 +36,9 @@ test "send void arg to var args" {
34}36}
3537
36test "pass args directly" {38test "pass args directly" {
37 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO39 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3842
39 try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);43 try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
40 try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234);44 try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234);
...@@ -46,7 +50,9 @@ fn addSomeStuff(args: anytype) i32 {...@@ -46,7 +50,9 @@ fn addSomeStuff(args: anytype) i32 {
46}50}
4751
48test "runtime parameter before var args" {52test "runtime parameter before var args" {
49 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5056
51 try expect((try extraFn(10, .{})) == 0);57 try expect((try extraFn(10, .{})) == 0);
52 try expect((try extraFn(10, .{false})) == 1);58 try expect((try extraFn(10, .{false})) == 1);