InstCombineAtomicRMW.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. #include "InstCombineInternal.h"
  13. #include "llvm/IR/Instructions.h"
  14. #include "llvm/Transforms/InstCombine/InstCombiner.h"
  15. using namespace llvm;
  16. namespace {
  17. /// Return true if and only if the given instruction does not modify the memory
  18. /// location referenced. Note that an idemptent atomicrmw may still have
  19. /// ordering effects on nearby instructions, or be volatile.
  20. /// TODO: Common w/ the version in AtomicExpandPass, and change the term used.
  21. /// Idemptotent is confusing in this context.
  22. bool isIdempotentRMW(AtomicRMWInst& RMWI) {
  23. if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
  24. switch(RMWI.getOperation()) {
  25. case AtomicRMWInst::FAdd: // -0.0
  26. return CF->isZero() && CF->isNegative();
  27. case AtomicRMWInst::FSub: // +0.0
  28. return CF->isZero() && !CF->isNegative();
  29. default:
  30. return false;
  31. };
  32. auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
  33. if(!C)
  34. return false;
  35. switch(RMWI.getOperation()) {
  36. case AtomicRMWInst::Add:
  37. case AtomicRMWInst::Sub:
  38. case AtomicRMWInst::Or:
  39. case AtomicRMWInst::Xor:
  40. return C->isZero();
  41. case AtomicRMWInst::And:
  42. return C->isMinusOne();
  43. case AtomicRMWInst::Min:
  44. return C->isMaxValue(true);
  45. case AtomicRMWInst::Max:
  46. return C->isMinValue(true);
  47. case AtomicRMWInst::UMin:
  48. return C->isMaxValue(false);
  49. case AtomicRMWInst::UMax:
  50. return C->isMinValue(false);
  51. default:
  52. return false;
  53. }
  54. }
  55. /// Return true if the given instruction always produces a value in memory
  56. /// equivalent to its value operand.
  57. bool isSaturating(AtomicRMWInst& RMWI) {
  58. if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
  59. switch(RMWI.getOperation()) {
  60. case AtomicRMWInst::FAdd:
  61. case AtomicRMWInst::FSub:
  62. return CF->isNaN();
  63. default:
  64. return false;
  65. };
  66. auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
  67. if(!C)
  68. return false;
  69. switch(RMWI.getOperation()) {
  70. default:
  71. return false;
  72. case AtomicRMWInst::Xchg:
  73. return true;
  74. case AtomicRMWInst::Or:
  75. return C->isAllOnesValue();
  76. case AtomicRMWInst::And:
  77. return C->isZero();
  78. case AtomicRMWInst::Min:
  79. return C->isMinValue(true);
  80. case AtomicRMWInst::Max:
  81. return C->isMaxValue(true);
  82. case AtomicRMWInst::UMin:
  83. return C->isMinValue(false);
  84. case AtomicRMWInst::UMax:
  85. return C->isMaxValue(false);
  86. };
  87. }
  88. } // namespace
  89. Instruction *InstCombinerImpl::visitAtomicRMWInst(AtomicRMWInst &RMWI) {
  90. // Volatile RMWs perform a load and a store, we cannot replace this by just a
  91. // load or just a store. We chose not to canonicalize out of general paranoia
  92. // about user expectations around volatile.
  93. if (RMWI.isVolatile())
  94. return nullptr;
  95. // Any atomicrmw op which produces a known result in memory can be
  96. // replaced w/an atomicrmw xchg.
  97. if (isSaturating(RMWI) &&
  98. RMWI.getOperation() != AtomicRMWInst::Xchg) {
  99. RMWI.setOperation(AtomicRMWInst::Xchg);
  100. return &RMWI;
  101. }
  102. AtomicOrdering Ordering = RMWI.getOrdering();
  103. assert(Ordering != AtomicOrdering::NotAtomic &&
  104. Ordering != AtomicOrdering::Unordered &&
  105. "AtomicRMWs don't make sense with Unordered or NotAtomic");
  106. // Any atomicrmw xchg with no uses can be converted to a atomic store if the
  107. // ordering is compatible.
  108. if (RMWI.getOperation() == AtomicRMWInst::Xchg &&
  109. RMWI.use_empty()) {
  110. if (Ordering != AtomicOrdering::Release &&
  111. Ordering != AtomicOrdering::Monotonic)
  112. return nullptr;
  113. auto *SI = new StoreInst(RMWI.getValOperand(),
  114. RMWI.getPointerOperand(), &RMWI);
  115. SI->setAtomic(Ordering, RMWI.getSyncScopeID());
  116. SI->setAlignment(DL.getABITypeAlign(RMWI.getType()));
  117. return eraseInstFromFunction(RMWI);
  118. }
  119. if (!isIdempotentRMW(RMWI))
  120. return nullptr;
  121. // We chose to canonicalize all idempotent operations to an single
  122. // operation code and constant. This makes it easier for the rest of the
  123. // optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are
  124. // arbitrary.
  125. if (RMWI.getType()->isIntegerTy() &&
  126. RMWI.getOperation() != AtomicRMWInst::Or) {
  127. RMWI.setOperation(AtomicRMWInst::Or);
  128. return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), 0));
  129. } else if (RMWI.getType()->isFloatingPointTy() &&
  130. RMWI.getOperation() != AtomicRMWInst::FAdd) {
  131. RMWI.setOperation(AtomicRMWInst::FAdd);
  132. return replaceOperand(RMWI, 1, ConstantFP::getNegativeZero(RMWI.getType()));
  133. }
  134. // Check if the required ordering is compatible with an atomic load.
  135. if (Ordering != AtomicOrdering::Acquire &&
  136. Ordering != AtomicOrdering::Monotonic)
  137. return nullptr;
  138. LoadInst *Load = new LoadInst(RMWI.getType(), RMWI.getPointerOperand(), "",
  139. false, DL.getABITypeAlign(RMWI.getType()),
  140. Ordering, RMWI.getSyncScopeID());
  141. return Load;
  142. }