static void fixnum_or(JITOperations& ops, Inliner& i) { Value* lint = ops.cast_int(i.recv()); Value* rint = ops.cast_int(i.arg(0)); Value* anded = BinaryOperator::CreateAnd(lint, rint, "fixnums_anded", ops.current_block()); Value* fix_mask = ConstantInt::get(ops.NativeIntTy, TAG_FIXNUM_MASK); Value* fix_tag = ConstantInt::get(ops.NativeIntTy, TAG_FIXNUM); Value* masked = BinaryOperator::CreateAnd(anded, fix_mask, "masked", ops.current_block()); Value* cmp = ops.create_equal(masked, fix_tag, "is_fixnum"); BasicBlock* push = ops.new_block("push_bit_or"); BasicBlock* send = i.failure(); ops.create_conditional_branch(push, send, cmp); ops.set_block(push); Value* ored = BinaryOperator::CreateOr(lint, rint, "fixnums_ored", ops.current_block()); i.exception_safe(); i.set_result(ops.as_obj(ored)); }
static void float_op(MathOperation op, Class* klass, JITOperations& ops, Inliner& i) { Value* self = i.recv(); ops.check_class(self, klass, i.failure()); Value* arg = i.arg(0); ops.check_class(arg, klass, i.failure()); Value* fself = ops.b().CreateBitCast(self, ops.state()->ptr_type("Float"), "self_float"); Value* farg = ops.b().CreateBitCast(arg, ops.state()->ptr_type("Float"), "arg_float"); Value* lhs = ops.b().CreateLoad( ops.b().CreateConstGEP2_32(fself, 0, 1, "self.value_pos"), "fself"); Value* rhs = ops.b().CreateLoad( ops.b().CreateConstGEP2_32(farg, 0, 1, "arg.value_pos"), "farg"); Value* performed = 0; switch(op) { case cAdd: performed = ops.b().CreateFAdd(lhs, rhs, "float.add"); break; case cSub: performed = ops.b().CreateFSub(lhs, rhs, "float.sub"); break; case cMultiply: performed = ops.b().CreateFMul(lhs, rhs, "float.mul"); break; case cDivide: performed = ops.b().CreateFDiv(lhs, rhs, "float.div"); break; case cMod: performed = ops.b().CreateFRem(lhs, rhs, "float.mod"); break; default: abort(); } Signature sig(ops.state(), ops.state()->ptr_type("Float")); sig << "VM"; Function* func = sig.function("rbx_float_allocate"); func->setDoesNotAlias(0, true); // return value Value* call_args[] = { ops.vm() }; CallInst* res = sig.call("rbx_float_allocate", call_args, 1, "result", ops.b()); ops.b().CreateStore( performed, ops.b().CreateConstGEP2_32(res, 0, 1)); i.exception_safe(); i.set_result(ops.b().CreateBitCast(res, ops.ObjType)); }
static void fixnum_s_eqq(JITOperations& ops, Inliner& i) { Value* cmp = ops.check_if_fixnum(i.arg(0)); Value* imm_value = ops.b().CreateSelect(cmp, ops.constant(Qtrue), ops.constant(Qfalse), "is_fixnum"); i.exception_safe(); i.set_result(imm_value); }
static void object_equal(Class* klass, JITOperations& ops, Inliner& i) { Value* self = i.recv(); ops.check_class(self, klass, i.failure()); Value* cmp = ops.create_equal(self, i.arg(0), "idenity_equal"); Value* imm_value = SelectInst::Create(cmp, ops.constant(Qtrue), ops.constant(Qfalse), "select_bool", ops.current_block()); i.exception_safe(); i.set_result(imm_value); }
static void fixnum_compare(MathOperation op, JITOperations& ops, Inliner& i) { Value* lint = ops.cast_int(i.recv()); Value* rint = ops.cast_int(i.arg(0)); Value* anded = BinaryOperator::CreateAnd(lint, rint, "fixnums_anded", ops.current_block()); Value* fix_mask = ConstantInt::get(ops.NativeIntTy, TAG_FIXNUM_MASK); Value* fix_tag = ConstantInt::get(ops.NativeIntTy, TAG_FIXNUM); Value* masked = BinaryOperator::CreateAnd(anded, fix_mask, "masked", ops.current_block()); Value* cmp = ops.create_equal(masked, fix_tag, "is_fixnum"); BasicBlock* push = ops.new_block("push_le"); BasicBlock* send = i.failure(); ops.create_conditional_branch(push, send, cmp); ops.set_block(push); Value* performed = 0; switch(op) { case cEqual: performed = ops.b().CreateICmpEQ(lint, rint, "fixnum.eq"); break; case cLessThan: performed = ops.b().CreateICmpSLT(lint, rint, "fixnum.lt"); break; case cLessThanEqual: performed = ops.b().CreateICmpSLE(lint, rint, "fixnum.le"); break; case cGreaterThan: performed = ops.b().CreateICmpSGT(lint, rint, "fixnum.gt"); break; case cGreaterThanEqual: performed = ops.b().CreateICmpSGE(lint, rint, "fixnum.ge"); break; default: abort(); } Value* le = ops.b().CreateSelect( performed, ops.constant(Qtrue), ops.constant(Qfalse)); i.use_send_for_failure(); i.exception_safe(); i.set_result(ops.as_obj(le)); }
static void call_tuple_swap(JITOperations& ops, Inliner& i) { Value* rec = i.recv(); ops.verify_guard(ops.check_is_tuple(rec), i.failure()); Value* left_index = i.arg(0); Value* right_index = i.arg(1); Value* fix_cmp = ops.check_if_fixnums(left_index, right_index); ops.verify_guard(fix_cmp, i.failure()); // Check that index is not over the end of the Tuple Value* tup = ops.upcast(rec, "Tuple"); Value* full_size = ops.get_tuple_size(tup); Value* lindex = ops.fixnum_to_native(left_index); Value* lsize_cmp = ops.create_less_than(lindex, full_size, "is_in_bounds"); Value* rindex = ops.fixnum_to_native(right_index); Value* rsize_cmp = ops.create_less_than(rindex, full_size, "is_in_bounds"); // Combine lsize_cmp and rsize_cmp to validate entry into access code Value* access_cmp = ops.create_and(lsize_cmp, rsize_cmp, "access_cmp"); ops.verify_guard(access_cmp, i.failure()); Value* lidx[] = { ConstantInt::get(ops.state()->Int32Ty, 0), ConstantInt::get(ops.state()->Int32Ty, offset::tuple_field), lindex }; Value* lgep = ops.create_gep(tup, lidx, 3, "field_pos"); Value* ridx[] = { ConstantInt::get(ops.state()->Int32Ty, 0), ConstantInt::get(ops.state()->Int32Ty, offset::tuple_field), rindex }; Value* rgep = ops.create_gep(tup, ridx, 3, "field_pos"); Value* left_val = ops.create_load(lgep, "tuple_swap_left"); Value* right_val = ops.create_load(rgep, "tuple_swap_right"); ops.b().CreateStore(right_val, lgep); ops.b().CreateStore(left_val, rgep); i.exception_safe(); i.set_result(rec); }
static void symbol_s_eqq(JITOperations& ops, Inliner& i) { Value* sym_mask = ConstantInt::get(ops.state()->IntPtrTy, TAG_SYMBOL_MASK); Value* sym_tag = ConstantInt::get(ops.state()->IntPtrTy, TAG_SYMBOL); Value* lint = ops.cast_int(i.arg(0)); Value* masked = ops.b().CreateAnd(lint, sym_mask, "masked"); Value* cmp = ops.b().CreateICmpEQ(masked, sym_tag, "is_symbol"); Value* imm_value = ops.b().CreateSelect(cmp, ops.constant(Qtrue), ops.constant(Qfalse), "is_symbol"); i.exception_safe(); i.set_result(imm_value); }
static void call_tuple_put(JITOperations& ops, Inliner& i) { Value* rec = i.recv(); Value* cmp = ops.check_type_bits(rec, rubinius::Tuple::type); BasicBlock* is_tuple = ops.new_block("is_tuple"); BasicBlock* access = ops.new_block("tuple_put"); BasicBlock* is_other = i.failure(); ops.create_conditional_branch(is_tuple, is_other, cmp); ops.set_block(is_tuple); Value* index_val = i.arg(0); Value* fix_cmp = ops.check_if_fixnum(index_val); Value* tup = ops.upcast(rec, "Tuple"); Value* index = ops.fixnum_to_native(index_val); Value* full_size = ops.get_tuple_size(tup); Value* size_cmp = ops.create_less_than(index, full_size, "is_in_bounds"); // Combine fix_cmp and size_cmp to validate entry into access code Value* access_cmp = ops.create_and(fix_cmp, size_cmp, "access_cmp"); ops.create_conditional_branch(access, is_other, access_cmp); ops.set_block(access); Value* value = i.arg(1); Value* idx[] = { ConstantInt::get(ops.state()->Int32Ty, 0), ConstantInt::get(ops.state()->Int32Ty, offset::tuple_field), index }; Value* gep = ops.create_gep(tup, idx, 3, "field_pos"); ops.create_store(value, gep); ops.write_barrier(tup, value); i.exception_safe(); i.set_result(value); }
static void fixnum_neg(JITOperations& ops, Inliner& i) { BasicBlock* use_send = i.failure(); BasicBlock* inlined = ops.new_block("fixnum_neg"); Value* self = i.recv(); Value* cmp = ops.check_if_fixnum(self); ops.create_conditional_branch(inlined, use_send, cmp); ops.set_block(inlined); Value* native = ops.fixnum_strip(self); Value* neg = BinaryOperator::CreateSub( ops.Zero, native, "to_neg", ops.current_block()); Value* more = BinaryOperator::CreateShl(neg, ops.One, "shl", ops.current_block()); Value* tagged = BinaryOperator::CreateOr(more, ops.One, "or", ops.current_block()); i.exception_safe(); i.set_result(ops.as_obj(tagged)); }
static void float_compare(MathOperation op, Class* klass, JITOperations& ops, Inliner& i) { Value* self = i.recv(); ops.check_class(self, klass, i.failure()); // Support compare against Floats and Fixnums inline BasicBlock* do_compare = ops.new_block("float_compare"); BasicBlock* check_fix = ops.new_block("check_fixnum"); Value* arg = i.arg(0); ops.check_class(arg, klass, check_fix); Value* farg = ops.b().CreateBitCast(arg, ops.state()->ptr_type("Float"), "arg_float"); Value* unboxed_rhs = ops.b().CreateLoad( ops.b().CreateConstGEP2_32(farg, 0, 1, "arg.value_pos"), "farg"); BasicBlock* unboxed_block = ops.current_block(); ops.b().CreateBr(do_compare); ops.set_block(check_fix); ops.verify_guard(ops.check_is_fixnum(arg), i.failure()); Value* converted_rhs = ops.b().CreateUIToFP( ops.fixnum_to_native(arg), unboxed_rhs->getType()); BasicBlock* converted_block = ops.current_block(); ops.b().CreateBr(do_compare); ops.set_block(do_compare); do_compare->moveAfter(converted_block); PHINode* rhs = ops.b().CreatePHI(converted_rhs->getType(), "float_rhs"); rhs->addIncoming(unboxed_rhs, unboxed_block); rhs->addIncoming(converted_rhs, converted_block); Value* fself = ops.b().CreateBitCast(self, ops.state()->ptr_type("Float"), "self_float"); Value* lhs = ops.b().CreateLoad( ops.b().CreateConstGEP2_32(fself, 0, 1, "self.value_pos"), "fself"); Value* performed = 0; switch(op) { case cEqual: performed = ops.b().CreateFCmpUEQ(lhs, rhs, "float.eq"); break; case cLessThan: performed = ops.b().CreateFCmpULT(lhs, rhs, "float.lt"); break; case cLessThanEqual: performed = ops.b().CreateFCmpULE(lhs, rhs, "float.le"); break; case cGreaterThan: performed = ops.b().CreateFCmpUGT(lhs, rhs, "float.gt"); break; case cGreaterThanEqual: performed = ops.b().CreateFCmpUGE(lhs, rhs, "float.ge"); break; default: abort(); } Value* imm_value = ops.b().CreateSelect(performed, ops.constant(Qtrue), ops.constant(Qfalse), "select_bool"); i.exception_safe(); i.set_result(imm_value); }
static void float_op(MathOperation op, Class* klass, JITOperations& ops, Inliner& i) { i.use_send_for_failure(); Value* self = i.recv(); ops.check_class(self, klass, i.failure()); Value* arg = i.arg(0); BasicBlock* not_float = ops.new_block(); ops.check_class(arg, klass, not_float); // Float#*(Float) Value* farg = ops.b().CreateBitCast(arg, ops.state()->ptr_type("Float"), "arg_float"); Value* unboxed_rhs = ops.b().CreateLoad( ops.b().CreateConstGEP2_32(farg, 0, 1, "arg.value_pos"), "farg"); BasicBlock* perform = ops.new_block(); BasicBlock* unbox_block = ops.current_block(); ops.b().CreateBr(perform); // Float#*(Fixnum) ops.set_block(not_float); ops.verify_guard(ops.check_if_fixnum(arg), i.failure()); Value* fix_rhs = ops.b().CreateSIToFP( ops.fixnum_to_native(arg), unboxed_rhs->getType()); BasicBlock* convert_block = ops.current_block(); ops.b().CreateBr(perform); // perform operation perform->moveAfter(convert_block); ops.set_block(perform); PHINode* rhs = ops.b().CreatePHI(fix_rhs->getType(), "rhs"); rhs->addIncoming(unboxed_rhs, unbox_block); rhs->addIncoming(fix_rhs, convert_block); Value* fself = ops.b().CreateBitCast(self, ops.state()->ptr_type("Float"), "self_float"); Value* lhs = ops.b().CreateLoad( ops.b().CreateConstGEP2_32(fself, 0, 1, "self.value_pos"), "fself"); Value* performed = 0; switch(op) { case cAdd: performed = ops.b().CreateFAdd(lhs, rhs, "float.add"); break; case cSub: performed = ops.b().CreateFSub(lhs, rhs, "float.sub"); break; case cMultiply: performed = ops.b().CreateFMul(lhs, rhs, "float.mul"); break; case cDivide: performed = ops.b().CreateFDiv(lhs, rhs, "float.div"); break; case cMod: performed = ops.b().CreateFRem(lhs, rhs, "float.mod"); break; default: abort(); } Signature sig(ops.state(), ops.state()->ptr_type("Float")); sig << "VM"; Function* func = sig.function("rbx_float_allocate"); func->setDoesNotAlias(0, true); // return value Value* call_args[] = { ops.vm() }; CallInst* res = sig.call("rbx_float_allocate", call_args, 1, "result", ops.b()); ops.b().CreateStore( performed, ops.b().CreateConstGEP2_32(res, 0, 1)); i.exception_safe(); i.set_result(ops.b().CreateBitCast(res, ops.ObjType)); }