| author | |
| committer | |
| log | 106520329e5adc6cf5ef83595da6c9d5dd3c4b35 |
| tree | da0ceaa068638cd12ae91ce56795e88c8d7c367c |
| parent | 258f3ec5ecf8d2a165382d5837bed0dac2e0375b |
| signature |
4 files changed, 78 insertions(+), 43 deletions(-)
src/Module.zig+2-2| ... | @@ -2215,7 +2215,7 @@ pub fn addSwitchBr( | ... | @@ -2215,7 +2215,7 @@ pub fn addSwitchBr( |
| 2215 | self: *Module, | 2215 | self: *Module, |
| 2216 | block: *Scope.Block, | 2216 | block: *Scope.Block, |
| 2217 | src: usize, | 2217 | src: usize, |
| 2218 | target_ptr: *Inst, | 2218 | target: *Inst, |
| 2219 | cases: []Inst.SwitchBr.Case, | 2219 | cases: []Inst.SwitchBr.Case, |
| 2220 | else_body: ir.Body, | 2220 | else_body: ir.Body, |
| 2221 | ) !*Inst { | 2221 | ) !*Inst { |
| ... | @@ -2226,7 +2226,7 @@ pub fn addSwitchBr( | ... | @@ -2226,7 +2226,7 @@ pub fn addSwitchBr( |
| 2226 | .ty = Type.initTag(.noreturn), | 2226 | .ty = Type.initTag(.noreturn), |
| 2227 | .src = src, | 2227 | .src = src, |
| 2228 | }, | 2228 | }, |
| 2229 | .target_ptr = target_ptr, | 2229 | .target = target, |
| 2230 | .cases = cases, | 2230 | .cases = cases, |
| 2231 | .else_body = else_body, | 2231 | .else_body = else_body, |
| 2232 | }; | 2232 | }; |
src/codegen/c.zig+35| ... | @@ -129,6 +129,9 @@ pub const DeclGen = struct { | ... | @@ -129,6 +129,9 @@ pub const DeclGen = struct { |
| 129 | t: Type, | 129 | t: Type, |
| 130 | val: Value, | 130 | val: Value, |
| 131 | ) error{ OutOfMemory, AnalysisFail }!void { | 131 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 132 | if (val.isUndef()) { | ||
| 133 | return dg.fail(dg.decl.src(), "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{}); | ||
| 134 | } | ||
| 132 | switch (t.zigTypeTag()) { | 135 | switch (t.zigTypeTag()) { |
| 133 | .Int => { | 136 | .Int => { |
| 134 | if (t.isSignedInt()) | 137 | if (t.isSignedInt()) |
| ... | @@ -196,6 +199,7 @@ pub const DeclGen = struct { | ... | @@ -196,6 +199,7 @@ pub const DeclGen = struct { |
| 196 | }, | 199 | }, |
| 197 | } | 200 | } |
| 198 | }, | 201 | }, |
| 202 | .Bool => return writer.print("{}", .{val.toBool()}), | ||
| 199 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{ | 203 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{ |
| 200 | @tagName(e), | 204 | @tagName(e), |
| 201 | }), | 205 | }), |
| ... | @@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi | ... | @@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 409 | .condbr => try genCondBr(o, inst.castTag(.condbr).?), | 413 | .condbr => try genCondBr(o, inst.castTag(.condbr).?), |
| 410 | .br => try genBr(o, inst.castTag(.br).?), | 414 | .br => try genBr(o, inst.castTag(.br).?), |
| 411 | .brvoid => try genBrVoid(o, inst.castTag(.brvoid).?.block), | 415 | .brvoid => try genBrVoid(o, inst.castTag(.brvoid).?.block), |
| 416 | .switchbr => try genSwitchBr(o, inst.castTag(.switchbr).?), | ||
| 417 | // booland and boolor are non-short-circuit operations | ||
| 418 | .booland => try genBinOp(o, inst.castTag(.booland).?, " & "), | ||
| 419 | .boolor => try genBinOp(o, inst.castTag(.boolor).?, " | "), | ||
| 412 | else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}), | 420 | else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}), |
| 413 | }; | 421 | }; |
| 414 | switch (result_value) { | 422 | switch (result_value) { |
| ... | @@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue { | ... | @@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue { |
| 688 | return CValue.none; | 696 | return CValue.none; |
| 689 | } | 697 | } |
| 690 | 698 | ||
| 699 | fn genSwitchBr(o: *Object, inst: *Inst.SwitchBr) !CValue { | ||
| 700 | const target = try o.resolveInst(inst.target); | ||
| 701 | const writer = o.writer(); | ||
| 702 | |||
| 703 | try writer.writeAll("switch ("); | ||
| 704 | try o.writeCValue(writer, target); | ||
| 705 | try writer.writeAll(") {\n"); | ||
| 706 | o.indent_writer.pushIndent(); | ||
| 707 | |||
| 708 | for (inst.cases) |case| { | ||
| 709 | try writer.writeAll("case "); | ||
| 710 | try o.dg.renderValue(writer, inst.target.ty, case.item); | ||
| 711 | try writer.writeAll(": "); | ||
| 712 | // the case body must be noreturn so we don't need to insert a break | ||
| 713 | try genBody(o, case.body); | ||
| 714 | try o.indent_writer.insertNewline(); | ||
| 715 | } | ||
| 716 | |||
| 717 | try writer.writeAll("default: "); | ||
| 718 | try genBody(o, inst.else_body); | ||
| 719 | try o.indent_writer.insertNewline(); | ||
| 720 | |||
| 721 | o.indent_writer.popIndent(); | ||
| 722 | try writer.writeAll("}\n"); | ||
| 723 | return CValue.none; | ||
| 724 | } | ||
| 725 | |||
| 691 | fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { | 726 | fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { |
| 692 | if (as.base.isUnused() and !as.is_volatile) | 727 | if (as.base.isUnused() and !as.is_volatile) |
| 693 | return CValue.none; | 728 | return CValue.none; |
src/ir.zig+2-2| ... | @@ -521,7 +521,7 @@ pub const Inst = struct { | ... | @@ -521,7 +521,7 @@ pub const Inst = struct { |
| 521 | pub const base_tag = Tag.switchbr; | 521 | pub const base_tag = Tag.switchbr; |
| 522 | 522 | ||
| 523 | base: Inst, | 523 | base: Inst, |
| 524 | target_ptr: *Inst, | 524 | target: *Inst, |
| 525 | cases: []Case, | 525 | cases: []Case, |
| 526 | /// Set of instructions whose lifetimes end at the start of one of the cases. | 526 | /// Set of instructions whose lifetimes end at the start of one of the cases. |
| 527 | /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ]. | 527 | /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ]. |
| ... | @@ -544,7 +544,7 @@ pub const Inst = struct { | ... | @@ -544,7 +544,7 @@ pub const Inst = struct { |
| 544 | var i = index; | 544 | var i = index; |
| 545 | 545 | ||
| 546 | if (i < 1) | 546 | if (i < 1) |
| 547 | return self.target_ptr; | 547 | return self.target; |
| 548 | i -= 1; | 548 | i -= 1; |
| 549 | 549 | ||
| 550 | return null; | 550 | return null; |
test/stage2/cbe.zig+39-39| ... | @@ -133,45 +133,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -133,45 +133,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 133 | \\} | 133 | \\} |
| 134 | \\ | 134 | \\ |
| 135 | , ""); | 135 | , ""); |
| 136 | |||
| 137 | // Simple while loop | ||
| 138 | case.addCompareOutput( | ||
| 139 | \\export fn main() c_int { | ||
| 140 | \\ var a: c_int = 0; | ||
| 141 | \\ while (a < 5) : (a+=1) {} | ||
| 142 | \\ exit(a - 5); | ||
| 143 | \\} | ||
| 144 | \\ | ||
| 145 | \\fn exit(code: usize) noreturn { | ||
| 146 | \\ asm volatile ("syscall" | ||
| 147 | \\ : | ||
| 148 | \\ : [number] "{rax}" (231), | ||
| 149 | \\ [arg1] "{rdi}" (code) | ||
| 150 | \\ ); | ||
| 151 | \\ unreachable; | ||
| 152 | \\} | ||
| 153 | , ""); | ||
| 154 | |||
| 155 | // If expression | ||
| 156 | case.addCompareOutput( | ||
| 157 | \\export fn main() c_int { | ||
| 158 | \\ var cond: c_int = 0; | ||
| 159 | \\ var a: c_int = @as(c_int, if (cond == 0) | ||
| 160 | \\ 2 | ||
| 161 | \\ else | ||
| 162 | \\ 3) + 9; | ||
| 163 | \\ exit(a - 11); | ||
| 164 | \\} | ||
| 165 | \\ | ||
| 166 | \\fn exit(code: usize) noreturn { | ||
| 167 | \\ asm volatile ("syscall" | ||
| 168 | \\ : | ||
| 169 | \\ : [number] "{rax}" (231), | ||
| 170 | \\ [arg1] "{rdi}" (code) | ||
| 171 | \\ ); | ||
| 172 | \\ unreachable; | ||
| 173 | \\} | ||
| 174 | , ""); | ||
| 175 | } | 136 | } |
| 176 | 137 | ||
| 177 | { | 138 | { |
| ... | @@ -224,6 +185,45 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -224,6 +185,45 @@ pub fn addCases(ctx: *TestContext) !void { |
| 224 | \\} | 185 | \\} |
| 225 | , ""); | 186 | , ""); |
| 226 | } | 187 | } |
| 188 | { | ||
| 189 | var case = ctx.exeFromCompiledC("control flow", .{}); | ||
| 190 | |||
| 191 | // Simple while loop | ||
| 192 | case.addCompareOutput( | ||
| 193 | \\export fn main() c_int { | ||
| 194 | \\ var a: c_int = 0; | ||
| 195 | \\ while (a < 5) : (a+=1) {} | ||
| 196 | \\ return a - 5; | ||
| 197 | \\} | ||
| 198 | , ""); | ||
| 199 | |||
| 200 | // If expression | ||
| 201 | case.addCompareOutput( | ||
| 202 | \\export fn main() c_int { | ||
| 203 | \\ var cond: c_int = 0; | ||
| 204 | \\ var a: c_int = @as(c_int, if (cond == 0) | ||
| 205 | \\ 2 | ||
| 206 | \\ else | ||
| 207 | \\ 3) + 9; | ||
| 208 | \\ return a - 11; | ||
| 209 | \\} | ||
| 210 | , ""); | ||
| 211 | |||
| 212 | // Switch expression | ||
| 213 | case.addCompareOutput( | ||
| 214 | \\export fn main() c_int { | ||
| 215 | \\ var cond: c_int = 0; | ||
| 216 | \\ var a: c_int = switch (cond) { | ||
| 217 | \\ 1 => 1, | ||
| 218 | \\ 2 => 2, | ||
| 219 | \\ 99...300, 12 => 3, | ||
| 220 | \\ 0 => 4, | ||
| 221 | \\ else => 5, | ||
| 222 | \\ }; | ||
| 223 | \\ return a - 4; | ||
| 224 | \\} | ||
| 225 | , ""); | ||
| 226 | } | ||
| 227 | ctx.c("empty start function", linux_x64, | 227 | ctx.c("empty start function", linux_x64, |
| 228 | \\export fn _start() noreturn { | 228 | \\export fn _start() noreturn { |
| 229 | \\ unreachable; | 229 | \\ unreachable; |