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 {
306306 /// Result type is the element type of the inner pointer operand.
307307 /// Uses the `bin_op` field.
308308 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
310313 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
311314 return switch (op) {
......@@ -526,6 +529,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
526529 .struct_field_ptr_index_1,
527530 .struct_field_ptr_index_2,
528531 .struct_field_ptr_index_3,
532 .array_to_slice,
529533 => return air.getRefType(datas[inst].ty_op.ty),
530534
531535 .loop,
src/Liveness.zig+1
......@@ -287,6 +287,7 @@ fn analyzeInst(
287287 .struct_field_ptr_index_1,
288288 .struct_field_ptr_index_2,
289289 .struct_field_ptr_index_3,
290 .array_to_slice,
290291 => {
291292 const o = inst_datas[inst].ty_op;
292293 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/Sema.zig+2-1
......@@ -8952,7 +8952,8 @@ fn coerceArrayPtrToSlice(
89528952 // The comptime Value representation is compatible with both types.
89538953 return sema.addConstant(dest_type, val);
89548954 }
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);
89568957}
89578958
89588959fn coerceArrayPtrToMany(
src/codegen.zig+11
......@@ -856,6 +856,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
856856 .store => try self.airStore(inst),
857857 .struct_field_ptr=> try self.airStructFieldPtr(inst),
858858 .struct_field_val=> try self.airStructFieldVal(inst),
859 .array_to_slice => try self.airArrayToSlice(inst),
859860
860861 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
861862 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
......@@ -4761,6 +4762,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
47614762 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
47624763 }
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
47644775 fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
47654776 // First section of indexes correspond to a set number of constant values.
47664777 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
910910 .switch_br => try airSwitchBr(o, inst),
911911 .wrap_optional => try airWrapOptional(o, inst),
912912 .struct_field_ptr => try airStructFieldPtr(o, inst),
913 .array_to_slice => try airArrayToSlice(o, inst),
913914
914915 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),
915916 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),
......@@ -1860,6 +1861,23 @@ fn airIsErr(
18601861 return local;
18611862}
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
18631881fn IndentWriter(comptime UnderlyingWriter: type) type {
18641882 return struct {
18651883 const Self = @This();
src/codegen/llvm.zig+41-22
......@@ -1006,28 +1006,29 @@ pub const FuncGen = struct {
10061006 .is_err => try self.airIsErr(inst, .NE, false),
10071007 .is_err_ptr => try self.airIsErr(inst, .NE, true),
10081008
1009 .alloc => try self.airAlloc(inst),
1010 .arg => try self.airArg(inst),
1011 .bitcast => try self.airBitCast(inst),
1012 .bool_to_int=> try self.airBoolToInt(inst),
1013 .block => try self.airBlock(inst),
1014 .br => try self.airBr(inst),
1015 .switch_br => try self.airSwitchBr(inst),
1016 .breakpoint => try self.airBreakpoint(inst),
1017 .call => try self.airCall(inst),
1018 .cond_br => try self.airCondBr(inst),
1019 .intcast => try self.airIntCast(inst),
1020 .trunc => try self.airTrunc(inst),
1021 .floatcast => try self.airFloatCast(inst),
1022 .ptrtoint => try self.airPtrToInt(inst),
1023 .load => try self.airLoad(inst),
1024 .loop => try self.airLoop(inst),
1025 .not => try self.airNot(inst),
1026 .ret => try self.airRet(inst),
1027 .store => try self.airStore(inst),
1028 .assembly => try self.airAssembly(inst),
1029 .slice_ptr => try self.airSliceField(inst, 0),
1030 .slice_len => try self.airSliceField(inst, 1),
1009 .alloc => try self.airAlloc(inst),
1010 .arg => try self.airArg(inst),
1011 .bitcast => try self.airBitCast(inst),
1012 .bool_to_int => try self.airBoolToInt(inst),
1013 .block => try self.airBlock(inst),
1014 .br => try self.airBr(inst),
1015 .switch_br => try self.airSwitchBr(inst),
1016 .breakpoint => try self.airBreakpoint(inst),
1017 .call => try self.airCall(inst),
1018 .cond_br => try self.airCondBr(inst),
1019 .intcast => try self.airIntCast(inst),
1020 .trunc => try self.airTrunc(inst),
1021 .floatcast => try self.airFloatCast(inst),
1022 .ptrtoint => try self.airPtrToInt(inst),
1023 .load => try self.airLoad(inst),
1024 .loop => try self.airLoop(inst),
1025 .not => try self.airNot(inst),
1026 .ret => try self.airRet(inst),
1027 .store => try self.airStore(inst),
1028 .assembly => try self.airAssembly(inst),
1029 .slice_ptr => try self.airSliceField(inst, 0),
1030 .slice_len => try self.airSliceField(inst, 1),
1031 .array_to_slice => try self.airArrayToSlice(inst),
10311032
10321033 .struct_field_ptr => try self.airStructFieldPtr(inst),
10331034 .struct_field_val => try self.airStructFieldVal(inst),
......@@ -1246,6 +1247,24 @@ pub const FuncGen = struct {
12461247 return null;
12471248 }
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
12491268 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
12501269 if (self.liveness.isUnused(inst))
12511270 return null;
src/codegen/llvm/bindings.zig+9
......@@ -484,6 +484,15 @@ pub const Builder = opaque {
484484 DestTy: *const Type,
485485 Name: [*:0]const u8,
486486 ) *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;
487496};
488497
489498pub const IntPredicate = enum(c_uint) {
src/print_air.zig+1
......@@ -174,6 +174,7 @@ const Writer = struct {
174174 .struct_field_ptr_index_1,
175175 .struct_field_ptr_index_2,
176176 .struct_field_ptr_index_3,
177 .array_to_slice,
177178 => try w.writeTyOp(s, inst),
178179
179180 .block,
test/behavior/array.zig+24
......@@ -3,3 +3,27 @@ const testing = std.testing;
33const mem = std.mem;
44const expect = testing.expect;
55const 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;
44const expect = testing.expect;
55const 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
317test "array with sentinels" {
328 const S = struct {
339 fn doTheTest(is_ct: bool) !void {
......@@ -64,12 +40,7 @@ test "void arrays" {
6440}
6541
6642test "array literal" {
67 const hex_mult = [_]u16{
68 4096,
69 256,
70 16,
71 1,
72 };
43 const hex_mult = [_]u16{ 4096, 256, 16, 1 };
7344
7445 try expect(hex_mult.len == 4);
7546 try expect(hex_mult[1] == 256);
......@@ -84,21 +55,10 @@ test "array dot len const expr" {
8455const ArrayDotLenConstExpr = struct {
8556 y: [some_array.len]u8,
8657};
87const some_array = [_]u8{
88 0,
89 1,
90 2,
91 3,
92};
58const some_array = [_]u8{ 0, 1, 2, 3 };
9359
9460test "nested arrays" {
95 const array_of_strings = [_][]const u8{
96 "hello",
97 "this",
98 "is",
99 "my",
100 "thing",
101 };
61 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
10262 for (array_of_strings) |s, i| {
10363 if (i == 0) try expect(mem.eql(u8, s, "hello"));
10464 if (i == 1) try expect(mem.eql(u8, s, "this"));
......@@ -109,12 +69,8 @@ test "nested arrays" {
10969}
11070
11171var s_array: [8]Sub = undefined;
112const Sub = struct {
113 b: u8,
114};
115const Str = struct {
116 a: []Sub,
117};
72const Sub = struct { b: u8 };
73const Str = struct { a: []Sub };
11874test "set global var array via slice embedded in struct" {
11975 var s = Str{ .a = s_array[0..] };
12076
......@@ -208,26 +164,10 @@ test "runtime initialize array elem and then implicit cast to slice" {
208164test "array literal as argument to function" {
209165 const S = struct {
210166 fn entry(two: i32) !void {
211 try foo(&[_]i32{
212 1,
213 2,
214 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 });
167 try foo(&[_]i32{ 1, 2, 3 });
168 try foo(&[_]i32{ 1, two, 3 });
169 try foo2(true, &[_]i32{ 1, 2, 3 });
170 try foo2(true, &[_]i32{ 1, two, 3 });
231171 }
232172 fn foo(x: []const i32) !void {
233173 try expect(x[0] == 1);