diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-10-20 14:10:37 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-10-20 14:10:37 -0700 |
| commit | ed2a5081e1f379cf089f7700a2818db35faadc05 (patch) | |
| tree | db42e8cdfddcd712d7f3f01fd4bcd015f9a20d6d /src/codegen | |
| parent | dfb3231959bb340d260ddbec2b8eabfb5063c1bf (diff) | |
| download | zig-ed2a5081e1f379cf089f7700a2818db35faadc05.tar.gz zig-ed2a5081e1f379cf089f7700a2818db35faadc05.zip | |
stage2: LLVM backend: implement switch_br
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm.zig | 54 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 6 |
2 files changed, 49 insertions, 11 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index bcffc1f0a2..5dc0a251bd 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1993,23 +1993,55 @@ pub const FuncGen = struct { const then_block = self.context.appendBasicBlock(self.llvm_func, "Then"); const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); - { - const prev_block = self.builder.getInsertBlock(); - defer self.builder.positionBuilderAtEnd(prev_block); + _ = self.builder.buildCondBr(cond, then_block, else_block); - self.builder.positionBuilderAtEnd(then_block); - try self.genBody(then_body); + self.builder.positionBuilderAtEnd(then_block); + try self.genBody(then_body); - self.builder.positionBuilderAtEnd(else_block); - try self.genBody(else_body); - } - _ = self.builder.buildCondBr(cond, then_block, else_block); + self.builder.positionBuilderAtEnd(else_block); + try self.genBody(else_body); + + // No need to reset the insert cursor since this instruction is noreturn. return null; } fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { - _ = inst; - return self.todo("implement llvm codegen for switch_br", .{}); + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const cond = try self.resolveInst(pl_op.operand); + const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); + const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); + const llvm_switch = self.builder.buildSwitch(cond, else_block, switch_br.data.cases_len); + + var extra_index: usize = switch_br.end; + var case_i: u32 = 0; + + while (case_i < switch_br.data.cases_len) : (case_i += 1) { + const case = self.air.extraData(Air.SwitchBr.Case, extra_index); + const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); + const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; + extra_index = case.end + case.data.items_len + case_body.len; + + const case_block = self.context.appendBasicBlock(self.llvm_func, "Case"); + + for (items) |item| { + const llvm_item = try self.resolveInst(item); + llvm_switch.addCase(llvm_item, case_block); + } + + self.builder.positionBuilderAtEnd(case_block); + try self.genBody(case_body); + } + + self.builder.positionBuilderAtEnd(else_block); + const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; + if (else_body.len != 0) { + try self.genBody(else_body); + } else { + _ = self.builder.buildUnreachable(); + } + + // No need to reset the insert cursor since this instruction is noreturn. + return null; } fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 1b7806d22a..c583d0cd00 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -178,6 +178,9 @@ pub const Value = opaque { pub const setInitializer = LLVMSetInitializer; extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void; + + pub const addCase = LLVMAddCase; + extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void; }; pub const Type = opaque { @@ -554,6 +557,9 @@ pub const Builder = opaque { pub const buildCondBr = LLVMBuildCondBr; extern fn LLVMBuildCondBr(*const Builder, If: *const Value, Then: *const BasicBlock, Else: *const BasicBlock) *const Value; + pub const buildSwitch = LLVMBuildSwitch; + extern fn LLVMBuildSwitch(*const Builder, V: *const Value, Else: *const BasicBlock, NumCases: c_uint) *const Value; + pub const buildPhi = LLVMBuildPhi; extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value; |
