authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-08 17:25:04+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-08 19:56:07-05:00
log2a39d8063d99cd2a2437c581ed9996578faa9a63
tree5c1389b7aefc9c9ca7433b6979283626fad7a7c1
parent7651913fd20c3bd8ee4b2c8bb180c068e3e037a8

wasm: Implement arrays


2 files changed, 138 insertions(+), 28 deletions(-)

src/arch/wasm/CodeGen.zig+134-24
...@@ -915,7 +915,7 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -915,7 +915,7 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
915 },915 },
916 .array => {916 .array => {
917 const elem_vals = val.castTag(.array).?.data;917 const elem_vals = val.castTag(.array).?.data;
918 const elem_ty = ty.elemType();918 const elem_ty = ty.childType();
919 for (elem_vals) |elem_val| {919 for (elem_vals) |elem_val| {
920 switch (try self.genTypedValue(elem_ty, elem_val)) {920 switch (try self.genTypedValue(elem_ty, elem_val)) {
921 .appended => {},921 .appended => {},
...@@ -1269,10 +1269,15 @@ fn isByRef(ty: Type) bool {...@@ -1269,10 +1269,15 @@ fn isByRef(ty: Type) bool {
12691269
1270/// Creates a new local for a pointer that points to memory with given offset.1270/// Creates a new local for a pointer that points to memory with given offset.
1271/// This can be used to get a pointer to a struct field, error payload, etc.1271/// This can be used to get a pointer to a struct field, error payload, etc.
1272fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64) InnerError!WValue {1272/// By providing `modify` as action, it will modify the given `ptr_value` instead of making a new
1273/// local value to store the pointer. This allows for local re-use and improves binary size.
1274fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum { modify, new }) InnerError!WValue {
1273 // do not perform arithmetic when offset is 0.1275 // do not perform arithmetic when offset is 0.
1274 if (offset == 0) return ptr_value;1276 if (offset == 0) return ptr_value;
1275 const result_ptr = try self.allocLocal(Type.usize);1277 const result_ptr: WValue = switch (action) {
1278 .new => try self.allocLocal(Type.usize),
1279 .modify => ptr_value,
1280 };
1276 try self.emitWValue(ptr_value);1281 try self.emitWValue(ptr_value);
1277 switch (self.target.cpu.arch.ptrBitWidth()) {1282 switch (self.target.cpu.arch.ptrBitWidth()) {
1278 32 => {1283 32 => {
...@@ -1289,6 +1294,16 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64) InnerError!WV...@@ -1289,6 +1294,16 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64) InnerError!WV
1289 return result_ptr;1294 return result_ptr;
1290}1295}
12911296
1297/// Creates a new local and sets its value to the given `value` local.
1298/// User must ensure `ty` matches that of given `value`.
1299/// Asserts `value` is a `local`.
1300fn copyLocal(self: *Self, value: WValue, ty: Type) InnerError!WValue {
1301 const copy = try self.allocLocal(ty);
1302 try self.addLabel(.local_get, value.local);
1303 try self.addLabel(.local_set, copy.local);
1304 return copy;
1305}
1306
1292fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {1307fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1293 const air_tags = self.air.instructions.items(.tag);1308 const air_tags = self.air.instructions.items(.tag);
1294 return switch (air_tags[inst]) {1309 return switch (air_tags[inst]) {
...@@ -1312,6 +1327,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1312,6 +1327,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1312 .cmp_lt => self.airCmp(inst, .lt),1327 .cmp_lt => self.airCmp(inst, .lt),
1313 .cmp_neq => self.airCmp(inst, .neq),1328 .cmp_neq => self.airCmp(inst, .neq),
13141329
1330 .array_elem_val => self.airArrayElemVal(inst),
1315 .array_to_slice => self.airArrayToSlice(inst),1331 .array_to_slice => self.airArrayToSlice(inst),
1316 .alloc => self.airAlloc(inst),1332 .alloc => self.airAlloc(inst),
1317 .arg => self.airArg(inst),1333 .arg => self.airArg(inst),
...@@ -1601,8 +1617,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1601,8 +1617,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1601 const tag_local = try self.load(rhs, tag_ty, 0);1617 const tag_local = try self.load(rhs, tag_ty, 0);
1602 if (payload_ty.hasCodeGenBits()) {1618 if (payload_ty.hasCodeGenBits()) {
1603 if (isByRef(payload_ty)) {1619 if (isByRef(payload_ty)) {
1604 const payload_ptr = try self.buildPointerOffset(rhs, payload_offset);1620 const payload_ptr = try self.buildPointerOffset(rhs, payload_offset, .new);
1605 const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset);1621 const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset, .new);
1606 try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0);1622 try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0);
1607 } else {1623 } else {
1608 const payload_local = try self.load(rhs, payload_ty, payload_offset);1624 const payload_local = try self.load(rhs, payload_ty, payload_offset);
...@@ -1632,7 +1648,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1632,7 +1648,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1632 else => unreachable,1648 else => unreachable,
1633 }1649 }
1634 },1650 },
1635 .Struct => {1651 .Struct, .Array => {
1636 if (rhs == .constant) {1652 if (rhs == .constant) {
1637 try self.emitWValue(rhs);1653 try self.emitWValue(rhs);
1638 try self.addLabel(.local_set, lhs.local);1654 try self.addLabel(.local_set, lhs.local);
...@@ -1968,19 +1984,76 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -1968,19 +1984,76 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
1968 const result = try self.allocStack(ty);1984 const result = try self.allocStack(ty);
19691985
1970 const fields = ty.structFields();1986 const fields = ty.structFields();
1971 var offset: u32 = 0;1987 const offset = try self.copyLocal(result, ty);
1972 for (fields.values()) |field, index| {1988 for (fields.values()) |field, index| {
1973 if (isByRef(field.ty)) {
1974 return self.fail("TODO: emitConstant for struct field type {}\n", .{field.ty});
1975 }
1976 const tmp = try self.allocLocal(field.ty);1989 const tmp = try self.allocLocal(field.ty);
1977 try self.emitConstant(struct_data.data[index], field.ty);1990 try self.emitConstant(struct_data.data[index], field.ty);
1978 try self.addLabel(.local_set, tmp.local);1991 try self.addLabel(.local_set, tmp.local);
1979 try self.store(result, tmp, field.ty, offset);1992 try self.store(offset, tmp, field.ty, 0);
1980 offset += @intCast(u32, field.ty.abiSize(self.target));1993
1994 // this prevents us from emitting useless instructions when we reached the end of the loop
1995 if (index != (fields.count() - 1)) {
1996 _ = try self.buildPointerOffset(offset, field.ty.abiSize(self.target), .modify);
1997 }
1981 }1998 }
1982 try self.addLabel(.local_get, result.local);1999 try self.addLabel(.local_get, result.local);
1983 },2000 },
2001 .Array => {
2002 const result = try self.allocStack(ty);
2003 if (val.castTag(.bytes)) |bytes| {
2004 for (bytes.data) |byte, index| {
2005 try self.addLabel(.local_get, result.local);
2006 try self.addImm32(@intCast(i32, byte));
2007 try self.addMemArg(.i32_store8, .{ .offset = @intCast(u32, index), .alignment = 1 });
2008 }
2009 } else if (val.castTag(.array)) |array| {
2010 const elem_ty = ty.childType();
2011 const elem_size = elem_ty.abiSize(self.target);
2012 const tmp = try self.allocLocal(elem_ty);
2013 const offset = try self.copyLocal(result, ty);
2014 for (array.data) |value, index| {
2015 try self.emitConstant(value, elem_ty);
2016 try self.addLabel(.local_set, tmp.local);
2017 try self.store(offset, tmp, elem_ty, 0);
2018
2019 if (index != (array.data.len - 1)) {
2020 _ = try self.buildPointerOffset(offset, elem_size, .modify);
2021 }
2022 }
2023 } else if (val.castTag(.repeated)) |repeated| {
2024 const value = repeated.data;
2025 const elem_ty = ty.childType();
2026 const elem_size = elem_ty.abiSize(self.target);
2027 const sentinel = ty.sentinel();
2028 const len = ty.arrayLen();
2029 const len_with_sent = len + @boolToInt(sentinel != null);
2030 const tmp = try self.allocLocal(elem_ty);
2031 const offset = try self.copyLocal(result, ty);
2032
2033 var index: u32 = 0;
2034 while (index < len_with_sent) : (index += 1) {
2035 if (sentinel != null and index == len) {
2036 try self.emitConstant(sentinel.?, elem_ty);
2037 } else {
2038 try self.emitConstant(value, elem_ty);
2039 }
2040 try self.addLabel(.local_set, tmp.local);
2041 try self.store(offset, tmp, elem_ty, 0);
2042
2043 if (index != (len_with_sent - 1)) {
2044 _ = try self.buildPointerOffset(offset, elem_size, .modify);
2045 }
2046 }
2047 } else if (val.tag() == .empty_array_sentinel) {
2048 const elem_ty = ty.childType();
2049 const sent_val = ty.sentinel().?;
2050 const tmp = try self.allocLocal(elem_ty);
2051 try self.emitConstant(sent_val, elem_ty);
2052 try self.addLabel(.local_set, tmp.local);
2053 try self.store(result, tmp, elem_ty, 0);
2054 } else unreachable;
2055 try self.addLabel(.local_get, result.local);
2056 },
1984 else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),2057 else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
1985 }2058 }
1986}2059}
...@@ -2010,12 +2083,19 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void {...@@ -2010,12 +2083,19 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void {
2010 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))),2083 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))),
2011 else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),2084 else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),
2012 },2085 },
2013 // As arrays point to linear memory, we cannot use 0xaaaaaaaa as the wasm2086 .Array, .Struct => {
2014 // validator will not accept it due to out-of-bounds memory access);
2015 .Array => try self.addImm32(@bitCast(i32, @as(u32, 0xaa))),
2016 .Struct => {
2017 // TODO: Write 0xaa struct's memory
2018 const result = try self.allocStack(ty);2087 const result = try self.allocStack(ty);
2088 const abi_size = ty.abiSize(self.target);
2089 var offset: u32 = 0;
2090 while (offset < abi_size) : (offset += 1) {
2091 try self.emitWValue(result);
2092 try self.addImm32(0xaa);
2093 switch (self.ptrSize()) {
2094 4 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),
2095 8 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),
2096 else => unreachable,
2097 }
2098 }
2019 try self.addLabel(.local_get, result.local);2099 try self.addLabel(.local_get, result.local);
2020 },2100 },
2021 .Pointer => switch (self.ptrSize()) {2101 .Pointer => switch (self.ptrSize()) {
...@@ -2293,7 +2373,7 @@ fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValu...@@ -2293,7 +2373,7 @@ fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValu
2293 },2373 },
2294 else => unreachable,2374 else => unreachable,
2295 };2375 };
2296 return self.buildPointerOffset(.{ .local = local }, final_offset);2376 return self.buildPointerOffset(.{ .local = local }, final_offset, .new);
2297}2377}
22982378
2299fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2379fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2528,7 +2608,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2528,7 +2608,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2528 const offset = err_ty.errorUnionSet().abiSize(self.target);2608 const offset = err_ty.errorUnionSet().abiSize(self.target);
25292609
2530 const err_union = try self.allocStack(err_ty);2610 const err_union = try self.allocStack(err_ty);
2531 const payload_ptr = try self.buildPointerOffset(err_union, offset);2611 const payload_ptr = try self.buildPointerOffset(err_union, offset, .new);
2532 try self.store(payload_ptr, operand, op_ty, 0);2612 try self.store(payload_ptr, operand, op_ty, 0);
25332613
2534 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.2614 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.
...@@ -2620,7 +2700,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2620,7 +2700,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2620 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);2700 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
26212701
2622 if (isByRef(payload_ty)) {2702 if (isByRef(payload_ty)) {
2623 return self.buildPointerOffset(operand, offset);2703 return self.buildPointerOffset(operand, offset, .new);
2624 }2704 }
26252705
2626 return self.load(operand, payload_ty, @intCast(u32, offset));2706 return self.load(operand, payload_ty, @intCast(u32, offset));
...@@ -2640,7 +2720,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2640,7 +2720,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2640 }2720 }
26412721
2642 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);2722 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
2643 return self.buildPointerOffset(operand, offset);2723 return self.buildPointerOffset(operand, offset, .new);
2644}2724}
26452725
2646fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2726fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2665,7 +2745,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -2665,7 +2745,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
2665 try self.addImm32(1);2745 try self.addImm32(1);
2666 try self.addMemArg(.i32_store8, .{ .offset = 0, .alignment = 1 });2746 try self.addMemArg(.i32_store8, .{ .offset = 0, .alignment = 1 });
26672747
2668 return self.buildPointerOffset(operand, offset);2748 return self.buildPointerOffset(operand, offset, .new);
2669}2749}
26702750
2671fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2751fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2696,7 +2776,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2696,7 +2776,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2696 try self.addImm32(1);2776 try self.addImm32(1);
2697 try self.addMemArg(.i32_store8, .{ .offset = 0, .alignment = 1 });2777 try self.addMemArg(.i32_store8, .{ .offset = 0, .alignment = 1 });
26982778
2699 const payload_ptr = try self.buildPointerOffset(result, offset);2779 const payload_ptr = try self.buildPointerOffset(result, offset, .new);
2700 try self.store(payload_ptr, operand, payload_ty, 0);2780 try self.store(payload_ptr, operand, payload_ty, 0);
27012781
2702 return result;2782 return result;
...@@ -2952,7 +3032,11 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -2952,7 +3032,11 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
2952 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3032 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2953 const ptr = self.resolveInst(bin_op.lhs);3033 const ptr = self.resolveInst(bin_op.lhs);
2954 const offset = self.resolveInst(bin_op.rhs);3034 const offset = self.resolveInst(bin_op.rhs);
2955 const pointee_ty = self.air.typeOf(bin_op.lhs).childType();3035 const ptr_ty = self.air.typeOf(bin_op.lhs);
3036 const pointee_ty = switch (ptr_ty.ptrSize()) {
3037 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
3038 else => ptr_ty.childType(),
3039 };
29563040
2957 const valtype = try self.typeToValtype(Type.usize);3041 const valtype = try self.typeToValtype(Type.usize);
2958 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });3042 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });
...@@ -3036,3 +3120,29 @@ fn memSet(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void...@@ -3036,3 +3120,29 @@ fn memSet(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void
3036 try self.endBlock();3120 try self.endBlock();
3037 try self.endBlock();3121 try self.endBlock();
3038}3122}
3123
3124fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3125 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3126
3127 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3128 const array_ty = self.air.typeOf(bin_op.lhs);
3129 const array = self.resolveInst(bin_op.lhs);
3130 const index = self.resolveInst(bin_op.rhs);
3131 const elem_ty = array_ty.childType();
3132 const elem_size = elem_ty.abiSize(self.target);
3133
3134 // calculate index into slice
3135 try self.emitWValue(array);
3136 try self.emitWValue(index);
3137 try self.addImm32(@bitCast(i32, @intCast(u32, elem_size)));
3138 try self.addTag(.i32_mul);
3139 try self.addTag(.i32_add);
3140
3141 const result = try self.allocLocal(elem_ty);
3142 try self.addLabel(.local_set, result.local);
3143
3144 if (isByRef(elem_ty)) {
3145 return result;
3146 }
3147 return try self.load(result, elem_ty, 0);
3148}
test/behavior.zig+4-4
...@@ -16,6 +16,7 @@ test {...@@ -16,6 +16,7 @@ test {
1616
17 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {17 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
18 // Tests that pass for stage1, llvm backend, C backend, wasm backend.18 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
19 _ = @import("behavior/array.zig");
19 _ = @import("behavior/bugs/3586.zig");20 _ = @import("behavior/bugs/3586.zig");
20 _ = @import("behavior/basic.zig");21 _ = @import("behavior/basic.zig");
21 _ = @import("behavior/bitcast.zig");22 _ = @import("behavior/bitcast.zig");
...@@ -27,6 +28,7 @@ test {...@@ -27,6 +28,7 @@ test {
27 _ = @import("behavior/bugs/2692.zig");28 _ = @import("behavior/bugs/2692.zig");
28 _ = @import("behavior/bugs/2889.zig");29 _ = @import("behavior/bugs/2889.zig");
29 _ = @import("behavior/bugs/3046.zig");30 _ = @import("behavior/bugs/3046.zig");
31 _ = @import("behavior/bugs/4560.zig");
30 _ = @import("behavior/bugs/4769_a.zig");32 _ = @import("behavior/bugs/4769_a.zig");
31 _ = @import("behavior/bugs/4769_b.zig");33 _ = @import("behavior/bugs/4769_b.zig");
32 _ = @import("behavior/bugs/4954.zig");34 _ = @import("behavior/bugs/4954.zig");
...@@ -35,6 +37,7 @@ test {...@@ -35,6 +37,7 @@ test {
35 _ = @import("behavior/defer.zig");37 _ = @import("behavior/defer.zig");
36 _ = @import("behavior/enum.zig");38 _ = @import("behavior/enum.zig");
37 _ = @import("behavior/error.zig");39 _ = @import("behavior/error.zig");
40 _ = @import("behavior/for.zig");
38 _ = @import("behavior/generics.zig");41 _ = @import("behavior/generics.zig");
39 _ = @import("behavior/if.zig");42 _ = @import("behavior/if.zig");
40 _ = @import("behavior/import.zig");43 _ = @import("behavior/import.zig");
...@@ -48,6 +51,7 @@ test {...@@ -48,6 +51,7 @@ test {
48 _ = @import("behavior/struct.zig");51 _ = @import("behavior/struct.zig");
49 _ = @import("behavior/this.zig");52 _ = @import("behavior/this.zig");
50 _ = @import("behavior/truncate.zig");53 _ = @import("behavior/truncate.zig");
54 _ = @import("behavior/undefined.zig");
51 _ = @import("behavior/underscore.zig");55 _ = @import("behavior/underscore.zig");
52 _ = @import("behavior/usingnamespace.zig");56 _ = @import("behavior/usingnamespace.zig");
53 _ = @import("behavior/void.zig");57 _ = @import("behavior/void.zig");
...@@ -56,15 +60,11 @@ test {...@@ -56,15 +60,11 @@ test {
56 if (builtin.zig_backend != .stage2_wasm) {60 if (builtin.zig_backend != .stage2_wasm) {
57 // Tests that pass for stage1, llvm backend, C backend61 // Tests that pass for stage1, llvm backend, C backend
58 _ = @import("behavior/align.zig");62 _ = @import("behavior/align.zig");
59 _ = @import("behavior/array.zig");
60 _ = @import("behavior/bugs/4560.zig");
61 _ = @import("behavior/cast.zig");63 _ = @import("behavior/cast.zig");
62 _ = @import("behavior/for.zig");
63 _ = @import("behavior/int128.zig");64 _ = @import("behavior/int128.zig");
64 _ = @import("behavior/optional.zig");65 _ = @import("behavior/optional.zig");
65 _ = @import("behavior/translate_c_macros.zig");66 _ = @import("behavior/translate_c_macros.zig");
66 _ = @import("behavior/try.zig");67 _ = @import("behavior/try.zig");
67 _ = @import("behavior/undefined.zig");
68 _ = @import("behavior/src.zig");68 _ = @import("behavior/src.zig");
6969
70 if (builtin.zig_backend != .stage2_c) {70 if (builtin.zig_backend != .stage2_c) {