21#define GEN_PASS_DEF_AMDGPUEMULATEATOMICSPASS
22#include "mlir/Dialect/AMDGPU/Transforms/Passes.h.inc"
29struct AmdgpuEmulateAtomicsPass
31 AmdgpuEmulateAtomicsPass> {
34 void runOnOperation()
override;
37template <
typename AtomicOp,
typename ArithOp>
38struct RawBufferAtomicByCasPattern :
public OpConversionPattern<AtomicOp> {
39 using OpConversionPattern<AtomicOp>::OpConversionPattern;
40 using Adaptor =
typename AtomicOp::Adaptor;
43 matchAndRewrite(AtomicOp atomicOp, Adaptor adaptor,
44 ConversionPatternRewriter &rewriter)
const override;
49enum class DataArgAction :
unsigned char {
62 DataArgAction action) {
63 newAttrs.reserve(attrs.size());
65 if (attr.getName().getValue() !=
"operandSegmentSizes") {
66 newAttrs.push_back(attr);
69 auto segmentAttr = cast<DenseI32ArrayAttr>(attr.getValue());
73 case DataArgAction::Drop:
75 context, segmentAttr.asArrayRef().drop_front());
77 case DataArgAction::Duplicate: {
80 newVals.push_back(oldVals[0]);
81 newVals.append(oldVals.begin(), oldVals.end());
90template <
typename OpTy>
91static typename OpTy::Properties
94 typename OpTy::Properties properties{};
95 OpTy::populateDefaultProperties(
100 [&]() { return emitError(loc); });
101 assert(succeeded(
result) &&
"failed to convert operation properties");
110 auto vectorType = dyn_cast<VectorType>(val.
getType());
115 vectorType.getElementTypeBitWidth() * vectorType.getNumElements();
116 Type allBitsType = rewriter.getIntegerType(bitwidth);
117 auto allBitsVecType = VectorType::get({1}, allBitsType);
118 Value bitcast = vector::BitCastOp::create(rewriter, loc, allBitsVecType, val);
119 Value scalar = vector::ExtractOp::create(rewriter, loc, bitcast, 0);
123template <
typename AtomicOp,
typename ArithOp>
124LogicalResult RawBufferAtomicByCasPattern<AtomicOp, ArithOp>::matchAndRewrite(
125 AtomicOp atomicOp, Adaptor adaptor,
126 ConversionPatternRewriter &rewriter)
const {
130 atomicOp->getName().walkInherentAttrs(atomicOp,
132 origProperties.
append(name, attr);
135 atomicOp->getDiscardableAttrDictionary().getValue();
137 Value data = operands.take_front()[0];
138 ValueRange invariantArgs = operands.drop_front();
143 auto loadProperties =
146 RawBufferLoadOp::create(rewriter, loc,
TypeRange{dataType}, invariantArgs,
147 loadProperties, discardableAttrs);
148 Block *currentBlock = rewriter.getInsertionBlock();
150 rewriter.splitBlock(currentBlock, rewriter.getInsertionPoint());
152 Block *loopBlock = rewriter.createBlock(afterAtomic, {dataType}, {loc});
154 rewriter.setInsertionPointToEnd(currentBlock);
155 cf::BranchOp::create(rewriter, loc, loopBlock, initialLoad);
157 rewriter.setInsertionPointToEnd(loopBlock);
159 Value operated = ArithOp::create(rewriter, loc, data, prevLoad);
164 DataArgAction::Duplicate);
166 cmpswapArgs.append(invariantArgs.begin(), invariantArgs.end());
168 rewriter, loc, cmpswapAttrs);
169 Value atomicRes = RawBufferAtomicCmpswapOp::create(
170 rewriter, loc,
TypeRange{dataType}, cmpswapArgs, cmpswapProperties,
180 if (
auto floatDataTy = dyn_cast<FloatType>(dataType)) {
181 Type equivInt = rewriter.getIntegerType(floatDataTy.getWidth());
183 arith::BitcastOp::create(rewriter, loc, equivInt, prevLoad);
184 atomicResForCompare =
185 arith::BitcastOp::create(rewriter, loc, equivInt, atomicRes);
188 arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::eq,
189 atomicResForCompare, prevLoadForCompare);
190 cf::CondBranchOp::create(rewriter, loc, canLeave, afterAtomic,
199 RawBufferAtomicFaddOp op) {
200 namespace AMDGPU = ::llvm::AMDGPU;
204 bool hasFadd =
target.has(AMDGPU::FEAT_ATOMIC_FADD_RTN_INSTS) ||
205 (
target.has(AMDGPU::FEAT_ATOMIC_FADD_NO_RTN_INSTS) &&
206 op.getOldValue().use_empty());
212 if (isa<Float16Type>(elemType))
213 return target.has(AMDGPU::FEAT_ATOMIC_BUFFER_GLOBAL_PK_ADD_F16_INSTS);
214 if (isa<BFloat16Type>(elemType))
215 return target.has(AMDGPU::FEAT_ATOMIC_BUFFER_PK_ADD_BF16_INST);
222 namespace AMDGPU = ::llvm::AMDGPU;
224 target.addDynamicallyLegalOp<RawBufferAtomicFaddOp>(
225 [targetInfo](RawBufferAtomicFaddOp op) ->
bool {
233 target.addDynamicallyLegalOp<RawBufferAtomicFmaxOp>(
234 [targetInfo](RawBufferAtomicFmaxOp op) ->
bool {
235 return op.getValue().getType().isF64() &&
236 targetInfo.
has(AMDGPU::FEAT_ATOMIC_FMIN_FMAX_GLOBAL_F64);
240 RawBufferAtomicByCasPattern<RawBufferAtomicFaddOp, arith::AddFOp>,
241 RawBufferAtomicByCasPattern<RawBufferAtomicFmaxOp, arith::MaximumFOp>,
242 RawBufferAtomicByCasPattern<RawBufferAtomicSmaxOp, arith::MaxSIOp>,
243 RawBufferAtomicByCasPattern<RawBufferAtomicUminOp, arith::MinUIOp>>(
247void AmdgpuEmulateAtomicsPass::runOnOperation() {
249 FailureOr<ROCDL::TargetInfo> targetInfo =
252 if (failed(targetInfo))
253 return signalPassFailure();
258 target.markUnknownOpDynamicallyLegal(
259 [](
Operation *op) ->
bool {
return true; });
262 if (
failed(applyPartialConversion(op,
target, std::move(patterns))))
263 return signalPassFailure();
static Value flattenVecToBits(ConversionPatternRewriter &rewriter, Location loc, Value val)
static bool isFaddNativelySupported(const ROCDL::TargetInfo &target, RawBufferAtomicFaddOp op)
Returns whether op can be lowered to a native buffer atomic fadd on target.
static OpTy::Properties getPropertiesFromAttrs(OpBuilder &builder, Location loc, ArrayRef< NamedAttribute > attrs)
static void patchOperandSegmentSizes(ArrayRef< NamedAttribute > attrs, SmallVectorImpl< NamedAttribute > &newAttrs, DataArgAction action)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
MLIRContext * getContext() const
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttribute represents a combination of a name and an Attribute value.
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
Describes the AMDGPU target a lowering is producing code for: the triple's subarch (which identifies ...
bool has(Feature feature) const
Returns whether the target has feature.
bool isGeneration(unsigned major) const
Returns whether the target belongs to gfx generation major (9 for any gfx9xx, 12 for any gfx12xx,...
static FailureOr< TargetInfo > get(StringRef arch, unsigned waveSize=0, function_ref< InFlightDiagnostic()> emitError=nullptr)
Resolves a target description.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
StringRef resolveArchOption(StringRef arch, StringRef deprecatedAlias)
Returns the target architecture that a pass should parse, given its arch option and the value of the ...
void populateAmdgpuEmulateAtomicsPatterns(ConversionTarget &target, RewritePatternSet &patterns, const ROCDL::TargetInfo &targetInfo, PatternBenefit benefit=1)
Include the generated interface declarations.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr