| ... | ... | @@ -114,6 +114,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchBr *) { |
| 114 | 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 | 125 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPhi *) { |
| 118 | 126 | return IrInstructionIdPhi; |
| 119 | 127 | } |
| ... | ... | @@ -981,6 +989,51 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr |
| 981 | 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 | 1037 | static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, |
| 985 | 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 | 1100 | if (name) { |
| 1048 | 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 | 1104 | if (existing_var && !existing_var->shadowable) { |
| 1052 | 1105 | ErrorMsg *msg = add_node_error(codegen, node, |
| 1053 | 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 | 1114 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); |
| 1062 | 1115 | variable_entry->type = codegen->builtin_types.entry_invalid; |
| 1063 | 1116 | } else { |
| 1064 | | AstNode *decl_node = find_decl(node->block_context, name); |
| 1117 | AstNode *decl_node = find_decl(scope, name); |
| 1065 | 1118 | if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { |
| 1066 | 1119 | ErrorMsg *msg = add_node_error(codegen, node, |
| 1067 | 1120 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| ... | ... | @@ -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 | 1128 | } else { |
| 1076 | 1129 | assert(is_shadowable); |
| 1077 | 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 | 2105 | |
| 2053 | 2106 | ir_set_cursor_at_end(irb, then_block); |
| 2054 | 2107 | IrInstruction *var_type = nullptr; |
| 2055 | | if (var_decl->type) |
| 2108 | if (var_decl->type) { |
| 2056 | 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 | 2113 | BlockContext *child_scope = new_block_context(node, node->block_context); |
| 2058 | 2114 | bool is_shadowable = false; |
| 2059 | 2115 | bool is_const = var_decl->is_const; |
| ... | ... | @@ -2091,6 +2147,190 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) { |
| 2091 | 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 | 2334 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| 2095 | 2335 | LValPurpose lval) |
| 2096 | 2336 | { |
| ... | ... | @@ -2142,6 +2382,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex |
| 2142 | 2382 | return ir_gen_null_literal(irb, node); |
| 2143 | 2383 | case NodeTypeIfVarExpr: |
| 2144 | 2384 | return ir_gen_if_var_expr(irb, node); |
| 2385 | case NodeTypeSwitchExpr: |
| 2386 | return ir_gen_switch_expr(irb, node); |
| 2145 | 2387 | case NodeTypeUnwrapErrorExpr: |
| 2146 | 2388 | case NodeTypeDefer: |
| 2147 | 2389 | case NodeTypeSliceExpr: |
| ... | ... | @@ -2149,7 +2391,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex |
| 2149 | 2391 | case NodeTypeBreak: |
| 2150 | 2392 | case NodeTypeContinue: |
| 2151 | 2393 | case NodeTypeLabel: |
| 2152 | | case NodeTypeSwitchExpr: |
| 2153 | 2394 | case NodeTypeCharLiteral: |
| 2154 | 2395 | case NodeTypeZeroesLiteral: |
| 2155 | 2396 | case NodeTypeErrorType: |
| ... | ... | @@ -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 | 5132 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 4874 | 5133 | switch (instruction->id) { |
| 4875 | 5134 | case IrInstructionIdInvalid: |
| ... | ... | @@ -4937,6 +5196,11 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 4937 | 5196 | case IrInstructionIdCtz: |
| 4938 | 5197 | return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction); |
| 4939 | 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 | 5204 | case IrInstructionIdCast: |
| 4941 | 5205 | case IrInstructionIdContainerInitList: |
| 4942 | 5206 | case IrInstructionIdContainerInitFields: |
| ... | ... | @@ -5053,6 +5317,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 5053 | 5317 | case IrInstructionIdUnwrapMaybe: |
| 5054 | 5318 | case IrInstructionIdClz: |
| 5055 | 5319 | case IrInstructionIdCtz: |
| 5320 | case IrInstructionIdSwitchVar: |
| 5321 | case IrInstructionIdSwitchTarget: |
| 5056 | 5322 | return false; |
| 5057 | 5323 | case IrInstructionIdAsm: |
| 5058 | 5324 | { |
| ... | ... | @@ -7037,246 +7303,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 7037 | 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 | 7306 | //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 7281 | 7307 | // TypeTableEntry *expected_type, AstNode *node) |
| 7282 | 7308 | //{ |
| ... | ... | @@ -9338,190 +9364,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 9338 | 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 | 9367 | //static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { |
| 9526 | 9368 | // assert(node->type == NodeTypeArrayAccessExpr); |
| 9527 | 9369 | // |