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