authorgravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-08-11 10:24:32-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-12 21:58:21-07:00
log5a166cead80d4d77bffba0b116fdeffb5820f5a4
treef2a60d219fb889fdd23358a2538da9602c727bb6
parentdbd1e42ef227bf55e9356b2d1a1cbde1fbec0e82

CBE: fix handling of IR dependencies


3 files changed, 102 insertions(+), 54 deletions(-)

src-self-hosted/codegen/c.zig+99-52
......@@ -94,6 +94,28 @@ fn genArray(file: *C, decl: *Decl) !void {
9494 return file.fail(decl.src(), "TODO non-byte arrays", .{});
9595}
9696
97const Context = struct {
98 file: *C,
99 decl: *Decl,
100 inst_map: std.AutoHashMap(*Inst, []u8),
101 argdex: usize = 0,
102 unnamed_index: usize = 0,
103
104 fn name(self: *Context) ![]u8 {
105 const val = try std.fmt.allocPrint(self.file.base.allocator, "__temp_{}", .{self.unnamed_index});
106 self.unnamed_index += 1;
107 return val;
108 }
109
110 fn deinit(self: *Context) void {
111 for (self.inst_map.items()) |kv| {
112 self.file.base.allocator.free(kv.value);
113 }
114 self.inst_map.deinit();
115 self.* = undefined;
116 }
117};
118
97119fn genFn(file: *C, decl: *Decl) !void {
98120 const writer = file.main.writer();
99121 const tv = decl.typed_value.most_recent.typed_value;
......@@ -102,24 +124,31 @@ fn genFn(file: *C, decl: *Decl) !void {
102124
103125 try writer.writeAll(" {");
104126
127 var ctx = Context{
128 .file = file,
129 .decl = decl,
130 .inst_map = std.AutoHashMap(*Inst, []u8).init(file.base.allocator),
131 };
132 defer ctx.deinit();
133
105134 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;
106135 const instructions = func.analysis.success.instructions;
107 var argdex: usize = 0;
108136 if (instructions.len > 0) {
109137 try writer.writeAll("\n");
110138 for (instructions) |inst| {
111 switch (inst.tag) {
112 .assembly => try genAsm(file, inst.castTag(.assembly).?, decl, &argdex),
113 .call => try genCall(file, inst.castTag(.call).?, decl),
114 .ret => try genRet(file, inst.castTag(.ret).?, decl, tv.ty.fnReturnType()),
115 .retvoid => try file.main.writer().print(" return;\n", .{}),
116 .arg => {},
117 .dbg_stmt => try genDbgStmt(file, inst.castTag(.dbg_stmt).?, decl),
118 .breakpoint => try genBreak(file, inst.castTag(.breakpoint).?, decl),
119 .unreach => try genUnreach(file, inst.castTag(.unreach).?, decl),
120 // This will be handled correctly later?
121 .intcast => {},
139 if (switch (inst.tag) {
140 .assembly => try genAsm(&ctx, inst.castTag(.assembly).?),
141 .call => try genCall(&ctx, inst.castTag(.call).?),
142 .ret => try genRet(&ctx, inst.castTag(.ret).?),
143 .retvoid => try genRetVoid(&ctx),
144 .arg => try genArg(&ctx),
145 .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),
146 .breakpoint => try genBreak(&ctx, inst.castTag(.breakpoint).?),
147 .unreach => try genUnreach(&ctx, inst.castTag(.unreach).?),
148 .intcast => try genIntCast(&ctx, inst.castTag(.intcast).?),
122149 else => |e| return file.fail(decl.src(), "TODO implement C codegen for {}", .{e}),
150 }) |name| {
151 try ctx.inst_map.putNoClobber(inst, name);
123152 }
124153 }
125154 }
......@@ -127,27 +156,40 @@ fn genFn(file: *C, decl: *Decl) !void {
127156 try writer.writeAll("}\n\n");
128157}
129158
130fn genRet(file: *C, inst: *Inst.UnOp, decl: *Decl, expected_return_type: Type) !void {
131 return file.fail(decl.src(), "TODO return {}", .{expected_return_type});
159fn genArg(ctx: *Context) !?[]u8 {
160 const name = try std.fmt.allocPrint(ctx.file.base.allocator, "arg{}", .{ctx.argdex});
161 ctx.argdex += 1;
162 return name;
163}
164
165fn genRetVoid(ctx: *Context) !?[]u8 {
166 try ctx.file.main.writer().print(" return;\n", .{});
167 return null;
132168}
133169
134fn genIntCast(file: *C, inst: *Inst.UnOp, decl: *Decl, argdex: *usize) !void {
170fn genRet(ctx: *Context, inst: *Inst.UnOp) !?[]u8 {
171 return ctx.file.fail(ctx.decl.src(), "TODO return", .{});
172}
173
174fn genIntCast(ctx: *Context, inst: *Inst.UnOp) !?[]u8 {
175 if (inst.base.isUnused())
176 return null;
135177 const op = inst.operand;
136 const writer = file.main.writer();
137 try writer.writeByte('(');
138 try renderType(file, writer, inst.base.ty, decl.src());
139 try writer.writeByte(')');
140 if (op.castTag(.arg)) |_| {
141 try writer.print("arg{}", .{argdex.*});
142 argdex.* += 1;
143 } else {
144 return file.fail(decl.src(), "TODO intcast {} to {}", .{ op, inst.base.ty });
145 }
178 const writer = ctx.file.main.writer();
179 const name = try ctx.name();
180 const from = ctx.inst_map.get(op) orelse
181 return ctx.file.fail(ctx.decl.src(), "Internal error in C backend: intCast argument not found in inst_map", .{});
182 try writer.writeAll(" const ");
183 try renderType(ctx.file, writer, inst.base.ty, ctx.decl.src());
184 try writer.print(" {} = (", .{name});
185 try renderType(ctx.file, writer, inst.base.ty, ctx.decl.src());
186 try writer.print("){};\n", .{from});
187 return name;
146188}
147189
148fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
149 const writer = file.main.writer();
150 const header = file.header.writer();
190fn genCall(ctx: *Context, inst: *Inst.Call) !?[]u8 {
191 const writer = ctx.file.main.writer();
192 const header = ctx.file.header.writer();
151193 try writer.writeAll(" ");
152194 if (inst.func.castTag(.constant)) |func_inst| {
153195 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
......@@ -158,9 +200,9 @@ fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
158200 try writer.print("(void)", .{});
159201 }
160202 const tname = mem.spanZ(target.name);
161 if (file.called.get(tname) == null) {
162 try file.called.put(tname, void{});
163 try renderFunctionSignature(file, header, target);
203 if (ctx.file.called.get(tname) == null) {
204 try ctx.file.called.put(tname, void{});
205 try renderFunctionSignature(ctx.file, header, target);
164206 try header.writeAll(";\n");
165207 }
166208 try writer.print("{}(", .{tname});
......@@ -170,61 +212,65 @@ fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
170212 try writer.writeAll(", ");
171213 }
172214 if (arg.cast(Inst.Constant)) |con| {
173 try renderValue(file, writer, con.val, decl.src());
215 try renderValue(ctx.file, writer, con.val, ctx.decl.src());
174216 } else {
175 return file.fail(decl.src(), "TODO call pass arg {}", .{arg});
217 return ctx.file.fail(ctx.decl.src(), "TODO call pass arg {}", .{arg});
176218 }
177219 }
178220 }
179221 try writer.writeAll(");\n");
180222 } else {
181 return file.fail(decl.src(), "TODO non-function call target?", .{});
223 return ctx.file.fail(ctx.decl.src(), "TODO non-function call target?", .{});
182224 }
183225 } else {
184 return file.fail(decl.src(), "TODO non-constant call inst?", .{});
226 return ctx.file.fail(ctx.decl.src(), "TODO non-constant call inst?", .{});
185227 }
228 return null;
186229}
187230
188fn genDbgStmt(file: *C, inst: *Inst.NoOp, decl: *Decl) !void {
231fn genDbgStmt(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
189232 // TODO emit #line directive here with line number and filename
233 return null;
190234}
191235
192fn genBreak(file: *C, inst: *Inst.NoOp, decl: *Decl) !void {
236fn genBreak(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
193237 // TODO ??
238 return null;
194239}
195240
196fn genUnreach(file: *C, inst: *Inst.NoOp, decl: *Decl) !void {
197 try file.main.writer().writeAll(" zig_unreachable();\n");
241fn genUnreach(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
242 try ctx.file.main.writer().writeAll(" zig_unreachable();\n");
243 return null;
198244}
199245
200fn genAsm(file: *C, as: *Inst.Assembly, decl: *Decl, argdex: *usize) !void {
201 const writer = file.main.writer();
246fn genAsm(ctx: *Context, as: *Inst.Assembly) !?[]u8 {
247 const writer = ctx.file.main.writer();
202248 try writer.writeAll(" ");
203249 for (as.inputs) |i, index| {
204250 if (i[0] == '{' and i[i.len - 1] == '}') {
205251 const reg = i[1 .. i.len - 1];
206252 const arg = as.args[index];
207253 try writer.writeAll("register ");
208 try renderType(file, writer, arg.ty, decl.src());
254 try renderType(ctx.file, writer, arg.ty, ctx.decl.src());
209255 try writer.print(" {}_constant __asm__(\"{}\") = ", .{ reg, reg });
256 // TODO merge constant handling into inst_map as well
210257 if (arg.castTag(.constant)) |c| {
211 try renderValue(file, writer, c.val, decl.src());
212 } else if (arg.castTag(.arg)) |inst| {
213 try writer.print("arg{}", .{argdex.*});
214 argdex.* += 1;
215 } else if (arg.castTag(.intcast)) |inst| {
216 try genIntCast(file, inst, decl, argdex);
258 try renderValue(ctx.file, writer, c.val, ctx.decl.src());
259 try writer.writeAll(";\n ");
217260 } else {
218 return file.fail(decl.src(), "TODO non-constant inline asm args ({})", .{arg.tag});
261 const gop = try ctx.inst_map.getOrPut(arg);
262 if (!gop.found_existing) {
263 return ctx.file.fail(ctx.decl.src(), "Internal error in C backend: asm argument not found in inst_map", .{});
264 }
265 try writer.print("{};\n ", .{gop.entry.value});
219266 }
220 try writer.writeAll(";\n ");
221267 } else {
222 return file.fail(decl.src(), "TODO non-explicit inline asm regs", .{});
268 return ctx.file.fail(ctx.decl.src(), "TODO non-explicit inline asm regs", .{});
223269 }
224270 }
225271 try writer.print("__asm {} (\"{}\"", .{ if (as.is_volatile) @as([]const u8, "volatile") else "", as.asm_source });
226272 if (as.output) |o| {
227 return file.fail(decl.src(), "TODO inline asm output", .{});
273 return ctx.file.fail(ctx.decl.src(), "TODO inline asm output", .{});
228274 }
229275 if (as.inputs.len > 0) {
230276 if (as.output == null) {
......@@ -246,4 +292,5 @@ fn genAsm(file: *C, as: *Inst.Assembly, decl: *Decl, argdex: *usize) !void {
246292 }
247293 }
248294 try writer.writeAll(");\n");
295 return null;
249296}
src-self-hosted/link.zig+1-1
......@@ -229,7 +229,7 @@ pub const File = struct {
229229 return &c_file.base;
230230 }
231231
232 pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {
232 pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) anyerror {
233233 self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args);
234234 return error.AnalysisFail;
235235 }
test/stage2/cbe.zig+2-1
......@@ -129,8 +129,9 @@ pub fn addCases(ctx: *TestContext) !void {
129129 \\}
130130 \\
131131 \\zig_noreturn void exit(uint8_t arg0) {
132 \\ const size_t __temp_0 = (size_t)arg0;
132133 \\ register size_t rax_constant __asm__("rax") = 231;
133 \\ register size_t rdi_constant __asm__("rdi") = (size_t)arg0;
134 \\ register size_t rdi_constant __asm__("rdi") = __temp_0;
134135 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
135136 \\ zig_unreachable();
136137 \\}