-
Notifications
You must be signed in to change notification settings - Fork 17.2k
[AArch64] Implement the atomic store with hint intrinsic #198316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |
| #include "clang/Sema/Initialization.h" | ||
| #include "clang/Sema/ParsedAttr.h" | ||
| #include "clang/Sema/Sema.h" | ||
| #include "llvm/Support/AArch64AtomicHints.h" | ||
|
|
||
| namespace clang { | ||
|
|
||
|
|
@@ -320,6 +321,94 @@ bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, | |
| return false; | ||
| } | ||
|
|
||
| bool SemaARM::BuiltinARMAtomicStoreHintCall(unsigned BuiltinID, | ||
| CallExpr *TheCall) { | ||
| if (SemaRef.checkArgCount(TheCall, 4)) | ||
| return true; | ||
|
|
||
| // Arg 0 should be the pointer type. The pointee type must be a | ||
| // scalar integral or floating-point type of 8, 16, 32 or 64 bits. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to allow vectors?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @efriedma-quic,
|
||
| ASTContext &Context = getASTContext(); | ||
| Expr *PtrArg = TheCall->getArg(0); | ||
| auto PtrArgRes = SemaRef.DefaultFunctionArrayLvalueConversion(PtrArg); | ||
| if (PtrArgRes.isInvalid()) | ||
| return true; | ||
| auto *PtrTy = PtrArg->getType()->getAs<PointerType>(); | ||
| if (!PtrTy) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_builtin_must_be_pointer) | ||
| << PtrArg->getType() << 0 << PtrArg->getSourceRange(); | ||
| QualType PtrQT = PtrTy->getPointeeType(); | ||
|
|
||
| // TODO: Allow MFloat8 types when supported by atomic store | ||
| if (!PtrQT->isIntegralType(getASTContext()) && !PtrQT->isFloatingType()) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_op_needs_atomic_int_or_fp) | ||
| << 0 << PtrQT << PtrArg->getSourceRange(); | ||
|
|
||
| unsigned TySize = | ||
| Context.getTypeSize(Context.getCanonicalType(PtrQT).getUnqualifiedType()); | ||
| if (TySize != 8 && TySize != 16 && TySize != 32 && TySize != 64) | ||
| return Diag(TheCall->getBeginLoc(), diag::err_atomic_op_hint_data_size) | ||
| << PtrArg->getSourceRange(); | ||
|
|
||
| // Arg 1 is the data to be stored. The type must match the pointee | ||
| // type found above. | ||
| auto DataArgRes = | ||
| SemaRef.DefaultFunctionArrayLvalueConversion(TheCall->getArg(1)); | ||
| if (DataArgRes.isInvalid()) | ||
| return true; | ||
| QualType DataQT = DataArgRes.get()->getType(); | ||
|
|
||
| if (PtrQT != DataQT) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_typecheck_call_different_arg_types) | ||
| << PtrQT << DataQT; | ||
|
|
||
| // Arg 2 is the memory order, which must be relaxed, release or seq_cst | ||
| auto MemOrdArg = | ||
| SemaRef.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2)).get(); | ||
| std::optional<llvm::APSInt> MemOrdAP = | ||
| MemOrdArg->getIntegerConstantExpr(Context); | ||
| if (!MemOrdAP) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_hint_has_invalid_memory_order) | ||
| << MemOrdArg->getType() << MemOrdArg->getSourceRange(); | ||
|
|
||
| unsigned Ordering = MemOrdAP->getZExtValue(); | ||
| if (!llvm::isValidAtomicOrderingCABI(Ordering)) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_hint_has_invalid_memory_order) | ||
| << *MemOrdAP << MemOrdArg->getSourceRange(); | ||
|
|
||
| auto AtomicOrdering = static_cast<llvm::AtomicOrderingCABI>(Ordering); | ||
| if (AtomicOrdering != llvm::AtomicOrderingCABI::relaxed && | ||
| AtomicOrdering != llvm::AtomicOrderingCABI::release && | ||
| AtomicOrdering != llvm::AtomicOrderingCABI::seq_cst) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_hint_has_invalid_memory_order) | ||
| << *MemOrdAP << MemOrdArg->getSourceRange(); | ||
|
|
||
| // Arg 3 is the hint type. Only values represented by AArch64AtomicStoreHint | ||
| // are valid. | ||
| auto HintArg = | ||
| SemaRef.DefaultFunctionArrayLvalueConversion(TheCall->getArg(3)).get(); | ||
| std::optional<llvm::APSInt> HintAP = HintArg->getIntegerConstantExpr(Context); | ||
| if (!HintAP) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_hint_has_invalid_hint_type) | ||
| << HintArg->getType() << HintArg->getSourceRange(); | ||
|
|
||
| unsigned Hint = HintAP->getZExtValue(); | ||
| if (llvm::getAtomicStoreHintFromMD(Hint) == | ||
| llvm::AArch64AtomicStoreHint::HINT_NONE) | ||
| return Diag(TheCall->getBeginLoc(), | ||
| diag::err_atomic_hint_has_invalid_hint_type) | ||
| << *HintAP << HintArg->getSourceRange(); | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /// getNeonEltType - Return the QualType corresponding to the elements of | ||
| /// the vector type specified by the NeonTypeFlags. This is used to check | ||
| /// the pointer arguments for Neon load/store intrinsics. | ||
|
|
@@ -1164,6 +1253,9 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, | |
| BuiltinID == AArch64::BI__builtin_arm_wsrp) | ||
| return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); | ||
|
|
||
| if (BuiltinID == AArch64::BI__builtin_arm_atomic_store_with_hint) | ||
| return BuiltinARMAtomicStoreHintCall(BuiltinID, TheCall); | ||
|
|
||
| // Only check the valid encoding range. Any constant in this range would be | ||
| // converted to a register of the form S2_2_C3_C4_5. Let the hardware throw | ||
| // an exception for incorrect registers. This matches MSVC behavior. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| //===-- AArch64AtomicHints.h - AArch64 Atomic Hint Attributes ---*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_SUPPORT_AARCH64ATOMICHINTS_H | ||
| #define LLVM_SUPPORT_AARCH64ATOMICHINTS_H | ||
|
|
||
| namespace llvm { | ||
| enum class AArch64AtomicStoreHint { | ||
| HINT_NONE = 0, | ||
| HINT_STSHH_KEEP = 1, | ||
| HINT_STSHH_STRM = 2, | ||
| }; | ||
|
|
||
| template <typename Int> inline bool isValidAArch64AtomicHintValue(Int I) { | ||
| return (Int)AArch64AtomicStoreHint::HINT_STSHH_KEEP <= I && | ||
| I <= (Int)AArch64AtomicStoreHint::HINT_STSHH_STRM; | ||
| } | ||
|
|
||
| template <typename Int> | ||
| inline AArch64AtomicStoreHint getAtomicStoreHintFromMD(Int I) { | ||
| switch (I) { | ||
| case 0: | ||
| return AArch64AtomicStoreHint::HINT_STSHH_KEEP; | ||
| case 1: | ||
| return AArch64AtomicStoreHint::HINT_STSHH_STRM; | ||
| default: | ||
| return AArch64AtomicStoreHint::HINT_NONE; | ||
| } | ||
| } | ||
| } // namespace llvm | ||
| #endif // LLVM_SUPPORT_AARCH64ATOMICHINTS_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any plan to allow specifying a hint for atomicrmw instructions, in addition to plain stores? Or is it not useful for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @efriedma-quic ,
This PR only covers the ACLE atomic-store-with-hint intrinsic.
There is separate ACLE PR#430 for FEAT_CMH that proposes atomic fetch operations with hints, such as fetch_add/fetch_sub/fetch_and/fetch_xor/fetch_or
I think those could map to atomicrmw, but this will be in a follow-up work, not as part of this store-only patch.