LLVMValueRef gen_tuple(compile_t* c, ast_t* ast) { ast_t* child = ast_child(ast); if(ast_sibling(child) == NULL) return gen_expr(c, child); deferred_reification_t* reify = c->frame->reify; ast_t* type = deferred_reify(reify, ast_type(ast), c->opt); // If we contain '_', we have no usable value. if(contains_dontcare(type)) { ast_free_unattached(type); return GEN_NOTNEEDED; } reach_type_t* t = reach_type(c->reach, type); compile_type_t* c_t = (compile_type_t*)t->c_type; int count = LLVMCountStructElementTypes(c_t->primitive); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetStructElementTypes(c_t->primitive, elements); LLVMValueRef tuple = LLVMGetUndef(c_t->primitive); int i = 0; while(child != NULL) { LLVMValueRef value = gen_expr(c, child); if(value == NULL) { ponyint_pool_free_size(buf_size, elements); return NULL; } // We'll have an undefined element if one of our source elements is a // variable declaration. This is ok, since the tuple value will never be // used. if(value == GEN_NOVALUE || value == GEN_NOTNEEDED) { ponyint_pool_free_size(buf_size, elements); return value; } ast_t* child_type = deferred_reify(reify, ast_type(child), c->opt); value = gen_assign_cast(c, elements[i], value, child_type); ast_free_unattached(child_type); tuple = LLVMBuildInsertValue(c->builder, tuple, value, i++, ""); child = ast_sibling(child); } ponyint_pool_free_size(buf_size, elements); return tuple; }
LLVMValueRef gen_float(compile_t* c, ast_t* ast) { ast_t* type = deferred_reify(c->frame->reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; return LLVMConstReal(c_t->primitive, ast_float(ast)); }
LLVMValueRef gen_digestof(compile_t* c, ast_t* ast) { ast_t* expr = ast_child(ast); LLVMValueRef value = gen_expr(c, expr); ast_t* type = deferred_reify(c->frame->reify, ast_type(expr), c->opt); LLVMValueRef ret = gen_digestof_value(c, type, value); ast_free_unattached(type); return ret; }
LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); const char* name = ast_name(id); // If this local has already been generated, don't create another copy. This // can happen when the same ast node is generated more than once, such as // the condition block of a while expression. LLVMValueRef value = codegen_getlocal(c, name); if(value != NULL) return GEN_NOVALUE; ast_t* type = deferred_reify(c->frame->reify, ast_type(id), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; // All alloca should happen in the entry block of a function. LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef inst = LLVMGetFirstInstruction(entry_block); if(inst != NULL) LLVMPositionBuilderBefore(c->builder, inst); else LLVMPositionBuilderAtEnd(c->builder, entry_block); LLVMValueRef alloc = LLVMBuildAlloca(c->builder, c_t->mem_type, name); // Store the alloca to use when we reference this local. codegen_setlocal(c, name, alloc); LLVMMetadataRef file = codegen_difile(c); LLVMMetadataRef scope = codegen_discope(c); #if PONY_LLVM >= 700 uint32_t align_bytes = LLVMABIAlignmentOfType(c->target_data, c_t->mem_type); LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name, strlen(name), file, (unsigned)ast_line(ast), c_t->di_type, true, LLVMDIFlagZero, align_bytes * 8); #else LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name, file, (unsigned)ast_line(ast), c_t->di_type); #endif LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0); LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr, (unsigned)ast_line(ast), (unsigned)ast_pos(ast), scope, LLVMGetInsertBlock(c->builder)); // Put the builder back where it was. LLVMPositionBuilderAtEnd(c->builder, this_block); return GEN_NOTNEEDED; }
LLVMValueRef gen_tupleelemptr(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); LLVMValueRef l_value = gen_expr(c, left); if(l_value == NULL) return NULL; deferred_reification_t* reify = c->frame->reify; ast_t* type = deferred_reify(reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; ast_t* l_type = deferred_reify(reify, ast_type(left), c->opt); LLVMValueRef value = make_tupleelemptr(c, l_value, l_type, right); ast_free_unattached(l_type); return gen_assign_cast(c, c_t->use_type, value, t->ast_cap); }
LLVMValueRef gen_fieldptr(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); LLVMValueRef l_value = gen_expr(c, left); if(l_value == NULL) return NULL; ast_t* l_type = deferred_reify(c->frame->reify, ast_type(left), c->opt); LLVMValueRef ret = make_fieldptr(c, l_value, l_type, right); ast_free_unattached(l_type); return ret; }
LLVMValueRef gen_localload(compile_t* c, ast_t* ast) { LLVMValueRef local_ptr = gen_localptr(c, ast); if(local_ptr == NULL) return NULL; ast_t* type = deferred_reify(c->frame->reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; LLVMValueRef value = LLVMBuildLoad(c->builder, local_ptr, ""); return gen_assign_cast(c, c_t->use_type, value, t->ast_cap); }
LLVMValueRef gen_fieldload(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); LLVMValueRef field = gen_fieldptr(c, ast); if(field == NULL) return NULL; deferred_reification_t* reify = c->frame->reify; ast_t* type = deferred_reify(reify, ast_type(right), c->opt); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; field = LLVMBuildLoad(c->builder, field, ""); return gen_assign_cast(c, c_t->use_type, field, t->ast_cap); }
LLVMValueRef gen_int(compile_t* c, ast_t* ast) { ast_t* type = deferred_reify(c->frame->reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); ast_free_unattached(type); compile_type_t* c_t = (compile_type_t*)t->c_type; lexint_t* value = ast_int(ast); LLVMValueRef vlow = LLVMConstInt(c->i128, value->low, false); LLVMValueRef vhigh = LLVMConstInt(c->i128, value->high, false); LLVMValueRef shift = LLVMConstInt(c->i128, 64, false); vhigh = LLVMConstShl(vhigh, shift); vhigh = LLVMConstAdd(vhigh, vlow); if(c_t->primitive == c->i128) return vhigh; if((c_t->primitive == c->f32) || (c_t->primitive == c->f64)) return LLVMConstUIToFP(vhigh, c_t->primitive); return LLVMConstTrunc(vhigh, c_t->primitive); }
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name, reach_type_t* t, ast_t* args, bool intrinsic) { ast_t* last_arg = ast_childlast(args); if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS)) return declare_ffi_vararg(c, f_name, t); int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); count = 0; ast_t* arg = ast_child(args); deferred_reification_t* reify = c->frame->reify; while(arg != NULL) { ast_t* p_type = ast_type(arg); if(p_type == NULL) p_type = ast_childidx(arg, 1); p_type = deferred_reify(reify, p_type, c->opt); reach_type_t* pt = reach_type(c->reach, p_type); pony_assert(pt != NULL); f_params[count++] = ((compile_type_t*)pt->c_type)->use_type; ast_free_unattached(p_type); arg = ast_sibling(arg); } LLVMTypeRef r_type = ffi_return_type(c, t, intrinsic); LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false); LLVMValueRef func = LLVMAddFunction(c->module, f_name, f_type); ponyint_pool_free_size(buf_size, f_params); return func; }
LLVMValueRef gen_pattern_eq(compile_t* c, ast_t* pattern, LLVMValueRef r_value) { // This is used for structural equality in pattern matching. ast_t* pattern_type = deferred_reify(c->frame->reify, ast_type(pattern), c->opt); if(ast_id(pattern_type) == TK_NOMINAL) { AST_GET_CHILDREN(pattern_type, package, id); // Special case equality on primitive types. if(ast_name(package) == c->str_builtin) { const char* name = ast_name(id); if((name == c->str_Bool) || (name == c->str_I8) || (name == c->str_I16) || (name == c->str_I32) || (name == c->str_I64) || (name == c->str_I128) || (name == c->str_ILong) || (name == c->str_ISize) || (name == c->str_U8) || (name == c->str_U16) || (name == c->str_U32) || (name == c->str_U64) || (name == c->str_U128) || (name == c->str_ULong) || (name == c->str_USize) || (name == c->str_F32) || (name == c->str_F64) ) { ast_free_unattached(pattern_type); return gen_eq_rvalue(c, pattern, r_value, true); } } } // Generate the receiver. LLVMValueRef l_value = gen_expr(c, pattern); reach_type_t* t = reach_type(c->reach, pattern_type); pony_assert(t != NULL); // Static or virtual dispatch. token_id cap = cap_dispatch(pattern_type); reach_method_t* m = reach_method(t, cap, c->str_eq, NULL); LLVMValueRef func = dispatch_function(c, t, m, l_value); ast_free_unattached(pattern_type); if(func == NULL) return NULL; // Call the function. We know it isn't partial. LLVMValueRef args[2]; args[0] = l_value; args[1] = r_value; codegen_debugloc(c, pattern); LLVMValueRef result = codegen_call(c, func, args, 2, true); codegen_debugloc(c, NULL); return result; }
LLVMValueRef gen_call(compile_t* c, ast_t* ast) { // Special case calls. LLVMValueRef special; if(special_case_call(c, ast, &special)) return special; AST_GET_CHILDREN(ast, postfix, positional, named, question); AST_GET_CHILDREN(postfix, receiver, method); ast_t* typeargs = NULL; deferred_reification_t* reify = c->frame->reify; // Dig through function qualification. switch(ast_id(receiver)) { case TK_NEWREF: case TK_NEWBEREF: case TK_BEREF: case TK_FUNREF: case TK_BECHAIN: case TK_FUNCHAIN: typeargs = deferred_reify(reify, method, c->opt); AST_GET_CHILDREN_NO_DECL(receiver, receiver, method); break; default: {} } // Get the receiver type. const char* method_name = ast_name(method); ast_t* type = deferred_reify(reify, ast_type(receiver), c->opt); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, method_name, typeargs); ast_free_unattached(type); ast_free_unattached(typeargs); // Generate the arguments. size_t count = m->param_count + 1; size_t buf_size = count * sizeof(void*); LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); ast_t* arg = ast_child(positional); int i = 1; while(arg != NULL) { LLVMValueRef value = gen_expr(c, arg); if(value == NULL) { ponyint_pool_free_size(buf_size, args); return NULL; } args[i] = value; arg = ast_sibling(arg); i++; } bool is_new_call = false; // Generate the receiver. Must be done after the arguments because the args // could change things in the receiver expression that must be accounted for. if(call_needs_receiver(postfix, t)) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: args[0] = gen_constructor_receiver(c, t, ast); is_new_call = true; break; case TK_BEREF: case TK_FUNREF: case TK_BECHAIN: case TK_FUNCHAIN: args[0] = gen_expr(c, receiver); break; default: pony_assert(0); return NULL; } } else { // Use a null for the receiver type. args[0] = LLVMConstNull(((compile_type_t*)t->c_type)->use_type); } // Static or virtual dispatch. LLVMValueRef func = dispatch_function(c, t, m, args[0]); bool is_message = false; if((ast_id(postfix) == TK_NEWBEREF) || (ast_id(postfix) == TK_BEREF) || (ast_id(postfix) == TK_BECHAIN)) { switch(t->underlying) { case TK_ACTOR: is_message = true; break; case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_INTERFACE: case TK_TRAIT: if(m->cap == TK_TAG) is_message = can_inline_message_send(t, m, method_name); break; default: {} } } bool bare = m->cap == TK_AT; LLVMValueRef r = NULL; if(is_message) { // If we're sending a message, trace and send here instead of calling the // sender to trace the most specific types possible. codegen_debugloc(c, ast); gen_send_message(c, m, args, positional); codegen_debugloc(c, NULL); switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: r = args[0]; break; default: r = c->none_instance; break; } } else { LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params + (bare ? 1 : 0)); arg = ast_child(positional); i = 1; while(arg != NULL) { ast_t* arg_type = deferred_reify(reify, ast_type(arg), c->opt); args[i] = gen_assign_cast(c, params[i], args[i], arg_type); ast_free_unattached(arg_type); arg = ast_sibling(arg); i++; } uintptr_t arg_offset = 0; if(bare) { arg_offset = 1; i--; } if(func != NULL) { // If we can error out and we have an invoke target, generate an invoke // instead of a call. codegen_debugloc(c, ast); if(ast_canerror(ast) && (c->frame->invoke_target != NULL)) r = invoke_fun(c, func, args + arg_offset, i, "", !bare); else r = codegen_call(c, func, args + arg_offset, i, !bare); if(is_new_call) { LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(r, "pony.newcall", md); } codegen_debugloc(c, NULL); ponyint_pool_free_size(buf_size, params); } } // Bare methods with None return type return void, special case a None return // value. if(bare && is_none(m->result->ast)) r = c->none_instance; // Class constructors return void, expression result is the receiver. if(((ast_id(postfix) == TK_NEWREF) || (ast_id(postfix) == TK_NEWBEREF)) && (t->underlying == TK_CLASS)) r = args[0]; // Chained methods forward their receiver. if((ast_id(postfix) == TK_BECHAIN) || (ast_id(postfix) == TK_FUNCHAIN)) r = args[0]; ponyint_pool_free_size(buf_size, args); return r; }
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[], ast_t* args_ast) { // Allocate the message, setting its size and ID. compile_method_t* c_m = (compile_method_t*)m->c_method; size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, c_m->msg_type); LLVMTypeRef msg_type_ptr = LLVMPointerType(c_m->msg_type, 0); size_t params_buf_size = (m->param_count + 3) * sizeof(LLVMTypeRef); LLVMTypeRef* param_types = (LLVMTypeRef*)ponyint_pool_alloc_size(params_buf_size); LLVMGetStructElementTypes(c_m->msg_type, param_types); size_t args_buf_size = (m->param_count + 1) * sizeof(LLVMValueRef); LLVMValueRef* cast_args = (LLVMValueRef*)ponyint_pool_alloc_size(args_buf_size); size_t arg_types_buf_size = m->param_count * sizeof(ast_t*); ast_t** arg_types = (ast_t**)ponyint_pool_alloc_size(arg_types_buf_size); ast_t* arg_ast = ast_child(args_ast); deferred_reification_t* reify = c->frame->reify; for(size_t i = 0; i < m->param_count; i++) { arg_types[i] = deferred_reify(reify, ast_type(arg_ast), c->opt); cast_args[i+1] = gen_assign_cast(c, param_types[i+3], args[i+1], arg_types[i]); arg_ast = ast_sibling(arg_ast); } LLVMValueRef msg_args[5]; msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, ""); LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(msg, "pony.msgsend", md); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); for(unsigned int i = 0; i < m->param_count; i++) { LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, ""); LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr); } // Trace while populating the message contents. bool need_trace = false; for(size_t i = 0; i < m->param_count; i++) { if(gentrace_needed(c, arg_types[i], m->params[i].ast)) { need_trace = true; break; } } LLVMValueRef ctx = codegen_ctx(c); if(need_trace) { LLVMValueRef gc = gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); LLVMSetMetadataStr(gc, "pony.msgsend", md); for(size_t i = 0; i < m->param_count; i++) { gentrace(c, ctx, args[i+1], cast_args[i+1], arg_types[i], m->params[i].ast); } gc = gencall_runtime(c, "pony_send_done", &ctx, 1, ""); LLVMSetMetadataStr(gc, "pony.msgsend", md); } // Send the message. msg_args[0] = ctx; msg_args[1] = LLVMBuildBitCast(c->builder, args[0], c->object_ptr, ""); msg_args[2] = msg; msg_args[3] = msg; msg_args[4] = LLVMConstInt(c->i1, 1, false); LLVMValueRef send; if(ast_id(m->fun->ast) == TK_NEW) send = gencall_runtime(c, "pony_sendv_single", msg_args, 5, ""); else send = gencall_runtime(c, "pony_sendv", msg_args, 5, ""); LLVMSetMetadataStr(send, "pony.msgsend", md); ponyint_pool_free_size(params_buf_size, param_types); ponyint_pool_free_size(args_buf_size, cast_args); for(size_t i = 0; i < m->param_count; i++) ast_free_unattached(arg_types[i]); ponyint_pool_free_size(arg_types_buf_size, arg_types); }
LLVMValueRef gen_funptr(compile_t* c, ast_t* ast) { pony_assert((ast_id(ast) == TK_FUNREF) || (ast_id(ast) == TK_BEREF)); AST_GET_CHILDREN(ast, receiver, method); ast_t* typeargs = NULL; // Dig through function qualification. switch(ast_id(receiver)) { case TK_BEREF: case TK_FUNREF: typeargs = method; AST_GET_CHILDREN_NO_DECL(receiver, receiver, method); break; default: {} } // Generate the receiver. LLVMValueRef value = gen_expr(c, receiver); // Get the receiver type. ast_t* type = deferred_reify(c->frame->reify, ast_type(receiver), c->opt); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); const char* name = ast_name(method); token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, name, typeargs); LLVMValueRef funptr = dispatch_function(c, t, m, value); ast_free_unattached(type); if((m->cap != TK_AT) && (c->linkage != LLVMExternalLinkage)) { // We must reset the function linkage and calling convention since we're // passing a function pointer to a FFI call. Bare methods always use the // external linkage and the C calling convention so we don't need to process // them. switch(t->underlying) { case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: { compile_method_t* c_m = (compile_method_t*)m->c_method; LLVMSetFunctionCallConv(c_m->func, LLVMCCallConv); LLVMSetLinkage(c_m->func, LLVMExternalLinkage); break; } case TK_UNIONTYPE: case TK_ISECTTYPE: case TK_INTERFACE: case TK_TRAIT: set_method_external_interface(t, name, m->vtable_index); break; default: pony_assert(0); break; } } return funptr; }
static bool special_case_call(compile_t* c, ast_t* ast, LLVMValueRef* value) { AST_GET_CHILDREN(ast, postfix, positional, named, question); if((ast_id(postfix) != TK_FUNREF) || (ast_id(named) != TK_NONE)) return false; AST_GET_CHILDREN(postfix, receiver, method); ast_t* receiver_type = deferred_reify(c->frame->reify, ast_type(receiver), c->opt); const char* name = NULL; if(ast_id(receiver_type) == TK_NOMINAL) { AST_GET_CHILDREN(receiver_type, package, id); if(ast_name(package) == c->str_builtin) name = ast_name(id); } ast_free_unattached(receiver_type); if(name == NULL) return false; if(name == c->str_Bool) return special_case_operator(c, ast, value, true, true); if((name == c->str_I8) || (name == c->str_I16) || (name == c->str_I32) || (name == c->str_I64) || (name == c->str_ILong) || (name == c->str_ISize) || (name == c->str_U8) || (name == c->str_U16) || (name == c->str_U32) || (name == c->str_U64) || (name == c->str_ULong) || (name == c->str_USize) || (name == c->str_F32) || (name == c->str_F64) ) { return special_case_operator(c, ast, value, false, true); } if((name == c->str_I128) || (name == c->str_U128)) { bool native128 = target_is_native128(c->opt->triple); return special_case_operator(c, ast, value, false, native128); } if(name == c->str_Platform) { *value = special_case_platform(c, ast); return true; } return false; }
LLVMValueRef gen_ffi(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, id, typeargs, args, named_args, can_err); bool err = (ast_id(can_err) == TK_QUESTION); // Get the function name, +1 to skip leading @ const char* f_name = ast_name(id) + 1; deferred_reification_t* reify = c->frame->reify; // Get the return type. ast_t* type = deferred_reify(reify, ast_type(ast), c->opt); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); ast_free_unattached(type); // Get the function. First check if the name is in use by a global and error // if it's the case. ffi_decl_t* ffi_decl; bool is_func = false; LLVMValueRef func = LLVMGetNamedGlobal(c->module, f_name); if(func == NULL) { func = LLVMGetNamedFunction(c->module, f_name); is_func = true; } if(func == NULL) { // If we have no prototype, declare one. ast_t* decl = (ast_t*)ast_data(ast); if(decl != NULL) { // Define using the declared types. AST_GET_CHILDREN(decl, decl_id, decl_ret, decl_params, decl_err); err = (ast_id(decl_err) == TK_QUESTION); func = declare_ffi(c, f_name, t, decl_params, false); } else if(!strncmp(f_name, "llvm.", 5) || !strncmp(f_name, "internal.", 9)) { // Intrinsic, so use the exact types we supply. func = declare_ffi(c, f_name, t, args, true); } else { // Make it varargs. func = declare_ffi_vararg(c, f_name, t); } size_t index = HASHMAP_UNKNOWN; #ifndef PONY_NDEBUG ffi_decl_t k; k.func = func; ffi_decl = ffi_decls_get(&c->ffi_decls, &k, &index); pony_assert(ffi_decl == NULL); #endif ffi_decl = POOL_ALLOC(ffi_decl_t); ffi_decl->func = func; ffi_decl->decl = (decl != NULL) ? decl : ast; ffi_decls_putindex(&c->ffi_decls, ffi_decl, index); } else { ffi_decl_t k; k.func = func; size_t index = HASHMAP_UNKNOWN; ffi_decl = ffi_decls_get(&c->ffi_decls, &k, &index); if((ffi_decl == NULL) && (!is_func || LLVMHasMetadataStr(func, "pony.abi"))) { ast_error(c->opt->check.errors, ast, "cannot use '%s' as an FFI name: " "name is already in use by the internal ABI", f_name); return NULL; } pony_assert(is_func); } // Generate the arguments. int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* f_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); LLVMTypeRef* f_params = NULL; bool vararg = (LLVMIsFunctionVarArg(f_type) != 0); if(!vararg) { if(count != (int)LLVMCountParamTypes(f_type)) { ast_error(c->opt->check.errors, ast, "conflicting declarations for FFI function: declarations have an " "incompatible number of parameters"); if(ffi_decl != NULL) ast_error_continue(c->opt->check.errors, ffi_decl->decl, "first " "declaration is here"); return NULL; } f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, f_params); } ast_t* arg = ast_child(args); for(int i = 0; i < count; i++) { f_args[i] = gen_expr(c, arg); if(!vararg) f_args[i] = cast_ffi_arg(c, ffi_decl, ast, f_args[i], f_params[i], "parameters"); if(f_args[i] == NULL) { ponyint_pool_free_size(buf_size, f_args); return NULL; } arg = ast_sibling(arg); } // If we can error out and we have an invoke target, generate an invoke // instead of a call. LLVMValueRef result; codegen_debugloc(c, ast); if(err && (c->frame->invoke_target != NULL)) result = invoke_fun(c, func, f_args, count, "", false); else result = LLVMBuildCall(c->builder, func, f_args, count, ""); codegen_debugloc(c, NULL); ponyint_pool_free_size(buf_size, f_args); if(!vararg) ponyint_pool_free_size(buf_size, f_params); compile_type_t* c_t = (compile_type_t*)t->c_type; // Special case a None return value, which is used for void functions. bool isnone = is_none(t->ast); bool isvoid = LLVMGetReturnType(f_type) == c->void_type; if(isnone && isvoid) { result = c_t->instance; } else if(isnone != isvoid) { report_ffi_type_err(c, ffi_decl, ast, "return values"); return NULL; } result = cast_ffi_arg(c, ffi_decl, ast, result, c_t->use_type, "return values"); result = gen_assign_cast(c, c_t->use_type, result, t->ast_cap); return result; }