Value* code_emitter::emit_closure (filter_t *closure_filter, primary_t *args) { int num_args = compiler_num_filter_args(closure_filter) - 3; Value *closure = NULL, *uservals; userval_info_t *info; int i; g_assert(closure_filter->kind == FILTER_MATHMAP || closure_filter->kind == FILTER_NATIVE); if (closure_filter->kind == FILTER_MATHMAP) { vector<Value*> args; args.push_back(invocation_arg); args.push_back(pools_arg); args.push_back(make_int_const(num_args)); args.push_back(lookup_filter_function(module, closure_filter)); args.push_back(lookup_init_frame_function(module, closure_filter)); args.push_back(lookup_main_filter_function(module, closure_filter)); args.push_back(lookup_init_x_function(module, closure_filter)); args.push_back(lookup_init_y_function(module, closure_filter)); closure = builder->CreateCall(module->getFunction(string("alloc_closure_image")), args.begin(), args.end()); uservals = builder->CreateCall(module->getFunction(string("get_closure_uservals")), closure); } else uservals = builder->CreateCall2(module->getFunction(string("alloc_uservals")), pools_arg, make_int_const(compiler_num_filter_args(closure_filter) - 3)); for (i = 0, info = closure_filter->userval_infos; info != 0; ++i, info = info->next) { const char *set_func_name = get_userval_set_func_name(info->type); Value *arg = emit_primary(&args[i]); /* FIXME: remove this eventually - bool needs to be an int */ if (info->type == USERVAL_BOOL_CONST) arg = promote(arg, TYPE_FLOAT); builder->CreateCall3(module->getFunction(string(set_func_name)), uservals, make_int_const(i), arg); } g_assert(i == num_args); if (closure_filter->kind == FILTER_MATHMAP) { builder->CreateCall3(module->getFunction(string("set_closure_pixel_size")), closure, lookup_internal("__canvasPixelW"), lookup_internal("__canvasPixelH")); return closure; } else { string filter_func_name = string("llvm_") + string(closure_filter->v.native.func_name); return builder->CreateCall3(module->getFunction(filter_func_name), invocation_arg, uservals, pools_arg); } }
/// EmitFPutS - Emit a call to the puts function. Str is required to be a /// pointer and File is a pointer to FILE. void llvm::EmitFPutS(Value *Str, Value *File, IRBuilder<> &B, const TargetData *TD) { Module *M = B.GetInsertBlock()->getParent()->getParent(); AttributeWithIndex AWI[3]; AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture); AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture); AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind); Constant *F; if (File->getType()->isPointerTy()) F = M->getOrInsertFunction("fputs", AttrListPtr::get(AWI, 3), B.getInt32Ty(), B.getInt8PtrTy(), File->getType(), NULL); else F = M->getOrInsertFunction("fputs", B.getInt32Ty(), B.getInt8PtrTy(), File->getType(), NULL); CallInst *CI = B.CreateCall2(F, CastToCStr(Str, B), File, "fputs"); if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts())) CI->setCallingConv(Fn->getCallingConv()); }
Value* code_emitter::setup_init_x_or_y_function (string function_name, const char *internal_name, StructType *vars_type) { current_function = module->getFunction(function_name); Value *slice_arg; Function::arg_iterator args = current_function->arg_begin(); slice_arg = args++; slice_arg->setName("slice"); closure_arg = args++; closure_arg->setName("closure"); set_internal(::lookup_internal(filter->v.mathmap.internals, internal_name, true), args++); set_internal(::lookup_internal(filter->v.mathmap.internals, "t", true), args++); BasicBlock *block = BasicBlock::Create("entry", current_function); builder = new IRBuilder<> (block); frame_arg = builder->CreateCall(module->getFunction(string("get_slice_frame")), slice_arg); invocation_arg = builder->CreateCall(module->getFunction(string("get_frame_invocation")), frame_arg); pools_arg = builder->CreateCall(module->getFunction("get_slice_pools"), slice_arg); set_internals_from_invocation(invocation_arg); set_xy_vars_from_frame(); ret_var = builder->CreateCall2(module->getFunction(string("_mathmap_pools_alloc")), pools_arg, emit_sizeof(vars_type)); Value *vars_var = builder->CreateBitCast(ret_var, PointerType::getUnqual(vars_type)); alloc_complex_copy_var(); return vars_var; }
void code_emitter::setup_init_frame_function () { Value *t_arg; Function::arg_iterator args = init_frame_function->arg_begin(); invocation_arg = args++; invocation_arg->setName("invocation"); //frame_arg = args++; //frame_arg->setName("frame"); closure_arg = args++; closure_arg->setName("closure"); t_arg = args++; t_arg->setName("t"); pools_arg = args++; pools_arg->setName("pools"); BasicBlock *block = BasicBlock::Create("entry", init_frame_function); builder = new IRBuilder<> (block); //invocation_arg = builder->CreateCall(module->getFunction(string("get_frame_invocation")), frame_arg); //pools_arg = builder->CreateCall(module->getFunction(string("get_frame_pools")), frame_arg); set_internal(::lookup_internal(filter->v.mathmap.internals, "t", true), t_arg); set_internals_from_invocation(invocation_arg); ret_var = builder->CreateCall2(module->getFunction(string("_mathmap_pools_alloc")), pools_arg, emit_sizeof(xy_vars_type)); xy_vars_var = builder->CreateBitCast(ret_var, PointerType::getUnqual(xy_vars_type)); alloc_complex_copy_var(); current_function = init_frame_function; }
/// compile_if - Emit code for '[' void BrainFTraceRecorder::compile_if(BrainFTraceNode *node, IRBuilder<>& builder) { BasicBlock *ZeroChild = 0; BasicBlock *NonZeroChild = 0; BasicBlock *Parent = builder.GetInsertBlock(); LLVMContext &Context = Header->getContext(); // If both directions of the branch go back to the trace-head, just // jump there directly. if (node->left == (BrainFTraceNode*)~0ULL && node->right == (BrainFTraceNode*)~0ULL) { HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock()); builder.CreateBr(Header); return; } // Otherwise, there are two cases to handle for each direction: // ~0ULL - A branch back to the trace head // 0 - A branch out of the trace // * - A branch to a node we haven't compiled yet. // Go ahead and generate code for both targets. if (node->left == (BrainFTraceNode*)~0ULL) { NonZeroChild = Header; HeaderPHI->addIncoming(DataPtr, Parent); } else if (node->left == 0) { NonZeroChild = BasicBlock::Create(Context, "exit_left_"+utostr(node->pc), Header->getParent()); builder.SetInsertPoint(NonZeroChild); // Set the extension leaf, which is a pointer to the leaf of the trace // tree from which we are side exiting. ConstantInt *ExtLeaf = ConstantInt::get(int_type, (intptr_t)node); builder.CreateStore(ExtLeaf, ext_leaf); ConstantInt *NewPc = ConstantInt::get(int_type, node->pc+1); Value *BytecodeIndex = builder.CreateConstInBoundsGEP1_32(bytecode_array, node->pc+1); Value *Target = builder.CreateLoad(BytecodeIndex); CallInst *Call =cast<CallInst>(builder.CreateCall2(Target, NewPc, DataPtr)); Call->setTailCall(); builder.CreateRetVoid(); } else { NonZeroChild = BasicBlock::Create(Context, utostr(node->left->pc), Header->getParent()); builder.SetInsertPoint(NonZeroChild); compile_opcode(node->left, builder); } if (node->right == (BrainFTraceNode*)~0ULL) { ZeroChild = Header; HeaderPHI->addIncoming(DataPtr, Parent); } else if (node->right == 0) { ZeroChild = BasicBlock::Create(Context, "exit_right_"+utostr(node->pc), Header->getParent()); builder.SetInsertPoint(ZeroChild); // Set the extension leaf, which is a pointer to the leaf of the trace // tree from which we are side exiting. ConstantInt *ExtLeaf = ConstantInt::get(int_type, (intptr_t)node); builder.CreateStore(ExtLeaf, ext_leaf); ConstantInt *NewPc = ConstantInt::get(int_type, JumpMap[node->pc]+1); Value *BytecodeIndex = builder.CreateConstInBoundsGEP1_32(bytecode_array, JumpMap[node->pc]+1); Value *Target = builder.CreateLoad(BytecodeIndex); CallInst *Call =cast<CallInst>(builder.CreateCall2(Target, NewPc, DataPtr)); Call->setTailCall(); builder.CreateRetVoid(); } else { ZeroChild = BasicBlock::Create(Context, utostr(node->right->pc), Header->getParent()); builder.SetInsertPoint(ZeroChild); compile_opcode(node->right, builder); } // Generate the test and branch to select between the targets. builder.SetInsertPoint(Parent); Value *Loaded = builder.CreateLoad(DataPtr); Value *Cmp = builder.CreateICmpEQ(Loaded, ConstantInt::get(Loaded->getType(), 0)); builder.CreateCondBr(Cmp, ZeroChild, NonZeroChild); }
Value* code_emitter::emit_rhs (rhs_t *rhs) { switch (rhs->kind) { case RHS_PRIMARY : return emit_primary(&rhs->v.primary); case RHS_INTERNAL : return lookup_internal(rhs->v.internal); case RHS_OP : { operation_t *op = rhs->v.op.op; type_t promotion_type = TYPE_NIL; char *function_name = compiler_function_name_for_op_rhs(rhs, &promotion_type); if (promotion_type == TYPE_NIL) assert(op->type_prop == TYPE_PROP_CONST); if (op->type_prop != TYPE_PROP_CONST) assert(promotion_type != TYPE_NIL); Function *func = module->getFunction(string(function_name)); g_assert(func); vector<Value*> args; args.push_back(invocation_arg); args.push_back(closure_arg); args.push_back(pools_arg); for (int i = 0; i < rhs->v.op.op->num_args; ++i) { type_t type = promotion_type == TYPE_NIL ? op->arg_types[i] : promotion_type; Value *val = emit_primary(&rhs->v.op.args[i], type == TYPE_FLOAT); val = promote(val, type); #ifndef __MINGW32__ if (sizeof(gpointer) == 4 && val->getType() == llvm_type_for_type(module, TYPE_COMPLEX)) { Value *copy = builder->CreateAlloca(llvm_type_for_type(module, TYPE_COMPLEX)); builder->CreateStore(val, copy); val = copy; } #endif #ifdef DEBUG_OUTPUT val->dump(); #endif args.push_back(val); } #ifdef DEBUG_OUTPUT func->dump(); #endif Value *result = builder->CreateCall(func, args.begin(), args.end()); /* FIXME: this is ugly - we should check for the type of the operation or resulting value */ if (is_complex_return_type(result->getType())) result = convert_complex_return_value(result); return result; } case RHS_FILTER : { int num_args = compiler_num_filter_args(rhs->v.filter.filter); Value *closure = emit_closure(rhs->v.filter.filter, rhs->v.filter.args); Function *func = lookup_filter_function(module, rhs->v.filter.filter); vector<Value*> args; args.push_back(invocation_arg); args.push_back(closure); args.push_back(emit_primary(&rhs->v.filter.args[num_args - 3])); args.push_back(emit_primary(&rhs->v.filter.args[num_args - 2])); args.push_back(emit_primary(&rhs->v.filter.args[num_args - 1])); args.push_back(pools_arg); return builder->CreateCall(func, args.begin(), args.end()); } case RHS_CLOSURE : return emit_closure(rhs->v.closure.filter, rhs->v.closure.args); case RHS_TUPLE : case RHS_TREE_VECTOR : { Function *set_func = module->getFunction(string("tuple_set")); Value *tuple = builder->CreateCall2(module->getFunction(string("alloc_tuple")), pools_arg, make_int_const(rhs->v.tuple.length)); int i; for (i = 0; i < rhs->v.tuple.length; ++i) { Value *val = emit_primary(&rhs->v.tuple.args[i], true); builder->CreateCall3(set_func, tuple, make_int_const(i), val); } if (rhs->kind == RHS_TREE_VECTOR) { return builder->CreateCall3(module->getFunction(string("alloc_tree_vector")), pools_arg, make_int_const(rhs->v.tuple.length), tuple); } else return tuple; } default : g_assert_not_reached(); } }
Value* code_emitter::emit_primary (primary_t *primary, bool need_float) { switch (primary->kind) { case PRIMARY_VALUE : if (primary->v.value->index < 0) { switch (primary->v.value->compvar->type) { case TYPE_INT : return make_int_const(0); case TYPE_FLOAT : return make_float_const(0.0); case TYPE_IMAGE : return builder->CreateCall(module->getFunction(string("get_uninited_image"))); default : g_assert_not_reached(); } } else { Value *val = lookup_value(primary->v.value); if (need_float) val = promote(val, TYPE_FLOAT); return val; } case PRIMARY_CONST : switch (primary->const_type) { case TYPE_INT : if (need_float) return make_float_const((float)primary->v.constant.int_value); else return make_int_const(primary->v.constant.int_value); case TYPE_FLOAT : return make_float_const(primary->v.constant.float_value); case TYPE_COMPLEX : { assert(!need_float); Value *val = builder->CreateCall2(module->getFunction(string("make_complex")), make_float_const(__real__ primary->v.constant.complex_value), make_float_const(__imag__ primary->v.constant.complex_value)); return convert_complex_return_value(val); } case TYPE_COLOR : assert(!need_float); return builder->CreateCall4(module->getFunction(string("make_color")), make_int_const(RED(primary->v.constant.color_value)), make_int_const(GREEN(primary->v.constant.color_value)), make_int_const(BLUE(primary->v.constant.color_value)), make_int_const(ALPHA(primary->v.constant.color_value))); default : g_assert_not_reached(); } default: g_assert_not_reached(); } }