Compare commits
3 Commits
llvmorg-6.
...
llvmorg-6.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d359f20968 | ||
|
|
7daf52428c | ||
|
|
4f031296e9 |
@@ -159,7 +159,6 @@ typedef struct user_fpregs elf_fpregset_t;
|
||||
# include <sys/procfs.h>
|
||||
#endif
|
||||
#include <sys/user.h>
|
||||
#include <sys/ustat.h>
|
||||
#include <linux/cyclades.h>
|
||||
#include <linux/if_eql.h>
|
||||
#include <linux/if_plip.h>
|
||||
@@ -253,7 +252,19 @@ namespace __sanitizer {
|
||||
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
unsigned struct_ustat_sz = sizeof(struct ustat);
|
||||
// Use pre-computed size of struct ustat to avoid <sys/ustat.h> which
|
||||
// has been removed from glibc 2.28.
|
||||
#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \
|
||||
|| defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \
|
||||
|| defined(__x86_64__)
|
||||
#define SIZEOF_STRUCT_USTAT 32
|
||||
#elif defined(__arm__) || defined(__i386__) || defined(__mips__) \
|
||||
|| defined(__powerpc__) || defined(__s390__)
|
||||
#define SIZEOF_STRUCT_USTAT 20
|
||||
#else
|
||||
#error Unknown size of struct ustat
|
||||
#endif
|
||||
unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT;
|
||||
unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
|
||||
unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
|
||||
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
|
||||
@@ -2058,15 +2058,15 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c, const_iterator __f, con
|
||||
#endif
|
||||
if (__f != __l)
|
||||
{
|
||||
if (this != &__c)
|
||||
{
|
||||
size_type __s = _VSTD::distance(__f, __l);
|
||||
__c.__sz() -= __s;
|
||||
base::__sz() += __s;
|
||||
}
|
||||
__link_pointer __first = __f.__ptr_;
|
||||
--__l;
|
||||
__link_pointer __last = __l.__ptr_;
|
||||
if (this != &__c)
|
||||
{
|
||||
size_type __s = _VSTD::distance(__f, __l) + 1;
|
||||
__c.__sz() -= __s;
|
||||
base::__sz() += __s;
|
||||
}
|
||||
base::__unlink_nodes(__first, __last);
|
||||
__link_nodes(__p.__ptr_, __first, __last);
|
||||
#if _LIBCPP_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
Base::run();
|
||||
try {
|
||||
FrontOnEmptyContainer();
|
||||
|
||||
if constexpr (CT != CT_ForwardList) {
|
||||
AssignInvalidates();
|
||||
BackOnEmptyContainer();
|
||||
@@ -50,6 +51,8 @@ public:
|
||||
InsertIterIterIter();
|
||||
EmplaceIterValue();
|
||||
EraseIterIter();
|
||||
} else {
|
||||
SpliceFirstElemAfter();
|
||||
}
|
||||
if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
|
||||
PopBack();
|
||||
@@ -57,12 +60,66 @@ public:
|
||||
if constexpr (CT == CT_List || CT == CT_Deque) {
|
||||
PopFront(); // FIXME: Run with forward list as well
|
||||
}
|
||||
if constexpr (CT == CT_List || CT == CT_ForwardList) {
|
||||
RemoveFirstElem();
|
||||
}
|
||||
if constexpr (CT == CT_List) {
|
||||
SpliceFirstElem();
|
||||
}
|
||||
} catch (...) {
|
||||
assert(false && "uncaught debug exception");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void RemoveFirstElem() {
|
||||
// See llvm.org/PR35564
|
||||
CHECKPOINT("remove(<first-elem>)");
|
||||
{
|
||||
Container C = makeContainer(1);
|
||||
auto FirstVal = *(C.begin());
|
||||
C.remove(FirstVal);
|
||||
assert(C.empty());
|
||||
}
|
||||
{
|
||||
Container C = {1, 1, 1, 1};
|
||||
auto FirstVal = *(C.begin());
|
||||
C.remove(FirstVal);
|
||||
assert(C.empty());
|
||||
}
|
||||
}
|
||||
|
||||
static void SpliceFirstElem() {
|
||||
// See llvm.org/PR35564
|
||||
CHECKPOINT("splice(<first-elem>)");
|
||||
{
|
||||
Container C = makeContainer(1);
|
||||
Container C2;
|
||||
C2.splice(C2.end(), C, C.begin(), ++C.begin());
|
||||
}
|
||||
{
|
||||
Container C = makeContainer(1);
|
||||
Container C2;
|
||||
C2.splice(C2.end(), C, C.begin());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void SpliceFirstElemAfter() {
|
||||
// See llvm.org/PR35564
|
||||
CHECKPOINT("splice(<first-elem>)");
|
||||
{
|
||||
Container C = makeContainer(1);
|
||||
Container C2;
|
||||
C2.splice_after(C2.begin(), C, C.begin(), ++C.begin());
|
||||
}
|
||||
{
|
||||
Container C = makeContainer(1);
|
||||
Container C2;
|
||||
C2.splice_after(C2.begin(), C, C.begin());
|
||||
}
|
||||
}
|
||||
|
||||
static void AssignInvalidates() {
|
||||
CHECKPOINT("assign(Size, Value)");
|
||||
Container C(allocator_type{});
|
||||
|
||||
@@ -507,14 +507,28 @@ void DeadArgumentEliminationPass::SurveyFunction(const Function &F) {
|
||||
// MaybeLive. Initialized to a list of RetCount empty lists.
|
||||
RetUses MaybeLiveRetUses(RetCount);
|
||||
|
||||
for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
||||
if (const ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator()))
|
||||
bool HasMustTailCalls = false;
|
||||
|
||||
for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
|
||||
if (const ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
|
||||
if (RI->getNumOperands() != 0 && RI->getOperand(0)->getType()
|
||||
!= F.getFunctionType()->getReturnType()) {
|
||||
// We don't support old style multiple return values.
|
||||
MarkLive(F);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have any returns of `musttail` results - the signature can't
|
||||
// change
|
||||
if (BB->getTerminatingMustTailCall() != nullptr)
|
||||
HasMustTailCalls = true;
|
||||
}
|
||||
|
||||
if (HasMustTailCalls) {
|
||||
DEBUG(dbgs() << "DeadArgumentEliminationPass - " << F.getName()
|
||||
<< " has musttail calls\n");
|
||||
}
|
||||
|
||||
if (!F.hasLocalLinkage() && (!ShouldHackArguments || F.isIntrinsic())) {
|
||||
MarkLive(F);
|
||||
@@ -526,6 +540,9 @@ void DeadArgumentEliminationPass::SurveyFunction(const Function &F) {
|
||||
// Keep track of the number of live retvals, so we can skip checks once all
|
||||
// of them turn out to be live.
|
||||
unsigned NumLiveRetVals = 0;
|
||||
|
||||
bool HasMustTailCallers = false;
|
||||
|
||||
// Loop all uses of the function.
|
||||
for (const Use &U : F.uses()) {
|
||||
// If the function is PASSED IN as an argument, its address has been
|
||||
@@ -536,6 +553,11 @@ void DeadArgumentEliminationPass::SurveyFunction(const Function &F) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The number of arguments for `musttail` call must match the number of
|
||||
// arguments of the caller
|
||||
if (CS.isMustTailCall())
|
||||
HasMustTailCallers = true;
|
||||
|
||||
// If this use is anything other than a call site, the function is alive.
|
||||
const Instruction *TheCall = CS.getInstruction();
|
||||
if (!TheCall) { // Not a direct call site?
|
||||
@@ -580,6 +602,11 @@ void DeadArgumentEliminationPass::SurveyFunction(const Function &F) {
|
||||
}
|
||||
}
|
||||
|
||||
if (HasMustTailCallers) {
|
||||
DEBUG(dbgs() << "DeadArgumentEliminationPass - " << F.getName()
|
||||
<< " has musttail callers\n");
|
||||
}
|
||||
|
||||
// Now we've inspected all callers, record the liveness of our return values.
|
||||
for (unsigned i = 0; i != RetCount; ++i)
|
||||
MarkValue(CreateRet(&F, i), RetValLiveness[i], MaybeLiveRetUses[i]);
|
||||
@@ -593,12 +620,19 @@ void DeadArgumentEliminationPass::SurveyFunction(const Function &F) {
|
||||
for (Function::const_arg_iterator AI = F.arg_begin(),
|
||||
E = F.arg_end(); AI != E; ++AI, ++i) {
|
||||
Liveness Result;
|
||||
if (F.getFunctionType()->isVarArg()) {
|
||||
if (F.getFunctionType()->isVarArg() || HasMustTailCallers ||
|
||||
HasMustTailCalls) {
|
||||
// Variadic functions will already have a va_arg function expanded inside
|
||||
// them, making them potentially very sensitive to ABI changes resulting
|
||||
// from removing arguments entirely, so don't. For example AArch64 handles
|
||||
// register and stack HFAs very differently, and this is reflected in the
|
||||
// IR which has already been generated.
|
||||
//
|
||||
// `musttail` calls to this function restrict argument removal attempts.
|
||||
// The signature of the caller must match the signature of the function.
|
||||
//
|
||||
// `musttail` calls in this function prevents us from changing its
|
||||
// signature
|
||||
Result = Live;
|
||||
} else {
|
||||
// See what the effect of this use is (recording any uses that cause
|
||||
|
||||
16
llvm/test/Transforms/DeadArgElim/musttail-caller.ll
Normal file
16
llvm/test/Transforms/DeadArgElim/musttail-caller.ll
Normal file
@@ -0,0 +1,16 @@
|
||||
; RUN: opt -deadargelim -S < %s | FileCheck %s
|
||||
; PR36441
|
||||
; Dead arguments should not be removed in presence of `musttail` calls.
|
||||
|
||||
; CHECK-LABEL: define internal void @test(i32 %a, i32 %b)
|
||||
; CHECK: musttail call void @foo(i32 %a, i32 0)
|
||||
; FIXME: we should replace those with `undef`s
|
||||
define internal void @test(i32 %a, i32 %b) {
|
||||
musttail call void @foo(i32 %a, i32 0)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define internal void @foo(i32 %a, i32 %b)
|
||||
define internal void @foo(i32 %a, i32 %b) {
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user