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 308092c83c
commit 202bb919c0
19 changed files with 66 additions and 99 deletions

View File

@ -64,6 +64,12 @@ Changes to the LLVM IR
provided by the attribute is interfaced via the API provided by the
``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
------------------------

View File

@ -664,7 +664,7 @@ public:
///
/// Returns an alignment which is either specified explicitly, e.g. via
/// 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.
///

View File

@ -27,24 +27,12 @@
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,
const DataLayout &DL) {
if (MaybeAlign BA = getBaseAlign(Base, DL)) {
const APInt APBaseAlign(Offset.getBitWidth(), BA->value());
const APInt APAlign(Offset.getBitWidth(), Alignment.value());
assert(APAlign.isPowerOf2() && "must be a power of 2!");
return APBaseAlign.uge(APAlign) && !(Offset & (APAlign - 1));
}
return false;
Align BA = Base->getPointerAlignment(DL);
const APInt APAlign(Offset.getBitWidth(), Alignment.value());
assert(APAlign.isPowerOf2() && "must be a power of 2!");
return BA >= Alignment && !(Offset & (APAlign - 1));
}
/// 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
if (isa<PointerType>(V->getType())) {
const MaybeAlign Align = V->getPointerAlignment(Q.DL);
if (Align)
Known.Zero.setLowBits(countTrailingZeros(Align->value()));
Align Alignment = V->getPointerAlignment(Q.DL);
Known.Zero.setLowBits(countTrailingZeros(Alignment.value()));
}
// computeKnownBitsFromAssume strictly refines Known.

View File

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

View File

@ -1210,7 +1210,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
MaybeAlign GVAlign;
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
// is 4.
@ -1221,7 +1222,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
// increased code size (see https://reviews.llvm.org/D55115)
// FIXME: This code should be deleted once existing targets have
// appropriate defaults
if (!GVAlign && isa<Function>(GV))
if (isa<Function>(GV) && !DL.getFunctionPtrAlign())
GVAlign = Align(4);
} else if (isa<Function>(GV)) {
// 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;
}
MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
Align Value::getPointerAlignment(const DataLayout &DL) const {
assert(getType()->isPointerTy() && "must be pointer");
if (auto *GO = dyn_cast<GlobalObject>(this)) {
if (isa<Function>(GO)) {
const MaybeAlign FunctionPtrAlign = DL.getFunctionPtrAlign();
Align FunctionPtrAlign = DL.getFunctionPtrAlign().valueOrOne();
switch (DL.getFunctionPtrAlignType()) {
case DataLayout::FunctionPtrAlignType::Independent:
return FunctionPtrAlign;
case DataLayout::FunctionPtrAlignType::MultipleOfFunctionAlign:
return std::max(FunctionPtrAlign, MaybeAlign(GO->getAlignment()));
return std::max(FunctionPtrAlign, GO->getAlign().valueOrOne());
}
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
// may only have the minimum ABI alignment.
if (GVar->isStrongDefinitionForLinker())
return MaybeAlign(DL.getPreferredAlignment(GVar));
return Align(DL.getPreferredAlignment(GVar));
else
return DL.getABITypeAlign(ObjectType);
}
}
}
return Alignment;
return Alignment.valueOrOne();
} else if (const Argument *A = dyn_cast<Argument>(this)) {
const MaybeAlign Alignment = A->getParamAlign();
if (!Alignment && A->hasStructRetAttr()) {
@ -775,25 +775,18 @@ MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
if (EltTy->isSized())
return DL.getABITypeAlign(EltTy);
}
return Alignment;
return Alignment.valueOrOne();
} else if (const AllocaInst *AI = dyn_cast<AllocaInst>(this)) {
const MaybeAlign Alignment = AI->getAlign();
if (!Alignment) {
Type *AllocatedType = AI->getAllocatedType();
if (AllocatedType->isSized())
return MaybeAlign(DL.getPrefTypeAlignment(AllocatedType));
}
return Alignment;
return AI->getAlign();
} else if (const auto *Call = dyn_cast<CallBase>(this)) {
const MaybeAlign Alignment = Call->getRetAlign();
MaybeAlign Alignment = Call->getRetAlign();
if (!Alignment && Call->getCalledFunction())
return MaybeAlign(
Call->getCalledFunction()->getAttributes().getRetAlignment());
return Alignment;
Alignment = Call->getCalledFunction()->getAttributes().getRetAlignment();
return Alignment.valueOrOne();
} else if (const LoadInst *LI = dyn_cast<LoadInst>(this)) {
if (MDNode *MD = LI->getMetadata(LLVMContext::MD_align)) {
ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(0));
return MaybeAlign(CI->getLimitedValue());
return Align(CI->getLimitedValue());
}
} else if (auto *CstPtr = dyn_cast<Constant>(this)) {
if (auto *CstInt = dyn_cast_or_null<ConstantInt>(ConstantExpr::getPtrToInt(
@ -807,7 +800,7 @@ MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
: Value::MaximumAlignment);
}
}
return llvm::None;
return Align(1);
}
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), [{
if (auto *G = dyn_cast<GlobalAddressSDNode>(N)) {
const DataLayout &DL = MF->getDataLayout();
MaybeAlign Align = G->getGlobal()->getPointerAlignment(DL);
return Align && *Align >= 4 && G->getOffset() % 4 == 0;
Align Align = G->getGlobal()->getPointerAlignment(DL);
return Align >= 4 && G->getOffset() % 4 == 0;
}
if (auto *C = dyn_cast<ConstantPoolSDNode>(N))
return C->getAlign() >= 4 && C->getOffset() % 4 == 0;

View File

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

View File

@ -51,10 +51,10 @@ entry:
%sret_gep_outside = getelementptr %struct.A, %struct.A* %result, i64 0, i32 1, i64 7
load i8, i8* %sret_gep_outside
; CHECK: %dparam{{.*}}(aligned)
; CHECK: %dparam{{.*}}(unaligned)
%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)
%relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 7, i32 7)
%load4 = load i32, i32 addrspace(1)* %relocate
@ -70,7 +70,7 @@ entry:
%load6 = load i32, i32* %nd_load
; Load from a dereferenceable load
; CHECK: %d4_load{{.*}}(aligned)
; CHECK: %d4_load{{.*}}(unaligned)
%d4_load = load i32*, i32** @globali32ptr, !dereferenceable !0
%load7 = load i32, i32* %d4_load
@ -85,7 +85,7 @@ entry:
%load9 = load i32, i32* %d_or_null_load
; 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
%load10 = load i32, i32* %d_or_null_non_null_load

View File

@ -192,7 +192,7 @@ 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:
; CHECK-LABEL: @test6b
; CHECK: load i32, i32* %p

View File

@ -507,7 +507,7 @@ follow_2:
; dereferenceable can be loaded from speculatively without a risk of trapping.
; 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: entry:
@ -548,7 +548,7 @@ if.end:
; dereferenceable can be loaded from speculatively without a risk of trapping.
; 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: entry:

View File

@ -67,7 +67,7 @@ define void @negative_load(i32 %V1, i32* %P) {
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-NEXT: %V2 = load i32, i32* %P, align 4
; 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
}
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-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

View File

@ -981,7 +981,7 @@ entry:
; Test that we can speculate the loads around the select even when we can't
; 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-NEXT: [[X_VAL:%.*]] = load i32, i32* [[X:%.*]], 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: 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:
%cmp11 = icmp sgt i32 %n, 0
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: 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:
%cmp11 = icmp sgt i32 %n, 0
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: 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:
%not_null = icmp ne i32* %c, null
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 {
entry:
%c = load i32*, i32** %cptr, !dereferenceable !0
%c = load i32*, i32** %cptr, !dereferenceable !0, !align !{i64 4}
%cmp11 = icmp sgt i32 %n, 0
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 {
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
br i1 %not_null, label %not.null, label %for.end
@ -405,7 +405,7 @@ for.end: ; preds = %for.inc, %entry
; CHECK: if.then:
; 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:
%cmp11 = icmp sgt i32 %n, 0
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, ...)
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.
; 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
; 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: 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
; 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: load i32, i32* %c, align 4

View File

@ -119,7 +119,7 @@ end:
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-NEXT: entry:
; 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
; 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-NOT: call
; CHECK: load i32, i32*

View File

@ -143,7 +143,7 @@ TEST(FunctionTest, GetPointerAlignment) {
FunctionType *FuncType(FunctionType::get(VoidType, false));
std::unique_ptr<Function> Func(Function::Create(
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("Fn8")));
EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16")));
@ -153,7 +153,7 @@ TEST(FunctionTest, GetPointerAlignment) {
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(4), Func->getPointerAlignment(DataLayout("Fn8")));
EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16")));