authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-24 02:44:03-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-24 02:44:03-05:00
log0c22358cc1cccacb9a30929fbbc990ba9d82b6b3
tree68f861f84eaa471832ddb978e876d3097de6be8a
parenta2257e4b81764f8603a39b74eae3622651ec7d6b

IR: generating a switch statement


10 files changed, 334 insertions(+), 447 deletions(-)

README.md+6-6
...@@ -65,6 +65,12 @@ compromises backward compatibility....@@ -65,6 +65,12 @@ compromises backward compatibility.
65 * Compiler exposes itself as a library.65 * Compiler exposes itself as a library.
66 * Support for all popular architectures and operating systems.66 * Support for all popular architectures and operating systems.
6767
68## Community
69
70 * IRC: `#zig` on Freenode.
71 * Reddit: [/r/zig](https://www.reddit.com/r/zig)
72 * Email list: [ziglang@googlegroups.com](https://groups.google.com/forum/#!forum/ziglang)
73
68## Building74## Building
6975
70### Dependencies76### Dependencies
...@@ -147,9 +153,3 @@ To fix this, you have 2 options:...@@ -147,9 +153,3 @@ To fix this, you have 2 options:
147153
148 * Compile Zig with the same compiler that LLVM was compiled with.154 * Compile Zig with the same compiler that LLVM was compiled with.
149 * Add `-DZIG_LLVM_OLD_CXX_ABI=yes` to the cmake configure line.155 * Add `-DZIG_LLVM_OLD_CXX_ABI=yes` to the cmake configure line.
150
151## Community
152
153 * IRC chat: `#zig` on Freenode.
154 * Reddit: [/r/zig](https://www.reddit.com/r/zig)
155 * Email list: [ziglang@googlegroups.com](https://groups.google.com/forum/#!forum/ziglang)
doc/langref.md+1-1
...@@ -75,7 +75,7 @@ BlockExpression = IfExpression | Block | WhileExpression | ForExpression | Switc...@@ -75,7 +75,7 @@ BlockExpression = IfExpression | Block | WhileExpression | ForExpression | Switc
7575
76SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"76SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"
7777
78SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" Symbol "|") Expression ","78SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
7979
80SwitchItem = Expression | (Expression "..." Expression)80SwitchItem = Expression | (Expression "..." Expression)
8181
src/all_types.hpp+17-6
...@@ -560,18 +560,14 @@ struct AstNodeSwitchExpr {...@@ -560,18 +560,14 @@ struct AstNodeSwitchExpr {
560560
561 // populated by semantic analyzer561 // populated by semantic analyzer
562 Expr resolved_expr;562 Expr resolved_expr;
563 size_t const_chosen_prong_index;
564};563};
565564
566struct AstNodeSwitchProng {565struct AstNodeSwitchProng {
567 ZigList<AstNode *> items;566 ZigList<AstNode *> items;
568 AstNode *var_symbol;567 AstNode *var_symbol;
569 AstNode *expr;568 AstNode *expr;
570569 bool var_is_ptr;
571 // populated by semantic analyzer570 bool any_items_are_range;
572 BlockContext *block_context;
573 VariableTableEntry *var;
574 bool var_is_target_expr;
575};571};
576572
577struct AstNodeSwitchRange {573struct AstNodeSwitchRange {
...@@ -1426,6 +1422,8 @@ enum IrInstructionId {...@@ -1426,6 +1422,8 @@ enum IrInstructionId {
1426 IrInstructionIdBr,1422 IrInstructionIdBr,
1427 IrInstructionIdCondBr,1423 IrInstructionIdCondBr,
1428 IrInstructionIdSwitchBr,1424 IrInstructionIdSwitchBr,
1425 IrInstructionIdSwitchVar,
1426 IrInstructionIdSwitchTarget,
1429 IrInstructionIdPhi,1427 IrInstructionIdPhi,
1430 IrInstructionIdUnOp,1428 IrInstructionIdUnOp,
1431 IrInstructionIdBinOp,1429 IrInstructionIdBinOp,
...@@ -1509,6 +1507,19 @@ struct IrInstructionSwitchBr {...@@ -1509,6 +1507,19 @@ struct IrInstructionSwitchBr {
1509 bool is_inline;1507 bool is_inline;
1510};1508};
15111509
1510struct IrInstructionSwitchVar {
1511 IrInstruction base;
1512
1513 IrInstruction *target_value_ptr;
1514 IrInstruction *prong_value;
1515};
1516
1517struct IrInstructionSwitchTarget {
1518 IrInstruction base;
1519
1520 IrInstruction *target_value_ptr;
1521};
1522
1512struct IrInstructionPhi {1523struct IrInstructionPhi {
1513 IrInstruction base;1524 IrInstruction base;
15141525
src/ast_render.cpp+1-1
...@@ -727,6 +727,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -727,6 +727,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
727 }727 }
728 break;728 break;
729 }729 }
730 case NodeTypeSwitchExpr:
730 case NodeTypeFnDecl:731 case NodeTypeFnDecl:
731 case NodeTypeParamDecl:732 case NodeTypeParamDecl:
732 case NodeTypeErrorValueDecl:733 case NodeTypeErrorValueDecl:
...@@ -737,7 +738,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -737,7 +738,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
737 case NodeTypeUse:738 case NodeTypeUse:
738 case NodeTypeZeroesLiteral:739 case NodeTypeZeroesLiteral:
739 case NodeTypeForExpr:740 case NodeTypeForExpr:
740 case NodeTypeSwitchExpr:
741 case NodeTypeSwitchProng:741 case NodeTypeSwitchProng:
742 case NodeTypeSwitchRange:742 case NodeTypeSwitchRange:
743 case NodeTypeLabel:743 case NodeTypeLabel:
src/codegen.cpp+2
...@@ -1695,6 +1695,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1695,6 +1695,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1695 case IrInstructionIdCtz:1695 case IrInstructionIdCtz:
1696 return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);1696 return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
1697 case IrInstructionIdSwitchBr:1697 case IrInstructionIdSwitchBr:
1698 case IrInstructionIdSwitchTarget:
1699 case IrInstructionIdSwitchVar:
1698 case IrInstructionIdPhi:1700 case IrInstructionIdPhi:
1699 case IrInstructionIdContainerInitList:1701 case IrInstructionIdContainerInitList:
1700 case IrInstructionIdContainerInitFields:1702 case IrInstructionIdContainerInitFields:
src/ir.cpp+271-429
...@@ -114,6 +114,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchBr *) {...@@ -114,6 +114,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchBr *) {
114 return IrInstructionIdSwitchBr;114 return IrInstructionIdSwitchBr;
115}115}
116116
117static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchVar *) {
118 return IrInstructionIdSwitchVar;
119}
120
121static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchTarget *) {
122 return IrInstructionIdSwitchTarget;
123}
124
117static constexpr IrInstructionId ir_instruction_id(IrInstructionPhi *) {125static constexpr IrInstructionId ir_instruction_id(IrInstructionPhi *) {
118 return IrInstructionIdPhi;126 return IrInstructionIdPhi;
119}127}
...@@ -981,6 +989,51 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr...@@ -981,6 +989,51 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr
981 return new_instruction;989 return new_instruction;
982}990}
983991
992static IrInstruction *ir_build_switch_br(IrBuilder *irb, AstNode *source_node, IrInstruction *target_value,
993 IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, bool is_inline)
994{
995 IrInstructionSwitchBr *instruction = ir_build_instruction<IrInstructionSwitchBr>(irb, source_node);
996 instruction->target_value = target_value;
997 instruction->else_block = else_block;
998 instruction->case_count = case_count;
999 instruction->cases = cases;
1000 instruction->is_inline = is_inline;
1001
1002 ir_ref_instruction(target_value);
1003 ir_ref_bb(else_block);
1004
1005 for (size_t i = 0; i < case_count; i += 1) {
1006 ir_ref_instruction(cases[i].value);
1007 ir_ref_bb(cases[i].block);
1008 }
1009
1010 return &instruction->base;
1011}
1012
1013static IrInstruction *ir_build_switch_target(IrBuilder *irb, AstNode *source_node,
1014 IrInstruction *target_value_ptr)
1015{
1016 IrInstructionSwitchTarget *instruction = ir_build_instruction<IrInstructionSwitchTarget>(irb, source_node);
1017 instruction->target_value_ptr = target_value_ptr;
1018
1019 ir_ref_instruction(target_value_ptr);
1020
1021 return &instruction->base;
1022}
1023
1024static IrInstruction *ir_build_switch_var(IrBuilder *irb, AstNode *source_node,
1025 IrInstruction *target_value_ptr, IrInstruction *prong_value)
1026{
1027 IrInstructionSwitchVar *instruction = ir_build_instruction<IrInstructionSwitchVar>(irb, source_node);
1028 instruction->target_value_ptr = target_value_ptr;
1029 instruction->prong_value = prong_value;
1030
1031 ir_ref_instruction(target_value_ptr);
1032 ir_ref_instruction(prong_value);
1033
1034 return &instruction->base;
1035}
1036
984static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,1037static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
985 bool gen_error_defers, bool gen_maybe_defers)1038 bool gen_error_defers, bool gen_maybe_defers)
986{1039{
...@@ -1047,7 +1100,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, BlockC...@@ -1047,7 +1100,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, BlockC
1047 if (name) {1100 if (name) {
1048 buf_init_from_buf(&variable_entry->name, name);1101 buf_init_from_buf(&variable_entry->name, name);
10491102
1050 VariableTableEntry *existing_var = find_variable(codegen, node->block_context, name);1103 VariableTableEntry *existing_var = find_variable(codegen, scope, name);
1051 if (existing_var && !existing_var->shadowable) {1104 if (existing_var && !existing_var->shadowable) {
1052 ErrorMsg *msg = add_node_error(codegen, node,1105 ErrorMsg *msg = add_node_error(codegen, node,
1053 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));1106 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
...@@ -1061,7 +1114,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, BlockC...@@ -1061,7 +1114,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, BlockC
1061 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));1114 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
1062 variable_entry->type = codegen->builtin_types.entry_invalid;1115 variable_entry->type = codegen->builtin_types.entry_invalid;
1063 } else {1116 } else {
1064 AstNode *decl_node = find_decl(node->block_context, name);1117 AstNode *decl_node = find_decl(scope, name);
1065 if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {1118 if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
1066 ErrorMsg *msg = add_node_error(codegen, node,1119 ErrorMsg *msg = add_node_error(codegen, node,
1067 buf_sprintf("redefinition of '%s'", buf_ptr(name)));1120 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
...@@ -1071,7 +1124,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, BlockC...@@ -1071,7 +1124,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, BlockC
1071 }1124 }
1072 }1125 }
10731126
1074 node->block_context->var_table.put(&variable_entry->name, variable_entry);1127 scope->var_table.put(&variable_entry->name, variable_entry);
1075 } else {1128 } else {
1076 assert(is_shadowable);1129 assert(is_shadowable);
1077 // TODO replace _anon with @anon and make sure all tests still pass1130 // TODO replace _anon with @anon and make sure all tests still pass
...@@ -2052,8 +2105,11 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {...@@ -2052,8 +2105,11 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
20522105
2053 ir_set_cursor_at_end(irb, then_block);2106 ir_set_cursor_at_end(irb, then_block);
2054 IrInstruction *var_type = nullptr;2107 IrInstruction *var_type = nullptr;
2055 if (var_decl->type)2108 if (var_decl->type) {
2056 var_type = ir_gen_node(irb, var_decl->type, node->block_context);2109 var_type = ir_gen_node(irb, var_decl->type, node->block_context);
2110 if (var_type == irb->codegen->invalid_instruction)
2111 return irb->codegen->invalid_instruction;
2112 }
2057 BlockContext *child_scope = new_block_context(node, node->block_context);2113 BlockContext *child_scope = new_block_context(node, node->block_context);
2058 bool is_shadowable = false;2114 bool is_shadowable = false;
2059 bool is_const = var_decl->is_const;2115 bool is_const = var_decl->is_const;
...@@ -2091,6 +2147,190 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {...@@ -2091,6 +2147,190 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
2091 return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values);2147 return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values);
2092}2148}
20932149
2150static bool ir_gen_switch_prong_expr(IrBuilder *irb, AstNode *switch_node, AstNode *prong_node,
2151 IrBasicBlock *end_block, bool is_inline, IrInstruction *target_value_ptr, IrInstruction *prong_value,
2152 ZigList<IrBasicBlock *> incoming_blocks, ZigList<IrInstruction *> incoming_values)
2153{
2154 assert(switch_node->type == NodeTypeSwitchExpr);
2155 assert(prong_node->type == NodeTypeSwitchProng);
2156
2157 AstNode *expr_node = prong_node->data.switch_prong.expr;
2158 AstNode *var_symbol_node = prong_node->data.switch_prong.var_symbol;
2159 BlockContext *child_scope;
2160 if (var_symbol_node) {
2161 assert(var_symbol_node->type == NodeTypeSymbol);
2162 Buf *var_name = var_symbol_node->data.symbol_expr.symbol;
2163 bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr;
2164
2165 child_scope = new_block_context(switch_node, switch_node->block_context);
2166 bool is_shadowable = false;
2167 bool is_const = true;
2168 VariableTableEntry *var = ir_add_local_var(irb, var_symbol_node, child_scope,
2169 var_name, is_const, is_const, is_shadowable, is_inline);
2170 IrInstruction *var_value;
2171 if (prong_value) {
2172 IrInstruction *var_ptr_value = ir_build_switch_var(irb, var_symbol_node, target_value_ptr, prong_value);
2173 var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, var_symbol_node, var_ptr_value);
2174 } else {
2175 var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, var_symbol_node, target_value_ptr);
2176 }
2177 IrInstruction *var_type = nullptr; // infer the type
2178 ir_build_var_decl(irb, var_symbol_node, var, var_type, var_value);
2179 } else {
2180 child_scope = switch_node->block_context;
2181 }
2182
2183 IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope);
2184 if (expr_result == irb->codegen->invalid_instruction)
2185 return false;
2186 ir_build_br(irb, switch_node, end_block, is_inline);
2187 incoming_blocks.append(irb->current_basic_block);
2188 incoming_values.append(expr_result);
2189 return true;
2190}
2191
2192static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
2193 assert(node->type == NodeTypeSwitchExpr);
2194
2195 AstNode *target_node = node->data.switch_expr.expr;
2196 IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, node->block_context, LValPurposeAddressOf);
2197 if (target_value_ptr == irb->codegen->invalid_instruction)
2198 return target_value_ptr;
2199 IrInstruction *target_value = ir_build_switch_target(irb, node, target_value_ptr);
2200
2201 IrBasicBlock *else_block = ir_build_basic_block(irb, "SwitchElse");
2202 IrBasicBlock *end_block = ir_build_basic_block(irb, "SwitchEnd");
2203
2204 size_t prong_count = node->data.switch_expr.prongs.length;
2205 ZigList<IrInstructionSwitchBrCase> cases = {0};
2206 bool is_inline = (node->block_context->fn_entry == nullptr);
2207
2208 ZigList<IrInstruction *> incoming_values = {0};
2209 ZigList<IrBasicBlock *> incoming_blocks = {0};
2210
2211 AstNode *else_prong = nullptr;
2212 for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
2213 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
2214 size_t prong_item_count = prong_node->data.switch_prong.items.length;
2215 if (prong_item_count == 0) {
2216 if (else_prong) {
2217 ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
2218 buf_sprintf("multiple else prongs in switch expression"));
2219 add_error_note(irb->codegen, msg, else_prong,
2220 buf_sprintf("previous else prong is here"));
2221 return irb->codegen->invalid_instruction;
2222 }
2223 else_prong = prong_node;
2224
2225 if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
2226 is_inline, target_value_ptr, nullptr, incoming_blocks, incoming_values))
2227 {
2228 return irb->codegen->invalid_instruction;
2229 }
2230 } else {
2231 if (prong_node->data.switch_prong.any_items_are_range) {
2232 IrInstruction *ok_bit = nullptr;
2233 AstNode *last_item_node = nullptr;
2234 for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) {
2235 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
2236 last_item_node = item_node;
2237 if (item_node->type == NodeTypeSwitchRange) {
2238 AstNode *start_node = item_node->data.switch_range.start;
2239 AstNode *end_node = item_node->data.switch_range.end;
2240
2241 IrInstruction *start_value = ir_gen_node(irb, start_node, node->block_context);
2242 if (start_value == irb->codegen->invalid_instruction)
2243 return irb->codegen->invalid_instruction;
2244 IrInstruction *end_value = ir_gen_node(irb, end_node, node->block_context);
2245 if (end_value == irb->codegen->invalid_instruction)
2246 return irb->codegen->invalid_instruction;
2247
2248 IrInstruction *lower_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpGreaterOrEq,
2249 target_value, start_value);
2250 IrInstruction *upper_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpLessOrEq,
2251 target_value, end_value);
2252 IrInstruction *both_ok = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd,
2253 lower_range_ok, upper_range_ok);
2254 if (ok_bit) {
2255 ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd, both_ok, ok_bit);
2256 } else {
2257 ok_bit = both_ok;
2258 }
2259 } else {
2260 IrInstruction *item_value = ir_gen_node(irb, item_node, node->block_context);
2261 if (item_value == irb->codegen->invalid_instruction)
2262 return irb->codegen->invalid_instruction;
2263
2264 IrInstruction *cmp_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpEq,
2265 item_value, target_value);
2266 if (ok_bit) {
2267 ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd, cmp_ok, ok_bit);
2268 } else {
2269 ok_bit = cmp_ok;
2270 }
2271 }
2272 }
2273
2274 IrBasicBlock *range_block_yes = ir_build_basic_block(irb, "SwitchRangeYes");
2275 IrBasicBlock *range_block_no = ir_build_basic_block(irb, "SwitchRangeNo");
2276
2277 assert(ok_bit);
2278 assert(last_item_node);
2279 ir_build_cond_br(irb, last_item_node, ok_bit, range_block_yes, range_block_no, is_inline);
2280
2281 ir_set_cursor_at_end(irb, range_block_yes);
2282 if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
2283 is_inline, target_value_ptr, nullptr, incoming_blocks, incoming_values))
2284 {
2285 return irb->codegen->invalid_instruction;
2286 }
2287
2288 ir_set_cursor_at_end(irb, range_block_no);
2289 } else {
2290 for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) {
2291 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
2292 assert(item_node->type != NodeTypeSwitchRange);
2293
2294 IrInstruction *item_value = ir_gen_node(irb, item_node, node->block_context);
2295 if (item_value == irb->codegen->invalid_instruction)
2296 return irb->codegen->invalid_instruction;
2297
2298 IrBasicBlock *prong_block = ir_build_basic_block(irb, "SwitchProng");
2299 IrBasicBlock *prev_block = irb->current_basic_block;
2300 ir_set_cursor_at_end(irb, prong_block);
2301
2302 if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
2303 is_inline, target_value_ptr, item_value, incoming_blocks, incoming_values))
2304 {
2305 return irb->codegen->invalid_instruction;
2306 }
2307
2308 IrInstructionSwitchBrCase *this_case = cases.add_one();
2309 this_case->value = item_value;
2310 this_case->block = prong_block;
2311
2312 ir_set_cursor_at_end(irb, prev_block);
2313 }
2314 }
2315 }
2316 }
2317
2318 if (cases.length == 0) {
2319 ir_build_br(irb, node, else_block, is_inline);
2320 } else {
2321 ir_build_switch_br(irb, node, target_value, else_block, cases.length, cases.items, is_inline);
2322 }
2323
2324 if (!else_prong) {
2325 ir_set_cursor_at_end(irb, else_block);
2326 ir_build_unreachable(irb, node);
2327 }
2328
2329 ir_set_cursor_at_end(irb, end_block);
2330 assert(incoming_blocks.length == incoming_values.length);
2331 return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
2332}
2333
2094static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context,2334static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context,
2095 LValPurpose lval)2335 LValPurpose lval)
2096{2336{
...@@ -2142,6 +2382,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex...@@ -2142,6 +2382,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex
2142 return ir_gen_null_literal(irb, node);2382 return ir_gen_null_literal(irb, node);
2143 case NodeTypeIfVarExpr:2383 case NodeTypeIfVarExpr:
2144 return ir_gen_if_var_expr(irb, node);2384 return ir_gen_if_var_expr(irb, node);
2385 case NodeTypeSwitchExpr:
2386 return ir_gen_switch_expr(irb, node);
2145 case NodeTypeUnwrapErrorExpr:2387 case NodeTypeUnwrapErrorExpr:
2146 case NodeTypeDefer:2388 case NodeTypeDefer:
2147 case NodeTypeSliceExpr:2389 case NodeTypeSliceExpr:
...@@ -2149,7 +2391,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex...@@ -2149,7 +2391,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex
2149 case NodeTypeBreak:2391 case NodeTypeBreak:
2150 case NodeTypeContinue:2392 case NodeTypeContinue:
2151 case NodeTypeLabel:2393 case NodeTypeLabel:
2152 case NodeTypeSwitchExpr:
2153 case NodeTypeCharLiteral:2394 case NodeTypeCharLiteral:
2154 case NodeTypeZeroesLiteral:2395 case NodeTypeZeroesLiteral:
2155 case NodeTypeErrorType:2396 case NodeTypeErrorType:
...@@ -4870,6 +5111,24 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC...@@ -4870,6 +5111,24 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
4870 }5111 }
4871}5112}
48725113
5114static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
5115 IrInstructionSwitchBr *switch_br_instruction)
5116{
5117 zig_panic("TODO switch br analyze");
5118}
5119
5120static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
5121 IrInstructionSwitchTarget *switch_target_instruction)
5122{
5123 zig_panic("TODO switch target analyze");
5124}
5125
5126static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,
5127 IrInstructionSwitchVar *switch_var_instruction)
5128{
5129 zig_panic("TODO switch var analyze");
5130}
5131
4873static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {5132static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
4874 switch (instruction->id) {5133 switch (instruction->id) {
4875 case IrInstructionIdInvalid:5134 case IrInstructionIdInvalid:
...@@ -4937,6 +5196,11 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -4937,6 +5196,11 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
4937 case IrInstructionIdCtz:5196 case IrInstructionIdCtz:
4938 return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction);5197 return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction);
4939 case IrInstructionIdSwitchBr:5198 case IrInstructionIdSwitchBr:
5199 return ir_analyze_instruction_switch_br(ira, (IrInstructionSwitchBr *)instruction);
5200 case IrInstructionIdSwitchTarget:
5201 return ir_analyze_instruction_switch_target(ira, (IrInstructionSwitchTarget *)instruction);
5202 case IrInstructionIdSwitchVar:
5203 return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);
4940 case IrInstructionIdCast:5204 case IrInstructionIdCast:
4941 case IrInstructionIdContainerInitList:5205 case IrInstructionIdContainerInitList:
4942 case IrInstructionIdContainerInitFields:5206 case IrInstructionIdContainerInitFields:
...@@ -5053,6 +5317,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -5053,6 +5317,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
5053 case IrInstructionIdUnwrapMaybe:5317 case IrInstructionIdUnwrapMaybe:
5054 case IrInstructionIdClz:5318 case IrInstructionIdClz:
5055 case IrInstructionIdCtz:5319 case IrInstructionIdCtz:
5320 case IrInstructionIdSwitchVar:
5321 case IrInstructionIdSwitchTarget:
5056 return false;5322 return false;
5057 case IrInstructionIdAsm:5323 case IrInstructionIdAsm:
5058 {5324 {
...@@ -7037,246 +7303,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7037,246 +7303,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7037// return g->builtin_types.entry_invalid;7303// return g->builtin_types.entry_invalid;
7038// }7304// }
7039//}7305//}
7040//static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7041// TypeTableEntry *expected_type, AstNode *node)
7042//{
7043// AstNode **expr_node = &node->data.switch_expr.expr;
7044// TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
7045// ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
7046// if (expr_val->ok && !expr_val->depends_on_compile_var) {
7047// add_node_error(g, first_executing_node(*expr_node),
7048// buf_sprintf("value is constant; unnecessary switch statement"));
7049// }
7050// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
7051//
7052//
7053// size_t prong_count = node->data.switch_expr.prongs.length;
7054// AstNode **peer_nodes = allocate<AstNode*>(prong_count);
7055// TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count);
7056//
7057// bool any_errors = false;
7058// if (expr_type->id == TypeTableEntryIdInvalid) {
7059// return expr_type;
7060// } else if (expr_type->id == TypeTableEntryIdUnreachable) {
7061// add_node_error(g, first_executing_node(*expr_node),
7062// buf_sprintf("switch on unreachable expression not allowed"));
7063// return g->builtin_types.entry_invalid;
7064// }
7065//
7066//
7067// size_t *field_use_counts = nullptr;
7068// HashMap<int, AstNode *, int_hash, int_eq> err_use_nodes = {};
7069// if (expr_type->id == TypeTableEntryIdEnum) {
7070// field_use_counts = allocate<size_t>(expr_type->data.enumeration.src_field_count);
7071// } else if (expr_type->id == TypeTableEntryIdErrorUnion) {
7072// err_use_nodes.init(10);
7073// }
7074//
7075// size_t *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index;
7076// *const_chosen_prong_index = SIZE_MAX;
7077// AstNode *else_prong = nullptr;
7078// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
7079// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
7080//
7081// TypeTableEntry *var_type;
7082// bool var_is_target_expr;
7083// if (prong_node->data.switch_prong.items.length == 0) {
7084// if (else_prong) {
7085// add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
7086// any_errors = true;
7087// } else {
7088// else_prong = prong_node;
7089// }
7090// var_type = expr_type;
7091// var_is_target_expr = true;
7092// if (*const_chosen_prong_index == SIZE_MAX && expr_val->ok) {
7093// *const_chosen_prong_index = prong_i;
7094// }
7095// } else {
7096// bool all_agree_on_var_type = true;
7097// var_type = nullptr;
7098//
7099// for (size_t item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
7100// AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
7101// if (item_node->type == NodeTypeSwitchRange) {
7102// zig_panic("TODO range in switch statement");
7103// }
7104//
7105// if (expr_type->id == TypeTableEntryIdEnum) {
7106// if (item_node->type == NodeTypeSymbol) {
7107// Buf *field_name = item_node->data.symbol_expr.symbol;
7108// TypeEnumField *type_enum_field = find_enum_type_field(expr_type, field_name);
7109// if (type_enum_field) {
7110// item_node->data.symbol_expr.enum_field = type_enum_field;
7111// if (!var_type) {
7112// var_type = type_enum_field->type_entry;
7113// }
7114// if (type_enum_field->type_entry != var_type) {
7115// all_agree_on_var_type = false;
7116// }
7117// uint32_t field_index = type_enum_field->value;
7118// assert(field_use_counts);
7119// field_use_counts[field_index] += 1;
7120// if (field_use_counts[field_index] > 1) {
7121// add_node_error(g, item_node,
7122// buf_sprintf("duplicate switch value: '%s'",
7123// buf_ptr(type_enum_field->name)));
7124// any_errors = true;
7125// }
7126// if (!any_errors && expr_val->ok) {
7127// if (expr_val->data.x_enum.tag == type_enum_field->value) {
7128// *const_chosen_prong_index = prong_i;
7129// }
7130// }
7131// } else {
7132// add_node_error(g, item_node,
7133// buf_sprintf("enum '%s' has no field '%s'",
7134// buf_ptr(&expr_type->name), buf_ptr(field_name)));
7135// any_errors = true;
7136// }
7137// } else {
7138// add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
7139// any_errors = true;
7140// }
7141// } else if (expr_type->id == TypeTableEntryIdErrorUnion) {
7142// if (item_node->type == NodeTypeSymbol) {
7143// Buf *err_name = item_node->data.symbol_expr.symbol;
7144// bool is_ok_case = buf_eql_str(err_name, "Ok");
7145// auto err_table_entry = is_ok_case ? nullptr: g->error_table.maybe_get(err_name);
7146// if (is_ok_case || err_table_entry) {
7147// uint32_t err_value = is_ok_case ? 0 : err_table_entry->value->value;
7148// item_node->data.symbol_expr.err_value = err_value;
7149// TypeTableEntry *this_var_type;
7150// if (is_ok_case) {
7151// this_var_type = expr_type->data.error.child_type;
7152// } else {
7153// this_var_type = g->builtin_types.entry_pure_error;
7154// }
7155// if (!var_type) {
7156// var_type = this_var_type;
7157// }
7158// if (this_var_type != var_type) {
7159// all_agree_on_var_type = false;
7160// }
7161//
7162// // detect duplicate switch values
7163// auto existing_entry = err_use_nodes.maybe_get(err_value);
7164// if (existing_entry) {
7165// add_node_error(g, existing_entry->value,
7166// buf_sprintf("duplicate switch value: '%s'", buf_ptr(err_name)));
7167// any_errors = true;
7168// } else {
7169// err_use_nodes.put(err_value, item_node);
7170// }
7171//
7172// if (!any_errors && expr_val->ok) {
7173// if (expr_val->data.x_err.err->value == err_value) {
7174// *const_chosen_prong_index = prong_i;
7175// }
7176// }
7177// } else {
7178// add_node_error(g, item_node,
7179// buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
7180// any_errors = true;
7181// }
7182// } else {
7183// add_node_error(g, item_node, buf_sprintf("expected error value name"));
7184// any_errors = true;
7185// }
7186// } else {
7187// if (!any_errors && expr_val->ok) {
7188// // note: there is now a function in eval.cpp for doing const expr comparison
7189// zig_panic("TODO determine if const exprs are equal");
7190// }
7191// TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);
7192// if (item_type->id != TypeTableEntryIdInvalid) {
7193// ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val;
7194// if (!const_val->ok) {
7195// add_node_error(g, item_node,
7196// buf_sprintf("unable to evaluate constant expression"));
7197// any_errors = true;
7198// }
7199// }
7200// }
7201// }
7202// if (!var_type || !all_agree_on_var_type) {
7203// var_type = expr_type;
7204// var_is_target_expr = true;
7205// } else {
7206// var_is_target_expr = false;
7207// }
7208// }
7209//
7210// BlockContext *child_context = new_block_context(node, context);
7211// prong_node->data.switch_prong.block_context = child_context;
7212// AstNode *var_node = prong_node->data.switch_prong.var_symbol;
7213// if (var_node) {
7214// assert(var_node->type == NodeTypeSymbol);
7215// Buf *var_name = var_node->data.symbol_expr.symbol;
7216// var_node->block_context = child_context;
7217// prong_node->data.switch_prong.var = add_local_var(g, var_node, import,
7218// child_context, var_name, var_type, true, nullptr);
7219// prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr;
7220// }
7221// }
7222//
7223// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
7224// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
7225// BlockContext *child_context = prong_node->data.switch_prong.block_context;
7226// child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);
7227//
7228// if (child_context->codegen_excluded) {
7229// peer_types[prong_i] = g->builtin_types.entry_unreachable;
7230// } else {
7231// peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
7232// prong_node->data.switch_prong.expr);
7233// }
7234// // This must go after the analyze_expression for
7235// // prong_node->data.switch_prong.expr because of AST rewriting.
7236// peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
7237// }
7238//
7239// if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {
7240// for (uint32_t i = 0; i < expr_type->data.enumeration.src_field_count; i += 1) {
7241// if (field_use_counts[i] == 0) {
7242// add_node_error(g, node,
7243// buf_sprintf("enumeration value '%s' not handled in switch",
7244// buf_ptr(expr_type->data.enumeration.fields[i].name)));
7245// any_errors = true;
7246// }
7247// }
7248// }
7249//
7250// if (any_errors) {
7251// return g->builtin_types.entry_invalid;
7252// }
7253//
7254// if (prong_count == 0) {
7255// add_node_error(g, node, buf_sprintf("switch statement has no prongs"));
7256// return g->builtin_types.entry_invalid;
7257// }
7258//
7259// TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node,
7260// peer_nodes, peer_types, prong_count);
7261//
7262// if (expr_val->ok) {
7263// assert(*const_chosen_prong_index != SIZE_MAX);
7264//
7265// *const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val;
7266// // the target expr depends on a compile var because we have an error on unnecessary
7267// // switch statement, so the entire switch statement does too
7268// const_val->depends_on_compile_var = true;
7269//
7270// if (!const_val->ok) {
7271// return add_error_if_type_is_num_lit(g, result_type, node);
7272// }
7273// } else {
7274// return add_error_if_type_is_num_lit(g, result_type, node);
7275// }
7276//
7277// return result_type;
7278//}
7279//
7280//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,7306//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7281// TypeTableEntry *expected_type, AstNode *node)7307// TypeTableEntry *expected_type, AstNode *node)
7282//{7308//{
...@@ -9338,190 +9364,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -9338,190 +9364,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9338// return nullptr;9364// return nullptr;
9339//}9365//}
9340//9366//
9341//static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
9342// assert(node->type == NodeTypeSwitchExpr);
9343//
9344// if (node->data.switch_expr.const_chosen_prong_index != SIZE_MAX) {
9345// AstNode *prong_node = node->data.switch_expr.prongs.at(node->data.switch_expr.const_chosen_prong_index);
9346// assert(prong_node->type == NodeTypeSwitchProng);
9347// AstNode *prong_expr = prong_node->data.switch_prong.expr;
9348// return gen_expr(g, prong_expr);
9349// }
9350//
9351// TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);
9352// LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);
9353// LLVMValueRef target_value;
9354// if (handle_is_ptr(target_type)) {
9355// if (target_type->id == TypeTableEntryIdEnum) {
9356// set_debug_source_node(g, node);
9357// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
9358// target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
9359// } else if (target_type->id == TypeTableEntryIdErrorUnion) {
9360// set_debug_source_node(g, node);
9361// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
9362// target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
9363// } else {
9364// zig_unreachable();
9365// }
9366// } else {
9367// target_value = target_value_handle;
9368// }
9369//
9370//
9371// TypeTableEntry *switch_type = get_expr_type(node);
9372// bool result_has_bits = type_has_bits(switch_type);
9373// bool end_unreachable = (switch_type->id == TypeTableEntryIdUnreachable);
9374//
9375// LLVMBasicBlockRef end_block = end_unreachable ?
9376// nullptr : LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchEnd");
9377// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchElse");
9378// size_t prong_count = node->data.switch_expr.prongs.length;
9379//
9380// set_debug_source_node(g, node);
9381// LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, prong_count);
9382//
9383// ZigList<LLVMValueRef> incoming_values = {0};
9384// ZigList<LLVMBasicBlockRef> incoming_blocks = {0};
9385//
9386// AstNode *else_prong = nullptr;
9387// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
9388// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
9389// VariableTableEntry *prong_var = prong_node->data.switch_prong.var;
9390//
9391// LLVMBasicBlockRef prong_block;
9392// if (prong_node->data.switch_prong.items.length == 0) {
9393// assert(!else_prong);
9394// else_prong = prong_node;
9395// prong_block = else_block;
9396// } else {
9397// prong_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProng");
9398// size_t prong_item_count = prong_node->data.switch_prong.items.length;
9399// bool make_item_blocks = prong_var && prong_item_count > 1;
9400//
9401// for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) {
9402// AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
9403//
9404// assert(item_node->type != NodeTypeSwitchRange);
9405// LLVMValueRef val;
9406// if (target_type->id == TypeTableEntryIdEnum ||
9407// target_type->id == TypeTableEntryIdErrorUnion)
9408// {
9409// assert(item_node->type == NodeTypeSymbol);
9410// TypeEnumField *enum_field = nullptr;
9411// uint32_t err_value = 0;
9412// if (target_type->id == TypeTableEntryIdEnum) {
9413// enum_field = item_node->data.symbol_expr.enum_field;
9414// assert(enum_field);
9415// val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,
9416// enum_field->value, false);
9417// } else if (target_type->id == TypeTableEntryIdErrorUnion) {
9418// err_value = item_node->data.symbol_expr.err_value;
9419// val = LLVMConstInt(g->err_tag_type->type_ref, err_value, false);
9420// } else {
9421// zig_unreachable();
9422// }
9423//
9424// if (prong_var && type_has_bits(prong_var->type)) {
9425// LLVMBasicBlockRef item_block;
9426//
9427// if (make_item_blocks) {
9428// item_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProngItem");
9429// LLVMAddCase(switch_instr, val, item_block);
9430// LLVMPositionBuilderAtEnd(g->builder, item_block);
9431// } else {
9432// LLVMAddCase(switch_instr, val, prong_block);
9433// LLVMPositionBuilderAtEnd(g->builder, prong_block);
9434// }
9435//
9436// AstNode *var_node = prong_node->data.switch_prong.var_symbol;
9437// set_debug_source_node(g, var_node);
9438// if (prong_node->data.switch_prong.var_is_target_expr) {
9439// gen_assign_raw(g, var_node, BinOpTypeAssign,
9440// prong_var->value_ref, target_value, prong_var->type, target_type);
9441// } else if (target_type->id == TypeTableEntryIdEnum) {
9442// assert(enum_field);
9443// assert(type_has_bits(enum_field->type_entry));
9444// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle,
9445// 1, "");
9446// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
9447// LLVMPointerType(enum_field->type_entry->type_ref, 0), "");
9448// LLVMValueRef handle_val = get_handle_value(g, bitcasted_union_field_ptr,
9449// enum_field->type_entry);
9450//
9451// gen_assign_raw(g, var_node, BinOpTypeAssign,
9452// prong_var->value_ref, handle_val, prong_var->type, enum_field->type_entry);
9453// } else if (target_type->id == TypeTableEntryIdErrorUnion) {
9454// if (err_value == 0) {
9455// // variable is the payload
9456// LLVMValueRef err_payload_ptr = LLVMBuildStructGEP(g->builder,
9457// target_value_handle, 1, "");
9458// LLVMValueRef handle_val = get_handle_value(g, err_payload_ptr, prong_var->type);
9459// gen_assign_raw(g, var_node, BinOpTypeAssign,
9460// prong_var->value_ref, handle_val, prong_var->type, prong_var->type);
9461// } else {
9462// // variable is the pure error value
9463// LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder,
9464// target_value_handle, 0, "");
9465// LLVMValueRef handle_val = LLVMBuildLoad(g->builder, err_tag_ptr, "");
9466// gen_assign_raw(g, var_node, BinOpTypeAssign,
9467// prong_var->value_ref, handle_val, prong_var->type, g->err_tag_type);
9468// }
9469// } else {
9470// zig_unreachable();
9471// }
9472// if (make_item_blocks) {
9473// set_debug_source_node(g, var_node);
9474// LLVMBuildBr(g->builder, prong_block);
9475// }
9476// } else {
9477// LLVMAddCase(switch_instr, val, prong_block);
9478// }
9479// } else {
9480// assert(get_resolved_expr(item_node)->const_val.ok);
9481// val = gen_expr(g, item_node);
9482// LLVMAddCase(switch_instr, val, prong_block);
9483// }
9484// }
9485// }
9486//
9487// LLVMPositionBuilderAtEnd(g->builder, prong_block);
9488// AstNode *prong_expr = prong_node->data.switch_prong.expr;
9489// LLVMValueRef prong_val = gen_expr(g, prong_expr);
9490//
9491// if (get_expr_type(prong_expr)->id != TypeTableEntryIdUnreachable) {
9492// set_debug_source_node(g, prong_expr);
9493// LLVMBuildBr(g->builder, end_block);
9494// incoming_values.append(prong_val);
9495// incoming_blocks.append(LLVMGetInsertBlock(g->builder));
9496// }
9497// }
9498//
9499// if (!else_prong) {
9500// LLVMPositionBuilderAtEnd(g->builder, else_block);
9501// set_debug_source_node(g, node);
9502// if (want_debug_safety(g, node)) {
9503// gen_debug_safety_crash(g);
9504// } else {
9505// LLVMBuildUnreachable(g->builder);
9506// }
9507// }
9508//
9509// if (end_unreachable) {
9510// return nullptr;
9511// }
9512//
9513// LLVMPositionBuilderAtEnd(g->builder, end_block);
9514//
9515// if (result_has_bits) {
9516// set_debug_source_node(g, node);
9517// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(incoming_values.at(0)), "");
9518// LLVMAddIncoming(phi, incoming_values.items, incoming_blocks.items, incoming_values.length);
9519// return phi;
9520// } else {
9521// return nullptr;
9522// }
9523//}
9524//
9525//static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {9367//static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
9526// assert(node->type == NodeTypeArrayAccessExpr);9368// assert(node->type == NodeTypeArrayAccessExpr);
9527//9369//
src/ir_print.cpp+2
...@@ -645,6 +645,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -645,6 +645,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
645 ir_print_clz(irp, (IrInstructionClz *)instruction);645 ir_print_clz(irp, (IrInstructionClz *)instruction);
646 break;646 break;
647 case IrInstructionIdSwitchBr:647 case IrInstructionIdSwitchBr:
648 case IrInstructionIdSwitchVar:
649 case IrInstructionIdSwitchTarget:
648 zig_panic("TODO print more IR instructions");650 zig_panic("TODO print more IR instructions");
649 }651 }
650 fprintf(irp->f, "\n");652 fprintf(irp->f, "\n");
src/list.hpp+3-2
...@@ -38,8 +38,9 @@ struct ZigList {...@@ -38,8 +38,9 @@ struct ZigList {
38 return items[--length];38 return items[--length];
39 }39 }
4040
41 void add_one() {41 T *add_one() {
42 return resize(length + 1);42 resize(length + 1);
43 return &last();
43 }44 }
4445
45 const T & last() const {46 const T & last() const {
src/parser.cpp+17-2
...@@ -1643,7 +1643,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m...@@ -1643,7 +1643,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m
16431643
1644/*1644/*
1645SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}"1645SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}"
1646SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Expression ","1646SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
1647SwitchItem : Expression | (Expression "..." Expression)1647SwitchItem : Expression | (Expression "..." Expression)
1648*/1648*/
1649static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1649static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
...@@ -1691,6 +1691,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo...@@ -1691,6 +1691,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
1691 range_node->data.switch_range.start = expr1;1691 range_node->data.switch_range.start = expr1;
1692 range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true);1692 range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true);
16931693
1694 prong_node->data.switch_prong.any_items_are_range = true;
1694 } else {1695 } else {
1695 prong_node->data.switch_prong.items.append(expr1);1696 prong_node->data.switch_prong.items.append(expr1);
1696 }1697 }
...@@ -1707,7 +1708,21 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo...@@ -1707,7 +1708,21 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
1707 Token *maybe_bar = &pc->tokens->at(*token_index);1708 Token *maybe_bar = &pc->tokens->at(*token_index);
1708 if (maybe_bar->id == TokenIdBinOr) {1709 if (maybe_bar->id == TokenIdBinOr) {
1709 *token_index += 1;1710 *token_index += 1;
1710 prong_node->data.switch_prong.var_symbol = ast_parse_symbol(pc, token_index);1711
1712 Token *star_or_symbol = &pc->tokens->at(*token_index);
1713 AstNode *var_symbol_node;
1714 bool var_is_ptr;
1715 if (star_or_symbol->id == TokenIdStar) {
1716 *token_index += 1;
1717 var_is_ptr = true;
1718 var_symbol_node = ast_parse_symbol(pc, token_index);
1719 } else {
1720 var_is_ptr = false;
1721 var_symbol_node = ast_parse_symbol(pc, token_index);
1722 }
1723
1724 prong_node->data.switch_prong.var_symbol = var_symbol_node;
1725 prong_node->data.switch_prong.var_is_ptr = var_is_ptr;
1711 ast_eat_token(pc, token_index, TokenIdBinOr);1726 ast_eat_token(pc, token_index, TokenIdBinOr);
1712 }1727 }
17131728
test/self_hosted2.zig+14
...@@ -12,9 +12,23 @@ export fn disabledExternFn() {...@@ -12,9 +12,23 @@ export fn disabledExternFn() {
12 @setFnVisible(this, false);12 @setFnVisible(this, false);
13}13}
1414
15fn inlinedLoop() {
16 inline var i = 0;
17 inline var sum = 0;
18 inline while (i <= 5; i += 1)
19 sum += i;
20 assert(sum == 15);
21}
22
23fn assert(ok: bool) {
24 if (!ok)
25 @unreachable();
26}
27
15fn runAllTests() {28fn runAllTests() {
16 emptyFunctionWithComments();29 emptyFunctionWithComments();
17 disabledExternFn();30 disabledExternFn();
31 inlinedLoop();
18}32}
1933
20export nakedcc fn _start() -> unreachable {34export nakedcc fn _start() -> unreachable {