aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-06-09 23:46:00 +0100
committergingerBill <bill@gingerbill.org>2021-06-09 23:46:00 +0100
commit82eae32bca73a9eda26da78df48f3c56172c13c1 (patch)
treeee4d98dd62a01a1dfa026e326e0c87eb9b331821 /src/llvm_backend.cpp
parentb0e21bd616d6111e301378475f493ddf9c75391f (diff)
Improve code generation for type switch statements to use a jump table by default
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp61
1 files changed, 35 insertions, 26 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 0d79be730..e7fb1194f 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -4882,7 +4882,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
}
lbValue lhs = lb_build_expr(p, ie->left);
lbValue rhs = lb_build_expr(p, ie->right);
- // TODO(bill): do short circuit here
+
lbValue cond_lhs = lb_emit_comp(p, Token_LtEq, lhs, tag);
lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs);
cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool);
@@ -5001,29 +5001,45 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
parent_ptr = lb_address_from_load_or_generate_local(p, parent);
}
- lbValue tag_index = {};
+ lbValue tag = {};
lbValue union_data = {};
if (switch_kind == TypeSwitch_Union) {
union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
if (is_type_union_maybe_pointer(type_deref(parent_ptr.type))) {
- tag_index = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int);
+ tag = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int);
} else {
lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr);
- tag_index = lb_emit_load(p, tag_ptr);
+ tag = lb_emit_load(p, tag_ptr);
}
+ } else if (switch_kind == TypeSwitch_Any) {
+ tag = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 1));
+ } else {
+ GB_PANIC("Unknown switch kind");
}
- lbBlock *start_block = lb_create_block(p, "typeswitch.case.first");
- lb_emit_jump(p, start_block);
- lb_start_block(p, start_block);
+ ast_node(body, BlockStmt, ss->body);
- // NOTE(bill): Append this later
lbBlock *done = lb_create_block(p, "typeswitch.done");
- Ast *default_ = nullptr;
+ lbBlock *else_block = done;
+ lbBlock *default_block = nullptr;
+ isize num_cases = 0;
- ast_node(body, BlockStmt, ss->body);
+ for_array(i, body->stmts) {
+ Ast *clause = body->stmts[i];
+ ast_node(cc, CaseClause, clause);
+ num_cases += cc->list.count;
+ if (cc->list.count == 0) {
+ GB_ASSERT(default_block == nullptr);
+ default_block = lb_create_block(p, "typeswitch.default.body");
+ else_block = default_block;
+ }
+ }
- gb_local_persist i32 weird_count = 0;
+ GB_ASSERT(tag.value != nullptr);
+ LLVMValueRef switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
+
+ // NOTE(bill): Append this later
+ Ast *default_ = nullptr;
for_array(i, body->stmts) {
Ast *clause = body->stmts[i];
@@ -5034,25 +5050,19 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
}
lbBlock *body = lb_create_block(p, "typeswitch.body");
- lbBlock *next = nullptr;
Type *case_type = nullptr;
for_array(type_index, cc->list) {
- next = lb_create_block(p, "typeswitch.next");
case_type = type_of_expr(cc->list[type_index]);
- lbValue cond = {};
+ lbValue on_val = {};
if (switch_kind == TypeSwitch_Union) {
Type *ut = base_type(type_deref(parent.type));
- lbValue variant_tag = lb_const_union_tag(m, ut, case_type);
- cond = lb_emit_comp(p, Token_CmpEq, tag_index, variant_tag);
+ on_val = lb_const_union_tag(m, ut, case_type);
+
} else if (switch_kind == TypeSwitch_Any) {
- lbValue any_typeid = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 1));
- lbValue case_typeid = lb_typeid(m, case_type);
- cond = lb_emit_comp(p, Token_CmpEq, any_typeid, case_typeid);
+ on_val = lb_typeid(m, case_type);
}
- GB_ASSERT(cond.value != nullptr);
-
- lb_emit_if(p, cond, body, next);
- lb_start_block(p, next);
+ GB_ASSERT(on_val.value != nullptr);
+ LLVMAddCase(switch_instr, on_val.value, body->block);
}
Entity *case_entity = implicit_entity_of_node(clause);
@@ -5068,8 +5078,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
if (switch_kind == TypeSwitch_Union) {
data = union_data;
} else if (switch_kind == TypeSwitch_Any) {
- lbValue any_data = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 0));
- data = any_data;
+ data = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 0));
}
Type *ct = case_entity->type;
@@ -5083,10 +5092,10 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
lb_store_type_case_implicit(p, clause, value);
lb_type_case_body(p, ss->label, clause, body, done);
- lb_start_block(p, next);
}
if (default_ != nullptr) {
+ lb_start_block(p, default_block);
lb_store_type_case_implicit(p, default_, parent_value);
lb_type_case_body(p, ss->label, default_, p->curr_block, done);
} else {