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))}); }
static struct expr_val cgasm_handle_ptr_cmp(struct cgasm_context *ctx, int tok_tag, struct expr_val lhs, struct expr_val rhs) { lhs = cgasm_handle_deref_flag(ctx, lhs); rhs = cgasm_handle_deref_flag(ctx, rhs); // allow pointer to compare with integer if ((lhs.ctype->tag != T_PTR && lhs.ctype->tag != T_INT) || (rhs.ctype->tag != T_PTR && rhs.ctype->tag != T_INT)) { panic("pointer required"); } lhs.ctype = get_int_type(); // convert to int type rhs.ctype = get_int_type(); return cgasm_handle_binary_op(ctx, tok_tag, lhs, rhs); }
DexClass* create_merger_class(const DexType* type, const DexType* super_type, const std::vector<DexField*>& merger_fields, const TypeSet& interfaces, bool add_type_tag_field, bool with_default_ctor /* false */) { always_assert(type && super_type); std::vector<DexField*> fields; if (add_type_tag_field) { auto type_tag_field = static_cast<DexField*>(DexField::make_field( type, DexString::make_string(INTERNAL_TYPE_TAG_FIELD_NAME), get_int_type())); type_tag_field->make_concrete(ACC_PUBLIC | ACC_FINAL); fields.push_back(type_tag_field); } for (auto f : merger_fields) { fields.push_back(f); } // Put merger class in the same package as super_type. auto pkg_name = get_merger_package_name(super_type); auto cls = create_class(type, super_type, pkg_name, fields, interfaces, with_default_ctor); TRACE(TERA, 3, " created merger class w/ fields %s \n", SHOW(cls)); return cls; }
static struct expr_val cgasm_handle_ptr_add(struct cgasm_context *ctx, struct expr_val lhs, struct expr_val rhs) { lhs = cgasm_handle_deref_flag(ctx, lhs); rhs = cgasm_handle_deref_flag(ctx, rhs); assert(lhs.ctype->tag == T_PTR || rhs.ctype->tag == T_PTR); if (lhs.ctype->tag == T_PTR && rhs.ctype->tag == T_PTR) { panic("add ptr to ptr is not valid"); } if (lhs.ctype->tag != T_PTR) { struct expr_val tmp = lhs; lhs = rhs; rhs = tmp; } if (!is_integer_type(rhs.ctype)) { panic("ptr is only allowed to add with integer type"); } struct type *ptrtype = lhs.ctype; struct type *subtype = ptrtype->subtype; lhs.ctype = get_int_type(); // convert to int struct expr_val res; if (subtype->tag != T_VOID && type_get_size(subtype) != 1) { rhs = cgasm_handle_binary_op(ctx, TOK_STAR, rhs, int_const_expr_val(type_get_size(subtype))); } res = cgasm_handle_binary_op(ctx, TOK_ADD, lhs, rhs); res = cgasm_handle_deref_flag(ctx, res); res.ctype = ptrtype; return res; }
std::vector<DexField*> create_merger_fields( const DexType* owner, const std::vector<DexField*>& mergeable_fields) { std::vector<DexField*> res; size_t cnt = 0; for (const auto f : mergeable_fields) { auto type = f->get_type(); std::string name; if (type == get_byte_type() || type == get_char_type() || type == get_short_type() || type == get_int_type()) { type = get_int_type(); name = "i"; } else if (type == get_boolean_type()) { type = get_boolean_type(); name = "z"; } else if (type == get_long_type()) { type = get_long_type(); name = "j"; } else if (type == get_float_type()) { type = get_float_type(); name = "f"; } else if (type == get_double_type()) { type = get_double_type(); name = "d"; } else { static DexType* string_type = DexType::make_type("Ljava/lang/String;"); if (type == string_type) { type = string_type; name = "s"; } else { char t = type_shorty(type); always_assert(t == 'L' || t == '['); type = get_object_type(); name = "l"; } } name = name + std::to_string(cnt); auto field = static_cast<DexField*>( DexField::make_field(owner, DexString::make_string(name), type)); field->make_concrete(ACC_PUBLIC); res.push_back(field); cnt++; } TRACE(TERA, 8, " created merger fields %d \n", res.size()); return res; }
void MethodBlock::load_const(Location& loc, int32_t value) { always_assert(!loc.is_wide()); DexInstruction* load = new DexInstruction(OPCODE_CONST_16); load->set_dest(reg_num(loc)); load->set_literal(value); loc.type = get_int_type(); push_instruction(load); }
void MethodBlock::binop_lit8(IROpcode op, const Location& dest, const Location& src, int8_t literal) { always_assert(OPCODE_ADD_INT_LIT8 <= op && op <= OPCODE_USHR_INT_LIT8); always_assert(dest.type == src.type); always_assert(dest.type == get_int_type()); IRInstruction* insn = new IRInstruction(op); insn->set_dest(dest.get_reg()); insn->set_src(0, src.get_reg()); insn->set_literal(literal); push_instruction(insn); }
static struct expr_val cgasm_handle_ptr_sub(struct cgasm_context *ctx, struct expr_val lhs, struct expr_val rhs) { lhs = cgasm_handle_deref_flag(ctx, lhs); rhs = cgasm_handle_deref_flag(ctx, rhs); if (lhs.ctype->tag == T_PTR && is_integer_type(rhs.ctype)) { struct type *oldtype = lhs.ctype; struct type *subtype = lhs.ctype->subtype; if (subtype->tag != T_VOID && type_get_size(subtype) != 1) { panic("non unit ptr"); } lhs.ctype = get_int_type(); struct expr_val res = cgasm_handle_binary_op(ctx, TOK_SUB, lhs, rhs); res = cgasm_handle_deref_flag(ctx, res); res.ctype = oldtype; return res; } if (lhs.ctype->tag == T_PTR && rhs.ctype->tag == T_PTR) { if (!type_eq(lhs.ctype->subtype, rhs.ctype->subtype)) { panic("incompatible pointer types"); } struct type *elem_type = lhs.ctype->subtype; lhs.ctype = get_int_type(); rhs.ctype = get_int_type(); struct expr_val res = cgasm_handle_binary_op(ctx, TOK_SUB, lhs, rhs); int elem_size = type_get_size(elem_type); if (elem_type->tag != T_VOID && elem_size != 1) { res = cgasm_handle_binary_op(ctx, TOK_DIV, res, int_const_expr_val(elem_size)); } return res; } panic("invalid ptr subtraction"); }
int get_scaled_double(const paramdsc* v, double& rc) { ISC_INT64 iv; int rct = get_int_type(v, iv); if (rct < 0) rct = get_double_type(v, rc); else { rc = static_cast<double>(iv); int scale = v->dsc_scale; for (; scale < 0; ++scale) rc /= 10; for (; scale > 0; --scale) rc *= 10; } return rct; }
// Returns the type of a unary expression. // // The operand of a unary arithmetic expression (-e, +e, and ~e) // shall have integer type. The result type the expression is `int`. // // The operand of the unary logical expression (!e) shall have // boolean type. The result type the expression is `bool`. Type const* get_type(Unary_op op, Expr const* e) { Type const* z = get_int_type(); Type const* b = get_bool_type(); switch (op) { case num_neg_op: case num_pos_op: case bit_not_op: return expect_type(e, z, z); case log_not_op: return expect_type(e, b, b); default: break; } lingo_unreachable(); }
// Returns the type of a binary expression. // // The operands of a binary arithmetic expression (e1 + e2, e1 - e2, // e1 * e2, e1 / e2, e1 % e2, e1 & e2, e1 | e2, e1 ^ e2, e1 << e2, // and e1 >> e2) shall have integer type. The result type the // expression is `int`. // // The operands of a binary relational expression (e1 < e2, e1 > e2, // e1 <= e2, e1 >= e2, e1 == e2, and e1 != e2) shall have integer or // boolean type. The result type the expression is `bool`. // // The operands of a binary logical expression (e1 && e2 and e1 || e2) // shall have boolean type. The result type the expression is `bool`. Type const* get_type(Binary_op op, Expr const* e1, Expr const* e2) { Type const* z = get_int_type(); Type const* b = get_bool_type(); switch (op) { case num_add_op: case num_sub_op: case num_mul_op: case num_div_op: case num_mod_op: case bit_and_op: case bit_or_op: case bit_xor_op: case bit_lsh_op: case bit_rsh_op: // Arithmetic expressions have integer opreands and results. return expect_type(e1, e2, z, z); case rel_eq_op: case rel_ne_op: case rel_lt_op: case rel_gt_op: case rel_le_op: case rel_ge_op: // Relational expressions have any type and the result // is bool. return b; case log_and_op: case log_or_op: // Logical expressions have boolean operands and result. return expect_type(e1, e2, b, b); default: break; } lingo_unreachable(); }
// Returns the canonical type `int8`. inline int_type& builder::get_int8_type() { return get_int_type(8); }
// Returns the canonical type `int64`. inline int_type& builder::get_int64_type() { return get_int_type(64); }
// Returns the canonical type `int32`. inline int_type& builder::get_int32_type() { return get_int_type(32); }
IntConstant* NodeBuilder::int_const(IInteger c) { return create_int_constant(_suif_env, get_int_type(), c); }
VariableSymbol* NodeBuilder::new_int_var(LString name, bool addr_taken) { return new_var(name, get_int_type()); }
Executor::GroupColLLVMValue Executor::groupByColumnCodegen(Analyzer::Expr* group_by_col, const size_t col_width, const CompilationOptions& co, const bool translate_null_val, const int64_t translated_null_val, GroupByAndAggregate::DiamondCodegen& diamond_codegen, std::stack<llvm::BasicBlock*>& array_loops, const bool thread_mem_shared) { #ifdef ENABLE_KEY_COMPACTION CHECK_GE(col_width, sizeof(int32_t)); #else CHECK_EQ(col_width, sizeof(int64_t)); #endif auto group_key = codegen(group_by_col, true, co).front(); auto key_to_cache = group_key; if (dynamic_cast<Analyzer::UOper*>(group_by_col) && static_cast<Analyzer::UOper*>(group_by_col)->get_optype() == kUNNEST) { auto preheader = cgen_state_->ir_builder_.GetInsertBlock(); auto array_loop_head = llvm::BasicBlock::Create( cgen_state_->context_, "array_loop_head", cgen_state_->row_func_, preheader->getNextNode()); diamond_codegen.setFalseTarget(array_loop_head); const auto ret_ty = get_int_type(32, cgen_state_->context_); auto array_idx_ptr = cgen_state_->ir_builder_.CreateAlloca(ret_ty); CHECK(array_idx_ptr); cgen_state_->ir_builder_.CreateStore(ll_int(int32_t(0)), array_idx_ptr); const auto arr_expr = static_cast<Analyzer::UOper*>(group_by_col)->get_operand(); const auto& array_ti = arr_expr->get_type_info(); CHECK(array_ti.is_array()); const auto& elem_ti = array_ti.get_elem_type(); auto array_len = cgen_state_->emitExternalCall( "array_size", ret_ty, {group_key, posArg(arr_expr), ll_int(log2_bytes(elem_ti.get_logical_size()))}); cgen_state_->ir_builder_.CreateBr(array_loop_head); cgen_state_->ir_builder_.SetInsertPoint(array_loop_head); CHECK(array_len); auto array_idx = cgen_state_->ir_builder_.CreateLoad(array_idx_ptr); auto bound_check = cgen_state_->ir_builder_.CreateICmp(llvm::ICmpInst::ICMP_SLT, array_idx, array_len); auto array_loop_body = llvm::BasicBlock::Create(cgen_state_->context_, "array_loop_body", cgen_state_->row_func_); cgen_state_->ir_builder_.CreateCondBr( bound_check, array_loop_body, array_loops.empty() ? diamond_codegen.orig_cond_false_ : array_loops.top()); cgen_state_->ir_builder_.SetInsertPoint(array_loop_body); cgen_state_->ir_builder_.CreateStore(cgen_state_->ir_builder_.CreateAdd(array_idx, ll_int(int32_t(1))), array_idx_ptr); const auto array_at_fname = "array_at_" + numeric_type_name(elem_ti); const auto ar_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_); group_key = cgen_state_->emitExternalCall(array_at_fname, ar_ret_ty, {group_key, posArg(arr_expr), array_idx}); if (need_patch_unnest_double(elem_ti, isArchMaxwell(co.device_type_), thread_mem_shared)) { key_to_cache = spillDoubleElement(group_key, ar_ret_ty); } else { key_to_cache = group_key; } CHECK(array_loop_head); array_loops.push(array_loop_head); } cgen_state_->group_by_expr_cache_.push_back(key_to_cache); llvm::Value* orig_group_key{nullptr}; if (translate_null_val) { const std::string translator_func_name(col_width == sizeof(int32_t) ? "translate_null_key_i32_" : "translate_null_key_"); const auto& ti = group_by_col->get_type_info(); const auto key_type = get_int_type(ti.get_logical_size() * 8, cgen_state_->context_); orig_group_key = group_key; group_key = cgen_state_->emitCall(translator_func_name + numeric_type_name(ti), {group_key, static_cast<llvm::Value*>(llvm::ConstantInt::get(key_type, inline_int_null_val(ti))), static_cast<llvm::Value*>(llvm::ConstantInt::get(key_type, translated_null_val))}); } group_key = cgen_state_->ir_builder_.CreateBitCast(castToTypeIn(group_key, col_width * 8), get_int_type(col_width * 8, cgen_state_->context_)); if (orig_group_key) { orig_group_key = cgen_state_->ir_builder_.CreateBitCast(castToTypeIn(orig_group_key, col_width * 8), get_int_type(col_width * 8, cgen_state_->context_)); } return {group_key, orig_group_key}; }
// Returns the canonical type `int16`. inline int_type& builder::get_int16_type() { return get_int_type(16); }
Integer_expr& Builder::get_int(Integer const& n) { return get_integer(get_int_type(), n); }