authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-22 03:08:50-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-22 03:08:50-04:00
logd58233b3612fe2d6bdd00859973aabdeb8c8574b
tree3141c46bf7804e34255548746510ac0326c55bfb
parentb1a86040dd530fd5632b22359eb7534dc2e3f4c9

ir: improve ZIR emission enough to emit hello world


4 files changed, 169 insertions(+), 14 deletions(-)

src-self-hosted/ir.zig+1-2
......@@ -666,8 +666,7 @@ const Analyze = struct {
666666 };
667667
668668 fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
669 // As a shortcut, if the small tags / addresses match, we're done.
670 if (dest_type.tag_if_small_enough == src_type.tag_if_small_enough)
669 if (dest_type.eql(src_type))
671670 return .ok;
672671
673672 // TODO: implement more of this function
src-self-hosted/ir/text.zig+62-11
......@@ -356,16 +356,15 @@ pub const Module = struct {
356356 comptime var need_comma = pos_fields.len != 0;
357357 const KW_Args = @TypeOf(inst.kw_args);
358358 inline for (@typeInfo(KW_Args).Struct.fields) |arg_field, i| {
359 if (need_comma) {
360 try stream.writeAll(", ");
361 }
362359 if (@typeInfo(arg_field.field_type) == .Optional) {
363360 if (@field(inst.kw_args, arg_field.name)) |non_optional| {
361 if (need_comma) try stream.writeAll(", ");
364362 try stream.print("{}=", .{arg_field.name});
365363 try self.writeParamToStream(stream, non_optional, inst_table);
366364 need_comma = true;
367365 }
368366 } else {
367 if (need_comma) try stream.writeAll(", ");
369368 try stream.print("{}=", .{arg_field.name});
370369 try self.writeParamToStream(stream, @field(inst.kw_args, arg_field.name), inst_table);
371370 need_comma = true;
......@@ -806,7 +805,7 @@ const EmitZIR = struct {
806805 decls: std.ArrayList(*Inst),
807806 decl_table: std.AutoHashMap(*ir.Inst, *Inst),
808807
809 pub fn emit(self: *EmitZIR) !void {
808 fn emit(self: *EmitZIR) !void {
810809 for (self.old_module.exports) |module_export| {
811810 const export_value = try self.emitTypedValue(module_export.src, module_export.typed_value);
812811 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.name);
......@@ -823,7 +822,7 @@ const EmitZIR = struct {
823822 }
824823 }
825824
826 pub fn resolveInst(self: *EmitZIR, inst_table: *const std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst {
825 fn resolveInst(self: *EmitZIR, inst_table: *const std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst {
827826 if (inst.cast(ir.Inst.Constant)) |const_inst| {
828827 if (self.decl_table.getValue(inst)) |decl| {
829828 return decl;
......@@ -836,7 +835,20 @@ const EmitZIR = struct {
836835 }
837836 }
838837
839 pub fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: ir.TypedValue) Allocator.Error!*Inst {
838 fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Inst {
839 const int_inst = try self.arena.allocator.create(Inst.Int);
840 int_inst.* = .{
841 .base = .{ .src = src, .tag = Inst.Int.base_tag },
842 .positionals = .{
843 .int = try val.toBigInt(&self.arena.allocator),
844 },
845 .kw_args = .{},
846 };
847 try self.decls.append(&int_inst.base);
848 return &int_inst.base;
849 }
850
851 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: ir.TypedValue) Allocator.Error!*Inst {
840852 switch (typed_value.ty.zigTypeTag()) {
841853 .Pointer => {
842854 const ptr_elem_type = typed_value.ty.elemType();
......@@ -854,6 +866,21 @@ const EmitZIR = struct {
854866 else => |t| std.debug.panic("TODO implement emitTypedValue for pointer to {}", .{@tagName(t)}),
855867 }
856868 },
869 .ComptimeInt => return self.emitComptimeIntVal(src, typed_value.val),
870 .Int => {
871 const as_inst = try self.arena.allocator.create(Inst.As);
872 as_inst.* = .{
873 .base = .{ .src = src, .tag = Inst.As.base_tag },
874 .positionals = .{
875 .dest_type = try self.emitType(src, typed_value.ty),
876 .value = try self.emitComptimeIntVal(src, typed_value.val),
877 },
878 .kw_args = .{},
879 };
880 try self.decls.append(&as_inst.base);
881
882 return &as_inst.base;
883 },
857884 .Type => {
858885 const ty = typed_value.val.toType();
859886 return self.emitType(src, ty);
......@@ -883,14 +910,38 @@ const EmitZIR = struct {
883910 .assembly => blk: {
884911 const old_inst = inst.cast(ir.Inst.Assembly).?;
885912 const new_inst = try self.arena.allocator.create(Inst.Asm);
913
914 const inputs = try self.arena.allocator.alloc(*Inst, old_inst.args.inputs.len);
915 for (inputs) |*elem, i| {
916 elem.* = try self.emitStringLiteral(inst.src, old_inst.args.inputs[i]);
917 }
918
919 const clobbers = try self.arena.allocator.alloc(*Inst, old_inst.args.clobbers.len);
920 for (clobbers) |*elem, i| {
921 elem.* = try self.emitStringLiteral(inst.src, old_inst.args.clobbers[i]);
922 }
923
924 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
925 for (args) |*elem, i| {
926 elem.* = try self.resolveInst(&inst_table, old_inst.args.args[i]);
927 }
928
886929 new_inst.* = .{
887930 .base = .{ .src = inst.src, .tag = Inst.Asm.base_tag },
888931 .positionals = .{
889932 .asm_source = try self.emitStringLiteral(inst.src, old_inst.args.asm_source),
890933 .return_type = try self.emitType(inst.src, inst.ty),
891934 },
892 // TODO emit more kw_args
893 .kw_args = .{},
935 .kw_args = .{
936 .@"volatile" = old_inst.args.is_volatile,
937 .output = if (old_inst.args.output) |o|
938 try self.emitStringLiteral(inst.src, o)
939 else
940 null,
941 .inputs = inputs,
942 .clobbers = clobbers,
943 .args = args,
944 },
894945 };
895946 break :blk &new_inst.base;
896947 },
......@@ -931,7 +982,7 @@ const EmitZIR = struct {
931982 }
932983 }
933984
934 pub fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst {
985 fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst {
935986 switch (ty.tag()) {
936987 .isize => return self.emitPrimitiveType(src, .isize),
937988 .usize => return self.emitPrimitiveType(src, .usize),
......@@ -986,7 +1037,7 @@ const EmitZIR = struct {
9861037 }
9871038 }
9881039
989 pub fn emitPrimitiveType(self: *EmitZIR, src: usize, tag: Inst.Primitive.BuiltinType) !*Inst {
1040 fn emitPrimitiveType(self: *EmitZIR, src: usize, tag: Inst.Primitive.BuiltinType) !*Inst {
9901041 const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
9911042 primitive_inst.* = .{
9921043 .base = .{ .src = src, .tag = Inst.Primitive.base_tag },
......@@ -999,7 +1050,7 @@ const EmitZIR = struct {
9991050 return &primitive_inst.base;
10001051 }
10011052
1002 pub fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {
1053 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {
10031054 const str_inst = try self.arena.allocator.create(Inst.Str);
10041055 str_inst.* = .{
10051056 .base = .{ .src = src, .tag = Inst.Str.base_tag },
src-self-hosted/type.zig+54
......@@ -88,6 +88,60 @@ pub const Type = extern union {
8888 return @fieldParentPtr(T, "base", self.ptr_otherwise);
8989 }
9090
91 pub fn eql(self: Type, other: Type) bool {
92 //std.debug.warn("test {} == {}\n", .{ self, other });
93 // As a shortcut, if the small tags / addresses match, we're done.
94 if (self.tag_if_small_enough == other.tag_if_small_enough)
95 return true;
96 const zig_tag_a = self.zigTypeTag();
97 const zig_tag_b = self.zigTypeTag();
98 if (zig_tag_a != zig_tag_b)
99 return false;
100 switch (zig_tag_a) {
101 .Type => return true,
102 .Void => return true,
103 .Bool => return true,
104 .NoReturn => return true,
105 .ComptimeFloat => return true,
106 .ComptimeInt => return true,
107 .Undefined => return true,
108 .Null => return true,
109 .Pointer => {
110 const is_slice_a = isSlice(self);
111 const is_slice_b = isSlice(other);
112 if (is_slice_a != is_slice_b)
113 return false;
114 @panic("TODO implement more pointer Type equality comparison");
115 },
116 .Int => {
117 if (self.tag() != other.tag()) {
118 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
119 return false;
120 }
121 // The target will not be branched upon, because we handled target-dependent cases above.
122 const info_a = self.intInfo(@as(Target, undefined));
123 const info_b = self.intInfo(@as(Target, undefined));
124 return info_a.signed == info_b.signed and info_a.bits == info_b.bits;
125 },
126 .Float,
127 .Array,
128 .Struct,
129 .Optional,
130 .ErrorUnion,
131 .ErrorSet,
132 .Enum,
133 .Union,
134 .Fn,
135 .BoundFn,
136 .Opaque,
137 .Frame,
138 .AnyFrame,
139 .Vector,
140 .EnumLiteral,
141 => @panic("TODO implement more Type equality comparison"),
142 }
143 }
144
91145 pub fn format(
92146 self: Type,
93147 comptime fmt: []const u8,
src-self-hosted/value.zig+52-1
......@@ -4,6 +4,7 @@ const log2 = std.math.log2;
44const assert = std.debug.assert;
55const BigInt = std.math.big.Int;
66const Target = std.Target;
7const Allocator = std.mem.Allocator;
78
89/// This is the raw data, with no bookkeeping, no memory awareness,
910/// no de-duplication, and no type system awareness.
......@@ -156,7 +157,7 @@ pub const Value = extern union {
156157
157158 /// Asserts that the value is representable as an array of bytes.
158159 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
159 pub fn toAllocatedBytes(self: Value, allocator: *std.mem.Allocator) error{OutOfMemory}![]u8 {
160 pub fn toAllocatedBytes(self: Value, allocator: *Allocator) Allocator.Error![]u8 {
160161 if (self.cast(Payload.Bytes)) |bytes| {
161162 return std.mem.dupe(allocator, u8, bytes.data);
162163 }
......@@ -213,6 +214,56 @@ pub const Value = extern union {
213214 };
214215 }
215216
217 /// Asserts the value is an integer.
218 pub fn toBigInt(self: Value, allocator: *Allocator) Allocator.Error!BigInt {
219 switch (self.tag()) {
220 .ty,
221 .u8_type,
222 .i8_type,
223 .isize_type,
224 .usize_type,
225 .c_short_type,
226 .c_ushort_type,
227 .c_int_type,
228 .c_uint_type,
229 .c_long_type,
230 .c_ulong_type,
231 .c_longlong_type,
232 .c_ulonglong_type,
233 .c_longdouble_type,
234 .f16_type,
235 .f32_type,
236 .f64_type,
237 .f128_type,
238 .c_void_type,
239 .bool_type,
240 .void_type,
241 .type_type,
242 .anyerror_type,
243 .comptime_int_type,
244 .comptime_float_type,
245 .noreturn_type,
246 .fn_naked_noreturn_no_args_type,
247 .single_const_pointer_to_comptime_int_type,
248 .const_slice_u8_type,
249 .void_value,
250 .noreturn_value,
251 .bool_true,
252 .bool_false,
253 .function,
254 .ref,
255 .ref_val,
256 .bytes,
257 => unreachable,
258
259 .zero => return BigInt.initSet(allocator, 0),
260
261 .int_u64 => return BigInt.initSet(allocator, self.cast(Payload.Int_u64).?.int),
262 .int_i64 => return BigInt.initSet(allocator, self.cast(Payload.Int_i64).?.int),
263 .int_big => return self.cast(Payload.IntBig).?.big_int,
264 }
265 }
266
216267 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
217268 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
218269 switch (self.tag()) {