authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-13 21:07:30-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-13 21:07:30-05:00
log2edc6c1a3fbce80132a023820897b929732f837e
treebd5bcd93a7026a053ddd2b37d8c6dab5f17fd01b
parent04c047463b2679c588c3fb09f3dace80aebd5723

IR: add assembly instruction


5 files changed, 368 insertions(+), 229 deletions(-)

src/all_types.hpp+11-1
...@@ -631,7 +631,6 @@ struct AstNodeAsmExpr {...@@ -631,7 +631,6 @@ struct AstNodeAsmExpr {
631 ZigList<Buf*> clobber_list;631 ZigList<Buf*> clobber_list;
632632
633 // populated by semantic analyzer633 // populated by semantic analyzer
634 size_t return_count;
635 Expr resolved_expr;634 Expr resolved_expr;
636};635};
637636
...@@ -1449,6 +1448,7 @@ enum IrInstructionId {...@@ -1449,6 +1448,7 @@ enum IrInstructionId {
1449 IrInstructionIdSetFnTest,1448 IrInstructionIdSetFnTest,
1450 IrInstructionIdArrayType,1449 IrInstructionIdArrayType,
1451 IrInstructionIdSliceType,1450 IrInstructionIdSliceType,
1451 IrInstructionIdAsm,
1452};1452};
14531453
1454struct IrInstruction {1454struct IrInstruction {
...@@ -1716,6 +1716,16 @@ struct IrInstructionSliceType {...@@ -1716,6 +1716,16 @@ struct IrInstructionSliceType {
1716 IrInstruction *child_type;1716 IrInstruction *child_type;
1717};1717};
17181718
1719struct IrInstructionAsm {
1720 IrInstruction base;
1721
1722 // Most information on inline assembly comes from the source node.
1723 IrInstruction **input_list;
1724 IrInstruction **output_types;
1725 size_t return_count;
1726 bool has_side_effects;
1727};
1728
1719enum LValPurpose {1729enum LValPurpose {
1720 LValPurposeNone,1730 LValPurposeNone,
1721 LValPurposeAssign,1731 LValPurposeAssign,
src/ast_render.cpp+61-2
...@@ -407,13 +407,19 @@ static void render_node(AstRender *ar, AstNode *node) {...@@ -407,13 +407,19 @@ static void render_node(AstRender *ar, AstNode *node) {
407 break;407 break;
408 }408 }
409 case NodeTypeBlock:409 case NodeTypeBlock:
410 if (node->data.block.statements.length == 0) {
411 fprintf(ar->f, "{}");
412 break;
413 }
410 fprintf(ar->f, "{\n");414 fprintf(ar->f, "{\n");
411 ar->indent += ar->indent_size;415 ar->indent += ar->indent_size;
412 for (size_t i = 0; i < node->data.block.statements.length; i += 1) {416 for (size_t i = 0; i < node->data.block.statements.length; i += 1) {
413 AstNode *statement = node->data.block.statements.at(i);417 AstNode *statement = node->data.block.statements.at(i);
414 print_indent(ar);418 print_indent(ar);
415 render_node(ar, statement);419 render_node(ar, statement);
416 fprintf(ar->f, ";\n");420 if (i != node->data.block.statements.length - 1)
421 fprintf(ar->f, ";");
422 fprintf(ar->f, "\n");
417 }423 }
418 ar->indent -= ar->indent_size;424 ar->indent -= ar->indent_size;
419 print_indent(ar);425 print_indent(ar);
...@@ -598,6 +604,60 @@ static void render_node(AstRender *ar, AstNode *node) {...@@ -598,6 +604,60 @@ static void render_node(AstRender *ar, AstNode *node) {
598 case NodeTypeVarLiteral:604 case NodeTypeVarLiteral:
599 fprintf(ar->f, "var");605 fprintf(ar->f, "var");
600 break;606 break;
607 case NodeTypeAsmExpr:
608 {
609 AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
610 const char *volatile_str = asm_expr->is_volatile ? " volatile" : "";
611 fprintf(ar->f, "asm%s (\"%s\"\n", volatile_str, buf_ptr(asm_expr->asm_template));
612 print_indent(ar);
613 fprintf(ar->f, ": ");
614 for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
615 AsmOutput *asm_output = asm_expr->output_list.at(i);
616
617 if (i != 0) {
618 fprintf(ar->f, ",\n");
619 print_indent(ar);
620 }
621
622 fprintf(ar->f, "[%s] \"%s\" (",
623 buf_ptr(asm_output->asm_symbolic_name),
624 buf_ptr(asm_output->constraint));
625 if (asm_output->return_type) {
626 fprintf(ar->f, "-> ");
627 render_node(ar, asm_output->return_type);
628 } else {
629 fprintf(ar->f, "%s", buf_ptr(asm_output->variable_name));
630 }
631 fprintf(ar->f, ")");
632 }
633 fprintf(ar->f, "\n");
634 print_indent(ar);
635 fprintf(ar->f, ": ");
636 for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
637 AsmInput *asm_input = asm_expr->input_list.at(i);
638
639 if (i != 0) {
640 fprintf(ar->f, ",\n");
641 print_indent(ar);
642 }
643
644 fprintf(ar->f, "[%s] \"%s\" (",
645 buf_ptr(asm_input->asm_symbolic_name),
646 buf_ptr(asm_input->constraint));
647 render_node(ar, asm_input->expr);
648 fprintf(ar->f, ")");
649 }
650 fprintf(ar->f, "\n");
651 print_indent(ar);
652 fprintf(ar->f, ": ");
653 for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) {
654 Buf *reg_name = asm_expr->clobber_list.at(i);
655 if (i != 0) fprintf(ar->f, ", ");
656 fprintf(ar->f, "\"%s\"", buf_ptr(reg_name));
657 }
658 fprintf(ar->f, ")");
659 break;
660 }
601 case NodeTypeFnDecl:661 case NodeTypeFnDecl:
602 case NodeTypeParamDecl:662 case NodeTypeParamDecl:
603 case NodeTypeErrorValueDecl:663 case NodeTypeErrorValueDecl:
...@@ -621,7 +681,6 @@ static void render_node(AstRender *ar, AstNode *node) {...@@ -621,7 +681,6 @@ static void render_node(AstRender *ar, AstNode *node) {
621 case NodeTypeGoto:681 case NodeTypeGoto:
622 case NodeTypeBreak:682 case NodeTypeBreak:
623 case NodeTypeContinue:683 case NodeTypeContinue:
624 case NodeTypeAsmExpr:
625 zig_panic("TODO more ast rendering");684 zig_panic("TODO more ast rendering");
626 }685 }
627}686}
src/codegen.cpp+132
...@@ -1537,6 +1537,136 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa...@@ -1537,6 +1537,136 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
1537 return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, "");1537 return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, "");
1538}1538}
15391539
1540static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstructionAsm *instruction) {
1541 zig_panic("TODO render asm");
1542}
1543//static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
1544// const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
1545// size_t len = tok->end - tok->start - 2;
1546// size_t result = 0;
1547// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
1548// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
1549// if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) {
1550// return result;
1551// }
1552// }
1553// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
1554// AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
1555// if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) {
1556// return result;
1557// }
1558// }
1559// return SIZE_MAX;
1560//}
1561//
1562//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
1563// assert(node->type == NodeTypeAsmExpr);
1564//
1565// AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
1566//
1567// Buf *src_template = asm_expr->asm_template;
1568//
1569// Buf llvm_template = BUF_INIT;
1570// buf_resize(&llvm_template, 0);
1571//
1572// for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) {
1573// AsmToken *asm_token = &asm_expr->token_list.at(token_i);
1574// switch (asm_token->id) {
1575// case AsmTokenIdTemplate:
1576// for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) {
1577// uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
1578// if (c == '$') {
1579// buf_append_str(&llvm_template, "$$");
1580// } else {
1581// buf_append_char(&llvm_template, c);
1582// }
1583// }
1584// break;
1585// case AsmTokenIdPercent:
1586// buf_append_char(&llvm_template, '%');
1587// break;
1588// case AsmTokenIdVar:
1589// size_t index = find_asm_index(g, node, asm_token);
1590// assert(index < SIZE_MAX);
1591// buf_appendf(&llvm_template, "$%zu", index);
1592// break;
1593// }
1594// }
1595//
1596// Buf constraint_buf = BUF_INIT;
1597// buf_resize(&constraint_buf, 0);
1598//
1599// assert(asm_expr->return_count == 0 || asm_expr->return_count == 1);
1600//
1601// size_t total_constraint_count = asm_expr->output_list.length +
1602// asm_expr->input_list.length +
1603// asm_expr->clobber_list.length;
1604// size_t input_and_output_count = asm_expr->output_list.length +
1605// asm_expr->input_list.length -
1606// asm_expr->return_count;
1607// size_t total_index = 0;
1608// size_t param_index = 0;
1609// LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
1610// LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
1611// for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
1612// AsmOutput *asm_output = asm_expr->output_list.at(i);
1613// bool is_return = (asm_output->return_type != nullptr);
1614// assert(*buf_ptr(asm_output->constraint) == '=');
1615// if (is_return) {
1616// buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
1617// } else {
1618// buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1);
1619// }
1620// if (total_index + 1 < total_constraint_count) {
1621// buf_append_char(&constraint_buf, ',');
1622// }
1623//
1624// if (!is_return) {
1625// VariableTableEntry *variable = asm_output->variable;
1626// assert(variable);
1627// param_types[param_index] = LLVMTypeOf(variable->value_ref);
1628// param_values[param_index] = variable->value_ref;
1629// param_index += 1;
1630// }
1631// }
1632// for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
1633// AsmInput *asm_input = asm_expr->input_list.at(i);
1634// buf_append_buf(&constraint_buf, asm_input->constraint);
1635// if (total_index + 1 < total_constraint_count) {
1636// buf_append_char(&constraint_buf, ',');
1637// }
1638//
1639// TypeTableEntry *expr_type = get_expr_type(asm_input->expr);
1640// param_types[param_index] = expr_type->type_ref;
1641// param_values[param_index] = gen_expr(g, asm_input->expr);
1642// }
1643// for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
1644// Buf *clobber_buf = asm_expr->clobber_list.at(i);
1645// buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf));
1646// if (total_index + 1 < total_constraint_count) {
1647// buf_append_char(&constraint_buf, ',');
1648// }
1649// }
1650//
1651// LLVMTypeRef ret_type;
1652// if (asm_expr->return_count == 0) {
1653// ret_type = LLVMVoidType();
1654// } else {
1655// ret_type = get_expr_type(node)->type_ref;
1656// }
1657// LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
1658//
1659// bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
1660// LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
1661// buf_ptr(&constraint_buf), is_volatile, false);
1662//
1663// set_debug_source_node(g, node);
1664// return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
1665//}
1666//
1667
1668
1669
1540static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {1670static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
1541 set_debug_source_node(g, instruction->source_node);1671 set_debug_source_node(g, instruction->source_node);
15421672
...@@ -1579,6 +1709,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1579,6 +1709,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1579 return ir_render_call(g, executable, (IrInstructionCall *)instruction);1709 return ir_render_call(g, executable, (IrInstructionCall *)instruction);
1580 case IrInstructionIdStructFieldPtr:1710 case IrInstructionIdStructFieldPtr:
1581 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);1711 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
1712 case IrInstructionIdAsm:
1713 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
1582 case IrInstructionIdSwitchBr:1714 case IrInstructionIdSwitchBr:
1583 case IrInstructionIdPhi:1715 case IrInstructionIdPhi:
1584 case IrInstructionIdContainerInitList:1716 case IrInstructionIdContainerInitList:
src/ir.cpp+119-226
...@@ -197,6 +197,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {...@@ -197,6 +197,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
197 return IrInstructionIdSliceType;197 return IrInstructionIdSliceType;
198}198}
199199
200static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {
201 return IrInstructionIdAsm;
202}
203
200template<typename T>204template<typename T>
201static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {205static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
202 T *special_instruction = allocate<T>(1);206 T *special_instruction = allocate<T>(1);
...@@ -796,6 +800,38 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node,...@@ -796,6 +800,38 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node,
796 return &instruction->base;800 return &instruction->base;
797}801}
798802
803static IrInstruction *ir_build_asm(IrBuilder *irb, AstNode *source_node, IrInstruction **input_list,
804 IrInstruction **output_types, size_t return_count, bool has_side_effects)
805{
806 IrInstructionAsm *instruction = ir_build_instruction<IrInstructionAsm>(irb, source_node);
807 instruction->input_list = input_list;
808 instruction->output_types = output_types;
809 instruction->return_count = return_count;
810 instruction->has_side_effects = has_side_effects;
811
812 assert(source_node->type == NodeTypeAsmExpr);
813 for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) {
814 IrInstruction *output_type = output_types[i];
815 if (output_type) ir_ref_instruction(output_type);
816 }
817
818 for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) {
819 IrInstruction *input_value = input_list[i];
820 ir_ref_instruction(input_value);
821 }
822
823 return &instruction->base;
824}
825
826static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction **input_list,
827 IrInstruction **output_types, size_t return_count, bool has_side_effects)
828{
829 IrInstruction *new_instruction = ir_build_asm(irb, old_instruction->source_node, input_list, output_types,
830 return_count, has_side_effects);
831 ir_link_new_instruction(new_instruction, old_instruction);
832 return new_instruction;
833}
834
799static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,835static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
800 bool gen_error_defers, bool gen_maybe_defers)836 bool gen_error_defers, bool gen_maybe_defers)
801{837{
...@@ -1683,6 +1719,56 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, AstNode *node) {...@@ -1683,6 +1719,56 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, AstNode *node) {
1683 return ir_build_const_undefined(irb, node);1719 return ir_build_const_undefined(irb, node);
1684}1720}
16851721
1722static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) {
1723 assert(node->type == NodeTypeAsmExpr);
1724
1725 IrInstruction **input_list = allocate<IrInstruction *>(node->data.asm_expr.input_list.length);
1726 IrInstruction **output_types = allocate<IrInstruction *>(node->data.asm_expr.output_list.length);
1727 size_t return_count = 0;
1728 bool is_volatile = node->data.asm_expr.is_volatile;
1729 if (!is_volatile && node->data.asm_expr.output_list.length == 0) {
1730 add_node_error(irb->codegen, node,
1731 buf_sprintf("assembly expression with no output must be marked volatile"));
1732 return irb->codegen->invalid_instruction;
1733 }
1734 for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
1735 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
1736 if (asm_output->return_type) {
1737 return_count += 1;
1738
1739 IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, node->block_context);
1740 if (return_type == irb->codegen->invalid_instruction)
1741 return irb->codegen->invalid_instruction;
1742 if (return_count > 1) {
1743 add_node_error(irb->codegen, node,
1744 buf_sprintf("inline assembly allows up to one output value"));
1745 return irb->codegen->invalid_instruction;
1746 }
1747 output_types[i] = return_type;
1748 } else {
1749 Buf *variable_name = asm_output->variable_name;
1750 VariableTableEntry *var = find_variable(irb->codegen, node->block_context, variable_name);
1751 if (var) {
1752 asm_output->variable = var;
1753 } else {
1754 add_node_error(irb->codegen, node,
1755 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
1756 return irb->codegen->invalid_instruction;
1757 }
1758 }
1759 }
1760 for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
1761 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
1762 IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, node->block_context);
1763 if (input_value == irb->codegen->invalid_instruction)
1764 return irb->codegen->invalid_instruction;
1765
1766 input_list[i] = input_value;
1767 }
1768
1769 return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile);
1770}
1771
1686static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,1772static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
1687 LValPurpose lval)1773 LValPurpose lval)
1688{1774{
...@@ -1728,11 +1814,12 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont...@@ -1728,11 +1814,12 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
1728 return ir_gen_string_literal(irb, node);1814 return ir_gen_string_literal(irb, node);
1729 case NodeTypeUndefinedLiteral:1815 case NodeTypeUndefinedLiteral:
1730 return ir_gen_undefined_literal(irb, node);1816 return ir_gen_undefined_literal(irb, node);
1817 case NodeTypeAsmExpr:
1818 return ir_gen_asm_expr(irb, node);
1731 case NodeTypeUnwrapErrorExpr:1819 case NodeTypeUnwrapErrorExpr:
1732 case NodeTypeDefer:1820 case NodeTypeDefer:
1733 case NodeTypeSliceExpr:1821 case NodeTypeSliceExpr:
1734 case NodeTypeIfVarExpr:1822 case NodeTypeIfVarExpr:
1735 case NodeTypeAsmExpr:
1736 case NodeTypeGoto:1823 case NodeTypeGoto:
1737 case NodeTypeBreak:1824 case NodeTypeBreak:
1738 case NodeTypeContinue:1825 case NodeTypeContinue:
...@@ -3865,6 +3952,30 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -3865,6 +3952,30 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
3865 zig_unreachable();3952 zig_unreachable();
3866}3953}
38673954
3955static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) {
3956 assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr);
3957 mark_impure_fn(ira->codegen, asm_instruction->base.source_node->block_context,
3958 asm_instruction->base.source_node);
3959
3960 // TODO validate the output types and variable types
3961
3962 AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr;
3963
3964 TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void;
3965 for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
3966 AsmOutput *asm_output = asm_expr->output_list.at(i);
3967 if (asm_output->return_type) {
3968 return_type = ir_resolve_type(ira, asm_instruction->output_types[i]);
3969 if (return_type->id == TypeTableEntryIdInvalid)
3970 return ira->codegen->builtin_types.entry_invalid;
3971 }
3972 }
3973
3974 ir_build_asm_from(&ira->new_irb, &asm_instruction->base, asm_instruction->input_list,
3975 asm_instruction->output_types, asm_instruction->return_count, asm_instruction->has_side_effects);
3976 return return_type;
3977}
3978
3868static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {3979static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
3869 switch (instruction->id) {3980 switch (instruction->id) {
3870 case IrInstructionIdInvalid:3981 case IrInstructionIdInvalid:
...@@ -3911,6 +4022,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -3911,6 +4022,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
3911 return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction);4022 return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction);
3912 case IrInstructionIdSliceType:4023 case IrInstructionIdSliceType:
3913 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);4024 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
4025 case IrInstructionIdAsm:
4026 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
3914 case IrInstructionIdSwitchBr:4027 case IrInstructionIdSwitchBr:
3915 case IrInstructionIdCast:4028 case IrInstructionIdCast:
3916 case IrInstructionIdContainerInitList:4029 case IrInstructionIdContainerInitList:
...@@ -4020,6 +4133,11 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -4020,6 +4133,11 @@ bool ir_has_side_effects(IrInstruction *instruction) {
4020 case IrInstructionIdArrayType:4133 case IrInstructionIdArrayType:
4021 case IrInstructionIdSliceType:4134 case IrInstructionIdSliceType:
4022 return false;4135 return false;
4136 case IrInstructionIdAsm:
4137 {
4138 IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction;
4139 return asm_instruction->has_side_effects;
4140 }
4023 }4141 }
4024 zig_unreachable();4142 zig_unreachable();
4025}4143}
...@@ -7135,44 +7253,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7135,44 +7253,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7135// return return_type;7253// return return_type;
7136//}7254//}
7137//7255//
7138//static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7139// TypeTableEntry *expected_type, AstNode *node)
7140//{
7141// mark_impure_fn(g, context, node);
7142//
7143// node->data.asm_expr.return_count = 0;
7144// TypeTableEntry *return_type = g->builtin_types.entry_void;
7145// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
7146// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
7147// if (asm_output->return_type) {
7148// node->data.asm_expr.return_count += 1;
7149// return_type = analyze_type_expr(g, import, context, asm_output->return_type);
7150// if (node->data.asm_expr.return_count > 1) {
7151// add_node_error(g, node,
7152// buf_sprintf("inline assembly allows up to one output value"));
7153// break;
7154// }
7155// } else {
7156// Buf *variable_name = asm_output->variable_name;
7157// VariableTableEntry *var = find_variable(g, context, variable_name);
7158// if (var) {
7159// asm_output->variable = var;
7160// return var->type;
7161// } else {
7162// add_node_error(g, node,
7163// buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
7164// return g->builtin_types.entry_invalid;
7165// }
7166// }
7167// }
7168// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
7169// AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
7170// analyze_expression(g, import, context, nullptr, asm_input->expr);
7171// }
7172//
7173// return return_type;
7174//}
7175//
7176//static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,7256//static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
7177// BlockContext *context, AstNode *node, Buf *err_name)7257// BlockContext *context, AstNode *node, Buf *err_name)
7178//{7258//{
...@@ -7274,49 +7354,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7274,49 +7354,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7274// return var->type;7354// return var->type;
7275//}7355//}
7276//7356//
7277//static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,
7278// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
7279//{
7280// assert(node->type == NodeTypeNullLiteral);
7281//
7282// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
7283// const_val->ok = true;
7284//
7285// return g->builtin_types.entry_null;
7286//}
7287//
7288//static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7289// TypeTableEntry *expected_type, AstNode *node)
7290//{
7291// assert(node->type == NodeTypeUndefinedLiteral);
7292//
7293// Expr *expr = get_resolved_expr(node);
7294// ConstExprValue *const_val = &expr->const_val;
7295//
7296// const_val->ok = true;
7297// const_val->special = ConstValSpecialUndef;
7298//
7299// return expected_type ? expected_type : g->builtin_types.entry_undef;
7300//}
7301//
7302//static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7303// TypeTableEntry *expected_type, AstNode *node)
7304//{
7305// Expr *expr = get_resolved_expr(node);
7306// ConstExprValue *const_val = &expr->const_val;
7307//
7308// const_val->ok = true;
7309// const_val->special = ConstValSpecialZeroes;
7310//
7311// return expected_type ? expected_type : g->builtin_types.entry_undef;
7312//}
7313//
7314//static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,
7315// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
7316//{
7317// return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false);
7318//}
7319//
7320//static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,7357//static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7321// TypeTableEntry *expected_type, AstNode *node)7358// TypeTableEntry *expected_type, AstNode *node)
7322//{7359//{
...@@ -8656,111 +8693,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -8656,111 +8693,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
8656// }8693// }
8657//}8694//}
8658//8695//
8659//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
8660// assert(node->type == NodeTypeAsmExpr);
8661//
8662// AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
8663//
8664// Buf *src_template = asm_expr->asm_template;
8665//
8666// Buf llvm_template = BUF_INIT;
8667// buf_resize(&llvm_template, 0);
8668//
8669// for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) {
8670// AsmToken *asm_token = &asm_expr->token_list.at(token_i);
8671// switch (asm_token->id) {
8672// case AsmTokenIdTemplate:
8673// for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) {
8674// uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
8675// if (c == '$') {
8676// buf_append_str(&llvm_template, "$$");
8677// } else {
8678// buf_append_char(&llvm_template, c);
8679// }
8680// }
8681// break;
8682// case AsmTokenIdPercent:
8683// buf_append_char(&llvm_template, '%');
8684// break;
8685// case AsmTokenIdVar:
8686// size_t index = find_asm_index(g, node, asm_token);
8687// assert(index < SIZE_MAX);
8688// buf_appendf(&llvm_template, "$%zu", index);
8689// break;
8690// }
8691// }
8692//
8693// Buf constraint_buf = BUF_INIT;
8694// buf_resize(&constraint_buf, 0);
8695//
8696// assert(asm_expr->return_count == 0 || asm_expr->return_count == 1);
8697//
8698// size_t total_constraint_count = asm_expr->output_list.length +
8699// asm_expr->input_list.length +
8700// asm_expr->clobber_list.length;
8701// size_t input_and_output_count = asm_expr->output_list.length +
8702// asm_expr->input_list.length -
8703// asm_expr->return_count;
8704// size_t total_index = 0;
8705// size_t param_index = 0;
8706// LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
8707// LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
8708// for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
8709// AsmOutput *asm_output = asm_expr->output_list.at(i);
8710// bool is_return = (asm_output->return_type != nullptr);
8711// assert(*buf_ptr(asm_output->constraint) == '=');
8712// if (is_return) {
8713// buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
8714// } else {
8715// buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1);
8716// }
8717// if (total_index + 1 < total_constraint_count) {
8718// buf_append_char(&constraint_buf, ',');
8719// }
8720//
8721// if (!is_return) {
8722// VariableTableEntry *variable = asm_output->variable;
8723// assert(variable);
8724// param_types[param_index] = LLVMTypeOf(variable->value_ref);
8725// param_values[param_index] = variable->value_ref;
8726// param_index += 1;
8727// }
8728// }
8729// for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
8730// AsmInput *asm_input = asm_expr->input_list.at(i);
8731// buf_append_buf(&constraint_buf, asm_input->constraint);
8732// if (total_index + 1 < total_constraint_count) {
8733// buf_append_char(&constraint_buf, ',');
8734// }
8735//
8736// TypeTableEntry *expr_type = get_expr_type(asm_input->expr);
8737// param_types[param_index] = expr_type->type_ref;
8738// param_values[param_index] = gen_expr(g, asm_input->expr);
8739// }
8740// for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
8741// Buf *clobber_buf = asm_expr->clobber_list.at(i);
8742// buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf));
8743// if (total_index + 1 < total_constraint_count) {
8744// buf_append_char(&constraint_buf, ',');
8745// }
8746// }
8747//
8748// LLVMTypeRef ret_type;
8749// if (asm_expr->return_count == 0) {
8750// ret_type = LLVMVoidType();
8751// } else {
8752// ret_type = get_expr_type(node)->type_ref;
8753// }
8754// LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
8755//
8756// bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
8757// LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
8758// buf_ptr(&constraint_buf), is_volatile, false);
8759//
8760// set_debug_source_node(g, node);
8761// return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
8762//}
8763//
8764//static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {8696//static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
8765// assert(node->type == NodeTypeContainerInitExpr);8697// assert(node->type == NodeTypeContainerInitExpr);
8766//8698//
...@@ -9404,35 +9336,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -9404,35 +9336,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9404// return result;9336// return result;
9405//}9337//}
9406//9338//
9407//static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
9408// const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
9409// size_t len = tok->end - tok->start - 2;
9410// size_t result = 0;
9411// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
9412// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
9413// if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) {
9414// return result;
9415// }
9416// }
9417// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
9418// AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
9419// if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) {
9420// return result;
9421// }
9422// }
9423// return SIZE_MAX;
9424//}
9425//
9426//static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
9427// assert(node->type == NodeTypeSymbol);
9428// VariableTableEntry *variable = get_resolved_expr(node)->variable;
9429// if (variable) {
9430// return gen_variable(g, node, variable);
9431// }
9432//
9433// zig_unreachable();
9434//}
9435//
9436//static LLVMValueRef gen_label(CodeGen *g, AstNode *node) {9339//static LLVMValueRef gen_label(CodeGen *g, AstNode *node) {
9437// assert(node->type == NodeTypeLabel);9340// assert(node->type == NodeTypeLabel);
9438//9341//
...@@ -9447,13 +9350,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -9447,13 +9350,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9447// LLVMPositionBuilderAtEnd(g->builder, basic_block);9350// LLVMPositionBuilderAtEnd(g->builder, basic_block);
9448// return nullptr;9351// return nullptr;
9449//}9352//}
9450//
9451//static LLVMValueRef gen_variable(CodeGen *g, AstNode *source_node, VariableTableEntry *variable) {
9452// if (!type_has_bits(variable->type)) {
9453// return nullptr;
9454// } else {
9455// assert(variable->value_ref);
9456// return get_handle_value(g, variable->value_ref, variable->type);
9457// }
9458//}
9459//
src/ir_print.cpp+45
...@@ -420,6 +420,48 @@ static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instructio...@@ -420,6 +420,48 @@ static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instructio
420 ir_print_other_instruction(irp, instruction->child_type);420 ir_print_other_instruction(irp, instruction->child_type);
421}421}
422422
423static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {
424 assert(instruction->base.source_node->type == NodeTypeAsmExpr);
425 AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr;
426 const char *volatile_kw = instruction->has_side_effects ? " volatile" : "";
427 fprintf(irp->f, "asm%s (\"%s\") : ", volatile_kw, buf_ptr(asm_expr->asm_template));
428
429 for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
430 AsmOutput *asm_output = asm_expr->output_list.at(i);
431 if (i != 0) fprintf(irp->f, ", ");
432
433 fprintf(irp->f, "[%s] \"%s\" (",
434 buf_ptr(asm_output->asm_symbolic_name),
435 buf_ptr(asm_output->constraint));
436 if (asm_output->return_type) {
437 fprintf(irp->f, "-> ");
438 ir_print_other_instruction(irp, instruction->output_types[i]);
439 } else {
440 fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name));
441 }
442 fprintf(irp->f, ")");
443 }
444
445 fprintf(irp->f, " : ");
446 for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
447 AsmInput *asm_input = asm_expr->input_list.at(i);
448
449 if (i != 0) fprintf(irp->f, ", ");
450 fprintf(irp->f, "[%s] \"%s\" (",
451 buf_ptr(asm_input->asm_symbolic_name),
452 buf_ptr(asm_input->constraint));
453 ir_print_other_instruction(irp, instruction->input_list[i]);
454 fprintf(irp->f, ")");
455 }
456 fprintf(irp->f, " : ");
457 for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) {
458 Buf *reg_name = asm_expr->clobber_list.at(i);
459 if (i != 0) fprintf(irp->f, ", ");
460 fprintf(irp->f, "\"%s\"", buf_ptr(reg_name));
461 }
462 fprintf(irp->f, ")");
463}
464
423static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {465static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
424 ir_print_prefix(irp, instruction);466 ir_print_prefix(irp, instruction);
425 switch (instruction->id) {467 switch (instruction->id) {
...@@ -503,6 +545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -503,6 +545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
503 case IrInstructionIdSliceType:545 case IrInstructionIdSliceType:
504 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);546 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
505 break;547 break;
548 case IrInstructionIdAsm:
549 ir_print_asm(irp, (IrInstructionAsm *)instruction);
550 break;
506 case IrInstructionIdSwitchBr:551 case IrInstructionIdSwitchBr:
507 zig_panic("TODO print more IR instructions");552 zig_panic("TODO print more IR instructions");
508 }553 }