/// specified pointer, we do a quick local scan of the basic block containing
/// ScanFrom, to determine if the address is already accessed.
bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
- const TargetData *TD = 0);
+ unsigned Align, const TargetData *TD = 0);
//===----------------------------------------------------------------------===//
// Local constant propagation.
//
if (SelectInst *SI = dyn_cast<SelectInst>(Op)) {
// load (select (Cond, &V1, &V2)) --> select(Cond, load &V1, load &V2).
- if (isSafeToLoadUnconditionally(SI->getOperand(1), SI, TD) &&
- isSafeToLoadUnconditionally(SI->getOperand(2), SI, TD)) {
+ unsigned Align = LI.getAlignment();
+ if (isSafeToLoadUnconditionally(SI->getOperand(1), SI, Align, TD) &&
+ isSafeToLoadUnconditionally(SI->getOperand(2), SI, Align, TD)) {
LoadInst *V1 = Builder->CreateLoad(SI->getOperand(1),
- SI->getOperand(1)->getName()+".val");
+ SI->getOperand(1)->getName()+".val");
LoadInst *V2 = Builder->CreateLoad(SI->getOperand(2),
- SI->getOperand(2)->getName()+".val");
- V1->setAlignment(LI.getAlignment());
- V2->setAlignment(LI.getAlignment());
+ SI->getOperand(2)->getName()+".val");
+ V1->setAlignment(Align);
+ V2->setAlignment(Align);
return SelectInst::Create(SI->getCondition(), V1, V2);
}
if (!allSingleSucc &&
// FIXME: REEVALUTE THIS.
!isSafeToLoadUnconditionally(LoadPtr,
- UnavailablePred->getTerminator(), TD)) {
+ UnavailablePred->getTerminator(),
+ LI->getAlignment(), TD)) {
assert(NewInsts.empty() && "Should not have inserted instructions");
return false;
}
// FIXME: Writes to memory only matter if they may alias the pointer
// being loaded from.
if (CI->mayWriteToMemory() ||
- !isSafeToLoadUnconditionally(L->getPointerOperand(), L))
+ !isSafeToLoadUnconditionally(L->getPointerOperand(), L,
+ L->getAlignment()))
return false;
}
}
/// specified pointer, we do a quick local scan of the basic block containing
/// ScanFrom, to determine if the address is already accessed.
bool llvm::isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
- const TargetData *TD) {
+ unsigned Align, const TargetData *TD) {
uint64_t ByteOffset = 0;
Value *Base = V;
if (TD)
Base = getUnderlyingObjectWithOffset(V, TD, ByteOffset);
const Type *BaseType = 0;
- if (const AllocaInst *AI = dyn_cast<AllocaInst>(Base))
- // If it is an alloca it is always safe to load from.
+ unsigned BaseAlign = 0;
+ if (const AllocaInst *AI = dyn_cast<AllocaInst>(Base)) {
+ // An alloca is safe to load from as load as it is suitably aligned.
BaseType = AI->getAllocatedType();
- else if (const GlobalValue *GV = dyn_cast<GlobalValue>(Base)) {
+ BaseAlign = AI->getAlignment();
+ } else if (const GlobalValue *GV = dyn_cast<GlobalValue>(Base)) {
// Global variables are safe to load from but their size cannot be
// guaranteed if they are overridden.
- if (!isa<GlobalAlias>(GV) && !GV->mayBeOverridden())
+ if (!isa<GlobalAlias>(GV) && !GV->mayBeOverridden()) {
BaseType = GV->getType()->getElementType();
+ BaseAlign = GV->getAlignment();
+ }
}
+ if (TD && BaseType && BaseAlign == 0)
+ BaseAlign = TD->getPrefTypeAlignment(BaseType);
- if (BaseType) {
+ if (BaseType && Align <= BaseAlign) {
if (!TD)
return true; // Loading directly from an alloca or global is OK.
if (BaseType->isSized()) {
// Check if the load is within the bounds of the underlying object.
const PointerType *AddrTy = cast<PointerType>(V->getType());
uint64_t LoadSize = TD->getTypeStoreSize(AddrTy->getElementType());
- if (ByteOffset + LoadSize <= TD->getTypeAllocSize(BaseType))
+ if (ByteOffset + LoadSize <= TD->getTypeAllocSize(BaseType) &&
+ (Align == 0 || (ByteOffset % Align) == 0))
return true;
}
}
--- /dev/null
+; RUN: opt < %s -gvn -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32-n32"
+
+@p = external global i32
+
+define arm_apcscc i32 @test(i32 %n) nounwind {
+; CHECK: @test
+entry:
+ br label %for.cond
+
+; loads aligned greater than the memory should not be moved past conditionals
+; CHECK-NOT: load
+; CHECK: br i1
+
+for.cond:
+ %i.0 = phi i32 [ 0, %entry ], [ %indvar.next, %for.inc ]
+ %cmp = icmp slt i32 %i.0, %n
+ br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:
+; ...but PRE can still move the load out of for.end to here.
+; CHECK: for.cond.for.end_crit_edge:
+; CHECK-NEXT: load
+ br label %for.end
+
+for.body:
+ %tmp3 = load i32* @p, align 8
+ %dec = add i32 %tmp3, -1
+ store i32 %dec, i32* @p
+ %cmp6 = icmp slt i32 %dec, 0
+ br i1 %cmp6, label %for.body.for.end_crit_edge, label %for.inc
+
+for.body.for.end_crit_edge:
+ br label %for.end
+
+for.inc:
+ %indvar.next = add i32 %i.0, 1
+ br label %for.cond
+
+for.end:
+ %tmp9 = load i32* @p, align 8
+ ret i32 %tmp9
+}