aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-20 14:10:37 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-20 14:10:37 -0700
commited2a5081e1f379cf089f7700a2818db35faadc05 (patch)
treedb42e8cdfddcd712d7f3f01fd4bcd015f9a20d6d /src/codegen
parentdfb3231959bb340d260ddbec2b8eabfb5063c1bf (diff)
downloadzig-ed2a5081e1f379cf089f7700a2818db35faadc05.tar.gz
zig-ed2a5081e1f379cf089f7700a2818db35faadc05.zip
stage2: LLVM backend: implement switch_br
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/llvm.zig54
-rw-r--r--src/codegen/llvm/bindings.zig6
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;