Changeset View
Changeset View
Standalone View
Standalone View
lib/CodeGen/CGExprScalar.cpp
Show First 20 Lines • Show All 1,845 Lines • ▼ Show 20 Lines | ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, | ||||
bool isInc, bool isPre) { | bool isInc, bool isPre) { | ||||
QualType type = E->getSubExpr()->getType(); | QualType type = E->getSubExpr()->getType(); | ||||
llvm::PHINode *atomicPHI = nullptr; | llvm::PHINode *atomicPHI = nullptr; | ||||
llvm::Value *value; | llvm::Value *value; | ||||
llvm::Value *input; | llvm::Value *input; | ||||
int amount = (isInc ? 1 : -1); | int amount = (isInc ? 1 : -1); | ||||
bool signedIndex = !isInc; | bool isSubtraction = !isInc; | ||||
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) { | if (const AtomicType *atomicTy = type->getAs<AtomicType>()) { | ||||
type = atomicTy->getValueType(); | type = atomicTy->getValueType(); | ||||
if (isInc && type->isBooleanType()) { | if (isInc && type->isBooleanType()) { | ||||
llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type); | llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type); | ||||
if (isPre) { | if (isPre) { | ||||
Builder.CreateStore(True, LV.getAddress(), LV.isVolatileQualified()) | Builder.CreateStore(True, LV.getAddress(), LV.isVolatileQualified()) | ||||
->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent); | ->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent); | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | // Next most common: pointer increment. | ||||
// VLA types don't have constant size. | // VLA types don't have constant size. | ||||
if (const VariableArrayType *vla | if (const VariableArrayType *vla | ||||
= CGF.getContext().getAsVariableArrayType(type)) { | = CGF.getContext().getAsVariableArrayType(type)) { | ||||
llvm::Value *numElts = CGF.getVLASize(vla).first; | llvm::Value *numElts = CGF.getVLASize(vla).first; | ||||
if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize"); | if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize"); | ||||
if (CGF.getLangOpts().isSignedOverflowDefined()) | if (CGF.getLangOpts().isSignedOverflowDefined()) | ||||
value = Builder.CreateGEP(value, numElts, "vla.inc"); | value = Builder.CreateGEP(value, numElts, "vla.inc"); | ||||
else | else | ||||
value = CGF.EmitCheckedInBoundsGEP(value, numElts, signedIndex, | value = CGF.EmitCheckedInBoundsGEP( | ||||
value, numElts, /*SignedIndices=*/false, isSubtraction, | |||||
E->getExprLoc(), "vla.inc"); | E->getExprLoc(), "vla.inc"); | ||||
// Arithmetic on function pointers (!) is just +-1. | // Arithmetic on function pointers (!) is just +-1. | ||||
} else if (type->isFunctionType()) { | } else if (type->isFunctionType()) { | ||||
llvm::Value *amt = Builder.getInt32(amount); | llvm::Value *amt = Builder.getInt32(amount); | ||||
value = CGF.EmitCastToVoidPtr(value); | value = CGF.EmitCastToVoidPtr(value); | ||||
if (CGF.getLangOpts().isSignedOverflowDefined()) | if (CGF.getLangOpts().isSignedOverflowDefined()) | ||||
value = Builder.CreateGEP(value, amt, "incdec.funcptr"); | value = Builder.CreateGEP(value, amt, "incdec.funcptr"); | ||||
else | else | ||||
value = CGF.EmitCheckedInBoundsGEP(value, amt, signedIndex, | value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false, | ||||
E->getExprLoc(), "incdec.funcptr"); | isSubtraction, E->getExprLoc(), | ||||
"incdec.funcptr"); | |||||
value = Builder.CreateBitCast(value, input->getType()); | value = Builder.CreateBitCast(value, input->getType()); | ||||
// For everything else, we can just do a simple increment. | // For everything else, we can just do a simple increment. | ||||
} else { | } else { | ||||
llvm::Value *amt = Builder.getInt32(amount); | llvm::Value *amt = Builder.getInt32(amount); | ||||
if (CGF.getLangOpts().isSignedOverflowDefined()) | if (CGF.getLangOpts().isSignedOverflowDefined()) | ||||
value = Builder.CreateGEP(value, amt, "incdec.ptr"); | value = Builder.CreateGEP(value, amt, "incdec.ptr"); | ||||
else | else | ||||
value = CGF.EmitCheckedInBoundsGEP(value, amt, signedIndex, | value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false, | ||||
E->getExprLoc(), "incdec.ptr"); | isSubtraction, E->getExprLoc(), | ||||
"incdec.ptr"); | |||||
} | } | ||||
// Vector increment/decrement. | // Vector increment/decrement. | ||||
} else if (type->isVectorType()) { | } else if (type->isVectorType()) { | ||||
if (type->hasIntegerRepresentation()) { | if (type->hasIntegerRepresentation()) { | ||||
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount); | llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount); | ||||
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); | value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | // Objective-C pointer types. | ||||
CharUnits size = CGF.getContext().getTypeSizeInChars(OPT->getObjectType()); | CharUnits size = CGF.getContext().getTypeSizeInChars(OPT->getObjectType()); | ||||
if (!isInc) size = -size; | if (!isInc) size = -size; | ||||
llvm::Value *sizeValue = | llvm::Value *sizeValue = | ||||
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity()); | llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity()); | ||||
if (CGF.getLangOpts().isSignedOverflowDefined()) | if (CGF.getLangOpts().isSignedOverflowDefined()) | ||||
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); | value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); | ||||
else | else | ||||
value = CGF.EmitCheckedInBoundsGEP(value, sizeValue, signedIndex, | value = CGF.EmitCheckedInBoundsGEP(value, sizeValue, | ||||
/*SignedIndices=*/false, isSubtraction, | |||||
E->getExprLoc(), "incdec.objptr"); | E->getExprLoc(), "incdec.objptr"); | ||||
value = Builder.CreateBitCast(value, input->getType()); | value = Builder.CreateBitCast(value, input->getType()); | ||||
} | } | ||||
if (atomicPHI) { | if (atomicPHI) { | ||||
llvm::BasicBlock *opBB = Builder.GetInsertBlock(); | llvm::BasicBlock *opBB = Builder.GetInsertBlock(); | ||||
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn); | llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn); | ||||
auto Pair = CGF.EmitAtomicCompareExchange( | auto Pair = CGF.EmitAtomicCompareExchange( | ||||
▲ Show 20 Lines • Show All 602 Lines • ▼ Show 20 Lines | static Value *emitPointerArithmetic(CodeGenFunction &CGF, | ||||
// In a subtraction, the LHS is always the pointer. | // In a subtraction, the LHS is always the pointer. | ||||
if (!isSubtraction && !pointer->getType()->isPointerTy()) { | if (!isSubtraction && !pointer->getType()->isPointerTy()) { | ||||
std::swap(pointer, index); | std::swap(pointer, index); | ||||
std::swap(pointerOperand, indexOperand); | std::swap(pointerOperand, indexOperand); | ||||
} | } | ||||
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType(); | bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType(); | ||||
bool mayHaveNegativeGEPIndex = isSigned || isSubtraction; | |||||
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth(); | unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth(); | ||||
auto &DL = CGF.CGM.getDataLayout(); | auto &DL = CGF.CGM.getDataLayout(); | ||||
auto PtrTy = cast<llvm::PointerType>(pointer->getType()); | auto PtrTy = cast<llvm::PointerType>(pointer->getType()); | ||||
if (width != DL.getTypeSizeInBits(PtrTy)) { | if (width != DL.getTypeSizeInBits(PtrTy)) { | ||||
// Zero-extend or sign-extend the pointer value according to | // Zero-extend or sign-extend the pointer value according to | ||||
// whether the index is signed or not. | // whether the index is signed or not. | ||||
index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned, | index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned, | ||||
Show All 35 Lines | if (const VariableArrayType *vla | ||||
// signed-overflow, so we use the same semantics for our explicit | // signed-overflow, so we use the same semantics for our explicit | ||||
// multiply. We suppress this if overflow is not undefined behavior. | // multiply. We suppress this if overflow is not undefined behavior. | ||||
if (CGF.getLangOpts().isSignedOverflowDefined()) { | if (CGF.getLangOpts().isSignedOverflowDefined()) { | ||||
index = CGF.Builder.CreateMul(index, numElements, "vla.index"); | index = CGF.Builder.CreateMul(index, numElements, "vla.index"); | ||||
pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr"); | pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr"); | ||||
} else { | } else { | ||||
index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index"); | index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index"); | ||||
pointer = | pointer = | ||||
CGF.EmitCheckedInBoundsGEP(pointer, index, mayHaveNegativeGEPIndex, | CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction, | ||||
op.E->getExprLoc(), "add.ptr"); | op.E->getExprLoc(), "add.ptr"); | ||||
} | } | ||||
return pointer; | return pointer; | ||||
} | } | ||||
// Explicitly handle GNU void* and function pointer arithmetic extensions. The | // Explicitly handle GNU void* and function pointer arithmetic extensions. The | ||||
// GNU void* casts amount to no-ops since our void* type is i8*, but this is | // GNU void* casts amount to no-ops since our void* type is i8*, but this is | ||||
// future proof. | // future proof. | ||||
if (elementType->isVoidType() || elementType->isFunctionType()) { | if (elementType->isVoidType() || elementType->isFunctionType()) { | ||||
Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy); | Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy); | ||||
result = CGF.Builder.CreateGEP(result, index, "add.ptr"); | result = CGF.Builder.CreateGEP(result, index, "add.ptr"); | ||||
return CGF.Builder.CreateBitCast(result, pointer->getType()); | return CGF.Builder.CreateBitCast(result, pointer->getType()); | ||||
} | } | ||||
if (CGF.getLangOpts().isSignedOverflowDefined()) | if (CGF.getLangOpts().isSignedOverflowDefined()) | ||||
return CGF.Builder.CreateGEP(pointer, index, "add.ptr"); | return CGF.Builder.CreateGEP(pointer, index, "add.ptr"); | ||||
return CGF.EmitCheckedInBoundsGEP(pointer, index, mayHaveNegativeGEPIndex, | return CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction, | ||||
op.E->getExprLoc(), "add.ptr"); | op.E->getExprLoc(), "add.ptr"); | ||||
} | } | ||||
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and | // Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and | ||||
// Addend. Use negMul and negAdd to negate the first operand of the Mul or | // Addend. Use negMul and negAdd to negate the first operand of the Mul or | ||||
// the add operand respectively. This allows fmuladd to represent a*b-c, or | // the add operand respectively. This allows fmuladd to represent a*b-c, or | ||||
// c-a*b. Patterns in LLVM should catch the negated forms and translate them to | // c-a*b. Patterns in LLVM should catch the negated forms and translate them to | ||||
// efficient operations. | // efficient operations. | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | static Value* tryEmitFMulAdd(const BinOpInfo &op, | ||||
} | } | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { | Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { | ||||
if (op.LHS->getType()->isPointerTy() || | if (op.LHS->getType()->isPointerTy() || | ||||
op.RHS->getType()->isPointerTy()) | op.RHS->getType()->isPointerTy()) | ||||
return emitPointerArithmetic(CGF, op, /*subtraction*/ false); | return emitPointerArithmetic(CGF, op, CodeGenFunction::NotSubtraction); | ||||
if (op.Ty->isSignedIntegerOrEnumerationType()) { | if (op.Ty->isSignedIntegerOrEnumerationType()) { | ||||
switch (CGF.getLangOpts().getSignedOverflowBehavior()) { | switch (CGF.getLangOpts().getSignedOverflowBehavior()) { | ||||
case LangOptions::SOB_Defined: | case LangOptions::SOB_Defined: | ||||
return Builder.CreateAdd(op.LHS, op.RHS, "add"); | return Builder.CreateAdd(op.LHS, op.RHS, "add"); | ||||
case LangOptions::SOB_Undefined: | case LangOptions::SOB_Undefined: | ||||
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) | if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) | ||||
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); | return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | if (!op.LHS->getType()->isPointerTy()) { | ||||
} | } | ||||
return Builder.CreateSub(op.LHS, op.RHS, "sub"); | return Builder.CreateSub(op.LHS, op.RHS, "sub"); | ||||
} | } | ||||
// If the RHS is not a pointer, then we have normal pointer | // If the RHS is not a pointer, then we have normal pointer | ||||
// arithmetic. | // arithmetic. | ||||
if (!op.RHS->getType()->isPointerTy()) | if (!op.RHS->getType()->isPointerTy()) | ||||
return emitPointerArithmetic(CGF, op, /*subtraction*/ true); | return emitPointerArithmetic(CGF, op, CodeGenFunction::IsSubtraction); | ||||
// Otherwise, this is a pointer subtraction. | // Otherwise, this is a pointer subtraction. | ||||
// Do the raw subtraction part. | // Do the raw subtraction part. | ||||
llvm::Value *LHS | llvm::Value *LHS | ||||
= Builder.CreatePtrToInt(op.LHS, CGF.PtrDiffTy, "sub.ptr.lhs.cast"); | = Builder.CreatePtrToInt(op.LHS, CGF.PtrDiffTy, "sub.ptr.lhs.cast"); | ||||
llvm::Value *RHS | llvm::Value *RHS | ||||
= Builder.CreatePtrToInt(op.RHS, CGF.PtrDiffTy, "sub.ptr.rhs.cast"); | = Builder.CreatePtrToInt(op.RHS, CGF.PtrDiffTy, "sub.ptr.rhs.cast"); | ||||
▲ Show 20 Lines • Show All 958 Lines • ▼ Show 20 Lines | #undef COMPOUND_OP | ||||
} | } | ||||
llvm_unreachable("Unhandled compound assignment operator"); | llvm_unreachable("Unhandled compound assignment operator"); | ||||
} | } | ||||
Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, | Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, | ||||
ArrayRef<Value *> IdxList, | ArrayRef<Value *> IdxList, | ||||
bool SignedIndices, | bool SignedIndices, | ||||
bool IsSubtraction, | |||||
SourceLocation Loc, | SourceLocation Loc, | ||||
const Twine &Name) { | const Twine &Name) { | ||||
Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name); | Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name); | ||||
// If the pointer overflow sanitizer isn't enabled, do nothing. | // If the pointer overflow sanitizer isn't enabled, do nothing. | ||||
if (!SanOpts.has(SanitizerKind::PointerOverflow)) | if (!SanOpts.has(SanitizerKind::PointerOverflow)) | ||||
return GEPVal; | return GEPVal; | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, | ||||
auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset); | auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset); | ||||
// The GEP is valid if: | // The GEP is valid if: | ||||
// 1) The total offset doesn't overflow, and | // 1) The total offset doesn't overflow, and | ||||
// 2) The sign of the difference between the computed address and the base | // 2) The sign of the difference between the computed address and the base | ||||
// pointer matches the sign of the total offset. | // pointer matches the sign of the total offset. | ||||
llvm::Value *ValidGEP; | llvm::Value *ValidGEP; | ||||
auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows); | auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows); | ||||
auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr); | |||||
if (SignedIndices) { | if (SignedIndices) { | ||||
auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr); | |||||
auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero); | auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero); | ||||
llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr); | llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr); | ||||
ValidGEP = Builder.CreateAnd( | ValidGEP = Builder.CreateAnd( | ||||
Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid), | Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid), | ||||
NoOffsetOverflow); | NoOffsetOverflow); | ||||
} else { | } else if (!SignedIndices && !IsSubtraction) { | ||||
auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr); | |||||
ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow); | ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow); | ||||
efriedma: Please make this an "else" rather than an "else if" (you can assert the inside the else body if… | |||||
} else { | |||||
auto *NegOrZeroValid = Builder.CreateICmpULE(ComputedGEP, IntPtr); | |||||
ValidGEP = Builder.CreateAnd(NegOrZeroValid, NoOffsetOverflow); | |||||
} | } | ||||
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)}; | llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)}; | ||||
// Pass the computed GEP to the runtime to avoid emitting poisoned arguments. | // Pass the computed GEP to the runtime to avoid emitting poisoned arguments. | ||||
llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP}; | llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP}; | ||||
EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow), | EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow), | ||||
SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs); | SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs); | ||||
return GEPVal; | return GEPVal; | ||||
} | } |
Please make this an "else" rather than an "else if" (you can assert the inside the else body if it's helpful).