authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-13 21:37:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-13 21:37:11-07:00
log97d69e3352ab50f88580c383b5f375b0edadacfd
tree8245d3d55b3304c19ca18238a01d6532031e1ff8
parenta9a21c59888905e060915dee818633110cc54cfa

stage2: add array_to_slice AIR instruction


10 files changed, 120 insertions(+), 92 deletions(-)

src/Air.zig+4
...@@ -306,6 +306,9 @@ pub const Inst = struct {...@@ -306,6 +306,9 @@ pub const Inst = struct {
306 /// Result type is the element type of the inner pointer operand.306 /// Result type is the element type of the inner pointer operand.
307 /// Uses the `bin_op` field.307 /// Uses the `bin_op` field.
308 ptr_ptr_elem_val,308 ptr_ptr_elem_val,
309 /// Given a pointer to an array, return a slice.
310 /// Uses the `ty_op` field.
311 array_to_slice,
309312
310 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {313 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
311 return switch (op) {314 return switch (op) {
...@@ -526,6 +529,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -526,6 +529,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
526 .struct_field_ptr_index_1,529 .struct_field_ptr_index_1,
527 .struct_field_ptr_index_2,530 .struct_field_ptr_index_2,
528 .struct_field_ptr_index_3,531 .struct_field_ptr_index_3,
532 .array_to_slice,
529 => return air.getRefType(datas[inst].ty_op.ty),533 => return air.getRefType(datas[inst].ty_op.ty),
530534
531 .loop,535 .loop,
src/Liveness.zig+1
...@@ -287,6 +287,7 @@ fn analyzeInst(...@@ -287,6 +287,7 @@ fn analyzeInst(
287 .struct_field_ptr_index_1,287 .struct_field_ptr_index_1,
288 .struct_field_ptr_index_2,288 .struct_field_ptr_index_2,
289 .struct_field_ptr_index_3,289 .struct_field_ptr_index_3,
290 .array_to_slice,
290 => {291 => {
291 const o = inst_datas[inst].ty_op;292 const o = inst_datas[inst].ty_op;
292 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });293 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/Sema.zig+2-1
...@@ -8952,7 +8952,8 @@ fn coerceArrayPtrToSlice(...@@ -8952,7 +8952,8 @@ fn coerceArrayPtrToSlice(
8952 // The comptime Value representation is compatible with both types.8952 // The comptime Value representation is compatible with both types.
8953 return sema.addConstant(dest_type, val);8953 return sema.addConstant(dest_type, val);
8954 }8954 }
8955 return sema.mod.fail(&block.base, inst_src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});8955 try sema.requireRuntimeBlock(block, inst_src);
8956 return block.addTyOp(.array_to_slice, dest_type, inst);
8956}8957}
89578958
8958fn coerceArrayPtrToMany(8959fn coerceArrayPtrToMany(
src/codegen.zig+11
...@@ -856,6 +856,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -856,6 +856,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
856 .store => try self.airStore(inst),856 .store => try self.airStore(inst),
857 .struct_field_ptr=> try self.airStructFieldPtr(inst),857 .struct_field_ptr=> try self.airStructFieldPtr(inst),
858 .struct_field_val=> try self.airStructFieldVal(inst),858 .struct_field_val=> try self.airStructFieldVal(inst),
859 .array_to_slice => try self.airArrayToSlice(inst),
859860
860 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),861 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
861 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),862 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
...@@ -4761,6 +4762,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4761,6 +4762,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4761 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4762 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4762 }4763 }
47634764
4765 fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
4766 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4767 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
4768 else => return self.fail("TODO implement airArrayToSlice for {}", .{
4769 self.target.cpu.arch,
4770 }),
4771 };
4772 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4773 }
4774
4764 fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {4775 fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
4765 // First section of indexes correspond to a set number of constant values.4776 // First section of indexes correspond to a set number of constant values.
4766 const ref_int = @enumToInt(inst);4777 const ref_int = @enumToInt(inst);
src/codegen/c.zig+18
...@@ -910,6 +910,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -910,6 +910,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
910 .switch_br => try airSwitchBr(o, inst),910 .switch_br => try airSwitchBr(o, inst),
911 .wrap_optional => try airWrapOptional(o, inst),911 .wrap_optional => try airWrapOptional(o, inst),
912 .struct_field_ptr => try airStructFieldPtr(o, inst),912 .struct_field_ptr => try airStructFieldPtr(o, inst),
913 .array_to_slice => try airArrayToSlice(o, inst),
913914
914 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),915 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),
915 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),916 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),
...@@ -1860,6 +1861,23 @@ fn airIsErr(...@@ -1860,6 +1861,23 @@ fn airIsErr(
1860 return local;1861 return local;
1861}1862}
18621863
1864fn airArrayToSlice(o: *Object, inst: Air.Inst.Index) !CValue {
1865 if (o.liveness.isUnused(inst))
1866 return CValue.none;
1867
1868 const inst_ty = o.air.typeOfIndex(inst);
1869 const local = try o.allocLocal(inst_ty, .Const);
1870 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1871 const writer = o.writer();
1872 const operand = try o.resolveInst(ty_op.operand);
1873 const array_len = o.air.typeOf(ty_op.operand).elemType().arrayLen();
1874
1875 try writer.writeAll(" = { .ptr = ");
1876 try o.writeCValue(writer, operand);
1877 try writer.print(", .len = {d} }};\n", .{array_len});
1878 return local;
1879}
1880
1863fn IndentWriter(comptime UnderlyingWriter: type) type {1881fn IndentWriter(comptime UnderlyingWriter: type) type {
1864 return struct {1882 return struct {
1865 const Self = @This();1883 const Self = @This();
src/codegen/llvm.zig+41-22
...@@ -1006,28 +1006,29 @@ pub const FuncGen = struct {...@@ -1006,28 +1006,29 @@ pub const FuncGen = struct {
1006 .is_err => try self.airIsErr(inst, .NE, false),1006 .is_err => try self.airIsErr(inst, .NE, false),
1007 .is_err_ptr => try self.airIsErr(inst, .NE, true),1007 .is_err_ptr => try self.airIsErr(inst, .NE, true),
10081008
1009 .alloc => try self.airAlloc(inst),1009 .alloc => try self.airAlloc(inst),
1010 .arg => try self.airArg(inst),1010 .arg => try self.airArg(inst),
1011 .bitcast => try self.airBitCast(inst),1011 .bitcast => try self.airBitCast(inst),
1012 .bool_to_int=> try self.airBoolToInt(inst),1012 .bool_to_int => try self.airBoolToInt(inst),
1013 .block => try self.airBlock(inst),1013 .block => try self.airBlock(inst),
1014 .br => try self.airBr(inst),1014 .br => try self.airBr(inst),
1015 .switch_br => try self.airSwitchBr(inst),1015 .switch_br => try self.airSwitchBr(inst),
1016 .breakpoint => try self.airBreakpoint(inst),1016 .breakpoint => try self.airBreakpoint(inst),
1017 .call => try self.airCall(inst),1017 .call => try self.airCall(inst),
1018 .cond_br => try self.airCondBr(inst),1018 .cond_br => try self.airCondBr(inst),
1019 .intcast => try self.airIntCast(inst),1019 .intcast => try self.airIntCast(inst),
1020 .trunc => try self.airTrunc(inst),1020 .trunc => try self.airTrunc(inst),
1021 .floatcast => try self.airFloatCast(inst),1021 .floatcast => try self.airFloatCast(inst),
1022 .ptrtoint => try self.airPtrToInt(inst),1022 .ptrtoint => try self.airPtrToInt(inst),
1023 .load => try self.airLoad(inst),1023 .load => try self.airLoad(inst),
1024 .loop => try self.airLoop(inst),1024 .loop => try self.airLoop(inst),
1025 .not => try self.airNot(inst),1025 .not => try self.airNot(inst),
1026 .ret => try self.airRet(inst),1026 .ret => try self.airRet(inst),
1027 .store => try self.airStore(inst),1027 .store => try self.airStore(inst),
1028 .assembly => try self.airAssembly(inst),1028 .assembly => try self.airAssembly(inst),
1029 .slice_ptr => try self.airSliceField(inst, 0),1029 .slice_ptr => try self.airSliceField(inst, 0),
1030 .slice_len => try self.airSliceField(inst, 1),1030 .slice_len => try self.airSliceField(inst, 1),
1031 .array_to_slice => try self.airArrayToSlice(inst),
10311032
1032 .struct_field_ptr => try self.airStructFieldPtr(inst),1033 .struct_field_ptr => try self.airStructFieldPtr(inst),
1033 .struct_field_val => try self.airStructFieldVal(inst),1034 .struct_field_val => try self.airStructFieldVal(inst),
...@@ -1246,6 +1247,24 @@ pub const FuncGen = struct {...@@ -1246,6 +1247,24 @@ pub const FuncGen = struct {
1246 return null;1247 return null;
1247 }1248 }
12481249
1250 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1251 if (self.liveness.isUnused(inst))
1252 return null;
1253
1254 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1255 const operand = try self.resolveInst(ty_op.operand);
1256 const array_len = self.air.typeOf(ty_op.operand).elemType().arrayLen();
1257 const usize_llvm_ty = try self.dg.llvmType(Type.initTag(.usize));
1258 const len = usize_llvm_ty.constInt(array_len, .False);
1259 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
1260 const indices: [2]*const llvm.Value = .{
1261 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
1262 };
1263 const ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
1264 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr, 0, "");
1265 return self.builder.buildInsertValue(partial, len, 1, "");
1266 }
1267
1249 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {1268 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
1250 if (self.liveness.isUnused(inst))1269 if (self.liveness.isUnused(inst))
1251 return null;1270 return null;
src/codegen/llvm/bindings.zig+9
...@@ -484,6 +484,15 @@ pub const Builder = opaque {...@@ -484,6 +484,15 @@ pub const Builder = opaque {
484 DestTy: *const Type,484 DestTy: *const Type,
485 Name: [*:0]const u8,485 Name: [*:0]const u8,
486 ) *const Value;486 ) *const Value;
487
488 pub const buildInsertValue = LLVMBuildInsertValue;
489 extern fn LLVMBuildInsertValue(
490 *const Builder,
491 AggVal: *const Value,
492 EltVal: *const Value,
493 Index: c_uint,
494 Name: [*:0]const u8,
495 ) *const Value;
487};496};
488497
489pub const IntPredicate = enum(c_uint) {498pub const IntPredicate = enum(c_uint) {
src/print_air.zig+1
...@@ -174,6 +174,7 @@ const Writer = struct {...@@ -174,6 +174,7 @@ const Writer = struct {
174 .struct_field_ptr_index_1,174 .struct_field_ptr_index_1,
175 .struct_field_ptr_index_2,175 .struct_field_ptr_index_2,
176 .struct_field_ptr_index_3,176 .struct_field_ptr_index_3,
177 .array_to_slice,
177 => try w.writeTyOp(s, inst),178 => try w.writeTyOp(s, inst),
178179
179 .block,180 .block,
test/behavior/array.zig+24
...@@ -3,3 +3,27 @@ const testing = std.testing;...@@ -3,3 +3,27 @@ const testing = std.testing;
3const mem = std.mem;3const mem = std.mem;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
6
7test "arrays" {
8 var array: [5]u32 = undefined;
9
10 var i: u32 = 0;
11 while (i < 5) {
12 array[i] = i + 1;
13 i = array[i];
14 }
15
16 i = 0;
17 var accumulator = @as(u32, 0);
18 while (i < 5) {
19 accumulator += array[i];
20
21 i += 1;
22 }
23
24 try expect(accumulator == 15);
25 try expect(getArrayLen(&array) == 5);
26}
27fn getArrayLen(a: []const u32) usize {
28 return a.len;
29}
test/behavior/array_stage1.zig+9-69
...@@ -4,30 +4,6 @@ const mem = std.mem;...@@ -4,30 +4,6 @@ const mem = std.mem;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
66
7test "arrays" {
8 var array: [5]u32 = undefined;
9
10 var i: u32 = 0;
11 while (i < 5) {
12 array[i] = i + 1;
13 i = array[i];
14 }
15
16 i = 0;
17 var accumulator = @as(u32, 0);
18 while (i < 5) {
19 accumulator += array[i];
20
21 i += 1;
22 }
23
24 try expect(accumulator == 15);
25 try expect(getArrayLen(&array) == 5);
26}
27fn getArrayLen(a: []const u32) usize {
28 return a.len;
29}
30
31test "array with sentinels" {7test "array with sentinels" {
32 const S = struct {8 const S = struct {
33 fn doTheTest(is_ct: bool) !void {9 fn doTheTest(is_ct: bool) !void {
...@@ -64,12 +40,7 @@ test "void arrays" {...@@ -64,12 +40,7 @@ test "void arrays" {
64}40}
6541
66test "array literal" {42test "array literal" {
67 const hex_mult = [_]u16{43 const hex_mult = [_]u16{ 4096, 256, 16, 1 };
68 4096,
69 256,
70 16,
71 1,
72 };
7344
74 try expect(hex_mult.len == 4);45 try expect(hex_mult.len == 4);
75 try expect(hex_mult[1] == 256);46 try expect(hex_mult[1] == 256);
...@@ -84,21 +55,10 @@ test "array dot len const expr" {...@@ -84,21 +55,10 @@ test "array dot len const expr" {
84const ArrayDotLenConstExpr = struct {55const ArrayDotLenConstExpr = struct {
85 y: [some_array.len]u8,56 y: [some_array.len]u8,
86};57};
87const some_array = [_]u8{58const some_array = [_]u8{ 0, 1, 2, 3 };
88 0,
89 1,
90 2,
91 3,
92};
9359
94test "nested arrays" {60test "nested arrays" {
95 const array_of_strings = [_][]const u8{61 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
96 "hello",
97 "this",
98 "is",
99 "my",
100 "thing",
101 };
102 for (array_of_strings) |s, i| {62 for (array_of_strings) |s, i| {
103 if (i == 0) try expect(mem.eql(u8, s, "hello"));63 if (i == 0) try expect(mem.eql(u8, s, "hello"));
104 if (i == 1) try expect(mem.eql(u8, s, "this"));64 if (i == 1) try expect(mem.eql(u8, s, "this"));
...@@ -109,12 +69,8 @@ test "nested arrays" {...@@ -109,12 +69,8 @@ test "nested arrays" {
109}69}
11070
111var s_array: [8]Sub = undefined;71var s_array: [8]Sub = undefined;
112const Sub = struct {72const Sub = struct { b: u8 };
113 b: u8,73const Str = struct { a: []Sub };
114};
115const Str = struct {
116 a: []Sub,
117};
118test "set global var array via slice embedded in struct" {74test "set global var array via slice embedded in struct" {
119 var s = Str{ .a = s_array[0..] };75 var s = Str{ .a = s_array[0..] };
12076
...@@ -208,26 +164,10 @@ test "runtime initialize array elem and then implicit cast to slice" {...@@ -208,26 +164,10 @@ test "runtime initialize array elem and then implicit cast to slice" {
208test "array literal as argument to function" {164test "array literal as argument to function" {
209 const S = struct {165 const S = struct {
210 fn entry(two: i32) !void {166 fn entry(two: i32) !void {
211 try foo(&[_]i32{167 try foo(&[_]i32{ 1, 2, 3 });
212 1,168 try foo(&[_]i32{ 1, two, 3 });
213 2,169 try foo2(true, &[_]i32{ 1, 2, 3 });
214 3,170 try foo2(true, &[_]i32{ 1, two, 3 });
215 });
216 try foo(&[_]i32{
217 1,
218 two,
219 3,
220 });
221 try foo2(true, &[_]i32{
222 1,
223 2,
224 3,
225 });
226 try foo2(true, &[_]i32{
227 1,
228 two,
229 3,
230 });
231 }171 }
232 fn foo(x: []const i32) !void {172 fn foo(x: []const i32) !void {
233 try expect(x[0] == 1);173 try expect(x[0] == 1);