| ... | ... | @@ -11,6 +11,7 @@ const Type = @import("../type.zig").Type; |
| 11 | 11 | const C = link.File.C; |
| 12 | 12 | const Decl = Module.Decl; |
| 13 | 13 | const mem = std.mem; |
| 14 | const log = std.log.scoped(.c); |
| 14 | 15 | |
| 15 | 16 | const Writer = std.ArrayList(u8).Writer; |
| 16 | 17 | |
| ... | ... | @@ -22,7 +23,6 @@ fn map(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 { |
| 22 | 23 | |
| 23 | 24 | fn renderType( |
| 24 | 25 | ctx: *Context, |
| 25 | | header: *C.Header, |
| 26 | 26 | writer: Writer, |
| 27 | 27 | t: Type, |
| 28 | 28 | ) error{ OutOfMemory, AnalysisFail }!void { |
| ... | ... | @@ -80,12 +80,12 @@ fn renderType( |
| 80 | 80 | if (t.isVolatilePtr()) { |
| 81 | 81 | try writer.writeAll("volatile "); |
| 82 | 82 | } |
| 83 | | try renderType(ctx, header, writer, t.elemType()); |
| 83 | try renderType(ctx, writer, t.elemType()); |
| 84 | 84 | try writer.writeAll(" *"); |
| 85 | 85 | } |
| 86 | 86 | }, |
| 87 | 87 | .Array => { |
| 88 | | try renderType(ctx, header, writer, t.elemType()); |
| 88 | try renderType(ctx, writer, t.elemType()); |
| 89 | 89 | const sentinel_bit = @boolToInt(t.sentinel() != null); |
| 90 | 90 | const c_len = t.arrayLen() + sentinel_bit; |
| 91 | 91 | try writer.print("[{d}]", .{c_len}); |
| ... | ... | @@ -113,7 +113,16 @@ fn renderValue( |
| 113 | 113 | .one => try writer.writeAll("1"), |
| 114 | 114 | .decl_ref => { |
| 115 | 115 | const decl_ref_payload = val.cast(Value.Payload.DeclRef).?; |
| 116 | | try writer.print("&{s}", .{decl_ref_payload.decl.name}); |
| 116 | |
| 117 | // Determine if we must pointer cast. |
| 118 | const decl_tv = decl_ref_payload.decl.typed_value.most_recent.typed_value; |
| 119 | if (t.eql(decl_tv.ty)) { |
| 120 | try writer.print("&{s}", .{decl_ref_payload.decl.name}); |
| 121 | } else { |
| 122 | try writer.writeAll("("); |
| 123 | try renderType(ctx, writer, t); |
| 124 | try writer.print(")&{s}", .{decl_ref_payload.decl.name}); |
| 125 | } |
| 117 | 126 | }, |
| 118 | 127 | .function => { |
| 119 | 128 | const payload = val.cast(Value.Payload.Function).?; |
| ... | ... | @@ -155,12 +164,11 @@ fn renderValue( |
| 155 | 164 | |
| 156 | 165 | fn renderFunctionSignature( |
| 157 | 166 | ctx: *Context, |
| 158 | | header: *C.Header, |
| 159 | 167 | writer: Writer, |
| 160 | 168 | decl: *Decl, |
| 161 | 169 | ) !void { |
| 162 | 170 | const tv = decl.typed_value.most_recent.typed_value; |
| 163 | | try renderType(ctx, header, writer, tv.ty.fnReturnType()); |
| 171 | try renderType(ctx, writer, tv.ty.fnReturnType()); |
| 164 | 172 | // Use the child allocator directly, as we know the name can be freed before |
| 165 | 173 | // the rest of the arena. |
| 166 | 174 | const name = try map(ctx.arena.child_allocator, mem.spanZ(decl.name)); |
| ... | ... | @@ -175,7 +183,7 @@ fn renderFunctionSignature( |
| 175 | 183 | if (index > 0) { |
| 176 | 184 | try writer.writeAll(", "); |
| 177 | 185 | } |
| 178 | | try renderType(ctx, header, writer, tv.ty.fnParamType(index)); |
| 186 | try renderType(ctx, writer, tv.ty.fnParamType(index)); |
| 179 | 187 | try writer.print(" arg{}", .{index}); |
| 180 | 188 | } |
| 181 | 189 | } |
| ... | ... | @@ -194,6 +202,7 @@ pub fn generate(file: *C, decl: *Decl) !void { |
| 194 | 202 | .arena = &arena, |
| 195 | 203 | .inst_map = &inst_map, |
| 196 | 204 | .target = file.base.options.target, |
| 205 | .header = &file.header, |
| 197 | 206 | }; |
| 198 | 207 | defer { |
| 199 | 208 | file.error_msg = ctx.error_msg; |
| ... | ... | @@ -202,7 +211,7 @@ pub fn generate(file: *C, decl: *Decl) !void { |
| 202 | 211 | |
| 203 | 212 | if (tv.val.cast(Value.Payload.Function)) |func_payload| { |
| 204 | 213 | const writer = file.main.writer(); |
| 205 | | try renderFunctionSignature(&ctx, &file.header, writer, decl); |
| 214 | try renderFunctionSignature(&ctx, writer, decl); |
| 206 | 215 | |
| 207 | 216 | try writer.writeAll(" {"); |
| 208 | 217 | |
| ... | ... | @@ -211,9 +220,11 @@ pub fn generate(file: *C, decl: *Decl) !void { |
| 211 | 220 | if (instructions.len > 0) { |
| 212 | 221 | try writer.writeAll("\n"); |
| 213 | 222 | for (instructions) |inst| { |
| 214 | | const indent_size = 4; |
| 215 | | const indent_level = 1; |
| 216 | | try writer.writeByteNTimes(' ', indent_size * indent_level); |
| 223 | if (inst.tag != .dbg_stmt) { |
| 224 | const indent_size = 4; |
| 225 | const indent_level = 1; |
| 226 | try writer.writeByteNTimes(' ', indent_size * indent_level); |
| 227 | } |
| 217 | 228 | if (switch (inst.tag) { |
| 218 | 229 | .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?), |
| 219 | 230 | .call => try genCall(&ctx, file, inst.castTag(.call).?), |
| ... | ... | @@ -226,7 +237,7 @@ pub fn generate(file: *C, decl: *Decl) !void { |
| 226 | 237 | .breakpoint => try genBreak(&ctx, inst.castTag(.breakpoint).?), |
| 227 | 238 | .unreach => try genUnreach(file, inst.castTag(.unreach).?), |
| 228 | 239 | .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?), |
| 229 | | else => |e| return ctx.fail(decl.src(), "TODO implement C codegen for {}", .{e}), |
| 240 | else => |e| return ctx.fail(decl.src(), "TODO: C backend: implement codegen for {}", .{e}), |
| 230 | 241 | }) |name| { |
| 231 | 242 | try ctx.inst_map.putNoClobber(inst, name); |
| 232 | 243 | } |
| ... | ... | @@ -243,7 +254,7 @@ pub fn generate(file: *C, decl: *Decl) !void { |
| 243 | 254 | // TODO ask the Decl if it is const |
| 244 | 255 | // https://github.com/ziglang/zig/issues/7582 |
| 245 | 256 | |
| 246 | | try renderType(&ctx, &file.header, writer, tv.ty); |
| 257 | try renderType(&ctx, writer, tv.ty); |
| 247 | 258 | try writer.print(" {s} = ", .{decl.name}); |
| 248 | 259 | try renderValue(&ctx, writer, tv.ty, tv.val); |
| 249 | 260 | try writer.writeAll(";\n"); |
| ... | ... | @@ -269,9 +280,10 @@ pub fn generateHeader( |
| 269 | 280 | .arena = &arena, |
| 270 | 281 | .inst_map = &inst_map, |
| 271 | 282 | .target = comp.getTarget(), |
| 283 | .header = header, |
| 272 | 284 | }; |
| 273 | 285 | const writer = header.buf.writer(); |
| 274 | | renderFunctionSignature(&ctx, header, writer, decl) catch |err| { |
| 286 | renderFunctionSignature(&ctx, writer, decl) catch |err| { |
| 275 | 287 | if (err == error.AnalysisFail) { |
| 276 | 288 | try module.failed_decls.put(module.gpa, decl, ctx.error_msg); |
| 277 | 289 | } |
| ... | ... | @@ -291,6 +303,7 @@ const Context = struct { |
| 291 | 303 | unnamed_index: usize = 0, |
| 292 | 304 | error_msg: *Compilation.ErrorMsg = undefined, |
| 293 | 305 | target: std.Target, |
| 306 | header: *C.Header, |
| 294 | 307 | |
| 295 | 308 | fn resolveInst(self: *Context, inst: *Inst) ![]u8 { |
| 296 | 309 | if (inst.cast(Inst.Constant)) |const_inst| { |
| ... | ... | @@ -355,9 +368,9 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 { |
| 355 | 368 | const name = try ctx.name(); |
| 356 | 369 | const from = try ctx.resolveInst(inst.operand); |
| 357 | 370 | try writer.writeAll("const "); |
| 358 | | try renderType(ctx, &file.header, writer, inst.base.ty); |
| 371 | try renderType(ctx, writer, inst.base.ty); |
| 359 | 372 | try writer.print(" {} = (", .{name}); |
| 360 | | try renderType(ctx, &file.header, writer, inst.base.ty); |
| 373 | try renderType(ctx, writer, inst.base.ty); |
| 361 | 374 | try writer.print("){};\n", .{from}); |
| 362 | 375 | return name; |
| 363 | 376 | } |
| ... | ... | @@ -370,7 +383,7 @@ fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, comptime operator: []con |
| 370 | 383 | const writer = file.main.writer(); |
| 371 | 384 | const name = try ctx.name(); |
| 372 | 385 | try writer.writeAll("const "); |
| 373 | | try renderType(ctx, &file.header, writer, inst.base.ty); |
| 386 | try renderType(ctx, writer, inst.base.ty); |
| 374 | 387 | try writer.print(" {} = {} " ++ operator ++ " {};\n", .{ name, lhs, rhs }); |
| 375 | 388 | return name; |
| 376 | 389 | } |
| ... | ... | @@ -394,7 +407,7 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 { |
| 394 | 407 | const fn_name = mem.spanZ(fn_decl.name); |
| 395 | 408 | if (file.called.get(fn_name) == null) { |
| 396 | 409 | try file.called.put(fn_name, void{}); |
| 397 | | try renderFunctionSignature(ctx, &file.header, header, fn_decl); |
| 410 | try renderFunctionSignature(ctx, header, fn_decl); |
| 398 | 411 | try header.writeAll(";\n"); |
| 399 | 412 | } |
| 400 | 413 | try writer.print("{s}(", .{fn_name}); |
| ... | ... | @@ -440,7 +453,7 @@ fn genAsm(ctx: *Context, file: *C, as: *Inst.Assembly) !?[]u8 { |
| 440 | 453 | const reg = i[1 .. i.len - 1]; |
| 441 | 454 | const arg = as.args[index]; |
| 442 | 455 | try writer.writeAll("register "); |
| 443 | | try renderType(ctx, &file.header, writer, arg.ty); |
| 456 | try renderType(ctx, writer, arg.ty); |
| 444 | 457 | try writer.print(" {}_constant __asm__(\"{}\") = ", .{ reg, reg }); |
| 445 | 458 | // TODO merge constant handling into inst_map as well |
| 446 | 459 | if (arg.castTag(.constant)) |c| { |