Skip to content

Commit

Permalink
[InstCombine] Extend "idempotent" atomicrmw optimizations to floating…
Browse files Browse the repository at this point in the history
… point

An idempotent atomicrmw is one that does not change memory in the process of execution.  We have already added handling for the various integer operations; this patch extends the same handling to floating point operations which were recently added to IR.

Note: At the moment, we canonicalize idempotent fsub to fadd when ordering requirements prevent us from using a load.  As discussed in the review, I will be replacing this with canonicalizing both floating point ops to integer ops in the near future.

Differential Revision: https://reviews.llvm.org/D58251

llvm-svn: 355210
  • Loading branch information
preames committed Mar 1, 2019
1 parent 39f6d7e commit 7798286
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
19 changes: 17 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp
Expand Up @@ -21,9 +21,18 @@ namespace {
/// TODO: Common w/ the version in AtomicExpandPass, and change the term used.
/// Idemptotent is confusing in this context.
bool isIdempotentRMW(AtomicRMWInst& RMWI) {
if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand()))
switch(RMWI.getOperation()) {
case AtomicRMWInst::FAdd: // -0.0
return CF->isZero() && CF->isNegative();
case AtomicRMWInst::FSub: // +0.0
return CF->isZero() && !CF->isNegative();
default:
return false;
};

auto C = dyn_cast<ConstantInt>(RMWI.getValOperand());
if(!C)
// TODO: Handle fadd, fsub?
return false;

switch(RMWI.getOperation()) {
Expand Down Expand Up @@ -116,12 +125,18 @@ Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) {

// We chose to canonicalize all idempotent operations to an single
// operation code and constant. This makes it easier for the rest of the
// optimizer to match easily. The choice of or w/zero is arbitrary.
// optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are
// arbitrary.
if (RMWI.getType()->isIntegerTy() &&
RMWI.getOperation() != AtomicRMWInst::Or) {
RMWI.setOperation(AtomicRMWInst::Or);
RMWI.setOperand(1, ConstantInt::get(RMWI.getType(), 0));
return &RMWI;
} else if (RMWI.getType()->isFloatingPointTy() &&
RMWI.getOperation() != AtomicRMWInst::FAdd) {
RMWI.setOperation(AtomicRMWInst::FAdd);
RMWI.setOperand(1, ConstantFP::getNegativeZero(RMWI.getType()));
return &RMWI;
}

// Check if the required ordering is compatible with an atomic load.
Expand Down
23 changes: 23 additions & 0 deletions llvm/test/Transforms/InstCombine/atomicrmw.ll
Expand Up @@ -67,6 +67,29 @@ define i8 @atomic_max_smin_char(i8* %addr) {
ret i8 %res
}

; CHECK-LABEL: atomic_fsub
; CHECK-NEXT: %res = load atomic float, float* %addr monotonic, align 4
; CHECK-NEXT: ret float %res
define float @atomic_fsub_zero(float* %addr) {
%res = atomicrmw fsub float* %addr, float 0.0 monotonic
ret float %res
}

; CHECK-LABEL: atomic_fadd
; CHECK-NEXT: %res = load atomic float, float* %addr monotonic, align 4
; CHECK-NEXT: ret float %res
define float @atomic_fadd_zero(float* %addr) {
%res = atomicrmw fadd float* %addr, float -0.0 monotonic
ret float %res
}

; CHECK-LABEL: atomic_fsub_canon
; CHECK-NEXT: %res = atomicrmw fadd float* %addr, float -0.000000e+00 release
; CHECK-NEXT: ret float %res
define float @atomic_fsub_canon(float* %addr) {
%res = atomicrmw fsub float* %addr, float 0.0 release
ret float %res
}

; Can't replace a volatile w/a load; this would eliminate a volatile store.
; CHECK-LABEL: atomic_sub_zero_volatile
Expand Down

0 comments on commit 7798286

Please sign in to comment.