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
signaturelock-open 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 @@...@@ -1,9 +1,11 @@
1const link = @import("link.zig");1const link = @import("link.zig");
2const Module = @import("Module.zig");2const Module = @import("Module.zig");
3const ir = @import("ir.zig");3
4const std = @import("std");
5
6const Inst = @import("ir.zig").Inst;
4const Value = @import("value.zig").Value;7const Value = @import("value.zig").Value;
5const Type = @import("type.zig").Type;8const Type = @import("type.zig").Type;
6const std = @import("std");
79
8const C = link.File.C;10const C = link.File.C;
9const Decl = Module.Decl;11const Decl = Module.Decl;
...@@ -45,159 +47,159 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De...@@ -45,159 +47,159 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De
45 const name = try map(file.allocator, mem.spanZ(decl.name));47 const name = try map(file.allocator, mem.spanZ(decl.name));
46 defer file.allocator.free(name);48 defer file.allocator.free(name);
47 try writer.print(" {}(", .{name});49 try writer.print(" {}(", .{name});
48 if (tv.ty.fnParamLen() == 0) {50 if (tv.ty.fnParamLen() == 0)
49 try writer.writeAll("void)");51 try writer.writeAll("void)")
50 } else {52 else
51 return file.fail(decl.src(), "TODO implement parameters", .{});53 return file.fail(decl.src(), "TODO implement parameters", .{});
52 }
53}54}
5455
55pub fn generate(file: *C, decl: *Decl) !void {56pub 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 {
56 const writer = file.main.writer();82 const writer = file.main.writer();
57 const header = file.header.writer();
58 const tv = decl.typed_value.most_recent.typed_value;83 const tv = decl.typed_value.most_recent.typed_value;
59 switch (tv.ty.zigTypeTag()) {84
60 .Fn => {85 try renderFunctionSignature(file, writer, decl);
61 try renderFunctionSignature(file, writer, decl);86
6287 try writer.writeAll(" {");
63 try writer.writeAll(" {");88
6489 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;
65 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;90 const instructions = func.analysis.success.instructions;
66 const instructions = func.analysis.success.instructions;91 if (instructions.len > 0) {
67 if (instructions.len > 0) {92 for (instructions) |inst| {
68 for (instructions) |inst| {93 try writer.writeAll("\n\t");
69 try writer.writeAll("\n\t");94 switch (inst.tag) {
70 switch (inst.tag) {95 .assembly => try genAsm(file, inst.cast(Inst.Assembly).?, decl),
71 .assembly => {96 .call => try genCall(file, inst.cast(Inst.Call).?, decl),
72 const as = inst.cast(ir.Inst.Assembly).?.args;97 .ret => try genRet(file, inst.cast(Inst.Ret).?, decl, tv.ty.fnReturnType()),
73 for (as.inputs) |i, index| {98 else => |e| return file.fail(decl.src(), "TODO {}", .{e}),
74 if (i[0] == '{' and i[i.len - 1] == '}') {99 }
75 const reg = i[1 .. i.len - 1];100 }
76 const arg = as.args[index];101 try writer.writeAll("\n");
77 if (arg.cast(ir.Inst.Constant)) |c| {102 }
78 if (c.val.tag() == .int_u64) {103
79 try writer.writeAll("register ");104 try writer.writeAll("}\n\n");
80 try renderType(file, writer, arg.ty, decl.src());105}
81 try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() });106
82 } else {107fn genRet(file: *C, inst: *Inst.Ret, decl: *Decl, expected_return_type: Type) !void {
83 return file.fail(decl.src(), "TODO inline asm {} args", .{c.val.tag()});108 const writer = file.main.writer();
84 }109 const ret_value = inst.args.operand;
85 } else {110 const value = ret_value.value().?;
86 return file.fail(decl.src(), "TODO non-constant inline asm args", .{});111 if (expected_return_type.eql(ret_value.ty))
87 }112 return file.fail(decl.src(), "TODO return {}", .{expected_return_type})
88 } else {113 else if (expected_return_type.isInt() and ret_value.ty.tag() == .comptime_int)
89 return file.fail(decl.src(), "TODO non-explicit inline asm regs", .{});114 if (value.intFitsInType(expected_return_type, file.options.target))
90 }115 if (expected_return_type.intInfo(file.options.target).bits <= 64)
91 }116 try writer.print("return {};", .{value.toUnsignedInt()})
92 try writer.print("__asm {} (\"{}\"", .{ if (as.is_volatile) @as([]const u8, "volatile") else "", as.asm_source });117 else
93 if (as.output) |o| {118 return file.fail(decl.src(), "TODO return ints > 64 bits", .{})
94 return file.fail(decl.src(), "TODO inline asm output", .{});119 else
95 }120 return file.fail(decl.src(), "comptime int {} does not fit in {}", .{ value.toUnsignedInt(), expected_return_type })
96 if (as.inputs.len > 0) {121 else
97 if (as.output == null) {122 return file.fail(decl.src(), "return type mismatch: expected {}, found {}", .{ expected_return_type, ret_value.ty });
98 try writer.writeAll(" :");123}
99 }124
100 try writer.writeAll(": ");125fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
101 for (as.inputs) |i, index| {126 const writer = file.main.writer();
102 if (i[0] == '{' and i[i.len - 1] == '}') {127 const header = file.header.writer();
103 const reg = i[1 .. i.len - 1];128 if (inst.args.func.cast(Inst.Constant)) |func_inst| {
104 const arg = as.args[index];129 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
105 if (index > 0) {130 const target = func_val.func.owner_decl;
106 try writer.writeAll(", ");131 const target_ty = target.typed_value.most_recent.typed_value.ty;
107 }132 const ret_ty = target_ty.fnReturnType().tag();
108 if (arg.cast(ir.Inst.Constant)) |c| {133 if (target_ty.fnReturnType().hasCodeGenBits() and inst.base.isUnused()) {
109 try writer.print("\"\"({}_constant)", .{reg});134 try writer.print("(void)", .{});
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");
177 }135 }
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");154fn genAsm(file: *C, inst: *Inst.Assembly, decl: *Decl) !void {
180 },155 const as = inst.args;
181 .Array => {156 const writer = file.main.writer();
182 // TODO: prevent inline asm constants from being emitted157 for (as.inputs) |i, index| {
183 const name = try map(file.allocator, mem.span(decl.name));158 if (i[0] == '{' and i[i.len - 1] == '}') {
184 defer file.allocator.free(name);159 const reg = i[1 .. i.len - 1];
185 if (tv.val.cast(Value.Payload.Bytes)) |payload| {160 const arg = as.args[index];
186 if (tv.ty.arraySentinel()) |sentinel| {161 if (arg.cast(Inst.Constant)) |c| {
187 if (sentinel.toUnsignedInt() == 0) {162 if (c.val.tag() == .int_u64) {
188 try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data });163 try writer.writeAll("register ");
189 } else {164 try renderType(file, writer, arg.ty, decl.src());
190 return file.fail(decl.src(), "TODO byte arrays with non-zero sentinels", .{});165 try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() });
191 }
192 } else {166 } 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()});
194 }168 }
195 } else {169 } else {
196 return file.fail(decl.src(), "TODO non-byte arrays", .{});170 return file.fail(decl.src(), "TODO non-constant inline asm args", .{});
197 }171 }
198 },172 } else {
199 else => |e| {173 return file.fail(decl.src(), "TODO non-explicit inline asm regs", .{});
200 return file.fail(decl.src(), "TODO {}", .{e});174 }
201 },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 }
202 }203 }
204 try writer.writeAll(");");
203}205}