authorgravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-07-13 01:47:44-04:00
committergravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-07-13 01:49:04-04:00
log8d6cadee1622b2548e02c0c63f9a65625d608ada
treeb1bc29909e1cff122c7df851288c3bae4d6c3232
parent4a462481982e96e1f94e2dd431aeaf8686c0c4b1
signature Commit is signed but in an unrecognized format.

CBE: Code cleanup


1 files changed, 146 insertions(+), 144 deletions(-)

src-self-hosted/cgen.zig+146-144
......@@ -1,9 +1,11 @@
11const link = @import("link.zig");
22const Module = @import("Module.zig");
3const ir = @import("ir.zig");
3
4const std = @import("std");
5
6const Inst = @import("ir.zig").Inst;
47const Value = @import("value.zig").Value;
58const Type = @import("type.zig").Type;
6const std = @import("std");
79
810const C = link.File.C;
911const Decl = Module.Decl;
......@@ -45,159 +47,159 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De
4547 const name = try map(file.allocator, mem.spanZ(decl.name));
4648 defer file.allocator.free(name);
4749 try writer.print(" {}(", .{name});
48 if (tv.ty.fnParamLen() == 0) {
49 try writer.writeAll("void)");
50 } else {
50 if (tv.ty.fnParamLen() == 0)
51 try writer.writeAll("void)")
52 else
5153 return file.fail(decl.src(), "TODO implement parameters", .{});
52 }
5354}
5455
5556pub fn generate(file: *C, decl: *Decl) !void {
57 switch (decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {
58 .Fn => try genFn(file, decl),
59 .Array => try genArray(file, decl),
60 else => |e| return file.fail(decl.src(), "TODO {}", .{e}),
61 }
62}
63
64fn genArray(file: *C, decl: *Decl) !void {
65 const tv = decl.typed_value.most_recent.typed_value;
66 // TODO: prevent inline asm constants from being emitted
67 const name = try map(file.allocator, mem.span(decl.name));
68 defer file.allocator.free(name);
69 if (tv.val.cast(Value.Payload.Bytes)) |payload|
70 if (tv.ty.arraySentinel()) |sentinel|
71 if (sentinel.toUnsignedInt() == 0)
72 try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data })
73 else
74 return file.fail(decl.src(), "TODO byte arrays with non-zero sentinels", .{})
75 else
76 return file.fail(decl.src(), "TODO byte arrays without sentinels", .{})
77 else
78 return file.fail(decl.src(), "TODO non-byte arrays", .{});
79}
80
81fn genFn(file: *C, decl: *Decl) !void {
5682 const writer = file.main.writer();
57 const header = file.header.writer();
5883 const tv = decl.typed_value.most_recent.typed_value;
59 switch (tv.ty.zigTypeTag()) {
60 .Fn => {
61 try renderFunctionSignature(file, writer, decl);
62
63 try writer.writeAll(" {");
64
65 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;
66 const instructions = func.analysis.success.instructions;
67 if (instructions.len > 0) {
68 for (instructions) |inst| {
69 try writer.writeAll("\n\t");
70 switch (inst.tag) {
71 .assembly => {
72 const as = inst.cast(ir.Inst.Assembly).?.args;
73 for (as.inputs) |i, index| {
74 if (i[0] == '{' and i[i.len - 1] == '}') {
75 const reg = i[1 .. i.len - 1];
76 const arg = as.args[index];
77 if (arg.cast(ir.Inst.Constant)) |c| {
78 if (c.val.tag() == .int_u64) {
79 try writer.writeAll("register ");
80 try renderType(file, writer, arg.ty, decl.src());
81 try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() });
82 } else {
83 return file.fail(decl.src(), "TODO inline asm {} args", .{c.val.tag()});
84 }
85 } else {
86 return file.fail(decl.src(), "TODO non-constant inline asm args", .{});
87 }
88 } else {
89 return file.fail(decl.src(), "TODO non-explicit inline asm regs", .{});
90 }
91 }
92 try writer.print("__asm {} (\"{}\"", .{ if (as.is_volatile) @as([]const u8, "volatile") else "", as.asm_source });
93 if (as.output) |o| {
94 return file.fail(decl.src(), "TODO inline asm output", .{});
95 }
96 if (as.inputs.len > 0) {
97 if (as.output == null) {
98 try writer.writeAll(" :");
99 }
100 try writer.writeAll(": ");
101 for (as.inputs) |i, index| {
102 if (i[0] == '{' and i[i.len - 1] == '}') {
103 const reg = i[1 .. i.len - 1];
104 const arg = as.args[index];
105 if (index > 0) {
106 try writer.writeAll(", ");
107 }
108 if (arg.cast(ir.Inst.Constant)) |c| {
109 try writer.print("\"\"({}_constant)", .{reg});
110 } else {
111 // This is blocked by the earlier test
112 unreachable;
113 }
114 } else {
115 // This is blocked by the earlier test
116 unreachable;
117 }
118 }
119 }
120 try writer.writeAll(");");
121 },
122 .call => {
123 const call = inst.cast(ir.Inst.Call).?;
124 if (call.args.func.cast(ir.Inst.Constant)) |func_inst| {
125 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
126 const target = func_val.func.owner_decl;
127 const target_ty = target.typed_value.most_recent.typed_value.ty;
128 const ret_ty = target_ty.fnReturnType().tag();
129 if (target_ty.fnReturnType().hasCodeGenBits() and call.base.isUnused()) {
130 try writer.print("(void)", .{});
131 }
132 const tname = mem.spanZ(target.name);
133 if (file.called.get(tname) == null) {
134 try file.called.put(tname, void{});
135 try renderFunctionSignature(file, header, target);
136 try header.writeAll(";\n");
137 }
138 try writer.print("{}();", .{tname});
139 } else {
140 return file.fail(decl.src(), "TODO non-function call target?", .{});
141 }
142 if (call.args.args.len != 0) {
143 return file.fail(decl.src(), "TODO function arguments", .{});
144 }
145 } else {
146 return file.fail(decl.src(), "TODO non-constant call inst?", .{});
147 }
148 },
149 .ret => {
150 const ret_value: *ir.Inst = inst.cast(ir.Inst.Ret).?.args.operand;
151 const expected_return_type = tv.ty.fnReturnType();
152 const value = ret_value.value().?;
153 if (expected_return_type.eql(ret_value.ty)) {
154 return file.fail(decl.src(), "TODO return {}", .{expected_return_type});
155 } else {
156 if (expected_return_type.isInt() and ret_value.ty.tag() == .comptime_int) {
157 if (value.intFitsInType(expected_return_type, file.options.target)) {
158 if (expected_return_type.intInfo(file.options.target).bits <= 64) {
159 try writer.print("return {};", .{value.toUnsignedInt()});
160 } else {
161 return file.fail(decl.src(), "TODO return ints > 64 bits", .{});
162 }
163 } else {
164 return file.fail(decl.src(), "comptime int {} does not fit in {}", .{ value.toUnsignedInt(), expected_return_type });
165 }
166 } else {
167 return file.fail(decl.src(), "return type mismatch: expected {}, found {}", .{ expected_return_type, ret_value.ty });
168 }
169 }
170 },
171 else => |e| {
172 return file.fail(decl.src(), "TODO {}", .{e});
173 },
174 }
175 }
176 try writer.writeAll("\n");
84
85 try renderFunctionSignature(file, writer, decl);
86
87 try writer.writeAll(" {");
88
89 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;
90 const instructions = func.analysis.success.instructions;
91 if (instructions.len > 0) {
92 for (instructions) |inst| {
93 try writer.writeAll("\n\t");
94 switch (inst.tag) {
95 .assembly => try genAsm(file, inst.cast(Inst.Assembly).?, decl),
96 .call => try genCall(file, inst.cast(Inst.Call).?, decl),
97 .ret => try genRet(file, inst.cast(Inst.Ret).?, decl, tv.ty.fnReturnType()),
98 else => |e| return file.fail(decl.src(), "TODO {}", .{e}),
99 }
100 }
101 try writer.writeAll("\n");
102 }
103
104 try writer.writeAll("}\n\n");
105}
106
107fn genRet(file: *C, inst: *Inst.Ret, decl: *Decl, expected_return_type: Type) !void {
108 const writer = file.main.writer();
109 const ret_value = inst.args.operand;
110 const value = ret_value.value().?;
111 if (expected_return_type.eql(ret_value.ty))
112 return file.fail(decl.src(), "TODO return {}", .{expected_return_type})
113 else if (expected_return_type.isInt() and ret_value.ty.tag() == .comptime_int)
114 if (value.intFitsInType(expected_return_type, file.options.target))
115 if (expected_return_type.intInfo(file.options.target).bits <= 64)
116 try writer.print("return {};", .{value.toUnsignedInt()})
117 else
118 return file.fail(decl.src(), "TODO return ints > 64 bits", .{})
119 else
120 return file.fail(decl.src(), "comptime int {} does not fit in {}", .{ value.toUnsignedInt(), expected_return_type })
121 else
122 return file.fail(decl.src(), "return type mismatch: expected {}, found {}", .{ expected_return_type, ret_value.ty });
123}
124
125fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
126 const writer = file.main.writer();
127 const header = file.header.writer();
128 if (inst.args.func.cast(Inst.Constant)) |func_inst| {
129 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
130 const target = func_val.func.owner_decl;
131 const target_ty = target.typed_value.most_recent.typed_value.ty;
132 const ret_ty = target_ty.fnReturnType().tag();
133 if (target_ty.fnReturnType().hasCodeGenBits() and inst.base.isUnused()) {
134 try writer.print("(void)", .{});
177135 }
136 const tname = mem.spanZ(target.name);
137 if (file.called.get(tname) == null) {
138 try file.called.put(tname, void{});
139 try renderFunctionSignature(file, header, target);
140 try header.writeAll(";\n");
141 }
142 try writer.print("{}();", .{tname});
143 } else {
144 return file.fail(decl.src(), "TODO non-function call target?", .{});
145 }
146 if (inst.args.args.len != 0) {
147 return file.fail(decl.src(), "TODO function arguments", .{});
148 }
149 } else {
150 return file.fail(decl.src(), "TODO non-constant call inst?", .{});
151 }
152}
178153
179 try writer.writeAll("}\n\n");
180 },
181 .Array => {
182 // TODO: prevent inline asm constants from being emitted
183 const name = try map(file.allocator, mem.span(decl.name));
184 defer file.allocator.free(name);
185 if (tv.val.cast(Value.Payload.Bytes)) |payload| {
186 if (tv.ty.arraySentinel()) |sentinel| {
187 if (sentinel.toUnsignedInt() == 0) {
188 try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data });
189 } else {
190 return file.fail(decl.src(), "TODO byte arrays with non-zero sentinels", .{});
191 }
154fn genAsm(file: *C, inst: *Inst.Assembly, decl: *Decl) !void {
155 const as = inst.args;
156 const writer = file.main.writer();
157 for (as.inputs) |i, index| {
158 if (i[0] == '{' and i[i.len - 1] == '}') {
159 const reg = i[1 .. i.len - 1];
160 const arg = as.args[index];
161 if (arg.cast(Inst.Constant)) |c| {
162 if (c.val.tag() == .int_u64) {
163 try writer.writeAll("register ");
164 try renderType(file, writer, arg.ty, decl.src());
165 try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() });
192166 } else {
193 return file.fail(decl.src(), "TODO byte arrays without sentinels", .{});
167 return file.fail(decl.src(), "TODO inline asm {} args", .{c.val.tag()});
194168 }
195169 } else {
196 return file.fail(decl.src(), "TODO non-byte arrays", .{});
170 return file.fail(decl.src(), "TODO non-constant inline asm args", .{});
197171 }
198 },
199 else => |e| {
200 return file.fail(decl.src(), "TODO {}", .{e});
201 },
172 } else {
173 return file.fail(decl.src(), "TODO non-explicit inline asm regs", .{});
174 }
175 }
176 try writer.print("__asm {} (\"{}\"", .{ if (as.is_volatile) @as([]const u8, "volatile") else "", as.asm_source });
177 if (as.output) |o| {
178 return file.fail(decl.src(), "TODO inline asm output", .{});
179 }
180 if (as.inputs.len > 0) {
181 if (as.output == null) {
182 try writer.writeAll(" :");
183 }
184 try writer.writeAll(": ");
185 for (as.inputs) |i, index| {
186 if (i[0] == '{' and i[i.len - 1] == '}') {
187 const reg = i[1 .. i.len - 1];
188 const arg = as.args[index];
189 if (index > 0) {
190 try writer.writeAll(", ");
191 }
192 if (arg.cast(Inst.Constant)) |c| {
193 try writer.print("\"\"({}_constant)", .{reg});
194 } else {
195 // This is blocked by the earlier test
196 unreachable;
197 }
198 } else {
199 // This is blocked by the earlier test
200 unreachable;
201 }
202 }
202203 }
204 try writer.writeAll(");");
203205}