LLVMValueRef gen_right(struct node *ast) { return LLVMBuildLShr(builder, codegen(ast->one), codegen(ast->two), ""); }
LLVMValueRef gen_switch(struct node *ast) { LLVMValueRef func, switch_; LLVMBasicBlockRef this_block, switch_first_block, switch_last_block, end_block; int i; this_block = LLVMGetInsertBlock(builder); func = LLVMGetBasicBlockParent(this_block); switch_first_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, switch_first_block); case_count = 0; codegen(ast->two); switch_last_block = LLVMGetLastBasicBlock(func); end_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, switch_last_block); LLVMBuildBr(builder, end_block); LLVMPositionBuilderAtEnd(builder, this_block); switch_ = LLVMBuildSwitch(builder, codegen(ast->one), end_block, case_count); for (i = 0; i < case_count; i++) LLVMAddCase(switch_, case_vals[i], case_blocks[i]); LLVMPositionBuilderAtEnd(builder, end_block); return NULL; }
LLVMValueRef gen_div(struct node *ast) { return LLVMBuildSDiv(builder, codegen(ast->one), codegen(ast->two), ""); }
LLVMValueRef gen_mod(struct node *ast) { return LLVMBuildSRem(builder, codegen(ast->one), codegen(ast->two), ""); }
LLVMValueRef gen_if(struct node *ast) { LLVMValueRef condition, func; LLVMBasicBlockRef then_block, else_block, end; condition = codegen(ast->one); condition = LLVMBuildICmp(builder, LLVMIntNE, condition, CONST(0), ""); func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)); then_block = LLVMAppendBasicBlock(func, ""); else_block = LLVMAppendBasicBlock(func, ""); end = LLVMAppendBasicBlock(func, ""); LLVMBuildCondBr(builder, condition, then_block, else_block); LLVMPositionBuilderAtEnd(builder, then_block); codegen(ast->two); LLVMBuildBr(builder, end); LLVMPositionBuilderAtEnd(builder, else_block); if (ast->three) codegen(ast->three); LLVMBuildBr(builder, end); LLVMPositionBuilderAtEnd(builder, end); return NULL; }
LLVMValueRef gen_auto(struct node *ast) { codegen(ast->one); codegen(ast->two); return NULL; }
LLVMValueRef gen_case(struct node *ast) { LLVMValueRef func; LLVMBasicBlockRef this_block, next_block; this_block = LLVMGetInsertBlock(builder); func = LLVMGetBasicBlockParent(this_block); next_block = LLVMAppendBasicBlock(func, ""); LLVMMoveBasicBlockAfter(next_block, this_block); case_blocks[case_count] = next_block; case_vals[case_count] = codegen(ast->one); LLVMBuildBr(builder, next_block); LLVMPositionBuilderAtEnd(builder, next_block); case_count++; if (case_count >= MAX_CASES) generror(">c"); codegen(ast->two); return NULL; }
Value *ClastExpCodeGen::codegen(const clast_reduction *r, Type *Ty) { assert((r->type == clast_red_min || r->type == clast_red_max || r->type == clast_red_sum) && "Clast reduction type not supported"); Value *old = codegen(r->elts[0], Ty); for (int i = 1; i < r->n; ++i) { Value *exprValue = codegen(r->elts[i], Ty); switch (r->type) { case clast_red_min: { Value *cmp = Builder.CreateICmpSLT(old, exprValue); old = Builder.CreateSelect(cmp, old, exprValue); break; } case clast_red_max: { Value *cmp = Builder.CreateICmpSGT(old, exprValue); old = Builder.CreateSelect(cmp, old, exprValue); break; } case clast_red_sum: old = Builder.CreateAdd(old, exprValue); break; } } return old; }
llvm::Value* Executor::codegenArrayAt(const Analyzer::BinOper* array_at, const CompilationOptions& co) { const auto arr_expr = array_at->get_left_operand(); const auto idx_expr = array_at->get_right_operand(); const auto& idx_ti = idx_expr->get_type_info(); CHECK(idx_ti.is_integer()); auto idx_lvs = codegen(idx_expr, true, co); CHECK_EQ(size_t(1), idx_lvs.size()); auto idx_lv = idx_lvs.front(); if (idx_ti.get_logical_size() < 8) { idx_lv = cgen_state_->ir_builder_.CreateCast( llvm::Instruction::CastOps::SExt, idx_lv, get_int_type(64, cgen_state_->context_)); } const auto& array_ti = arr_expr->get_type_info(); CHECK(array_ti.is_array()); const auto& elem_ti = array_ti.get_elem_type(); const std::string array_at_fname{ elem_ti.is_fp() ? "array_at_" + std::string(elem_ti.get_type() == kDOUBLE ? "double_checked" : "float_checked") : "array_at_int" + std::to_string(elem_ti.get_logical_size() * 8) + "_t_checked"}; const auto ret_ty = elem_ti.is_fp() ? (elem_ti.get_type() == kDOUBLE ? llvm::Type::getDoubleTy(cgen_state_->context_) : llvm::Type::getFloatTy(cgen_state_->context_)) : get_int_type(elem_ti.get_logical_size() * 8, cgen_state_->context_); const auto arr_lvs = codegen(arr_expr, true, co); CHECK_EQ(size_t(1), arr_lvs.size()); return cgen_state_->emitExternalCall(array_at_fname, ret_ty, {arr_lvs.front(), posArg(arr_expr), idx_lv, elem_ti.is_fp() ? static_cast<llvm::Value*>(inlineFpNull(elem_ti)) : static_cast<llvm::Value*>(inlineIntNull(elem_ti))}); }
void IRGenerator::accept(MatchStmt& stmt) { FNTRACE(); Value* cond = codegen(stmt.condition()); BasicBlock* contBlock = createBlock("match.cont"); MatchInstr* matchInstr = createMatch(stmt.op(), cond); for (const MatchCase& one: stmt.cases()) { BasicBlock* bb = createBlock("match.case"); setInsertPoint(bb); codegen(one.second.get()); createBr(contBlock); for (auto& labelNode: one.first) { Constant* label = getConstant(labelNode.get()); matchInstr->addCase(label, bb); } } if (stmt.elseStmt()) { BasicBlock* elseBlock = createBlock("match.else"); setInsertPoint(elseBlock); codegen(stmt.elseStmt()); createBr(contBlock); matchInstr->setElseBlock(elseBlock); } setInsertPoint(contBlock); }
void CodeGen_X86::visit(const EQ *op) { Type t = op->a.type(); int bits = t.lanes() * t.bits(); if (t.lanes() == 1 || bits % 128 == 0) { // LLVM is fine for native vector widths or scalars CodeGen_Posix::visit(op); } else { // Non-native vector widths get legalized poorly by llvm. We // split it up ourselves. Value *a = codegen(op->a), *b = codegen(op->b); int slice_size = 128 / t.bits(); if (target.has_feature(Target::AVX) && bits > 128) { slice_size = 256 / t.bits(); } vector<Value *> result; for (int i = 0; i < op->type.lanes(); i += slice_size) { Value *sa = slice_vector(a, i, slice_size); Value *sb = slice_vector(b, i, slice_size); Value *slice_value; if (t.is_float()) { slice_value = builder->CreateFCmpOEQ(sa, sb); } else { slice_value = builder->CreateICmpEQ(sa, sb); } result.push_back(slice_value); } value = concat_vectors(result); value = slice_vector(value, 0, t.lanes()); } }
void IRGenerator::accept(CallExpr& call) { FNTRACE(); std::vector<Value*> args; for (Expr* arg: call.args().values()) { if (Value* v = codegen(arg)) { args.push_back(v); } else { return; } } if (call.callee()->isFunction()) { Value* callee = codegen(call.callee()); // builtin function result_ = createCallFunction(static_cast<IRBuiltinFunction*>(callee), args); } else if (call.callee()->isBuiltin()) { Value* callee = codegen(call.callee()); // builtin handler result_ = createInvokeHandler(static_cast<IRBuiltinHandler*>(callee), args); } else { // source handler codegenInline(*static_cast<Handler*>(call.callee())); result_ = nullptr; } }
void CodeGen_X86::visit(const Select *op) { if (op->condition.type().is_vector()) { // LLVM handles selects on vector conditions much better at native width Value *cond = codegen(op->condition); Value *true_val = codegen(op->true_value); Value *false_val = codegen(op->false_value); Type t = op->true_value.type(); int slice_size = 128 / t.bits(); if (slice_size < t.lanes()) { slice_size = target.natural_vector_size(t); } vector<Value *> result; for (int i = 0; i < t.lanes(); i += slice_size) { Value *st = slice_vector(true_val, i, slice_size); Value *sf = slice_vector(false_val, i, slice_size); Value *sc = slice_vector(cond, i, slice_size); Value *slice_value = builder->CreateSelect(sc, st, sf); result.push_back(slice_value); } value = concat_vectors(result); value = slice_vector(value, 0, t.lanes()); } else { CodeGen_Posix::visit(op); } }
int genlst(Error_printer *err, char **argv, Pseudo ** initv, char *quote, Node * n) { switch (n->what) { case nEMPTY: { return 0; } case nADDR: { quote[0] = 1; return genlst(err, argv, initv, quote, n->r); } case nPAREN: { return genlst(err, argv, initv, quote, n->r); } case nSEMI: case nCOMMA: case nCALL: { int x = genlst(err, argv, initv, quote, n->l); return x + genlst(err, argv + x, initv + x, quote + x, n->r); /* } case nCALL: { if (n->l->what == nNAM && n->r->what == nEMPTY) return argv[0] = strdup(n->l->s), initv[0] = 0, 1; break; */ } case nNAM: { return argv[0] = strdup(n->s), initv[0] = 0, 1; } case nSET: { if (n->l->what == nNAM) return argv[0] = strdup(n->l->s), initv[0] = codegen(err, n->r), 1; else if (n->l->what == nADDR && n->l->r->what == nNAM) { quote[0] = 1; return argv[0] = strdup(n->l->r->s), initv[0] = codegen(err, n->r), 1; } break; } } error_3(err, "\"%s\" %d: incorrect argument list %s", n->loc->name, n->loc->line, what_tab[n->what].name); return 0; }
LLVMValueRef gen_left(struct node *ast) { return LLVMBuildShl(builder, codegen(ast->one), codegen(ast->two), ""); }
void CodeGen_X86::visit(const GT *op) { if (op->type.is_vector()) { // Non-native vector widths get legalized poorly by llvm. We // split it up ourselves. Type t = op->a.type(); int slice_size = 128 / t.bits(); if (slice_size < t.lanes()) { slice_size = target.natural_vector_size(t); } Value *a = codegen(op->a), *b = codegen(op->b); vector<Value *> result; for (int i = 0; i < op->type.lanes(); i += slice_size) { Value *sa = slice_vector(a, i, slice_size); Value *sb = slice_vector(b, i, slice_size); Value *slice_value; if (t.is_float()) { slice_value = builder->CreateFCmpOGT(sa, sb); } else if (t.is_int()) { slice_value = builder->CreateICmpSGT(sa, sb); } else { slice_value = builder->CreateICmpUGT(sa, sb); } result.push_back(slice_value); } value = concat_vectors(result); value = slice_vector(value, 0, t.lanes()); } else { CodeGen_Posix::visit(op); } }
static LLVMValueRef lvalue_index(struct node *ast) { LLVMValueRef ptr; ptr = LLVMBuildAdd(builder, codegen(ast->one), codegen(ast->two), ""); return rvalue_to_lvalue(ptr); }
static ValueType genMod(Func *, Cons *cons, CodeBuilder *cb, int sp) { codegen(cons, cb, sp); cons = cons->cdr; for(; cons != NULL; cons = cons->cdr) { codegen(cons, cb, sp + 1); cb->createIMod(sp, sp + 1); } return VT_INT; }
LLVMValueRef gen_inits(struct node *ast) { codegen(ast->one); if (ast->two) codegen(ast->two); return NULL; }
void IRGenerator::accept(BinaryExpr& expr) { FNTRACE(); static const std::unordered_map< int /*FlowVM::Opcode*/, Value* (IRGenerator::*)(Value*, Value*, const std::string&) > ops = { // numerical { FlowVM::Opcode::NADD, &IRGenerator::createAdd }, { FlowVM::Opcode::NSUB, &IRGenerator::createSub }, { FlowVM::Opcode::NMUL, &IRGenerator::createMul }, { FlowVM::Opcode::NDIV, &IRGenerator::createDiv }, { FlowVM::Opcode::NREM, &IRGenerator::createRem }, { FlowVM::Opcode::NSHL, &IRGenerator::createShl }, { FlowVM::Opcode::NSHR, &IRGenerator::createShr }, { FlowVM::Opcode::NPOW, &IRGenerator::createPow }, { FlowVM::Opcode::NAND, &IRGenerator::createAnd }, { FlowVM::Opcode::NOR, &IRGenerator::createOr }, { FlowVM::Opcode::NXOR, &IRGenerator::createXor }, { FlowVM::Opcode::NCMPEQ, &IRGenerator::createNCmpEQ }, { FlowVM::Opcode::NCMPNE, &IRGenerator::createNCmpNE }, { FlowVM::Opcode::NCMPLE, &IRGenerator::createNCmpLE }, { FlowVM::Opcode::NCMPGE, &IRGenerator::createNCmpGE }, { FlowVM::Opcode::NCMPLT, &IRGenerator::createNCmpLT }, { FlowVM::Opcode::NCMPGT, &IRGenerator::createNCmpGT }, // string { FlowVM::Opcode::SADD, &IRGenerator::createSAdd }, { FlowVM::Opcode::SCMPEQ, &IRGenerator::createSCmpEQ }, { FlowVM::Opcode::SCMPNE, &IRGenerator::createSCmpNE }, { FlowVM::Opcode::SCMPLE, &IRGenerator::createSCmpLE }, { FlowVM::Opcode::SCMPGE, &IRGenerator::createSCmpGE }, { FlowVM::Opcode::SCMPLT, &IRGenerator::createSCmpLT }, { FlowVM::Opcode::SCMPGT, &IRGenerator::createSCmpGT }, { FlowVM::Opcode::SCMPBEG, &IRGenerator::createSCmpEB }, { FlowVM::Opcode::SCMPEND, &IRGenerator::createSCmpEE }, //{ FlowVM::Opcode::SCONTAINS, &IRGenerator::createSContains }, // regex { FlowVM::Opcode::SREGMATCH, &IRGenerator::createSCmpRE }, }; Value* lhs = codegen(expr.leftExpr()); Value* rhs = codegen(expr.rightExpr()); auto i = ops.find(expr.op()); if (i != ops.end()) { result_ = (this->*i->second)(lhs, rhs, ""); } else { // fall back to generic VmInstr result_ = insert(new VmInstr(expr.op(), {lhs, rhs})); } }
LLVMValueRef gen_ge(struct node *ast) { LLVMValueRef truth; truth = LLVMBuildICmp(builder, LLVMIntSGE, codegen(ast->one), codegen(ast->two), ""); return LLVMBuildZExt(builder, truth, TYPE_INT, ""); }
Value *ClastExpCodeGen::codegen(const clast_expr *e, Type *Ty) { switch (e->type) { case clast_expr_name: return codegen((const clast_name *)e, Ty); case clast_expr_term: return codegen((const clast_term *)e, Ty); case clast_expr_bin: return codegen((const clast_binary *)e, Ty); case clast_expr_red: return codegen((const clast_reduction *)e, Ty); } llvm_unreachable("Unknown clast expression!"); }
void IRGenerator::accept(UnaryExpr& expr) { FNTRACE(); static const std::unordered_map< int /*FlowVM::Opcode*/, Value* (IRGenerator::*)(Value*, const std::string&) > ops = { { FlowVM::Opcode::I2S, &IRGenerator::createI2S }, { FlowVM::Opcode::P2S, &IRGenerator::createP2S }, { FlowVM::Opcode::C2S, &IRGenerator::createC2S }, { FlowVM::Opcode::R2S, &IRGenerator::createR2S }, { FlowVM::Opcode::S2I, &IRGenerator::createS2I }, { FlowVM::Opcode::NNEG, &IRGenerator::createNeg }, }; Value* rhs = codegen(expr.subExpr()); auto i = ops.find(expr.op()); if (i != ops.end()) { result_ = (this->*i->second)(rhs, ""); } else { assert(!"Unsupported unary expression in IRGenerator."); result_ = nullptr; } }
static void gen_u8_cvt(const casemap &cm, const char *ftmpl) { static const struct { unsigned first, last; } u8r[] = { {0, 0x7f}, {0x80, 0x7ff}, {0x800, 0xffff}, {0x10000, 0x1fffff} }; for (unsigned i = 0; i < sizeof(u8r) / sizeof(*u8r); i++) { casemap::const_iterator b, e; char fname[1024]; snprintf(fname, sizeof(fname), "%s_%04X_%04X.h", ftmpl, u8r[i].first, u8r[i].last); FILE *out = fopen(fname, "w"); if (!out) { perror("fopen"); exit(EXIT_FAILURE); } fprintf(out, "do {\n"); b = cm.lower_bound(u8r[i].first); if (b != cm.end()) { e = cm.upper_bound(u8r[i].last); codegen(b, e, out, "ic", gen_var_cb, spanu8); } fprintf(out, "} while (0);\n"); fclose(out); } }
/* TCC isn't threadsafe and even seems not to like having more than * one TCCState created or used at any one time in a single threaded * environment. So, this code is all for investigation only and can't * currently be used in Mesa proper. * * I've taken some liberties with globals myself, now. */ GLboolean _swrast_execute_codegen_program( GLcontext *ctx, const struct fragment_program *program, GLuint maxInst, struct fp_machine *machine, const struct sw_span *span, GLuint column ) { if (program != current_program) { _swrast_translate_program( ctx ); fprintf(stderr, "%s: compiling:\n%s\n", __FUNCTION__, program->c_str); current_program = program; current_func = codegen( current_tcc_state, program->c_str, "run_program" ); } assert(current_func); return current_func( ctx, program->Base.LocalParams, (const GLfloat (*)[4])ctx->FragmentProgram.Parameters, program->Parameters->Parameters, (const GLfloat (*)[4])machine->Inputs, machine->Outputs ); }
bool generate_passes(ast_t* program, pass_opt_t* options) { if(options->limit < PASS_LLVM_IR) return true; return codegen(program, options); }
LLVMValueRef gen_compound(struct node *ast) { if (ast->one) return codegen(ast->one); return NULL; }
LLVMValueRef gen_cond(struct node *ast) { LLVMValueRef truth; truth = LLVMBuildICmp(builder, LLVMIntNE, codegen(ast->one), CONST(0), ""); return LLVMBuildSelect(builder, truth, codegen(ast->two), codegen(ast->three), ""); }
void defun(Context *ctx, Cons *cons) { const char *name = cons->str; cons = cons->cdr; Cons *args = cons->car; cons = cons->cdr; Func *func = newFunc(name, args, genCall); func->rtype = VT_INT; ctx->putFunc(func); CodeBuilder cb(ctx, func, false, true); if(cons == NULL) { cb.createIConst(0, 0); func->rtype = VT_BOOLEAN; } else { while(cons != NULL) { func->rtype = codegen(cons, &cb, func->argc); cons = cons->cdr; } } cb.createRet(func->argc); cb.createEnd(); func->code = cb.getCode(); func->codeLength = cb.getCodeLength(); codeopt(ctx, func); }
void IRGenerator::accept(Handler& handler) { FNTRACE(); setHandler(getHandler(handler.name())); setInsertPoint(createBlock("EntryPoint")); this->handler()->setEntryPoint(getInsertPoint()); for (Symbol* symbol: *handler.scope()) { codegen(symbol); } codegen(handler.body()); createRet(get(false)); }