@@ -11,6 +11,8 @@ const C = link.File.C;
11
11
const Decl = Module .Decl ;
12
12
const mem = std .mem ;
13
13
14
+ const indentation = " " ;
15
+
14
16
/// Maps a name from Zig source to C. Currently, this will always give the same
15
17
/// output for any given input, sometimes resulting in broken identifiers.
16
18
fn map (allocator : * std.mem.Allocator , name : []const u8 ) ! []const u8 {
@@ -52,8 +54,10 @@ fn renderValue(ctx: *Context, writer: std.ArrayList(u8).Writer, T: Type, val: Va
52
54
fn renderFunctionSignature (ctx : * Context , writer : std .ArrayList (u8 ).Writer , decl : * Decl ) ! void {
53
55
const tv = decl .typed_value .most_recent .typed_value ;
54
56
try renderType (ctx , writer , tv .ty .fnReturnType ());
55
- const name = try map (ctx .file .base .allocator , mem .spanZ (decl .name ));
56
- defer ctx .file .base .allocator .free (name );
57
+ // Use the child allocator directly, as we know the name can be freed before
58
+ // the rest of the arena.
59
+ const name = try map (ctx .arena .child_allocator , mem .spanZ (decl .name ));
60
+ defer ctx .arena .child_allocator .free (name );
57
61
try writer .print (" {}(" , .{name });
58
62
var param_len = tv .ty .fnParamLen ();
59
63
if (param_len == 0 )
@@ -87,6 +91,7 @@ fn genArray(file: *C, decl: *Decl) !void {
87
91
if (tv .val .cast (Value .Payload .Bytes )) | payload |
88
92
if (tv .ty .sentinel ()) | sentinel |
89
93
if (sentinel .toUnsignedInt () == 0 )
94
+ // TODO: static by default
90
95
try file .constants .writer ().print ("const char *const {} = \" {}\" ;\n " , .{ name , payload .data })
91
96
else
92
97
return file .fail (decl .src (), "TODO byte arrays with non-zero sentinels" , .{})
@@ -99,22 +104,30 @@ fn genArray(file: *C, decl: *Decl) !void {
99
104
const Context = struct {
100
105
file : * C ,
101
106
decl : * Decl ,
102
- inst_map : std .AutoHashMap (* Inst , []u8 ),
107
+ inst_map : * std .AutoHashMap (* Inst , []u8 ),
108
+ arena : * std.heap.ArenaAllocator ,
103
109
argdex : usize = 0 ,
104
110
unnamed_index : usize = 0 ,
105
111
112
+ fn resolveInst (self : * Context , inst : * Inst ) ! []u8 {
113
+ if (inst .cast (Inst .Constant )) | const_inst | {
114
+ var out = std .ArrayList (u8 ).init (& self .arena .allocator );
115
+ try renderValue (self , out .writer (), inst .ty , const_inst .val );
116
+ return out .toOwnedSlice ();
117
+ }
118
+ if (self .inst_map .get (inst )) | val | {
119
+ return val ;
120
+ }
121
+ unreachable ;
122
+ }
123
+
106
124
fn name (self : * Context ) ! []u8 {
107
- const val = try std .fmt .allocPrint (self .file . base .allocator , "__temp_{}" , .{self .unnamed_index });
125
+ const val = try std .fmt .allocPrint (& self .arena .allocator , "__temp_{}" , .{self .unnamed_index });
108
126
self .unnamed_index += 1 ;
109
127
return val ;
110
128
}
111
129
112
130
fn deinit (self : * Context ) void {
113
- var it = self .inst_map .iterator ();
114
- while (it .next ()) | kv | {
115
- self .file .base .allocator .free (kv .value );
116
- }
117
- self .inst_map .deinit ();
118
131
self .* = undefined ;
119
132
}
120
133
};
@@ -123,10 +136,15 @@ fn genFn(file: *C, decl: *Decl) !void {
123
136
const writer = file .main .writer ();
124
137
const tv = decl .typed_value .most_recent .typed_value ;
125
138
139
+ var arena = std .heap .ArenaAllocator .init (file .base .allocator );
140
+ defer arena .deinit ();
141
+ var inst_map = std .AutoHashMap (* Inst , []u8 ).init (& arena .allocator );
142
+ defer inst_map .deinit ();
126
143
var ctx = Context {
127
144
.file = file ,
128
145
.decl = decl ,
129
- .inst_map = std .AutoHashMap (* Inst , []u8 ).init (file .base .allocator ),
146
+ .arena = & arena ,
147
+ .inst_map = & inst_map ,
130
148
};
131
149
defer ctx .deinit ();
132
150
@@ -142,6 +160,8 @@ fn genFn(file: *C, decl: *Decl) !void {
142
160
if (switch (inst .tag ) {
143
161
.assembly = > try genAsm (& ctx , inst .castTag (.assembly ).? ),
144
162
.call = > try genCall (& ctx , inst .castTag (.call ).? ),
163
+ .add = > try genBinOp (& ctx , inst .cast (Inst .BinOp ).? , "+" ),
164
+ .sub = > try genBinOp (& ctx , inst .cast (Inst .BinOp ).? , "-" ),
145
165
.ret = > try genRet (& ctx , inst .castTag (.ret ).? ),
146
166
.retvoid = > try genRetVoid (& ctx ),
147
167
.arg = > try genArg (& ctx ),
@@ -160,13 +180,13 @@ fn genFn(file: *C, decl: *Decl) !void {
160
180
}
161
181
162
182
fn genArg (ctx : * Context ) ! ? []u8 {
163
- const name = try std .fmt .allocPrint (ctx .file . base .allocator , "arg{}" , .{ctx .argdex });
183
+ const name = try std .fmt .allocPrint (& ctx .arena .allocator , "arg{}" , .{ctx .argdex });
164
184
ctx .argdex += 1 ;
165
185
return name ;
166
186
}
167
187
168
188
fn genRetVoid (ctx : * Context ) ! ? []u8 {
169
- try ctx .file .main .writer ().print (" return;\n " , .{});
189
+ try ctx .file .main .writer ().print (indentation ++ " return;\n " , .{});
170
190
return null ;
171
191
}
172
192
@@ -180,20 +200,32 @@ fn genIntCast(ctx: *Context, inst: *Inst.UnOp) !?[]u8 {
180
200
const op = inst .operand ;
181
201
const writer = ctx .file .main .writer ();
182
202
const name = try ctx .name ();
183
- const from = ctx .inst_map .get (op ) orelse
184
- return ctx .file .fail (ctx .decl .src (), "Internal error in C backend: intCast argument not found in inst_map" , .{});
185
- try writer .writeAll (" const " );
203
+ const from = try ctx .resolveInst (inst .operand );
204
+ try writer .writeAll (indentation ++ "const " );
186
205
try renderType (ctx , writer , inst .base .ty );
187
206
try writer .print (" {} = (" , .{name });
188
207
try renderType (ctx , writer , inst .base .ty );
189
208
try writer .print ("){};\n " , .{from });
190
209
return name ;
191
210
}
192
211
212
+ fn genBinOp (ctx : * Context , inst : * Inst.BinOp , comptime operator : []const u8 ) ! ? []u8 {
213
+ if (inst .base .isUnused ())
214
+ return null ;
215
+ const lhs = ctx .resolveInst (inst .lhs );
216
+ const rhs = ctx .resolveInst (inst .rhs );
217
+ const writer = ctx .file .main .writer ();
218
+ const name = try ctx .name ();
219
+ try writer .writeAll (indentation ++ "const " );
220
+ try renderType (ctx , writer , inst .base .ty );
221
+ try writer .print (" {} = {} " ++ operator ++ " {};\n " , .{ name , lhs , rhs });
222
+ return name ;
223
+ }
224
+
193
225
fn genCall (ctx : * Context , inst : * Inst.Call ) ! ? []u8 {
194
226
const writer = ctx .file .main .writer ();
195
227
const header = ctx .file .header .writer ();
196
- try writer .writeAll (" " );
228
+ try writer .writeAll (indentation );
197
229
if (inst .func .castTag (.constant )) | func_inst | {
198
230
if (func_inst .val .cast (Value .Payload .Function )) | func_val | {
199
231
const target = func_val .func .owner_decl ;
@@ -217,7 +249,8 @@ fn genCall(ctx: *Context, inst: *Inst.Call) !?[]u8 {
217
249
if (arg .cast (Inst .Constant )) | con | {
218
250
try renderValue (ctx , writer , arg .ty , con .val );
219
251
} else {
220
- return ctx .file .fail (ctx .decl .src (), "TODO call pass arg {}" , .{arg });
252
+ const val = try ctx .resolveInst (arg );
253
+ try writer .print ("{}" , .{val });
221
254
}
222
255
}
223
256
}
@@ -242,13 +275,13 @@ fn genBreak(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
242
275
}
243
276
244
277
fn genUnreach (ctx : * Context , inst : * Inst.NoOp ) ! ? []u8 {
245
- try ctx .file .main .writer ().writeAll (" zig_unreachable();\n " );
278
+ try ctx .file .main .writer ().writeAll (indentation ++ " zig_unreachable();\n " );
246
279
return null ;
247
280
}
248
281
249
282
fn genAsm (ctx : * Context , as : * Inst.Assembly ) ! ? []u8 {
250
283
const writer = ctx .file .main .writer ();
251
- try writer .writeAll (" " );
284
+ try writer .writeAll (indentation );
252
285
for (as .inputs ) | i , index | {
253
286
if (i [0 ] == '{' and i [i .len - 1 ] == '}' ) {
254
287
const reg = i [1 .. i .len - 1 ];
0 commit comments