[macruby-changes] [4094] MacRuby/trunk/compiler.cpp

source_changes at macosforge.org source_changes at macosforge.org
Thu May 13 18:14:37 PDT 2010


Revision: 4094
          http://trac.macosforge.org/projects/ruby/changeset/4094
Author:   lsansonetti at apple.com
Date:     2010-05-13 18:14:32 -0700 (Thu, 13 May 2010)
Log Message:
-----------
make the division of negative fixnums behave like MRI

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-05-14 00:34:03 UTC (rev 4093)
+++ MacRuby/trunk/compiler.cpp	2010-05-14 01:14:32 UTC (rev 4094)
@@ -2109,10 +2109,59 @@
 	res = BinaryOperator::CreateSub(leftVal, rightVal, "", bb);
     }
     else if (sel == selDIV) {
-	res = float_op
-	    ? BinaryOperator::CreateFDiv(leftVal, rightVal, "", bb)
-	    : BinaryOperator::CreateSDiv(leftVal, rightVal, "", bb);
-		
+	if (float_op) {
+	    res = BinaryOperator::CreateFDiv(leftVal, rightVal, "", bb);
+	}
+	else {
+	    // Fixnum division in Ruby is not a simple matter of returning the
+	    // division result. We must round up the result in case one of the
+	    // operands is negative.
+
+	    Value *normal_res = BinaryOperator::CreateSDiv(leftVal, rightVal,
+		    "", bb);
+
+	    ICmpInst *left_negative = new ICmpInst(*bb, ICmpInst::ICMP_SLT,
+		    leftVal, zeroVal);
+
+	    ICmpInst *right_negative = new ICmpInst(*bb, ICmpInst::ICMP_SLT,
+		    rightVal, zeroVal);
+
+	    Function *f = bb->getParent();
+	    BasicBlock *negative_bb = BasicBlock::Create(context, "", f);
+	    BasicBlock *check_right_bb = BasicBlock::Create(context, "", f);
+	    BasicBlock *try_right_bb = BasicBlock::Create(context, "", f);
+	    BasicBlock *hack_res_bb = BasicBlock::Create(context, "", f);
+	    BasicBlock *merge_bb = BasicBlock::Create(context, "", f);
+
+	    BranchInst::Create(check_right_bb, try_right_bb, left_negative, bb);
+
+	    bb = check_right_bb;
+	    BranchInst::Create(merge_bb, negative_bb, right_negative, bb);
+
+	    bb = try_right_bb;
+	    BranchInst::Create(negative_bb, merge_bb, right_negative, bb);
+
+	    bb = negative_bb;
+	    Value *rem = BinaryOperator::CreateSRem(leftVal, rightVal,
+		    "", bb);
+	    ICmpInst *hack_result = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
+		    rem, zeroVal);
+	    BranchInst::Create(merge_bb, hack_res_bb, hack_result, bb);
+
+	    bb = hack_res_bb;
+	    Value *hacked_res = BinaryOperator::CreateSub(normal_res,
+		    ConstantInt::get(IntTy, 1), "", bb);
+	    BranchInst::Create(merge_bb, bb);
+ 
+	    bb = merge_bb;	
+	    PHINode *pn = PHINode::Create(IntTy, "", bb);
+	    pn->addIncoming(hacked_res, hack_res_bb);
+	    pn->addIncoming(normal_res, check_right_bb);
+	    pn->addIncoming(normal_res, try_right_bb);
+	    pn->addIncoming(normal_res, negative_bb);
+
+	    return pn;
+	}
     }
     else if (sel == selMULT) {
 	res = BinaryOperator::CreateMul(leftVal, rightVal, "", bb);
@@ -2312,6 +2361,15 @@
 			res_val = res == 1 ? trueVal : falseVal;
 		    }
 		    else if (FIXABLE(res)) {
+			if (sel == selDIV) {
+			    // MRI compliant negative fixnum division.
+			    long x = leftImm.long_val();
+			    long y = rightImm.long_val();
+			    if (((x < 0 && y >= 0) || (x >= 0 && y < 0))
+				    && (x % y) != 0) {
+				res--;
+			    }
+			}
 			res_val = ConstantInt::get(RubyObjTy, LONG2FIX(res));
 		    }
 		}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100513/c53015cd/attachment.html>


More information about the macruby-changes mailing list