diff options
author | Chris Lattner <sabre@nondot.org> | 2010-09-11 21:47:09 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-09-11 21:47:09 +0000 |
commit | 8023030f76d334355b73d9c675d3870858aaf4fd (patch) | |
tree | aa2a3d126c2764122dc56f2493de1ac9dcec47dd /lib/CodeGen/CGExprScalar.cpp | |
parent | b2043d71df9e8a2e4d20a8d0e37f894aa399bd9d (diff) |
Augment -ftrapv to check for divide by zero, mod by zero, and INT_MIN % -1.
Patch by John Regehr!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113705 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExprScalar.cpp')
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 69 |
1 files changed, 65 insertions, 4 deletions
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 5d864fc560..a783737a0b 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -322,9 +322,23 @@ public: return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } + bool isTrapvOverflowBehavior() { + return CGF.getContext().getLangOptions().getSignedOverflowBehavior() + == LangOptions::SOB_Trapping; + } /// Create a binary op that checks for overflow. /// Currently only supports +, - and *. Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops); + // Emit the overflow BB when -ftrapv option is activated. + void EmitOverflowBB(llvm::BasicBlock *overflowBB) { + Builder.SetInsertPoint(overflowBB); + llvm::Function *Trap = CGF.CGM.getIntrinsic(llvm::Intrinsic::trap); + Builder.CreateCall(Trap); + Builder.CreateUnreachable(); + } + // Check for undefined division and modulus behaviors. + void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops, + llvm::Value *Zero,bool isDiv); Value *EmitDiv(const BinOpInfo &Ops); Value *EmitRem(const BinOpInfo &Ops); Value *EmitAdd(const BinOpInfo &Ops); @@ -1499,8 +1513,51 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, return EmitLoadOfLValue(LHS, E->getType()); } +void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( + const BinOpInfo &Ops, + llvm::Value *Zero, bool isDiv) { + llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn); + llvm::BasicBlock *contBB = + CGF.createBasicBlock(isDiv ? "div.cont" : "rem.cont", CGF.CurFn); + + const llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType()); + + if (Ops.Ty->hasSignedIntegerRepresentation()) { + llvm::Value *IntMin = + llvm::ConstantInt::get(VMContext, + llvm::APInt::getSignedMinValue(Ty->getBitWidth())); + llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL); + + llvm::Value *Cond1 = Builder.CreateICmpEQ(Ops.RHS, Zero); + llvm::Value *LHSCmp = Builder.CreateICmpEQ(Ops.LHS, IntMin); + llvm::Value *RHSCmp = Builder.CreateICmpEQ(Ops.RHS, NegOne); + llvm::Value *Cond2 = Builder.CreateAnd(LHSCmp, RHSCmp, "and"); + Builder.CreateCondBr(Builder.CreateOr(Cond1, Cond2, "or"), + overflowBB, contBB); + } else { + CGF.Builder.CreateCondBr(Builder.CreateICmpEQ(Ops.RHS, Zero), + overflowBB, contBB); + } + EmitOverflowBB(overflowBB); + Builder.SetInsertPoint(contBB); +} Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { + if (isTrapvOverflowBehavior()) { + llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); + + if (Ops.Ty->isIntegerType()) + EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true); + else if (Ops.Ty->isRealFloatingType()) { + llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", + CGF.CurFn); + llvm::BasicBlock *DivCont = CGF.createBasicBlock("div.cont", CGF.CurFn); + CGF.Builder.CreateCondBr(Builder.CreateFCmpOEQ(Ops.RHS, Zero), + overflowBB, DivCont); + EmitOverflowBB(overflowBB); + Builder.SetInsertPoint(DivCont); + } + } if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); else if (Ops.Ty->hasUnsignedIntegerRepresentation()) @@ -1511,6 +1568,13 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { // Rem in C can't be a floating point type: C99 6.5.5p2. + if (isTrapvOverflowBehavior()) { + llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); + + if (Ops.Ty->isIntegerType()) + EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false); + } + if (Ops.Ty->isUnsignedIntegerType()) return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); else @@ -1560,10 +1624,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { // Handle overflow with llvm.trap. // TODO: it would be better to generate one of these blocks per function. - Builder.SetInsertPoint(overflowBB); - llvm::Function *Trap = CGF.CGM.getIntrinsic(llvm::Intrinsic::trap); - Builder.CreateCall(Trap); - Builder.CreateUnreachable(); + EmitOverflowBB(overflowBB); // Continue on. Builder.SetInsertPoint(continueBB); |