Skip to content

Commit 97d69e3

Browse files
committed
stage2: add array_to_slice AIR instruction
1 parent a9a21c5 commit 97d69e3

File tree

10 files changed

+120
-92
lines changed

10 files changed

+120
-92
lines changed

src/Air.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

89588959
fn coerceArrayPtrToMany(

src/codegen.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

1864+
fn 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+
18631881
fn IndentWriter(comptime UnderlyingWriter: type) type {
18641882
return struct {
18651883
const Self = @This();

src/codegen/llvm.zig

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

489498
pub const IntPredicate = enum(c_uint) {

src/print_air.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,27 @@ const testing = std.testing;
33
const mem = std.mem;
44
const expect = testing.expect;
55
const expectEqual = testing.expectEqual;
6+
7+
test "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+
}
27+
fn getArrayLen(a: []const u32) usize {
28+
return a.len;
29+
}

test/behavior/array_stage1.zig

Lines changed: 9 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,6 @@ const mem = std.mem;
44
const expect = testing.expect;
55
const expectEqual = testing.expectEqual;
66

7-
test "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-
}
27-
fn getArrayLen(a: []const u32) usize {
28-
return a.len;
29-
}
30-
317
test "array with sentinels" {
328
const S = struct {
339
fn doTheTest(is_ct: bool) !void {
@@ -64,12 +40,7 @@ test "void arrays" {
6440
}
6541

6642
test "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" {
8455
const ArrayDotLenConstExpr = struct {
8556
y: [some_array.len]u8,
8657
};
87-
const some_array = [_]u8{
88-
0,
89-
1,
90-
2,
91-
3,
92-
};
58+
const some_array = [_]u8{ 0, 1, 2, 3 };
9359

9460
test "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

11171
var s_array: [8]Sub = undefined;
112-
const Sub = struct {
113-
b: u8,
114-
};
115-
const Str = struct {
116-
a: []Sub,
117-
};
72+
const Sub = struct { b: u8 };
73+
const Str = struct { a: []Sub };
11874
test "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" {
208164
test "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);

0 commit comments

Comments
 (0)