| ... | @@ -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 | } |
| 116 | | 116 | |
| | 117 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchVar *) { |
| | 118 | return IrInstructionIdSwitchVar; |
| | 119 | } |
| | 120 | |
| | 121 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchTarget *) { |
| | 122 | return IrInstructionIdSwitchTarget; |
| | 123 | } |
| | 124 | |
| 117 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPhi *) { | 125 | static 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 | } |
| 983 | | 991 | |
| | 992 | static 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 | |
| | 1013 | static 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 | |
| | 1024 | static 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 | |
| 984 | static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, | 1037 | static 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); |
| 1049 | | 1102 | |
| 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 | } |
| 1073 | | 1126 | |
| 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 pass | 1130 | // 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) { |
| 2052 | | 2105 | |
| 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 | } |
| 2093 | | 2149 | |
| | 2150 | static 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 | |
| | 2192 | static 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 | |
| 2094 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context, | 2334 | static 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 | } |
| 4872 | | 5113 | |
| | 5114 | static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, |
| | 5115 | IrInstructionSwitchBr *switch_br_instruction) |
| | 5116 | { |
| | 5117 | zig_panic("TODO switch br analyze"); |
| | 5118 | } |
| | 5119 | |
| | 5120 | static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| | 5121 | IrInstructionSwitchTarget *switch_target_instruction) |
| | 5122 | { |
| | 5123 | zig_panic("TODO switch target analyze"); |
| | 5124 | } |
| | 5125 | |
| | 5126 | static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, |
| | 5127 | IrInstructionSwitchVar *switch_var_instruction) |
| | 5128 | { |
| | 5129 | zig_panic("TODO switch var analyze"); |
| | 5130 | } |
| | 5131 | |
| 4873 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 5132 | static 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 | // |