Browse files

floating point arithmetic optimization: Float objects are now immedia…

…te types and we generate optimized machine code for arithmetic operations dealing with floats

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/experimental@1870 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent 15a24d2 commit 01528a725728304b8d725f4247d71e5e25a298e3 @lrz lrz committed Jun 18, 2009
Showing with 422 additions and 187 deletions.
  1. +354 −170 compiler.cpp
  2. +6 −0 compiler.h
  3. +39 −8 include/ruby/ruby.h
  4. +19 −8 numeric.c
  5. +4 −1 parse.y
View
524 compiler.cpp
@@ -123,6 +123,7 @@ RoxorCompiler::RoxorCompiler(const char *_fname)
zeroVal = ConstantInt::get(IntTy, 0);
oneVal = ConstantInt::get(IntTy, 1);
twoVal = ConstantInt::get(IntTy, 2);
+ threeVal = ConstantInt::get(IntTy, 3);
RubyObjPtrTy = PointerType::getUnqual(RubyObjTy);
RubyObjPtrPtrTy = PointerType::getUnqual(RubyObjPtrTy);
@@ -1514,8 +1515,182 @@ RoxorCompiler::compile_rethrow_exception(void)
new UnreachableInst(bb);
}
+typedef struct rb_vm_immediate_val {
+ int type;
+ union {
+ long l;
+ double d;
+ } v;
+ rb_vm_immediate_val(void) { type = 0; }
+ bool is_fixnum(void) { return type == T_FIXNUM; }
+ bool is_float(void) { return type == T_FLOAT; }
+ long long_val(void) { return is_fixnum() ? v.l : (long)v.d; }
+ double double_val(void) { return is_float() ? v.d : (double)v.l; }
+} rb_vm_immediate_val_t;
+
+static bool
+unbox_immediate_val(VALUE rval, rb_vm_immediate_val_t *val)
+{
+ if (rval != Qundef) {
+ if (FIXNUM_P(rval)) {
+ val->type = T_FIXNUM;
+ val->v.l = FIX2LONG(rval);
+ return true;
+ }
+ else if (FIXFLOAT_P(rval)) {
+ val->type = T_FLOAT;
+ val->v.d = FIXFLOAT2DBL(rval);
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class T> static bool
+optimized_const_immediate_op(SEL sel, T leftVal, T rightVal,
+ bool *is_predicate, T *res_p)
+{
+ T res;
+ if (sel == selPLUS) {
+ res = leftVal + rightVal;
+ }
+ else if (sel == selMINUS) {
+ res = leftVal - rightVal;
+ }
+ else if (sel == selDIV) {
+ if (rightVal == 0) {
+ return false;
+ }
+ res = leftVal / rightVal;
+ }
+ else if (sel == selMULT) {
+ res = leftVal * rightVal;
+ }
+ else {
+ *is_predicate = true;
+ if (sel == selLT) {
+ res = leftVal < rightVal;
+ }
+ else if (sel == selLE) {
+ res = leftVal <= rightVal;
+ }
+ else if (sel == selGT) {
+ res = leftVal > rightVal;
+ }
+ else if (sel == selGE) {
+ res = leftVal >= rightVal;
+ }
+ else if (sel == selEq || sel == selEqq) {
+ res = leftVal == rightVal;
+ }
+ else if (sel == selNeq) {
+ res = leftVal != rightVal;
+ }
+ else {
+ abort();
+ }
+ }
+ *res_p = res;
+ return true;
+}
+
Value *
-RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> &params)
+RoxorCompiler::optimized_immediate_op(SEL sel, Value *leftVal, Value *rightVal,
+ bool float_op, bool *is_predicate)
+{
+ Value *res;
+ if (sel == selPLUS) {
+ res = BinaryOperator::CreateAdd(leftVal, rightVal, "", bb);
+ }
+ else if (sel == selMINUS) {
+ res = BinaryOperator::CreateSub(leftVal, rightVal, "", bb);
+ }
+ else if (sel == selDIV) {
+ res = float_op
+ ? BinaryOperator::CreateFDiv(leftVal, rightVal, "", bb)
+ : BinaryOperator::CreateSDiv(leftVal, rightVal, "", bb);
+
+ }
+ else if (sel == selMULT) {
+ res = BinaryOperator::CreateMul(leftVal, rightVal, "", bb);
+ }
+ else {
+ *is_predicate = true;
+
+ CmpInst::Predicate predicate;
+
+ if (sel == selLT) {
+ predicate = float_op ? FCmpInst::FCMP_OLT : ICmpInst::ICMP_SLT;
+ }
+ else if (sel == selLE) {
+ predicate = float_op ? FCmpInst::FCMP_OLE : ICmpInst::ICMP_SLE;
+ }
+ else if (sel == selGT) {
+ predicate = float_op ? FCmpInst::FCMP_OGT : ICmpInst::ICMP_SGT;
+ }
+ else if (sel == selGE) {
+ predicate = float_op ? FCmpInst::FCMP_OGE : ICmpInst::ICMP_SGE;
+ }
+ else if (sel == selEq || sel == selEqq) {
+ predicate = float_op ? FCmpInst::FCMP_OEQ : ICmpInst::ICMP_EQ;
+ }
+ else if (sel == selNeq) {
+ predicate = float_op ? FCmpInst::FCMP_ONE : ICmpInst::ICMP_NE;
+ }
+ else {
+ abort();
+ }
+
+ if (float_op) {
+ res = new FCmpInst(predicate, leftVal, rightVal, "", bb);
+ }
+ else {
+ res = new ICmpInst(predicate, leftVal, rightVal, "", bb);
+ }
+ res = SelectInst::Create(res, trueVal, falseVal, "", bb);
+ }
+ return res;
+}
+
+Value *
+RoxorCompiler::compile_double_coercion(Value *val, Value *mask,
+ BasicBlock *fallback_bb, Function *f)
+{
+ Value *is_float = new ICmpInst(ICmpInst::ICMP_EQ,
+ mask, threeVal, "", bb);
+
+ BasicBlock *is_float_bb = BasicBlock::Create("is_float", f);
+ BasicBlock *isnt_float_bb = BasicBlock::Create("isnt_float", f);
+ BasicBlock *merge_bb = BasicBlock::Create("merge", f);
+
+ BranchInst::Create(is_float_bb, isnt_float_bb, is_float, bb);
+
+ bb = is_float_bb;
+ Value *is_float_val = BinaryOperator::CreateXor(val, threeVal, "", bb);
+ is_float_val = new BitCastInst(is_float_val, Type::DoubleTy, "", bb);
+ BranchInst::Create(merge_bb, bb);
+
+ bb = isnt_float_bb;
+ Value *is_fixnum = new ICmpInst(ICmpInst::ICMP_EQ, mask, oneVal, "", bb);
+ BasicBlock *is_fixnum_bb = BasicBlock::Create("is_fixnum", f);
+ BranchInst::Create(is_fixnum_bb, fallback_bb, is_fixnum, bb);
+
+ bb = is_fixnum_bb;
+ Value *is_fixnum_val = BinaryOperator::CreateAShr(val, twoVal, "", bb);
+ is_fixnum_val = new SIToFPInst(is_fixnum_val, Type::DoubleTy, "", bb);
+ BranchInst::Create(merge_bb, bb);
+
+ bb = merge_bb;
+ PHINode *pn = PHINode::Create(Type::DoubleTy, "op_tmp", bb);
+ pn->addIncoming(is_float_val, is_float_bb);
+ pn->addIncoming(is_fixnum_val, is_fixnum_bb);
+
+ return pn;
+}
+
+Value *
+RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc,
+ std::vector<Value *> &params)
{
// The not operator (!).
if (sel == selNot) {
@@ -1560,7 +1735,7 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
Value *leftVal = params[1]; // self
Value *rightVal = params.back();
- VALUE leftRVal = 0, rightRVal = 0;
+ VALUE leftRVal = Qundef, rightRVal = Qundef;
const bool leftIsConstant = unbox_ruby_constant(leftVal, &leftRVal);
const bool rightIsConst = unbox_ruby_constant(rightVal, &rightRVal);
@@ -1608,57 +1783,52 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
}
}
- const bool leftIsFixnumConstant = FIXNUM_P(leftRVal);
- const bool rightIsFixnumConstant = FIXNUM_P(rightRVal);
-
- long leftLong = leftIsFixnumConstant ? FIX2LONG(leftRVal) : 0;
- long rightLong = rightIsFixnumConstant ? FIX2LONG(rightRVal) : 0;
-
- if (leftIsFixnumConstant && rightIsFixnumConstant) {
- // Both operands are fixnum constants.
- bool result_is_fixnum = true;
- long res;
-
- if (sel == selPLUS) {
- res = leftLong + rightLong;
- }
- else if (sel == selMINUS) {
- res = leftLong - rightLong;
- }
- else if (sel == selDIV) {
- if (rightLong == 0) {
- return NULL;
+ rb_vm_immediate_val_t leftImm, rightImm;
+ const bool leftIsImmediateConst = unbox_immediate_val(leftRVal,
+ &leftImm);
+ const bool rightIsImmediateConst = unbox_immediate_val(rightRVal,
+ &rightImm);
+
+ if (leftIsImmediateConst && rightIsImmediateConst) {
+ Value *res_val = NULL;
+
+ if (leftImm.is_fixnum() && rightImm.is_fixnum()) {
+ bool result_is_predicate = false;
+ long res;
+ if (optimized_const_immediate_op<long>(
+ sel,
+ leftImm.long_val(),
+ rightImm.long_val(),
+ &result_is_predicate,
+ &res)) {
+ if (result_is_predicate) {
+ res_val = res == 1 ? trueVal : falseVal;
+ }
+ else if (FIXABLE(res)) {
+ res_val = ConstantInt::get(RubyObjTy, LONG2FIX(res));
+ }
}
- res = leftLong / rightLong;
- }
- else if (sel == selMULT) {
- res = leftLong * rightLong;
}
else {
- result_is_fixnum = false;
- if (sel == selLT) {
- res = leftLong < rightLong;
- }
- else if (sel == selLE) {
- res = leftLong <= rightLong;
- }
- else if (sel == selGT) {
- res = leftLong > rightLong;
- }
- else if (sel == selGE) {
- res = leftLong >= rightLong;
- }
- else if ((sel == selEq) || (sel == selEqq)) {
- res = leftLong == rightLong;
- }
- else if (sel == selNeq) {
- res = leftLong != rightLong;
- }
- else {
- abort();
+ bool result_is_predicate = false;
+ double res;
+ if (optimized_const_immediate_op<double>(
+ sel,
+ leftImm.double_val(),
+ rightImm.double_val(),
+ &result_is_predicate,
+ &res)) {
+ if (result_is_predicate) {
+ res_val = res == 1 ? trueVal : falseVal;
+ }
+ else {
+ res_val = ConstantInt::get(RubyObjTy,
+ DBL2FIXFLOAT(res));
+ }
}
}
- if (!result_is_fixnum || FIXABLE(res)) {
+
+ if (res_val != NULL) {
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
is_redefined_val, ConstantInt::getFalse(), "", bb);
@@ -1670,9 +1840,7 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
- Value *thenVal = result_is_fixnum
- ? ConstantInt::get(RubyObjTy, LONG2FIX(res))
- : (res == 1 ? trueVal : falseVal);
+ Value *thenVal = res_val;
BranchInst::Create(mergeBB, thenBB);
bb = elseBB;
@@ -1687,169 +1855,188 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
return pn;
}
- // Non fixable (bignum), call the dispatcher.
+ // Can't optimize, call the dispatcher.
return NULL;
}
else {
- // Either one or both is not a constant fixnum.
+ // Either one or both is not a constant immediate.
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
is_redefined_val, ConstantInt::getFalse(), "", bb);
Function *f = bb->getParent();
- BasicBlock *then1BB = BasicBlock::Create("op_not_redefined", f);
- BasicBlock *then2BB = BasicBlock::Create("op_optimize", f);
- BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
- BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
+ BasicBlock *not_redefined_bb =
+ BasicBlock::Create("op_not_redefined", f);
+ BasicBlock *optimize_fixnum_bb =
+ BasicBlock::Create("op_optimize_fixnum", f);
+ BasicBlock *optimize_float_bb =
+ BasicBlock::Create("op_optimize_float", f);
+ BasicBlock *dispatch_bb = BasicBlock::Create("op_dispatch", f);
+ BasicBlock *merge_bb = BasicBlock::Create("op_merge", f);
- BranchInst::Create(then1BB, elseBB, isOpRedefined, bb);
+ BranchInst::Create(not_redefined_bb, dispatch_bb, isOpRedefined,
+ bb);
- bb = then1BB;
+ bb = not_redefined_bb;
Value *leftAndOp = NULL;
- if (!leftIsFixnumConstant) {
- leftAndOp = BinaryOperator::CreateAnd(leftVal, oneVal, "",
+ if (!leftIsImmediateConst) {
+ leftAndOp = BinaryOperator::CreateAnd(leftVal, threeVal, "",
bb);
}
Value *rightAndOp = NULL;
- if (!rightIsFixnumConstant) {
- rightAndOp = BinaryOperator::CreateAnd(rightVal, oneVal, "",
+ if (!rightIsImmediateConst) {
+ rightAndOp = BinaryOperator::CreateAnd(rightVal, threeVal, "",
bb);
}
- Value *areFixnums = NULL;
if (leftAndOp != NULL && rightAndOp != NULL) {
- Value *foo = BinaryOperator::CreateAdd(leftAndOp, rightAndOp,
- "", bb);
- areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, foo, twoVal, "", bb);
+ Value *leftIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
+ leftAndOp, oneVal, "", bb);
+ BasicBlock *left_is_fixnum_bb =
+ BasicBlock::Create("left_fixnum", f);
+ BranchInst::Create(left_is_fixnum_bb, optimize_float_bb,
+ leftIsFixnum, bb);
+
+ bb = left_is_fixnum_bb;
+ Value *rightIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
+ rightAndOp, oneVal, "", bb);
+ BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
+ rightIsFixnum, bb);
}
else if (leftAndOp != NULL) {
- areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, leftAndOp, oneVal, "", bb);
- }
- else {
- areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, rightAndOp, oneVal, "", bb);
- }
-
- Value *fastEqqVal = NULL;
- BasicBlock *fastEqqBB = NULL;
- if (sel == selEqq) {
- // compile_fast_eqq_call won't be called if #=== has been redefined
- // fixnum optimizations are done separately
- fastEqqBB = BasicBlock::Create("fast_eqq", f);
- BranchInst::Create(then2BB, fastEqqBB, areFixnums, bb);
- bb = fastEqqBB;
- fastEqqVal = compile_fast_eqq_call(leftVal, rightVal);
- fastEqqBB = bb;
- BranchInst::Create(mergeBB, bb);
+ if (rightImm.is_fixnum()) {
+ Value *leftIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
+ leftAndOp, oneVal, "", bb);
+ BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
+ leftIsFixnum, bb);
+ }
+ else {
+ BranchInst::Create(optimize_float_bb, bb);
+ }
}
- else {
- BranchInst::Create(then2BB, elseBB, areFixnums, bb);
+ else if (rightAndOp != NULL) {
+ if (leftImm.is_fixnum()) {
+ Value *rightIsFixnum = new ICmpInst(ICmpInst::ICMP_EQ,
+ rightAndOp, oneVal, "", bb);
+ BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
+ rightIsFixnum, bb);
+ }
+ else {
+ BranchInst::Create(optimize_float_bb, bb);
+ }
}
- bb = then2BB;
+
+ bb = optimize_fixnum_bb;
Value *unboxedLeft;
- if (leftIsFixnumConstant) {
- unboxedLeft = ConstantInt::get(RubyObjTy, leftLong);
+ if (leftIsImmediateConst) {
+ unboxedLeft = ConstantInt::get(IntTy, leftImm.long_val());
}
else {
- unboxedLeft = BinaryOperator::CreateAShr(leftVal, oneVal, "", bb);
+ unboxedLeft = BinaryOperator::CreateAShr(leftVal, twoVal, "",
+ bb);
}
Value *unboxedRight;
- if (rightIsFixnumConstant) {
- unboxedRight = ConstantInt::get(RubyObjTy, rightLong);
- }
- else {
- unboxedRight = BinaryOperator::CreateAShr(rightVal, oneVal, "", bb);
- }
-
- Value *opVal;
- bool result_is_fixnum = true;
- if (sel == selPLUS) {
- opVal = BinaryOperator::CreateAdd(unboxedLeft, unboxedRight, "", bb);
- }
- else if (sel == selMINUS) {
- opVal = BinaryOperator::CreateSub(unboxedLeft, unboxedRight, "", bb);
- }
- else if (sel == selDIV) {
- opVal = BinaryOperator::CreateSDiv(unboxedLeft, unboxedRight, "", bb);
- }
- else if (sel == selMULT) {
- opVal = BinaryOperator::CreateMul(unboxedLeft, unboxedRight, "", bb);
+ if (rightIsImmediateConst) {
+ unboxedRight = ConstantInt::get(IntTy, rightImm.long_val());
}
else {
- result_is_fixnum = false;
-
- CmpInst::Predicate predicate;
-
- if (sel == selLT) {
- predicate = ICmpInst::ICMP_SLT;
- }
- else if (sel == selLE) {
- predicate = ICmpInst::ICMP_SLE;
- }
- else if (sel == selGT) {
- predicate = ICmpInst::ICMP_SGT;
- }
- else if (sel == selGE) {
- predicate = ICmpInst::ICMP_SGE;
- }
- else if ((sel == selEq) || (sel == selEqq)) {
- predicate = ICmpInst::ICMP_EQ;
- }
- else if (sel == selNeq) {
- predicate = ICmpInst::ICMP_NE;
- }
- else {
- abort();
- }
-
- opVal = new ICmpInst(predicate, unboxedLeft, unboxedRight, "", bb);
- opVal = SelectInst::Create(opVal, trueVal, falseVal, "", bb);
+ unboxedRight = BinaryOperator::CreateAShr(rightVal, twoVal, "",
+ bb);
}
- Value *thenVal;
- BasicBlock *then3BB;
+ bool result_is_predicate = false;
+ Value *fix_op_res = optimized_immediate_op(sel, unboxedLeft,
+ unboxedRight, false, &result_is_predicate);
- if (result_is_fixnum) {
- Value *shift = BinaryOperator::CreateShl(opVal, oneVal, "", bb);
- thenVal = BinaryOperator::CreateOr(shift, oneVal, "", bb);
+ if (!result_is_predicate) {
+ // Box the fixnum.
+ Value *shift = BinaryOperator::CreateShl(fix_op_res, twoVal, "",
+ bb);
+ Value *boxed_op_res = BinaryOperator::CreateOr(shift, oneVal,
+ "", bb);
// Is result fixable?
Value *fixnumMax = ConstantInt::get(IntTy, FIXNUM_MAX + 1);
- Value *isFixnumMaxOk = new ICmpInst(ICmpInst::ICMP_SLT, opVal, fixnumMax, "", bb);
+ Value *isFixnumMaxOk = new ICmpInst(ICmpInst::ICMP_SLT,
+ fix_op_res, fixnumMax, "", bb);
- then3BB = BasicBlock::Create("op_fixable_max", f);
+ BasicBlock *fixable_max_bb =
+ BasicBlock::Create("op_fixable_max", f);
- BranchInst::Create(then3BB, elseBB, isFixnumMaxOk, bb);
+ BranchInst::Create(fixable_max_bb, dispatch_bb, isFixnumMaxOk,
+ bb);
- bb = then3BB;
+ bb = fixable_max_bb;
Value *fixnumMin = ConstantInt::get(IntTy, FIXNUM_MIN);
- Value *isFixnumMinOk = new ICmpInst(ICmpInst::ICMP_SGE, opVal, fixnumMin, "", bb);
+ Value *isFixnumMinOk = new ICmpInst(ICmpInst::ICMP_SGE,
+ fix_op_res, fixnumMin, "", bb);
+
+ BranchInst::Create(merge_bb, dispatch_bb, isFixnumMinOk, bb);
+ fix_op_res = boxed_op_res;
+ optimize_fixnum_bb = fixable_max_bb;
+ }
+ else {
+ BranchInst::Create(merge_bb, bb);
+ }
+
+ bb = optimize_float_bb;
+
+ if (leftIsImmediateConst) {
+ unboxedLeft = ConstantFP::get(Type::DoubleTy,
+ leftImm.double_val());
+ }
+ else {
+ unboxedLeft = compile_double_coercion(leftVal, leftAndOp,
+ dispatch_bb, f);
+ }
- BranchInst::Create(mergeBB, elseBB, isFixnumMinOk, bb);
+ if (rightIsImmediateConst) {
+ unboxedRight = ConstantFP::get(Type::DoubleTy,
+ rightImm.double_val());
}
else {
- thenVal = opVal;
- then3BB = then2BB;
- BranchInst::Create(mergeBB, then3BB);
+ unboxedRight = compile_double_coercion(rightVal, rightAndOp,
+ dispatch_bb, f);
}
- bb = elseBB;
- Value *elseVal = compile_dispatch_call(params);
- elseBB = bb;
- BranchInst::Create(mergeBB, elseBB);
+ result_is_predicate = false;
+ Value *flp_op_res = optimized_immediate_op(sel, unboxedLeft,
+ unboxedRight, true, &result_is_predicate);
- bb = mergeBB;
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, then3BB);
- pn->addIncoming(elseVal, elseBB);
+ if (!result_is_predicate) {
+ // Box the float.
+ flp_op_res = new BitCastInst(flp_op_res, RubyObjTy, "", bb);
+ flp_op_res = BinaryOperator::CreateOr(flp_op_res, threeVal,
+ "", bb);
+ }
+ optimize_float_bb = bb;
+ BranchInst::Create(merge_bb, bb);
+ bb = dispatch_bb;
+ Value *dispatch_val;
if (sel == selEqq) {
- pn->addIncoming(fastEqqVal, fastEqqBB);
+ dispatch_val = compile_fast_eqq_call(leftVal, rightVal);
}
+ else {
+ dispatch_val = compile_dispatch_call(params);
+ }
+ dispatch_bb = bb;
+ BranchInst::Create(merge_bb, bb);
+
+ bb = merge_bb;
+ PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", bb);
+ pn->addIncoming(fix_op_res, optimize_fixnum_bb);
+ pn->addIncoming(flp_op_res, optimize_float_bb);
+ pn->addIncoming(dispatch_val, dispatch_bb);
+
+// if (sel == selEqq) {
+// pn->addIncoming(fastEqqVal, fastEqqBB);
+// }
return pn;
}
@@ -4896,15 +5083,15 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
case _C_SHT:
case _C_INT:
val = new SExtInst(val, RubyObjTy, "", bb);
- val = BinaryOperator::CreateShl(val, oneVal, "", bb);
+ val = BinaryOperator::CreateShl(val, twoVal, "", bb);
val = BinaryOperator::CreateOr(val, oneVal, "", bb);
return val;
case _C_UCHR:
case _C_USHT:
case _C_UINT:
val = new ZExtInst(val, RubyObjTy, "", bb);
- val = BinaryOperator::CreateShl(val, oneVal, "", bb);
+ val = BinaryOperator::CreateShl(val, twoVal, "", bb);
val = BinaryOperator::CreateOr(val, oneVal, "", bb);
return val;
@@ -4925,15 +5112,12 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
break;
case _C_FLT:
- {
- char buf = _C_DBL;
- const Type *dbl_type = convert_type(&buf);
- val = new FPExtInst(val, dbl_type, "", bb);
- llvm_type = dbl_type;
- }
+ val = new FPExtInst(val, Type::DoubleTy, "", bb);
// fall through
case _C_DBL:
- func_name = "rb_float_new";
+ val = new BitCastInst(val, RubyObjTy, "", bb);
+ val = BinaryOperator::CreateOr(val, threeVal, "", bb);
+ return val;
break;
case _C_SEL:
View
6 compiler.h
@@ -148,6 +148,7 @@ class RoxorCompiler {
Constant *zeroVal;
Constant *oneVal;
Constant *twoVal;
+ Constant *threeVal;
Constant *nilVal;
Constant *trueVal;
Constant *falseVal;
@@ -267,6 +268,11 @@ class RoxorCompiler {
void compile_ivar_slots(Value *klass, BasicBlock::InstListType &list,
BasicBlock::InstListType::iterator iter);
bool unbox_ruby_constant(Value *val, VALUE *rval);
+ Value *optimized_immediate_op(SEL sel, Value *leftVal, Value *rightVal,
+ bool float_op, bool *is_predicate);
+ Value *compile_double_coercion(Value *val, Value *mask,
+ BasicBlock *fallback_bb, Function *f);
+
SEL mid_to_sel(ID mid, int arity);
};
View
47 include/ruby/ruby.h
@@ -167,10 +167,10 @@ typedef unsigned LONG_LONG ID;
# endif
#endif
-#define FIXNUM_MAX (LONG_MAX>>1)
-#define FIXNUM_MIN RSHIFT((long)LONG_MIN,1)
+#define FIXNUM_MAX (LONG_MAX>>2)
+#define FIXNUM_MIN RSHIFT((long)LONG_MIN,2)
-#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))
+#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<2 | FIXNUM_FLAG))
#define LONG2FIX(i) INT2FIX(i)
#define rb_fix_new(v) INT2FIX(v)
VALUE rb_int2inum(SIGNED_VALUE);
@@ -224,15 +224,21 @@ VALUE rb_ull2inum(unsigned LONG_LONG);
#define NUM2GIDT(v) NUM2LONG(v)
#endif
-#define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,1)
-#define FIX2ULONG(x) ((((VALUE)(x))>>1)&LONG_MAX)
-#define FIXNUM_P(f) (((SIGNED_VALUE)(f))&FIXNUM_FLAG)
+#define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,2)
+#define FIX2ULONG(x) ((((VALUE)(x))>>2)&LONG_MAX)
+#define FIXNUM_P(f) ((((SIGNED_VALUE)(f)) & IMMEDIATE_MASK) == FIXNUM_FLAG)
#define POSFIXABLE(f) ((f) < FIXNUM_MAX+1)
#define NEGFIXABLE(f) ((f) >= FIXNUM_MIN)
#define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
#define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK)
+
+#define VOODOO_DOUBLE(d) (*(VALUE*)(&d))
+#define DBL2FIXFLOAT(d) (VOODOO_DOUBLE(d) | FIXFLOAT_FLAG)
+#define FIXFLOAT_P(v) (((VALUE)v & IMMEDIATE_MASK) == FIXFLOAT_FLAG)
+#define FIXFLOAT2DBL(v) coerce_ptr_to_double((VALUE)v)
+
#if WITH_OBJC
# define SYMBOL_P(x) (TYPE(x) == T_SYMBOL)
# define ID2SYM(x) (rb_id2str((ID)x))
@@ -252,18 +258,29 @@ enum ruby_special_consts {
RUBY_IMMEDIATE_MASK = 0x03,
RUBY_FIXNUM_FLAG = 0x01,
+ RUBY_FIXFLOAT_FLAG = 0x03,
#if !WITH_OBJC
RUBY_SYMBOL_FLAG = 0x0e,
#endif
RUBY_SPECIAL_SHIFT = 8,
};
+// We can't directly cast a void* to a double, so we cast it to a union
+// and then extract its double member. Hacky, but effective.
+static inline double coerce_ptr_to_double(VALUE v)
+{
+ union {VALUE val; double d;} coerced_value;
+ coerced_value.val = v & ~RUBY_FIXFLOAT_FLAG; // unset the last two bits.
+ return coerced_value.d;
+}
+
#define Qfalse ((VALUE)RUBY_Qfalse)
#define Qtrue ((VALUE)RUBY_Qtrue)
#define Qnil ((VALUE)RUBY_Qnil)
#define Qundef ((VALUE)RUBY_Qundef) /* undefined value for placeholder */
#define IMMEDIATE_MASK RUBY_IMMEDIATE_MASK
#define FIXNUM_FLAG RUBY_FIXNUM_FLAG
+#define FIXFLOAT_FLAG RUBY_FIXFLOAT_FLAG
#if !WITH_OBJC
# define SYMBOL_FLAG RUBY_SYMBOL_FLAG
#endif
@@ -536,7 +553,7 @@ struct RFloat {
struct RBasic basic;
double float_value;
};
-#define RFLOAT_VALUE(v) (RFLOAT(v)->float_value)
+#define RFLOAT_VALUE(v) (FIXFLOAT_P(v) ? FIXFLOAT2DBL(v) : RFLOAT(v)->float_value)
#define DOUBLE2NUM(dbl) rb_float_new(dbl)
#if WITH_OBJC
@@ -1148,6 +1165,7 @@ rb_is_native(VALUE obj) {
#define CONDITION_TO_BOOLEAN(c) ((c) ? Qtrue : Qfalse)
VALUE rb_box_fixnum(VALUE);
+VALUE rb_box_fixfloat(VALUE);
static inline id
rb_rval_to_ocid(VALUE obj)
@@ -1162,9 +1180,12 @@ rb_rval_to_ocid(VALUE obj)
if (obj == Qnil) {
return (id)kCFNull;
}
- if (FIXNUM_P(obj)) {
+ if (FIXNUM_P(obj)) {
return (id)rb_box_fixnum(obj);
}
+ if (FIXFLOAT_P(obj)) {
+ return (id)rb_box_fixfloat(obj);
+ }
}
return (id)obj;
}
@@ -1184,6 +1205,12 @@ rb_ocid_to_rval(id obj)
if (*(Class *)obj == (Class)rb_cFixnum) {
return LONG2FIX(RFIXNUM(obj)->value);
}
+#if 0 // XXX this does not seem to be needed
+ if (*(Class *)obj == (Class)rb_cFloat) {
+ extern VALUE rb_float_new(double);
+ return rb_float_new(RFLOAT(obj)->float_value);
+ }
+#endif
if (*(Class *)obj == (Class)rb_cCFNumber) {
/* TODO NSNumber should implement the Numeric primitive methods */
if (CFNumberIsFloatType((CFNumberRef)obj)) {
@@ -1217,6 +1244,7 @@ rb_class_of(VALUE obj)
{
if (IMMEDIATE_P(obj)) {
if (FIXNUM_P(obj)) return rb_cFixnum;
+ if (FIXFLOAT_P(obj)) return rb_cFloat;
if (obj == Qtrue) return rb_cTrueClass;
#if !WITH_OBJC
if (SYMBOL_P(obj)) return rb_cSymbol;
@@ -1237,6 +1265,9 @@ rb_type(VALUE obj)
if (FIXNUM_P(obj)) {
return T_FIXNUM;
}
+ if (FIXFLOAT_P(obj)) {
+ return T_FLOAT;
+ }
if (obj == Qtrue) {
return T_TRUE;
}
View
27 numeric.c
@@ -95,6 +95,21 @@ VALUE rb_eFloatDomainError;
static CFMutableDictionaryRef fixnum_dict = NULL;
static struct RFixnum *fixnum_cache = NULL;
+static inline VALUE
+rb_box_fixfloat0(double v)
+{
+ NEWOBJ(val, struct RFloat);
+ OBJSETUP(val, rb_cFloat, T_FLOAT);
+ val->float_value = v;
+ return (VALUE)val;
+}
+
+VALUE
+rb_box_fixfloat(VALUE fixfloat)
+{
+ return rb_box_fixfloat0(NUM2DBL(fixfloat));
+}
+
VALUE
rb_box_fixnum(VALUE fixnum)
{
@@ -533,12 +548,7 @@ num_to_int(VALUE num, SEL sel)
VALUE
rb_float_new(double d)
{
- NEWOBJ(flt, struct RFloat);
- OBJSETUP(flt, rb_cFloat, T_FLOAT);
-
- flt->float_value = d;
-
- return (VALUE)flt;
+ return DBL2FIXFLOAT(d);
}
/*
@@ -1379,7 +1389,6 @@ flo_truncate(VALUE num, SEL sel)
return LONG2FIX(val);
}
-
/*
* call-seq:
* num.floor => integer
@@ -3136,6 +3145,8 @@ fix_even_p(VALUE num, SEL sel)
return Qtrue;
}
+
+
static const char *
imp_rb_float_objCType(void *rcv, SEL sel)
{
@@ -3384,6 +3395,6 @@ Init_Numeric(void)
rb_objc_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0);
rb_objc_define_method(rb_cFloat, "infinite?", flo_is_infinite_p, 0);
rb_objc_define_method(rb_cFloat, "finite?", flo_is_finite_p, 0);
-
+
rb_install_nsnumber_primitives();
}
View
5 parse.y
@@ -8765,7 +8765,10 @@ negate_lit(NODE *node)
GC_WB(&node->nd_lit, rb_funcall(node->nd_lit,tUMINUS,0,0));
break;
case T_FLOAT:
- RFLOAT(node->nd_lit)->float_value = -RFLOAT_VALUE(node->nd_lit);
+ {
+ double v = -RFLOAT_VALUE(node->nd_lit);
+ node->nd_lit = DBL2FIXFLOAT(v);
+ }
break;
default:
break;

0 comments on commit 01528a7

Please sign in to comment.