static LLVMValueRef raw_is_box(compile_t* c, ast_t* left_type, LLVMValueRef l_value, LLVMValueRef r_value) { pony_assert(LLVMGetTypeKind(LLVMTypeOf(r_value)) == LLVMPointerTypeKind); LLVMValueRef r_desc = gendesc_fetch(c, r_value); LLVMValueRef same_type = gendesc_isentity(c, r_desc, left_type); pony_assert(same_type != GEN_NOVALUE); LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef value_block = codegen_block(c, "is_value"); LLVMBasicBlockRef post_block = codegen_block(c, "is_post"); LLVMBuildCondBr(c->builder, same_type, value_block, post_block); LLVMPositionBuilderAtEnd(c->builder, value_block); r_value = gen_unbox(c, left_type, r_value); LLVMValueRef is_value = gen_is_value(c, left_type, left_type, l_value, r_value); LLVMBuildBr(c->builder, post_block); value_block = LLVMGetInsertBlock(c->builder); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, ""); LLVMValueRef zero = LLVMConstInt(c->i1, 0, false); LLVMAddIncoming(phi, &is_value, &value_block, 1); LLVMAddIncoming(phi, &zero, &this_block, 1); return phi; }
static LLVMValueRef tuple_is(compile_t* c, ast_t* left_type, ast_t* right_type, LLVMValueRef l_value, LLVMValueRef r_value) { pony_assert(ast_id(left_type) == TK_TUPLETYPE); pony_assert(ast_id(right_type) == TK_TUPLETYPE); pony_assert(ast_childcount(left_type) == ast_childcount(right_type)); // Pairwise comparison. LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef post_block = codegen_block(c, "post"); // Set up the phi node. LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, ""); ast_t* left_child = ast_child(left_type); ast_t* right_child = ast_child(right_type); int i = 0; while(left_child != NULL) { // Set up the next block. LLVMBasicBlockRef next_block = codegen_block(c, "next"); LLVMPositionBuilderAtEnd(c->builder, this_block); // Test the element. LLVMValueRef l_elem = LLVMBuildExtractValue(c->builder, l_value, i, ""); LLVMValueRef r_elem = LLVMBuildExtractValue(c->builder, r_value, i, ""); LLVMValueRef test = gen_is_value(c, left_child, right_child, l_elem, r_elem); // If false, go directly to the post block. LLVMBuildCondBr(c->builder, test, next_block, post_block); LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &test, ¤t_block, 1); // Point to the next block. this_block = next_block; left_child = ast_sibling(left_child); right_child = ast_sibling(right_child); i++; } // The last block is reached if every element returns true. Jump directly to // the post block. LLVMPositionBuilderAtEnd(c->builder, this_block); LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef one = LLVMConstInt(c->i1, 1, false); LLVMAddIncoming(phi, &one, &this_block, 1); return phi; }
static LLVMValueRef gen_digestof_box(compile_t* c, reach_type_t* type, LLVMValueRef value, int boxed_subtype) { pony_assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind); LLVMBasicBlockRef box_block = NULL; LLVMBasicBlockRef nonbox_block = NULL; LLVMBasicBlockRef post_block = NULL; LLVMValueRef desc = gendesc_fetch(c, value); if((boxed_subtype & SUBTYPE_KIND_UNBOXED) != 0) { box_block = codegen_block(c, "digestof_box"); nonbox_block = codegen_block(c, "digestof_nonbox"); post_block = codegen_block(c, "digestof_post"); // Check if it's a boxed value. LLVMValueRef type_id = gendesc_typeid(c, desc); LLVMValueRef boxed_mask = LLVMConstInt(c->i32, 1, false); LLVMValueRef is_boxed = LLVMBuildAnd(c->builder, type_id, boxed_mask, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); is_boxed = LLVMBuildICmp(c->builder, LLVMIntEQ, is_boxed, zero, ""); LLVMBuildCondBr(c->builder, is_boxed, box_block, nonbox_block); LLVMPositionBuilderAtEnd(c->builder, box_block); } // Call the type-specific __digestof function, which will unbox the value. reach_method_t* digest_fn = reach_method(type, TK_BOX, stringtab("__digestof"), NULL); pony_assert(digest_fn != NULL); LLVMValueRef func = gendesc_vtable(c, desc, digest_fn->vtable_index); LLVMTypeRef fn_type = LLVMFunctionType(c->intptr, &c->object_ptr, 1, false); func = LLVMBuildBitCast(c->builder, func, LLVMPointerType(fn_type, 0), ""); LLVMValueRef box_digest = codegen_call(c, func, &value, 1, true); if((boxed_subtype & SUBTYPE_KIND_UNBOXED) != 0) { LLVMBuildBr(c->builder, post_block); // Just cast the address. LLVMPositionBuilderAtEnd(c->builder, nonbox_block); LLVMValueRef nonbox_digest = LLVMBuildPtrToInt(c->builder, value, c->intptr, ""); LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMAddIncoming(phi, &box_digest, &box_block, 1); LLVMAddIncoming(phi, &nonbox_digest, &nonbox_block, 1); return phi; } else { return box_digest; } }
LLVMValueRef gendesc_istrait(compile_t* c, LLVMValueRef desc, ast_t* type) { // Get the trait identifier. reach_type_t* t = reach_type(c->reach, type); assert(t != NULL); LLVMValueRef trait_id = LLVMConstInt(c->i32, t->type_id, false); // Read the count and the trait list from the descriptor. LLVMValueRef count = desc_field(c, desc, DESC_TRAIT_COUNT); LLVMValueRef list = desc_field(c, desc, DESC_TRAITS); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMBuildBr(c->builder, cond_block); // While the index is less than the count, check an ID. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i32, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, count, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get ID and compare it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef gep[2]; gep[0] = LLVMConstInt(c->i32, 0, false); gep[1] = phi; LLVMValueRef id_ptr = LLVMBuildInBoundsGEP(c->builder, list, gep, 2, ""); LLVMValueRef id = LLVMBuildLoad(c->builder, id_ptr, ""); LLVMValueRef test_id = LLVMBuildICmp(c->builder, LLVMIntEQ, id, trait_id, ""); // Add one to the phi node. LLVMValueRef one = LLVMConstInt(c->i32, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); LLVMAddIncoming(phi, &inc, &body_block, 1); // Either to the post block or back to the condition. LLVMBuildCondBr(c->builder, test_id, post_block, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef result = LLVMBuildPhi(c->builder, c->i1, ""); LLVMAddIncoming(result, &test, &cond_block, 1); LLVMAddIncoming(result, &test_id, &body_block, 1); return result; }
static void trace_array_elements(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object, LLVMValueRef pointer) { // Get the type argument for the array. This will be used to generate the // per-element trace call. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); if(!gentrace_needed(typearg)) return; reach_type_t* t_elem = reach_type(c->reach, typearg); pointer = LLVMBuildBitCast(c->builder, pointer, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); // Read the size. LLVMValueRef size = field_value(c, object, 1); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, trace an element. The initial // index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and trace it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, pointer, &phi, 1, "elem"); LLVMValueRef elem = LLVMBuildLoad(c->builder, elem_ptr, ""); gentrace(c, ctx, elem, typearg); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); }
SCM llvm_add_incoming(SCM scm_phi, SCM scm_value, SCM scm_block) { struct llvm_value_t *phi = get_llvm_value(scm_phi); struct llvm_value_t *value = get_llvm_value(scm_value); struct llvm_basic_block_t *block = get_llvm_basic_block(scm_block); LLVMAddIncoming(phi->value, &value->value, &block->basic_block, 1); return SCM_UNSPECIFIED; }
static LLVMValueRef translateIfThenExpr(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { ASTNode *CondNode = (ASTNode*) ptrVectorGet(&(Node->Child), 0), *ThenNode = (ASTNode*) ptrVectorGet(&(Node->Child), 1), *ElseNode = (ASTNode*) ptrVectorGet(&(Node->Child), 2); LLVMBasicBlockRef ThisBB = LLVMGetInsertBlock(Builder); LLVMValueRef ThisFn = LLVMGetBasicBlockParent(ThisBB); // Creating the BasicBlocks that will be used. LLVMBasicBlockRef TrueBB, FalseBB, EndBB; TrueBB = LLVMAppendBasicBlock(ThisFn, "if.then"); EndBB = LLVMAppendBasicBlock(ThisFn, "if.end"); if (ElseNode) FalseBB = LLVMAppendBasicBlock(ThisFn, "if.else"); else FalseBB = EndBB; // Creating the conditional branch. LLVMValueRef CondValue = translateExpr(TyTable, ValTable, CondNode); LLVMValueRef CondLoad = LLVMBuildLoad(Builder, CondValue, ""); LLVMValueRef CalcTrueFalse = LLVMBuildICmp(Builder, LLVMIntNE, CondLoad, getSConstInt(0), ""); LLVMBuildCondBr(Builder, CalcTrueFalse, TrueBB, FalseBB); // Filling the BasicBlocks. LLVMValueRef TrueValue, FalseValue; LLVMPositionBuilderAtEnd(Builder, TrueBB); TrueValue = translateExpr(TyTable, ValTable, ThenNode); LLVMBuildBr(Builder, EndBB); if (ElseNode) { LLVMPositionBuilderAtEnd(Builder, FalseBB); FalseValue = translateExpr(TyTable, ValTable, ElseNode); LLVMBuildBr(Builder, EndBB); } FalseBB = LLVMGetInsertBlock(Builder); LLVMPositionBuilderAtEnd(Builder, EndBB); if (ElseNode && LLVMGetTypeKind(LLVMTypeOf(TrueValue)) != LLVMVoidTypeKind) { LLVMValueRef PhiNode = LLVMBuildPhi(Builder, LLVMTypeOf(TrueValue), ""); // Adding incoming to phi-node. LLVMValueRef Values[] = { TrueValue, FalseValue }; LLVMBasicBlockRef Blocks[] = { TrueBB, FalseBB }; LLVMAddIncoming(PhiNode, Values, Blocks, 2); return PhiNode; } return NULL; }
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; }
static bool case_body(compile_t* c, ast_t* body, LLVMBasicBlockRef post_block, LLVMValueRef phi, LLVMTypeRef phi_type) { LLVMValueRef body_value = gen_expr(c, body); // If it returns, we don't branch to the post block. if(body_value == GEN_NOVALUE) return true; if(is_result_needed(body)) { ast_t* body_type = ast_type(body); body_value = gen_assign_cast(c, phi_type, body_value, body_type); if(body_value == NULL) return false; LLVMBasicBlockRef block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &body_value, &block, 1); } LLVMBuildBr(c->builder, post_block); return true; }
LLVMValueRef gen_while(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); AST_GET_CHILDREN(ast, cond, body, else_clause); ast_t* type = ast_type(ast); ast_t* body_type = ast_type(body); ast_t* else_type = ast_type(else_clause); reach_type_t* phi_type = NULL; if(needed && !is_control_type(type)) phi_type = reach_type(c->reach, type); LLVMBasicBlockRef init_block = codegen_block(c, "while_init"); LLVMBasicBlockRef body_block = codegen_block(c, "while_body"); LLVMBasicBlockRef else_block = codegen_block(c, "while_else"); LLVMBasicBlockRef post_block = NULL; LLVMBuildBr(c->builder, init_block); // start the post block so that a break can modify the phi node LLVMValueRef phi = GEN_NOTNEEDED; if(!is_control_type(type)) { // Start the post block so that a break can modify the phi node. post_block = codegen_block(c, "while_post"); LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) phi = LLVMBuildPhi(c->builder, phi_type->use_type, ""); } // Push the loop status. codegen_pushloop(c, init_block, post_block, else_block); // init // This jumps either to the body or the else clause. This is not evaluated // on each loop iteration: only on the first entry or after a continue. LLVMPositionBuilderAtEnd(c->builder, init_block); LLVMValueRef i_value = gen_expr(c, cond); if(i_value == NULL) return NULL; LLVMValueRef test = LLVMBuildTrunc(c->builder, i_value, c->i1, ""); LLVMBuildCondBr(c->builder, test, body_block, else_block); // Body. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef l_value = gen_expr(c, body); if(needed) l_value = gen_assign_cast(c, phi_type->use_type, l_value, body_type); if(l_value == NULL) return NULL; LLVMBasicBlockRef body_from = NULL; // If the body can't result in a value, don't generate the conditional // evaluation. This basic block for the body already has a terminator. if(l_value != GEN_NOVALUE) { // The body evaluates the condition itself, jumping either back to the body // or directly to the post block. LLVMValueRef c_value = gen_expr(c, cond); if(c_value == NULL) return NULL; body_from = LLVMGetInsertBlock(c->builder); LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); } // Don't need loop status for the else block. codegen_poploop(c); // else // If the loop doesn't generate a value (doesn't execute, or continues on the // last iteration), the else clause generates the value. LLVMPositionBuilderAtEnd(c->builder, else_block); LLVMValueRef r_value = gen_expr(c, else_clause); LLVMBasicBlockRef else_from = NULL; if(r_value != GEN_NOVALUE) { if(r_value == NULL) return NULL; if(needed) r_value = gen_assign_cast(c, phi_type->use_type, r_value, else_type); else_from = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } if(is_control_type(type)) return GEN_NOVALUE; // post LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) { if(l_value != GEN_NOVALUE) LLVMAddIncoming(phi, &l_value, &body_from, 1); if(r_value != GEN_NOVALUE) LLVMAddIncoming(phi, &r_value, &else_from, 1); return phi; } return GEN_NOTNEEDED; }
static LLVMValueRef get_stritem_len_fn(struct llvm_ctx *ctx) { if(ctx->stritem_len_fn != NULL) return ctx->stritem_len_fn; /* returns (i32 len, i32 new_tpos) * params (word *utcbptr, i32 tpos) * * when return value "new_tpos" > tmax + 1, the result is invalid. the function * should also not be called when tpos > tmax + 1. */ LLVMTypeRef ret_types[2] = { ctx->i32t, ctx->i32t }, parm_types[2] = { LLVMPointerType(ctx->wordt, 0), ctx->i32t }, ret_type = LLVMStructTypeInContext(ctx->ctx, ret_types, 2, 0), fn_type = LLVMFunctionType(ret_type, parm_types, 2, 0); LLVMValueRef fn = LLVMAddFunction(ctx->module, "__muidl_get_stritem_len", fn_type); LLVMSetVisibility(fn, LLVMHiddenVisibility); LLVMSetLinkage(fn, LLVMInternalLinkage); V fn_args[2]; LLVMGetParams(fn, fn_args); LLVMAddAttribute(fn_args[0], LLVMNoCaptureAttribute); for(int i=0; i<2; i++) { LLVMAddAttribute(fn_args[i], LLVMInRegAttribute); } ctx->stritem_len_fn = fn; LLVMBuilderRef old_builder = ctx->builder; ctx->builder = LLVMCreateBuilderInContext(ctx->ctx); LLVMBasicBlockRef entry_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "EntryBlock"), loop_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "loop"), valid_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "valid"), exit_bb = LLVMAppendBasicBlockInContext(ctx->ctx, fn, "exit"); LLVMPositionBuilderAtEnd(ctx->builder, entry_bb); LLVMValueRef old_utcb = ctx->utcb, old_tpos = ctx->tpos; ctx->utcb = fn_args[0]; ctx->tpos = fn_args[1]; LLVMBuildBr(ctx->builder, loop_bb); LLVMPositionBuilderAtEnd(ctx->builder, exit_bb); LLVMValueRef exit_len_phi = LLVMBuildPhi(ctx->builder, ctx->i32t, "exit.len.phi"), exit_tpos_phi = LLVMBuildPhi(ctx->builder, ctx->i32t, "exit.tpos.phi"); LLVMValueRef rvals[2] = { exit_len_phi, exit_tpos_phi }; LLVMBuildAggregateRet(ctx->builder, rvals, 2); LLVMPositionBuilderAtEnd(ctx->builder, loop_bb); LLVMValueRef len_phi = LLVMBuildPhi(ctx->builder, ctx->i32t, "len.phi"), tpos_phi = LLVMBuildPhi(ctx->builder, ctx->i32t, "tpos.phi"); LLVMAddIncoming(len_phi, &ctx->zero, &entry_bb, 1); LLVMAddIncoming(tpos_phi, &ctx->tpos, &entry_bb, 1); ctx->tpos = tpos_phi; /* test: if *tpos doesn't look like a string item, conk out. */ LLVMValueRef infoword = build_utcb_load(ctx, ctx->tpos, "si.info"); LLVMValueRef is_cond = LLVMBuildICmp(ctx->builder, LLVMIntEQ, ctx->zero, LLVMBuildAnd(ctx->builder, infoword, CONST_WORD(1 << 4), "infoword.si.mask"), "infoword.si.cond"); /* anything + 100 is sure to be > tmax + 1. */ LLVMValueRef fucked_tpos = LLVMBuildAdd(ctx->builder, tpos_phi, CONST_INT(100), "f****d.tpos"); branch_set_phi(ctx, exit_len_phi, len_phi); branch_set_phi(ctx, exit_tpos_phi, fucked_tpos); LLVMBuildCondBr(ctx->builder, is_cond, valid_bb, exit_bb); LLVMPositionBuilderAtEnd(ctx->builder, valid_bb); LLVMValueRef string_length = LLVMBuildTruncOrBitCast(ctx->builder, LLVMBuildLShr(ctx->builder, infoword, CONST_INT(10), "si.info.len"), ctx->i32t, "si.info.len.int"), string_j = LLVMBuildTruncOrBitCast(ctx->builder, LLVMBuildAnd(ctx->builder, CONST_WORD(0x1f), LLVMBuildLShr(ctx->builder, infoword, CONST_WORD(4), "si.info.j.shift"), "si.info.j.masked"), ctx->i32t, "si.info.j"), string_c = LLVMBuildTruncOrBitCast(ctx->builder, LLVMBuildAnd(ctx->builder, CONST_WORD(1 << 9), infoword, "si.info.c.masked"), ctx->i32t, "si.info.c.masked.int"), c_cond = LLVMBuildICmp(ctx->builder, LLVMIntNE, string_c, CONST_WORD(0), "si.info.c.cond"), new_len = LLVMBuildAdd(ctx->builder, len_phi, LLVMBuildMul(ctx->builder, string_length, LLVMBuildAdd(ctx->builder, string_j, CONST_INT(1), "j.plus.one"), "len.incr"), "len.new"), new_tpos = LLVMBuildAdd(ctx->builder, ctx->tpos, LLVMBuildSelect(ctx->builder, c_cond, LLVMBuildAdd(ctx->builder, CONST_INT(2), string_j, "cont.tpos.bump"), CONST_INT(2), "tpos.bump"), "tpos.new"); LLVMAddIncoming(len_phi, &new_len, &valid_bb, 1); LLVMAddIncoming(tpos_phi, &new_tpos, &valid_bb, 1); LLVMAddIncoming(exit_len_phi, &new_len, &valid_bb, 1); LLVMAddIncoming(exit_tpos_phi, &new_tpos, &valid_bb, 1); LLVMBuildCondBr(ctx->builder, c_cond, loop_bb, exit_bb); LLVMDisposeBuilder(ctx->builder); ctx->builder = old_builder; ctx->utcb = old_utcb; ctx->tpos = old_tpos; return ctx->stritem_len_fn; }
LLVMValueRef gen_if(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); ast_t* type = ast_type(ast); AST_GET_CHILDREN(ast, cond, left, right); ast_t* left_type = ast_type(left); ast_t* right_type = ast_type(right); // We will have no type if both branches have return statements. reach_type_t* phi_type = NULL; if(!is_control_type(type)) phi_type = reach_type(c->reach, type); LLVMValueRef c_value = gen_expr(c, cond); if(c_value == NULL) return NULL; // If the conditional is constant, generate only one branch. bool gen_left = true; bool gen_right = true; if(LLVMIsAConstantInt(c_value)) { int value = (int)LLVMConstIntGetZExtValue(c_value); if(value == 0) gen_left = false; else gen_right = false; } LLVMBasicBlockRef then_block = codegen_block(c, "if_then"); LLVMBasicBlockRef else_block = codegen_block(c, "if_else"); LLVMBasicBlockRef post_block = NULL; // If both branches return, we have no post block. if(!is_control_type(type)) post_block = codegen_block(c, "if_post"); LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, ""); LLVMBuildCondBr(c->builder, test, then_block, else_block); // Left branch. LLVMPositionBuilderAtEnd(c->builder, then_block); LLVMValueRef l_value; if(gen_left) { l_value = gen_expr(c, left); } else if(phi_type != NULL) { l_value = LLVMConstNull(phi_type->use_type); } else { LLVMBuildUnreachable(c->builder); l_value = GEN_NOVALUE; } if(l_value != GEN_NOVALUE) { if(needed) l_value = gen_assign_cast(c, phi_type->use_type, l_value, left_type); if(l_value == NULL) return NULL; then_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } // Right branch. LLVMPositionBuilderAtEnd(c->builder, else_block); LLVMValueRef r_value; if(gen_right) { r_value = gen_expr(c, right); } else if(phi_type != NULL) { r_value = LLVMConstNull(phi_type->use_type); } else { LLVMBuildUnreachable(c->builder); r_value = GEN_NOVALUE; } // If the right side returns, we don't branch to the post block. if(r_value != GEN_NOVALUE) { if(needed) r_value = gen_assign_cast(c, phi_type->use_type, r_value, right_type); if(r_value == NULL) return NULL; else_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } // If both sides return, we return a sentinal value. if(is_control_type(type)) return GEN_NOVALUE; // Continue in the post block. LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) { LLVMValueRef phi = LLVMBuildPhi(c->builder, phi_type->use_type, ""); if(l_value != GEN_NOVALUE) LLVMAddIncoming(phi, &l_value, &then_block, 1); if(r_value != GEN_NOVALUE) LLVMAddIncoming(phi, &r_value, &else_block, 1); return phi; } return GEN_NOTNEEDED; }
LLVMValueRef make_divmod(compile_t* c, ast_t* left, ast_t* right, const_binop const_f, const_binop const_ui, const_binop const_si, build_binop build_f, build_binop build_ui, build_binop build_si) { ast_t* type = ast_type(left); bool sign = is_signed(c->opt, type); LLVMValueRef l_value = gen_expr(c, left); LLVMValueRef r_value = gen_expr(c, right); if((l_value == NULL) || (r_value == NULL)) return NULL; if(!is_fp(r_value) && LLVMIsConstant(r_value) && (LLVMConstIntGetSExtValue(r_value) == 0) ) { ast_error(right, "constant divide or mod by zero"); return NULL; } if(LLVMIsConstant(l_value) && LLVMIsConstant(r_value)) { if(is_fp(l_value)) return const_f(l_value, r_value); if(sign) return const_si(l_value, r_value); return const_ui(l_value, r_value); } if(is_fp(l_value)) return build_f(c->builder, l_value, r_value, ""); // Setup additional blocks. LLVMBasicBlockRef insert = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef then_block = codegen_block(c, "div_then"); LLVMBasicBlockRef post_block = codegen_block(c, "div_post"); // Check for div by zero. LLVMTypeRef r_type = LLVMTypeOf(r_value); LLVMValueRef zero = LLVMConstInt(r_type, 0, false); LLVMValueRef cmp = LLVMBuildICmp(c->builder, LLVMIntNE, r_value, zero, ""); LLVMBuildCondBr(c->builder, cmp, then_block, post_block); // Divisor is not zero. LLVMPositionBuilderAtEnd(c->builder, then_block); LLVMValueRef result; if(sign) result = build_si(c->builder, l_value, r_value, ""); else result = build_ui(c->builder, l_value, r_value, ""); LLVMBuildBr(c->builder, post_block); // Phi node. LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, r_type, ""); LLVMAddIncoming(phi, &zero, &insert, 1); LLVMAddIncoming(phi, &result, &then_block, 1); return phi; }
LLVMValueRef gen_try(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); AST_GET_CHILDREN(ast, body, else_clause, then_clause); ast_t* type = ast_type(ast); ast_t* body_type = ast_type(body); ast_t* else_type = ast_type(else_clause); reach_type_t* phi_type = NULL; // We will have no type if both branches have return statements. if(!is_control_type(type)) phi_type = reach_type(c->reach, type); LLVMBasicBlockRef block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef else_block = codegen_block(c, "try_else"); LLVMBasicBlockRef post_block = NULL; if(!is_control_type(type)) post_block = codegen_block(c, "try_post"); // Keep a reference to the else block. codegen_pushtry(c, else_block); // Body block. LLVMPositionBuilderAtEnd(c->builder, block); LLVMValueRef body_value = gen_expr(c, body); if(body_value != GEN_NOVALUE) { if(needed) { body_value = gen_assign_cast(c, phi_type->use_type, body_value, body_type); } if(body_value == NULL) return NULL; gen_expr(c, then_clause); block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } // Pop the try before generating the else block. codegen_poptry(c); // Else block. LLVMPositionBuilderAtEnd(c->builder, else_block); // The landing pad is marked as a cleanup, since exceptions are typeless and // valueless. The first landing pad is always the destination. LLVMTypeRef lp_elements[2]; lp_elements[0] = c->void_ptr; lp_elements[1] = c->i32; LLVMTypeRef lp_type = LLVMStructTypeInContext(c->context, lp_elements, 2, false); #if PONY_LLVM == 307 && LLVM_VERSION_PATCH == 0 // This backwards-incompatible API change to LLVMBuildLandingPad is only in // LLVM 3.7.0. In 3.7.1 and all later versions, backward-compatibility was // restored. assert((c->frame->fun != NULL) && "No function in current frame!"); LLVMSetPersonalityFn(c->frame->fun, c->personality); LLVMValueRef landing = LLVMBuildLandingPad(c->builder, lp_type, 1, ""); #else LLVMValueRef landing = LLVMBuildLandingPad(c->builder, lp_type, c->personality, 1, ""); #endif LLVMAddClause(landing, LLVMConstNull(c->void_ptr)); LLVMValueRef else_value = gen_expr(c, else_clause); if(else_value != GEN_NOVALUE) { if(needed) { else_value = gen_assign_cast(c, phi_type->use_type, else_value, else_type); } if(else_value == NULL) return NULL; gen_expr(c, then_clause); else_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } // If both sides return, we return a sentinal value. if(is_control_type(type)) return GEN_NOVALUE; // Continue in the post block. LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) { LLVMValueRef phi = LLVMBuildPhi(c->builder, phi_type->use_type, ""); if(body_value != GEN_NOVALUE) LLVMAddIncoming(phi, &body_value, &block, 1); if(else_value != GEN_NOVALUE) LLVMAddIncoming(phi, &else_value, &else_block, 1); return phi; } return GEN_NOTNEEDED; }
void genprim_array_deserialise(compile_t* c, reach_type_t* t) { // Generate the deserisalise function. t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name), c->trace_type); codegen_startfun(c, t->deserialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); gendeserialise_typeid(c, t, object); // Deserialise the array contents. LLVMValueRef alloc = field_value(c, object, 2); LLVMValueRef ptr_offset = field_value(c, object, 3); ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, ""); ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr_offset; args[2] = LLVMBuildMul(c->builder, alloc, l_size, ""); LLVMValueRef ptr = gencall_runtime(c, "pony_deserialise_block", args, 3, ""); LLVMValueRef ptr_loc = LLVMBuildStructGEP(c->builder, object, 3, ""); LLVMBuildStore(c->builder, ptr, ptr_loc); if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL)) { // Do nothing. A memcpy is sufficient. } else { LLVMValueRef size = field_value(c, object, 1); ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, deserialise an element. The // initial index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and deserialise it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, ""); gendeserialise_element(c, t_elem, false, ctx, elem_ptr); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
LLVMValueRef make_short_circuit(compile_t* c, ast_t* left, ast_t* right, bool is_and) { LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef left_block = codegen_block(c, "sc_left"); LLVMValueRef branch = LLVMBuildBr(c->builder, left_block); LLVMPositionBuilderAtEnd(c->builder, left_block); LLVMValueRef l_value = gen_expr(c, left); if(l_value == NULL) return NULL; if(is_constant_i1(c, l_value)) { LLVMInstructionEraseFromParent(branch); LLVMDeleteBasicBlock(left_block); LLVMPositionBuilderAtEnd(c->builder, entry_block); if(is_and) { if(is_always_false(c, l_value)) return gen_expr(c, left); } else { if(is_always_true(c, l_value)) return gen_expr(c, left); } return gen_expr(c, right); } LLVMBasicBlockRef left_exit_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef right_block = codegen_block(c, "sc_right"); LLVMBasicBlockRef post_block = codegen_block(c, "sc_post"); if(is_and) LLVMBuildCondBr(c->builder, l_value, right_block, post_block); else LLVMBuildCondBr(c->builder, l_value, post_block, right_block); LLVMPositionBuilderAtEnd(c->builder, right_block); LLVMValueRef r_value = gen_expr(c, right); if(r_value == NULL) return NULL; LLVMBasicBlockRef right_exit_block = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, ""); LLVMAddIncoming(phi, &l_value, &left_exit_block, 1); LLVMAddIncoming(phi, &r_value, &right_exit_block, 1); if(is_constant_i1(c, r_value)) { if(is_and) { if(is_always_false(c, r_value)) return r_value; } else { if(is_always_true(c, r_value)) return r_value; } return l_value; } return phi; }
void genprim_array_serialise(compile_t* c, reach_type_t* t) { // Generate the serialise function. t->serialise_fn = codegen_addfun(c, genname_serialise(t->name), c->serialise_type); codegen_startfun(c, t->serialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->serialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_fn, 1); LLVMValueRef addr = LLVMGetParam(t->serialise_fn, 2); LLVMValueRef offset = LLVMGetParam(t->serialise_fn, 3); LLVMValueRef mut = LLVMGetParam(t->serialise_fn, 4); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); LLVMValueRef offset_addr = LLVMBuildAdd(c->builder, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), offset, ""); genserialise_typeid(c, t, offset_addr); // Don't serialise our contents if we are opaque. LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntNE, mut, LLVMConstInt(c->i32, PONY_TRACE_OPAQUE, false), ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); LLVMPositionBuilderAtEnd(c->builder, body_block); // Write the size twice, effectively rewriting alloc to be the same as size. LLVMValueRef size = field_value(c, object, 1); LLVMValueRef size_loc = field_loc(c, offset_addr, t->structure, c->intptr, 1); LLVMBuildStore(c->builder, size, size_loc); LLVMValueRef alloc_loc = field_loc(c, offset_addr, t->structure, c->intptr, 2); LLVMBuildStore(c->builder, size, alloc_loc); // Write the pointer. LLVMValueRef ptr = field_value(c, object, 3); // The resulting offset will only be invalid (i.e. have the high bit set) if // the size is zero. For an opaque array, we don't serialise the contents, // so we don't get here, so we don't end up with an invalid offset. LLVMValueRef args[5]; args[0] = ctx; args[1] = ptr; LLVMValueRef ptr_offset = gencall_runtime(c, "pony_serialise_offset", args, 2, ""); LLVMValueRef ptr_loc = field_loc(c, offset_addr, t->structure, c->intptr, 3); LLVMBuildStore(c->builder, ptr_offset, ptr_loc); LLVMValueRef ptr_offset_addr = LLVMBuildAdd(c->builder, ptr_offset, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), ""); // Serialise elements. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false); if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL)) { // memcpy machine words args[0] = LLVMBuildIntToPtr(c->builder, ptr_offset_addr, c->void_ptr, ""); args[1] = LLVMBuildBitCast(c->builder, ptr, c->void_ptr, ""); args[2] = LLVMBuildMul(c->builder, size, l_size, ""); args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i64", args, 5, ""); } } else { ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMValueRef offset_var = LLVMBuildAlloca(c->builder, c->intptr, ""); LLVMBuildStore(c->builder, ptr_offset_addr, offset_var); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, serialise an element. The // initial index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and serialise it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, ""); ptr_offset_addr = LLVMBuildLoad(c->builder, offset_var, ""); genserialise_element(c, t_elem, false, ctx, elem_ptr, ptr_offset_addr); ptr_offset_addr = LLVMBuildAdd(c->builder, ptr_offset_addr, l_size, ""); LLVMBuildStore(c->builder, ptr_offset_addr, offset_var); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); } LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
static LLVMValueRef box_is_box(compile_t* c, ast_t* left_type, LLVMValueRef l_value, LLVMValueRef r_value, int possible_boxes) { pony_assert(LLVMGetTypeKind(LLVMTypeOf(l_value)) == LLVMPointerTypeKind); pony_assert(LLVMGetTypeKind(LLVMTypeOf(r_value)) == LLVMPointerTypeKind); LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef checkbox_block = codegen_block(c, "is_checkbox"); LLVMBasicBlockRef box_block = codegen_block(c, "is_box"); LLVMBasicBlockRef num_block = NULL; if((possible_boxes & BOXED_SUBTYPES_NUMERIC) != 0) num_block = codegen_block(c, "is_num"); LLVMBasicBlockRef tuple_block = NULL; if((possible_boxes & BOXED_SUBTYPES_TUPLE) != 0) tuple_block = codegen_block(c, "is_tuple"); LLVMBasicBlockRef post_block = codegen_block(c, "is_post"); LLVMValueRef eq_addr = LLVMBuildICmp(c->builder, LLVMIntEQ, l_value, r_value, ""); LLVMBuildCondBr(c->builder, eq_addr, post_block, checkbox_block); // Check whether we have two boxed objects of the same type. LLVMPositionBuilderAtEnd(c->builder, checkbox_block); LLVMValueRef l_desc = gendesc_fetch(c, l_value); LLVMValueRef r_desc = gendesc_fetch(c, r_value); LLVMValueRef same_type = LLVMBuildICmp(c->builder, LLVMIntEQ, l_desc, r_desc, ""); LLVMValueRef l_typeid = NULL; if((possible_boxes & BOXED_SUBTYPES_UNBOXED) != 0) { l_typeid = gendesc_typeid(c, l_value); LLVMValueRef boxed_mask = LLVMConstInt(c->i32, 1, false); LLVMValueRef left_boxed = LLVMBuildAnd(c->builder, l_typeid, boxed_mask, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); left_boxed = LLVMBuildICmp(c->builder, LLVMIntEQ, left_boxed, zero, ""); LLVMValueRef both_boxed = LLVMBuildAnd(c->builder, same_type, left_boxed, ""); LLVMBuildCondBr(c->builder, both_boxed, box_block, post_block); } else { LLVMBuildCondBr(c->builder, same_type, box_block, post_block); } // Check whether it's a numeric primitive or a tuple. LLVMPositionBuilderAtEnd(c->builder, box_block); if((possible_boxes & BOXED_SUBTYPES_BOXED) == BOXED_SUBTYPES_BOXED) { if(l_typeid == NULL) l_typeid = gendesc_typeid(c, l_value); LLVMValueRef num_mask = LLVMConstInt(c->i32, 2, false); LLVMValueRef boxed_num = LLVMBuildAnd(c->builder, l_typeid, num_mask, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); boxed_num = LLVMBuildICmp(c->builder, LLVMIntEQ, boxed_num, zero, ""); LLVMBuildCondBr(c->builder, boxed_num, num_block, tuple_block); } else if((possible_boxes & BOXED_SUBTYPES_NUMERIC) != 0) { LLVMBuildBr(c->builder, num_block); } else { pony_assert((possible_boxes & BOXED_SUBTYPES_TUPLE) != 0); LLVMBuildBr(c->builder, tuple_block); } LLVMValueRef args[3]; LLVMValueRef is_num = NULL; if(num_block != NULL) { // Get the machine word size and memcmp without unboxing. LLVMPositionBuilderAtEnd(c->builder, num_block); if(l_typeid == NULL) l_typeid = gendesc_typeid(c, l_value); LLVMValueRef num_sizes = LLVMBuildBitCast(c->builder, c->numeric_sizes, c->void_ptr, ""); args[0] = LLVMBuildZExt(c->builder, l_typeid, c->intptr, ""); LLVMValueRef size = LLVMBuildInBoundsGEP(c->builder, num_sizes, args, 1, ""); size = LLVMBuildBitCast(c->builder, size, LLVMPointerType(c->i32, 0), ""); size = LLVMBuildLoad(c->builder, size, ""); LLVMSetAlignment(size, 4); LLVMValueRef one = LLVMConstInt(c->i32, 1, false); args[0] = LLVMBuildInBoundsGEP(c->builder, l_value, &one, 1, ""); args[0] = LLVMBuildBitCast(c->builder, args[0], c->void_ptr, ""); args[1] = LLVMBuildInBoundsGEP(c->builder, r_value, &one, 1, ""); args[1] = LLVMBuildBitCast(c->builder, args[1], c->void_ptr, ""); args[2] = LLVMBuildZExt(c->builder, size, c->intptr, ""); is_num = gencall_runtime(c, "memcmp", args, 3, ""); is_num = LLVMBuildICmp(c->builder, LLVMIntEQ, is_num, LLVMConstInt(c->i32, 0, false), ""); LLVMBuildBr(c->builder, post_block); } LLVMValueRef is_tuple = NULL; if(tuple_block != NULL) { // Call the type-specific __is function, which will unbox the tuples. LLVMPositionBuilderAtEnd(c->builder, tuple_block); reach_type_t* r_left = reach_type(c->reach, left_type); reach_method_t* is_fn = reach_method(r_left, TK_BOX, stringtab("__is"), NULL); pony_assert(is_fn != NULL); LLVMValueRef func = gendesc_vtable(c, l_value, is_fn->vtable_index); LLVMTypeRef params[2]; params[0] = c->object_ptr; params[1] = c->object_ptr; LLVMTypeRef type = LLVMFunctionType(c->i1, params, 2, false); func = LLVMBuildBitCast(c->builder, func, LLVMPointerType(type, 0), ""); args[0] = l_value; args[1] = r_value; is_tuple = codegen_call(c, func, args, 2); LLVMBuildBr(c->builder, post_block); } LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, ""); LLVMValueRef one = LLVMConstInt(c->i1, 1, false); LLVMValueRef zero = LLVMConstInt(c->i1, 0, false); LLVMAddIncoming(phi, &one, &this_block, 1); if(is_num != NULL) LLVMAddIncoming(phi, &is_num, &num_block, 1); if(is_tuple != NULL) LLVMAddIncoming(phi, &is_tuple, &tuple_block, 1); LLVMAddIncoming(phi, &zero, &checkbox_block, 1); return phi; }
/// Try and compile a fragment starting at the specified address. Returns /// true if successful setting \a nextAddress to the first instruction after /// the fragment. If unsuccessful returns false and sets \a nextAddress to the /// address after the current function. \a endOfBlock is set to true if the /// next address is in a new basic block. bool JITImpl:: compileOneFragment(Core &core, JITCoreInfo &coreInfo, uint32_t startPc, bool &endOfBlock, uint32_t &pcAfterFragment) { assert(initialized); resetPerFunctionState(); std::map<uint32_t,JITFunctionInfo*>::iterator infoIt = coreInfo.functionMap.find(startPc); JITFunctionInfo *info = (infoIt == coreInfo.functionMap.end()) ? 0 : infoIt->second; if (info && !info->isStub) { endOfBlock = true; return false; } std::vector<InstructionOpcode> opcode; std::vector<Operands> operands; if (!getFragmentToCompile(core, startPc, opcode, operands, endOfBlock, pcAfterFragment)) { return false; } std::queue<std::pair<uint32_t,MemoryCheck*> > checks; placeMemoryChecks(opcode, operands, checks); LLVMValueRef f; if (info) { f = info->value; info->func = 0; info->isStub = false; deleteFunctionBody(f); } else { info = new JITFunctionInfo(startPc); coreInfo.functionMap.insert(std::make_pair(startPc, info)); // Create function to contain the code we are about to add. info->value = f = LLVMAddFunction(module, "", jitFunctionType); LLVMSetFunctionCallConv(f, LLVMFastCallConv); } threadParam = LLVMGetParam(f, 0); LLVMValueRef ramBase = LLVMConstInt(LLVMInt32Type(), core.ram_base, false); ramSizeLog2Param = LLVMConstInt(LLVMInt32Type(), core.ramSizeLog2, false); LLVMBasicBlockRef entryBB = LLVMAppendBasicBlock(f, "entry"); LLVMPositionBuilderAtEnd(builder, entryBB); uint32_t pc = startPc; bool needsReturn = true; for (unsigned i = 0, e = opcode.size(); i != e; ++i) { InstructionOpcode opc = opcode[i]; const Operands &ops = operands[i]; InstructionProperties *properties = &instructionProperties[opc]; uint32_t nextPc = pc + properties->size / 2; emitMemoryChecks(i, checks); // Lookup function to call. LLVMValueRef callee = LLVMGetNamedFunction(module, properties->function); assert(callee && "Function for instruction not found in module"); LLVMTypeRef calleeType = LLVMGetElementType(LLVMTypeOf(callee)); const unsigned fixedArgs = 4; const unsigned maxOperands = 6; unsigned numArgs = properties->getNumExplicitOperands() + fixedArgs; assert(LLVMCountParamTypes(calleeType) == numArgs); LLVMTypeRef paramTypes[fixedArgs + maxOperands]; assert(numArgs <= (fixedArgs + maxOperands)); LLVMGetParamTypes(calleeType, paramTypes); // Build call. LLVMValueRef args[fixedArgs + maxOperands]; args[0] = threadParam; args[1] = LLVMConstInt(paramTypes[1], nextPc, false); args[2] = ramBase; args[3] = ramSizeLog2Param; for (unsigned i = fixedArgs; i < numArgs; i++) { uint32_t value = properties->getNumExplicitOperands() <= 3 ? ops.ops[i - fixedArgs] : ops.lops[i - fixedArgs]; args[i] = LLVMConstInt(paramTypes[i], value, false); } LLVMValueRef call = emitCallToBeInlined(callee, args, numArgs); checkReturnValue(call, *properties); if (properties->mayBranch() && properties->function && emitJumpToNextFragment(opc, ops, coreInfo, nextPc, info)) { needsReturn = false; } pc = nextPc; } assert(checks.empty() && "Not all checks emitted"); if (needsReturn) { LLVMValueRef args[] = { threadParam }; emitCallToBeInlined(functions.jitUpdateExecutionFrequency, args, 1); // Build return. LLVMBuildRet(builder, LLVMConstInt(LLVMGetReturnType(jitFunctionType), JIT_RETURN_CONTINUE, 0)); } // Add incoming phi values. if (earlyReturnBB) { LLVMAddIncoming(earlyReturnPhi, &earlyReturnIncomingValues[0], &earlyReturnIncomingBlocks[0], earlyReturnIncomingValues.size()); } if (DEBUG_JIT) { LLVMDumpValue(f); LLVMVerifyFunction(f, LLVMAbortProcessAction); } // Optimize. for (std::vector<LLVMValueRef>::iterator it = calls.begin(), e = calls.end(); it != e; ++it) { LLVMExtraInlineFunction(*it); } LLVMRunFunctionPassManager(FPM, f); if (DEBUG_JIT) { LLVMDumpValue(f); } // Compile. JITInstructionFunction_t compiledFunction = reinterpret_cast<JITInstructionFunction_t>( LLVMRecompileAndRelinkFunction(executionEngine, f)); info->isStub = false; info->func = compiledFunction; core.setOpcode(startPc, getFunctionThunk(*info), (pc - startPc) * 2); return true; }
LLVMValueRef gen_repeat(compile_t* c, ast_t* ast) { bool needed = is_result_needed(ast); AST_GET_CHILDREN(ast, body, cond, else_clause); ast_t* type = ast_type(ast); ast_t* body_type = ast_type(body); ast_t* else_type = ast_type(else_clause); reach_type_t* phi_type = NULL; if(needed && !is_control_type(type)) phi_type = reach_type(c->reach, type); LLVMBasicBlockRef body_block = codegen_block(c, "repeat_body"); LLVMBasicBlockRef cond_block = codegen_block(c, "repeat_cond"); LLVMBasicBlockRef else_block = codegen_block(c, "repeat_else"); LLVMBasicBlockRef post_block = NULL; LLVMBuildBr(c->builder, body_block); // start the post block so that a break can modify the phi node LLVMValueRef phi = GEN_NOTNEEDED; if(!is_control_type(type)) { // Start the post block so that a break can modify the phi node. post_block = codegen_block(c, "repeat_post"); LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) phi = LLVMBuildPhi(c->builder, phi_type->use_type, ""); } // Push the loop status. codegen_pushloop(c, cond_block, post_block, else_block); // Body. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef value = gen_expr(c, body); if(needed) value = gen_assign_cast(c, phi_type->use_type, value, body_type); if(value == NULL) return NULL; LLVMBasicBlockRef body_from = NULL; // If the body can't result in a value, don't generate the conditional // evaluation. This basic block for the body already has a terminator. if(value != GEN_NOVALUE) { // The body evaluates the condition itself, jumping either back to the body // or directly to the post block. LLVMValueRef c_value = gen_expr(c, cond); if(c_value == NULL) return NULL; body_from = LLVMGetInsertBlock(c->builder); LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, ""); LLVMBuildCondBr(c->builder, test, post_block, body_block); } // cond block // This is only evaluated from a continue, jumping either back to the body // or to the else block. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef i_value = gen_expr(c, cond); LLVMValueRef test = LLVMBuildTrunc(c->builder, i_value, c->i1, ""); LLVMBuildCondBr(c->builder, test, else_block, body_block); // Don't need loop status for the else block. codegen_poploop(c); // else // Only happens for a continue in the last iteration. LLVMPositionBuilderAtEnd(c->builder, else_block); LLVMValueRef else_value = gen_expr(c, else_clause); LLVMBasicBlockRef else_from = NULL; if(else_value == NULL) return NULL; if(needed) else_value = gen_assign_cast(c, phi_type->use_type, else_value, else_type); if(else_value != GEN_NOVALUE) { else_from = LLVMGetInsertBlock(c->builder); LLVMBuildBr(c->builder, post_block); } if(is_control_type(type)) return GEN_NOVALUE; // post LLVMPositionBuilderAtEnd(c->builder, post_block); if(needed) { if(value != GEN_NOVALUE) LLVMAddIncoming(phi, &value, &body_from, 1); if(else_value != GEN_NOVALUE) LLVMAddIncoming(phi, &else_value, &else_from, 1); return phi; } return GEN_NOTNEEDED; }
void Build::visit_select(ast::Select& x) { // Get the current LLVM block and function auto current_block = LLVMGetInsertBlock(_ctx.irb); auto current_fn = LLVMGetBasicBlockParent(current_block); std::vector<LLVMBasicBlockRef> blocks; std::vector<LLVMValueRef> values; std::vector<LLVMBasicBlockRef> value_blocks; // Resolve the type of us (in full; only used if we have a value) auto type = Resolve(_scope).run(x); // A Select expression has a value IIF it has an else and // each of its branches have a value bool has_value = !!type; auto do_select_branch = [&](ast::Block& block) -> bool { // Build the block auto value = Build(_ctx, _scope).run_scalar(block); auto iblock = LLVMGetInsertBlock(_ctx.irb); if (has_value && value && !value->type.is<code::TypeNone>()) { // Cast the value to the type analyzed result value = util::cast(_ctx, value, block, type, false); if (!value) return false; // Append to the value chain values.push_back(value->get_value(_ctx)); value_blocks.push_back(iblock); } else if (!LLVMGetBasicBlockTerminator(iblock)) { // This block wasn't terminated and it has no value // We no longer have a value has_value = false; } // Append to the block chain blocks.push_back(iblock); return true; }; // Iterate through each branch and build its contained block .. for (auto& br : x.branches) { // Build the condition expression auto cond = Build(_ctx, _scope).run_scalar(*br->condition); if (!cond) return; // Create the THEN and NEXT LLVM blocks auto then_block = LLVMAppendBasicBlock(current_fn, "select-then"); auto next_block = LLVMAppendBasicBlock(current_fn, "select-next"); // Build the conditional branch LLVMBuildCondBr(_ctx.irb, cond->get_value(_ctx), then_block, next_block); // Activate the THEN block LLVMPositionBuilderAtEnd(_ctx.irb, then_block); // Process the branch .. if (!do_select_branch(*br->block)) return; // Insert the `next` block after our current block. LLVMMoveBasicBlockAfter(next_block, LLVMGetInsertBlock(_ctx.irb)); // Replace the outer-block with our new "merge" block. LLVMPositionBuilderAtEnd(_ctx.irb, next_block); } // Check for and build the else_block LLVMBasicBlockRef merge_block; if (x.else_block) { // Process the branch .. do_select_branch(*x.else_block); // Create the final "merge" block merge_block = LLVMAppendBasicBlock(current_fn, "select-merge"); } else { // Use the elided "else" block as the "merge" block merge_block = LLVMGetLastBasicBlock(current_fn); } // Iterate through the established branches and have them return to // the "merge" block (if they are not otherwise terminated). unsigned term = 0; for (auto& ib : blocks) { if (!LLVMGetBasicBlockTerminator(ib)) { // Insert the non-conditional branch. LLVMPositionBuilderAtEnd(_ctx.irb, ib); LLVMBuildBr(_ctx.irb, merge_block); } else { term += 1; } } // If all blocks were terminated and there is an ELSE present; // remove the merge block if (term == blocks.size() && x.else_block) { LLVMDeleteBasicBlock(merge_block); } // Re-establish our insertion point. LLVMPositionBuilderAtEnd(_ctx.irb, merge_block); // If we still have a value .. if (has_value && values.size() > 0) { // Make the PHI value auto res = LLVMBuildPhi(_ctx.irb, type->handle(), ""); LLVMAddIncoming(res, values.data(), value_blocks.data(), values.size()); Ref<code::Value> res_value = new code::Value(res, type); _stack.push_front(res_value); } }