authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 13:50:04-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 13:50:04-04:00
log9a2ea5ca420c7fdd4ab22b1f8814fa068d8ac56e
treee54e3998be254ae49bf62e08ecf13c051f557a03
parentfb63ba25779a4e482d2acc4c2cfc265c68c1b1eb

ir: comptime coerceArrayPtrToSlice


2 files changed, 66 insertions(+), 33 deletions(-)

src-self-hosted/ir.zig+63-31
......@@ -14,7 +14,8 @@ const text = @import("ir/text.zig");
1414pub const Inst = struct {
1515 tag: Tag,
1616 ty: Type,
17 src_offset: usize,
17 /// Byte offset into the source.
18 src: usize,
1819
1920 pub const Tag = enum {
2021 unreach,
......@@ -29,6 +30,15 @@ pub const Inst = struct {
2930 return @fieldParentPtr(T, "base", base);
3031 }
3132
33 /// Returns `null` if runtime-known.
34 pub fn value(base: *Inst) ?Value {
35 return switch (base.tag) {
36 .unreach => Value.initTag(.noreturn_value),
37 .constant => base.cast(Constant).?.val,
38 .assembly => null,
39 };
40 }
41
3242 pub const Constant = struct {
3343 pub const base_tag = Tag.constant;
3444 base: Inst,
......@@ -156,9 +166,7 @@ const Analyze = struct {
156166 }
157167
158168 fn resolveConstValue(self: *Analyze, base: *Inst) !Value {
159 const const_inst = base.cast(Inst.Constant) orelse
160 return self.fail(base.src_offset, "unable to resolve comptime value", .{});
161 return const_inst.val;
169 return base.value() orelse return self.fail(base.src, "unable to resolve comptime value", .{});
162170 }
163171
164172 fn resolveConstString(self: *Analyze, old_inst: *text.Inst) ![]u8 {
......@@ -176,7 +184,7 @@ const Analyze = struct {
176184 switch (typed_value.ty.zigTypeTag()) {
177185 .Fn => {},
178186 else => return self.fail(
179 export_inst.positionals.value.src_offset,
187 export_inst.positionals.value.src,
180188 "unable to export type '{}'",
181189 .{typed_value.ty},
182190 ),
......@@ -187,7 +195,20 @@ const Analyze = struct {
187195 });
188196 }
189197
190 fn constStr(self: *Analyze, src_offset: usize, str: []const u8) !*Inst {
198 fn constInst(self: *Analyze, src: usize, typed_value: TypedValue) !*Inst {
199 const const_inst = try self.arena.allocator.create(Inst.Constant);
200 const_inst.* = .{
201 .base = .{
202 .tag = Inst.Constant.base_tag,
203 .ty = typed_value.ty,
204 .src = src,
205 },
206 .val = typed_value.val,
207 };
208 return &const_inst.base;
209 }
210
211 fn constStr(self: *Analyze, src: usize, str: []const u8) !*Inst {
191212 const array_payload = try self.arena.allocator.create(Type.Payload.Array_u8_Sentinel0);
192213 array_payload.* = .{ .len = str.len };
193214
......@@ -197,16 +218,10 @@ const Analyze = struct {
197218 const bytes_payload = try self.arena.allocator.create(Value.Payload.Bytes);
198219 bytes_payload.* = .{ .data = str };
199220
200 const const_inst = try self.arena.allocator.create(Inst.Constant);
201 const_inst.* = .{
202 .base = .{
203 .tag = Inst.Constant.base_tag,
204 .ty = Type.initPayload(&ty_payload.base),
205 .src_offset = src_offset,
206 },
221 return self.constInst(src, .{
222 .ty = Type.initPayload(&ty_payload.base),
207223 .val = Value.initPayload(&bytes_payload.base),
208 };
209 return &const_inst.base;
224 });
210225 }
211226
212227 fn analyzeDecl(self: *Analyze, old_inst: *text.Inst) !*Inst {
......@@ -215,23 +230,28 @@ const Analyze = struct {
215230 // We can use this reference because Inst.Const's Value is arena-allocated.
216231 // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends.
217232 const bytes = old_inst.cast(text.Inst.Str).?.positionals.bytes;
218 return self.constStr(old_inst.src_offset, bytes);
233 return self.constStr(old_inst.src, bytes);
219234 },
220 .int => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
221 .ptrtoint => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
222 .fieldptr => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
223 .deref => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
224 .as => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
225 .@"asm" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
226 .@"unreachable" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
227 .@"fn" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
228 .@"export" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
229 .primitive => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
230 .fntype => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
235 .int => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
236 .ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
237 .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
238 .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
239 .as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
240 .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
241 .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
242 .@"fn" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
243 .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
244 .primitive => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
245 .fntype => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
231246 }
232247 }
233248
234249 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
250 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
251 if (in_memory_result == .ok) {
252 return self.bitcast(dest_type, inst);
253 }
254
235255 // *[N]T to []T
236256 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
237257 (!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))
......@@ -241,17 +261,29 @@ const Analyze = struct {
241261 if (array_type.zigTypeTag() == .Array and
242262 coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok)
243263 {
244 return self.fail(inst.src_offset, "TODO do the type coercion", .{});
264 return self.coerceArrayPtrToSlice(dest_type, inst);
245265 }
246266 }
247 return self.fail(inst.src_offset, "TODO implement type coercion", .{});
267 return self.fail(inst.src, "TODO implement type coercion", .{});
268 }
269
270 fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
271 return self.fail(inst.src, "TODO implement bitcast analysis", .{});
272 }
273
274 fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
275 if (inst.value()) |val| {
276 // The comptime Value representation is compatible with both types.
277 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
278 }
279 return self.fail(inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
248280 }
249281
250 fn fail(self: *Analyze, src_offset: usize, comptime format: []const u8, args: var) InnerError {
282 fn fail(self: *Analyze, src: usize, comptime format: []const u8, args: var) InnerError {
251283 @setCold(true);
252284 const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args);
253285 (try self.errors.addOne()).* = .{
254 .byte_offset = src_offset,
286 .byte_offset = src,
255287 .msg = msg,
256288 };
257289 return error.AnalysisFail;
src-self-hosted/ir/text.zig+3-2
......@@ -12,7 +12,8 @@ const BigInt = std.math.big.Int;
1212/// in-memory, analyzed instructions with types and values.
1313pub const Inst = struct {
1414 tag: Tag,
15 src_offset: usize,
15 /// Byte offset into the source.
16 src: usize,
1617
1718 /// These names are used directly as the instruction names in the text format.
1819 pub const Tag = enum {
......@@ -599,7 +600,7 @@ const Parser = struct {
599600 ) !*Inst {
600601 const inst_specific = try self.arena.allocator.create(InstType);
601602 inst_specific.base = .{
602 .src_offset = self.i,
603 .src = self.i,
603604 .tag = InstType.base_tag,
604605 };
605606