Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -8388,13 +8388,16 @@ - min - umax - umin +- fadd -The type of '' must be an integer type whose bit width is a power -of two greater than or equal to eight and less than or equal to a -target-specific size limit. The type of the '````' operand must -be a pointer to that type. If the ``atomicrmw`` is marked as -``volatile``, then the optimizer is not allowed to modify the number or -order of execution of this ``atomicrmw`` with other :ref:`volatile + +For most of these operations, the type of '' must be an integer +type whose bit width is a power of two greater than or equal to eight +and less than or equal to a target-specific size limit. For fadd, this +must be a floating point type. The type of the '````' operand +must be a pointer to that type. If the ``atomicrmw`` is marked as +``volatile``, then the optimizer is not allowed to modify the number +or order of execution of this ``atomicrmw`` with other :ref:`volatile operations `. A ``atomicrmw`` instruction can also take an optional @@ -8421,6 +8424,7 @@ comparison) - umin: ``*ptr = *ptr < val ? *ptr : val`` (using an unsigned comparison) +- fadd: ``*ptr = *ptr + val`` (using floating point rules) Example: """""""" Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -398,7 +398,8 @@ RMW_MAX = 7, RMW_MIN = 8, RMW_UMAX = 9, - RMW_UMIN = 10 + RMW_UMIN = 10, + RMW_FADD = 11 }; /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -714,8 +714,11 @@ /// *p = old getType()->getPointerAddressSpace(); } + bool isFloatingPointOperation() const { + return isFPOperation(getOperation()); + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Instruction *I) { return I->getOpcode() == Instruction::AtomicRMW; Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -6694,6 +6694,7 @@ AtomicOrdering Ordering = AtomicOrdering::NotAtomic; SyncScope::ID SSID = SyncScope::System; bool isVolatile = false; + bool IsFP = false; AtomicRMWInst::BinOp Operation; if (EatIfPresent(lltok::kw_volatile)) @@ -6712,6 +6713,10 @@ case lltok::kw_min: Operation = AtomicRMWInst::Min; break; case lltok::kw_umax: Operation = AtomicRMWInst::UMax; break; case lltok::kw_umin: Operation = AtomicRMWInst::UMin; break; + case lltok::kw_fadd: + Operation = AtomicRMWInst::FAdd; + IsFP = true; + break; } Lex.Lex(); // Eat the operation. @@ -6728,18 +6733,25 @@ if (cast(Ptr->getType())->getElementType() != Val->getType()) return Error(ValLoc, "atomicrmw value and pointer type do not match"); - if (Operation != AtomicRMWInst::Xchg && !Val->getType()->isIntegerTy()) { - return Error(ValLoc, "atomicrmw " + - AtomicRMWInst::getOperationName(Operation) + - " operand must be an integer"); - } - - if (Operation == AtomicRMWInst::Xchg && - !Val->getType()->isIntegerTy() && - !Val->getType()->isFloatingPointTy()) { - return Error(ValLoc, "atomicrmw " + - AtomicRMWInst::getOperationName(Operation) + - " operand must be an integer or floating point type"); + if (Operation == AtomicRMWInst::Xchg) { + if (!Val->getType()->isIntegerTy() && + !Val->getType()->isFloatingPointTy()) { + return Error(ValLoc, "atomicrmw " + + AtomicRMWInst::getOperationName(Operation) + + " operand must be an integer or floating point type"); + } + } else if (IsFP) { + if (!Val->getType()->isFloatingPointTy()) { + return Error(ValLoc, "atomicrmw " + + AtomicRMWInst::getOperationName(Operation) + + " operand must be a floating point type"); + } + } else { + if (!Val->getType()->isIntegerTy()) { + return Error(ValLoc, "atomicrmw " + + AtomicRMWInst::getOperationName(Operation) + + " operand must be an integer"); + } } unsigned Size = Val->getType()->getPrimitiveSizeInBits(); Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1015,6 +1015,7 @@ case bitc::RMW_MIN: return AtomicRMWInst::Min; case bitc::RMW_UMAX: return AtomicRMWInst::UMax; case bitc::RMW_UMIN: return AtomicRMWInst::UMin; + case bitc::RMW_FADD: return AtomicRMWInst::FAdd; } } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -551,6 +551,7 @@ case AtomicRMWInst::Min: return bitc::RMW_MIN; case AtomicRMWInst::UMax: return bitc::RMW_UMAX; case AtomicRMWInst::UMin: return bitc::RMW_UMIN; + case AtomicRMWInst::FAdd: return bitc::RMW_FADD; } } Index: lib/CodeGen/AtomicExpandPass.cpp =================================================================== --- lib/CodeGen/AtomicExpandPass.cpp +++ lib/CodeGen/AtomicExpandPass.cpp @@ -1519,6 +1519,8 @@ case AtomicRMWInst::UMin: // No atomic libcalls are available for max/min/umax/umin. return {}; + default: + llvm_unreachable("unhandled operation"); } llvm_unreachable("Unexpected AtomicRMW operation."); } Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -1354,6 +1354,8 @@ return "umax"; case AtomicRMWInst::UMin: return "umin"; + case AtomicRMWInst::FAdd: + return "fadd"; case AtomicRMWInst::BAD_BINOP: return ""; } Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -3368,6 +3368,11 @@ AtomicRMWInst::getOperationName(Op) + " operand must have integer or floating point type!", &RMWI, ElTy); + } else if (AtomicRMWInst::isFPOperation(Op)) { + Assert(ElTy->isFloatingPointTy(), "atomicrmw " + + AtomicRMWInst::getOperationName(Op) + + " operand must have floating point type!", + &RMWI, ElTy); } else { Assert(ElTy->isIntegerTy(), "atomicrmw " + AtomicRMWInst::getOperationName(Op) + Index: test/Assembler/atomic.ll =================================================================== --- test/Assembler/atomic.ll +++ test/Assembler/atomic.ll @@ -39,3 +39,13 @@ fence syncscope("device") seq_cst ret void } + +define void @fp_atomics(float* %x) { + ; CHECK: atomicrmw fadd float* %x, float 1.000000e+00 seq_cst + atomicrmw fadd float* %x, float 1.0 seq_cst + + ; CHECK: atomicrmw volatile fadd float* %x, float 1.000000e+00 seq_cst + atomicrmw volatile fadd float* %x, float 1.0 seq_cst + + ret void +} Index: test/Assembler/invalid-atomicrmw-fadd-must-be-fp-type.ll =================================================================== --- /dev/null +++ test/Assembler/invalid-atomicrmw-fadd-must-be-fp-type.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s + +; CHECK: error: atomicrmw fadd operand must be a floating point type +define void @f(i32* %ptr) { + atomicrmw fadd i32* %ptr, i32 2 seq_cst + ret void +} Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -764,6 +764,10 @@ define void @fp_atomics(float* %word) { ; CHECK: %atomicrmw.xchg = atomicrmw xchg float* %word, float 1.000000e+00 monotonic %atomicrmw.xchg = atomicrmw xchg float* %word, float 1.0 monotonic + +; CHECK: %atomicrmw.fadd = atomicrmw fadd float* %word, float 1.000000e+00 monotonic + %atomicrmw.fadd = atomicrmw fadd float* %word, float 1.0 monotonic + ret void }