mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 00:35:10 +00:00
stage2: add array_to_slice AIR instruction
This commit is contained in:
parent
a9a21c5988
commit
97d69e3352
@ -306,6 +306,9 @@ pub const Inst = struct {
|
||||
/// Result type is the element type of the inner pointer operand.
|
||||
/// Uses the `bin_op` field.
|
||||
ptr_ptr_elem_val,
|
||||
/// Given a pointer to an array, return a slice.
|
||||
/// Uses the `ty_op` field.
|
||||
array_to_slice,
|
||||
|
||||
pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
|
||||
return switch (op) {
|
||||
@ -526,6 +529,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
||||
.struct_field_ptr_index_1,
|
||||
.struct_field_ptr_index_2,
|
||||
.struct_field_ptr_index_3,
|
||||
.array_to_slice,
|
||||
=> return air.getRefType(datas[inst].ty_op.ty),
|
||||
|
||||
.loop,
|
||||
|
||||
@ -287,6 +287,7 @@ fn analyzeInst(
|
||||
.struct_field_ptr_index_1,
|
||||
.struct_field_ptr_index_2,
|
||||
.struct_field_ptr_index_3,
|
||||
.array_to_slice,
|
||||
=> {
|
||||
const o = inst_datas[inst].ty_op;
|
||||
return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
|
||||
|
||||
@ -8952,7 +8952,8 @@ fn coerceArrayPtrToSlice(
|
||||
// The comptime Value representation is compatible with both types.
|
||||
return sema.addConstant(dest_type, val);
|
||||
}
|
||||
return sema.mod.fail(&block.base, inst_src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
|
||||
try sema.requireRuntimeBlock(block, inst_src);
|
||||
return block.addTyOp(.array_to_slice, dest_type, inst);
|
||||
}
|
||||
|
||||
fn coerceArrayPtrToMany(
|
||||
|
||||
@ -856,6 +856,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.store => try self.airStore(inst),
|
||||
.struct_field_ptr=> try self.airStructFieldPtr(inst),
|
||||
.struct_field_val=> try self.airStructFieldVal(inst),
|
||||
.array_to_slice => try self.airArrayToSlice(inst),
|
||||
|
||||
.struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
|
||||
.struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
|
||||
@ -4761,6 +4762,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||
else => return self.fail("TODO implement airArrayToSlice for {}", .{
|
||||
self.target.cpu.arch,
|
||||
}),
|
||||
};
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
|
||||
// First section of indexes correspond to a set number of constant values.
|
||||
const ref_int = @enumToInt(inst);
|
||||
|
||||
@ -910,6 +910,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
|
||||
.switch_br => try airSwitchBr(o, inst),
|
||||
.wrap_optional => try airWrapOptional(o, inst),
|
||||
.struct_field_ptr => try airStructFieldPtr(o, inst),
|
||||
.array_to_slice => try airArrayToSlice(o, inst),
|
||||
|
||||
.struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),
|
||||
.struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),
|
||||
@ -1860,6 +1861,23 @@ fn airIsErr(
|
||||
return local;
|
||||
}
|
||||
|
||||
fn airArrayToSlice(o: *Object, inst: Air.Inst.Index) !CValue {
|
||||
if (o.liveness.isUnused(inst))
|
||||
return CValue.none;
|
||||
|
||||
const inst_ty = o.air.typeOfIndex(inst);
|
||||
const local = try o.allocLocal(inst_ty, .Const);
|
||||
const ty_op = o.air.instructions.items(.data)[inst].ty_op;
|
||||
const writer = o.writer();
|
||||
const operand = try o.resolveInst(ty_op.operand);
|
||||
const array_len = o.air.typeOf(ty_op.operand).elemType().arrayLen();
|
||||
|
||||
try writer.writeAll(" = { .ptr = ");
|
||||
try o.writeCValue(writer, operand);
|
||||
try writer.print(", .len = {d} }};\n", .{array_len});
|
||||
return local;
|
||||
}
|
||||
|
||||
fn IndentWriter(comptime UnderlyingWriter: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
@ -1006,28 +1006,29 @@ pub const FuncGen = struct {
|
||||
.is_err => try self.airIsErr(inst, .NE, false),
|
||||
.is_err_ptr => try self.airIsErr(inst, .NE, true),
|
||||
|
||||
.alloc => try self.airAlloc(inst),
|
||||
.arg => try self.airArg(inst),
|
||||
.bitcast => try self.airBitCast(inst),
|
||||
.bool_to_int=> try self.airBoolToInt(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.switch_br => try self.airSwitchBr(inst),
|
||||
.breakpoint => try self.airBreakpoint(inst),
|
||||
.call => try self.airCall(inst),
|
||||
.cond_br => try self.airCondBr(inst),
|
||||
.intcast => try self.airIntCast(inst),
|
||||
.trunc => try self.airTrunc(inst),
|
||||
.floatcast => try self.airFloatCast(inst),
|
||||
.ptrtoint => try self.airPtrToInt(inst),
|
||||
.load => try self.airLoad(inst),
|
||||
.loop => try self.airLoop(inst),
|
||||
.not => try self.airNot(inst),
|
||||
.ret => try self.airRet(inst),
|
||||
.store => try self.airStore(inst),
|
||||
.assembly => try self.airAssembly(inst),
|
||||
.slice_ptr => try self.airSliceField(inst, 0),
|
||||
.slice_len => try self.airSliceField(inst, 1),
|
||||
.alloc => try self.airAlloc(inst),
|
||||
.arg => try self.airArg(inst),
|
||||
.bitcast => try self.airBitCast(inst),
|
||||
.bool_to_int => try self.airBoolToInt(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.switch_br => try self.airSwitchBr(inst),
|
||||
.breakpoint => try self.airBreakpoint(inst),
|
||||
.call => try self.airCall(inst),
|
||||
.cond_br => try self.airCondBr(inst),
|
||||
.intcast => try self.airIntCast(inst),
|
||||
.trunc => try self.airTrunc(inst),
|
||||
.floatcast => try self.airFloatCast(inst),
|
||||
.ptrtoint => try self.airPtrToInt(inst),
|
||||
.load => try self.airLoad(inst),
|
||||
.loop => try self.airLoop(inst),
|
||||
.not => try self.airNot(inst),
|
||||
.ret => try self.airRet(inst),
|
||||
.store => try self.airStore(inst),
|
||||
.assembly => try self.airAssembly(inst),
|
||||
.slice_ptr => try self.airSliceField(inst, 0),
|
||||
.slice_len => try self.airSliceField(inst, 1),
|
||||
.array_to_slice => try self.airArrayToSlice(inst),
|
||||
|
||||
.struct_field_ptr => try self.airStructFieldPtr(inst),
|
||||
.struct_field_val => try self.airStructFieldVal(inst),
|
||||
@ -1246,6 +1247,24 @@ pub const FuncGen = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
const array_len = self.air.typeOf(ty_op.operand).elemType().arrayLen();
|
||||
const usize_llvm_ty = try self.dg.llvmType(Type.initTag(.usize));
|
||||
const len = usize_llvm_ty.constInt(array_len, .False);
|
||||
const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
|
||||
};
|
||||
const ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
|
||||
const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr, 0, "");
|
||||
return self.builder.buildInsertValue(partial, len, 1, "");
|
||||
}
|
||||
|
||||
fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
@ -484,6 +484,15 @@ pub const Builder = opaque {
|
||||
DestTy: *const Type,
|
||||
Name: [*:0]const u8,
|
||||
) *const Value;
|
||||
|
||||
pub const buildInsertValue = LLVMBuildInsertValue;
|
||||
extern fn LLVMBuildInsertValue(
|
||||
*const Builder,
|
||||
AggVal: *const Value,
|
||||
EltVal: *const Value,
|
||||
Index: c_uint,
|
||||
Name: [*:0]const u8,
|
||||
) *const Value;
|
||||
};
|
||||
|
||||
pub const IntPredicate = enum(c_uint) {
|
||||
|
||||
@ -174,6 +174,7 @@ const Writer = struct {
|
||||
.struct_field_ptr_index_1,
|
||||
.struct_field_ptr_index_2,
|
||||
.struct_field_ptr_index_3,
|
||||
.array_to_slice,
|
||||
=> try w.writeTyOp(s, inst),
|
||||
|
||||
.block,
|
||||
|
||||
@ -3,3 +3,27 @@ const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
|
||||
test "arrays" {
|
||||
var array: [5]u32 = undefined;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 5) {
|
||||
array[i] = i + 1;
|
||||
i = array[i];
|
||||
}
|
||||
|
||||
i = 0;
|
||||
var accumulator = @as(u32, 0);
|
||||
while (i < 5) {
|
||||
accumulator += array[i];
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
try expect(accumulator == 15);
|
||||
try expect(getArrayLen(&array) == 5);
|
||||
}
|
||||
fn getArrayLen(a: []const u32) usize {
|
||||
return a.len;
|
||||
}
|
||||
|
||||
@ -4,30 +4,6 @@ const mem = std.mem;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
|
||||
test "arrays" {
|
||||
var array: [5]u32 = undefined;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 5) {
|
||||
array[i] = i + 1;
|
||||
i = array[i];
|
||||
}
|
||||
|
||||
i = 0;
|
||||
var accumulator = @as(u32, 0);
|
||||
while (i < 5) {
|
||||
accumulator += array[i];
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
try expect(accumulator == 15);
|
||||
try expect(getArrayLen(&array) == 5);
|
||||
}
|
||||
fn getArrayLen(a: []const u32) usize {
|
||||
return a.len;
|
||||
}
|
||||
|
||||
test "array with sentinels" {
|
||||
const S = struct {
|
||||
fn doTheTest(is_ct: bool) !void {
|
||||
@ -64,12 +40,7 @@ test "void arrays" {
|
||||
}
|
||||
|
||||
test "array literal" {
|
||||
const hex_mult = [_]u16{
|
||||
4096,
|
||||
256,
|
||||
16,
|
||||
1,
|
||||
};
|
||||
const hex_mult = [_]u16{ 4096, 256, 16, 1 };
|
||||
|
||||
try expect(hex_mult.len == 4);
|
||||
try expect(hex_mult[1] == 256);
|
||||
@ -84,21 +55,10 @@ test "array dot len const expr" {
|
||||
const ArrayDotLenConstExpr = struct {
|
||||
y: [some_array.len]u8,
|
||||
};
|
||||
const some_array = [_]u8{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
const some_array = [_]u8{ 0, 1, 2, 3 };
|
||||
|
||||
test "nested arrays" {
|
||||
const array_of_strings = [_][]const u8{
|
||||
"hello",
|
||||
"this",
|
||||
"is",
|
||||
"my",
|
||||
"thing",
|
||||
};
|
||||
const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
|
||||
for (array_of_strings) |s, i| {
|
||||
if (i == 0) try expect(mem.eql(u8, s, "hello"));
|
||||
if (i == 1) try expect(mem.eql(u8, s, "this"));
|
||||
@ -109,12 +69,8 @@ test "nested arrays" {
|
||||
}
|
||||
|
||||
var s_array: [8]Sub = undefined;
|
||||
const Sub = struct {
|
||||
b: u8,
|
||||
};
|
||||
const Str = struct {
|
||||
a: []Sub,
|
||||
};
|
||||
const Sub = struct { b: u8 };
|
||||
const Str = struct { a: []Sub };
|
||||
test "set global var array via slice embedded in struct" {
|
||||
var s = Str{ .a = s_array[0..] };
|
||||
|
||||
@ -208,26 +164,10 @@ test "runtime initialize array elem and then implicit cast to slice" {
|
||||
test "array literal as argument to function" {
|
||||
const S = struct {
|
||||
fn entry(two: i32) !void {
|
||||
try foo(&[_]i32{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
});
|
||||
try foo(&[_]i32{
|
||||
1,
|
||||
two,
|
||||
3,
|
||||
});
|
||||
try foo2(true, &[_]i32{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
});
|
||||
try foo2(true, &[_]i32{
|
||||
1,
|
||||
two,
|
||||
3,
|
||||
});
|
||||
try foo(&[_]i32{ 1, 2, 3 });
|
||||
try foo(&[_]i32{ 1, two, 3 });
|
||||
try foo2(true, &[_]i32{ 1, 2, 3 });
|
||||
try foo2(true, &[_]i32{ 1, two, 3 });
|
||||
}
|
||||
fn foo(x: []const i32) !void {
|
||||
try expect(x[0] == 1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user