LLVM 23.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;
17using namespace PatternMatch;
18
19/// Return true if and only if the given instruction does not modify the memory
20/// location referenced. Note that an idemptent atomicrmw may still have
21/// ordering effects on nearby instructions, or be volatile.
22/// TODO: Common w/ the version in AtomicExpandPass, and change the term used.
23/// Idemptotent is confusing in this context.
24static bool isIdempotentRMW(AtomicRMWInst &RMWI) {
25 if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
26 switch(RMWI.getOperation()) {
27 case AtomicRMWInst::FAdd: // -0.0
28 return CF->isZero() && CF->isNegative();
29 case AtomicRMWInst::FSub: // +0.0
30 return CF->isZero() && !CF->isNegative();
31 default:
32 return false;
33 };
34
36 if(!C)
37 return false;
38
39 switch(RMWI.getOperation()) {
44 return C->isZero();
46 return C->isMinusOne();
48 return C->isMaxValue(true);
50 return C->isMinValue(true);
52 return C->isMaxValue(false);
54 return C->isMinValue(false);
55 default:
56 return false;
57 }
58}
59
60/// Return true if the given instruction always produces a value in memory
61/// equivalent to its value operand.
62static bool isSaturating(AtomicRMWInst &RMWI) {
63 if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
64 switch (RMWI.getOperation()) {
66 // maxnum(x, +inf) -> +inf
67 return !CF->isNegative() && CF->isInfinity();
69 // minnum(x, -inf) -> +inf
70 return CF->isNegative() && CF->isInfinity();
73 return CF->isNaN();
74 default:
75 return false;
76 };
77
79 if(!C)
80 return false;
81
82 switch(RMWI.getOperation()) {
83 default:
84 return false;
86 return true;
88 return C->isAllOnesValue();
90 return C->isZero();
92 return C->isMinValue(true);
94 return C->isMaxValue(true);
96 return C->isMinValue(false);
98 return C->isMaxValue(false);
99 };
100}
101
103
104 // Volatile RMWs perform a load and a store, we cannot replace this by just a
105 // load or just a store. We chose not to canonicalize out of general paranoia
106 // about user expectations around volatile.
107 if (RMWI.isVolatile())
108 return nullptr;
109
110 // Any atomicrmw op which produces a known result in memory can be
111 // replaced w/an atomicrmw xchg.
112 if (isSaturating(RMWI) &&
115 return &RMWI;
116 }
117
120 "AtomicRMWs don't make sense with Unordered or NotAtomic");
121
122 // Canonicalize atomicrmw add(ptr, neg(X)) -> atomicrmw sub(ptr, X)
123 // atomicrmw sub(ptr, neg(X)) -> atomicrmw add(ptr, X)
124 // old + (-X) == old - X and old - (-X) == old + X; the returned old value
125 // is identical in both cases. We match strictly on `sub 0, X` (negation) to
126 // avoid infinite loops: a general negation of `sub A, B` yields `sub B, A`,
127 // which would infinitely be negated back on the next iteration.
128 auto Op = RMWI.getOperation();
130 Value *Val = RMWI.getValOperand();
131 Value *X;
132 if (match(Val, m_Neg(m_Value(X)))) {
135 return replaceOperand(RMWI, 1, X);
136 }
137 }
138
139 if (!isIdempotentRMW(RMWI))
140 return nullptr;
141
142 // We chose to canonicalize all idempotent operations to an single
143 // operation code and constant. This makes it easier for the rest of the
144 // optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are
145 // arbitrary.
146 if (RMWI.getType()->isIntegerTy() &&
149 return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), 0));
150 } else if (RMWI.getType()->isFloatingPointTy() &&
153 return replaceOperand(RMWI, 1, ConstantFP::getNegativeZero(RMWI.getType()));
154 }
155
156 return nullptr;
157}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define X(NUM, ENUM, NAME)
Definition ELF.h:849
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:458
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:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
LLVM Value Representation.
Definition Value.h:75
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
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
bool match(Val *V, const Pattern &P)
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
DWARFExpression::Operation Op