InferAddressSpaces: Support atomics

llvm-svn: 293584
This commit is contained in:
Matt Arsenault 2017-01-31 01:40:38 +00:00
parent 6138cf87ce
commit 6c907a9bb3
3 changed files with 122 additions and 16 deletions

View File

@ -232,16 +232,25 @@ InferAddressSpaces::collectFlatAddressExpressions(Function &F) const {
std::vector<std::pair<Value*, bool>> PostorderStack;
// The set of visited expressions.
DenseSet<Value*> Visited;
auto PushPtrOperand = [&](Value *Ptr) {
appendsFlatAddressExpressionToPostorderStack(
Ptr, &PostorderStack, &Visited);
};
// We only explore address expressions that are reachable from loads and
// stores for now because we aim at generating faster loads and stores.
for (Instruction &I : instructions(F)) {
if (isa<LoadInst>(I)) {
appendsFlatAddressExpressionToPostorderStack(
I.getOperand(0), &PostorderStack, &Visited);
} else if (isa<StoreInst>(I)) {
appendsFlatAddressExpressionToPostorderStack(
I.getOperand(1), &PostorderStack, &Visited);
}
if (auto *LI = dyn_cast<LoadInst>(&I))
PushPtrOperand(LI->getPointerOperand());
else if (auto *SI = dyn_cast<StoreInst>(&I))
PushPtrOperand(SI->getPointerOperand());
else if (auto *RMW = dyn_cast<AtomicRMWInst>(&I))
PushPtrOperand(RMW->getPointerOperand());
else if (auto *CmpX = dyn_cast<AtomicCmpXchgInst>(&I))
PushPtrOperand(CmpX->getPointerOperand());
// TODO: Support intrinsics
}
std::vector<Value *> Postorder; // The resultant postorder.
@ -527,6 +536,30 @@ Optional<unsigned> InferAddressSpaces::updateAddressSpace(
return NewAS;
}
/// \p returns true if \p U is the pointer operand of a memory instruction with
/// a single pointer operand that can have its address space changed by simply
/// mutating the use to a new value.
static bool isSimplePointerUseValidToReplace(Use &U) {
User *Inst = U.getUser();
unsigned OpNo = U.getOperandNo();
if (auto *LI = dyn_cast<LoadInst>(Inst))
return OpNo == LoadInst::getPointerOperandIndex() && !LI->isVolatile();
if (auto *SI = dyn_cast<StoreInst>(Inst))
return OpNo == StoreInst::getPointerOperandIndex() && !SI->isVolatile();
if (auto *RMW = dyn_cast<AtomicRMWInst>(Inst))
return OpNo == AtomicRMWInst::getPointerOperandIndex() && !RMW->isVolatile();
if (auto *CmpX = dyn_cast<AtomicCmpXchgInst>(Inst)) {
return OpNo == AtomicCmpXchgInst::getPointerOperandIndex() &&
!CmpX->isVolatile();
}
return false;
}
bool InferAddressSpaces::rewriteWithNewAddressSpaces(
const std::vector<Value *> &Postorder,
const ValueToAddrSpaceMapTy &InferredAddrSpace, Function *F) const {
@ -570,15 +603,10 @@ bool InferAddressSpaces::rewriteWithNewAddressSpaces(
<< "\n with\n " << *NewV << '\n');
for (Use *U : Uses) {
LoadInst *LI = dyn_cast<LoadInst>(U->getUser());
StoreInst *SI = dyn_cast<StoreInst>(U->getUser());
if ((LI && !LI->isVolatile()) ||
(SI && !SI->isVolatile() &&
U->getOperandNo() == StoreInst::getPointerOperandIndex())) {
// If V is used as the pointer operand of a load/store, sets the pointer
// operand to NewV. This replacement does not change the element type,
// so the resultant load/store is still valid.
if (isSimplePointerUseValidToReplace(*U)) {
// If V is used as the pointer operand of a compatible memory operation,
// sets the pointer operand to NewV. This replacement does not change
// the element type, so the resultant load/store is still valid.
U->set(NewV);
} else if (isa<Instruction>(U->getUser())) {
// Otherwise, replaces the use with flat(NewV).

View File

@ -128,4 +128,46 @@ define void @store_addrspacecast_ptr_value(i32 addrspace(1)* nocapture %input, i
ret void
}
; CHECK-LABEL: @atomicrmw_add_global_to_flat(
; CHECK-NEXT: %ret = atomicrmw add i32 addrspace(1)* %global.ptr, i32 %y seq_cst
define i32 @atomicrmw_add_global_to_flat(i32 addrspace(1)* %global.ptr, i32 %y) #0 {
%cast = addrspacecast i32 addrspace(1)* %global.ptr to i32 addrspace(4)*
%ret = atomicrmw add i32 addrspace(4)* %cast, i32 %y seq_cst
ret i32 %ret
}
; CHECK-LABEL: @atomicrmw_add_group_to_flat(
; CHECK-NEXT: %ret = atomicrmw add i32 addrspace(3)* %group.ptr, i32 %y seq_cst
define i32 @atomicrmw_add_group_to_flat(i32 addrspace(3)* %group.ptr, i32 %y) #0 {
%cast = addrspacecast i32 addrspace(3)* %group.ptr to i32 addrspace(4)*
%ret = atomicrmw add i32 addrspace(4)* %cast, i32 %y seq_cst
ret i32 %ret
}
; CHECK-LABEL: @cmpxchg_global_to_flat(
; CHECK: %ret = cmpxchg i32 addrspace(1)* %global.ptr, i32 %cmp, i32 %val seq_cst monotonic
define { i32, i1 } @cmpxchg_global_to_flat(i32 addrspace(1)* %global.ptr, i32 %cmp, i32 %val) #0 {
%cast = addrspacecast i32 addrspace(1)* %global.ptr to i32 addrspace(4)*
%ret = cmpxchg i32 addrspace(4)* %cast, i32 %cmp, i32 %val seq_cst monotonic
ret { i32, i1 } %ret
}
; CHECK-LABEL: @cmpxchg_group_to_flat(
; CHECK: %ret = cmpxchg i32 addrspace(3)* %group.ptr, i32 %cmp, i32 %val seq_cst monotonic
define { i32, i1 } @cmpxchg_group_to_flat(i32 addrspace(3)* %group.ptr, i32 %cmp, i32 %val) #0 {
%cast = addrspacecast i32 addrspace(3)* %group.ptr to i32 addrspace(4)*
%ret = cmpxchg i32 addrspace(4)* %cast, i32 %cmp, i32 %val seq_cst monotonic
ret { i32, i1 } %ret
}
; Not pointer operand
; CHECK-LABEL: @cmpxchg_group_to_flat_wrong_operand(
; CHECK: %cast.cmp = addrspacecast i32 addrspace(3)* %cmp.ptr to i32 addrspace(4)*
; CHECK: %ret = cmpxchg i32 addrspace(4)* addrspace(3)* %cas.ptr, i32 addrspace(4)* %cast.cmp, i32 addrspace(4)* %val seq_cst monotonic
define { i32 addrspace(4)*, i1 } @cmpxchg_group_to_flat_wrong_operand(i32 addrspace(4)* addrspace(3)* %cas.ptr, i32 addrspace(3)* %cmp.ptr, i32 addrspace(4)* %val) #0 {
%cast.cmp = addrspacecast i32 addrspace(3)* %cmp.ptr to i32 addrspace(4)*
%ret = cmpxchg i32 addrspace(4)* addrspace(3)* %cas.ptr, i32 addrspace(4)* %cast.cmp, i32 addrspace(4)* %val seq_cst monotonic
ret { i32 addrspace(4)*, i1 } %ret
}
attributes #0 = { nounwind }

View File

@ -79,4 +79,40 @@ define void @volatile_store_flat_to_private(i32* nocapture %input, i32* nocaptur
ret void
}
; CHECK-LABEL: @volatile_atomicrmw_add_group_to_flat(
; CHECK: addrspacecast i32 addrspace(3)* %group.ptr to i32 addrspace(4)*
; CHECK: atomicrmw volatile add i32 addrspace(4)*
define i32 @volatile_atomicrmw_add_group_to_flat(i32 addrspace(3)* %group.ptr, i32 %y) #0 {
%cast = addrspacecast i32 addrspace(3)* %group.ptr to i32 addrspace(4)*
%ret = atomicrmw volatile add i32 addrspace(4)* %cast, i32 %y seq_cst
ret i32 %ret
}
; CHECK-LABEL: @volatile_atomicrmw_add_global_to_flat(
; CHECK: addrspacecast i32 addrspace(1)* %global.ptr to i32 addrspace(4)*
; CHECK: %ret = atomicrmw volatile add i32 addrspace(4)*
define i32 @volatile_atomicrmw_add_global_to_flat(i32 addrspace(1)* %global.ptr, i32 %y) #0 {
%cast = addrspacecast i32 addrspace(1)* %global.ptr to i32 addrspace(4)*
%ret = atomicrmw volatile add i32 addrspace(4)* %cast, i32 %y seq_cst
ret i32 %ret
}
; CHECK-LABEL: @volatile_cmpxchg_global_to_flat(
; CHECK: addrspacecast i32 addrspace(1)* %global.ptr to i32 addrspace(4)*
; CHECK: cmpxchg volatile i32 addrspace(4)*
define { i32, i1 } @volatile_cmpxchg_global_to_flat(i32 addrspace(1)* %global.ptr, i32 %cmp, i32 %val) #0 {
%cast = addrspacecast i32 addrspace(1)* %global.ptr to i32 addrspace(4)*
%ret = cmpxchg volatile i32 addrspace(4)* %cast, i32 %cmp, i32 %val seq_cst monotonic
ret { i32, i1 } %ret
}
; CHECK-LABEL: @volatile_cmpxchg_group_to_flat(
; CHECK: addrspacecast i32 addrspace(3)* %group.ptr to i32 addrspace(4)*
; CHECK: cmpxchg volatile i32 addrspace(4)*
define { i32, i1 } @volatile_cmpxchg_group_to_flat(i32 addrspace(3)* %group.ptr, i32 %cmp, i32 %val) #0 {
%cast = addrspacecast i32 addrspace(3)* %group.ptr to i32 addrspace(4)*
%ret = cmpxchg volatile i32 addrspace(4)* %cast, i32 %cmp, i32 %val seq_cst monotonic
ret { i32, i1 } %ret
}
attributes #0 = { nounwind }