[Clang][CodeGen] Move EmitPointerArithmetic into CodeGenFunction. NFC. (#152634)

`CodeGenFunction::EmitPointerArithmetic` is needed by
https://github.com/llvm/llvm-project/pull/152575. Separate the NFC
changes into a new PR for smooth review.
This commit is contained in:
Yingwei Zheng 2025-08-08 21:41:03 +08:00 committed by GitHub
parent 26b302fd8b
commit ac8295550b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 53 deletions

View File

@ -4183,9 +4183,8 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
return phi;
}
/// Emit pointer + index arithmetic.
static Value *emitPointerArithmetic(CodeGenFunction &CGF,
const BinOpInfo &op,
/// This function is used for BO_Add/BO_Sub/BO_AddAssign/BO_SubAssign.
static Value *emitPointerArithmetic(CodeGenFunction &CGF, const BinOpInfo &op,
bool isSubtraction) {
// Must have binary (not unary) expr here. Unary pointer
// increment/decrement doesn't use this path.
@ -4202,11 +4201,19 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
std::swap(pointerOperand, indexOperand);
}
return CGF.EmitPointerArithmetic(expr, pointerOperand, pointer, indexOperand,
index, isSubtraction);
}
/// Emit pointer + index arithmetic.
llvm::Value *CodeGenFunction::EmitPointerArithmetic(
const BinaryOperator *BO, Expr *pointerOperand, llvm::Value *pointer,
Expr *indexOperand, llvm::Value *index, bool isSubtraction) {
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
auto &DL = CGF.CGM.getDataLayout();
auto PtrTy = cast<llvm::PointerType>(pointer->getType());
auto &DL = CGM.getDataLayout();
auto *PtrTy = cast<llvm::PointerType>(pointer->getType());
// Some versions of glibc and gcc use idioms (particularly in their malloc
// routines) that add a pointer-sized integer (known to be a pointer value)
@ -4227,79 +4234,77 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
//
// Note that we do not suppress the pointer overflow check in this case.
if (BinaryOperator::isNullPointerArithmeticExtension(
CGF.getContext(), op.Opcode, expr->getLHS(), expr->getRHS())) {
Value *Ptr = CGF.Builder.CreateIntToPtr(index, pointer->getType());
if (CGF.getLangOpts().PointerOverflowDefined ||
!CGF.SanOpts.has(SanitizerKind::PointerOverflow) ||
NullPointerIsDefined(CGF.Builder.GetInsertBlock()->getParent(),
getContext(), BO->getOpcode(), pointerOperand, indexOperand)) {
llvm::Value *Ptr = Builder.CreateIntToPtr(index, pointer->getType());
if (getLangOpts().PointerOverflowDefined ||
!SanOpts.has(SanitizerKind::PointerOverflow) ||
NullPointerIsDefined(Builder.GetInsertBlock()->getParent(),
PtrTy->getPointerAddressSpace()))
return Ptr;
// The inbounds GEP of null is valid iff the index is zero.
auto CheckOrdinal = SanitizerKind::SO_PointerOverflow;
auto CheckHandler = SanitizerHandler::PointerOverflow;
SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
Value *IsZeroIndex = CGF.Builder.CreateIsNull(index);
llvm::Constant *StaticArgs[] = {
CGF.EmitCheckSourceLocation(op.E->getExprLoc())};
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
llvm::Value *IsZeroIndex = Builder.CreateIsNull(index);
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(BO->getExprLoc())};
llvm::Type *IntPtrTy = DL.getIntPtrType(PtrTy);
Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
Value *ComputedGEP = CGF.Builder.CreateZExtOrTrunc(index, IntPtrTy);
Value *DynamicArgs[] = {IntPtr, ComputedGEP};
CGF.EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
DynamicArgs);
llvm::Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
llvm::Value *ComputedGEP = Builder.CreateZExtOrTrunc(index, IntPtrTy);
llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
DynamicArgs);
return Ptr;
}
if (width != DL.getIndexTypeSizeInBits(PtrTy)) {
// Zero-extend or sign-extend the pointer value according to
// whether the index is signed or not.
index = CGF.Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
"idx.ext");
index = Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned,
"idx.ext");
}
// If this is subtraction, negate the index.
if (isSubtraction)
index = CGF.Builder.CreateNeg(index, "idx.neg");
index = Builder.CreateNeg(index, "idx.neg");
if (CGF.SanOpts.has(SanitizerKind::ArrayBounds))
CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
/*Accessed*/ false);
if (SanOpts.has(SanitizerKind::ArrayBounds))
EmitBoundsCheck(BO, pointerOperand, index, indexOperand->getType(),
/*Accessed*/ false);
const PointerType *pointerType
= pointerOperand->getType()->getAs<PointerType>();
const PointerType *pointerType =
pointerOperand->getType()->getAs<PointerType>();
if (!pointerType) {
QualType objectType = pointerOperand->getType()
->castAs<ObjCObjectPointerType>()
->getPointeeType();
llvm::Value *objectSize
= CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(objectType));
->castAs<ObjCObjectPointerType>()
->getPointeeType();
llvm::Value *objectSize =
CGM.getSize(getContext().getTypeSizeInChars(objectType));
index = CGF.Builder.CreateMul(index, objectSize);
index = Builder.CreateMul(index, objectSize);
Value *result =
CGF.Builder.CreateGEP(CGF.Int8Ty, pointer, index, "add.ptr");
return CGF.Builder.CreateBitCast(result, pointer->getType());
llvm::Value *result = Builder.CreateGEP(Int8Ty, pointer, index, "add.ptr");
return Builder.CreateBitCast(result, pointer->getType());
}
QualType elementType = pointerType->getPointeeType();
if (const VariableArrayType *vla
= CGF.getContext().getAsVariableArrayType(elementType)) {
if (const VariableArrayType *vla =
getContext().getAsVariableArrayType(elementType)) {
// The element count here is the total number of non-VLA elements.
llvm::Value *numElements = CGF.getVLASize(vla).NumElts;
llvm::Value *numElements = getVLASize(vla).NumElts;
// Effectively, the multiply by the VLA size is part of the GEP.
// GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
if (CGF.getLangOpts().PointerOverflowDefined) {
index = CGF.Builder.CreateMul(index, numElements, "vla.index");
pointer = CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
llvm::Type *elemTy = ConvertTypeForMem(vla->getElementType());
if (getLangOpts().PointerOverflowDefined) {
index = Builder.CreateMul(index, numElements, "vla.index");
pointer = Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
} else {
index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
pointer = CGF.EmitCheckedInBoundsGEP(
elemTy, pointer, index, isSigned, isSubtraction, op.E->getExprLoc(),
"add.ptr");
index = Builder.CreateNSWMul(index, numElements, "vla.index");
pointer =
EmitCheckedInBoundsGEP(elemTy, pointer, index, isSigned,
isSubtraction, BO->getExprLoc(), "add.ptr");
}
return pointer;
}
@ -4309,16 +4314,15 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
// future proof.
llvm::Type *elemTy;
if (elementType->isVoidType() || elementType->isFunctionType())
elemTy = CGF.Int8Ty;
elemTy = Int8Ty;
else
elemTy = CGF.ConvertTypeForMem(elementType);
elemTy = ConvertTypeForMem(elementType);
if (CGF.getLangOpts().PointerOverflowDefined)
return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
if (getLangOpts().PointerOverflowDefined)
return Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
return CGF.EmitCheckedInBoundsGEP(
elemTy, pointer, index, isSigned, isSubtraction, op.E->getExprLoc(),
"add.ptr");
return EmitCheckedInBoundsGEP(elemTy, pointer, index, isSigned, isSubtraction,
BO->getExprLoc(), "add.ptr");
}
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and

View File

@ -5212,6 +5212,12 @@ public:
/// operation is a subtraction.
enum { NotSubtraction = false, IsSubtraction = true };
/// Emit pointer + index arithmetic.
llvm::Value *EmitPointerArithmetic(const BinaryOperator *BO,
Expr *pointerOperand, llvm::Value *pointer,
Expr *indexOperand, llvm::Value *index,
bool isSubtraction);
/// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
/// detect undefined behavior when the pointer overflow sanitizer is enabled.
/// \p SignedIndices indicates whether any of the GEP indices are signed.