xref: /llvm-project/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp (revision da6e9ef4cea9654d11ac07c0e3b93ac500d2291f)
196f54de8SQuentin Colombet //===- InstCombineAtomicRMW.cpp -------------------------------------------===//
296f54de8SQuentin Colombet //
396f54de8SQuentin Colombet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
496f54de8SQuentin Colombet // See https://llvm.org/LICENSE.txt for license information.
596f54de8SQuentin Colombet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
696f54de8SQuentin Colombet //
796f54de8SQuentin Colombet //===----------------------------------------------------------------------===//
896f54de8SQuentin Colombet //
996f54de8SQuentin Colombet // This file implements the visit functions for atomic rmw instructions.
1096f54de8SQuentin Colombet //
1196f54de8SQuentin Colombet //===----------------------------------------------------------------------===//
122a6c8715SSebastian Neubauer 
1396f54de8SQuentin Colombet #include "InstCombineInternal.h"
1496f54de8SQuentin Colombet #include "llvm/IR/Instructions.h"
1596f54de8SQuentin Colombet 
1696f54de8SQuentin Colombet using namespace llvm;
1796f54de8SQuentin Colombet 
1897067d3cSPhilip Reames namespace {
1997067d3cSPhilip Reames /// Return true if and only if the given instruction does not modify the memory
2097067d3cSPhilip Reames /// location referenced.  Note that an idemptent atomicrmw may still have
2197067d3cSPhilip Reames /// ordering effects on nearby instructions, or be volatile.
2297067d3cSPhilip Reames /// TODO: Common w/ the version in AtomicExpandPass, and change the term used.
2397067d3cSPhilip Reames /// Idemptotent is confusing in this context.
isIdempotentRMW(AtomicRMWInst & RMWI)2497067d3cSPhilip Reames bool isIdempotentRMW(AtomicRMWInst& RMWI) {
2577982868SPhilip Reames   if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
2677982868SPhilip Reames     switch(RMWI.getOperation()) {
2777982868SPhilip Reames     case AtomicRMWInst::FAdd: // -0.0
2877982868SPhilip Reames       return CF->isZero() && CF->isNegative();
2977982868SPhilip Reames     case AtomicRMWInst::FSub: // +0.0
3077982868SPhilip Reames       return CF->isZero() && !CF->isNegative();
3177982868SPhilip Reames     default:
3277982868SPhilip Reames       return false;
3377982868SPhilip Reames     };
3477982868SPhilip Reames 
3597067d3cSPhilip Reames   auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
3697067d3cSPhilip Reames   if(!C)
3797067d3cSPhilip Reames     return false;
3897067d3cSPhilip Reames 
398220ecbcSPhilip Reames   switch(RMWI.getOperation()) {
4096f54de8SQuentin Colombet     case AtomicRMWInst::Add:
4196f54de8SQuentin Colombet     case AtomicRMWInst::Sub:
4296f54de8SQuentin Colombet     case AtomicRMWInst::Or:
4397067d3cSPhilip Reames     case AtomicRMWInst::Xor:
4497067d3cSPhilip Reames       return C->isZero();
4597067d3cSPhilip Reames     case AtomicRMWInst::And:
4697067d3cSPhilip Reames       return C->isMinusOne();
4797067d3cSPhilip Reames     case AtomicRMWInst::Min:
4897067d3cSPhilip Reames       return C->isMaxValue(true);
4997067d3cSPhilip Reames     case AtomicRMWInst::Max:
5097067d3cSPhilip Reames       return C->isMinValue(true);
5197067d3cSPhilip Reames     case AtomicRMWInst::UMin:
5297067d3cSPhilip Reames       return C->isMaxValue(false);
5397067d3cSPhilip Reames     case AtomicRMWInst::UMax:
5497067d3cSPhilip Reames       return C->isMinValue(false);
5597067d3cSPhilip Reames     default:
5697067d3cSPhilip Reames       return false;
5797067d3cSPhilip Reames   }
5897067d3cSPhilip Reames }
59cae6c767SPhilip Reames 
60cae6c767SPhilip Reames /// Return true if the given instruction always produces a value in memory
61cf0a978eSPhilip Reames /// equivalent to its value operand.
isSaturating(AtomicRMWInst & RMWI)62cae6c767SPhilip Reames bool isSaturating(AtomicRMWInst& RMWI) {
63cf0a978eSPhilip Reames   if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
64cf0a978eSPhilip Reames     switch (RMWI.getOperation()) {
651023ddafSShilei Tian     case AtomicRMWInst::FMax:
661023ddafSShilei Tian       // maxnum(x, +inf) -> +inf
671023ddafSShilei Tian       return !CF->isNegative() && CF->isInfinity();
681023ddafSShilei Tian     case AtomicRMWInst::FMin:
691023ddafSShilei Tian       // minnum(x, -inf) -> +inf
701023ddafSShilei Tian       return CF->isNegative() && CF->isInfinity();
71cf0a978eSPhilip Reames     case AtomicRMWInst::FAdd:
72cf0a978eSPhilip Reames     case AtomicRMWInst::FSub:
73cf0a978eSPhilip Reames       return CF->isNaN();
74cf0a978eSPhilip Reames     default:
75cf0a978eSPhilip Reames       return false;
76cf0a978eSPhilip Reames     };
77cf0a978eSPhilip Reames 
78cae6c767SPhilip Reames   auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
79cae6c767SPhilip Reames   if(!C)
80cae6c767SPhilip Reames     return false;
81cae6c767SPhilip Reames 
828220ecbcSPhilip Reames   switch(RMWI.getOperation()) {
83cae6c767SPhilip Reames   default:
84cae6c767SPhilip Reames     return false;
858220ecbcSPhilip Reames   case AtomicRMWInst::Xchg:
868220ecbcSPhilip Reames     return true;
87cae6c767SPhilip Reames   case AtomicRMWInst::Or:
88cae6c767SPhilip Reames     return C->isAllOnesValue();
89cae6c767SPhilip Reames   case AtomicRMWInst::And:
90cae6c767SPhilip Reames     return C->isZero();
91cae6c767SPhilip Reames   case AtomicRMWInst::Min:
92cae6c767SPhilip Reames     return C->isMinValue(true);
93cae6c767SPhilip Reames   case AtomicRMWInst::Max:
94cae6c767SPhilip Reames     return C->isMaxValue(true);
95cae6c767SPhilip Reames   case AtomicRMWInst::UMin:
96cae6c767SPhilip Reames     return C->isMinValue(false);
97cae6c767SPhilip Reames   case AtomicRMWInst::UMax:
98cae6c767SPhilip Reames     return C->isMaxValue(false);
99cae6c767SPhilip Reames   };
100cae6c767SPhilip Reames }
10191589cf6SSimon Pilgrim } // namespace
10297067d3cSPhilip Reames 
visitAtomicRMWInst(AtomicRMWInst & RMWI)1032a6c8715SSebastian Neubauer Instruction *InstCombinerImpl::visitAtomicRMWInst(AtomicRMWInst &RMWI) {
10497067d3cSPhilip Reames 
10548547420SPhilip Reames   // Volatile RMWs perform a load and a store, we cannot replace this by just a
106cae6c767SPhilip Reames   // load or just a store. We chose not to canonicalize out of general paranoia
107cae6c767SPhilip Reames   // about user expectations around volatile.
10896f54de8SQuentin Colombet   if (RMWI.isVolatile())
10997067d3cSPhilip Reames     return nullptr;
11096f54de8SQuentin Colombet 
111cae6c767SPhilip Reames   // Any atomicrmw op which produces a known result in memory can be
112cae6c767SPhilip Reames   // replaced w/an atomicrmw xchg.
1138220ecbcSPhilip Reames   if (isSaturating(RMWI) &&
1148220ecbcSPhilip Reames       RMWI.getOperation() != AtomicRMWInst::Xchg) {
115cae6c767SPhilip Reames     RMWI.setOperation(AtomicRMWInst::Xchg);
116cae6c767SPhilip Reames     return &RMWI;
117cae6c767SPhilip Reames   }
118cae6c767SPhilip Reames 
119*da6e9ef4SBenjamin Kramer   assert(RMWI.getOrdering() != AtomicOrdering::NotAtomic &&
120*da6e9ef4SBenjamin Kramer          RMWI.getOrdering() != AtomicOrdering::Unordered &&
121cae6c767SPhilip Reames          "AtomicRMWs don't make sense with Unordered or NotAtomic");
122cae6c767SPhilip Reames 
123cae6c767SPhilip Reames   if (!isIdempotentRMW(RMWI))
124cae6c767SPhilip Reames     return nullptr;
125cae6c767SPhilip Reames 
12648547420SPhilip Reames   // We chose to canonicalize all idempotent operations to an single
12748547420SPhilip Reames   // operation code and constant.  This makes it easier for the rest of the
12877982868SPhilip Reames   // optimizer to match easily.  The choices of or w/0 and fadd w/-0.0 are
12977982868SPhilip Reames   // arbitrary.
13048547420SPhilip Reames   if (RMWI.getType()->isIntegerTy() &&
13148547420SPhilip Reames       RMWI.getOperation() != AtomicRMWInst::Or) {
13248547420SPhilip Reames     RMWI.setOperation(AtomicRMWInst::Or);
1335a8819b2SNikita Popov     return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), 0));
13477982868SPhilip Reames   } else if (RMWI.getType()->isFloatingPointTy() &&
13577982868SPhilip Reames              RMWI.getOperation() != AtomicRMWInst::FAdd) {
13677982868SPhilip Reames     RMWI.setOperation(AtomicRMWInst::FAdd);
1375a8819b2SNikita Popov     return replaceOperand(RMWI, 1, ConstantFP::getNegativeZero(RMWI.getType()));
13848547420SPhilip Reames   }
13948547420SPhilip Reames 
14097067d3cSPhilip Reames   return nullptr;
14196f54de8SQuentin Colombet }
142