| ... | @@ -140,7 +140,7 @@ pub const DeclGen = struct { | ... | @@ -140,7 +140,7 @@ pub const DeclGen = struct { |
| 140 | return writer.print("{d}", .{val.toUnsignedInt()}); | 140 | return writer.print("{d}", .{val.toUnsignedInt()}); |
| 141 | }, | 141 | }, |
| 142 | .Pointer => switch (val.tag()) { | 142 | .Pointer => switch (val.tag()) { |
| 143 | .undef, .zero => try writer.writeAll("0"), | 143 | .null_value, .zero => try writer.writeAll("NULL"), |
| 144 | .one => try writer.writeAll("1"), | 144 | .one => try writer.writeAll("1"), |
| 145 | .decl_ref => { | 145 | .decl_ref => { |
| 146 | const decl = val.castTag(.decl_ref).?.data; | 146 | const decl = val.castTag(.decl_ref).?.data; |
| ... | @@ -201,6 +201,20 @@ pub const DeclGen = struct { | ... | @@ -201,6 +201,20 @@ pub const DeclGen = struct { |
| 201 | } | 201 | } |
| 202 | }, | 202 | }, |
| 203 | .Bool => return writer.print("{}", .{val.toBool()}), | 203 | .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 | }, |
| 204 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{ | 218 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{ |
| 205 | @tagName(e), | 219 | @tagName(e), |
| 206 | }), | 220 | }), |
| ... | @@ -299,6 +313,14 @@ pub const DeclGen = struct { | ... | @@ -299,6 +313,14 @@ pub const DeclGen = struct { |
| 299 | try dg.renderType(w, t.elemType()); | 313 | try dg.renderType(w, t.elemType()); |
| 300 | try w.writeAll(" *"); | 314 | try w.writeAll(" *"); |
| 301 | }, | 315 | }, |
| | 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 | }, |
| 302 | .Null, .Undefined => unreachable, // must be const or comptime | 324 | .Null, .Undefined => unreachable, // must be const or comptime |
| 303 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{ | 325 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{ |
| 304 | @tagName(e), | 326 | @tagName(e), |
| ... | @@ -429,6 +451,13 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi | ... | @@ -429,6 +451,13 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 429 | .bit_or => try genBinOp(o, inst.castTag(.bit_or).?, " | "), | 451 | .bit_or => try genBinOp(o, inst.castTag(.bit_or).?, " | "), |
| 430 | .xor => try genBinOp(o, inst.castTag(.xor).?, " ^ "), | 452 | .xor => try genBinOp(o, inst.castTag(.xor).?, " ^ "), |
| 431 | .not => try genUnOp(o, inst.castTag(.not).?, "!"), | 453 | .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).?), |
| 432 | else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}), | 461 | else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}), |
| 433 | }; | 462 | }; |
| 434 | switch (result_value) { | 463 | switch (result_value) { |
| ... | @@ -802,6 +831,56 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { | ... | @@ -802,6 +831,56 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { |
| 802 | return o.dg.fail(o.dg.decl.src(), "TODO: C backend: inline asm expression result used", .{}); | 831 | return o.dg.fail(o.dg.decl.src(), "TODO: C backend: inline asm expression result used", .{}); |
| 803 | } | 832 | } |
| 804 | | 833 | |
| | 834 | fn 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 | |
| | 855 | fn 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 | |
| | 872 | fn 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 | |
| 805 | fn IndentWriter(comptime UnderlyingWriter: type) type { | 884 | fn IndentWriter(comptime UnderlyingWriter: type) type { |
| 806 | return struct { | 885 | return struct { |
| 807 | const Self = @This(); | 886 | const Self = @This(); |