static LLVMValueRef assign_rvalue(compile_t* c, ast_t* left, ast_t* r_type, LLVMValueRef r_value) { switch(ast_id(left)) { case TK_VAR: case TK_LET: { // Generate the locals. if(gen_localdecl(c, left) == NULL) return NULL; return assign_rvalue(c, ast_child(left), r_type, r_value); } case TK_FVARREF: case TK_FLETREF: { // The result is the previous value of the field. LLVMValueRef l_value = gen_fieldptr(c, left); return assign_one(c, l_value, r_value, r_type); } case TK_VARREF: { // The result is the previous value of the local. LLVMValueRef l_value = gen_localptr(c, left); return assign_one(c, l_value, r_value, r_type); } case TK_TUPLE: { // If the l_value is a tuple, assemble it as the result. LLVMValueRef result = gen_expr(c, left); if(result == NULL) return NULL; if(!assign_tuple(c, left, r_type, r_value)) return NULL; // Return the original tuple. return result; } case TK_ID: { // We may have recursed here from a VAR or LET or arrived directly. const char* name = ast_name(left); LLVMValueRef l_value = codegen_getlocal(c, name); return assign_one(c, l_value, r_value, r_type); } default: {} } assert(0); return NULL; }
LLVMValueRef gen_fieldembed(compile_t* c, ast_t* ast) { LLVMValueRef field = gen_fieldptr(c, ast); if(field == NULL) return NULL; return field; }
static LLVMValueRef gen_constructor_receiver(compile_t* c, reach_type_t* t, ast_t* call) { ast_t* fieldref = find_embed_constructor_receiver(call); if(fieldref != NULL) { LLVMValueRef receiver = gen_fieldptr(c, fieldref); set_descriptor(c, t, receiver); return receiver; } else { return gencall_alloc(c, t); } }
LLVMValueRef gen_fieldload(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); ast_t* l_type = ast_type(left); LLVMValueRef field = gen_fieldptr(c, ast); if(field == NULL) return NULL; // Don't load if we're reading from a tuple. if(ast_id(l_type) != TK_TUPLETYPE) field = LLVMBuildLoad(c->builder, field, ""); return field; }
LLVMValueRef gen_addressof(compile_t* c, ast_t* ast) { ast_t* expr = ast_child(ast); switch(ast_id(expr)) { case TK_VARREF: case TK_LETREF: return gen_localptr(c, expr); case TK_FVARREF: case TK_FLETREF: return gen_fieldptr(c, expr); default: {} } assert(0); return NULL; }
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_fieldload(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, left, right); ast_t* l_type = ast_type(left); LLVMValueRef field = gen_fieldptr(c, ast); if(field == NULL) return NULL; assert((ast_id(l_type) == TK_NOMINAL) || (ast_id(l_type) == TK_TUPLETYPE)); // Don't load if we're reading from a tuple. if(ast_id(l_type) != TK_TUPLETYPE) { field = LLVMBuildLoad(c->builder, field, ""); LLVMValueRef metadata = tbaa_metadata_for_type(c, l_type); const char id[] = "tbaa"; LLVMSetMetadata(field, LLVMGetMDKindID(id, sizeof(id) - 1), metadata); } return field; }
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; }
LLVMValueRef gen_expr(compile_t* c, ast_t* ast) { LLVMValueRef ret; bool has_scope = ast_has_scope(ast); if(has_scope) codegen_pushscope(c, ast); switch(ast_id(ast)) { case TK_SEQ: ret = gen_seq(c, ast); break; case TK_FVARREF: case TK_FLETREF: ret = gen_fieldload(c, ast); break; case TK_EMBEDREF: ret = gen_fieldptr(c, ast); break; case TK_PARAMREF: ret = gen_param(c, ast); break; case TK_VAR: case TK_LET: case TK_MATCH_CAPTURE: ret = gen_localdecl(c, ast); break; case TK_VARREF: case TK_LETREF: ret = gen_localload(c, ast); break; case TK_IF: ret = gen_if(c, ast); break; case TK_WHILE: ret = gen_while(c, ast); break; case TK_REPEAT: ret = gen_repeat(c, ast); break; case TK_TRY: case TK_TRY_NO_CHECK: ret = gen_try(c, ast); break; case TK_MATCH: ret = gen_match(c, ast); break; case TK_CALL: ret = gen_call(c, ast); break; case TK_CONSUME: ret = gen_expr(c, ast_childidx(ast, 1)); break; case TK_RECOVER: ret = gen_expr(c, ast_childidx(ast, 1)); break; case TK_BREAK: ret = gen_break(c, ast); break; case TK_CONTINUE: ret = gen_continue(c, ast); break; case TK_RETURN: ret = gen_return(c, ast); break; case TK_ERROR: ret = gen_error(c, ast); break; case TK_IS: ret = gen_is(c, ast); break; case TK_ISNT: ret = gen_isnt(c, ast); break; case TK_ASSIGN: ret = gen_assign(c, ast); break; case TK_THIS: ret = gen_this(c, ast); break; case TK_TRUE: ret = LLVMConstInt(c->i1, 1, false); break; case TK_FALSE: ret = LLVMConstInt(c->i1, 0, false); break; case TK_INT: ret = gen_int(c, ast); break; case TK_FLOAT: ret = gen_float(c, ast); break; case TK_STRING: ret = gen_string(c, ast); break; case TK_TUPLE: ret = gen_tuple(c, ast); break; case TK_FFICALL: ret = gen_ffi(c, ast); break; case TK_ADDRESS: ret = gen_addressof(c, ast); break; case TK_DIGESTOF: ret = gen_digestof(c, ast); break; case TK_DONTCARE: ret = GEN_NOVALUE; break; case TK_COMPILE_INTRINSIC: ast_error(c->opt->check.errors, ast, "unimplemented compile intrinsic"); return NULL; case TK_COMPILE_ERROR: { ast_t* reason_seq = ast_child(ast); ast_t* reason = ast_child(reason_seq); ast_error(c->opt->check.errors, ast, "compile error: %s", ast_name(reason)); return NULL; } default: ast_error(c->opt->check.errors, ast, "not implemented (codegen unknown)"); return NULL; } if(has_scope) codegen_popscope(c); return ret; }
static LLVMValueRef assign_rvalue(compile_t* c, ast_t* left, ast_t* r_type, LLVMValueRef r_value) { switch(ast_id(left)) { case TK_SEQ: // The actual expression is inside a sequence node. while(ast_id(left) == TK_SEQ) { assert(ast_childcount(left) == 1); left = ast_child(left); } return assign_rvalue(c, left, r_type, r_value); case TK_VAR: case TK_LET: { // Generate the locals. if(gen_localdecl(c, left) == NULL) return NULL; return assign_rvalue(c, ast_child(left), r_type, r_value); } case TK_FVARREF: case TK_FLETREF: { // The result is the previous value of the field. LLVMValueRef l_value = gen_fieldptr(c, left); return assign_one(c, l_value, r_value, r_type); } case TK_EMBEDREF: { // Do nothing. The embed field was already passed as the receiver. return GEN_NOVALUE; } case TK_VARREF: { // The result is the previous value of the local. LLVMValueRef l_value = gen_localptr(c, left); return assign_one(c, l_value, r_value, r_type); } case TK_TUPLE: { // If the l_value is a tuple, assemble it as the result. LLVMValueRef result = gen_expr(c, left); if(result == NULL) return NULL; if(!assign_tuple(c, left, r_type, r_value)) return NULL; // Return the original tuple. return result; } case TK_ID: { // We may have recursed here from a VAR or LET or arrived directly. const char* name = ast_name(left); LLVMValueRef l_value = codegen_getlocal(c, name); return assign_one(c, l_value, r_value, r_type); } default: {} } assert(0); return NULL; }
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; }