void genprim_string_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 string 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, ""); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr_offset; args[2] = alloc; LLVMValueRef ptr_addr = gencall_runtime(c, "pony_deserialise_block", args, 3, ""); LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, object, 3, ""); LLVMBuildStore(c->builder, ptr_addr, ptr); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
LLVMValueRef gen_name(struct node *ast) { LLVMValueRef func, ptr, val; LLVMTypeRef type; ptr = lvalue(ast); type = LLVMTypeOf(ptr); if (LLVMGetTypeKind(type) == LLVMLabelTypeKind) { func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)); return LLVMBuildPtrToInt(builder, LLVMBlockAddress(func, (LLVMBasicBlockRef)ptr), TYPE_INT, ""); } type = LLVMGetElementType(LLVMTypeOf(ptr)); switch (LLVMGetTypeKind(type)) { case LLVMIntegerTypeKind: val = LLVMBuildLoad(builder, ptr, ast->val); if (LLVMIsAGlobalValue(ptr)) val = LLVMBuildLShr(builder, val, CONST(WORDPOW), ""); return val; default: generror("unexpected type '%s'", LLVMPrintTypeToString(type)); return NULL; } }
static void pointer_offset(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_offset"); LLVMTypeRef params[3]; params[0] = t->use_type; params[1] = c->intptr; start_function(c, m, t->use_type, params, 2); // Set up a constant integer for the allocation size. size_t size = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, size, false); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef n = LLVMGetParam(m->func, 1); // Return ptr + (n * sizeof(len)). LLVMValueRef src = LLVMBuildPtrToInt(c->builder, ptr, c->intptr, ""); LLVMValueRef offset = LLVMBuildMul(c->builder, n, l_size, ""); LLVMValueRef result = LLVMBuildAdd(c->builder, src, offset, ""); result = LLVMBuildIntToPtr(c->builder, result, t->use_type, ""); LLVMBuildRet(c->builder, result); codegen_finishfun(c); BOX_FUNCTION(); }
void gendeserialise_element(compile_t* c, reach_type_t* t, bool embed, LLVMValueRef ctx, LLVMValueRef ptr) { if(embed || (t->underlying == TK_TUPLETYPE)) { // Embedded field or tuple, deserialise in place. deserialise(c, t, ctx, ptr); } else if(t->primitive != NULL) { // Machine word, already copied. } else { // Lookup the pointer and write that. LLVMValueRef value = LLVMBuildLoad(c->builder, ptr, ""); LLVMValueRef args[3]; args[0] = ctx; args[1] = (t->desc != NULL) ? LLVMBuildBitCast(c->builder, t->desc, c->descriptor_ptr, "") : LLVMConstNull(c->descriptor_ptr); args[2] = LLVMBuildPtrToInt(c->builder, value, c->intptr, ""); LLVMValueRef object = gencall_runtime(c, "pony_deserialise_offset", args, 3, ""); object = LLVMBuildBitCast(c->builder, object, t->use_type, ""); LLVMBuildStore(c->builder, object, ptr); } }
static LLVMValueRef lvalue_to_rvalue(LLVMValueRef lvalue) { /* * TODO: Make sure all addresses are word-aligned * (autos, vectors, strings, etc.) */ lvalue = LLVMBuildPtrToInt(builder, lvalue, TYPE_INT, ""); return LLVMBuildLShr(builder, lvalue, CONST(WORDPOW), ""); }
static LLVMValueRef gen_digestof_value(compile_t* c, LLVMValueRef value) { LLVMTypeRef type = LLVMTypeOf(value); switch(LLVMGetTypeKind(type)) { case LLVMFloatTypeKind: value = LLVMBuildBitCast(c->builder, value, c->i32, ""); return LLVMBuildZExt(c->builder, value, c->i64, ""); case LLVMDoubleTypeKind: return LLVMBuildBitCast(c->builder, value, c->i64, ""); case LLVMIntegerTypeKind: { uint32_t width = LLVMGetIntTypeWidth(type); if(width < 64) { value = LLVMBuildZExt(c->builder, value, c->i64, ""); } else if(width == 128) { LLVMValueRef shift = LLVMConstInt(c->i128, 64, false); LLVMValueRef high = LLVMBuildLShr(c->builder, value, shift, ""); high = LLVMBuildTrunc(c->builder, high, c->i64, ""); value = LLVMBuildTrunc(c->builder, value, c->i64, ""); value = LLVMBuildXor(c->builder, value, high, ""); } return value; } case LLVMStructTypeKind: { uint32_t count = LLVMCountStructElementTypes(type); LLVMValueRef result = LLVMConstInt(c->i64, 0, false); for(uint32_t i = 0; i < count; i++) { LLVMValueRef elem = LLVMBuildExtractValue(c->builder, value, i, ""); elem = gen_digestof_value(c, elem); result = LLVMBuildXor(c->builder, result, elem, ""); } return result; } case LLVMPointerTypeKind: return LLVMBuildPtrToInt(c->builder, value, c->i64, ""); default: {} } assert(0); return NULL; }
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_isentity(compile_t* c, LLVMValueRef desc, ast_t* type) { gentype_t g; if(!gentype(c, type, &g)) return GEN_NOVALUE; LLVMValueRef left = LLVMBuildPtrToInt(c->builder, desc, c->intptr, ""); LLVMValueRef right = LLVMConstPtrToInt(g.desc, c->intptr); return LLVMBuildICmp(c->builder, LLVMIntEQ, left, right, ""); }
static void pointer_usize(compile_t* c, reach_type_t* t) { FIND_METHOD("usize"); start_function(c, m, c->intptr, &t->use_type, 1); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef result = LLVMBuildPtrToInt(c->builder, ptr, c->intptr, ""); LLVMBuildRet(c->builder, result); codegen_finishfun(c); }
LLVMValueRef gendesc_isentity(compile_t* c, LLVMValueRef desc, ast_t* type) { reach_type_t* t = reach_type(c->reach, type); if(t == NULL) return GEN_NOVALUE; LLVMValueRef left = LLVMBuildPtrToInt(c->builder, desc, c->intptr, ""); LLVMValueRef right = LLVMConstPtrToInt(t->desc, c->intptr); return LLVMBuildICmp(c->builder, LLVMIntEQ, left, right, ""); }
LLVMValueRef gendesc_ptr_to_fields(compile_t* c, LLVMValueRef object, LLVMValueRef desc) { // Skip the descriptor. LLVMValueRef offset = desc_field(c, desc, DESC_FIELD_OFFSET); offset = LLVMBuildZExt(c->builder, offset, c->intptr, ""); LLVMValueRef base = LLVMBuildPtrToInt(c->builder, object, c->intptr, ""); LLVMValueRef result = LLVMBuildAdd(c->builder, base, offset, ""); // Return as a c->intptr. return result; }
LLVMValueRef build_l4_ipc_call( struct llvm_ctx *ctx, LLVMValueRef arg_to, LLVMValueRef arg_timeouts, LLVMValueRef arg_fromspec, LLVMValueRef arg_mr0, LLVMValueRef *from_p, LLVMValueRef *mr1_p, LLVMValueRef *mr2_p) { LLVMTypeRef params[5]; for(int i=0; i<5; i++) params[i] = ctx->wordt; LLVMTypeRef ipc_result_type = LLVMStructTypeInContext(ctx->ctx, params, 4, 0); LLVMTypeRef ipc_type = LLVMFunctionType(ipc_result_type, params, 5, 0); LLVMValueRef fn = LLVMConstInlineAsm(ipc_type, /* NOTE: this compensates against LLVM 3.3's inability to save %ebp * over an asm statement. clearly a bug, but w/e. * * it's been around since at least LLVM 3.2. */ " pushl %ebp\n" "\tcall __L4_Ipc\n" "\tmovl %ebp, %ecx\n" "\tpopl %ebp\n", "={ax},={si},={bx},={cx},{ax},{cx},{dx},{si},{di},~{dirflag},~{fpsr},~{flags}", 1, 0); LLVMValueRef args[5] = { arg_to, arg_timeouts, arg_fromspec, arg_mr0, LLVMBuildPtrToInt(ctx->builder, ctx->utcb, ctx->wordt, "l4ipc.utcb"), }; LLVMValueRef result = LLVMBuildCall(ctx->builder, fn, args, 5, "l4ipc"); LLVMSetTailCall(result, 1); if(from_p != NULL) { *from_p = LLVMBuildExtractValue(ctx->builder, result, 0, "from"); } if(mr1_p != NULL) { *mr1_p = LLVMBuildExtractValue(ctx->builder, result, 2, "mr1"); } if(mr2_p != NULL) { *mr2_p = LLVMBuildExtractValue(ctx->builder, result, 3, "mr2"); } return LLVMBuildExtractValue(ctx->builder, result, 1, "mr0"); }
static void pointer_delete(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_delete"); LLVMTypeRef params[3]; params[0] = t->use_type; params[1] = c->intptr; params[2] = c->intptr; start_function(c, m, t_elem->use_type, params, 3); // Set up a constant integer for the allocation size. size_t size = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, size, false); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef n = LLVMGetParam(m->func, 1); LLVMValueRef len = LLVMGetParam(m->func, 2); LLVMValueRef elem_ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMValueRef result = LLVMBuildLoad(c->builder, elem_ptr, ""); LLVMValueRef dst = LLVMBuildPtrToInt(c->builder, elem_ptr, c->intptr, ""); LLVMValueRef offset = LLVMBuildMul(c->builder, n, l_size, ""); LLVMValueRef src = LLVMBuildAdd(c->builder, dst, offset, ""); LLVMValueRef elen = LLVMBuildMul(c->builder, len, l_size, ""); LLVMValueRef args[5]; args[0] = LLVMBuildIntToPtr(c->builder, dst, c->void_ptr, ""); args[1] = LLVMBuildIntToPtr(c->builder, src, c->void_ptr, ""); args[2] = elen; args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); // llvm.memmove.*(ptr, ptr + (n * sizeof(elem)), len * sizeof(elem)) if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memmove.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memmove.p0i8.p0i8.i64", args, 5, ""); } // Return ptr[0]. LLVMBuildRet(c->builder, result); codegen_finishfun(c); }
void build_simple_string_item( struct llvm_ctx *ctx, LLVMValueRef *dest, LLVMValueRef data_ptr, LLVMValueRef data_len, LLVMValueRef cache_hint) { if(cache_hint == NULL) cache_hint = CONST_WORD(0); dest[0] = LLVMBuildOr(ctx->builder, LLVMBuildShl(ctx->builder, data_len, CONST_WORD(10), "stritem.simple.len.shl"), LLVMBuildShl(ctx->builder, cache_hint, CONST_WORD(1), "stritem.simple.ch.shl"), "stritem.simple.info"); dest[1] = LLVMBuildPtrToInt(ctx->builder, data_ptr, ctx->wordt, "stritem.simple.ptr"); }
LLVMValueRef gen_vecdef(struct node *ast) { LLVMValueRef global, array, init, *ival_list; struct node *n; int size, initsize, i; initsize = count_chain(ast->three); if (ast->two) size = LLVMConstIntGetZExtValue(codegen(ast->two)); else size = 0; if (initsize > size) size = initsize; ival_list = calloc(sizeof(LLVMValueRef), size); if (size > 0 && ival_list == NULL) generror("out of memory"); for (i = 0, n = ast->three; i < initsize; i++, n = n->two) /* TODO: handle NAMES (convert global pointer to int) */ ival_list[initsize - i - 1] = codegen(n->one); for (i = initsize; i < size; i++) ival_list[i] = CONST(0); global = find_or_add_global(ast->one->val); array = LLVMAddGlobal(module, TYPE_ARRAY(size), ".gvec"); LLVMSetLinkage(array, LLVMPrivateLinkage); if (initsize) init = LLVMConstArray(TYPE_INT, ival_list, size); else init = LLVMConstNull(TYPE_ARRAY(size)); LLVMSetInitializer(array, init); LLVMSetInitializer(global, LLVMBuildPtrToInt(builder, array, TYPE_INT, "")); return NULL; }
static LLVMValueRef cast_ffi_arg(compile_t* c, ffi_decl_t* decl, ast_t* ast, LLVMValueRef arg, LLVMTypeRef param, const char* name) { if(arg == NULL) return NULL; LLVMTypeRef arg_type = LLVMTypeOf(arg); if(param == arg_type) return arg; if((LLVMABISizeOfType(c->target_data, param) != LLVMABISizeOfType(c->target_data, arg_type))) { report_ffi_type_err(c, decl, ast, name); return NULL; } switch(LLVMGetTypeKind(param)) { case LLVMPointerTypeKind: if(LLVMGetTypeKind(arg_type) == LLVMIntegerTypeKind) return LLVMBuildIntToPtr(c->builder, arg, param, ""); else return LLVMBuildBitCast(c->builder, arg, param, ""); case LLVMIntegerTypeKind: if(LLVMGetTypeKind(arg_type) == LLVMPointerTypeKind) return LLVMBuildPtrToInt(c->builder, arg, param, ""); break; case LLVMStructTypeKind: pony_assert(LLVMGetTypeKind(arg_type) == LLVMStructTypeKind); return arg; default: {} } pony_assert(false); return NULL; }
static LLVMValueRef gen_digestof_value(compile_t* c, ast_t* type, LLVMValueRef value) { LLVMTypeRef impl_type = LLVMTypeOf(value); switch(LLVMGetTypeKind(impl_type)) { case LLVMFloatTypeKind: value = LLVMBuildBitCast(c->builder, value, c->i32, ""); return LLVMBuildZExt(c->builder, value, c->intptr, ""); case LLVMDoubleTypeKind: value = LLVMBuildBitCast(c->builder, value, c->i64, ""); return gen_digestof_int64(c, value); case LLVMIntegerTypeKind: { uint32_t width = LLVMGetIntTypeWidth(impl_type); if(width < 64) { return LLVMBuildZExt(c->builder, value, c->intptr, ""); } else if(width == 64) { return gen_digestof_int64(c, value); } else if(width == 128) { LLVMValueRef shift = LLVMConstInt(c->i128, 64, false); LLVMValueRef high = LLVMBuildLShr(c->builder, value, shift, ""); high = LLVMBuildTrunc(c->builder, high, c->i64, ""); value = LLVMBuildTrunc(c->builder, value, c->i64, ""); high = gen_digestof_int64(c, high); value = gen_digestof_int64(c, value); return LLVMBuildXor(c->builder, value, high, ""); } break; } case LLVMStructTypeKind: { uint32_t count = LLVMCountStructElementTypes(impl_type); LLVMValueRef result = LLVMConstInt(c->intptr, 0, false); ast_t* child = ast_child(type); for(uint32_t i = 0; i < count; i++) { LLVMValueRef elem = LLVMBuildExtractValue(c->builder, value, i, ""); elem = gen_digestof_value(c, child, elem); result = LLVMBuildXor(c->builder, result, elem, ""); child = ast_sibling(child); } pony_assert(child == NULL); return result; } case LLVMPointerTypeKind: if(!is_known(type)) { reach_type_t* t = reach_type(c->reach, type); int sub_kind = subtype_kind(t); if((sub_kind & SUBTYPE_KIND_BOXED) != 0) return gen_digestof_box(c, t, value, sub_kind); } return LLVMBuildPtrToInt(c->builder, value, c->intptr, ""); default: {} } pony_assert(0); return NULL; }
LLVMValueRef gen_funcdef(struct node *ast) { LLVMValueRef global, func, retval; LLVMTypeRef func_type, *param_types; LLVMBasicBlockRef body_block, ret_block; int param_count, i; if (hcreate(SYMTAB_SIZE) == 0) generror(">s"); param_count = count_chain(ast->two); param_types = calloc(sizeof(LLVMTypeRef), param_count); if (param_count > 0 && param_types == NULL) generror("out of memory"); for (i = 0; i < param_count; i++) param_types[i] = TYPE_INT; func_type = LLVMFunctionType(TYPE_INT, param_types, param_count, 0); func = LLVMAddFunction(module, ".gfunc", func_type); LLVMSetLinkage(func, LLVMPrivateLinkage); /* TODO: How to specify stack alignment? Should be 16 bytes */ LLVMAddFunctionAttr(func, LLVMStackAlignment); global = find_or_add_global(ast->one->val); LLVMSetInitializer(global, LLVMBuildPtrToInt(builder, func, TYPE_INT, "")); body_block = LLVMAppendBasicBlock(func, ""); ret_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, body_block); retval = LLVMBuildAlloca(builder, TYPE_INT, ""); LLVMBuildStore(builder, CONST(0), retval); symtab_enter(ast->one->val, global); symtab_enter(".return", ret_block); symtab_enter(".retval", retval); label_count = 0; predeclare_labels(ast->three); if (ast->two) codegen(ast->two); codegen(ast->three); LLVMBuildBr(builder, ret_block); /* TODO: Untangle out-of-order blocks */ LLVMPositionBuilderAtEnd(builder, ret_block); LLVMBuildRet(builder, LLVMBuildLoad(builder, retval, "")); LLVMMoveBasicBlockAfter(ret_block, LLVMGetLastBasicBlock(func)); /* TODO: Handle failed verification and print internal compiler error */ LLVMVerifyFunction(func, LLVMPrintMessageAction); hdestroy(); return NULL; }
static void update_cached_block(struct gallivm_state *gallivm, const struct util_format_description *format_desc, LLVMValueRef ptr_addr, LLVMValueRef hash_index, LLVMValueRef cache) { LLVMBuilderRef builder = gallivm->builder; LLVMTypeRef i8t = LLVMInt8TypeInContext(gallivm->context); LLVMTypeRef pi8t = LLVMPointerType(i8t, 0); LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context); LLVMTypeRef i32x4 = LLVMVectorType(LLVMInt32TypeInContext(gallivm->context), 4); LLVMValueRef function; LLVMValueRef tag_value, tmp_ptr; LLVMValueRef col[4]; unsigned i, j; /* * Use format_desc->fetch_rgba_8unorm() for each pixel in the block. * This doesn't actually make any sense whatsoever, someone would need * to write a function doing this for all pixels in a block (either as * an external c function or with generated code). Don't ask. */ { /* * Function to call looks like: * fetch(uint8_t *dst, const uint8_t *src, unsigned i, unsigned j) */ LLVMTypeRef ret_type; LLVMTypeRef arg_types[4]; LLVMTypeRef function_type; assert(format_desc->fetch_rgba_8unorm); ret_type = LLVMVoidTypeInContext(gallivm->context); arg_types[0] = pi8t; arg_types[1] = pi8t; arg_types[2] = i32t; arg_types[3] = i32t; function_type = LLVMFunctionType(ret_type, arg_types, ARRAY_SIZE(arg_types), 0); /* make const pointer for the C fetch_rgba_8unorm function */ function = lp_build_const_int_pointer(gallivm, func_to_pointer((func_pointer) format_desc->fetch_rgba_8unorm)); /* cast the callee pointer to the function's type */ function = LLVMBuildBitCast(builder, function, LLVMPointerType(function_type, 0), "cast callee"); } tmp_ptr = lp_build_array_alloca(gallivm, i32x4, lp_build_const_int32(gallivm, 16), "tmp_decode_store"); tmp_ptr = LLVMBuildBitCast(builder, tmp_ptr, pi8t, ""); /* * Invoke format_desc->fetch_rgba_8unorm() for each pixel. * This is going to be really really slow. * Note: the block store format is actually * x0y0x0y1x0y2x0y3 x1y0x1y1x1y2x1y3 ... */ for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) { LLVMValueRef args[4]; LLVMValueRef dst_offset = lp_build_const_int32(gallivm, (i * 4 + j) * 4); /* * Note we actually supply a pointer to the start of the block, * not the start of the texture. */ args[0] = LLVMBuildGEP(gallivm->builder, tmp_ptr, &dst_offset, 1, ""); args[1] = ptr_addr; args[2] = LLVMConstInt(i32t, i, 0); args[3] = LLVMConstInt(i32t, j, 0); LLVMBuildCall(builder, function, args, ARRAY_SIZE(args), ""); } } /* Finally store the block - pointless mem copy + update tag. */ tmp_ptr = LLVMBuildBitCast(builder, tmp_ptr, LLVMPointerType(i32x4, 0), ""); for (i = 0; i < 4; ++i) { LLVMValueRef tmp_offset = lp_build_const_int32(gallivm, i); LLVMValueRef ptr = LLVMBuildGEP(gallivm->builder, tmp_ptr, &tmp_offset, 1, ""); col[i] = LLVMBuildLoad(builder, ptr, ""); } tag_value = LLVMBuildPtrToInt(gallivm->builder, ptr_addr, LLVMInt64TypeInContext(gallivm->context), ""); store_cached_block(gallivm, col, tag_value, hash_index, cache); }
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); }
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); }
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); }
/* * Do a cached lookup. * * Returns (vectors of) 4x8 rgba aos value */ LLVMValueRef lp_build_fetch_cached_texels(struct gallivm_state *gallivm, const struct util_format_description *format_desc, unsigned n, LLVMValueRef base_ptr, LLVMValueRef offset, LLVMValueRef i, LLVMValueRef j, LLVMValueRef cache) { LLVMBuilderRef builder = gallivm->builder; unsigned count, low_bit, log2size; LLVMValueRef color, offset_stored, addr, ptr_addrtrunc, tmp; LLVMValueRef ij_index, hash_index, hash_mask, block_index; LLVMTypeRef i8t = LLVMInt8TypeInContext(gallivm->context); LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context); LLVMTypeRef i64t = LLVMInt64TypeInContext(gallivm->context); struct lp_type type; struct lp_build_context bld32; memset(&type, 0, sizeof type); type.width = 32; type.length = n; assert(format_desc->block.width == 4); assert(format_desc->block.height == 4); lp_build_context_init(&bld32, gallivm, type); /* * compute hash - we use direct mapped cache, the hash function could * be better but it needs to be simple * per-element: * compare offset with offset stored at tag (hash) * if not equal decode/store block, update tag * extract color from cache * assemble result vector */ /* TODO: not ideal with 32bit pointers... */ low_bit = util_logbase2(format_desc->block.bits / 8); log2size = util_logbase2(LP_BUILD_FORMAT_CACHE_SIZE); addr = LLVMBuildPtrToInt(builder, base_ptr, i64t, ""); ptr_addrtrunc = LLVMBuildPtrToInt(builder, base_ptr, i32t, ""); ptr_addrtrunc = lp_build_broadcast_scalar(&bld32, ptr_addrtrunc); /* For the hash function, first mask off the unused lowest bits. Then just do some xor with address bits - only use lower 32bits */ ptr_addrtrunc = LLVMBuildAdd(builder, offset, ptr_addrtrunc, ""); ptr_addrtrunc = LLVMBuildLShr(builder, ptr_addrtrunc, lp_build_const_int_vec(gallivm, type, low_bit), ""); /* This only really makes sense for size 64,128,256 */ hash_index = ptr_addrtrunc; ptr_addrtrunc = LLVMBuildLShr(builder, ptr_addrtrunc, lp_build_const_int_vec(gallivm, type, 2*log2size), ""); hash_index = LLVMBuildXor(builder, ptr_addrtrunc, hash_index, ""); tmp = LLVMBuildLShr(builder, hash_index, lp_build_const_int_vec(gallivm, type, log2size), ""); hash_index = LLVMBuildXor(builder, hash_index, tmp, ""); hash_mask = lp_build_const_int_vec(gallivm, type, LP_BUILD_FORMAT_CACHE_SIZE - 1); hash_index = LLVMBuildAnd(builder, hash_index, hash_mask, ""); ij_index = LLVMBuildShl(builder, i, lp_build_const_int_vec(gallivm, type, 2), ""); ij_index = LLVMBuildAdd(builder, ij_index, j, ""); block_index = LLVMBuildShl(builder, hash_index, lp_build_const_int_vec(gallivm, type, 4), ""); block_index = LLVMBuildAdd(builder, ij_index, block_index, ""); if (n > 1) { color = LLVMGetUndef(LLVMVectorType(i32t, n)); for (count = 0; count < n; count++) { LLVMValueRef index, cond, colorx; LLVMValueRef block_indexx, hash_indexx, addrx, offsetx, ptr_addrx; struct lp_build_if_state if_ctx; index = lp_build_const_int32(gallivm, count); offsetx = LLVMBuildExtractElement(builder, offset, index, ""); addrx = LLVMBuildZExt(builder, offsetx, i64t, ""); addrx = LLVMBuildAdd(builder, addrx, addr, ""); block_indexx = LLVMBuildExtractElement(builder, block_index, index, ""); hash_indexx = LLVMBuildLShr(builder, block_indexx, lp_build_const_int32(gallivm, 4), ""); offset_stored = lookup_tag_data(gallivm, cache, hash_indexx); cond = LLVMBuildICmp(builder, LLVMIntNE, offset_stored, addrx, ""); lp_build_if(&if_ctx, gallivm, cond); { ptr_addrx = LLVMBuildIntToPtr(builder, addrx, LLVMPointerType(i8t, 0), ""); update_cached_block(gallivm, format_desc, ptr_addrx, hash_indexx, cache); #if LP_BUILD_FORMAT_CACHE_DEBUG update_cache_access(gallivm, cache, 1, LP_BUILD_FORMAT_CACHE_MEMBER_ACCESS_MISS); #endif } lp_build_endif(&if_ctx); colorx = lookup_cached_pixel(gallivm, cache, block_indexx); color = LLVMBuildInsertElement(builder, color, colorx, lp_build_const_int32(gallivm, count), ""); } } else { LLVMValueRef cond; struct lp_build_if_state if_ctx; tmp = LLVMBuildZExt(builder, offset, i64t, ""); addr = LLVMBuildAdd(builder, tmp, addr, ""); offset_stored = lookup_tag_data(gallivm, cache, hash_index); cond = LLVMBuildICmp(builder, LLVMIntNE, offset_stored, addr, ""); lp_build_if(&if_ctx, gallivm, cond); { tmp = LLVMBuildIntToPtr(builder, addr, LLVMPointerType(i8t, 0), ""); update_cached_block(gallivm, format_desc, tmp, hash_index, cache); #if LP_BUILD_FORMAT_CACHE_DEBUG update_cache_access(gallivm, cache, 1, LP_BUILD_FORMAT_CACHE_MEMBER_ACCESS_MISS); #endif } lp_build_endif(&if_ctx); color = lookup_cached_pixel(gallivm, cache, block_index); } #if LP_BUILD_FORMAT_CACHE_DEBUG update_cache_access(gallivm, cache, n, LP_BUILD_FORMAT_CACHE_MEMBER_ACCESS_TOTAL); #endif return LLVMBuildBitCast(builder, color, LLVMVectorType(i8t, n * 4), ""); }