Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp
35269 views
//===- InstCombineAtomicRMW.cpp -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the visit functions for atomic rmw instructions.9//10//===----------------------------------------------------------------------===//1112#include "InstCombineInternal.h"13#include "llvm/IR/Instructions.h"1415using namespace llvm;1617namespace {18/// Return true if and only if the given instruction does not modify the memory19/// location referenced. Note that an idemptent atomicrmw may still have20/// 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.23bool isIdempotentRMW(AtomicRMWInst& RMWI) {24if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))25switch(RMWI.getOperation()) {26case AtomicRMWInst::FAdd: // -0.027return CF->isZero() && CF->isNegative();28case AtomicRMWInst::FSub: // +0.029return CF->isZero() && !CF->isNegative();30default:31return false;32};3334auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());35if(!C)36return false;3738switch(RMWI.getOperation()) {39case AtomicRMWInst::Add:40case AtomicRMWInst::Sub:41case AtomicRMWInst::Or:42case AtomicRMWInst::Xor:43return C->isZero();44case AtomicRMWInst::And:45return C->isMinusOne();46case AtomicRMWInst::Min:47return C->isMaxValue(true);48case AtomicRMWInst::Max:49return C->isMinValue(true);50case AtomicRMWInst::UMin:51return C->isMaxValue(false);52case AtomicRMWInst::UMax:53return C->isMinValue(false);54default:55return false;56}57}5859/// Return true if the given instruction always produces a value in memory60/// equivalent to its value operand.61bool isSaturating(AtomicRMWInst& RMWI) {62if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))63switch (RMWI.getOperation()) {64case AtomicRMWInst::FMax:65// maxnum(x, +inf) -> +inf66return !CF->isNegative() && CF->isInfinity();67case AtomicRMWInst::FMin:68// minnum(x, -inf) -> +inf69return CF->isNegative() && CF->isInfinity();70case AtomicRMWInst::FAdd:71case AtomicRMWInst::FSub:72return CF->isNaN();73default:74return false;75};7677auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());78if(!C)79return false;8081switch(RMWI.getOperation()) {82default:83return false;84case AtomicRMWInst::Xchg:85return true;86case AtomicRMWInst::Or:87return C->isAllOnesValue();88case AtomicRMWInst::And:89return C->isZero();90case AtomicRMWInst::Min:91return C->isMinValue(true);92case AtomicRMWInst::Max:93return C->isMaxValue(true);94case AtomicRMWInst::UMin:95return C->isMinValue(false);96case AtomicRMWInst::UMax:97return C->isMaxValue(false);98};99}100} // namespace101102Instruction *InstCombinerImpl::visitAtomicRMWInst(AtomicRMWInst &RMWI) {103104// Volatile RMWs perform a load and a store, we cannot replace this by just a105// load or just a store. We chose not to canonicalize out of general paranoia106// about user expectations around volatile.107if (RMWI.isVolatile())108return nullptr;109110// Any atomicrmw op which produces a known result in memory can be111// replaced w/an atomicrmw xchg.112if (isSaturating(RMWI) &&113RMWI.getOperation() != AtomicRMWInst::Xchg) {114RMWI.setOperation(AtomicRMWInst::Xchg);115return &RMWI;116}117118assert(RMWI.getOrdering() != AtomicOrdering::NotAtomic &&119RMWI.getOrdering() != AtomicOrdering::Unordered &&120"AtomicRMWs don't make sense with Unordered or NotAtomic");121122if (!isIdempotentRMW(RMWI))123return nullptr;124125// We chose to canonicalize all idempotent operations to an single126// operation code and constant. This makes it easier for the rest of the127// optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are128// arbitrary.129if (RMWI.getType()->isIntegerTy() &&130RMWI.getOperation() != AtomicRMWInst::Or) {131RMWI.setOperation(AtomicRMWInst::Or);132return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), 0));133} else if (RMWI.getType()->isFloatingPointTy() &&134RMWI.getOperation() != AtomicRMWInst::FAdd) {135RMWI.setOperation(AtomicRMWInst::FAdd);136return replaceOperand(RMWI, 1, ConstantFP::getNegativeZero(RMWI.getType()));137}138139return nullptr;140}141142143