Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -6818,7 +6818,7 @@ The argument to the '``fneg``' instruction must be a :ref:`floating-point ` or :ref:`vector ` of -floating-point values. +floating-point values. Semantics: """""""""" @@ -8430,15 +8430,17 @@ - min - umax - umin +- fadd +- fsub 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 xchg, this may also be a floating point type with the same size constraints as -integers. 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 `. +integers. For fadd/fsub, 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 A ``atomicrmw`` instruction can also take an optional ":ref:`syncscope `" argument. @@ -8464,6 +8466,8 @@ comparison) - umin: ``*ptr = *ptr < val ? *ptr : val`` (using an unsigned comparison) +- fadd: ``*ptr = *ptr + val`` (using floating point rules) +- fsub: ``*ptr = *ptr - val`` (using floating point rules) Example: """""""" @@ -14765,13 +14769,13 @@ Overview: """"""""" -The '``llvm.experimental.constrained.maxnum``' intrinsic returns the maximum +The '``llvm.experimental.constrained.maxnum``' intrinsic returns the maximum of the two arguments. Arguments: """""""""" -The first two arguments and the return value are floating-point numbers +The first two arguments and the return value are floating-point numbers of the same type. The third and forth arguments specify the rounding mode and exception @@ -14839,7 +14843,7 @@ Overview: """"""""" -The '``llvm.experimental.constrained.ceil``' intrinsic returns the ceiling of the +The '``llvm.experimental.constrained.ceil``' intrinsic returns the ceiling of the first operand. Arguments: @@ -14875,7 +14879,7 @@ Overview: """"""""" -The '``llvm.experimental.constrained.floor``' intrinsic returns the floor of the +The '``llvm.experimental.constrained.floor``' intrinsic returns the floor of the first operand. Arguments: @@ -14892,7 +14896,7 @@ """""""""" This function returns the same values as the libm ``floor`` functions -would and handles error conditions in the same way. +would and handles error conditions in the same way. '``llvm.experimental.constrained.round``' Intrinsic @@ -14911,7 +14915,7 @@ Overview: """"""""" -The '``llvm.experimental.constrained.round``' intrinsic returns the first +The '``llvm.experimental.constrained.round``' intrinsic returns the first operand rounded to the nearest integer. Arguments: @@ -14947,8 +14951,8 @@ Overview: """"""""" -The '``llvm.experimental.constrained.trunc``' intrinsic returns the first -operand rounded to the nearest integer not larger in magnitude than the +The '``llvm.experimental.constrained.trunc``' intrinsic returns the first +operand rounded to the nearest integer not larger in magnitude than the operand. Arguments: Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -407,7 +407,9 @@ RMW_MAX = 7, RMW_MIN = 8, RMW_UMAX = 9, - RMW_UMIN = 10 + RMW_UMIN = 10, + RMW_FADD = 11, + RMW_FSUB = 12 }; /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -714,8 +714,14 @@ /// *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 @@ -6816,6 +6816,7 @@ AtomicOrdering Ordering = AtomicOrdering::NotAtomic; SyncScope::ID SSID = SyncScope::System; bool isVolatile = false; + bool IsFP = false; AtomicRMWInst::BinOp Operation; if (EatIfPresent(lltok::kw_volatile)) @@ -6834,6 +6835,14 @@ 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; + case lltok::kw_fsub: + Operation = AtomicRMWInst::FSub; + IsFP = true; + break; } Lex.Lex(); // Eat the operation. @@ -6850,18 +6859,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 @@ -1035,6 +1035,8 @@ 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; + case bitc::RMW_FSUB: return AtomicRMWInst::FSub; } } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -560,6 +560,8 @@ 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; + case AtomicRMWInst::FSub: return bitc::RMW_FSUB; } } 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 @@ -1423,6 +1423,10 @@ return "umax"; case AtomicRMWInst::UMin: return "umin"; + case AtomicRMWInst::FAdd: + return "fadd"; + case AtomicRMWInst::FSub: + return "fsub"; case AtomicRMWInst::BAD_BINOP: return ""; } Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -3403,6 +3403,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/Assembler/invalid-atomicrmw-fsub-must-be-fp-type.ll =================================================================== --- /dev/null +++ test/Assembler/invalid-atomicrmw-fsub-must-be-fp-type.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s + +; CHECK: error: atomicrmw fsub operand must be a floating point type +define void @f(i32* %ptr) { + atomicrmw fsub i32* %ptr, i32 2 seq_cst + ret void +} Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -764,6 +764,13 @@ 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 + +; CHECK: %atomicrmw.fsub = atomicrmw fsub float* %word, float 1.000000e+00 monotonic + %atomicrmw.fsub = atomicrmw fsub float* %word, float 1.0 monotonic + ret void }