Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 57 additions & 53 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand All @@ -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;
}
Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5220,6 +5220,12 @@ class CodeGenFunction : public CodeGenTypeCache {
/// 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.
Expand Down