LLVM  14.0.0git
InstCombineAtomicRMW.cpp
Go to the documentation of this file.
1 //===- InstCombineAtomicRMW.cpp -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the visit functions for atomic rmw instructions.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "InstCombineInternal.h"
14 #include "llvm/IR/Instructions.h"
16 
17 using namespace llvm;
18 
19 namespace {
20 /// Return true if and only if the given instruction does not modify the memory
21 /// location referenced. Note that an idemptent atomicrmw may still have
22 /// ordering effects on nearby instructions, or be volatile.
23 /// TODO: Common w/ the version in AtomicExpandPass, and change the term used.
24 /// Idemptotent is confusing in this context.
25 bool isIdempotentRMW(AtomicRMWInst& RMWI) {
26  if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
27  switch(RMWI.getOperation()) {
28  case AtomicRMWInst::FAdd: // -0.0
29  return CF->isZero() && CF->isNegative();
30  case AtomicRMWInst::FSub: // +0.0
31  return CF->isZero() && !CF->isNegative();
32  default:
33  return false;
34  };
35 
36  auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
37  if(!C)
38  return false;
39 
40  switch(RMWI.getOperation()) {
41  case AtomicRMWInst::Add:
42  case AtomicRMWInst::Sub:
43  case AtomicRMWInst::Or:
44  case AtomicRMWInst::Xor:
45  return C->isZero();
46  case AtomicRMWInst::And:
47  return C->isMinusOne();
48  case AtomicRMWInst::Min:
49  return C->isMaxValue(true);
50  case AtomicRMWInst::Max:
51  return C->isMinValue(true);
53  return C->isMaxValue(false);
55  return C->isMinValue(false);
56  default:
57  return false;
58  }
59 }
60 
61 /// Return true if the given instruction always produces a value in memory
62 /// equivalent to its value operand.
63 bool isSaturating(AtomicRMWInst& RMWI) {
64  if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
65  switch(RMWI.getOperation()) {
68  return CF->isNaN();
69  default:
70  return false;
71  };
72 
73  auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
74  if(!C)
75  return false;
76 
77  switch(RMWI.getOperation()) {
78  default:
79  return false;
81  return true;
82  case AtomicRMWInst::Or:
83  return C->isAllOnesValue();
84  case AtomicRMWInst::And:
85  return C->isZero();
86  case AtomicRMWInst::Min:
87  return C->isMinValue(true);
88  case AtomicRMWInst::Max:
89  return C->isMaxValue(true);
91  return C->isMinValue(false);
93  return C->isMaxValue(false);
94  };
95 }
96 } // namespace
97 
99 
100  // Volatile RMWs perform a load and a store, we cannot replace this by just a
101  // load or just a store. We chose not to canonicalize out of general paranoia
102  // about user expectations around volatile.
103  if (RMWI.isVolatile())
104  return nullptr;
105 
106  // Any atomicrmw op which produces a known result in memory can be
107  // replaced w/an atomicrmw xchg.
108  if (isSaturating(RMWI) &&
109  RMWI.getOperation() != AtomicRMWInst::Xchg) {
111  return &RMWI;
112  }
113 
114  AtomicOrdering Ordering = RMWI.getOrdering();
115  assert(Ordering != AtomicOrdering::NotAtomic &&
116  Ordering != AtomicOrdering::Unordered &&
117  "AtomicRMWs don't make sense with Unordered or NotAtomic");
118 
119  // Any atomicrmw xchg with no uses can be converted to a atomic store if the
120  // ordering is compatible.
121  if (RMWI.getOperation() == AtomicRMWInst::Xchg &&
122  RMWI.use_empty()) {
123  if (Ordering != AtomicOrdering::Release &&
124  Ordering != AtomicOrdering::Monotonic)
125  return nullptr;
126  auto *SI = new StoreInst(RMWI.getValOperand(),
127  RMWI.getPointerOperand(), &RMWI);
128  SI->setAtomic(Ordering, RMWI.getSyncScopeID());
129  SI->setAlignment(DL.getABITypeAlign(RMWI.getType()));
130  return eraseInstFromFunction(RMWI);
131  }
132 
133  if (!isIdempotentRMW(RMWI))
134  return nullptr;
135 
136  // We chose to canonicalize all idempotent operations to an single
137  // operation code and constant. This makes it easier for the rest of the
138  // optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are
139  // arbitrary.
140  if (RMWI.getType()->isIntegerTy() &&
141  RMWI.getOperation() != AtomicRMWInst::Or) {
143  return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), 0));
144  } else if (RMWI.getType()->isFloatingPointTy() &&
145  RMWI.getOperation() != AtomicRMWInst::FAdd) {
147  return replaceOperand(RMWI, 1, ConstantFP::getNegativeZero(RMWI.getType()));
148  }
149 
150  // Check if the required ordering is compatible with an atomic load.
151  if (Ordering != AtomicOrdering::Acquire &&
152  Ordering != AtomicOrdering::Monotonic)
153  return nullptr;
154 
155  LoadInst *Load = new LoadInst(RMWI.getType(), RMWI.getPointerOperand(), "",
156  false, DL.getABITypeAlign(RMWI.getType()),
157  Ordering, RMWI.getSyncScopeID());
158  return Load;
159 }
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
llvm::AtomicRMWInst::setOperation
void setOperation(BinOp Operation)
Definition: Instructions.h:818
InstCombiner.h
llvm::AtomicRMWInst::Xor
@ Xor
*p = old ^ v
Definition: Instructions.h:752
llvm::AtomicRMWInst::getOperation
BinOp getOperation() const
Definition: Instructions.h:804
llvm::SPII::Load
@ Load
Definition: SparcInstrInfo.h:32
llvm::ConstantFP::getNegativeZero
static Constant * getNegativeZero(Type *Ty)
Definition: Constants.cpp:1046
llvm::Type::isFloatingPointTy
bool isFloatingPointTy() const
Return true if this is one of the six floating-point types.
Definition: Type.h:162
llvm::AtomicOrdering::Monotonic
@ Monotonic
llvm::InstCombinerImpl::visitAtomicRMWInst
Instruction * visitAtomicRMWInst(AtomicRMWInst &SI)
Definition: InstCombineAtomicRMW.cpp:98
llvm::AtomicRMWInst::getPointerOperand
Value * getPointerOperand()
Definition: Instructions.h:865
llvm::InstCombinerImpl::eraseInstFromFunction
Instruction * eraseInstFromFunction(Instruction &I) override
Combiner aware instruction erasure.
Definition: InstCombineInternal.h:447
InstCombineInternal.h
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::Instruction
Definition: Instruction.h:45
llvm::DataLayout::getABITypeAlign
Align getABITypeAlign(Type *Ty) const
Returns the minimum ABI-required alignment for the specified type.
Definition: DataLayout.cpp:826
llvm::AtomicOrdering::Acquire
@ Acquire
llvm::ConstantInt::get
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
Definition: Constants.cpp:925
llvm::AtomicRMWInst::Xchg
@ Xchg
*p = v
Definition: Instructions.h:740
llvm::AtomicRMWInst::Add
@ Add
*p = old + v
Definition: Instructions.h:742
llvm::Value::use_empty
bool use_empty() const
Definition: Value.h:345
llvm::Type::isIntegerTy
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:190
llvm::AtomicOrdering
AtomicOrdering
Atomic ordering for LLVM's memory model.
Definition: AtomicOrdering.h:56
llvm::AtomicRMWInst::UMin
@ UMin
*p = old <unsigned v ? old : v
Definition: Instructions.h:760
llvm::StoreInst
An instruction for storing to memory.
Definition: Instructions.h:304
llvm::AtomicRMWInst::Sub
@ Sub
*p = old - v
Definition: Instructions.h:744
llvm::AtomicRMWInst::getOrdering
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
Definition: Instructions.h:844
llvm::AtomicOrdering::Unordered
@ Unordered
llvm::AtomicRMWInst::Min
@ Min
*p = old <signed v ? old : v
Definition: Instructions.h:756
llvm::AtomicRMWInst::Or
@ Or
*p = old | v
Definition: Instructions.h:750
llvm::AtomicRMWInst::getSyncScopeID
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
Definition: Instructions.h:856
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SI
StandardInstrumentations SI(Debug, VerifyEach)
llvm::Value::getType
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:256
llvm::LoadInst
An instruction for reading from memory.
Definition: Instructions.h:175
llvm::AtomicRMWInst
an instruction that atomically reads a memory location, combines it with another value,...
Definition: Instructions.h:726
llvm::AtomicOrdering::Release
@ Release
llvm::AtomicRMWInst::isVolatile
bool isVolatile() const
Return true if this is a RMW on a volatile memory location.
Definition: Instructions.h:834
llvm::AtomicRMWInst::FSub
@ FSub
*p = old - v
Definition: Instructions.h:766
llvm::InstCombiner::DL
const DataLayout & DL
Definition: InstCombiner.h:71
llvm::AtomicRMWInst::And
@ And
*p = old & v
Definition: Instructions.h:746
llvm::AtomicRMWInst::getValOperand
Value * getValOperand()
Definition: Instructions.h:869
llvm::InstCombinerImpl::replaceOperand
Instruction * replaceOperand(Instruction &I, unsigned OpNum, Value *V)
Replace operand of instruction and add old operand to the worklist.
Definition: InstCombineInternal.h:420
Instructions.h
llvm::AtomicRMWInst::FAdd
@ FAdd
*p = old + v
Definition: Instructions.h:763
llvm::AtomicRMWInst::UMax
@ UMax
*p = old >unsigned v ? old : v
Definition: Instructions.h:758
llvm::AtomicOrdering::NotAtomic
@ NotAtomic
llvm::AtomicRMWInst::Max
@ Max
*p = old >signed v ? old : v
Definition: Instructions.h:754