diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-12-31 01:54:02 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-12-31 01:54:02 -0700 |
| commit | a46d24af1cf2885991c67bf39a2e639891c16121 (patch) | |
| tree | d4f3c81b798cbae420819434c810a52b6817a85b /src/codegen | |
| parent | 3f7d9b5fc19e4081236b3b63aebbc80e1b17f5b5 (diff) | |
| download | zig-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.zig | 20 |
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"); |
