LLVM 22.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"
15
16using namespace llvm;
17
18/// Return true if and only if the given instruction does not modify the memory
19/// location referenced. Note that an idemptent atomicrmw may still have
20/// ordering effects on nearby instructions, or be volatile.
21/// TODO: Common w/ the version in AtomicExpandPass, and change the term used.
22/// Idemptotent is confusing in this context.
23static bool isIdempotentRMW(AtomicRMWInst &RMWI) {
24 if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
25 switch(RMWI.getOperation()) {
26 case AtomicRMWInst::FAdd: // -0.0
27 return CF->isZero() && CF->isNegative();
28 case AtomicRMWInst::FSub: // +0.0
29 return CF->isZero() && !CF->isNegative();
30 default:
31 return false;
32 };
33
35 if(!C)
36 return false;
37
38 switch(RMWI.getOperation()) {
43 return C->isZero();
45 return C->isMinusOne();
47 return C->isMaxValue(true);
49 return C->isMinValue(true);
51 return C->isMaxValue(false);
53 return C->isMinValue(false);
54 default:
55 return false;
56 }
57}
58
59/// Return true if the given instruction always produces a value in memory
60/// equivalent to its value operand.
61static bool isSaturating(AtomicRMWInst &RMWI) {
62 if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
63 switch (RMWI.getOperation()) {
65 // maxnum(x, +inf) -> +inf
66 return !CF->isNegative() && CF->isInfinity();
68 // minnum(x, -inf) -> +inf
69 return CF->isNegative() && CF->isInfinity();
72 return CF->isNaN();
73 default:
74 return false;
75 };
76
78 if(!C)
79 return false;
80
81 switch(RMWI.getOperation()) {
82 default:
83 return false;
85 return true;
87 return C->isAllOnesValue();
89 return C->isZero();
91 return C->isMinValue(true);
93 return C->isMaxValue(true);
95 return C->isMinValue(false);
97 return C->isMaxValue(false);
98 };
99}
100
102
103 // Volatile RMWs perform a load and a store, we cannot replace this by just a
104 // load or just a store. We chose not to canonicalize out of general paranoia
105 // about user expectations around volatile.
106 if (RMWI.isVolatile())
107 return nullptr;
108
109 // Any atomicrmw op which produces a known result in memory can be
110 // replaced w/an atomicrmw xchg.
111 if (isSaturating(RMWI) &&
114 return &RMWI;
115 }
116
119 "AtomicRMWs don't make sense with Unordered or NotAtomic");
120
121 if (!isIdempotentRMW(RMWI))
122 return nullptr;
123
124 // We chose to canonicalize all idempotent operations to an single
125 // operation code and constant. This makes it easier for the rest of the
126 // optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are
127 // arbitrary.
128 if (RMWI.getType()->isIntegerTy() &&
131 return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), 0));
132 } else if (RMWI.getType()->isFloatingPointTy() &&
135 return replaceOperand(RMWI, 1, ConstantFP::getNegativeZero(RMWI.getType()));
136 }
137
138 return nullptr;
139}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isIdempotentRMW(AtomicRMWInst &RMWI)
Return true if and only if the given instruction does not modify the memory location referenced.
static bool isSaturating(AtomicRMWInst &RMWI)
Return true if the given instruction always produces a value in memory equivalent to its value operan...
This file provides internal interfaces used to implement the InstCombine.
an instruction that atomically reads a memory location, combines it with another value,...
bool isVolatile() const
Return true if this is a RMW on a volatile memory location.
@ Add
*p = old + v
@ FAdd
*p = old + v
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ FSub
*p = old - v
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ UMax
*p = old >unsigned v ? old : v
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
void setOperation(BinOp Operation)
BinOp getOperation() const
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
static Constant * getNegativeZero(Type *Ty)
Definition Constants.h:315
Instruction * visitAtomicRMWInst(AtomicRMWInst &SI)
Instruction * replaceOperand(Instruction &I, unsigned OpNum, Value *V)
Replace operand of instruction and add old operand to the worklist.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:184
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:240
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643