21#define GEN_PASS_DEF_AMDGPUEMULATEATOMICSPASS
22#include "mlir/Dialect/AMDGPU/Transforms/Passes.h.inc"
29struct AmdgpuEmulateAtomicsPass
30 :
public amdgpu::impl::AmdgpuEmulateAtomicsPassBase<
31 AmdgpuEmulateAtomicsPass> {
32 using AmdgpuEmulateAtomicsPassBase<
33 AmdgpuEmulateAtomicsPass>::AmdgpuEmulateAtomicsPassBase;
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,
201 target.addIllegalOp<RawBufferAtomicFaddOp>();
205 target.addDynamicallyLegalOp<RawBufferAtomicFaddOp>(
206 [](RawBufferAtomicFaddOp op) ->
bool {
208 return !isa<Float16Type, BFloat16Type>(elemType);
213 if (chipset >=
Chipset(9, 0, 0xa)) {
216 target.addDynamicallyLegalOp<RawBufferAtomicFmaxOp>(
217 [](RawBufferAtomicFmaxOp op) ->
bool {
218 return op.getValue().getType().isF64();
221 target.addIllegalOp<RawBufferAtomicFmaxOp>();
225 if (chipset <
Chipset(9, 5, 0)) {
226 target.addDynamicallyLegalOp<RawBufferAtomicFaddOp>(
227 [](RawBufferAtomicFaddOp op) ->
bool {
229 return !isa<BFloat16Type>(elemType);
234 RawBufferAtomicByCasPattern<RawBufferAtomicFaddOp, arith::AddFOp>,
235 RawBufferAtomicByCasPattern<RawBufferAtomicFmaxOp, arith::MaximumFOp>,
236 RawBufferAtomicByCasPattern<RawBufferAtomicSmaxOp, arith::MaxSIOp>,
237 RawBufferAtomicByCasPattern<RawBufferAtomicUminOp, arith::MinUIOp>>(
241void AmdgpuEmulateAtomicsPass::runOnOperation() {
244 if (failed(maybeChipset)) {
246 return signalPassFailure();
252 target.markUnknownOpDynamicallyLegal(
253 [](
Operation *op) ->
bool {
return true; });
256 if (
failed(applyPartialConversion(op,
target, std::move(patterns))))
257 return signalPassFailure();
static Value flattenVecToBits(ConversionPatternRewriter &rewriter, Location loc, Value val)
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.
Location getLoc()
The source location the operation was defined or derived from.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
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)
void populateAmdgpuEmulateAtomicsPatterns(ConversionTarget &target, RewritePatternSet &patterns, Chipset chipset, PatternBenefit benefit=1)
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
Represents the amdgpu gfx chipset version, e.g., gfx90a, gfx942, gfx1103.
static FailureOr< Chipset > parse(StringRef name)
Parses the chipset version string and returns the chipset on success, and failure otherwise.