| author | |
| committer | |
| log | a292eb8d64da4383f2d4637f231d338ed9c680e0 |
| tree | 1a368a2cc65675b793651a8da83b6cd12b8a4bca |
| parent | 66ca916805efee6b35b8dd6104fb1da50dd1dc8b |
6 files changed, 64 insertions(+), 27 deletions(-)
doc/langref.md+1-1| ... | ... | @@ -84,7 +84,7 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput) |
| 84 | 84 | |
| 85 | 85 | AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers) |
| 86 | 86 | |
| 87 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) token(Symbol) token(RParen) | |
| 87 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Return) Type) token(RParen) | |
| 88 | 88 | |
| 89 | 89 | AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen) |
| 90 | 90 |
src/analyze.cpp+13-2| ... | ... | @@ -1233,16 +1233,27 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1233 | 1233 | } |
| 1234 | 1234 | case NodeTypeAsmExpr: |
| 1235 | 1235 | { |
| 1236 | node->data.asm_expr.return_count = 0; | |
| 1237 | return_type = g->builtin_types.entry_void; | |
| 1236 | 1238 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| 1237 | 1239 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); |
| 1238 | analyze_variable_name(g, import, context, node, &asm_output->variable_name); | |
| 1240 | if (asm_output->return_type) { | |
| 1241 | node->data.asm_expr.return_count += 1; | |
| 1242 | return_type = resolve_type(g, asm_output->return_type); | |
| 1243 | if (node->data.asm_expr.return_count > 1) { | |
| 1244 | add_node_error(g, node, | |
| 1245 | buf_sprintf("inline assembly allows up to one output value")); | |
| 1246 | break; | |
| 1247 | } | |
| 1248 | } else { | |
| 1249 | analyze_variable_name(g, import, context, node, &asm_output->variable_name); | |
| 1250 | } | |
| 1239 | 1251 | } |
| 1240 | 1252 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { |
| 1241 | 1253 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); |
| 1242 | 1254 | analyze_expression(g, import, context, nullptr, asm_input->expr); |
| 1243 | 1255 | } |
| 1244 | 1256 | |
| 1245 | return_type = g->builtin_types.entry_void; | |
| 1246 | 1257 | break; |
| 1247 | 1258 | } |
| 1248 | 1259 | case NodeTypeBinOpExpr: |
src/codegen.cpp+30-12| ... | ... | @@ -790,33 +790,45 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { |
| 790 | 790 | |
| 791 | 791 | Buf constraint_buf = BUF_INIT; |
| 792 | 792 | buf_resize(&constraint_buf, 0); |
| 793 | ||
| 794 | assert(asm_expr->return_count == 0 || asm_expr->return_count == 1); | |
| 795 | ||
| 793 | 796 | int total_constraint_count = asm_expr->output_list.length + |
| 794 | 797 | asm_expr->input_list.length + |
| 795 | 798 | asm_expr->clobber_list.length; |
| 796 | 799 | int input_and_output_count = asm_expr->output_list.length + |
| 797 | asm_expr->input_list.length; | |
| 800 | asm_expr->input_list.length - | |
| 801 | asm_expr->return_count; | |
| 798 | 802 | int total_index = 0; |
| 803 | int param_index = 0; | |
| 799 | 804 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count); |
| 800 | 805 | LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count); |
| 801 | 806 | for (int i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) { |
| 802 | 807 | AsmOutput *asm_output = asm_expr->output_list.at(i); |
| 808 | bool is_return = false; | |
| 803 | 809 | if (buf_eql_str(&asm_output->constraint, "=m")) { |
| 804 | 810 | buf_append_str(&constraint_buf, "=*m"); |
| 811 | } else if (buf_eql_str(&asm_output->constraint, "=r")) { | |
| 812 | buf_append_str(&constraint_buf, "=r"); | |
| 813 | is_return = true; | |
| 805 | 814 | } else { |
| 806 | zig_panic("TODO unable to handle anything other than '=m' for outputs"); | |
| 815 | zig_panic("TODO unable to handle anything other than '=m' and '=r' for outputs"); | |
| 807 | 816 | } |
| 808 | 817 | if (total_index + 1 < total_constraint_count) { |
| 809 | 818 | buf_append_char(&constraint_buf, ','); |
| 810 | 819 | } |
| 811 | 820 | |
| 812 | VariableTableEntry *variable = find_variable( | |
| 813 | node->codegen_node->expr_node.block_context, | |
| 814 | &asm_output->variable_name); | |
| 815 | assert(variable); | |
| 816 | param_types[total_index] = LLVMTypeOf(variable->value_ref); | |
| 817 | param_values[total_index] = variable->value_ref; | |
| 821 | if (!is_return) { | |
| 822 | VariableTableEntry *variable = find_variable( | |
| 823 | node->codegen_node->expr_node.block_context, | |
| 824 | &asm_output->variable_name); | |
| 825 | assert(variable); | |
| 826 | param_types[param_index] = LLVMTypeOf(variable->value_ref); | |
| 827 | param_values[param_index] = variable->value_ref; | |
| 828 | param_index += 1; | |
| 829 | } | |
| 818 | 830 | } |
| 819 | for (int i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1) { | |
| 831 | for (int i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { | |
| 820 | 832 | AsmInput *asm_input = asm_expr->input_list.at(i); |
| 821 | 833 | buf_append_buf(&constraint_buf, &asm_input->constraint); |
| 822 | 834 | if (total_index + 1 < total_constraint_count) { |
| ... | ... | @@ -824,8 +836,8 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { |
| 824 | 836 | } |
| 825 | 837 | |
| 826 | 838 | TypeTableEntry *expr_type = get_expr_type(asm_input->expr); |
| 827 | param_types[total_index] = expr_type->type_ref; | |
| 828 | param_values[total_index] = gen_expr(g, asm_input->expr); | |
| 839 | param_types[param_index] = expr_type->type_ref; | |
| 840 | param_values[param_index] = gen_expr(g, asm_input->expr); | |
| 829 | 841 | } |
| 830 | 842 | for (int i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { |
| 831 | 843 | Buf *clobber_buf = asm_expr->clobber_list.at(i); |
| ... | ... | @@ -835,7 +847,13 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { |
| 835 | 847 | } |
| 836 | 848 | } |
| 837 | 849 | |
| 838 | LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), param_types, input_and_output_count, false); | |
| 850 | LLVMTypeRef ret_type; | |
| 851 | if (asm_expr->return_count == 0) { | |
| 852 | ret_type = LLVMVoidType(); | |
| 853 | } else { | |
| 854 | ret_type = get_expr_type(node)->type_ref; | |
| 855 | } | |
| 856 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false); | |
| 839 | 857 | |
| 840 | 858 | bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0); |
| 841 | 859 | LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), |
src/parser.cpp+14-4| ... | ... | @@ -1731,7 +1731,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode |
| 1731 | 1731 | } |
| 1732 | 1732 | |
| 1733 | 1733 | /* |
| 1734 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) token(Symbol) token(RParen) | |
| 1734 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Return) Type) token(RParen) | |
| 1735 | 1735 | */ |
| 1736 | 1736 | static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) { |
| 1737 | 1737 | ast_eat_token(pc, token_index, TokenIdLBracket); |
| ... | ... | @@ -1740,14 +1740,24 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod |
| 1740 | 1740 | |
| 1741 | 1741 | Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral); |
| 1742 | 1742 | |
| 1743 | AsmOutput *asm_output = allocate<AsmOutput>(1); | |
| 1744 | ||
| 1743 | 1745 | ast_eat_token(pc, token_index, TokenIdLParen); |
| 1744 | Token *out_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 1746 | ||
| 1747 | Token *token = &pc->tokens->at(*token_index); | |
| 1748 | *token_index += 1; | |
| 1749 | if (token->id == TokenIdSymbol) { | |
| 1750 | ast_buf_from_token(pc, token, &asm_output->variable_name); | |
| 1751 | } else if (token->id == TokenIdKeywordReturn) { | |
| 1752 | asm_output->return_type = ast_parse_type(pc, token_index); | |
| 1753 | } else { | |
| 1754 | ast_invalid_token_error(pc, token); | |
| 1755 | } | |
| 1756 | ||
| 1745 | 1757 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 1746 | 1758 | |
| 1747 | AsmOutput *asm_output = allocate<AsmOutput>(1); | |
| 1748 | 1759 | ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name); |
| 1749 | 1760 | parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr); |
| 1750 | ast_buf_from_token(pc, out_symbol, &asm_output->variable_name); | |
| 1751 | 1761 | node->data.asm_expr.output_list.append(asm_output); |
| 1752 | 1762 | } |
| 1753 | 1763 |
src/parser.hpp+2| ... | ... | @@ -228,6 +228,7 @@ struct AsmOutput { |
| 228 | 228 | Buf asm_symbolic_name; |
| 229 | 229 | Buf constraint; |
| 230 | 230 | Buf variable_name; |
| 231 | AstNode *return_type; // null unless "=r" and return | |
| 231 | 232 | }; |
| 232 | 233 | |
| 233 | 234 | struct AsmInput { |
| ... | ... | @@ -249,6 +250,7 @@ struct AstNodeAsmExpr { |
| 249 | 250 | ZigList<AsmOutput*> output_list; |
| 250 | 251 | ZigList<AsmInput*> input_list; |
| 251 | 252 | ZigList<Buf*> clobber_list; |
| 253 | int return_count; // populated by analyze | |
| 252 | 254 | }; |
| 253 | 255 | |
| 254 | 256 | struct AstNodeStructDecl { |
std/std.zig+4-8| ... | ... | @@ -3,20 +3,17 @@ const SYS_exit : isize = 60; |
| 3 | 3 | const stdout_fileno : isize = 1; |
| 4 | 4 | |
| 5 | 5 | fn syscall1(number: isize, arg1: isize) -> isize { |
| 6 | var result : isize; | |
| 7 | 6 | asm volatile (" |
| 8 | 7 | mov %[number], %%rax |
| 9 | 8 | mov %[arg1], %%rdi |
| 10 | 9 | syscall |
| 11 | 10 | mov %%rax, %[ret]" |
| 12 | : [ret] "=m" (result) | |
| 11 | : [ret] "=r" (return isize) | |
| 13 | 12 | : [number] "r" (number), [arg1] "r" (arg1) |
| 14 | : "rcx", "r11", "rax", "rdi"); | |
| 15 | return result; | |
| 13 | : "rcx", "r11", "rax", "rdi") | |
| 16 | 14 | } |
| 17 | 15 | |
| 18 | 16 | fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 19 | var result : isize; | |
| 20 | 17 | asm volatile (" |
| 21 | 18 | mov %[number], %%rax |
| 22 | 19 | mov %[arg1], %%rdi |
| ... | ... | @@ -24,10 +21,9 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 24 | 21 | mov %[arg3], %%rdx |
| 25 | 22 | syscall |
| 26 | 23 | mov %%rax, %[ret]" |
| 27 | : [ret] "=m" (result) | |
| 24 | : [ret] "=r" (return isize) | |
| 28 | 25 | : [number] "r" (number), [arg1] "r" (arg1), [arg2] "r" (arg2), [arg3] "r" (arg3) |
| 29 | : "rcx", "r11", "rax", "rdi", "rsi", "rdx"); | |
| 30 | return result; | |
| 26 | : "rcx", "r11", "rax", "rdi", "rsi", "rdx") | |
| 31 | 27 | } |
| 32 | 28 | |
| 33 | 29 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { |