static void make_global_instance(compile_t* c, gentype_t* g) { // Not a primitive type. if(g->underlying != TK_PRIMITIVE) return; // No instance for base types. if(g->primitive != NULL) return; // Check for an existing instance. const char* inst_name = genname_instance(g->type_name); g->instance = LLVMGetNamedGlobal(c->module, inst_name); if(g->instance != NULL) return; // Create a unique global instance. LLVMValueRef args[1]; args[0] = g->desc; LLVMValueRef value = LLVMConstNamedStruct(g->structure, args, 1); g->instance = LLVMAddGlobal(c->module, g->structure, inst_name); LLVMSetInitializer(g->instance, value); LLVMSetGlobalConstant(g->instance, true); LLVMSetLinkage(g->instance, LLVMInternalLinkage); }
static void *find_or_add_global(const char *name) { LLVMValueRef global; global = LLVMGetNamedGlobal(module, name); if (global == NULL) global = LLVMAddGlobal(module, TYPE_INT, name); return global; }
LLVMValueRef symbol_find(const char*name,int *isArg) { struct symbol_info *si = get_symbol_in_scope(name,head); if (si) { *isArg = si->isArg; return si->val; } else { *isArg = 0; return LLVMGetNamedGlobal(Module,name); } }
static void make_global_descriptor(compile_t* c, gentype_t* g) { // Fetch or create a descriptor type. if(g->underlying == TK_TUPLETYPE) g->field_count = (int)ast_childcount(g->ast); // Check for an existing descriptor. g->desc_type = gendesc_type(c, g); g->desc = LLVMGetNamedGlobal(c->module, g->desc_name); if(g->desc != NULL) return; g->desc = LLVMAddGlobal(c->module, g->desc_type, g->desc_name); LLVMSetGlobalConstant(g->desc, true); LLVMSetLinkage(g->desc, LLVMInternalLinkage); }
static LLVMValueRef make_type_id(compile_t* c, const char* type_name) { // Generate a named constant for the type that is set to a unique integer // value for that type. const char* name = genname_typeid(type_name); LLVMValueRef global = LLVMGetNamedGlobal(c->module, name); // Return the constant initialiser, not the global. if(global != NULL) return LLVMGetInitializer(global); global = LLVMAddGlobal(c->module, c->i32, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMValueRef id = LLVMConstInt(c->i32, c->next_type_id++, false); LLVMSetInitializer(global, id); return id; }
void *jit_var_ptr(const char *name, bool required) { if (using_jit) { LLVMValueRef var = LLVMGetNamedGlobal(module, name); if (var == NULL) { if (required) fatal("cannot find global %s", name); else return NULL; } return LLVMGetPointerToGlobal(exec_engine, var); } else { dlerror(); // Clear any previous error char dlname[256]; jit_native_name(name, dlname, sizeof(dlname)); void *sym = dlsym(dl_handle, dlname); const char *error = dlerror(); if ((error != NULL) && required) fatal("%s", error); return sym; } }
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; }