bool genexe(compile_t* c, ast_t* program) { // The first package is the main package. It has to have a Main actor. const char* main_actor = stringtab("Main"); const char* env_class = stringtab("Env"); ast_t* package = ast_child(program); ast_t* main_def = ast_get(package, main_actor, NULL); if(main_def == NULL) { errorf(NULL, "no Main actor found in package '%s'", c->filename); return false; } // Generate the Main actor and the Env class. ast_t* main_ast = type_builtin(c->opt, main_def, main_actor); ast_t* env_ast = type_builtin(c->opt, main_def, env_class); genprim_reachable_init(c, program); reach(c->reachable, main_ast, stringtab("create"), NULL); reach(c->reachable, env_ast, stringtab("_create"), NULL); paint(c->reachable); gentype_t main_g; gentype_t env_g; bool ok = gentype(c, main_ast, &main_g) && gentype(c, env_ast, &env_g); if(ok) gen_main(c, &main_g, &env_g); ast_free_unattached(main_ast); ast_free_unattached(env_ast); if(!ok) return false; if(!genopt(c)) return false; const char* file_o = genobj(c); if(file_o == NULL) return false; if(c->opt->limit < PASS_ALL) return true; if(!link_exe(c, program, file_o)) return false; #ifdef PLATFORM_IS_WINDOWS _unlink(file_o); #else unlink(file_o); #endif return true; }
static LLVMTypeRef get_signature(compile_t* c, gentype_t* g, ast_t* fun) { // Get a type for the result. ast_t* rtype = ast_childidx(fun, 4); gentype_t rtype_g; if(!gentype(c, rtype, &rtype_g)) { ast_error(rtype, "couldn't generate result type"); return NULL; } // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size); count = 0; // Get a type for the receiver. tparams[count++] = g->use_type; // Get a type for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); gentype_t ptype_g; if(!gentype(c, ptype, &ptype_g)) { ast_error(ptype, "couldn't generate parameter type"); pool_free_size(buf_size, tparams); return NULL; } tparams[count++] = ptype_g.use_type; param = ast_sibling(param); } LLVMTypeRef result = rtype_g.use_type; // Generate the function type. LLVMTypeRef r = LLVMFunctionType(result, tparams, (int)count, false); pool_free_size(buf_size, tparams); return r; }
LLVMValueRef gen_int(compile_t* c, ast_t* ast) { ast_t* type = ast_type(ast); gentype_t g; if(!gentype(c, type, &g)) return NULL; __uint128_t value = ast_int(ast); uint64_t low, high; #if !defined(HAVE_STRUCT_INT128) low = (uint64_t)value; high = (uint64_t)(value >> 64); #else low = value.low; high = value.high; #endif LLVMValueRef vlow = LLVMConstInt(c->i128, low, false); LLVMValueRef vhigh = LLVMConstInt(c->i128, high, false); LLVMValueRef shift = LLVMConstInt(c->i128, 64, false); vhigh = LLVMConstShl(vhigh, shift); vhigh = LLVMConstAdd(vhigh, vlow); if(g.primitive == c->i128) return vhigh; if((g.primitive == c->f32) || (g.primitive == c->f64)) return LLVMConstUIToFP(vhigh, g.primitive); return LLVMConstTrunc(vhigh, g.primitive); }
static bool dynamic_value_ptr(compile_t* c, LLVMValueRef ptr, LLVMValueRef desc, ast_t* pattern, LLVMBasicBlockRef next_block) { // Get the type of the right-hand side of the pattern's eq() function. ast_t* param_type = eq_param_type(pattern); // Check the runtime type. We pass a pointer to the fields because we may // still need to match a tuple type inside a type expression. if(!check_type(c, ptr, desc, param_type, next_block)) return false; // We now know that ptr points to something of type pattern_type, and that // it isn't a boxed primitive, as that would go through the other path, ie // dynamic_match_object(). We also know it isn't an unboxed tuple. We can // load from ptr with a type based on the static type of the pattern. gentype_t g; if(!gentype(c, param_type, &g)) return false; LLVMTypeRef ptr_type = LLVMPointerType(g.use_type, 0); ptr = LLVMBuildIntToPtr(c->builder, ptr, ptr_type, ""); LLVMValueRef value = LLVMBuildLoad(c->builder, ptr, ""); return check_value(c, pattern, param_type, value, next_block); }
static bool check_value(compile_t* c, ast_t* pattern, ast_t* param_type, LLVMValueRef value, LLVMBasicBlockRef next_block) { LLVMValueRef l_value = gen_expr(c, pattern); if(l_value == NULL) return false; gentype_t g; if(!gentype(c, param_type, &g)) return false; LLVMValueRef r_value = gen_assign_cast(c, g.use_type, value, param_type); if(r_value == NULL) return false; LLVMValueRef test = gen_pattern_eq(c, pattern, r_value); if(test == NULL) return false; LLVMBasicBlockRef continue_block = codegen_block(c, "pattern_continue"); LLVMBuildCondBr(c->builder, test, continue_block, next_block); LLVMPositionBuilderAtEnd(c->builder, continue_block); return true; }
LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); ast_t* type = ast_type(id); gentype_t g; if(!gentype(c, type, &g)) return NULL; // 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); const char* name = ast_name(id); LLVMValueRef l_value = LLVMBuildAlloca(c->builder, g.use_type, name); // Store the alloca to use when we reference this local. codegen_setlocal(c, name, l_value); // Emit debug info for local variable declaration. dwarf_local(&c->dwarf, ast, g.type_name, entry_block, inst, l_value); // Put the builder back where it was. LLVMPositionBuilderAtEnd(c->builder, this_block); return GEN_NOVALUE; }
LLVMValueRef gen_funptr(compile_t* c, ast_t* ast) { 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 type. const char* method_name = ast_name(method); ast_t* type = ast_type(receiver); gentype_t g; if(!gentype(c, type, &g)) return NULL; LLVMValueRef value = gen_expr(c, receiver); return dispatch_function(c, ast, &g, value, method_name, typeargs); }
static bool dynamic_capture_ptr(compile_t* c, LLVMValueRef ptr, LLVMValueRef desc, ast_t* pattern, LLVMBasicBlockRef next_block) { // Here, ptr is a pointer to a tuple field. It could be a primitive, an // object, or a nested tuple. ast_t* pattern_type = ast_type(pattern); // Check the runtime type. We pass a pointer to the fields because we may // still need to match a tuple type inside a type expression. if(!check_type(c, ptr, desc, pattern_type, next_block)) return false; // We now know that ptr points to something of type pattern_type, and that // it isn't a boxed primitive or tuple, as that would go through the other // path, ie dynamic_match_object(). We also know it isn't an unboxed tuple. // We can load from ptr with a type based on the static type of the pattern. gentype_t g; if(!gentype(c, pattern_type, &g)) return false; LLVMTypeRef ptr_type = LLVMPointerType(g.use_type, 0); ptr = LLVMBuildIntToPtr(c->builder, ptr, ptr_type, ""); LLVMValueRef value = LLVMBuildLoad(c->builder, ptr, ""); return gen_assign_value(c, pattern, value, pattern_type) != NULL; }
static bool trace_known(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { gentype_t g; if(!gentype(c, type, &g)) return false; // Get the trace function statically. const char* fun = genname_trace(g.type_name); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, fun); // If this type has no trace function, don't try to recurse in the runtime. if(trace_fn != NULL) { // Cast the value to an object pointer. LLVMValueRef args[3]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, value, c->object_ptr, ""); args[2] = trace_fn; gencall_runtime(c, "pony_traceobject", args, 3, ""); } else { // Cast the value to a void pointer. LLVMValueRef args[2]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, value, c->void_ptr, ""); gencall_runtime(c, "pony_trace", args, 2, ""); } 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); 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); } } // Generate the receiver. LLVMValueRef l_value = gen_expr(c, pattern); gentype_t g; if(!gentype(c, pattern_type, &g)) return NULL; // Static or virtual dispatch. LLVMValueRef func = dispatch_function(c, pattern, &g, l_value, stringtab("eq"), NULL); 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; // Emit debug location for calls to test for structural equality dwarf_location(&c->dwarf, pattern); return codegen_call(c, func, args, 2); }
void genp9(Node *file, char *out) { Htab *globls, *strtab; Node *n, **blob; Func **fn; size_t nfn, nblob; size_t i; FILE *fd; /* ensure that all physical registers have a loc created before any * other locs, so that locmap[Physreg] maps to the Loc for the physreg * in question */ for (i = 0; i < Nreg; i++) locphysreg(i); fn = NULL; nfn = 0; blob = NULL; nblob = 0; globls = mkht(varhash, vareq); initconsts(globls); /* We need to define all global variables before use */ fillglobls(file->file.globls, globls); pushstab(file->file.globls); for (i = 0; i < file->file.nstmts; i++) { n = file->file.stmts[i]; switch (n->type) { case Nuse: /* nothing to do */ case Nimpl: break; case Ndecl: simpglobl(n, globls, &fn, &nfn, &blob, &nblob); break; default: die("Bad node %s in toplevel", nodestr[n->type]); break; } } popstab(); fd = fopen(out, "w"); if (!fd) die("Couldn't open fd %s", out); strtab = mkht(strlithash, strliteq); for (i = 0; i < nblob; i++) genblob(fd, blob[i], globls, strtab); for (i = 0; i < nfn; i++) genfunc(fd, fn[i], globls, strtab); for (i = 0; i < ntypes; i++) if (types[i]->isreflect && !types[i]->isimport) gentype(fd, types[i]); fprintf(fd, "\n"); genstrings(fd, strtab); fclose(fd); }
static LLVMValueRef make_field_list(compile_t* c, gentype_t* g) { // The list is an array of field descriptors. int count; if(g->underlying == TK_TUPLETYPE) count = g->field_count; else count = 0; LLVMTypeRef type = LLVMArrayType(c->field_descriptor, count); // If we aren't a tuple, return a null pointer to a list. if(count == 0) return LLVMConstNull(LLVMPointerType(type, 0)); // Create a constant array of field descriptors. size_t buf_size = count *sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)pool_alloc_size(buf_size); for(int i = 0; i < count; i++) { gentype_t fg; if(!gentype(c, g->fields[i], &fg)) return NULL; LLVMValueRef fdesc[2]; fdesc[0] = LLVMConstInt(c->i32, LLVMOffsetOfElement(c->target_data, g->primitive, i), false); if(fg.desc != NULL) { // We are a concrete type. fdesc[1] = LLVMConstBitCast(fg.desc, c->descriptor_ptr); } else { // We aren't a concrete type. fdesc[1] = LLVMConstNull(c->descriptor_ptr); } list[i] = LLVMConstStructInContext(c->context, fdesc, 2, false); } LLVMValueRef field_array = LLVMConstArray(c->field_descriptor, list, count); // Create a global to hold the array. const char* name = genname_fieldlist(g->type_name); LLVMValueRef global = LLVMAddGlobal(c->module, type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMSetInitializer(global, field_array); pool_free_size(buf_size, list); return global; }
LLVMValueRef gen_float(compile_t* c, ast_t* ast) { ast_t* type = ast_type(ast); gentype_t g; if(!gentype(c, type, &g)) return NULL; return LLVMConstReal(g.primitive, ast_float(ast)); }
LLVMValueRef gendesc_isentity(compile_t* c, LLVMValueRef desc, ast_t* type) { gentype_t g; if(!gentype(c, type, &g)) return GEN_NOVALUE; LLVMValueRef left = LLVMBuildPtrToInt(c->builder, desc, c->intptr, ""); LLVMValueRef right = LLVMConstPtrToInt(g.desc, c->intptr); return LLVMBuildICmp(c->builder, LLVMIntEQ, left, right, ""); }
void update_pop(population *S,mic_matrix M) { int i=0; for(i=0;i<S->n;i++) { int **gtp=(int **)malloc(sizeof(int *)); int num=gentype(S->m[i].chro,gtp,S->m[i].l); S->m[i].sig=cal_merit(*gtp,num,M); free(*gtp); free(gtp); gtp=NULL; } }
static void name_param(compile_t* c, LLVMValueRef func, const char* name, ast_t* type, int index) { gentype_t g; gentype(c, type, &g); LLVMValueRef param = LLVMGetParam(func, index); LLVMSetValueName(param, name); LLVMValueRef value = LLVMBuildAlloca(c->builder, g.use_type, name); LLVMBuildStore(c->builder, param, value); codegen_setlocal(c, name, value); }
static bool generate_actor(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); ast_t* type = type_builtin(c->opt, ast, ast_name(id)); if(type == NULL) return false; gentype_t g; bool ok = gentype(c, type, &g); ast_free_unattached(type); return ok; }
static bool make_components(compile_t* c, gentype_t* g) { for(int i = 0; i < g->field_count; i++) { gentype_t field_g; if(!gentype(c, g->fields[i], &field_g)) return false; dwarf_field(&c->dwarf, g, &field_g, i); } return true; }
static void gentypes(FILE *fd) { Type *ty; size_t i; for (i = Ntypes; i < ntypes; i++) { if (!types[i]->isreflect) continue; ty = tydedup(types[i]); if (ty->isemitted || ty->isimport) continue; gentype(fd, ty); } fprintf(fd, "\n"); }
bool gentype_prelim(compile_t* c, ast_t* ast, gentype_t* g) { if(ast_id(ast) == TK_NOMINAL) { memset(g, 0, sizeof(gentype_t)); g->ast = ast; g->type_name = genname_type(ast); g->desc_name = genname_descriptor(g->type_name); return make_nominal(c, ast, g, true); } return gentype(c, ast, g); }
static void primitive_call(compile_t* c, const char* method, LLVMValueRef arg) { size_t count = 1; if(arg != NULL) count++; size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(c->reachable, &i)) != NULL) { if(ast_id(t->type) == TK_TUPLETYPE) continue; ast_t* def = (ast_t*)ast_data(t->type); if(ast_id(def) != TK_PRIMITIVE) continue; reachable_method_name_t* n = reach_method_name(t, method); if(n == NULL) continue; gentype_t g; if(!gentype(c, t->type, &g)) { assert(0); return; } LLVMValueRef fun = genfun_proto(c, &g, method, NULL); assert(fun != NULL); LLVMValueRef args[2]; args[0] = g.instance; args[1] = arg; codegen_call(c, fun, args, count); } }
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); ast_t* type = ast_type(ast); gentype_t g; if(!gentype(c, type, &g)) return NULL; // If we contain TK_DONTCARE, we have no usable value. if(g.primitive == NULL) return GEN_NOVALUE; LLVMValueRef tuple = LLVMGetUndef(g.primitive); int i = 0; while(child != NULL) { LLVMValueRef value = gen_expr(c, child); if(value == NULL) 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) tuple = LLVMBuildInsertValue(c->builder, tuple, value, i++, ""); child = ast_sibling(child); } return tuple; }
//initialize the population void ini_pop(mic_matrix M,population *pop) { pop->m=(chro_ptr)malloc(sizeof(chrosome)*(pop->n)); if(pop->m==NULL) { printf("Ini_pop memory error!\n"); } int i=0; while(i < pop->n) { /* Here pop->m[i].l denotes the length of the chrosome ,染色体长度不应该包含类标签*/ pop->m[i].l=M.atrn-1; pop->m[i].chro=(int *)malloc(sizeof(int)*(pop->m[i].l)); if(pop->m[i].chro==NULL) { printf("GA ini_pop mem error!\n"); exit(0); } int j=0; for(;j<pop->m[i].l;j++) { pop->m[i].chro[j]=rand()%2; } int **gtp=(int **)malloc(sizeof(int *)); if(gtp==NULL) { puts("GA gtp mem error!"); exit(1); } int num=gentype(pop->m[i].chro,gtp,pop->m[i].l); pop->m[i].sig=cal_merit(gtp[0],num,M); free(*gtp); free(gtp); gtp=NULL; i++; }; }
LLVMValueRef gen_string(compile_t* c, ast_t* ast) { ast_t* type = ast_type(ast); const char* name = ast_name(ast); size_t len = strlen(name); LLVMValueRef args[4]; args[0] = LLVMConstInt(c->i32, 0, false); args[1] = LLVMConstInt(c->i32, 0, false); LLVMValueRef str = LLVMConstStringInContext(c->context, name, (int)len, false); LLVMValueRef g_str = LLVMAddGlobal(c->module, LLVMTypeOf(str), "$strval"); LLVMSetLinkage(g_str, LLVMInternalLinkage); LLVMSetInitializer(g_str, str); LLVMSetGlobalConstant(g_str, true); LLVMValueRef str_ptr = LLVMConstInBoundsGEP(g_str, args, 2); gentype_t g; if(!gentype(c, type, &g)) return NULL; args[0] = g.desc; args[1] = LLVMConstInt(c->i64, len, false); args[2] = LLVMConstInt(c->i64, 0, false); args[3] = str_ptr; LLVMValueRef inst = LLVMConstNamedStruct(g.structure, args, 4); LLVMValueRef g_inst = LLVMAddGlobal(c->module, g.structure, "$string"); LLVMSetInitializer(g_inst, inst); LLVMSetGlobalConstant(g_inst, true); LLVMSetLinkage(g_inst, LLVMInternalLinkage); return g_inst; }
LLVMValueRef gen_ffi(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, id, typeargs, args); // Get the function name, +1 to skip leading @ const char* f_name = ast_name(id) + 1; // Generate the return type. ast_t* type = ast_type(ast); gentype_t g; // Emit dwarf location of ffi call dwarf_location(&c->dwarf, ast); if(!gentype(c, type, &g)) return NULL; // Get the function. LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name); if(func == NULL) { // If we have no prototype, declare one. if(!strncmp(f_name, "llvm.", 5)) { // Intrinsic, so use the exact types we supply. int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)pool_alloc_size(buf_size); count = 0; ast_t* arg = ast_child(args); while(arg != NULL) { ast_t* p_type = ast_type(arg); gentype_t param_g; if(!gentype(c, p_type, ¶m_g)) return NULL; f_params[count++] = param_g.use_type; arg = ast_sibling(arg); } // We may have generated the function by generating a parameter type. func = LLVMGetNamedFunction(c->module, f_name); if(func == NULL) { LLVMTypeRef r_type; if(g.underlying == TK_TUPLETYPE) { // Can't use the named type. Build an unnamed type with the same // elements. unsigned int count = LLVMCountStructElementTypes(g.use_type); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* e_types = (LLVMTypeRef*)pool_alloc_size(buf_size); LLVMGetStructElementTypes(g.use_type, e_types); r_type = LLVMStructTypeInContext(c->context, e_types, count, false); pool_free_size(buf_size, e_types); } else { r_type = g.use_type; } LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false); func = LLVMAddFunction(c->module, f_name, f_type); if(!ast_canerror(ast)) LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute); } pool_free_size(buf_size, f_params); } else { // Make it varargs. LLVMTypeRef f_type = LLVMFunctionType(g.use_type, NULL, 0, true); func = LLVMAddFunction(c->module, f_name, f_type); if(!ast_canerror(ast)) LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute); } } // Generate the arguments. int count = (int)ast_childcount(args); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* f_args = (LLVMValueRef*)pool_alloc_size(buf_size); ast_t* arg = ast_child(args); for(int i = 0; i < count; i++) { f_args[i] = gen_expr(c, arg); if(f_args[i] == NULL) { 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; if(ast_canerror(ast) && (c->frame->invoke_target != NULL)) result = invoke_fun(c, func, f_args, count, "", false); else result = LLVMBuildCall(c->builder, func, f_args, count, ""); pool_free_size(buf_size, f_args); // Special case a None return value, which is used for void functions. if(is_none(type)) return g.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, 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: typeargs = method; AST_GET_CHILDREN_NO_DECL(receiver, receiver, method); break; default: {} } // Generate the receiver type. const char* method_name = ast_name(method); ast_t* type = ast_type(receiver); gentype_t g; if(!gentype(c, type, &g)) return NULL; // Generate the arguments. LLVMTypeRef f_type = genfun_sig(c, &g, method_name, typeargs); if(f_type == NULL) { ast_error(ast, "couldn't create a signature for '%s'", method_name); return NULL; } size_t count = ast_childcount(positional) + 1; size_t buf_size = count * sizeof(void*); LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params); ast_t* arg = ast_child(positional); int i = 1; while(arg != NULL) { LLVMValueRef value = make_arg(c, params[i], arg); if(value == NULL) { ponyint_pool_free_size(buf_size, args); ponyint_pool_free_size(buf_size, params); return NULL; } args[i] = value; arg = ast_sibling(arg); i++; } // 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, &g)) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: { ast_t* parent = ast_parent(ast); ast_t* sibling = ast_sibling(ast); // If we're constructing an embed field, pass a pointer to the field // as the receiver. Otherwise, allocate an object. if((ast_id(parent) == TK_ASSIGN) && (ast_id(sibling) == TK_EMBEDREF)) args[0] = gen_fieldptr(c, sibling); else args[0] = gencall_alloc(c, &g); break; } case TK_BEREF: case TK_FUNREF: args[0] = gen_expr(c, receiver); break; default: assert(0); return NULL; } } else { // Use a null for the receiver type. args[0] = LLVMConstNull(g.use_type); } // Always emit location info for a call, to prevent inlining errors. This may // be disabled in dispatch_function, if the target function has no debug // info set. ast_setdebug(ast, true); dwarf_location(&c->dwarf, ast); // Static or virtual dispatch. LLVMValueRef func = dispatch_function(c, ast, &g, args[0], method_name, typeargs); LLVMValueRef r = NULL; if(func != NULL) { // If we can error out and we have an invoke target, generate an invoke // instead of a call. 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); } ponyint_pool_free_size(buf_size, args); ponyint_pool_free_size(buf_size, params); return r; }
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name, gentype_t* g, ast_t* args, bool err) { ast_t* last_arg = ast_childlast(args); if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS)) return declare_ffi_vararg(c, f_name, g, err); 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); while(arg != NULL) { ast_t* p_type = ast_type(arg); if(p_type == NULL) p_type = ast_childidx(arg, 1); gentype_t param_g; if(!gentype(c, p_type, ¶m_g)) return NULL; f_params[count++] = param_g.use_type; arg = ast_sibling(arg); } // We may have generated the function by generating a parameter type. LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name); if(func == NULL) { LLVMTypeRef r_type; if(g->underlying == TK_TUPLETYPE) { // Can't use the named type. Build an unnamed type with the same // elements. unsigned int count = LLVMCountStructElementTypes(g->use_type); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* e_types = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetStructElementTypes(g->use_type, e_types); r_type = LLVMStructTypeInContext(c->context, e_types, count, false); ponyint_pool_free_size(buf_size, e_types); } else { r_type = g->use_type; } LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false); func = LLVMAddFunction(c->module, f_name, f_type); if(!err) LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute); } ponyint_pool_free_size(buf_size, f_params); return func; }
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; // Generate the return type. ast_t* type = ast_type(ast); gentype_t g; // Emit dwarf location of ffi call dwarf_location(&c->dwarf, ast); if(!gentype(c, type, &g)) return 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, &g, decl_params, err); } else if(!strncmp(f_name, "llvm.", 5)) { // Intrinsic, so use the exact types we supply. func = declare_ffi(c, f_name, &g, args, err); } else { // Make it varargs. func = declare_ffi_vararg(c, f_name, &g, 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 && (LLVMGetTypeKind(f_params[i]) == LLVMPointerTypeKind)) { if(LLVMGetTypeKind(LLVMTypeOf(f_args[i])) == LLVMIntegerTypeKind) f_args[i] = LLVMBuildIntToPtr(c->builder, f_args[i], f_params[i], ""); else f_args[i] = LLVMBuildBitCast(c->builder, 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; 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, ""); 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 g.instance; return result; }
static bool make_struct(compile_t* c, gentype_t* g) { LLVMTypeRef type; int extra = 0; if(g->underlying != TK_TUPLETYPE) { type = g->structure; if(g->underlying != TK_STRUCT) extra++; } else { type = g->primitive; } if(g->underlying == TK_ACTOR) extra++; size_t buf_size = (g->field_count + extra) * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)pool_alloc_size(buf_size); // Create the type descriptor as element 0. if(extra > 0) elements[0] = LLVMPointerType(g->desc_type, 0); // Create the actor pad as element 1. if(g->underlying == TK_ACTOR) elements[1] = c->actor_pad; // Get a preliminary type for each field and set the struct body. This is // needed in case a struct for the type being generated here is required when // generating a field. for(int i = 0; i < g->field_count; i++) { gentype_t field_g; bool ok; if((g->field_keys != NULL) && (g->field_keys[i] == TK_EMBED)) { ok = gentype(c, g->fields[i], &field_g); elements[i + extra] = field_g.structure; } else { ok = gentype_prelim(c, g->fields[i], &field_g); elements[i + extra] = field_g.use_type; } if(!ok) { pool_free_size(buf_size, elements); return false; } } // An embedded field may have caused the current type to be fully generated // at this point. If so, finish gracefully. if(!LLVMIsOpaqueStruct(type)) { g->done = true; return true; } LLVMStructSetBody(type, elements, g->field_count + extra, false); // Create a box type for tuples. if(g->underlying == TK_TUPLETYPE) make_box_type(c, g); pool_free_size(buf_size, elements); return true; }
LLVMValueRef gen_match(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); ast_t* type = ast_type(ast); AST_GET_CHILDREN(ast, match_expr, cases, else_expr); // We will have no type if all case have control types. gentype_t phi_type; if(needed && !is_control_type(type) && !gentype(c, type, &phi_type)) { assert(0); return NULL; } ast_t* match_type = alias(ast_type(match_expr)); LLVMValueRef match_value = gen_expr(c, match_expr); LLVMBasicBlockRef pattern_block = codegen_block(c, "case_pattern"); LLVMBasicBlockRef else_block = codegen_block(c, "match_else"); LLVMBasicBlockRef post_block = NULL; LLVMBasicBlockRef next_block = NULL; // Jump to the first case. LLVMBuildBr(c->builder, pattern_block); LLVMValueRef phi = GEN_NOVALUE; if(!is_control_type(type)) { // Start the post block so that a case can modify the phi node. post_block = codegen_block(c, "match_post"); LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) phi = LLVMBuildPhi(c->builder, phi_type.use_type, ""); else phi = GEN_NOTNEEDED; } // Iterate over the cases. ast_t* the_case = ast_child(cases); while(the_case != NULL) { ast_t* next_case = ast_sibling(the_case); if(next_case != NULL) next_block = codegen_block(c, "case_pattern"); else next_block = else_block; AST_GET_CHILDREN(the_case, pattern, guard, body); LLVMPositionBuilderAtEnd(c->builder, pattern_block); codegen_pushscope(c); ast_t* pattern_type = ast_type(pattern); bool ok = true; if(is_matchtype(match_type, pattern_type) != MATCHTYPE_ACCEPT) { // If there's no possible match, jump directly to the next block. LLVMBuildBr(c->builder, next_block); } else { // Check the pattern. ok = static_match(c, match_value, match_type, pattern, next_block); // Check the guard. ok = ok && guard_match(c, guard, next_block); // Case body. ok = ok && case_body(c, body, post_block, phi, phi_type.use_type); } codegen_popscope(c); if(!ok) { ast_free_unattached(match_type); return NULL; } the_case = next_case; pattern_block = next_block; } ast_free_unattached(match_type); // Else body. LLVMPositionBuilderAtEnd(c->builder, else_block); codegen_pushscope(c); bool ok = case_body(c, else_expr, post_block, phi, phi_type.use_type); codegen_popscope(c); if(!ok) return NULL; if(post_block != NULL) LLVMPositionBuilderAtEnd(c->builder, post_block); return phi; }