Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: MacRuby/MacRuby
...
head fork: MacRuby/MacRuby
Checking mergeability… Don't worry, you can still create the pull request.
  • 20 commits
  • 7 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jun 03, 2009
Patrick Thomson Creating a new branch to test out floating-point optimization. ae1bb3e
Patrick Thomson First attempt at adding floating-point optimization.
Floats that do not use their last two bits will be represented as FixFloats.
THIS ONLY WORKS ON 64-BIT. PROCEED WITH CAUTION.



git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1709 23306eb0-4c56-4727-a40e-e92c0eb68959
2448a11
Patrick Thomson Got rid of the FixFloat class and replaced with the Float#__immediate…
…__? method.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1710 23306eb0-4c56-4727-a40e-e92c0eb68959
c330b72
Patrick Thomson Removed the union casting, opting instead to create a union inline. T…
…his works on both C and C++.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1711 23306eb0-4c56-4727-a40e-e92c0eb68959
c46b983
Patrick Thomson Implemented preliminary compile-side optimization for floating-point …
…numbers.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1712 23306eb0-4c56-4727-a40e-e92c0eb68959
5ea5baa
Commits on Jun 04, 2009
Patrick Thomson Added a little bit of trickery to save on a whole lot of repeated code. 79357a3
Commits on Jun 05, 2009
Patrick Thomson Fixed some evil bugs related to old assumptions we were making regard…
…ing optimizations.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1744 23306eb0-4c56-4727-a40e-e92c0eb68959
aead5a7
Commits on Jun 11, 2009
Patrick Thomson Fixed an incorrect shift parameter. b7a5fe7
Commits on Jun 12, 2009
Patrick Thomson A little refactoring and some bug fixes. d12840f
Patrick Thomson More refactoring. c87324d
Commits on Jun 13, 2009
Patrick Thomson Added support for optimizing functions that add a constant floating p…
…oint value.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1851 23306eb0-4c56-4727-a40e-e92c0eb68959
9593e20
Commits on Jun 15, 2009
Patrick Thomson Got the complex case of floating-point operations working. b3e7447
Patrick Thomson Fixed comparisons to return true and false rather than numeric values. 41ded23
Patrick Thomson Changed SDivs to FDivs in the case of doubles. d51f0d1
Patrick Thomson Removed the FIXABLE_DBL() macro (all doubles are fixable now regardle…
…ss of precision loss) and cleaned up compiler.cpp a little bit.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1862 23306eb0-4c56-4727-a40e-e92c0eb68959
330f1d7
Patrick Thomson Put in checks to see if the result is fixable in compile_variable_ari…
…th_node.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1863 23306eb0-4c56-4727-a40e-e92c0eb68959
02e3b48
Patrick Thomson Got rid of an embarassing bug in compile_variable_and_floating_node. 2a50d36
Commits on Jun 16, 2009
Patrick Thomson Fixed a completely boneheaded bug in the precomplation sections. c297b19
Patrick Thomson Fixed some, but not all, zero-division issues. 245a85c
Patrick Thomson Added a TODO and got rid of the Float#__immediate__? method, as all f…
…loats are fixfloats now.

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/fp-optimized-experimental@1868 23306eb0-4c56-4727-a40e-e92c0eb68959
aaaf25d
View
1  TODO
@@ -75,3 +75,4 @@
[ ] test/spec
[ ] mocha
[X] known_bugs
+[ ] for JIT, make divide-by-zero work properly.
View
849 compiler.cpp
@@ -121,6 +121,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);
@@ -162,16 +163,14 @@ RoxorCompiler::unbox_ruby_constant(Value *val, VALUE *rval)
*rval = tmp;
return true;
}
+ else if (ConstantFP::classof(val)) {
+ double tmp = cast<ConstantFP>(val)->getValueAPF().convertToDouble();
+ *rval = tmp;
+ return true;
+ }
return false;
}
-inline ICmpInst *
-RoxorCompiler::is_value_a_fixnum(Value *val)
-{
- Value *andOp = BinaryOperator::CreateAnd(val, oneVal, "", bb);
- return new ICmpInst(ICmpInst::ICMP_EQ, andOp, oneVal, "", bb);
-}
-
Value *
RoxorCompiler::compile_protected_call(Function *func, std::vector<Value *> &params)
{
@@ -1512,127 +1511,228 @@ RoxorCompiler::compile_rethrow_exception(void)
new UnreachableInst(bb);
}
-Value *
-RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> &params)
-{
- // The not operator (!).
- if (sel == selNot) {
-
+PHINode *
+RoxorCompiler::compile_negation_node(int argc, Value *val) {
if (current_block_func != NULL || argc != 0) {
return NULL;
}
- Value *val = params[1]; // self
-
Function *f = bb->getParent();
-
+
BasicBlock *falseBB = BasicBlock::Create("", f);
BasicBlock *trueBB = BasicBlock::Create("", f);
BasicBlock *mergeBB = BasicBlock::Create("", f);
-
+
compile_boolean_test(val, trueBB, falseBB);
-
+
BranchInst::Create(mergeBB, falseBB);
BranchInst::Create(mergeBB, trueBB);
-
+
bb = mergeBB;
-
+
PHINode *pn = PHINode::Create(RubyObjTy, "", bb);
pn->addIncoming(trueVal, falseBB);
pn->addIncoming(falseVal, trueBB);
-
+
return pn;
- }
- // Pure arithmetic operations.
- else if (sel == selPLUS || sel == selMINUS || sel == selDIV
- || sel == selMULT || sel == selLT || sel == selLE
- || sel == selGT || sel == selGE || sel == selEq
- || sel == selNeq || sel == selEqq) {
-
- if (current_block_func != NULL || argc != 1) {
- return NULL;
- }
+}
+PHINode *
+RoxorCompiler::compile_symbol_equality_node(SEL sel, VALUE leftRVal, VALUE rightRVal, int argc, std::vector<Value *> &params)
+{
GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
+ Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
+ Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
+ is_redefined_val, ConstantInt::getFalse(), "", bb);
- Value *leftVal = params[1]; // self
- Value *rightVal = params.back();
-
- VALUE leftRVal = 0, rightRVal = 0;
- const bool leftIsConstant = unbox_ruby_constant(leftVal, &leftRVal);
- const bool rightIsConst = unbox_ruby_constant(rightVal, &rightRVal);
-
- if (leftIsConstant && rightIsConst
- && TYPE(leftRVal) == T_SYMBOL && TYPE(rightRVal) == T_SYMBOL) {
- // Both operands are symbol constants.
- if (sel == selEq || sel == selEqq || sel == selNeq) {
- 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 *thenBB = BasicBlock::Create("op_not_redefined", f);
- BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
- BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
+ Function *f = bb->getParent();
+
+ BasicBlock *thenBB = BasicBlock::Create("op_not_redefined", f);
+ BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
+ BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
+
+ BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
+ Value *thenVal = NULL;
+ if (sel == selEq || sel == selEqq) {
+ thenVal = leftRVal == rightRVal ? trueVal : falseVal;
+ }
+ else if (sel == selNeq) {
+ thenVal = leftRVal != rightRVal ? trueVal : falseVal;
+ }
+ else {
+ abort();
+ }
+ BranchInst::Create(mergeBB, thenBB);
+
+ bb = elseBB;
+ Value *elseVal = compile_dispatch_call(params);
+ elseBB = bb;
+ BranchInst::Create(mergeBB, elseBB);
+
+ PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
+ pn->addIncoming(thenVal, thenBB);
+ pn->addIncoming(elseVal, elseBB);
+ bb = mergeBB;
+
+ return pn;
+}
- BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
- Value *thenVal = NULL;
- if (sel == selEq || sel == selEqq) {
- thenVal = leftRVal == rightRVal ? trueVal : falseVal;
+PHINode *
+RoxorCompiler::precompile_floating_arith_node(SEL sel, double leftDouble, long rightDouble, int argc, std::vector<Value *> &params)
+{
+ GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
+ bool result_is_fixfloat = true;
+ double res;
+ // TODO: put checks in here for NaN, +/- infinity
+ if (sel == selPLUS) {
+ res = leftDouble + rightDouble;
+ }
+ else if (sel == selMINUS) {
+ res = leftDouble - rightDouble;
+ }
+ else if (sel == selMULT) {
+ res = leftDouble * rightDouble;
+ }
+ else if (sel == selDIV) {
+ if (rightDouble == 0.0) {
+ return NULL;
+ }
+ res = leftDouble / rightDouble;
+ } else {
+ result_is_fixfloat = false;
+ if (sel == selLT) {
+ res = leftDouble < rightDouble;
+ }
+ else if (sel == selLE) {
+ res = leftDouble <= rightDouble;
+ }
+ else if (sel == selGT) {
+ res = leftDouble > rightDouble;
+ }
+ else if (sel == selGE) {
+ res = leftDouble >= rightDouble;
+ }
+ else if ((sel == selEq) || (sel == selEqq)) {
+ res = leftDouble == rightDouble;
}
else if (sel == selNeq) {
- thenVal = leftRVal != rightRVal ? trueVal : falseVal;
+ res = leftDouble != rightDouble;
}
else {
- abort();
+ abort();
}
- BranchInst::Create(mergeBB, thenBB);
-
- bb = elseBB;
- Value *elseVal = compile_dispatch_call(params);
- elseBB = bb;
- BranchInst::Create(mergeBB, elseBB);
-
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, thenBB);
- pn->addIncoming(elseVal, elseBB);
- bb = mergeBB;
-
- return pn;
- }
- else {
- return NULL;
- }
}
+ 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 *thenBB = BasicBlock::Create("op_not_redefined", f);
+ BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
+ BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
+
+ BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
+ Value *thenVal = result_is_fixfloat
+ ? ConstantInt::get(RubyObjTy, DBL2FIXFLOAT(res))
+ : (res == 1 ? trueVal : falseVal);
+ BranchInst::Create(mergeBB, thenBB);
+
+ bb = elseBB;
+ Value *elseVal = compile_dispatch_call(params);
+ elseBB = bb;
+ BranchInst::Create(mergeBB, elseBB);
+
+ PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
+ pn->addIncoming(thenVal, thenBB);
+ pn->addIncoming(elseVal, elseBB);
+ bb = mergeBB;
+
+ return pn;
+}
- const bool leftIsFixnumConstant = FIXNUM_P(leftRVal);
- const bool rightIsFixnumConstant = FIXNUM_P(rightRVal);
-
- long leftLong = leftIsFixnumConstant ? FIX2LONG(leftRVal) : 0;
- long rightLong = rightIsFixnumConstant ? FIX2LONG(rightRVal) : 0;
+CmpInst::Predicate
+RoxorCompiler::integer_predicate_for_selector(SEL sel)
+{
+ 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();
+ }
+ return predicate;
+}
- if (leftIsFixnumConstant && rightIsFixnumConstant) {
- // Both operands are fixnum constants.
- bool result_is_fixnum = true;
- long res;
+CmpInst::Predicate
+RoxorCompiler::floating_point_predicate_for_selector(SEL sel)
+{
+ CmpInst::Predicate predicate;
+
+ if (sel == selLT) {
+ predicate = FCmpInst::FCMP_OLT;
+ }
+ else if (sel == selLE) {
+ predicate = FCmpInst::FCMP_OLE;
+ }
+ else if (sel == selGT) {
+ predicate = FCmpInst::FCMP_OGT;
+ }
+ else if (sel == selGE) {
+ predicate = FCmpInst::FCMP_OGE;
+ }
+ else if ((sel == selEq) || (sel == selEqq)) {
+ predicate = FCmpInst::FCMP_OEQ;
+ }
+ else if (sel == selNeq) {
+ predicate = FCmpInst::FCMP_ONE;
+ }
+ else {
+ abort();
+ }
+
+ return predicate;
+}
- if (sel == selPLUS) {
+PHINode *
+RoxorCompiler::precompile_integral_arith_node(SEL sel, long leftLong, long rightLong, int argc, std::vector<Value *> &params)
+{
+ GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
+ bool result_is_fixnum = true;
+ long res;
+
+ if (sel == selPLUS) {
res = leftLong + rightLong;
- }
- else if (sel == selMINUS) {
+ }
+ else if (sel == selMINUS) {
res = leftLong - rightLong;
- }
- else if (sel == selDIV) {
+ }
+ else if (sel == selDIV) {
if (rightLong == 0) {
return NULL;
}
res = leftLong / rightLong;
- }
- else if (sel == selMULT) {
+ }
+ else if (sel == selMULT) {
res = leftLong * rightLong;
- }
- else {
+ }
+ else {
result_is_fixnum = false;
if (sel == selLT) {
res = leftLong < rightLong;
@@ -1655,203 +1755,471 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
else {
abort();
}
- }
- if (!result_is_fixnum || FIXABLE(res)) {
+ }
+ if (!result_is_fixnum || FIXABLE(res)) {
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
- Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
- is_redefined_val, ConstantInt::getFalse(), "", bb);
-
+ Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ, is_redefined_val, ConstantInt::getFalse(), "", bb);
+
Function *f = bb->getParent();
-
+
BasicBlock *thenBB = BasicBlock::Create("op_not_redefined", f);
BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
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);
+ ? ConstantInt::get(RubyObjTy, LONG2FIX(res))
+ : (res == 1 ? trueVal : falseVal);
BranchInst::Create(mergeBB, thenBB);
-
+
bb = elseBB;
Value *elseVal = compile_dispatch_call(params);
elseBB = bb;
BranchInst::Create(mergeBB, elseBB);
-
+
PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
pn->addIncoming(thenVal, thenBB);
pn->addIncoming(elseVal, elseBB);
bb = mergeBB;
-
+
return pn;
- }
- // Non fixable (bignum), call the dispatcher.
- return NULL;
}
- else {
- // Either one or both is not a constant fixnum.
- 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);
-
- BranchInst::Create(then1BB, elseBB, isOpRedefined, bb);
-
- bb = then1BB;
-
- Value *leftAndOp = NULL;
- if (!leftIsFixnumConstant) {
- leftAndOp = BinaryOperator::CreateAnd(leftVal, oneVal, "",
- bb);
- }
-
- Value *rightAndOp = NULL;
- if (!rightIsFixnumConstant) {
- rightAndOp = BinaryOperator::CreateAnd(rightVal, oneVal, "",
- bb);
- }
+ // Non fixable (bignum), call the dispatcher.
+ return NULL;
+}
- Value *areFixnums = NULL;
- if (leftAndOp != NULL && rightAndOp != NULL) {
- Value *foo = BinaryOperator::CreateAdd(leftAndOp, rightAndOp,
- "", bb);
- areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, foo, twoVal, "", bb);
- }
- else if (leftAndOp != NULL) {
- areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, leftAndOp, oneVal, "", bb);
- }
- else {
- areFixnums = new ICmpInst(ICmpInst::ICMP_EQ, rightAndOp, oneVal, "", bb);
- }
+PHINode *
+RoxorCompiler::compile_variable_and_integral_node(SEL sel, long fixedLong, bool leftToRight, Value *targetVal, Value *otherVal,
+ int argc, std::vector<Value *> &params) {
+ if ((!leftToRight) && (fixedLong == 0) && (sel == selDIV)) {
+ return NULL; // division by zero
+ }
+ GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
+ // Either one or both of the operands was not a fixable constant.
+ 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);
+
+ BranchInst::Create(then1BB, elseBB, isOpRedefined, bb);
+ bb = then1BB;
+
+ Value *andOp = BinaryOperator::CreateAnd(targetVal, threeVal, "", bb);
+ Value *isFixnum = new ICmpInst(ICmpInst::ICMP_EQ, andOp, oneVal, "", bb);
- Value *fastEqqVal = NULL;
- BasicBlock *fastEqqBB = NULL;
- if (sel == selEqq) {
+
+ 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);
+ BranchInst::Create(then2BB, fastEqqBB, isFixnum, bb);
bb = fastEqqBB;
- fastEqqVal = compile_fast_eqq_call(leftVal, rightVal);
+ fastEqqVal = compile_fast_eqq_call(targetVal, otherVal);
fastEqqBB = bb;
BranchInst::Create(mergeBB, bb);
- }
- else {
- BranchInst::Create(then2BB, elseBB, areFixnums, bb);
- }
- bb = then2BB;
-
- Value *unboxedLeft;
- if (leftIsFixnumConstant) {
- unboxedLeft = ConstantInt::get(RubyObjTy, leftLong);
- }
- else {
- unboxedLeft = BinaryOperator::CreateAShr(leftVal, oneVal, "", 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) {
+ }
+ else {
+ BranchInst::Create(then2BB, elseBB, isFixnum, bb);
+ }
+ bb = then2BB;
+
+ Value *unboxedLeft = NULL;
+ Value *unboxedRight = NULL;
+
+ if (leftToRight) {
+ unboxedLeft = ConstantInt::get(RubyObjTy, fixedLong);
+ unboxedRight = BinaryOperator::CreateAShr(targetVal, twoVal, "", bb);
+ } else {
+ unboxedLeft = BinaryOperator::CreateAShr(targetVal, twoVal, "", bb);
+ unboxedRight = ConstantInt::get(RubyObjTy, fixedLong);
+ }
+
+ Value *opVal;
+ bool result_is_fixnum = true;
+ if (sel == selPLUS) {
opVal = BinaryOperator::CreateAdd(unboxedLeft, unboxedRight, "", bb);
- }
- else if (sel == selMINUS) {
+ }
+ else if (sel == selMINUS) {
opVal = BinaryOperator::CreateSub(unboxedLeft, unboxedRight, "", bb);
- }
- else if (sel == selDIV) {
+ }
+ else if (sel == selDIV) {
opVal = BinaryOperator::CreateSDiv(unboxedLeft, unboxedRight, "", bb);
- }
- else if (sel == selMULT) {
+ }
+ else if (sel == selMULT) {
opVal = BinaryOperator::CreateMul(unboxedLeft, unboxedRight, "", bb);
- }
- else {
+ }
+ 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();
- }
-
+ CmpInst::Predicate predicate = integer_predicate_for_selector(sel);
opVal = new ICmpInst(predicate, unboxedLeft, unboxedRight, "", bb);
opVal = SelectInst::Create(opVal, trueVal, falseVal, "", bb);
- }
-
- Value *thenVal;
- BasicBlock *then3BB;
-
- if (result_is_fixnum) {
- Value *shift = BinaryOperator::CreateShl(opVal, oneVal, "", bb);
+ }
+
+ Value *thenVal;
+ BasicBlock *then3BB;
+
+ if (result_is_fixnum) {
+ Value *shift = BinaryOperator::CreateShl(opVal, twoVal, "", bb);
thenVal = 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);
-
+
then3BB = BasicBlock::Create("op_fixable_max", f);
-
+
BranchInst::Create(then3BB, elseBB, isFixnumMaxOk, bb);
-
+
bb = then3BB;
Value *fixnumMin = ConstantInt::get(IntTy, FIXNUM_MIN);
Value *isFixnumMinOk = new ICmpInst(ICmpInst::ICMP_SGE, opVal, fixnumMin, "", bb);
-
+
BranchInst::Create(mergeBB, elseBB, isFixnumMinOk, bb);
- }
- else {
+ }
+ else {
thenVal = opVal;
then3BB = then2BB;
BranchInst::Create(mergeBB, then3BB);
- }
+ }
+
+ bb = elseBB;
+ Value *elseVal = compile_dispatch_call(params);
+ BranchInst::Create(mergeBB, elseBB);
+
+ bb = mergeBB;
+ PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
+ pn->addIncoming(thenVal, then3BB);
+ pn->addIncoming(elseVal, elseBB);
+
+ if (sel == selEqq) {
+ pn->addIncoming(fastEqqVal, fastEqqBB);
+ }
+
+ return pn;
+}
- bb = elseBB;
- Value *elseVal = compile_dispatch_call(params);
- elseBB = bb;
- BranchInst::Create(mergeBB, elseBB);
+PHINode *
+RoxorCompiler::compile_variable_arith_node(SEL sel, Value *leftVal, Value *rightVal, int argc, std::vector<Value *>params)
+{
+ GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
+ // Either one or both of the operands was not a fixable constant.
+ 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 *redefBB = BasicBlock::Create("op_not_redefined", f);
+ BasicBlock *toDblBB = BasicBlock::Create("op_optimize_floating", f);
+ BasicBlock *toIntBB = BasicBlock::Create("op_optimize_integral", f);
+ BasicBlock *then3BB = BasicBlock::Create("op_fixable_max", f);
+ BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
+ BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
+
+ BranchInst::Create(redefBB, elseBB, isOpRedefined, bb);
+ bb = redefBB;
+
+ Value *leftAndOp = BinaryOperator::CreateAnd(leftVal, threeVal, "", bb);
+ Value *rightAndOp = BinaryOperator::CreateAnd(rightVal, threeVal, "", bb);
+ Value *andSum = BinaryOperator::CreateAdd(leftAndOp, rightAndOp, "", bb);
+
+ Value *leftAsInt = NULL;
+ Value *rightAsInt = NULL;
+ Value *leftAsDouble = NULL;
+ Value *rightAsDouble = NULL;
+ Value *opVal = NULL;
+
+ SwitchInst *switcher = SwitchInst::Create(andSum, elseBB, 2, bb);
+ switcher->addCase(ConstantInt::get(IntTy, 6), toDblBB);
+ switcher->addCase(ConstantInt::get(IntTy, 2), toIntBB);
+
+ bb = toDblBB;
+ Value *unmaskedLeft = BinaryOperator::CreateXor(leftVal, threeVal, "", bb);
+ Value *unmaskedRight = BinaryOperator::CreateXor(rightVal, threeVal, "", bb);
+ leftAsDouble = new BitCastInst(unmaskedLeft, Type::DoubleTy, "", bb);
+ rightAsDouble = new BitCastInst(unmaskedRight, Type::DoubleTy, "", bb);
+ bool result_is_bool = false;
+ if (sel == selPLUS) {
+ opVal = BinaryOperator::CreateAdd(leftAsDouble, rightAsDouble, "", bb);
+ }
+ else if (sel == selMINUS) {
+ opVal = BinaryOperator::CreateSub(leftAsDouble, rightAsDouble, "", bb);
+ }
+ else if (sel == selDIV) {
+ opVal = BinaryOperator::CreateFDiv(leftAsDouble, rightAsDouble, "", bb);
+ }
+ else if (sel == selMULT) {
+ opVal = BinaryOperator::CreateMul(leftAsDouble, rightAsDouble, "", bb);
+ }
+ else {
+ result_is_bool = true;
+ CmpInst::Predicate predicate = floating_point_predicate_for_selector(sel);
+ opVal = new FCmpInst(predicate, leftAsDouble, rightAsDouble, "", bb);
+ opVal = SelectInst::Create(opVal, trueVal, falseVal, "", bb);
+ }
+
+ Value *dblReturnResult;
+ if (result_is_bool) {
+ dblReturnResult = opVal;
+ } else {
+ Value *castedResult = new BitCastInst(opVal, IntTy, "", bb);
+ dblReturnResult = BinaryOperator::CreateOr(castedResult, threeVal, "", bb);
+ }
+ BranchInst::Create(mergeBB, toDblBB);
+
+ bb = toIntBB;
+ leftAsInt = BinaryOperator::CreateAShr(leftVal, twoVal, "", bb);
+ rightAsInt = BinaryOperator::CreateAShr(rightVal, twoVal, "", bb);
+
+ if (sel == selPLUS) {
+ opVal = BinaryOperator::CreateAdd(leftAsInt, rightAsInt, "", bb);
+ }
+ else if (sel == selMINUS) {
+ opVal = BinaryOperator::CreateSub(leftAsInt, rightAsInt, "", bb);
+ }
+ else if (sel == selDIV) {
+ opVal = BinaryOperator::CreateSDiv(leftAsInt, rightAsInt, "", bb);
+ }
+ else if (sel == selMULT) {
+ opVal = BinaryOperator::CreateMul(leftAsInt, rightAsInt, "", bb);
+ }
+ else {
+ result_is_bool = true;
+
+ CmpInst::Predicate predicate = integer_predicate_for_selector(sel);
+ opVal = new ICmpInst(predicate, leftAsInt, rightAsInt, "", bb);
+ opVal = SelectInst::Create(opVal, trueVal, falseVal, "", bb);
+ }
+
+ Value *intReturnResult = NULL;
+ if(result_is_bool) {
+ intReturnResult = opVal;
+ }
+ else {
+ Value *shiftedResult = BinaryOperator::CreateShl(opVal, twoVal, "", bb);
+ intReturnResult = BinaryOperator::CreateOr(shiftedResult, oneVal, "", bb);
+
+ // Is result fixable?
+ Value *fixnumMax = ConstantInt::get(IntTy, FIXNUM_MAX + 1);
+ Value *isFixnumMaxOk = new ICmpInst(ICmpInst::ICMP_SLT, opVal, fixnumMax, "", bb);
+ BranchInst::Create(then3BB, elseBB, isFixnumMaxOk, bb);
+
+ bb = then3BB;
+ Value *fixnumMin = ConstantInt::get(IntTy, FIXNUM_MIN);
+ Value *isFixnumMinOk = new ICmpInst(ICmpInst::ICMP_SGE, opVal, fixnumMin, "", bb);
+
+ BranchInst::Create(mergeBB, elseBB, isFixnumMinOk, bb);
+ }
+
+ bb = elseBB;
+ Value *elseVal = compile_dispatch_call(params);
+ elseBB = bb;
+ BranchInst::Create(mergeBB, elseBB);
+
+ bb = mergeBB;
+ PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
+ pn->addIncoming(dblReturnResult, toDblBB);
+ pn->addIncoming(intReturnResult, then3BB);
+ pn->addIncoming(elseVal, elseBB);
- bb = mergeBB;
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, then3BB);
- pn->addIncoming(elseVal, elseBB);
+ return pn;
+}
- if (sel == selEqq) {
+PHINode *
+RoxorCompiler::compile_variable_and_floating_node(SEL sel, double fixedDouble, bool leftToRight, Value *targetVal, Value *otherVal,
+ int argc, std::vector<Value *> &params)
+{
+ if ((!leftToRight) && (fixedDouble == 0.0) && (sel == selDIV)) {
+ return NULL; // division by zero
+ }
+ GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
+ // Either one or both of the operands was not a fixable constant.
+ 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);
+
+ BranchInst::Create(then1BB, elseBB, isOpRedefined, bb);
+ bb = then1BB;
+
+ Value *andOp = BinaryOperator::CreateAnd(targetVal, threeVal, "", bb);
+ Value *isDouble = new ICmpInst(ICmpInst::ICMP_EQ, andOp, threeVal, "", 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, isDouble, bb);
+ bb = fastEqqBB;
+ fastEqqVal = compile_fast_eqq_call(targetVal, otherVal);
+ fastEqqBB = bb;
+ BranchInst::Create(mergeBB, bb);
+ }
+ else {
+ BranchInst::Create(then2BB, elseBB, isDouble, bb);
+ }
+ bb = then2BB;
+
+
+ Value *left = NULL;
+ Value *right = NULL;
+ if (leftToRight) {
+ left = ConstantFP::get(Type::DoubleTy, fixedDouble);
+ right = BinaryOperator::CreateXor(targetVal, threeVal, "", bb);
+ right = new BitCastInst(right, Type::DoubleTy, "", bb);
+ } else {
+ right = ConstantFP::get(Type::DoubleTy, fixedDouble);
+ left = BinaryOperator::CreateXor(targetVal, threeVal, "", bb);
+ left = new BitCastInst(right, Type::DoubleTy, "", bb);
+ }
+
+
+
+ Value *opVal;
+ bool result_is_double = true;
+ if (sel == selPLUS) {
+ opVal = BinaryOperator::CreateAdd(left, right, "", bb);
+ }
+ else if (sel == selMINUS) {
+ opVal = BinaryOperator::CreateSub(left, right, "", bb);
+ }
+ else if (sel == selDIV) {
+ opVal = BinaryOperator::CreateFDiv(left, right, "", bb);
+ }
+ else if (sel == selMULT) {
+ opVal = BinaryOperator::CreateMul(left, right, "", bb);
+ }
+ else {
+ result_is_double = false;
+ CmpInst::Predicate predicate = floating_point_predicate_for_selector(sel);
+ opVal = new FCmpInst(predicate, left, right, "", bb);
+ opVal = SelectInst::Create(opVal, trueVal, falseVal, "", bb);
+ }
+
+ Value *thenVal;
+ BasicBlock *then3BB;
+
+ if (result_is_double) {
+ Value *casted = new BitCastInst(opVal, IntTy, "", bb);
+ thenVal = BinaryOperator::CreateOr(casted, threeVal, "", bb);
+ then3BB = bb;
+ BranchInst::Create(mergeBB, bb);
+ }
+ else {
+ thenVal = opVal;
+ then3BB = then2BB;
+ BranchInst::Create(mergeBB, then3BB);
+ }
+
+ bb = elseBB;
+ Value *elseVal = compile_dispatch_call(params);
+ elseBB = bb;
+ BranchInst::Create(mergeBB, elseBB);
+
+ bb = mergeBB;
+ PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
+ pn->addIncoming(thenVal, then3BB);
+ pn->addIncoming(elseVal, elseBB);
+
+ if (sel == selEqq) {
pn->addIncoming(fastEqqVal, fastEqqBB);
+ }
+
+ return pn;
+
+}
+
+Value *
+RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> &params)
+{
+ // The not operator (!).
+ if (sel == selNot) {
+ return compile_negation_node(argc, params[1]);
+ }
+ // Pure arithmetic operations.
+ else if (sel == selPLUS || sel == selMINUS || sel == selDIV
+ || sel == selMULT || sel == selLT || sel == selLE
+ || sel == selGT || sel == selGE || sel == selEq
+ || sel == selNeq || sel == selEqq) {
+
+ if (current_block_func != NULL || argc != 1) {
+ return NULL;
+ }
+
+ Value *leftVal = params[1]; // self
+ Value *rightVal = params.back();
+
+ VALUE leftRVal = 0, rightRVal = 0;
+ const bool leftIsConstant = unbox_ruby_constant(leftVal, &leftRVal);
+ const bool rightIsConst = unbox_ruby_constant(rightVal, &rightRVal);
+
+ if (leftIsConstant && rightIsConst && TYPE(leftRVal) == T_SYMBOL && TYPE(rightRVal) == T_SYMBOL) {
+ // Both operands are symbol constants.
+ if (sel == selEq || sel == selEqq || sel == selNeq) {
+ return compile_symbol_equality_node(sel, leftRVal, rightRVal, argc, params);
+ }
+ else {
+ return NULL;
}
+ }
+
+ const bool leftIsFixnumConstant = FIXNUM_P(leftRVal);
+ const bool rightIsFixnumConstant = FIXNUM_P(rightRVal);
+
+ long leftLong = leftIsFixnumConstant ? FIX2LONG(leftRVal) : 0;
+ long rightLong = rightIsFixnumConstant ? FIX2LONG(rightRVal) : 0;
+
+ bool leftIsFixFloatConstant = FIXFLOAT_P(leftRVal);
+ bool rightIsFixFloatConstant = FIXFLOAT_P(rightRVal);
+
+ double leftDouble = leftIsFixFloatConstant ? FIXFLOAT2DBL(leftRVal) : 0;
+ double rightDouble = rightIsFixFloatConstant ? FIXFLOAT2DBL(rightRVal) : 0;
+
+
- return pn;
+ if (leftIsFixnumConstant && rightIsFixnumConstant) {
+ return precompile_integral_arith_node(sel, leftLong, rightLong, argc, params);
+ }
+ else if (leftIsFixFloatConstant && rightIsFixnumConstant) {
+ return precompile_floating_arith_node(sel, leftDouble, (double)rightLong, argc, params);
+ }
+ else if (leftIsFixnumConstant && rightIsFixFloatConstant) {
+ return precompile_floating_arith_node(sel, (double)leftLong, rightDouble, argc, params);
+ }
+ else if (leftIsFixFloatConstant && rightIsFixFloatConstant) {
+ return precompile_floating_arith_node(sel, leftDouble, rightDouble, argc, params);
+ }
+ else if ((!(leftIsFixFloatConstant || rightIsFixFloatConstant)) && (leftIsFixnumConstant || rightIsFixnumConstant)) {
+ // One of the operands is a fixnum, the other is a variable
+ if (leftIsFixnumConstant) {
+ return compile_variable_and_integral_node(sel, leftLong, true, rightVal, leftVal, argc, params);
+ }
+ else {
+ return compile_variable_and_integral_node(sel, rightLong, false, leftVal, rightVal, argc, params);
+ }
+ } else if((!(leftIsFixnumConstant || rightIsFixnumConstant)) && (leftIsFixFloatConstant || rightIsFixFloatConstant)) {
+ if (leftIsFixFloatConstant) {
+ return compile_variable_and_floating_node(sel, leftDouble, true, rightVal, leftVal, argc, params);
+ } else {
+ return compile_variable_and_floating_node(sel, rightDouble, false, leftVal, rightVal, argc, params);
+ }
+ } else {
+ return compile_variable_arith_node(sel, leftVal, rightVal, argc, params);
+ }
}
- }
// Other operators (#<< or #[] or #[]=)
else if (sel == selLTLT || sel == selAREF || sel == selASET) {
@@ -1952,6 +2320,7 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
bb = mergeBB;
PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
pn->addIncoming(thenVal, thenBB);
+
pn->addIncoming(elseVal, elseBB);
return pn;
@@ -2011,6 +2380,8 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Va
PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
pn->addIncoming(thenVal, thenBB);
pn->addIncoming(elseVal, elseBB);
+
+
return pn;
@@ -4301,7 +4672,7 @@ rval_to_long_long(VALUE rval)
static inline double
rval_to_double(VALUE rval)
{
- return RFLOAT_VALUE(rb_Float(bool_to_fix(rval)));
+ return RFLOAT_VALUE(rb_Float(bool_to_fix(rval)));
}
extern "C"
@@ -4866,7 +5237,7 @@ 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;
@@ -4874,7 +5245,7 @@ RoxorCompiler::compile_conversion_to_ruby(const char *type,
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;
View
22 compiler.h
@@ -145,6 +145,7 @@ class RoxorCompiler {
Constant *zeroVal;
Constant *oneVal;
Constant *twoVal;
+ Constant *threeVal;
Constant *nilVal;
Constant *trueVal;
Constant *falseVal;
@@ -175,6 +176,26 @@ class RoxorCompiler {
? new IntToPtrInst(ptrint, PtrPtrTy, "", bb)
: new IntToPtrInst(ptrint, PtrPtrTy, "");
}
+
+ CmpInst::Predicate integer_predicate_for_selector(SEL sel);
+ CmpInst::Predicate floating_point_predicate_for_selector(SEL sel);
+
+
+ PHINode *compile_negation_node(int argc, Value *val);
+ PHINode *compile_symbol_equality_node(SEL sel, VALUE leftRVal, VALUE rightRVal, int argc, std::vector<Value *> &params);
+ PHINode *
+ precompile_integral_arith_node(SEL sel, long leftLong, long rightLong, int argc, std::vector<Value *> &params);
+ PHINode *
+ precompile_floating_arith_node(SEL sel, double leftDouble, long rightDouble, int argc, std::vector<Value *> &params);
+ PHINode *
+ compile_variable_and_integral_node(SEL sel, long fixedLong, bool leftIsFixed, Value *val, Value *other, int argc,
+ std::vector<Value *> &params);
+ PHINode *
+ compile_variable_and_floating_node(SEL sel, double fixedDouble, bool leftIsFixed, Value *val, Value *other,
+ int argc, std::vector<Value *> &params);
+
+ PHINode *
+ compile_variable_arith_node(SEL sel, Value *leftVal, Value *rightVal, int argc, std::vector<Value *>params);
Value *compile_protected_call(Function *func,
std::vector<Value *> &params);
@@ -259,7 +280,6 @@ class RoxorCompiler {
return iter->second;
}
- ICmpInst *is_value_a_fixnum(Value *val);
void compile_ivar_slots(Value *klass, BasicBlock::InstListType &list,
BasicBlock::InstListType::iterator iter);
bool unbox_ruby_constant(Value *val, VALUE *rval);
View
48 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 & FIXFLOAT_FLAG) == 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,30 @@ 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
@@ -300,6 +318,7 @@ enum ruby_value_type {
#if WITH_OBJC
RUBY_T_NATIVE = 0x16,
#endif
+ RUBY_T_FIXFLOAT = 0x17,
RUBY_T_UNDEF = 0x1b,
RUBY_T_NODE = 0x1c,
@@ -323,6 +342,7 @@ enum ruby_value_type {
#define T_BIGNUM RUBY_T_BIGNUM
#define T_FILE RUBY_T_FILE
#define T_FIXNUM RUBY_T_FIXNUM
+#define T_FIXFLOAT RUBY_T_FIXFLOAT
#if WITH_OBJC
# define T_NATIVE RUBY_T_NATIVE
#endif
@@ -535,7 +555,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
@@ -1149,6 +1169,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)
@@ -1165,7 +1186,10 @@ rb_rval_to_ocid(VALUE obj)
}
if (FIXNUM_P(obj)) {
return (id)rb_box_fixnum(obj);
- }
+ }
+ if (FIXFLOAT_P(obj)) {
+ return (id)rb_box_fixfloat(obj);
+ }
}
return (id)obj;
}
@@ -1185,6 +1209,10 @@ rb_ocid_to_rval(id obj)
if (*(Class *)obj == (Class)rb_cFixnum) {
return LONG2FIX(RFIXNUM(obj)->value);
}
+ if (*(Class *)obj == (Class)rb_cFloat) {
+ extern VALUE rb_float_new(double);
+ return rb_float_new(RFLOAT(obj)->float_value);
+ }
if (*(Class *)obj == (Class)rb_cCFNumber) {
/* TODO NSNumber should implement the Numeric primitive methods */
if (CFNumberIsFloatType((CFNumberRef)obj)) {
@@ -1218,6 +1246,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;
@@ -1238,6 +1267,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
21 numeric.c
@@ -95,6 +95,15 @@ static CFMutableDictionaryRef fixnum_dict = NULL;
static struct RFixnum *fixnum_cache = NULL;
VALUE
+rb_box_fixfloat(VALUE fixfloat)
+{
+ struct RFloat *val = malloc(sizeof(struct RFloat));
+ (val->basic).klass = rb_cFloat;
+ val->float_value = NUM2DBL(fixfloat);
+ return (VALUE)val;
+}
+
+VALUE
rb_box_fixnum(VALUE fixnum)
{
struct RFixnum *val;
@@ -532,12 +541,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);
}
/*
@@ -1378,7 +1382,6 @@ flo_truncate(VALUE num, SEL sel)
return LONG2FIX(val);
}
-
/*
* call-seq:
* num.floor => integer
@@ -3135,6 +3138,8 @@ fix_even_p(VALUE num, SEL sel)
return Qtrue;
}
+
+
static const char *
imp_rb_float_objCType(void *rcv, SEL sel)
{
@@ -3368,6 +3373,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
1  object.c
@@ -2484,7 +2484,6 @@ rb_num2dbl(VALUE val)
switch (TYPE(val)) {
case T_FLOAT:
return RFLOAT_VALUE(val);
-
case T_STRING:
rb_raise(rb_eTypeError, "no implicit conversion to float from string");
break;
View
2  vm.cpp
@@ -207,7 +207,7 @@ RoxorVM::RoxorVM(void)
emp = new ExistingModuleProvider(RoxorCompiler::module);
jmm = new RoxorJITManager;
- ee = ExecutionEngine::createJIT(emp, 0, jmm, CodeGenOpt::None);
+ ee = ExecutionEngine::createJIT(emp, 0, jmm, CodeGenOpt::None);
assert(ee != NULL);
fpm = new FunctionPassManager(emp);

No commit comments for this range

Something went wrong with that request. Please try again.