LLVMValueRef gen_return(compile_t* c, ast_t* ast) { ast_t* expr = ast_child(ast); LLVMValueRef value = gen_expr(c, expr); size_t clause; ast_t* try_expr = ast_try_clause(ast, &clause); // Do the then block only if we return in the body or else clause. // In the then block, return without doing the then block. if((try_expr != NULL) && (clause != 2)) gen_expr(c, ast_childidx(try_expr, 2)); LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(codegen_fun(c))); LLVMTypeRef r_type = LLVMGetReturnType(f_type); codegen_debugloc(c, ast); if(LLVMGetTypeKind(r_type) != LLVMVoidTypeKind) { LLVMValueRef ret = gen_assign_cast(c, r_type, value, ast_type(expr)); codegen_scope_lifetime_end(c); LLVMBuildRet(c->builder, ret); } else { codegen_scope_lifetime_end(c); LLVMBuildRetVoid(c->builder); } codegen_debugloc(c, NULL); return GEN_NOVALUE; }
static bool genfun_new(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); codegen_startfun(c, m->func, m->di_file, m->di_method); name_params(c, t, m, params, m->func); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; // Return 'this'. if(t->primitive == NULL) value = LLVMGetParam(m->func, 0); codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, value); codegen_debugloc(c, NULL); codegen_finishfun(c); return true; }
LLVMValueRef gen_continue(compile_t* c, ast_t* ast) { (void)ast; // Jump to the continue target. codegen_scope_lifetime_end(c); codegen_debugloc(c, ast); LLVMBuildBr(c->builder, c->frame->continue_target); codegen_debugloc(c, NULL); return GEN_NOVALUE; }
LLVMValueRef gen_assign(compile_t* c, ast_t* ast) { // Must generate the right hand side before the left hand side. Left and // right are swapped for type checking, so we fetch them in reverse order. AST_GET_CHILDREN(ast, right, left); LLVMValueRef r_value = gen_expr(c, right); if(r_value == NULL) return NULL; codegen_debugloc(c, ast); LLVMValueRef result = assign_rvalue(c, left, ast_type(right), r_value); codegen_debugloc(c, NULL); return result; }
LLVMValueRef gen_break(compile_t* c, ast_t* ast) { ast_t* body = ast_child(ast); LLVMBasicBlockRef target; if(ast_id(body) == TK_NONE) { target = c->frame->break_novalue_target; } else { ast_t* body_type = ast_type(body); // Get the break target. target = c->frame->break_target; // Get the phi node. LLVMValueRef post_phi = LLVMGetFirstInstruction(target); bool needed = (post_phi != NULL) && LLVMIsAPHINode(post_phi); // Build the break expression. LLVMValueRef value = gen_expr(c, body); if(needed) { // Cast it to the phi type if we need to. LLVMTypeRef phi_type = LLVMTypeOf(post_phi); value = gen_assign_cast(c, phi_type, value, body_type); } if(value == NULL) return NULL; // Add break value to the post block phi node. if(needed) { LLVMBasicBlockRef insert_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(post_phi, &value, &insert_block, 1); } } // Jump to the break target. codegen_scope_lifetime_end(c); codegen_debugloc(c, ast); LLVMBuildBr(c->builder, target); codegen_debugloc(c, NULL); return GEN_NOVALUE; }
LLVMValueRef gen_error(compile_t* c, ast_t* ast) { size_t clause; ast_t* try_expr = ast_try_clause(ast, &clause); // Do the then block only if we error out in the else clause. if((try_expr != NULL) && (clause == 1)) gen_expr(c, ast_childidx(try_expr, 2)); codegen_scope_lifetime_end(c); codegen_debugloc(c, ast); gencall_throw(c); codegen_debugloc(c, NULL); return GEN_NOVALUE; }
static bool genfun_fun(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); if(m->name == c->str__final) { t->final_fn = m->func; LLVMSetFunctionCallConv(m->func, LLVMCCallConv); } codegen_startfun(c, m->func, m->di_file, m->di_method); name_params(c, t, m, params, m->func); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; if(value != GEN_NOVALUE) { LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(m->func)); LLVMTypeRef r_type = LLVMGetReturnType(f_type); // If the result type is known to be a tuple, do the correct assignment // cast even if the body type is not a tuple. ast_t* body_type = ast_type(body); if(ast_id(result) == TK_TUPLETYPE) body_type = result; LLVMValueRef ret = gen_assign_cast(c, r_type, value, body_type); if(ret == NULL) return false; codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, ret); codegen_debugloc(c, NULL); } codegen_finishfun(c); return true; }
LLVMValueRef gen_is(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); ast_t* left_type = ast_type(left); ast_t* right_type = ast_type(right); LLVMValueRef l_value = gen_expr(c, left); LLVMValueRef r_value = gen_expr(c, right); if((l_value == NULL) || (r_value == NULL)) return NULL; codegen_debugloc(c, ast); LLVMValueRef result = gen_is_value(c, left_type, right_type, l_value, r_value); LLVMValueRef value = LLVMBuildZExt(c->builder, result, c->ibool, ""); codegen_debugloc(c, NULL); return value; }
static bool genfun_newbe(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); assert(m->func_handler != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); // Generate the handler. codegen_startfun(c, m->func_handler, m->di_file, m->di_method); name_params(c, t, m, params, m->func_handler); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; LLVMBuildRetVoid(c->builder); codegen_finishfun(c); // Generate the sender. codegen_startfun(c, m->func, NULL, NULL); LLVMValueRef this_ptr = LLVMGetParam(m->func, 0); // Send the arguments in a message to 'this'. LLVMTypeRef msg_type_ptr = send_message(c, params, this_ptr, m->func, m->vtable_index); // Return 'this'. codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, this_ptr); codegen_debugloc(c, NULL); codegen_finishfun(c); // Add the dispatch case. add_dispatch_case(c, t, params, m->vtable_index, m->func_handler, msg_type_ptr); return true; }
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 = ast_type(pattern); 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) ) { 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); 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); 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, positional, named, postfix); AST_GET_CHILDREN(postfix, receiver, method); ast_t* typeargs = NULL; // 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 = method; AST_GET_CHILDREN_NO_DECL(receiver, receiver, method); break; default: {} } // Get the receiver type. const char* method_name = ast_name(method); ast_t* type = ast_type(receiver); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); // Generate the arguments. size_t count = ast_childcount(positional) + 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: { call_tuple_indices_t tuple_indices = {NULL, 0, 4}; tuple_indices.data = (size_t*)ponyint_pool_alloc_size(4 * sizeof(size_t)); ast_t* current = ast; ast_t* parent = ast_parent(current); while((parent != NULL) && (ast_id(parent) != TK_ASSIGN) && (ast_id(parent) != TK_CALL)) { if(ast_id(parent) == TK_TUPLE) { size_t index = 0; ast_t* child = ast_child(parent); while(current != child) { ++index; child = ast_sibling(child); } tuple_indices_push(&tuple_indices, index); } current = parent; parent = ast_parent(current); } // If we're constructing an embed field, pass a pointer to the field // as the receiver. Otherwise, allocate an object. if((parent != NULL) && (ast_id(parent) == TK_ASSIGN)) { size_t index = 1; current = ast_childidx(parent, 1); while((ast_id(current) == TK_TUPLE) || (ast_id(current) == TK_SEQ)) { parent = current; if(ast_id(current) == TK_TUPLE) { // If there are no indices left, we're destructuring a tuple. // Errors in those cases have already been catched by the expr // pass. if(tuple_indices.count == 0) break; index = tuple_indices_pop(&tuple_indices); current = ast_childidx(parent, index); } else { current = ast_childlast(parent); } } if(ast_id(current) == TK_EMBEDREF) { args[0] = gen_fieldptr(c, current); set_descriptor(c, t, args[0]); } else { args[0] = gencall_alloc(c, t); } } else { args[0] = gencall_alloc(c, t); } is_new_call = true; ponyint_pool_free_size(tuple_indices.alloc * sizeof(size_t), tuple_indices.data); 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(t->use_type); } // Static or virtual dispatch. token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, method_name, typeargs); 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: {} } } // Cast the arguments to the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params); arg = ast_child(positional); i = 1; 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. LLVMValueRef* cast_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); cast_args[0] = args[0]; while(arg != NULL) { cast_args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg)); arg = ast_sibling(arg); i++; } token_id cap = cap_dispatch(type); reach_method_t* m = reach_method(t, cap, method_name, typeargs); codegen_debugloc(c, ast); gen_send_message(c, m, args, cast_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; } ponyint_pool_free_size(buf_size, cast_args); } else { while(arg != NULL) { args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg)); arg = ast_sibling(arg); 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, i, "", true); else r = codegen_call(c, func, args, i); if(is_new_call) { LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(r, "pony.newcall", md); } codegen_debugloc(c, NULL); } } // 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); ponyint_pool_free_size(buf_size, params); return r; }
static bool special_case_operator(compile_t* c, ast_t* ast, LLVMValueRef *value, bool short_circuit, bool native128) { AST_GET_CHILDREN(ast, positional, named, postfix); AST_GET_CHILDREN(postfix, left, method); ast_t* right = ast_child(positional); const char* name = ast_name(method); bool special_case = true; *value = NULL; codegen_debugloc(c, ast); if(name == c->str_add) *value = gen_add(c, left, right, true); else if(name == c->str_sub) *value = gen_sub(c, left, right, true); else if((name == c->str_mul) && native128) *value = gen_mul(c, left, right, true); else if((name == c->str_div) && native128) *value = gen_div(c, left, right, true); else if((name == c->str_mod) && native128) *value = gen_mod(c, left, right, true); else if(name == c->str_neg) *value = gen_neg(c, left, true); else if(name == c->str_add_unsafe) *value = gen_add(c, left, right, false); else if(name == c->str_sub_unsafe) *value = gen_sub(c, left, right, false); else if((name == c->str_mul_unsafe) && native128) *value = gen_mul(c, left, right, false); else if((name == c->str_div_unsafe) && native128) *value = gen_div(c, left, right, false); else if((name == c->str_mod_unsafe) && native128) *value = gen_mod(c, left, right, false); else if(name == c->str_neg_unsafe) *value = gen_neg(c, left, false); else if((name == c->str_and) && short_circuit) *value = gen_and_sc(c, left, right); else if((name == c->str_or) && short_circuit) *value = gen_or_sc(c, left, right); else if((name == c->str_and) && !short_circuit) *value = gen_and(c, left, right); else if((name == c->str_or) && !short_circuit) *value = gen_or(c, left, right); else if(name == c->str_xor) *value = gen_xor(c, left, right); else if(name == c->str_not) *value = gen_not(c, left); else if(name == c->str_shl) *value = gen_shl(c, left, right, true); else if(name == c->str_shr) *value = gen_shr(c, left, right, true); else if(name == c->str_shl_unsafe) *value = gen_shl(c, left, right, false); else if(name == c->str_shr_unsafe) *value = gen_shr(c, left, right, false); else if(name == c->str_eq) *value = gen_eq(c, left, right, true); else if(name == c->str_ne) *value = gen_ne(c, left, right, true); else if(name == c->str_lt) *value = gen_lt(c, left, right, true); else if(name == c->str_le) *value = gen_le(c, left, right, true); else if(name == c->str_ge) *value = gen_ge(c, left, right, true); else if(name == c->str_gt) *value = gen_gt(c, left, right, true); else if(name == c->str_eq_unsafe) *value = gen_eq(c, left, right, false); else if(name == c->str_ne_unsafe) *value = gen_ne(c, left, right, false); else if(name == c->str_lt_unsafe) *value = gen_lt(c, left, right, false); else if(name == c->str_le_unsafe) *value = gen_le(c, left, right, false); else if(name == c->str_ge_unsafe) *value = gen_ge(c, left, right, false); else if(name == c->str_gt_unsafe) *value = gen_gt(c, left, right, false); else special_case = false; codegen_debugloc(c, NULL); return special_case; }
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; // Get the return type. ast_t* type = ast_type(ast); reach_type_t* t = reach_type(c->reach, type); pony_assert(t != NULL); // Get the function. LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name); 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, err, false); } else if(!strncmp(f_name, "llvm.", 5)) { // Intrinsic, so use the exact types we supply. func = declare_ffi(c, f_name, t, args, err, true); } else { // Make it varargs. func = declare_ffi_vararg(c, f_name, t, err); } } // 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) { 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, f_args[i], f_params[i]); 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); // Special case a None return value, which is used for void functions. if(is_none(type)) return t->instance; 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; }
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; }