authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 00:46:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 00:46:56-07:00
loga292eb8d64da4383f2d4637f231d338ed9c680e0
tree1a368a2cc65675b793651a8da83b6cd12b8a4bca
parent66ca916805efee6b35b8dd6104fb1da50dd1dc8b

support inline assembly expressions with return type


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,7 +84,7 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
8484
85AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)85AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
8686
87AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) token(Symbol) token(RParen)87AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Return) Type) token(RParen)
8888
89AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)89AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
9090
src/analyze.cpp+13-2
...@@ -1233,16 +1233,27 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1233,16 +1233,27 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1233 }1233 }
1234 case NodeTypeAsmExpr:1234 case NodeTypeAsmExpr:
1235 {1235 {
1236 node->data.asm_expr.return_count = 0;
1237 return_type = g->builtin_types.entry_void;
1236 for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {1238 for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
1237 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);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 for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {1252 for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
1241 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);1253 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
1242 analyze_expression(g, import, context, nullptr, asm_input->expr);1254 analyze_expression(g, import, context, nullptr, asm_input->expr);
1243 }1255 }
12441256
1245 return_type = g->builtin_types.entry_void;
1246 break;1257 break;
1247 }1258 }
1248 case NodeTypeBinOpExpr:1259 case NodeTypeBinOpExpr:
src/codegen.cpp+30-12
...@@ -790,33 +790,45 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {...@@ -790,33 +790,45 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
790790
791 Buf constraint_buf = BUF_INIT;791 Buf constraint_buf = BUF_INIT;
792 buf_resize(&constraint_buf, 0);792 buf_resize(&constraint_buf, 0);
793
794 assert(asm_expr->return_count == 0 || asm_expr->return_count == 1);
795
793 int total_constraint_count = asm_expr->output_list.length +796 int total_constraint_count = asm_expr->output_list.length +
794 asm_expr->input_list.length +797 asm_expr->input_list.length +
795 asm_expr->clobber_list.length;798 asm_expr->clobber_list.length;
796 int input_and_output_count = asm_expr->output_list.length +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 int total_index = 0;802 int total_index = 0;
803 int param_index = 0;
799 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);804 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
800 LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);805 LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
801 for (int i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {806 for (int i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
802 AsmOutput *asm_output = asm_expr->output_list.at(i);807 AsmOutput *asm_output = asm_expr->output_list.at(i);
808 bool is_return = false;
803 if (buf_eql_str(&asm_output->constraint, "=m")) {809 if (buf_eql_str(&asm_output->constraint, "=m")) {
804 buf_append_str(&constraint_buf, "=*m");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 } else {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 if (total_index + 1 < total_constraint_count) {817 if (total_index + 1 < total_constraint_count) {
809 buf_append_char(&constraint_buf, ',');818 buf_append_char(&constraint_buf, ',');
810 }819 }
811820
812 VariableTableEntry *variable = find_variable(821 if (!is_return) {
813 node->codegen_node->expr_node.block_context,822 VariableTableEntry *variable = find_variable(
814 &asm_output->variable_name);823 node->codegen_node->expr_node.block_context,
815 assert(variable);824 &asm_output->variable_name);
816 param_types[total_index] = LLVMTypeOf(variable->value_ref);825 assert(variable);
817 param_values[total_index] = variable->value_ref;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 AsmInput *asm_input = asm_expr->input_list.at(i);832 AsmInput *asm_input = asm_expr->input_list.at(i);
821 buf_append_buf(&constraint_buf, &asm_input->constraint);833 buf_append_buf(&constraint_buf, &asm_input->constraint);
822 if (total_index + 1 < total_constraint_count) {834 if (total_index + 1 < total_constraint_count) {
...@@ -824,8 +836,8 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {...@@ -824,8 +836,8 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
824 }836 }
825837
826 TypeTableEntry *expr_type = get_expr_type(asm_input->expr);838 TypeTableEntry *expr_type = get_expr_type(asm_input->expr);
827 param_types[total_index] = expr_type->type_ref;839 param_types[param_index] = expr_type->type_ref;
828 param_values[total_index] = gen_expr(g, asm_input->expr);840 param_values[param_index] = gen_expr(g, asm_input->expr);
829 }841 }
830 for (int i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {842 for (int i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
831 Buf *clobber_buf = asm_expr->clobber_list.at(i);843 Buf *clobber_buf = asm_expr->clobber_list.at(i);
...@@ -835,7 +847,13 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {...@@ -835,7 +847,13 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
835 }847 }
836 }848 }
837849
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);
839857
840 bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);858 bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
841 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),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,7 +1731,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
1731}1731}
17321732
1733/*1733/*
1734AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) token(Symbol) token(RParen)1734AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Return) Type) token(RParen)
1735*/1735*/
1736static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {1736static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
1737 ast_eat_token(pc, token_index, TokenIdLBracket);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,14 +1740,24 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
17401740
1741 Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);1741 Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
17421742
1743 AsmOutput *asm_output = allocate<AsmOutput>(1);
1744
1743 ast_eat_token(pc, token_index, TokenIdLParen);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 ast_eat_token(pc, token_index, TokenIdRParen);1757 ast_eat_token(pc, token_index, TokenIdRParen);
17461758
1747 AsmOutput *asm_output = allocate<AsmOutput>(1);
1748 ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);1759 ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
1749 parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);1760 parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);
1750 ast_buf_from_token(pc, out_symbol, &asm_output->variable_name);
1751 node->data.asm_expr.output_list.append(asm_output);1761 node->data.asm_expr.output_list.append(asm_output);
1752}1762}
17531763
src/parser.hpp+2
...@@ -228,6 +228,7 @@ struct AsmOutput {...@@ -228,6 +228,7 @@ struct AsmOutput {
228 Buf asm_symbolic_name;228 Buf asm_symbolic_name;
229 Buf constraint;229 Buf constraint;
230 Buf variable_name;230 Buf variable_name;
231 AstNode *return_type; // null unless "=r" and return
231};232};
232233
233struct AsmInput {234struct AsmInput {
...@@ -249,6 +250,7 @@ struct AstNodeAsmExpr {...@@ -249,6 +250,7 @@ struct AstNodeAsmExpr {
249 ZigList<AsmOutput*> output_list;250 ZigList<AsmOutput*> output_list;
250 ZigList<AsmInput*> input_list;251 ZigList<AsmInput*> input_list;
251 ZigList<Buf*> clobber_list;252 ZigList<Buf*> clobber_list;
253 int return_count; // populated by analyze
252};254};
253255
254struct AstNodeStructDecl {256struct AstNodeStructDecl {
std/std.zig+4-8
...@@ -3,20 +3,17 @@ const SYS_exit : isize = 60;...@@ -3,20 +3,17 @@ const SYS_exit : isize = 60;
3const stdout_fileno : isize = 1;3const stdout_fileno : isize = 1;
44
5fn syscall1(number: isize, arg1: isize) -> isize {5fn syscall1(number: isize, arg1: isize) -> isize {
6 var result : isize;
7 asm volatile ("6 asm volatile ("
8 mov %[number], %%rax7 mov %[number], %%rax
9 mov %[arg1], %%rdi8 mov %[arg1], %%rdi
10 syscall9 syscall
11 mov %%rax, %[ret]"10 mov %%rax, %[ret]"
12 : [ret] "=m" (result)11 : [ret] "=r" (return isize)
13 : [number] "r" (number), [arg1] "r" (arg1)12 : [number] "r" (number), [arg1] "r" (arg1)
14 : "rcx", "r11", "rax", "rdi");13 : "rcx", "r11", "rax", "rdi")
15 return result;
16}14}
1715
18fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {16fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
19 var result : isize;
20 asm volatile ("17 asm volatile ("
21 mov %[number], %%rax18 mov %[number], %%rax
22 mov %[arg1], %%rdi19 mov %[arg1], %%rdi
...@@ -24,10 +21,9 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {...@@ -24,10 +21,9 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
24 mov %[arg3], %%rdx21 mov %[arg3], %%rdx
25 syscall22 syscall
26 mov %%rax, %[ret]"23 mov %%rax, %[ret]"
27 : [ret] "=m" (result)24 : [ret] "=r" (return isize)
28 : [number] "r" (number), [arg1] "r" (arg1), [arg2] "r" (arg2), [arg3] "r" (arg3)25 : [number] "r" (number), [arg1] "r" (arg1), [arg2] "r" (arg2), [arg3] "r" (arg3)
29 : "rcx", "r11", "rax", "rdi", "rsi", "rdx");26 : "rcx", "r11", "rax", "rdi", "rsi", "rdx")
30 return result;
31}27}
3228
33pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {29pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {