[FunctionAttrs] Add handling for operand bundles
Summary: Teach the FunctionAttrs to do the right thing for IR with operand bundles. Reviewers: reames, chandlerc Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D14408 llvm-svn: 252387
This commit is contained in:
parent
436e2397f8
commit
71fe81fd25
|
@ -328,7 +328,21 @@ struct ArgumentUsesTracker : public CaptureTracker {
|
||||||
unsigned UseIndex =
|
unsigned UseIndex =
|
||||||
std::distance(const_cast<const Use *>(CS.arg_begin()), U);
|
std::distance(const_cast<const Use *>(CS.arg_begin()), U);
|
||||||
|
|
||||||
assert(UseIndex < CS.arg_size() && "Non-argument use?");
|
assert(UseIndex < CS.data_operands_size() &&
|
||||||
|
"Indirect function calls should have been filtered above!");
|
||||||
|
|
||||||
|
if (UseIndex >= CS.getNumArgOperands()) {
|
||||||
|
// Data operand, but not a argument operand -- must be a bundle operand
|
||||||
|
assert(CS.hasOperandBundles() && "Must be!");
|
||||||
|
|
||||||
|
// CaptureTracking told us that we're being captured by an operand bundle
|
||||||
|
// use. In this case it does not matter if the callee is within our SCC
|
||||||
|
// or not -- we've been captured in some unknown way, and we have to be
|
||||||
|
// conservative.
|
||||||
|
Captured = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (UseIndex >= F->arg_size()) {
|
if (UseIndex >= F->arg_size()) {
|
||||||
assert(F->isVarArg() && "More params than args in non-varargs call");
|
assert(F->isVarArg() && "More params than args in non-varargs call");
|
||||||
Captured = true;
|
Captured = true;
|
||||||
|
@ -443,14 +457,27 @@ determinePointerReadAttrs(Argument *A,
|
||||||
|
|
||||||
unsigned UseIndex = std::distance(CS.arg_begin(), U);
|
unsigned UseIndex = std::distance(CS.arg_begin(), U);
|
||||||
|
|
||||||
assert(UseIndex < CS.arg_size() && "Non-argument use?");
|
assert(UseIndex < CS.data_operands_size() && "Non-argument use?");
|
||||||
if (UseIndex >= F->arg_size()) {
|
|
||||||
|
bool IsOperandBundleUse = UseIndex >= CS.getNumArgOperands();
|
||||||
|
|
||||||
|
if (UseIndex >= F->arg_size() && !IsOperandBundleUse) {
|
||||||
assert(F->isVarArg() && "More params than args in non-varargs call");
|
assert(F->isVarArg() && "More params than args in non-varargs call");
|
||||||
return Attribute::None;
|
return Attribute::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Captures &= !CS.doesNotCapture(UseIndex);
|
Captures &= !CS.doesNotCapture(UseIndex);
|
||||||
if (!SCCNodes.count(std::next(F->arg_begin(), UseIndex))) {
|
|
||||||
|
// Since the optimizer (by design) cannot see the data flow corresponding
|
||||||
|
// to a operand bundle use, these cannot participate in the optimistic SCC
|
||||||
|
// analysis. Instead, we model the operand bundle uses as arguments in
|
||||||
|
// call to a function external to the SCC.
|
||||||
|
if (!SCCNodes.count(std::next(F->arg_begin(), UseIndex)) ||
|
||||||
|
IsOperandBundleUse) {
|
||||||
|
|
||||||
|
// The accessors used on CallSite here do the right thing for calls and
|
||||||
|
// invokes with operand bundles.
|
||||||
|
|
||||||
if (!CS.onlyReadsMemory() && !CS.onlyReadsMemory(UseIndex))
|
if (!CS.onlyReadsMemory() && !CS.onlyReadsMemory(UseIndex))
|
||||||
return Attribute::None;
|
return Attribute::None;
|
||||||
if (!CS.doesNotAccessMemory(UseIndex))
|
if (!CS.doesNotAccessMemory(UseIndex))
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
; RUN: opt -S -functionattrs < %s | FileCheck %s
|
||||||
|
|
||||||
|
declare void @f_readonly() readonly
|
||||||
|
declare void @f_readnone() readnone
|
||||||
|
|
||||||
|
define void @test_0(i32* %x) {
|
||||||
|
; FunctionAttrs must not infer readonly / readnone for %x
|
||||||
|
|
||||||
|
; CHECK-LABEL: define void @test_0(i32* %x) {
|
||||||
|
entry:
|
||||||
|
; CHECK: call void @f_readonly() [ "foo"(i32* %x) ]
|
||||||
|
call void @f_readonly() [ "foo"(i32* %x) ]
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @test_1(i32* %x) {
|
||||||
|
; FunctionAttrs must not infer readonly / readnone for %x
|
||||||
|
|
||||||
|
; CHECK-LABEL: define void @test_1(i32* %x) {
|
||||||
|
entry:
|
||||||
|
; CHECK: call void @f_readnone() [ "foo"(i32* %x) ]
|
||||||
|
call void @f_readnone() [ "foo"(i32* %x) ]
|
||||||
|
ret void
|
||||||
|
}
|
Loading…
Reference in New Issue