| ... | ... | @@ -339,10 +339,10 @@ static void destroy_instruction(IrInstruction *inst) { |
| 339 | 339 | return destroy(reinterpret_cast<IrInstructionSliceType *>(inst), name); |
| 340 | 340 | case IrInstructionIdAnyFrameType: |
| 341 | 341 | return destroy(reinterpret_cast<IrInstructionAnyFrameType *>(inst), name); |
| 342 | | case IrInstructionIdGlobalAsm: |
| 343 | | return destroy(reinterpret_cast<IrInstructionGlobalAsm *>(inst), name); |
| 344 | | case IrInstructionIdAsm: |
| 345 | | return destroy(reinterpret_cast<IrInstructionAsm *>(inst), name); |
| 342 | case IrInstructionIdAsmSrc: |
| 343 | return destroy(reinterpret_cast<IrInstructionAsmSrc *>(inst), name); |
| 344 | case IrInstructionIdAsmGen: |
| 345 | return destroy(reinterpret_cast<IrInstructionAsmGen *>(inst), name); |
| 346 | 346 | case IrInstructionIdSizeOf: |
| 347 | 347 | return destroy(reinterpret_cast<IrInstructionSizeOf *>(inst), name); |
| 348 | 348 | case IrInstructionIdTestNonNull: |
| ... | ... | @@ -1028,12 +1028,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) { |
| 1028 | 1028 | return IrInstructionIdSliceType; |
| 1029 | 1029 | } |
| 1030 | 1030 | |
| 1031 | | static constexpr IrInstructionId ir_instruction_id(IrInstructionGlobalAsm *) { |
| 1032 | | return IrInstructionIdGlobalAsm; |
| 1031 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAsmSrc *) { |
| 1032 | return IrInstructionIdAsmSrc; |
| 1033 | 1033 | } |
| 1034 | 1034 | |
| 1035 | | static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) { |
| 1036 | | return IrInstructionIdAsm; |
| 1035 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAsmGen *) { |
| 1036 | return IrInstructionIdAsmGen; |
| 1037 | 1037 | } |
| 1038 | 1038 | |
| 1039 | 1039 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) { |
| ... | ... | @@ -2268,18 +2268,39 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode |
| 2268 | 2268 | return &instruction->base; |
| 2269 | 2269 | } |
| 2270 | 2270 | |
| 2271 | | static IrInstruction *ir_build_global_asm(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *asm_code) { |
| 2272 | | IrInstructionGlobalAsm *instruction = ir_build_instruction<IrInstructionGlobalAsm>(irb, scope, source_node); |
| 2273 | | instruction->asm_code = asm_code; |
| 2271 | static IrInstruction *ir_build_asm_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2272 | IrInstruction *asm_template, IrInstruction **input_list, IrInstruction **output_types, |
| 2273 | ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global) |
| 2274 | { |
| 2275 | IrInstructionAsmSrc *instruction = ir_build_instruction<IrInstructionAsmSrc>(irb, scope, source_node); |
| 2276 | instruction->asm_template = asm_template; |
| 2277 | instruction->input_list = input_list; |
| 2278 | instruction->output_types = output_types; |
| 2279 | instruction->output_vars = output_vars; |
| 2280 | instruction->return_count = return_count; |
| 2281 | instruction->has_side_effects = has_side_effects; |
| 2282 | instruction->is_global = is_global; |
| 2283 | |
| 2284 | assert(source_node->type == NodeTypeAsmExpr); |
| 2285 | for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { |
| 2286 | IrInstruction *output_type = output_types[i]; |
| 2287 | if (output_type) ir_ref_instruction(output_type, irb->current_basic_block); |
| 2288 | } |
| 2289 | |
| 2290 | for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { |
| 2291 | IrInstruction *input_value = input_list[i]; |
| 2292 | ir_ref_instruction(input_value, irb->current_basic_block); |
| 2293 | } |
| 2294 | |
| 2274 | 2295 | return &instruction->base; |
| 2275 | 2296 | } |
| 2276 | 2297 | |
| 2277 | | static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2298 | static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, |
| 2278 | 2299 | Buf *asm_template, AsmToken *token_list, size_t token_list_len, |
| 2279 | 2300 | IrInstruction **input_list, IrInstruction **output_types, ZigVar **output_vars, size_t return_count, |
| 2280 | 2301 | bool has_side_effects) |
| 2281 | 2302 | { |
| 2282 | | IrInstructionAsm *instruction = ir_build_instruction<IrInstructionAsm>(irb, scope, source_node); |
| 2303 | IrInstructionAsmGen *instruction = ir_build_instruction<IrInstructionAsmGen>(&ira->new_irb, scope, source_node); |
| 2283 | 2304 | instruction->asm_template = asm_template; |
| 2284 | 2305 | instruction->token_list = token_list; |
| 2285 | 2306 | instruction->token_list_len = token_list_len; |
| ... | ... | @@ -2292,12 +2313,12 @@ static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source |
| 2292 | 2313 | assert(source_node->type == NodeTypeAsmExpr); |
| 2293 | 2314 | for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { |
| 2294 | 2315 | IrInstruction *output_type = output_types[i]; |
| 2295 | | if (output_type) ir_ref_instruction(output_type, irb->current_basic_block); |
| 2316 | if (output_type) ir_ref_instruction(output_type, ira->new_irb.current_basic_block); |
| 2296 | 2317 | } |
| 2297 | 2318 | |
| 2298 | 2319 | for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { |
| 2299 | 2320 | IrInstruction *input_value = input_list[i]; |
| 2300 | | ir_ref_instruction(input_value, irb->current_basic_block); |
| 2321 | ir_ref_instruction(input_value, ira->new_irb.current_basic_block); |
| 2301 | 2322 | } |
| 2302 | 2323 | |
| 2303 | 2324 | return &instruction->base; |
| ... | ... | @@ -7494,7 +7515,7 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, Ast |
| 7494 | 7515 | return ir_build_const_undefined(irb, scope, node); |
| 7495 | 7516 | } |
| 7496 | 7517 | |
| 7497 | | static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_template, |
| 7518 | static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template, |
| 7498 | 7519 | ZigList<AsmToken> *tok_list) |
| 7499 | 7520 | { |
| 7500 | 7521 | // TODO Connect the errors in this function back up to the actual source location |
| ... | ... | @@ -7542,7 +7563,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t |
| 7542 | 7563 | cur_tok->end = i; |
| 7543 | 7564 | state = StateStart; |
| 7544 | 7565 | } else { |
| 7545 | | add_node_error(irb->codegen, source_node, |
| 7566 | add_node_error(ira->codegen, source_node, |
| 7546 | 7567 | buf_create_from_str("expected a '%' or '['")); |
| 7547 | 7568 | return ErrorSemanticAnalyzeFail; |
| 7548 | 7569 | } |
| ... | ... | @@ -7565,7 +7586,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t |
| 7565 | 7586 | { |
| 7566 | 7587 | // do nothing |
| 7567 | 7588 | } else { |
| 7568 | | add_node_error(irb->codegen, source_node, |
| 7589 | add_node_error(ira->codegen, source_node, |
| 7569 | 7590 | buf_sprintf("invalid substitution character: '%c'", c)); |
| 7570 | 7591 | return ErrorSemanticAnalyzeFail; |
| 7571 | 7592 | } |
| ... | ... | @@ -7578,7 +7599,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t |
| 7578 | 7599 | break; |
| 7579 | 7600 | case StatePercent: |
| 7580 | 7601 | case StateVar: |
| 7581 | | add_node_error(irb->codegen, source_node, buf_sprintf("unexpected end of assembly template")); |
| 7602 | add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template")); |
| 7582 | 7603 | return ErrorSemanticAnalyzeFail; |
| 7583 | 7604 | case StateTemplate: |
| 7584 | 7605 | cur_tok->end = buf_len(asm_template); |
| ... | ... | @@ -7607,14 +7628,16 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_ |
| 7607 | 7628 | } |
| 7608 | 7629 | |
| 7609 | 7630 | static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 7610 | | Error err; |
| 7611 | 7631 | assert(node->type == NodeTypeAsmExpr); |
| 7612 | 7632 | AstNodeAsmExpr *asm_expr = &node->data.asm_expr; |
| 7633 | |
| 7634 | IrInstruction *asm_template = ir_gen_node(irb, asm_expr->asm_template, scope); |
| 7635 | if (asm_template == irb->codegen->invalid_instruction) |
| 7636 | return irb->codegen->invalid_instruction; |
| 7637 | |
| 7613 | 7638 | bool is_volatile = asm_expr->volatile_token != nullptr; |
| 7614 | 7639 | bool in_fn_scope = (scope_fn_entry(scope) != nullptr); |
| 7615 | 7640 | |
| 7616 | | Buf *template_buf = &asm_expr->asm_template->data.str_lit.str; |
| 7617 | | |
| 7618 | 7641 | if (!in_fn_scope) { |
| 7619 | 7642 | if (is_volatile) { |
| 7620 | 7643 | add_token_error(irb->codegen, node->owner, asm_expr->volatile_token, |
| ... | ... | @@ -7630,12 +7653,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 7630 | 7653 | return irb->codegen->invalid_instruction; |
| 7631 | 7654 | } |
| 7632 | 7655 | |
| 7633 | | return ir_build_global_asm(irb, scope, node, template_buf); |
| 7634 | | } |
| 7635 | | |
| 7636 | | ZigList<AsmToken> tok_list = {}; |
| 7637 | | if ((err = parse_asm_template(irb, node, template_buf, &tok_list))) { |
| 7638 | | return irb->codegen->invalid_instruction; |
| 7656 | return ir_build_asm_src(irb, scope, node, asm_template, nullptr, nullptr, |
| 7657 | nullptr, 0, is_volatile, true); |
| 7639 | 7658 | } |
| 7640 | 7659 | |
| 7641 | 7660 | IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length); |
| ... | ... | @@ -7693,24 +7712,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 7693 | 7712 | input_list[i] = input_value; |
| 7694 | 7713 | } |
| 7695 | 7714 | |
| 7696 | | for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) { |
| 7697 | | AsmToken asm_token = tok_list.at(token_i); |
| 7698 | | if (asm_token.id == AsmTokenIdVar) { |
| 7699 | | size_t index = find_asm_index(irb->codegen, node, &asm_token, template_buf); |
| 7700 | | if (index == SIZE_MAX) { |
| 7701 | | const char *ptr = buf_ptr(template_buf) + asm_token.start + 2; |
| 7702 | | uint32_t len = asm_token.end - asm_token.start - 2; |
| 7703 | | |
| 7704 | | add_node_error(irb->codegen, node, |
| 7705 | | buf_sprintf("could not find '%.*s' in the inputs or outputs", |
| 7706 | | len, ptr)); |
| 7707 | | return irb->codegen->invalid_instruction; |
| 7708 | | } |
| 7709 | | } |
| 7710 | | } |
| 7711 | | |
| 7712 | | return ir_build_asm(irb, scope, node, template_buf, tok_list.items, tok_list.length, |
| 7713 | | input_list, output_types, output_vars, return_count, is_volatile); |
| 7715 | return ir_build_asm_src(irb, scope, node, asm_template, input_list, output_types, |
| 7716 | output_vars, return_count, is_volatile, false); |
| 7714 | 7717 | } |
| 7715 | 7718 | |
| 7716 | 7719 | static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, |
| ... | ... | @@ -20150,21 +20153,49 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 20150 | 20153 | return result; |
| 20151 | 20154 | } |
| 20152 | 20155 | |
| 20153 | | static IrInstruction *ir_analyze_instruction_global_asm(IrAnalyze *ira, IrInstructionGlobalAsm *instruction) { |
| 20154 | | buf_append_char(&ira->codegen->global_asm, '\n'); |
| 20155 | | buf_append_buf(&ira->codegen->global_asm, instruction->asm_code); |
| 20156 | | |
| 20157 | | return ir_const_void(ira, &instruction->base); |
| 20158 | | } |
| 20156 | static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsmSrc *asm_instruction) { |
| 20157 | Error err; |
| 20159 | 20158 | |
| 20160 | | static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) { |
| 20161 | 20159 | assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr); |
| 20162 | 20160 | |
| 20161 | AstNode *node = asm_instruction->base.source_node; |
| 20163 | 20162 | AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr; |
| 20164 | 20163 | |
| 20164 | Buf *template_buf = ir_resolve_str(ira, asm_instruction->asm_template->child); |
| 20165 | if (template_buf == nullptr) |
| 20166 | return ira->codegen->invalid_instruction; |
| 20167 | |
| 20168 | if (asm_instruction->is_global) { |
| 20169 | buf_append_char(&ira->codegen->global_asm, '\n'); |
| 20170 | buf_append_buf(&ira->codegen->global_asm, template_buf); |
| 20171 | |
| 20172 | return ir_const_void(ira, &asm_instruction->base); |
| 20173 | } |
| 20174 | |
| 20165 | 20175 | if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base)) |
| 20166 | 20176 | return ira->codegen->invalid_instruction; |
| 20167 | 20177 | |
| 20178 | ZigList<AsmToken> tok_list = {}; |
| 20179 | if ((err = parse_asm_template(ira, node, template_buf, &tok_list))) { |
| 20180 | return ira->codegen->invalid_instruction; |
| 20181 | } |
| 20182 | |
| 20183 | for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) { |
| 20184 | AsmToken asm_token = tok_list.at(token_i); |
| 20185 | if (asm_token.id == AsmTokenIdVar) { |
| 20186 | size_t index = find_asm_index(ira->codegen, node, &asm_token, template_buf); |
| 20187 | if (index == SIZE_MAX) { |
| 20188 | const char *ptr = buf_ptr(template_buf) + asm_token.start + 2; |
| 20189 | uint32_t len = asm_token.end - asm_token.start - 2; |
| 20190 | |
| 20191 | add_node_error(ira->codegen, node, |
| 20192 | buf_sprintf("could not find '%.*s' in the inputs or outputs", |
| 20193 | len, ptr)); |
| 20194 | return ira->codegen->invalid_instruction; |
| 20195 | } |
| 20196 | } |
| 20197 | } |
| 20198 | |
| 20168 | 20199 | // TODO validate the output types and variable types |
| 20169 | 20200 | |
| 20170 | 20201 | IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length); |
| ... | ... | @@ -20197,9 +20228,9 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs |
| 20197 | 20228 | input_list[i] = input_value; |
| 20198 | 20229 | } |
| 20199 | 20230 | |
| 20200 | | IrInstruction *result = ir_build_asm(&ira->new_irb, |
| 20231 | IrInstruction *result = ir_build_asm_gen(ira, |
| 20201 | 20232 | asm_instruction->base.scope, asm_instruction->base.source_node, |
| 20202 | | asm_instruction->asm_template, asm_instruction->token_list, asm_instruction->token_list_len, |
| 20233 | template_buf, tok_list.items, tok_list.length, |
| 20203 | 20234 | input_list, output_types, asm_instruction->output_vars, asm_instruction->return_count, |
| 20204 | 20235 | asm_instruction->has_side_effects); |
| 20205 | 20236 | result->value->type = return_type; |
| ... | ... | @@ -27722,6 +27753,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 27722 | 27753 | case IrInstructionIdSplatGen: |
| 27723 | 27754 | case IrInstructionIdVectorExtractElem: |
| 27724 | 27755 | case IrInstructionIdVectorStoreElem: |
| 27756 | case IrInstructionIdAsmGen: |
| 27725 | 27757 | zig_unreachable(); |
| 27726 | 27758 | |
| 27727 | 27759 | case IrInstructionIdReturn: |
| ... | ... | @@ -27768,10 +27800,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 27768 | 27800 | return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction); |
| 27769 | 27801 | case IrInstructionIdSliceType: |
| 27770 | 27802 | return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction); |
| 27771 | | case IrInstructionIdGlobalAsm: |
| 27772 | | return ir_analyze_instruction_global_asm(ira, (IrInstructionGlobalAsm *)instruction); |
| 27773 | | case IrInstructionIdAsm: |
| 27774 | | return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction); |
| 27803 | case IrInstructionIdAsmSrc: |
| 27804 | return ir_analyze_instruction_asm(ira, (IrInstructionAsmSrc *)instruction); |
| 27775 | 27805 | case IrInstructionIdArrayType: |
| 27776 | 27806 | return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction); |
| 27777 | 27807 | case IrInstructionIdSizeOf: |
| ... | ... | @@ -28183,7 +28213,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 28183 | 28213 | case IrInstructionIdAssertZero: |
| 28184 | 28214 | case IrInstructionIdAssertNonNull: |
| 28185 | 28215 | case IrInstructionIdResizeSlice: |
| 28186 | | case IrInstructionIdGlobalAsm: |
| 28187 | 28216 | case IrInstructionIdUndeclaredIdent: |
| 28188 | 28217 | case IrInstructionIdEndExpr: |
| 28189 | 28218 | case IrInstructionIdPtrOfArrayToSlice: |
| ... | ... | @@ -28303,9 +28332,15 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 28303 | 28332 | case IrInstructionIdVectorExtractElem: |
| 28304 | 28333 | return false; |
| 28305 | 28334 | |
| 28306 | | case IrInstructionIdAsm: |
| 28335 | case IrInstructionIdAsmSrc: |
| 28336 | { |
| 28337 | IrInstructionAsmSrc *asm_instruction = (IrInstructionAsmSrc *)instruction; |
| 28338 | return asm_instruction->has_side_effects; |
| 28339 | } |
| 28340 | |
| 28341 | case IrInstructionIdAsmGen: |
| 28307 | 28342 | { |
| 28308 | | IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction; |
| 28343 | IrInstructionAsmGen *asm_instruction = (IrInstructionAsmGen *)instruction; |
| 28309 | 28344 | return asm_instruction->has_side_effects; |
| 28310 | 28345 | } |
| 28311 | 28346 | case IrInstructionIdUnwrapErrPayload: |