Commit ed31ae8867

Andrew Kelley <superjoe30@gmail.com>
2016-11-18 08:07:40
IR: inline assembly working
1 parent c3b603f
Changed files (2)
src/codegen.cpp
@@ -1544,133 +1544,129 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
     return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, "");
 }
 
+static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
+    const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
+    size_t len = tok->end - tok->start - 2;
+    size_t result = 0;
+    for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
+        AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
+        if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) {
+            return result;
+        }
+    }
+    for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
+        AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
+        if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) {
+            return result;
+        }
+    }
+    return SIZE_MAX;
+}
+
 static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstructionAsm *instruction) {
-    zig_panic("TODO render asm");
-}
-//static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
-//    const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
-//    size_t len = tok->end - tok->start - 2;
-//    size_t result = 0;
-//    for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
-//        AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
-//        if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) {
-//            return result;
-//        }
-//    }
-//    for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
-//        AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
-//        if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) {
-//            return result;
-//        }
-//    }
-//    return SIZE_MAX;
-//}
-//
-//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
-//    assert(node->type == NodeTypeAsmExpr);
-//
-//    AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
-//
-//    Buf *src_template = asm_expr->asm_template;
-//
-//    Buf llvm_template = BUF_INIT;
-//    buf_resize(&llvm_template, 0);
-//
-//    for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) {
-//        AsmToken *asm_token = &asm_expr->token_list.at(token_i);
-//        switch (asm_token->id) {
-//            case AsmTokenIdTemplate:
-//                for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) {
-//                    uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
-//                    if (c == '$') {
-//                        buf_append_str(&llvm_template, "$$");
-//                    } else {
-//                        buf_append_char(&llvm_template, c);
-//                    }
-//                }
-//                break;
-//            case AsmTokenIdPercent:
-//                buf_append_char(&llvm_template, '%');
-//                break;
-//            case AsmTokenIdVar:
-//                size_t index = find_asm_index(g, node, asm_token);
-//                assert(index < SIZE_MAX);
-//                buf_appendf(&llvm_template, "$%zu", index);
-//                break;
-//        }
-//    }
-//
-//    Buf constraint_buf = BUF_INIT;
-//    buf_resize(&constraint_buf, 0);
-//
-//    assert(asm_expr->return_count == 0 || asm_expr->return_count == 1);
-//
-//    size_t total_constraint_count = asm_expr->output_list.length +
-//                                 asm_expr->input_list.length +
-//                                 asm_expr->clobber_list.length;
-//    size_t input_and_output_count = asm_expr->output_list.length +
-//                                 asm_expr->input_list.length -
-//                                 asm_expr->return_count;
-//    size_t total_index = 0;
-//    size_t param_index = 0;
-//    LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
-//    LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
-//    for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
-//        AsmOutput *asm_output = asm_expr->output_list.at(i);
-//        bool is_return = (asm_output->return_type != nullptr);
-//        assert(*buf_ptr(asm_output->constraint) == '=');
-//        if (is_return) {
-//            buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
-//        } else {
-//            buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1);
-//        }
-//        if (total_index + 1 < total_constraint_count) {
-//            buf_append_char(&constraint_buf, ',');
-//        }
-//
-//        if (!is_return) {
-//            VariableTableEntry *variable = asm_output->variable;
-//            assert(variable);
-//            param_types[param_index] = LLVMTypeOf(variable->value_ref);
-//            param_values[param_index] = variable->value_ref;
-//            param_index += 1;
-//        }
-//    }
-//    for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
-//        AsmInput *asm_input = asm_expr->input_list.at(i);
-//        buf_append_buf(&constraint_buf, asm_input->constraint);
-//        if (total_index + 1 < total_constraint_count) {
-//            buf_append_char(&constraint_buf, ',');
-//        }
-//
-//        TypeTableEntry *expr_type = get_expr_type(asm_input->expr);
-//        param_types[param_index] = expr_type->type_ref;
-//        param_values[param_index] = gen_expr(g, asm_input->expr);
-//    }
-//    for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
-//        Buf *clobber_buf = asm_expr->clobber_list.at(i);
-//        buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf));
-//        if (total_index + 1 < total_constraint_count) {
-//            buf_append_char(&constraint_buf, ',');
-//        }
-//    }
-//
-//    LLVMTypeRef ret_type;
-//    if (asm_expr->return_count == 0) {
-//        ret_type = LLVMVoidType();
-//    } else {
-//        ret_type = get_expr_type(node)->type_ref;
-//    }
-//    LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
-//
-//    bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
-//    LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
-//            buf_ptr(&constraint_buf), is_volatile, false);
-//
-//    set_debug_source_node(g, node);
-//    return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
-//}
-//
+    AstNode *asm_node = instruction->base.source_node;
+    assert(asm_node->type == NodeTypeAsmExpr);
+    AstNodeAsmExpr *asm_expr = &asm_node->data.asm_expr;
+
+    Buf *src_template = asm_expr->asm_template;
+
+    Buf llvm_template = BUF_INIT;
+    buf_resize(&llvm_template, 0);
+
+    for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) {
+        AsmToken *asm_token = &asm_expr->token_list.at(token_i);
+        switch (asm_token->id) {
+            case AsmTokenIdTemplate:
+                for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) {
+                    uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
+                    if (c == '$') {
+                        buf_append_str(&llvm_template, "$$");
+                    } else {
+                        buf_append_char(&llvm_template, c);
+                    }
+                }
+                break;
+            case AsmTokenIdPercent:
+                buf_append_char(&llvm_template, '%');
+                break;
+            case AsmTokenIdVar:
+                size_t index = find_asm_index(g, asm_node, asm_token);
+                assert(index < SIZE_MAX);
+                buf_appendf(&llvm_template, "$%zu", index);
+                break;
+        }
+    }
+
+    Buf constraint_buf = BUF_INIT;
+    buf_resize(&constraint_buf, 0);
+
+    assert(instruction->return_count == 0 || instruction->return_count == 1);
+
+    size_t total_constraint_count = asm_expr->output_list.length +
+                                 asm_expr->input_list.length +
+                                 asm_expr->clobber_list.length;
+    size_t input_and_output_count = asm_expr->output_list.length +
+                                 asm_expr->input_list.length -
+                                 instruction->return_count;
+    size_t total_index = 0;
+    size_t param_index = 0;
+    LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
+    LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
+    for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
+        AsmOutput *asm_output = asm_expr->output_list.at(i);
+        bool is_return = (asm_output->return_type != nullptr);
+        assert(*buf_ptr(asm_output->constraint) == '=');
+        if (is_return) {
+            buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
+        } else {
+            buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1);
+        }
+        if (total_index + 1 < total_constraint_count) {
+            buf_append_char(&constraint_buf, ',');
+        }
+
+        if (!is_return) {
+            VariableTableEntry *variable = asm_output->variable;
+            assert(variable);
+            param_types[param_index] = LLVMTypeOf(variable->value_ref);
+            param_values[param_index] = variable->value_ref;
+            param_index += 1;
+        }
+    }
+    for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
+        AsmInput *asm_input = asm_expr->input_list.at(i);
+        IrInstruction *ir_input = instruction->input_list[i];
+        buf_append_buf(&constraint_buf, asm_input->constraint);
+        if (total_index + 1 < total_constraint_count) {
+            buf_append_char(&constraint_buf, ',');
+        }
+
+        param_types[param_index] = ir_input->type_entry->type_ref;
+        param_values[param_index] = ir_llvm_value(g, ir_input);
+    }
+    for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
+        Buf *clobber_buf = asm_expr->clobber_list.at(i);
+        buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf));
+        if (total_index + 1 < total_constraint_count) {
+            buf_append_char(&constraint_buf, ',');
+        }
+    }
+
+    LLVMTypeRef ret_type;
+    if (instruction->return_count == 0) {
+        ret_type = LLVMVoidType();
+    } else {
+        ret_type = instruction->base.type_entry->type_ref;
+    }
+    LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
+
+    bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
+    LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
+            buf_ptr(&constraint_buf), is_volatile, false);
+
+    set_debug_source_node(g, asm_node);
+    return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
+}
 
 
 
@@ -3307,7 +3303,7 @@ void codegen_generate_h_file(CodeGen *g) {
             continue;
 
         Buf return_type_c = BUF_INIT;
-        get_c_type_node(g, fn_proto->return_type, &return_type_c);
+        get_c_type(g, fn_table_entry->type_entry->data.fn.fn_type_id.return_type, &return_type_c);
 
         buf_appendf(&h_buf, "%s %s %s(",
                 buf_ptr(export_macro),
src/ir.cpp
@@ -4095,18 +4095,28 @@ static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionA
 
     AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr;
 
+    IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);
+    IrInstruction **output_types = allocate<IrInstruction *>(asm_expr->output_list.length);
+
     TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void;
     for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
         AsmOutput *asm_output = asm_expr->output_list.at(i);
         if (asm_output->return_type) {
-            return_type = ir_resolve_type(ira, asm_instruction->output_types[i]);
+            output_types[i] = asm_instruction->output_types[i]->other;
+            return_type = ir_resolve_type(ira, output_types[i]);
             if (return_type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
         }
     }
 
-    ir_build_asm_from(&ira->new_irb, &asm_instruction->base, asm_instruction->input_list,
-            asm_instruction->output_types, asm_instruction->return_count, asm_instruction->has_side_effects);
+    for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
+        input_list[i] = asm_instruction->input_list[i]->other;
+        if (input_list[i]->type_entry->id == TypeTableEntryIdInvalid)
+            return ira->codegen->builtin_types.entry_invalid;
+    }
+
+    ir_build_asm_from(&ira->new_irb, &asm_instruction->base, input_list, output_types,
+            asm_instruction->return_count, asm_instruction->has_side_effects);
     return return_type;
 }