aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-12-31 01:54:02 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-12-31 01:54:02 -0700
commita46d24af1cf2885991c67bf39a2e639891c16121 (patch)
treed4f3c81b798cbae420819434c810a52b6817a85b /src/codegen
parent3f7d9b5fc19e4081236b3b63aebbc80e1b17f5b5 (diff)
downloadzig-a46d24af1cf2885991c67bf39a2e639891c16121.tar.gz
zig-a46d24af1cf2885991c67bf39a2e639891c16121.zip
stage2: inferred local variables
This patch introduces the following new things: Types: - inferred_alloc - This is a special value that tracks a set of types that have been stored to an inferred allocation. It does not support most of the normal type queries. However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. - The payload for this type simply points to the corresponding Value payload. Values: - inferred_alloc - This is a special value that tracks a set of types that have been stored to an inferred allocation. It does not support any of the normal value queries. ZIR instructions: - store_to_inferred_ptr, - Same as `store` but the type of the value being stored will be used to infer the pointer type. - resolve_inferred_alloc - Each `store_to_inferred_ptr` puts the type of the stored value into a set, and then `resolve_inferred_alloc` triggers peer type resolution on the set. The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which is the allocation that needs to have its type inferred. Changes to the C backend: * Implements the bitcast instruction. If the source and dest types are both pointers, uses a cast, otherwise uses memcpy. * Tests are run with -Wno-declaration-after-statement. Someday we can conform to this but not today. In ZIR form it looks like this: ```zir fn_body main { // unanalyzed %0 = dbg_stmt() =>%1 = alloc_inferred() %2 = declval_in_module(Decl(add)) %3 = deref(%2) %4 = param_type(%3, 0) %5 = const(TypedValue{ .ty = comptime_int, .val = 1}) %6 = as(%4, %5) %7 = param_type(%3, 1) %8 = const(TypedValue{ .ty = comptime_int, .val = 2}) %9 = as(%7, %8) %10 = call(%3, [%6, %9], modifier=auto) =>%11 = store_to_inferred_ptr(%1, %10) =>%12 = resolve_inferred_alloc(%1) %13 = dbg_stmt() %14 = ret_type() %15 = const(TypedValue{ .ty = comptime_int, .val = 3}) %16 = sub(%10, %15) %17 = as(%14, %16) %18 = return(%17) } // fn_body main ``` I have not played around with very many test cases yet. Some interesting ones that I want to look at before merging: ```zig var x = blk: { var y = foo(); y.a = 1; break :blk y; }; ``` In the above test case, x and y are supposed to alias. ```zig var x = if (bar()) blk: { var y = foo(); y.a = 1; break :blk y; } else blk: { var z = baz(); z.b = 1; break :blk z; }; ``` In the above test case, x, y, and z are supposed to alias. I also haven't tested with `var` instead of `const` yet.
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig20
1 files changed, 20 insertions, 0 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 7cd4479bd9..6d9563b991 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -275,6 +275,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
try writer.writeAll(" {");
const func: *Module.Fn = func_payload.data;
+ //func.dump(module.*);
const instructions = func.analysis.success.instructions;
if (instructions.len > 0) {
try writer.writeAll("\n");
@@ -285,6 +286,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
.arg => try genArg(&ctx),
.assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
.block => try genBlock(&ctx, file, inst.castTag(.block).?),
+ .bitcast => try genBitcast(&ctx, file, inst.castTag(.bitcast).?),
.breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
.call => try genCall(&ctx, file, inst.castTag(.call).?),
.cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="),
@@ -537,6 +539,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {
return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});
}
+fn genBitcast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
+ const writer = file.main.writer();
+ try indent(file);
+ const local_name = try ctx.name();
+ const operand = try ctx.resolveInst(inst.operand);
+ try renderTypeAndName(ctx, writer, inst.base.ty, local_name, .Const);
+ if (inst.base.ty.zigTypeTag() == .Pointer and inst.operand.ty.zigTypeTag() == .Pointer) {
+ try writer.writeAll(" = (");
+ try renderType(ctx, writer, inst.base.ty);
+ try writer.print("){s};\n", .{operand});
+ } else {
+ try writer.writeAll(";\n");
+ try indent(file);
+ try writer.print("memcpy(&{s}, &{s}, sizeof {s});\n", .{ local_name, operand, local_name });
+ }
+ return local_name;
+}
+
fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {
try indent(file);
try file.main.writer().writeAll("zig_breakpoint();\n");