Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -721,6 +721,12 @@ ATOMIC_BUILTIN(__opencl_atomic_fetch_min, "v.", "t") ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t") +// GCC does not support these, they are a Clang extension. +ATOMIC_BUILTIN(__atomic_fetch_min, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_max, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_umin, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_umax, "v.", "t") + #undef ATOMIC_BUILTIN // Non-overloaded atomic builtins. Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -4051,6 +4051,10 @@ case AO__atomic_or_fetch: case AO__atomic_xor_fetch: case AO__atomic_nand_fetch: + case AO__atomic_fetch_min: + case AO__atomic_fetch_max: + case AO__atomic_fetch_umin: + case AO__atomic_fetch_umax: return 3; case AO__opencl_atomic_store: Index: lib/CodeGen/CGAtomic.cpp =================================================================== --- lib/CodeGen/CGAtomic.cpp +++ lib/CodeGen/CGAtomic.cpp @@ -633,6 +633,18 @@ case AtomicExpr::AO__atomic_fetch_nand: Op = llvm::AtomicRMWInst::Nand; break; + case AtomicExpr::AO__atomic_fetch_min: + Op = llvm::AtomicRMWInst::Min; + break; + case AtomicExpr::AO__atomic_fetch_max: + Op = llvm::AtomicRMWInst::Max; + break; + case AtomicExpr::AO__atomic_fetch_umin: + Op = llvm::AtomicRMWInst::UMin; + break; + case AtomicExpr::AO__atomic_fetch_umax: + Op = llvm::AtomicRMWInst::UMax; + break; } llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1); @@ -859,6 +871,10 @@ case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_nand_fetch: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_umin: + case AtomicExpr::AO__atomic_fetch_umax: Val1 = EmitValToTemp(*this, E->getVal1()); break; } @@ -913,6 +929,10 @@ case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_sub_fetch: case AtomicExpr::AO__atomic_xor_fetch: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_umin: + case AtomicExpr::AO__atomic_fetch_umax: // For these, only library calls for certain sizes exist. UseOptimizedLibcall = true; break; @@ -1095,6 +1115,8 @@ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), MemTy, E->getExprLoc(), sizeChars); break; + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_umin: case AtomicExpr::AO__opencl_atomic_fetch_min: LibCallName = E->getValueType()->isSignedIntegerType() ? "__atomic_fetch_min" @@ -1102,6 +1124,8 @@ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), LoweredMemTy, E->getExprLoc(), sizeChars); break; + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_umax: case AtomicExpr::AO__opencl_atomic_fetch_max: LibCallName = E->getValueType()->isSignedIntegerType() ? "__atomic_fetch_max" Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -3037,6 +3037,7 @@ Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; + bool IsMinMax = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -3090,6 +3091,14 @@ Form = Arithmetic; break; + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_umin: + case AtomicExpr::AO__atomic_fetch_umax: + IsMinMax = true; + Form = Arithmetic; + break; + case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: @@ -3172,12 +3181,13 @@ // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // gcc does not enforce these rules for GNU atomics, but we do so for sanity. - if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { + if ((IsAddSub || IsMinMax) && !ValType->isIntegerType() + && !ValType->isPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (!IsAddSub && !ValType->isIntegerType()) { + if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); Index: test/Sema/atomic-ops.c =================================================================== --- test/Sema/atomic-ops.c +++ test/Sema/atomic-ops.c @@ -173,6 +173,7 @@ __atomic_fetch_sub(P, 3, memory_order_seq_cst); __atomic_fetch_sub(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} __atomic_fetch_sub(s1, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} + __atomic_fetch_min(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} __c11_atomic_fetch_and(i, 1, memory_order_seq_cst); __c11_atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}} @@ -456,6 +457,34 @@ (void)__atomic_fetch_nand(p, val, memory_order_acq_rel); (void)__atomic_fetch_nand(p, val, memory_order_seq_cst); + (void)__atomic_fetch_min(p, val, memory_order_relaxed); + (void)__atomic_fetch_min(p, val, memory_order_acquire); + (void)__atomic_fetch_min(p, val, memory_order_consume); + (void)__atomic_fetch_min(p, val, memory_order_release); + (void)__atomic_fetch_min(p, val, memory_order_acq_rel); + (void)__atomic_fetch_min(p, val, memory_order_seq_cst); + + (void)__atomic_fetch_max(p, val, memory_order_relaxed); + (void)__atomic_fetch_max(p, val, memory_order_acquire); + (void)__atomic_fetch_max(p, val, memory_order_consume); + (void)__atomic_fetch_max(p, val, memory_order_release); + (void)__atomic_fetch_max(p, val, memory_order_acq_rel); + (void)__atomic_fetch_max(p, val, memory_order_seq_cst); + + (void)__atomic_fetch_umin(p, val, memory_order_relaxed); + (void)__atomic_fetch_umin(p, val, memory_order_acquire); + (void)__atomic_fetch_umin(p, val, memory_order_consume); + (void)__atomic_fetch_umin(p, val, memory_order_release); + (void)__atomic_fetch_umin(p, val, memory_order_acq_rel); + (void)__atomic_fetch_umin(p, val, memory_order_seq_cst); + + (void)__atomic_fetch_umax(p, val, memory_order_relaxed); + (void)__atomic_fetch_umax(p, val, memory_order_acquire); + (void)__atomic_fetch_umax(p, val, memory_order_consume); + (void)__atomic_fetch_umax(p, val, memory_order_release); + (void)__atomic_fetch_umax(p, val, memory_order_acq_rel); + (void)__atomic_fetch_umax(p, val, memory_order_seq_cst); + (void)__atomic_and_fetch(p, val, memory_order_relaxed); (void)__atomic_and_fetch(p, val, memory_order_acquire); (void)__atomic_and_fetch(p, val, memory_order_consume);