diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -1816,7 +1816,8 @@ Value *R = Roots.pop_back_val(); for (auto &U : R->uses()) { User *UU = U.getUser(); - if (Operator::getOpcode(UU) == Instruction::BitCast) + const unsigned OpCode = Operator::getOpcode(UU); + if (OpCode == Instruction::BitCast || OpCode == Instruction::PtrToInt) Roots.push_back(UU); else if (auto *LI = dyn_cast(UU)) Loads.push_back(std::make_pair<>(LI, LI->getType())); @@ -1829,7 +1830,8 @@ return false; unsigned ArgNo = CB->getArgOperandNo(&U); // Argument must not be captured for subsequent use - if (!CB->paramHasAttr(ArgNo, Attribute::NoCapture)) + if (U->getType()->isPointerTy() && + !CB->paramHasAttr(ArgNo, Attribute::NoCapture)) return false; // Depending on attributes, either treat calls as loads/stores at the // call site, or ignore them if they are not going to be dereferenced. diff --git a/llvm/lib/Transforms/Utils/GlobalStatus.cpp b/llvm/lib/Transforms/Utils/GlobalStatus.cpp --- a/llvm/lib/Transforms/Utils/GlobalStatus.cpp +++ b/llvm/lib/Transforms/Utils/GlobalStatus.cpp @@ -69,9 +69,9 @@ if (const ConstantExpr *CE = dyn_cast(UR)) { GS.HasNonInstructionUser = true; - // If the result of the constantexpr isn't pointer type, then we won't - // know to expect it in various places. Just reject early. - if (!isa(CE->getType())) + // If the result of the constantexpr isn't pointer/integer type, then we + // won't know to expect it in various places. Just reject early. + if (!isa(CE->getType()) && !isa(CE->getType())) return true; // FIXME: Do we need to add constexpr selects to VisitedUsers? @@ -137,7 +137,8 @@ GS.StoredType = GlobalStatus::Stored; } } - } else if (isa(I) || isa(I)) { + } else if (isa(I) || isa(I) || + isa(I)) { // Skip over bitcasts and GEPs; we don't care about the type or offset // of the pointer. if (analyzeGlobalAux(I, GS, VisitedUsers)) @@ -160,8 +161,7 @@ if (MTI->getArgOperand(1) == V) GS.IsLoaded = true; } else if (const MemSetInst *MSI = dyn_cast(I)) { - assert(MSI->getArgOperand(0) == V && "Memset only takes one pointer!"); - if (MSI->isVolatile()) + if (MSI->isVolatile() || MSI->getArgOperand(0) != V) return true; GS.StoredType = GlobalStatus::Stored; } else if (const CallBase *CB = dyn_cast(I)) { @@ -170,7 +170,8 @@ } else if (CB->isArgOperand(&U)) { unsigned ArgNo = CB->getArgOperandNo(&U); // Argument must not be captured for subsequent use - if (!CB->paramHasAttr(ArgNo, Attribute::NoCapture)) + if (U->getType()->isPointerTy() && + !CB->paramHasAttr(ArgNo, Attribute::NoCapture)) return true; // Depending on attributes, treat the operand as a pure call, load, or // store at the call site. diff --git a/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp b/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp --- a/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ b/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -88,6 +88,8 @@ } else if (const IntrinsicInst *II = dyn_cast(U)) { if (!II->isLifetimeStartOrEnd()) return false; + } else if (const PtrToIntInst *PTI = dyn_cast(U)) { + Roots.push_back(PTI); } else if (const BitCastInst *BCI = dyn_cast(U)) { Roots.push_back(BCI); } else if (const GetElementPtrInst *GEPI = @@ -347,7 +349,8 @@ ++UI; if (isa(U) || isa(U)) continue; - else if (isa(U) || isa(U)) + else if (isa(U) || isa(U) || + isa(U)) Roots.push_back(U); else if (CallBase *CB = dyn_cast(U)) { if (isa(U)) diff --git a/llvm/test/Instrumentation/AddressSanitizer/debug_info_noninstrumented_alloca2.ll b/llvm/test/Instrumentation/AddressSanitizer/debug_info_noninstrumented_alloca2.ll --- a/llvm/test/Instrumentation/AddressSanitizer/debug_info_noninstrumented_alloca2.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/debug_info_noninstrumented_alloca2.ll @@ -6,12 +6,15 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.10.0" +declare void @bar(i32) + define i32 @foo() sanitize_address { entry: %non_instrumented1 = alloca i32, align 4 %t = load i32, i32* %non_instrumented1, align 4 %instrumented = alloca i32, align 4 %ptr = ptrtoint i32* %instrumented to i32 + call void @bar(i32 %ptr) ret i32 %t } diff --git a/llvm/test/Transforms/GlobalOpt/localize-fnattr.ll b/llvm/test/Transforms/GlobalOpt/localize-fnattr.ll --- a/llvm/test/Transforms/GlobalOpt/localize-fnattr.ll +++ b/llvm/test/Transforms/GlobalOpt/localize-fnattr.ll @@ -76,3 +76,20 @@ %d = load i32, i32* @G4 ret i32 %d } + +declare void @foo5(i32, i8) local_unnamed_addr readnone + +@G5 = internal global i32 0 + +; Doesn't read from casted pointer argument +define i32 @e() norecurse { +; CHECK-LABEL: @e +; CHECK: alloca +; CHECK-NOT: @G5 +; CHECK: } + store i32 42, i32 *@G5 + %p = ptrtoint i32* @G5 to i8 + call void @foo5(i32 ptrtoint (i32* @G5 to i32), i8 %p) + %e = load i32, i32* @G5 + ret i32 %e +} diff --git a/llvm/test/Transforms/Mem2Reg/fnattr.ll b/llvm/test/Transforms/Mem2Reg/fnattr.ll --- a/llvm/test/Transforms/Mem2Reg/fnattr.ll +++ b/llvm/test/Transforms/Mem2Reg/fnattr.ll @@ -39,3 +39,22 @@ %b = load i32, i32* %g2 ret i32 %b } + +declare void @foo3(i32, i8) local_unnamed_addr readnone + +; Doesn't read from casted pointer argument +define i32 @c() norecurse { +; CHECK-LABEL: @c +; CHECK-NOT: alloca +; CHECK-NOT: ptrtoint +; CHECK-NOT: %g3 +; CHECK: undef +; CHECK: ret i32 42 +; CHECK: } + %g3 = alloca i32 + store i32 42, i32 *%g3 + %p = ptrtoint i32* %g3 to i32 + call void @foo3(i32 %p, i8 0) + %c = load i32, i32* %g3 + ret i32 %c +}