authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-19 19:41:55-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-19 19:41:55-04:00
log1bd595ceea7a0d888d09cd54e3ee39a548beb0db
tree5b76237d149084ec9acf4ed2581919144734d6a9
parent19331b323d15b0fa0bae7add37a03528256a119f
parent2fc91a09a2bcefdd2af2370cf6d24bc23e186425
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11233 from Luukdegram/wasm-tests

stage2: wasm - union_init and passing tests

6 files changed, 147 insertions(+), 67 deletions(-)

src/arch/wasm/CodeGen.zig+146-51
......@@ -1818,18 +1818,103 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
18181818 return bin_local;
18191819}
18201820
1821fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {
1822 switch (ptr_val.tag()) {
1823 .decl_ref_mut => {
1824 const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
1825 return self.lowerParentPtrDecl(ptr_val, decl);
1826 },
1827 .decl_ref => {
1828 const decl = ptr_val.castTag(.decl_ref).?.data;
1829 return self.lowerParentPtrDecl(ptr_val, decl);
1830 },
1831 .variable => {
1832 const decl = ptr_val.castTag(.variable).?.data.owner_decl;
1833 return self.lowerParentPtrDecl(ptr_val, decl);
1834 },
1835 .field_ptr => {
1836 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1837 const parent_ty = field_ptr.container_ty;
1838 const parent_ptr = try self.lowerParentPtr(field_ptr.container_ptr, parent_ty);
1839
1840 const offset = switch (parent_ty.zigTypeTag()) {
1841 .Struct => blk: {
1842 const offset = parent_ty.structFieldOffset(field_ptr.field_index, self.target);
1843 break :blk offset;
1844 },
1845 .Union => blk: {
1846 const layout: Module.Union.Layout = parent_ty.unionGetLayout(self.target);
1847 if (layout.payload_size == 0) break :blk 0;
1848 if (layout.payload_align > layout.tag_align) break :blk 0;
1849
1850 // tag is stored first so calculate offset from where payload starts
1851 const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
1852 break :blk offset;
1853 },
1854 else => unreachable,
1855 };
1856
1857 return switch (parent_ptr) {
1858 .memory => |ptr| WValue{
1859 .memory_offset = .{
1860 .pointer = ptr,
1861 .offset = @intCast(u32, offset),
1862 },
1863 },
1864 .memory_offset => |mem_off| WValue{
1865 .memory_offset = .{
1866 .pointer = mem_off.pointer,
1867 .offset = @intCast(u32, offset) + mem_off.offset,
1868 },
1869 },
1870 else => unreachable,
1871 };
1872 },
1873 .elem_ptr => {
1874 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
1875 const index = elem_ptr.index;
1876 const offset = index * ptr_child_ty.abiSize(self.target);
1877 const array_ptr = try self.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
1878
1879 return WValue{ .memory_offset = .{
1880 .pointer = array_ptr.memory,
1881 .offset = @intCast(u32, offset),
1882 } };
1883 },
1884 else => |tag| return self.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),
1885 }
1886}
1887
1888fn lowerParentPtrDecl(self: *Self, ptr_val: Value, decl: *Module.Decl) InnerError!WValue {
1889 decl.markAlive();
1890 var ptr_ty_payload: Type.Payload.ElemType = .{
1891 .base = .{ .tag = .single_mut_pointer },
1892 .data = decl.ty,
1893 };
1894 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
1895 return self.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl);
1896}
1897
1898fn lowerDeclRefValue(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!WValue {
1899 if (tv.ty.isSlice()) {
1900 return WValue{ .memory = try self.bin_file.lowerUnnamedConst(self.decl, tv) };
1901 } else if (decl.ty.zigTypeTag() != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime()) {
1902 return WValue{ .imm32 = 0xaaaaaaaa };
1903 }
1904
1905 decl.markAlive();
1906 const target_sym_index = decl.link.wasm.sym_index;
1907 if (decl.ty.zigTypeTag() == .Fn) {
1908 try self.bin_file.addTableFunction(target_sym_index);
1909 return WValue{ .function_index = target_sym_index };
1910 } else return WValue{ .memory = target_sym_index };
1911}
1912
18211913fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
18221914 if (val.isUndefDeep()) return self.emitUndefined(ty);
18231915 if (val.castTag(.decl_ref)) |decl_ref| {
18241916 const decl = decl_ref.data;
1825 decl.markAlive();
1826 const target_sym_index = decl.link.wasm.sym_index;
1827 if (ty.isSlice()) {
1828 return WValue{ .memory = try self.bin_file.lowerUnnamedConst(self.decl, .{ .ty = ty, .val = val }) };
1829 } else if (decl.ty.zigTypeTag() == .Fn) {
1830 try self.bin_file.addTableFunction(target_sym_index);
1831 return WValue{ .function_index = target_sym_index };
1832 } else return WValue{ .memory = target_sym_index };
1917 return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl);
18331918 }
18341919
18351920 switch (ty.zigTypeTag()) {
......@@ -1856,37 +1941,8 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
18561941 else => unreachable,
18571942 },
18581943 .Pointer => switch (val.tag()) {
1859 .elem_ptr => {
1860 const elem_ptr = val.castTag(.elem_ptr).?.data;
1861 const index = elem_ptr.index;
1862 const offset = index * ty.childType().abiSize(self.target);
1863 const array_ptr = try self.lowerConstant(elem_ptr.array_ptr, ty);
1864
1865 return WValue{ .memory_offset = .{
1866 .pointer = array_ptr.memory,
1867 .offset = @intCast(u32, offset),
1868 } };
1869 },
1870 .field_ptr => {
1871 const field_ptr = val.castTag(.field_ptr).?.data;
1872 const container = field_ptr.container_ptr;
1873 const parent_ptr = try self.lowerConstant(container, ty);
1874
1875 const offset = switch (container.tag()) {
1876 .decl_ref => blk: {
1877 const decl_ref = container.castTag(.decl_ref).?.data;
1878 if (decl_ref.ty.castTag(.@"struct")) |_| {
1879 const offset = decl_ref.ty.structFieldOffset(field_ptr.field_index, self.target);
1880 break :blk offset;
1881 }
1882 return self.fail("Wasm TODO: field_ptr decl_ref for type '{}'", .{decl_ref.ty});
1883 },
1884 else => |tag| return self.fail("Wasm TODO: Implement field_ptr for value tag: '{s}'", .{tag}),
1885 };
1886 return WValue{ .memory_offset = .{
1887 .pointer = parent_ptr.memory,
1888 .offset = @intCast(u32, offset),
1889 } };
1944 .field_ptr, .elem_ptr => {
1945 return self.lowerParentPtr(val, ty.childType());
18901946 },
18911947 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
18921948 .zero, .null_value => return WValue{ .imm32 = 0 },
......@@ -1999,6 +2055,11 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 {
19992055 return self.valueAsI32(tag_val, enum_full.tag_ty);
20002056 } else return @bitCast(i32, field_index.data);
20012057 },
2058 .enum_numbered => {
2059 const index = field_index.data;
2060 const enum_data = ty.castTag(.enum_numbered).?.data;
2061 return self.valueAsI32(enum_data.values.keys()[index], enum_data.tag_ty);
2062 },
20022063 else => unreachable,
20032064 }
20042065 } else {
......@@ -2124,8 +2185,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
21242185 return self.cmpBigInt(lhs, rhs, operand_ty, op);
21252186 }
21262187
2127 try self.emitWValue(lhs);
2128 try self.emitWValue(rhs);
2188 // ensure that when we compare pointers, we emit
2189 // the true pointer of a stack value, rather than the stack pointer.
2190 switch (lhs) {
2191 .stack_offset => try self.emitWValue(try self.buildPointerOffset(lhs, 0, .new)),
2192 else => try self.emitWValue(lhs),
2193 }
2194 switch (rhs) {
2195 .stack_offset => try self.emitWValue(try self.buildPointerOffset(rhs, 0, .new)),
2196 else => try self.emitWValue(rhs),
2197 }
21292198
21302199 const signedness: std.builtin.Signedness = blk: {
21312200 // by default we tell the operand type is unsigned (i.e. bools and enum values)
......@@ -3161,16 +3230,16 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31613230fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31623231 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
31633232
3164 const vector_ty = self.air.typeOfIndex(inst);
3165 const len = vector_ty.vectorLen();
31663233 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3234 const result_ty = self.air.typeOfIndex(inst);
3235 const len = @intCast(usize, result_ty.arrayLen());
31673236 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
31683237
3169 switch (vector_ty.zigTypeTag()) {
3238 switch (result_ty.zigTypeTag()) {
31703239 .Vector => return self.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
31713240 .Array => {
3172 const result = try self.allocStack(vector_ty);
3173 const elem_ty = vector_ty.childType();
3241 const result = try self.allocStack(result_ty);
3242 const elem_ty = result_ty.childType();
31743243 const elem_size = @intCast(u32, elem_ty.abiSize(self.target));
31753244
31763245 // When the element type is by reference, we must copy the entire
......@@ -3199,13 +3268,12 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31993268 return result;
32003269 },
32013270 .Struct => {
3202 const tuple = vector_ty.castTag(.tuple).?.data;
3203 const result = try self.allocStack(vector_ty);
3271 const result = try self.allocStack(result_ty);
32043272 const offset = try self.buildPointerOffset(result, 0, .new); // pointer to offset
32053273 for (elements) |elem, elem_index| {
3206 if (tuple.values[elem_index].tag() != .unreachable_value) continue;
3274 if (result_ty.structFieldValueComptime(elem_index) != null) continue;
32073275
3208 const elem_ty = tuple.types[elem_index];
3276 const elem_ty = result_ty.structFieldType(elem_index);
32093277 const elem_size = @intCast(u32, elem_ty.abiSize(self.target));
32103278 const value = try self.resolveInst(elem);
32113279 try self.store(offset, value, elem_ty, 0);
......@@ -3223,7 +3291,34 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32233291
32243292fn airUnionInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32253293 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3226 return self.fail("TODO: Wasm backend: implement airUnionInit", .{});
3294
3295 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3296 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
3297 const union_ty = self.air.typeOfIndex(inst);
3298 const layout = union_ty.unionGetLayout(self.target);
3299 if (layout.payload_size == 0) {
3300 if (layout.tag_size == 0) {
3301 return WValue{ .none = {} };
3302 }
3303 assert(!isByRef(union_ty, self.target));
3304 return WValue{ .imm32 = extra.field_index };
3305 }
3306 assert(isByRef(union_ty, self.target));
3307
3308 const result_ptr = try self.allocStack(union_ty);
3309 const payload = try self.resolveInst(extra.init);
3310 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
3311 assert(union_obj.haveFieldTypes());
3312 const field = union_obj.fields.values()[extra.field_index];
3313
3314 if (layout.tag_align >= layout.payload_align) {
3315 const payload_ptr = try self.buildPointerOffset(result_ptr, layout.tag_size, .new);
3316 try self.store(payload_ptr, payload, field.ty, 0);
3317 } else {
3318 try self.store(result_ptr, payload, field.ty, 0);
3319 }
3320
3321 return result_ptr;
32273322}
32283323
32293324fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
src/codegen.zig+1-2
......@@ -530,8 +530,7 @@ pub fn generateSymbol(
530530 return Result{ .appended = {} };
531531 },
532532 .Struct => {
533 const struct_obj = typed_value.ty.castTag(.@"struct").?.data;
534 if (struct_obj.layout == .Packed) {
533 if (typed_value.ty.containerLayout() == .Packed) {
535534 return Result{
536535 .fail = try ErrorMsg.create(
537536 bin_file.allocator,
test/behavior/array.zig-2
......@@ -455,7 +455,6 @@ test "type deduction for array subscript expression" {
455455test "sentinel element count towards the ABI size calculation" {
456456 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
457457 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
459458 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
460459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
461460
......@@ -537,7 +536,6 @@ test "type coercion of anon struct literal to array" {
537536}
538537
539538test "type coercion of pointer to anon struct literal to pointer to array" {
540 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
541539 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
542540 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
543541 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/slice.zig-2
......@@ -188,7 +188,6 @@ const y = x[0x100..];
188188test "compile time slice of pointer to hard coded address" {
189189 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
190190 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
192191
193192 try expect(@ptrToInt(x) == 0x1000);
194193 try expect(x.len == 0x500);
......@@ -496,7 +495,6 @@ test "slice syntax resulting in pointer-to-array" {
496495}
497496
498497test "type coercion of pointer to anon struct literal to pointer to slice" {
499 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
500498 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
501499 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
502500 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/tuple.zig-3
......@@ -4,7 +4,6 @@ const testing = std.testing;
44const expect = testing.expect;
55
66test "tuple concatenation" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -48,7 +47,6 @@ test "tuple multiplication" {
4847}
4948
5049test "more tuple concatenation" {
51 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
5250 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -126,7 +124,6 @@ test "tuple initializer for var" {
126124}
127125
128126test "array-like initializer for tuple types" {
129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
130127 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
131128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
132129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/union.zig-7
......@@ -436,7 +436,6 @@ test "global union with single field is correctly initialized" {
436436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
437437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
438438
439 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
440439 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
441440
442441 glbl = Foo1{
......@@ -453,7 +452,6 @@ pub const FooUnion = union(enum) {
453452var glbl_array: [2]FooUnion = undefined;
454453
455454test "initialize global array of union" {
456 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
457455 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
458456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
459457 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
......@@ -610,7 +608,6 @@ test "tagged union with all void fields but a meaningful tag" {
610608}
611609
612610test "union(enum(u32)) with specified and unspecified tag values" {
613 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
614611 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
615612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
616613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
......@@ -783,7 +780,6 @@ test "return union init with void payload" {
783780}
784781
785782test "@unionInit stored to a const" {
786 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
787783 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
788784 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
789785 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -945,7 +941,6 @@ test "function call result coerces from tagged union to the tag" {
945941}
946942
947943test "cast from anonymous struct to union" {
948 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
949944 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
950945 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
951946 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -978,7 +973,6 @@ test "cast from anonymous struct to union" {
978973}
979974
980975test "cast from pointer to anonymous struct to pointer to union" {
981 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
982976 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
983977 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
984978 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -1120,7 +1114,6 @@ test "union enum type gets a separate scope" {
11201114
11211115test "global variable struct contains union initialized to non-most-aligned field" {
11221116 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1123 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11241117 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11251118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11261119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO