| 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 | 2215 | self: *Module, |
| 2216 | 2216 | block: *Scope.Block, |
| 2217 | 2217 | src: usize, |
| 2218 | target_ptr: *Inst, | |
| 2218 | target: *Inst, | |
| 2219 | 2219 | cases: []Inst.SwitchBr.Case, |
| 2220 | 2220 | else_body: ir.Body, |
| 2221 | 2221 | ) !*Inst { |
| ... | ... | @@ -2226,7 +2226,7 @@ pub fn addSwitchBr( |
| 2226 | 2226 | .ty = Type.initTag(.noreturn), |
| 2227 | 2227 | .src = src, |
| 2228 | 2228 | }, |
| 2229 | .target_ptr = target_ptr, | |
| 2229 | .target = target, | |
| 2230 | 2230 | .cases = cases, |
| 2231 | 2231 | .else_body = else_body, |
| 2232 | 2232 | }; |
src/codegen/c.zig+35| ... | ... | @@ -129,6 +129,9 @@ pub const DeclGen = struct { |
| 129 | 129 | t: Type, |
| 130 | 130 | val: Value, |
| 131 | 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 | 135 | switch (t.zigTypeTag()) { |
| 133 | 136 | .Int => { |
| 134 | 137 | if (t.isSignedInt()) |
| ... | ... | @@ -196,6 +199,7 @@ pub const DeclGen = struct { |
| 196 | 199 | }, |
| 197 | 200 | } |
| 198 | 201 | }, |
| 202 | .Bool => return writer.print("{}", .{val.toBool()}), | |
| 199 | 203 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{ |
| 200 | 204 | @tagName(e), |
| 201 | 205 | }), |
| ... | ... | @@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 409 | 413 | .condbr => try genCondBr(o, inst.castTag(.condbr).?), |
| 410 | 414 | .br => try genBr(o, inst.castTag(.br).?), |
| 411 | 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 | 420 | else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}), |
| 413 | 421 | }; |
| 414 | 422 | switch (result_value) { |
| ... | ... | @@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue { |
| 688 | 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 | 726 | fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { |
| 692 | 727 | if (as.base.isUnused() and !as.is_volatile) |
| 693 | 728 | return CValue.none; |
src/ir.zig+2-2| ... | ... | @@ -521,7 +521,7 @@ pub const Inst = struct { |
| 521 | 521 | pub const base_tag = Tag.switchbr; |
| 522 | 522 | |
| 523 | 523 | base: Inst, |
| 524 | target_ptr: *Inst, | |
| 524 | target: *Inst, | |
| 525 | 525 | cases: []Case, |
| 526 | 526 | /// Set of instructions whose lifetimes end at the start of one of the cases. |
| 527 | 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 | 544 | var i = index; |
| 545 | 545 | |
| 546 | 546 | if (i < 1) |
| 547 | return self.target_ptr; | |
| 547 | return self.target; | |
| 548 | 548 | i -= 1; |
| 549 | 549 | |
| 550 | 550 | return null; |
test/stage2/cbe.zig+39-39| ... | ... | @@ -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 | 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 | 227 | ctx.c("empty start function", linux_x64, |
| 228 | 228 | \\export fn _start() noreturn { |
| 229 | 229 | \\ unreachable; |