authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-01-28 19:40:53+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-08 00:32:52+02:00
logca20d0ea26bba603229377f4843eb8772aeb749d
tree890e03ae83beef5061eccd31397cc09ddcaeb279
parent5d215cc76bcac12afbda7b10ec04bbf6c5b47910
signaturelock-open Commit is signed but in an unrecognized format.

stage2 cbe: pointer like optionals


2 files changed, 95 insertions(+), 1 deletions(-)

src/codegen/c.zig+80-1
......@@ -140,7 +140,7 @@ pub const DeclGen = struct {
140140 return writer.print("{d}", .{val.toUnsignedInt()});
141141 },
142142 .Pointer => switch (val.tag()) {
143 .undef, .zero => try writer.writeAll("0"),
143 .null_value, .zero => try writer.writeAll("NULL"),
144144 .one => try writer.writeAll("1"),
145145 .decl_ref => {
146146 const decl = val.castTag(.decl_ref).?.data;
......@@ -201,6 +201,20 @@ pub const DeclGen = struct {
201201 }
202202 },
203203 .Bool => return writer.print("{}", .{val.toBool()}),
204 .Optional => {
205 var opt_buf: Type.Payload.ElemType = undefined;
206 const child_type = t.optionalChild(&opt_buf);
207 if (t.isPtrLikeOptional()) {
208 return dg.renderValue(writer, child_type, val);
209 }
210 if (val.tag() == .null_value) {
211 try writer.writeAll("{ .is_null = true }");
212 } else {
213 try writer.writeAll("{ .is_null = false, .payload = ");
214 try dg.renderValue(writer, child_type, val);
215 try writer.writeAll(" }");
216 }
217 },
204218 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
205219 @tagName(e),
206220 }),
......@@ -299,6 +313,14 @@ pub const DeclGen = struct {
299313 try dg.renderType(w, t.elemType());
300314 try w.writeAll(" *");
301315 },
316 .Optional => {
317 var opt_buf: Type.Payload.ElemType = undefined;
318 const child_type = t.optionalChild(&opt_buf);
319 if (t.isPtrLikeOptional()) {
320 return dg.renderType(w, child_type);
321 }
322 return dg.fail(dg.decl.src(), "TODO: C backend: more optional types", .{});
323 },
302324 .Null, .Undefined => unreachable, // must be const or comptime
303325 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{
304326 @tagName(e),
......@@ -429,6 +451,13 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
429451 .bit_or => try genBinOp(o, inst.castTag(.bit_or).?, " | "),
430452 .xor => try genBinOp(o, inst.castTag(.xor).?, " ^ "),
431453 .not => try genUnOp(o, inst.castTag(.not).?, "!"),
454 .is_null => try genIsNull(o, inst.castTag(.is_null).?),
455 .is_non_null => try genIsNull(o, inst.castTag(.is_non_null).?),
456 .is_null_ptr => try genIsNull(o, inst.castTag(.is_null_ptr).?),
457 .is_non_null_ptr => try genIsNull(o, inst.castTag(.is_non_null_ptr).?),
458 .wrap_optional => try genWrapOptional(o, inst.castTag(.wrap_optional).?),
459 .optional_payload => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
460 .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
432461 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
433462 };
434463 switch (result_value) {
......@@ -802,6 +831,56 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
802831 return o.dg.fail(o.dg.decl.src(), "TODO: C backend: inline asm expression result used", .{});
803832}
804833
834fn genIsNull(o: *Object, inst: *Inst.UnOp) !CValue {
835 const writer = o.writer();
836 const invert_logic = inst.base.tag == .is_non_null or inst.base.tag == .is_non_null_ptr;
837 const maybe_deref = if (inst.base.tag == .is_null_ptr or inst.base.tag == .is_non_null_ptr) "[0]" else "";
838 const operand = try o.resolveInst(inst.operand);
839
840 const local = try o.allocLocal(Type.initTag(.bool), .Const);
841 try writer.writeAll(" = (");
842 try o.writeCValue(writer, operand);
843
844 if (inst.operand.ty.isPtrLikeOptional()) {
845 // operand is a regular pointer, test `operand !=/== NULL`
846 const operator = if (invert_logic) "!=" else "==";
847 try writer.print("){s} {s} NULL;\n", .{ maybe_deref, operator });
848 } else {
849 const operator = if (invert_logic) "!=" else "==";
850 try writer.print("){s}.is_null {s} true;\n", .{ maybe_deref, operator });
851 }
852 return local;
853}
854
855fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {
856 const writer = o.writer();
857 const operand = try o.resolveInst(inst.operand);
858
859 if (opt_ty.isPtrLikeOptional()) {
860 // the operand is just a regular pointer, no need to do anything special.
861 return operand;
862 }
863
864 const opt_ty = if (inst.operand.ty.zigTypeTag() == .Pointer)
865 inst.operand.ty.elemType()
866 else
867 inst.operand.ty;
868
869 return o.dg.fail(o.dg.decl.src(), "TODO: C backend: genOptionalPayload non ptr-like optionals", .{});
870}
871
872fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {
873 const writer = o.writer();
874 const operand = try o.resolveInst(inst.operand);
875
876 if (inst.base.ty.isPtrLikeOptional()) {
877 // the operand is just a regular pointer, no need to do anything special.
878 return operand;
879 }
880
881 return o.dg.fail(o.dg.decl.src(), "TODO: C backend: genWrapOptional non ptr-like optionals", .{});
882}
883
805884fn IndentWriter(comptime UnderlyingWriter: type) type {
806885 return struct {
807886 const Self = @This();
test/stage2/cbe.zig+15
......@@ -244,6 +244,21 @@ pub fn addCases(ctx: *TestContext) !void {
244244 \\}
245245 , "");
246246 }
247 {
248 var case = ctx.exeFromCompiledC("optionals", .{});
249
250 // Simple while loop
251 case.addCompareOutput(
252 \\export fn main() c_int {
253 \\ var count: c_int = 0;
254 \\ var opt_ptr: ?*c_int = &count;
255 \\ while (opt_ptr) |_| : (count += 1) {
256 \\ if (count == 4) opt_ptr = null;
257 \\ }
258 \\ return count - 5;
259 \\}
260 , "");
261 }
247262 ctx.c("empty start function", linux_x64,
248263 \\export fn _start() noreturn {
249264 \\ unreachable;