Make Value::getPointerAlignment() return an Align, not a MaybeAlign.

If we don't know anything about the alignment of a pointer, Align(1) is
still correct: all pointers are at least 1-byte aligned.

Included in this patch is a bugfix for an issue discovered during this
cleanup: pointers with "dereferenceable" attributes/metadata were
assumed to be aligned according to the type of the pointer.  This
wasn't intentional, as far as I can tell, so Loads.cpp was fixed to
stop making this assumption. Frontends may need to be updated.  I
updated clang's handling of C++ references, and added a release note for
this.

Differential Revision: https://reviews.llvm.org/D80072
This commit is contained in:
Eli Friedman 2020-05-16 17:55:18 -07:00
parent 770ba4f051
commit f26bdb539e
20 changed files with 67 additions and 100 deletions

View File

@ -64,6 +64,12 @@ Changes to the LLVM IR
provided by the attribute is interfaced via the API provided by the provided by the attribute is interfaced via the API provided by the
``VFDatabase`` class. ``VFDatabase`` class.
* `dereferenceable` attributes and metadata on pointers no longer imply
anything about the alignment of the pointer in question. Previously, some
optimizations would make assumptions based on the type of the pointer. This
behavior was undocumented. To preserve optimizations, frontends may need to
be updated to generate appropriate `align` attributes and metadata.
Changes to building LLVM Changes to building LLVM
------------------------ ------------------------

View File

@ -664,7 +664,7 @@ public:
/// ///
/// Returns an alignment which is either specified explicitly, e.g. via /// Returns an alignment which is either specified explicitly, e.g. via
/// align attribute of a function argument, or guaranteed by DataLayout. /// align attribute of a function argument, or guaranteed by DataLayout.
MaybeAlign getPointerAlignment(const DataLayout &DL) const; Align getPointerAlignment(const DataLayout &DL) const;
/// Translate PHI node to its predecessor from the given basic block. /// Translate PHI node to its predecessor from the given basic block.
/// ///

View File

@ -27,24 +27,12 @@
using namespace llvm; using namespace llvm;
static MaybeAlign getBaseAlign(const Value *Base, const DataLayout &DL) {
if (const MaybeAlign PA = Base->getPointerAlignment(DL))
return *PA;
Type *const Ty = Base->getType()->getPointerElementType();
if (!Ty->isSized())
return None;
return Align(DL.getABITypeAlignment(Ty));
}
static bool isAligned(const Value *Base, const APInt &Offset, Align Alignment, static bool isAligned(const Value *Base, const APInt &Offset, Align Alignment,
const DataLayout &DL) { const DataLayout &DL) {
if (MaybeAlign BA = getBaseAlign(Base, DL)) { Align BA = Base->getPointerAlignment(DL);
const APInt APBaseAlign(Offset.getBitWidth(), BA->value()); const APInt APAlign(Offset.getBitWidth(), Alignment.value());
const APInt APAlign(Offset.getBitWidth(), Alignment.value()); assert(APAlign.isPowerOf2() && "must be a power of 2!");
assert(APAlign.isPowerOf2() && "must be a power of 2!"); return BA >= Alignment && !(Offset & (APAlign - 1));
return APBaseAlign.uge(APAlign) && !(Offset & (APAlign - 1));
}
return false;
} }
/// Test if V is always a pointer to allocated and suitably aligned memory for /// Test if V is always a pointer to allocated and suitably aligned memory for

View File

@ -2008,9 +2008,8 @@ void computeKnownBits(const Value *V, const APInt &DemandedElts,
// Aligned pointers have trailing zeros - refine Known.Zero set // Aligned pointers have trailing zeros - refine Known.Zero set
if (isa<PointerType>(V->getType())) { if (isa<PointerType>(V->getType())) {
const MaybeAlign Align = V->getPointerAlignment(Q.DL); Align Alignment = V->getPointerAlignment(Q.DL);
if (Align) Known.Zero.setLowBits(countTrailingZeros(Alignment.value()));
Known.Zero.setLowBits(countTrailingZeros(Align->value()));
} }
// computeKnownBitsFromAssume strictly refines Known. // computeKnownBitsFromAssume strictly refines Known.

View File

@ -273,8 +273,8 @@ MemCmpExpansion::LoadPair MemCmpExpansion::getLoadPair(Type *LoadSizeType,
// Get the memory source at offset `OffsetBytes`. // Get the memory source at offset `OffsetBytes`.
Value *LhsSource = CI->getArgOperand(0); Value *LhsSource = CI->getArgOperand(0);
Value *RhsSource = CI->getArgOperand(1); Value *RhsSource = CI->getArgOperand(1);
Align LhsAlign = LhsSource->getPointerAlignment(DL).valueOrOne(); Align LhsAlign = LhsSource->getPointerAlignment(DL);
Align RhsAlign = RhsSource->getPointerAlignment(DL).valueOrOne(); Align RhsAlign = RhsSource->getPointerAlignment(DL);
if (OffsetBytes > 0) { if (OffsetBytes > 0) {
auto *ByteType = Type::getInt8Ty(CI->getContext()); auto *ByteType = Type::getInt8Ty(CI->getContext());
LhsSource = Builder.CreateConstGEP1_64( LhsSource = Builder.CreateConstGEP1_64(

View File

@ -1210,7 +1210,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
MaybeAlign GVAlign; MaybeAlign GVAlign;
if (Module *TheModule = GV->getParent()) { if (Module *TheModule = GV->getParent()) {
GVAlign = GV->getPointerAlignment(TheModule->getDataLayout()); const DataLayout &DL = TheModule->getDataLayout();
GVAlign = GV->getPointerAlignment(DL);
// If the function alignment is not specified then assume that it // If the function alignment is not specified then assume that it
// is 4. // is 4.
@ -1221,7 +1222,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
// increased code size (see https://reviews.llvm.org/D55115) // increased code size (see https://reviews.llvm.org/D55115)
// FIXME: This code should be deleted once existing targets have // FIXME: This code should be deleted once existing targets have
// appropriate defaults // appropriate defaults
if (!GVAlign && isa<Function>(GV)) if (isa<Function>(GV) && !DL.getFunctionPtrAlign())
GVAlign = Align(4); GVAlign = Align(4);
} else if (isa<Function>(GV)) { } else if (isa<Function>(GV)) {
// Without a datalayout we have to assume the worst case: that the // Without a datalayout we have to assume the worst case: that the

View File

@ -738,16 +738,16 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL,
return DerefBytes; return DerefBytes;
} }
MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const { Align Value::getPointerAlignment(const DataLayout &DL) const {
assert(getType()->isPointerTy() && "must be pointer"); assert(getType()->isPointerTy() && "must be pointer");
if (auto *GO = dyn_cast<GlobalObject>(this)) { if (auto *GO = dyn_cast<GlobalObject>(this)) {
if (isa<Function>(GO)) { if (isa<Function>(GO)) {
const MaybeAlign FunctionPtrAlign = DL.getFunctionPtrAlign(); Align FunctionPtrAlign = DL.getFunctionPtrAlign().valueOrOne();
switch (DL.getFunctionPtrAlignType()) { switch (DL.getFunctionPtrAlignType()) {
case DataLayout::FunctionPtrAlignType::Independent: case DataLayout::FunctionPtrAlignType::Independent:
return FunctionPtrAlign; return FunctionPtrAlign;
case DataLayout::FunctionPtrAlignType::MultipleOfFunctionAlign: case DataLayout::FunctionPtrAlignType::MultipleOfFunctionAlign:
return std::max(FunctionPtrAlign, MaybeAlign(GO->getAlignment())); return std::max(FunctionPtrAlign, GO->getAlign().valueOrOne());
} }
llvm_unreachable("Unhandled FunctionPtrAlignType"); llvm_unreachable("Unhandled FunctionPtrAlignType");
} }
@ -760,13 +760,13 @@ MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
// it the preferred alignment. Otherwise, we have to assume that it // it the preferred alignment. Otherwise, we have to assume that it
// may only have the minimum ABI alignment. // may only have the minimum ABI alignment.
if (GVar->isStrongDefinitionForLinker()) if (GVar->isStrongDefinitionForLinker())
return MaybeAlign(DL.getPreferredAlignment(GVar)); return Align(DL.getPreferredAlignment(GVar));
else else
return DL.getABITypeAlign(ObjectType); return DL.getABITypeAlign(ObjectType);
} }
} }
} }
return Alignment; return Alignment.valueOrOne();
} else if (const Argument *A = dyn_cast<Argument>(this)) { } else if (const Argument *A = dyn_cast<Argument>(this)) {
const MaybeAlign Alignment = A->getParamAlign(); const MaybeAlign Alignment = A->getParamAlign();
if (!Alignment && A->hasStructRetAttr()) { if (!Alignment && A->hasStructRetAttr()) {
@ -775,25 +775,18 @@ MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
if (EltTy->isSized()) if (EltTy->isSized())
return DL.getABITypeAlign(EltTy); return DL.getABITypeAlign(EltTy);
} }
return Alignment; return Alignment.valueOrOne();
} else if (const AllocaInst *AI = dyn_cast<AllocaInst>(this)) { } else if (const AllocaInst *AI = dyn_cast<AllocaInst>(this)) {
const MaybeAlign Alignment = AI->getAlign(); return AI->getAlign();
if (!Alignment) {
Type *AllocatedType = AI->getAllocatedType();
if (AllocatedType->isSized())
return MaybeAlign(DL.getPrefTypeAlignment(AllocatedType));
}
return Alignment;
} else if (const auto *Call = dyn_cast<CallBase>(this)) { } else if (const auto *Call = dyn_cast<CallBase>(this)) {
const MaybeAlign Alignment = Call->getRetAlign(); MaybeAlign Alignment = Call->getRetAlign();
if (!Alignment && Call->getCalledFunction()) if (!Alignment && Call->getCalledFunction())
return MaybeAlign( Alignment = Call->getCalledFunction()->getAttributes().getRetAlignment();
Call->getCalledFunction()->getAttributes().getRetAlignment()); return Alignment.valueOrOne();
return Alignment;
} else if (const LoadInst *LI = dyn_cast<LoadInst>(this)) { } else if (const LoadInst *LI = dyn_cast<LoadInst>(this)) {
if (MDNode *MD = LI->getMetadata(LLVMContext::MD_align)) { if (MDNode *MD = LI->getMetadata(LLVMContext::MD_align)) {
ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(0)); ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(0));
return MaybeAlign(CI->getLimitedValue()); return Align(CI->getLimitedValue());
} }
} else if (auto *CstPtr = dyn_cast<Constant>(this)) { } else if (auto *CstPtr = dyn_cast<Constant>(this)) {
if (auto *CstInt = dyn_cast_or_null<ConstantInt>(ConstantExpr::getPtrToInt( if (auto *CstInt = dyn_cast_or_null<ConstantInt>(ConstantExpr::getPtrToInt(
@ -807,7 +800,7 @@ MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
: Value::MaximumAlignment); : Value::MaximumAlignment);
} }
} }
return llvm::None; return Align(1);
} }
const Value *Value::DoPHITranslation(const BasicBlock *CurBB, const Value *Value::DoPHITranslation(const BasicBlock *CurBB,

View File

@ -2485,8 +2485,8 @@ def : InstAlias<"prfm $Rt, [$Rn]", (PRFMui prfop:$Rt, GPR64sp:$Rn, 0)>;
def alignedglobal : PatLeaf<(iPTR iPTR:$label), [{ def alignedglobal : PatLeaf<(iPTR iPTR:$label), [{
if (auto *G = dyn_cast<GlobalAddressSDNode>(N)) { if (auto *G = dyn_cast<GlobalAddressSDNode>(N)) {
const DataLayout &DL = MF->getDataLayout(); const DataLayout &DL = MF->getDataLayout();
MaybeAlign Align = G->getGlobal()->getPointerAlignment(DL); Align Align = G->getGlobal()->getPointerAlignment(DL);
return Align && *Align >= 4 && G->getOffset() % 4 == 0; return Align >= 4 && G->getOffset() % 4 == 0;
} }
if (auto *C = dyn_cast<ConstantPoolSDNode>(N)) if (auto *C = dyn_cast<ConstantPoolSDNode>(N))
return C->getAlign() >= 4 && C->getOffset() % 4 == 0; return C->getAlign() >= 4 && C->getOffset() % 4 == 0;

View File

@ -3523,17 +3523,6 @@ struct AADereferenceableCallSiteReturned final
// ------------------------ Align Argument Attribute ------------------------ // ------------------------ Align Argument Attribute ------------------------
/// \p Ptr is accessed so we can get alignment information if the ABI requires
/// the element type to be aligned.
static MaybeAlign getKnownAlignmentFromAccessedPtr(const Value *Ptr,
const DataLayout &DL) {
MaybeAlign KnownAlignment = Ptr->getPointerAlignment(DL);
Type *ElementTy = Ptr->getType()->getPointerElementType();
if (ElementTy->isSized())
KnownAlignment = max(KnownAlignment, DL.getABITypeAlign(ElementTy));
return KnownAlignment;
}
static unsigned getKnownAlignForUse(Attributor &A, static unsigned getKnownAlignForUse(Attributor &A,
AbstractAttribute &QueryingAA, AbstractAttribute &QueryingAA,
Value &AssociatedValue, const Use *U, Value &AssociatedValue, const Use *U,
@ -3569,19 +3558,11 @@ static unsigned getKnownAlignForUse(Attributor &A,
const DataLayout &DL = A.getDataLayout(); const DataLayout &DL = A.getDataLayout();
const Value *UseV = U->get(); const Value *UseV = U->get();
if (auto *SI = dyn_cast<StoreInst>(I)) { if (auto *SI = dyn_cast<StoreInst>(I)) {
if (SI->getPointerOperand() == UseV) { if (SI->getPointerOperand() == UseV)
if (unsigned SIAlign = SI->getAlignment()) MA = SI->getAlign();
MA = MaybeAlign(SIAlign);
else
MA = getKnownAlignmentFromAccessedPtr(UseV, DL);
}
} else if (auto *LI = dyn_cast<LoadInst>(I)) { } else if (auto *LI = dyn_cast<LoadInst>(I)) {
if (LI->getPointerOperand() == UseV) { if (LI->getPointerOperand() == UseV)
if (unsigned LIAlign = LI->getAlignment()) MA = LI->getAlign();
MA = MaybeAlign(LIAlign);
else
MA = getKnownAlignmentFromAccessedPtr(UseV, DL);
}
} }
if (!MA.hasValue() || MA <= 1) if (!MA.hasValue() || MA <= 1)
@ -3622,8 +3603,7 @@ struct AAAlignImpl : AAAlign {
// their uses and int2ptr is not handled. It is not a correctness // their uses and int2ptr is not handled. It is not a correctness
// problem though! // problem though!
if (!V.getType()->getPointerElementType()->isFunctionTy()) if (!V.getType()->getPointerElementType()->isFunctionTy())
takeKnownMaximum( takeKnownMaximum(V.getPointerAlignment(A.getDataLayout()).value());
V.getPointerAlignment(A.getDataLayout()).valueOrOne().value());
if (getIRPosition().isFnInterfaceKind() && if (getIRPosition().isFnInterfaceKind() &&
(!getAnchorScope() || (!getAnchorScope() ||
@ -3664,9 +3644,9 @@ struct AAAlignImpl : AAAlign {
ChangeStatus Changed = AAAlign::manifest(A); ChangeStatus Changed = AAAlign::manifest(A);
MaybeAlign InheritAlign = Align InheritAlign =
getAssociatedValue().getPointerAlignment(A.getDataLayout()); getAssociatedValue().getPointerAlignment(A.getDataLayout());
if (InheritAlign.valueOrOne() >= getAssumedAlign()) if (InheritAlign >= getAssumedAlign())
return LoadStoreChanged; return LoadStoreChanged;
return Changed | LoadStoreChanged; return Changed | LoadStoreChanged;
} }
@ -3717,8 +3697,8 @@ struct AAAlignFloating : AAAlignImpl {
const auto &AA = A.getAAFor<AAAlign>(*this, IRPosition::value(V)); const auto &AA = A.getAAFor<AAAlign>(*this, IRPosition::value(V));
if (!Stripped && this == &AA) { if (!Stripped && this == &AA) {
// Use only IR information if we did not strip anything. // Use only IR information if we did not strip anything.
const MaybeAlign PA = V.getPointerAlignment(DL); Align PA = V.getPointerAlignment(DL);
T.takeKnownMaximum(PA ? PA->value() : 0); T.takeKnownMaximum(PA.value());
T.indicatePessimisticFixpoint(); T.indicatePessimisticFixpoint();
} else { } else {
// Use abstract attribute information. // Use abstract attribute information.
@ -3786,9 +3766,9 @@ struct AAAlignCallSiteArgument final : AAAlignFloating {
if (A.getInfoCache().isInvolvedInMustTailCall(*Arg)) if (A.getInfoCache().isInvolvedInMustTailCall(*Arg))
return ChangeStatus::UNCHANGED; return ChangeStatus::UNCHANGED;
ChangeStatus Changed = AAAlignImpl::manifest(A); ChangeStatus Changed = AAAlignImpl::manifest(A);
MaybeAlign InheritAlign = Align InheritAlign =
getAssociatedValue().getPointerAlignment(A.getDataLayout()); getAssociatedValue().getPointerAlignment(A.getDataLayout());
if (InheritAlign.valueOrOne() >= getAssumedAlign()) if (InheritAlign >= getAssumedAlign())
Changed = ChangeStatus::UNCHANGED; Changed = ChangeStatus::UNCHANGED;
return Changed; return Changed;
} }

View File

@ -51,10 +51,10 @@ entry:
%sret_gep_outside = getelementptr %struct.A, %struct.A* %result, i64 0, i32 1, i64 7 %sret_gep_outside = getelementptr %struct.A, %struct.A* %result, i64 0, i32 1, i64 7
load i8, i8* %sret_gep_outside load i8, i8* %sret_gep_outside
; CHECK: %dparam{{.*}}(aligned) ; CHECK: %dparam{{.*}}(unaligned)
%load3 = load i32, i32 addrspace(1)* %dparam %load3 = load i32, i32 addrspace(1)* %dparam
; CHECK: %relocate{{.*}}(aligned) ; CHECK: %relocate{{.*}}(unaligned)
%tok = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam) %tok = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam)
%relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 7, i32 7) %relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 7, i32 7)
%load4 = load i32, i32 addrspace(1)* %relocate %load4 = load i32, i32 addrspace(1)* %relocate
@ -70,7 +70,7 @@ entry:
%load6 = load i32, i32* %nd_load %load6 = load i32, i32* %nd_load
; Load from a dereferenceable load ; Load from a dereferenceable load
; CHECK: %d4_load{{.*}}(aligned) ; CHECK: %d4_load{{.*}}(unaligned)
%d4_load = load i32*, i32** @globali32ptr, !dereferenceable !0 %d4_load = load i32*, i32** @globali32ptr, !dereferenceable !0
%load7 = load i32, i32* %d4_load %load7 = load i32, i32* %d4_load
@ -85,7 +85,7 @@ entry:
%load9 = load i32, i32* %d_or_null_load %load9 = load i32, i32* %d_or_null_load
; Load from a non-null pointer with dereferenceable_or_null ; Load from a non-null pointer with dereferenceable_or_null
; CHECK: %d_or_null_non_null_load{{.*}}(aligned) ; CHECK: %d_or_null_non_null_load{{.*}}(unaligned)
%d_or_null_non_null_load = load i32*, i32** @globali32ptr, !nonnull !2, !dereferenceable_or_null !0 %d_or_null_non_null_load = load i32*, i32** @globali32ptr, !nonnull !2, !dereferenceable_or_null !0
%load10 = load i32, i32* %d_or_null_non_null_load %load10 = load i32, i32* %d_or_null_non_null_load

View File

@ -192,7 +192,7 @@ header:
br label %header br label %header
} }
define i32 @test6b(i1 %cnd, i32* dereferenceable(8) %p) { define i32 @test6b(i1 %cnd, i32* dereferenceable(8) align 4 %p) {
entry: entry:
; CHECK-LABEL: @test6b ; CHECK-LABEL: @test6b
; CHECK: load i32, i32* %p ; CHECK: load i32, i32* %p

View File

@ -507,7 +507,7 @@ follow_2:
; dereferenceable can be loaded from speculatively without a risk of trapping. ; dereferenceable can be loaded from speculatively without a risk of trapping.
; Since it is OK to speculate, PRE is allowed. ; Since it is OK to speculate, PRE is allowed.
define i32 @test15(i32* noalias nocapture readonly dereferenceable(8) %x, i32* noalias nocapture %r, i32 %a) { define i32 @test15(i32* noalias nocapture readonly dereferenceable(8) align 4 %x, i32* noalias nocapture %r, i32 %a) {
; CHECK-LABEL: @test15 ; CHECK-LABEL: @test15
; CHECK: entry: ; CHECK: entry:
@ -548,7 +548,7 @@ if.end:
; dereferenceable can be loaded from speculatively without a risk of trapping. ; dereferenceable can be loaded from speculatively without a risk of trapping.
; Since it is OK to speculate, PRE is allowed. ; Since it is OK to speculate, PRE is allowed.
define i32 @test16(i32* noalias nocapture readonly dereferenceable(8) %x, i32* noalias nocapture %r, i32 %a) { define i32 @test16(i32* noalias nocapture readonly dereferenceable(8) align 4 %x, i32* noalias nocapture %r, i32 %a) {
; CHECK-LABEL: @test16( ; CHECK-LABEL: @test16(
; CHECK: entry: ; CHECK: entry:

View File

@ -67,7 +67,7 @@ define void @negative_load(i32 %V1, i32* %P) {
ret void ret void
} }
define void @deref_load(i32 %V1, i32* dereferenceable(4) %P) { define void @deref_load(i32 %V1, i32* dereferenceable(4) align 4 %P) {
; CHECK-LABEL: @deref_load ; CHECK-LABEL: @deref_load
; CHECK-NEXT: %V2 = load i32, i32* %P, align 4 ; CHECK-NEXT: %V2 = load i32, i32* %P, align 4
; CHECK-NEXT: %1 = and i32 %V2, %V1 ; CHECK-NEXT: %1 = and i32 %V2, %V1

View File

@ -83,7 +83,7 @@ define <2 x double> @load_generic(<2 x double>* %ptr, double %pt,
ret <2 x double> %res ret <2 x double> %res
} }
define <2 x double> @load_speculative(<2 x double>* dereferenceable(16) %ptr, define <2 x double> @load_speculative(<2 x double>* dereferenceable(16) align 4 %ptr,
; CHECK-LABEL: @load_speculative( ; CHECK-LABEL: @load_speculative(
; CHECK-NEXT: [[PTV1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0 ; CHECK-NEXT: [[PTV1:%.*]] = insertelement <2 x double> undef, double [[PT:%.*]], i64 0
; CHECK-NEXT: [[PTV2:%.*]] = shufflevector <2 x double> [[PTV1]], <2 x double> undef, <2 x i32> zeroinitializer ; CHECK-NEXT: [[PTV2:%.*]] = shufflevector <2 x double> [[PTV1]], <2 x double> undef, <2 x i32> zeroinitializer

View File

@ -981,7 +981,7 @@ entry:
; Test that we can speculate the loads around the select even when we can't ; Test that we can speculate the loads around the select even when we can't
; fold the load completely away. ; fold the load completely away.
define i32 @test78_deref(i1 %flag, i32* dereferenceable(4) %x, i32* dereferenceable(4) %y, i32* %z) { define i32 @test78_deref(i1 %flag, i32* dereferenceable(4) align 4 %x, i32* dereferenceable(4) align 4 %y, i32* %z) {
; CHECK-LABEL: @test78_deref( ; CHECK-LABEL: @test78_deref(
; CHECK-NEXT: [[X_VAL:%.*]] = load i32, i32* [[X:%.*]], align 4 ; CHECK-NEXT: [[X_VAL:%.*]] = load i32, i32* [[X:%.*]], align 4
; CHECK-NEXT: [[Y_VAL:%.*]] = load i32, i32* [[Y:%.*]], align 4 ; CHECK-NEXT: [[Y_VAL:%.*]] = load i32, i32* [[Y:%.*]], align 4

View File

@ -19,7 +19,7 @@ target triple = "x86_64-unknown-linux-gnu"
; CHECK: load i32, i32* %c, align 4 ; CHECK: load i32, i32* %c, align 4
; CHECK: for.body: ; CHECK: for.body:
define void @test1(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly nonnull dereferenceable(4) %c, i32 %n) #0 { define void @test1(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly nonnull dereferenceable(4) align 4 %c, i32 %n) #0 {
entry: entry:
%cmp11 = icmp sgt i32 %n, 0 %cmp11 = icmp sgt i32 %n, 0
br i1 %cmp11, label %for.body, label %for.end br i1 %cmp11, label %for.body, label %for.end
@ -99,7 +99,7 @@ for.end: ; preds = %for.inc, %entry
; CHECK: load i32, i32* %c2, align 4 ; CHECK: load i32, i32* %c2, align 4
; CHECK: for.body: ; CHECK: for.body:
define void @test3(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly dereferenceable(12) %c, i32 %n) #0 { define void @test3(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly dereferenceable(12) align 4 %c, i32 %n) #0 {
entry: entry:
%cmp11 = icmp sgt i32 %n, 0 %cmp11 = icmp sgt i32 %n, 0
br i1 %cmp11, label %for.body, label %for.end br i1 %cmp11, label %for.body, label %for.end
@ -183,7 +183,7 @@ for.end: ; preds = %for.inc, %entry
; CHECK: load i32, i32* %c, align 4 ; CHECK: load i32, i32* %c, align 4
; CHECK: for.body: ; CHECK: for.body:
define void @test5(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n) #0 { define void @test5(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) align 4 %c, i32 %n) #0 {
entry: entry:
%not_null = icmp ne i32* %c, null %not_null = icmp ne i32* %c, null
br i1 %not_null, label %not.null, label %for.end br i1 %not_null, label %not.null, label %for.end
@ -274,7 +274,7 @@ for.end: ; preds = %for.inc, %entry
define void @test7(i32* noalias %a, i32* %b, i32** %cptr, i32 %n) #0 { define void @test7(i32* noalias %a, i32* %b, i32** %cptr, i32 %n) #0 {
entry: entry:
%c = load i32*, i32** %cptr, !dereferenceable !0 %c = load i32*, i32** %cptr, !dereferenceable !0, !align !{i64 4}
%cmp11 = icmp sgt i32 %n, 0 %cmp11 = icmp sgt i32 %n, 0
br i1 %cmp11, label %for.body, label %for.end br i1 %cmp11, label %for.body, label %for.end
@ -321,7 +321,7 @@ for.end: ; preds = %for.inc, %entry
define void @test8(i32* noalias %a, i32* %b, i32** %cptr, i32 %n) #0 { define void @test8(i32* noalias %a, i32* %b, i32** %cptr, i32 %n) #0 {
entry: entry:
%c = load i32*, i32** %cptr, !dereferenceable_or_null !0 %c = load i32*, i32** %cptr, !dereferenceable_or_null !0, !align !{i64 4}
%not_null = icmp ne i32* %c, null %not_null = icmp ne i32* %c, null
br i1 %not_null, label %not.null, label %for.end br i1 %not_null, label %not.null, label %for.end
@ -405,7 +405,7 @@ for.end: ; preds = %for.inc, %entry
; CHECK: if.then: ; CHECK: if.then:
; CHECK: load i32, i32* %c, align 4 ; CHECK: load i32, i32* %c, align 4
define void @test10(i32* noalias %a, i32* %b, i32** dereferenceable(8) %cptr, i32 %n) #0 { define void @test10(i32* noalias %a, i32* %b, i32** dereferenceable(8) align 8 %cptr, i32 %n) #0 {
entry: entry:
%cmp11 = icmp sgt i32 %n, 0 %cmp11 = icmp sgt i32 %n, 0
br i1 %cmp11, label %for.body, label %for.end br i1 %cmp11, label %for.body, label %for.end
@ -475,7 +475,7 @@ for.end: ; preds = %for.inc, %entry
declare void @llvm.experimental.guard(i1, ...) declare void @llvm.experimental.guard(i1, ...)
define void @test12(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n) #0 { define void @test12(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) align 4 %c, i32 %n) #0 {
; Prove non-null ness of %c via a guard, not a branch. ; Prove non-null ness of %c via a guard, not a branch.
; CHECK-LABEL: @test12( ; CHECK-LABEL: @test12(
@ -560,7 +560,7 @@ for.end: ; preds = %for.inc, %entry, %e
; Check that branch by condition "null check AND something" allows to hoist the ; Check that branch by condition "null check AND something" allows to hoist the
; load. ; load.
define void @test14(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n, i1 %dummy_cond) #0 { define void @test14(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) align 4 %c, i32 %n, i1 %dummy_cond) #0 {
; CHECK-LABEL: @test14 ; CHECK-LABEL: @test14
; CHECK: load i32, i32* %c, align 4 ; CHECK: load i32, i32* %c, align 4
@ -602,7 +602,7 @@ for.end: ; preds = %for.inc, %entry, %n
; Check that guard by condition "null check AND something" allows to hoist the ; Check that guard by condition "null check AND something" allows to hoist the
; load. ; load.
define void @test15(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n, i1 %dummy_cond) #0 { define void @test15(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) align 4 %c, i32 %n, i1 %dummy_cond) #0 {
; CHECK-LABEL: @test15 ; CHECK-LABEL: @test15
; CHECK: load i32, i32* %c, align 4 ; CHECK: load i32, i32* %c, align 4

View File

@ -119,7 +119,7 @@ end:
ret i8* %x10 ret i8* %x10
} }
define i32* @test5(i32 %a, i32 %b, i32 %c, i32* dereferenceable(10) %ptr1, i32* dereferenceable(10) %ptr2, i32** dereferenceable(10) %ptr3) { define i32* @test5(i32 %a, i32 %b, i32 %c, i32* dereferenceable(10) %ptr1, i32* dereferenceable(10) %ptr2, i32** dereferenceable(10) align 8 %ptr3) {
; CHECK-LABEL: @test5( ; CHECK-LABEL: @test5(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[B:%.*]], 0 ; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[B:%.*]], 0

View File

@ -126,7 +126,7 @@ recurse: ; preds = %else
; This load can be moved above the call because the function won't write to it ; This load can be moved above the call because the function won't write to it
; and the a_arg is dereferenceable. ; and the a_arg is dereferenceable.
define fastcc i32 @raise_load_5(i32* dereferenceable(4) %a_arg, i32 %a_len_arg, i32 %start_arg) readonly { define fastcc i32 @raise_load_5(i32* dereferenceable(4) align 4 %a_arg, i32 %a_len_arg, i32 %start_arg) readonly {
; CHECK-LABEL: @raise_load_5( ; CHECK-LABEL: @raise_load_5(
; CHECK-NOT: call ; CHECK-NOT: call
; CHECK: load i32, i32* ; CHECK: load i32, i32*

View File

@ -143,7 +143,7 @@ TEST(FunctionTest, GetPointerAlignment) {
FunctionType *FuncType(FunctionType::get(VoidType, false)); FunctionType *FuncType(FunctionType::get(VoidType, false));
std::unique_ptr<Function> Func(Function::Create( std::unique_ptr<Function> Func(Function::Create(
FuncType, GlobalValue::ExternalLinkage)); FuncType, GlobalValue::ExternalLinkage));
EXPECT_EQ(MaybeAlign(), Func->getPointerAlignment(DataLayout(""))); EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("")));
EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fi8"))); EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fi8")));
EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fn8"))); EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fn8")));
EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16"))); EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16")));
@ -153,7 +153,7 @@ TEST(FunctionTest, GetPointerAlignment) {
Func->setAlignment(Align(4)); Func->setAlignment(Align(4));
EXPECT_EQ(MaybeAlign(), Func->getPointerAlignment(DataLayout(""))); EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("")));
EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fi8"))); EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fi8")));
EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn8"))); EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn8")));
EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16"))); EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16")));

View File

@ -17,7 +17,7 @@
; CHECK-NOT: Function: foo_undereferanceable ; CHECK-NOT: Function: foo_undereferanceable
define void @foo_dereferanceable(double* %A, double* %B, i64* dereferenceable(8) %sizeA_ptr, define void @foo_dereferanceable(double* %A, double* %B, i64* dereferenceable(8) align 8 %sizeA_ptr,
i32 %lb.i, i32 %lb.j, i32 %ub.i, i32 %ub.j) { i32 %lb.i, i32 %lb.j, i32 %ub.i, i32 %ub.j) {
entry: entry:
br label %for.i br label %for.i