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; }
void genprim_string_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, and rewrite alloc to be size + 1. 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 = LLVMBuildAdd(c->builder, size, LLVMConstInt(c->intptr, 1, false), ""); LLVMValueRef alloc_loc = field_loc(c, offset_addr, t->structure, c->intptr, 2); LLVMBuildStore(c->builder, alloc, alloc_loc); // Write the pointer. LLVMValueRef ptr = field_value(c, object, 3); 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); // Serialise the string contents. LLVMValueRef ptr_offset_addr = LLVMBuildAdd(c->builder, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), ptr_offset, ""); args[0] = LLVMBuildIntToPtr(c->builder, ptr_offset_addr, c->void_ptr, ""); args[1] = LLVMBuildBitCast(c->builder, field_value(c, object, 3), c->void_ptr, ""); args[2] = alloc; 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, ""); } LLVMBuildBr(c->builder, post_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); }
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); }
/* * Create a function that deforms a tuple of type desc up to natts columns. */ LLVMValueRef slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts) { char *funcname; LLVMModuleRef mod; LLVMBuilderRef b; LLVMTypeRef deform_sig; LLVMValueRef v_deform_fn; LLVMBasicBlockRef b_entry; LLVMBasicBlockRef b_adjust_unavail_cols; LLVMBasicBlockRef b_find_start; LLVMBasicBlockRef b_out; LLVMBasicBlockRef b_dead; LLVMBasicBlockRef *attcheckattnoblocks; LLVMBasicBlockRef *attstartblocks; LLVMBasicBlockRef *attisnullblocks; LLVMBasicBlockRef *attcheckalignblocks; LLVMBasicBlockRef *attalignblocks; LLVMBasicBlockRef *attstoreblocks; LLVMValueRef v_offp; LLVMValueRef v_tupdata_base; LLVMValueRef v_tts_values; LLVMValueRef v_tts_nulls; LLVMValueRef v_slotoffp; LLVMValueRef v_slowp; LLVMValueRef v_nvalidp; LLVMValueRef v_nvalid; LLVMValueRef v_maxatt; LLVMValueRef v_slot; LLVMValueRef v_tupleheaderp; LLVMValueRef v_tuplep; LLVMValueRef v_infomask1; LLVMValueRef v_infomask2; LLVMValueRef v_bits; LLVMValueRef v_hoff; LLVMValueRef v_hasnulls; /* last column (0 indexed) guaranteed to exist */ int guaranteed_column_number = -1; /* current known alignment */ int known_alignment = 0; /* if true, known_alignment describes definite offset of column */ bool attguaranteedalign = true; int attnum; mod = llvm_mutable_module(context); funcname = llvm_expand_funcname(context, "deform"); /* * Check which columns do have to exist, so we don't have to check the * rows natts unnecessarily. */ for (attnum = 0; attnum < desc->natts; attnum++) { Form_pg_attribute att = TupleDescAttr(desc, attnum); /* * If the column is possibly missing, we can't rely on its (or * subsequent) NOT NULL constraints to indicate minimum attributes in * the tuple, so stop here. */ if (att->atthasmissing) break; /* * Column is NOT NULL and there've been no preceding missing columns, * it's guaranteed that all columns up to here exist at least in the * NULL bitmap. */ if (att->attnotnull) guaranteed_column_number = attnum; } /* Create the signature and function */ { LLVMTypeRef param_types[1]; param_types[0] = l_ptr(StructTupleTableSlot); deform_sig = LLVMFunctionType(LLVMVoidType(), param_types, lengthof(param_types), 0); } v_deform_fn = LLVMAddFunction(mod, funcname, deform_sig); LLVMSetLinkage(v_deform_fn, LLVMInternalLinkage); LLVMSetParamAlignment(LLVMGetParam(v_deform_fn, 0), MAXIMUM_ALIGNOF); llvm_copy_attributes(AttributeTemplate, v_deform_fn); b_entry = LLVMAppendBasicBlock(v_deform_fn, "entry"); b_adjust_unavail_cols = LLVMAppendBasicBlock(v_deform_fn, "adjust_unavail_cols"); b_find_start = LLVMAppendBasicBlock(v_deform_fn, "find_startblock"); b_out = LLVMAppendBasicBlock(v_deform_fn, "outblock"); b_dead = LLVMAppendBasicBlock(v_deform_fn, "deadblock"); b = LLVMCreateBuilder(); attcheckattnoblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attstartblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attisnullblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attcheckalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attstoreblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); known_alignment = 0; LLVMPositionBuilderAtEnd(b, b_entry); /* perform allocas first, llvm only converts those to registers */ v_offp = LLVMBuildAlloca(b, TypeSizeT, "v_offp"); v_slot = LLVMGetParam(v_deform_fn, 0); v_tts_values = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_VALUES, "tts_values"); v_tts_nulls = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL, "tts_ISNULL"); v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, ""); v_slowp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_SLOW, ""); v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, ""); v_tupleheaderp = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE, "tupleheader"); v_tuplep = l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA, "tuple"); v_bits = LLVMBuildBitCast(b, LLVMBuildStructGEP(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_BITS, ""), l_ptr(LLVMInt8Type()), "t_bits"); v_infomask1 = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK, "infomask1"); v_infomask2 = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2, "infomask2"); /* t_infomask & HEAP_HASNULL */ v_hasnulls = LLVMBuildICmp(b, LLVMIntNE, LLVMBuildAnd(b, l_int16_const(HEAP_HASNULL), v_infomask1, ""), l_int16_const(0), "hasnulls"); /* t_infomask2 & HEAP_NATTS_MASK */ v_maxatt = LLVMBuildAnd(b, l_int16_const(HEAP_NATTS_MASK), v_infomask2, "maxatt"); v_hoff = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_HOFF, "t_hoff"); v_tupdata_base = LLVMBuildGEP(b, LLVMBuildBitCast(b, v_tuplep, l_ptr(LLVMInt8Type()), ""), &v_hoff, 1, "v_tupdata_base"); /* * Load tuple start offset from slot. Will be reset below in case there's * no existing deformed columns in slot. */ { LLVMValueRef v_off_start; v_off_start = LLVMBuildLoad(b, v_slotoffp, "v_slot_off"); v_off_start = LLVMBuildZExt(b, v_off_start, TypeSizeT, ""); LLVMBuildStore(b, v_off_start, v_offp); } /* build the basic block for each attribute, need them as jump target */ for (attnum = 0; attnum < natts; attnum++) { attcheckattnoblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckattno", attnum); attstartblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.start", attnum); attisnullblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attisnull", attnum); attcheckalignblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckalign", attnum); attalignblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.align", attnum); attstoreblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.store", attnum); } /* * Check if's guaranteed the all the desired attributes are available in * tuple. If so, we can start deforming. If not, need to make sure to * fetch the missing columns. */ if ((natts - 1) <= guaranteed_column_number) { /* just skip through unnecessary blocks */ LLVMBuildBr(b, b_adjust_unavail_cols); LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols); LLVMBuildBr(b, b_find_start); } else { LLVMValueRef v_params[3]; /* branch if not all columns available */ LLVMBuildCondBr(b, LLVMBuildICmp(b, LLVMIntULT, v_maxatt, l_int16_const(natts), ""), b_adjust_unavail_cols, b_find_start); /* if not, memset tts_isnull of relevant cols to true */ LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols); v_params[0] = v_slot; v_params[1] = LLVMBuildZExt(b, v_maxatt, LLVMInt32Type(), ""); v_params[2] = l_int32_const(natts); LLVMBuildCall(b, llvm_get_decl(mod, FuncSlotGetmissingattrs), v_params, lengthof(v_params), ""); LLVMBuildBr(b, b_find_start); } LLVMPositionBuilderAtEnd(b, b_find_start); v_nvalid = LLVMBuildLoad(b, v_nvalidp, ""); /* * Build switch to go from nvalid to the right startblock. Callers * currently don't have the knowledge, but it'd be good for performance to * avoid this check when it's known that the slot is empty (e.g. in scan * nodes). */ if (true) { LLVMValueRef v_switch = LLVMBuildSwitch(b, v_nvalid, b_dead, natts); for (attnum = 0; attnum < natts; attnum++) { LLVMValueRef v_attno = l_int32_const(attnum); LLVMAddCase(v_switch, v_attno, attcheckattnoblocks[attnum]); } } else { /* jump from entry block to first block */ LLVMBuildBr(b, attcheckattnoblocks[0]); } LLVMPositionBuilderAtEnd(b, b_dead); LLVMBuildUnreachable(b); /* * Iterate over each attribute that needs to be deformed, build code to * deform it. */ for (attnum = 0; attnum < natts; attnum++) { Form_pg_attribute att = TupleDescAttr(desc, attnum); LLVMValueRef v_incby; int alignto; LLVMValueRef l_attno = l_int16_const(attnum); LLVMValueRef v_attdatap; LLVMValueRef v_resultp; /* build block checking whether we did all the necessary attributes */ LLVMPositionBuilderAtEnd(b, attcheckattnoblocks[attnum]); /* * If this is the first attribute, slot->tts_nvalid was 0. Therefore * reset offset to 0 to, it be from a previous execution. */ if (attnum == 0) { LLVMBuildStore(b, l_sizet_const(0), v_offp); } /* * Build check whether column is available (i.e. whether the tuple has * that many columns stored). We can avoid the branch if we know * there's a subsequent NOT NULL column. */ if (attnum <= guaranteed_column_number) { LLVMBuildBr(b, attstartblocks[attnum]); } else { LLVMValueRef v_islast; v_islast = LLVMBuildICmp(b, LLVMIntUGE, l_attno, v_maxatt, "heap_natts"); LLVMBuildCondBr(b, v_islast, b_out, attstartblocks[attnum]); } LLVMPositionBuilderAtEnd(b, attstartblocks[attnum]); /* * Check for nulls if necessary. No need to take missing attributes * into account, because in case they're present the heaptuple's natts * would have indicated that a slot_getmissingattrs() is needed. */ if (!att->attnotnull) { LLVMBasicBlockRef b_ifnotnull; LLVMBasicBlockRef b_ifnull; LLVMBasicBlockRef b_next; LLVMValueRef v_attisnull; LLVMValueRef v_nullbyteno; LLVMValueRef v_nullbytemask; LLVMValueRef v_nullbyte; LLVMValueRef v_nullbit; b_ifnotnull = attcheckalignblocks[attnum]; b_ifnull = attisnullblocks[attnum]; if (attnum + 1 == natts) b_next = b_out; else b_next = attcheckattnoblocks[attnum + 1]; v_nullbyteno = l_int32_const(attnum >> 3); v_nullbytemask = l_int8_const(1 << ((attnum) & 0x07)); v_nullbyte = l_load_gep1(b, v_bits, v_nullbyteno, "attnullbyte"); v_nullbit = LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildAnd(b, v_nullbyte, v_nullbytemask, ""), l_int8_const(0), "attisnull"); v_attisnull = LLVMBuildAnd(b, v_hasnulls, v_nullbit, ""); LLVMBuildCondBr(b, v_attisnull, b_ifnull, b_ifnotnull); LLVMPositionBuilderAtEnd(b, b_ifnull); /* store null-byte */ LLVMBuildStore(b, l_int8_const(1), LLVMBuildGEP(b, v_tts_nulls, &l_attno, 1, "")); /* store zero datum */ LLVMBuildStore(b, l_sizet_const(0), LLVMBuildGEP(b, v_tts_values, &l_attno, 1, "")); LLVMBuildBr(b, b_next); attguaranteedalign = false; } else {
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); } }
static void trace_dynamic_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef ptr, LLVMValueRef desc, ast_t* type, ast_t* orig, ast_t* tuple) { // Build a "don't care" type of our cardinality. size_t cardinality = ast_childcount(type); ast_t* dontcare = ast_from(type, TK_TUPLETYPE); for(size_t i = 0; i < cardinality; i++) ast_append(dontcare, ast_from(type, TK_DONTCARETYPE)); // Replace our type in the tuple type with the "don't care" type. bool in_tuple = (tuple != NULL); if(in_tuple) ast_swap(type, dontcare); else tuple = dontcare; // If the original type is a subtype of the test type, then we are always // the correct cardinality. Otherwise, we need to dynamically check // cardinality. LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); if(!is_subtype(orig, tuple, NULL, c->opt)) { LLVMValueRef dynamic_count = gendesc_fieldcount(c, desc); LLVMValueRef static_count = LLVMConstInt(c->i32, cardinality, false); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntEQ, static_count, dynamic_count, ""); // Skip if not the right cardinality. LLVMBuildCondBr(c->builder, test, is_true, is_false); } else { LLVMBuildBr(c->builder, is_true); } LLVMPositionBuilderAtEnd(c->builder, is_true); size_t index = 0; ast_t* child = ast_child(type); ast_t* dc_child = ast_child(dontcare); while(child != NULL) { switch(trace_type(child)) { case TRACE_MACHINE_WORD: case TRACE_PRIMITIVE: // Skip this element. break; case TRACE_MUT_KNOWN: case TRACE_MUT_UNKNOWN: case TRACE_VAL_KNOWN: case TRACE_VAL_UNKNOWN: case TRACE_TAG_KNOWN: case TRACE_TAG_UNKNOWN: case TRACE_DYNAMIC: { // If we are (A, B), turn (_, _) into (A, _). ast_t* swap = ast_dup(child); ast_swap(dc_child, swap); // Create a next block. LLVMBasicBlockRef next_block = codegen_block(c, ""); // Load the object from the tuple field. LLVMValueRef field_info = gendesc_fieldinfo(c, desc, index); LLVMValueRef object = gendesc_fieldload(c, ptr, field_info); // Trace dynamic, even if the tuple thinks the field isn't dynamic. trace_dynamic(c, ctx, object, swap, orig, tuple, next_block); // Continue into the next block. LLVMBuildBr(c->builder, next_block); LLVMPositionBuilderAtEnd(c->builder, next_block); // Restore (A, _) to (_, _). ast_swap(swap, dc_child); ast_free_unattached(swap); break; } case TRACE_TUPLE: { // If we are (A, B), turn (_, _) into (A, _). ast_t* swap = ast_dup(child); ast_swap(dc_child, swap); // Get a pointer to the unboxed tuple and it's descriptor. LLVMValueRef field_info = gendesc_fieldinfo(c, desc, index); LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info); LLVMValueRef field_desc = gendesc_fielddesc(c, field_info); // Trace the tuple dynamically. trace_dynamic_tuple(c, ctx, field_ptr, field_desc, swap, orig, tuple); // Restore (A, _) to (_, _). ast_swap(swap, dc_child); ast_free_unattached(swap); break; } default: {} } index++; child = ast_sibling(child); dc_child = ast_sibling(dc_child); } // Restore the tuple type. if(in_tuple) ast_swap(dontcare, type); ast_free_unattached(dontcare); // Continue with other possible tracings. LLVMBuildBr(c->builder, is_false); LLVMPositionBuilderAtEnd(c->builder, is_false); }
static void trace_dynamic_nominal(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type, ast_t* orig, ast_t* tuple, LLVMBasicBlockRef next_block) { pony_assert(ast_id(type) == TK_NOMINAL); // Skip if a primitive. ast_t* def = (ast_t*)ast_data(type); if(ast_id(def) == TK_PRIMITIVE) return; int mutability = trace_cap_nominal(c->opt, type, orig, tuple); // If we can't extract the element from the original type, there is no need to // trace the element. if(mutability == -1) return; token_id dst_cap = TK_TAG; switch(mutability) { case PONY_TRACE_MUTABLE: dst_cap = TK_ISO; break; case PONY_TRACE_IMMUTABLE: dst_cap = TK_VAL; break; default: {} } ast_t* dst_type = ast_dup(type); ast_t* dst_cap_ast = cap_fetch(dst_type); ast_setid(dst_cap_ast, dst_cap); ast_t* dst_eph = ast_sibling(dst_cap_ast); if(ast_id(dst_eph) == TK_EPHEMERAL) ast_setid(dst_eph, TK_NONE); // We aren't always this type. We need to check dynamically. LLVMValueRef desc = gendesc_fetch(c, object); LLVMValueRef test = gendesc_isnominal(c, desc, type); LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); LLVMBuildCondBr(c->builder, test, is_true, is_false); // Trace as this type. LLVMPositionBuilderAtEnd(c->builder, is_true); gentrace(c, ctx, object, object, type, dst_type); ast_free_unattached(dst_type); // If we have traced as mut or val, we're done with this element. Otherwise, // continue tracing this as if the match had been unsuccessful. if(mutability != PONY_TRACE_OPAQUE) LLVMBuildBr(c->builder, next_block); else LLVMBuildBr(c->builder, is_false); // Carry on, whether we have traced or not. LLVMPositionBuilderAtEnd(c->builder, is_false); }
void JITImpl::emitCondBrToBlock(LLVMValueRef cond, LLVMBasicBlockRef trueBB) { LLVMBasicBlockRef afterBB = LLVMAppendBasicBlock(getCurrentFunction(), ""); LLVMBuildCondBr(builder, cond, trueBB, afterBB); LLVMPositionBuilderAtEnd(builder, afterBB); }
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; }
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 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; }
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; }