MLIR: lib/IR/OperationSupport.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

18 #include "llvm/ADT/BitVector.h"

19 #include "llvm/Support/SHA1.h"

20 #include

21 #include

22

23 using namespace mlir;

24

25

26

27

28

30 assign(attributes.begin(), attributes.end());

31 }

32

34 : NamedAttrList(attributes ? attributes.getValue()

36 dictionarySorted.setPointerAndInt(attributes, true);

37 }

38

40 assign(inStart, inEnd);

41 }

42

44

46 std::optional duplicate =

47 DictionaryAttr::findDuplicate(attrs, isSorted());

48

49

50 if (!isSorted())

51 dictionarySorted.setPointerAndInt(nullptr, true);

52 return duplicate;

53 }

54

56 if (!isSorted()) {

57 DictionaryAttr::sortInPlace(attrs);

58 dictionarySorted.setPointerAndInt(nullptr, true);

59 }

60 if (!dictionarySorted.getPointer())

61 dictionarySorted.setPointer(DictionaryAttr::getWithSorted(context, attrs));

62 return llvm::cast(dictionarySorted.getPointer());

63 }

64

65

68 dictionarySorted.setPointerAndInt(nullptr, true);

69 }

70

72 if (isSorted())

73 dictionarySorted.setInt(attrs.empty() || attrs.back() < newAttribute);

74 dictionarySorted.setPointer(nullptr);

75 attrs.push_back(newAttribute);

76 }

77

78

80 auto it = findAttr(*this, name);

81 return it.second ? it.first->getValue() : Attribute();

82 }

84 auto it = findAttr(*this, name);

85 return it.second ? it.first->getValue() : Attribute();

86 }

87

88

90 auto it = findAttr(*this, name);

91 return it.second ? *it.first : std::optional();

92 }

94 auto it = findAttr(*this, name);

95 return it.second ? *it.first : std::optional();

96 }

97

98

99

101 assert(value && "attributes may never be null");

102

103

104

105 auto it = findAttr(*this, name);

106 if (it.second) {

107

108

109 Attribute oldValue = it.first->getValue();

110 if (it.first->getValue() != value) {

111 it.first->setValue(value);

112

113

114 dictionarySorted.setPointer(nullptr);

115 }

116 return oldValue;

117 }

118

119

120 if (isSorted())

121 it = findAttr(*this, name.strref());

122 attrs.insert(it.first, {name, value});

123

124 dictionarySorted.setPointer(nullptr);

126 }

127

129 assert(value && "attributes may never be null");

131 }

132

135

137 attrs.erase(it);

138 dictionarySorted.setPointer(nullptr);

139 return attr;

140 }

141

143 auto it = findAttr(*this, name);

144 return it.second ? eraseImpl(it.first) : Attribute();

145 }

146

148 auto it = findAttr(*this, name);

149 return it.second ? eraseImpl(it.first) : Attribute();

150 }

151

154 assign(rhs.begin(), rhs.end());

155 return *this;

156 }

157

159

160

161

162

163

165 : location(location), name(name, location->getContext()) {}

166

168 : location(location), name(name) {}

169

175 : location(location), name(name),

176 operands(operands.begin(), operands.end()),

177 types(types.begin(), types.end()),

178 attributes(attributes.begin(), attributes.end()),

179 successors(successors.begin(), successors.end()) {

180 for (std::unique_ptr &r : regions)

181 this->regions.push_back(std::move(r));

182 }

189 operands, types, attributes, successors, regions) {}

190

192 if (properties)

193 propertiesDeleter(properties);

194 }

195

199 assert(!properties);

201 }

202 if (properties)

204 return success();

205 }

206

208 operands.append(newOperands.begin(), newOperands.end());

209 }

210

212 successors.append(newSuccessors.begin(), newSuccessors.end());

213 }

214

217 return regions.back().get();

218 }

219

221 regions.push_back(std::move(region));

222 }

223

226 for (std::unique_ptr &region : regions)

228 }

229

230

231

232

233

237 : isStorageDynamic(false), operandStorage(trailingOperands) {

238 numOperands = capacity = values.size();

239 for (unsigned i = 0; i < numOperands; ++i)

240 new (&operandStorage[i]) OpOperand(owner, values[i]);

241 }

242

244 for (auto &operand : getOperands())

245 operand.~OpOperand();

246

247

248 if (isStorageDynamic)

249 free(operandStorage);

250 }

251

252

253

256 for (unsigned i = 0, e = values.size(); i != e; ++i)

257 storageOperands[i].set(values[i]);

258 }

259

260

261

262

264 unsigned length, ValueRange operands) {

265

266 unsigned newSize = operands.size();

267 if (newSize == length) {

269 for (unsigned i = 0, e = length; i != e; ++i)

270 storageOperands[start + i].set(operands[i]);

271 return;

272 }

273

274

275 if (newSize < length) {

276 eraseOperands(start + operands.size(), length - newSize);

277 setOperands(owner, start, newSize, operands);

278 return;

279 }

280

281 auto storageOperands = resize(owner, size() + (newSize - length));

282

283

284 unsigned rotateSize = storageOperands.size() - (start + length);

285 auto rbegin = storageOperands.rbegin();

286 std::rotate(rbegin, std::next(rbegin, newSize - length), rbegin + rotateSize);

287

288

289 for (unsigned i = 0, e = operands.size(); i != e; ++i)

290 storageOperands[start + i].set(operands[i]);

291 }

292

293

296 assert((start + length) <= operands.size());

297 numOperands -= length;

298

299

300 if (start != numOperands) {

301 auto *indexIt = std::next(operands.begin(), start);

302 std::rotate(indexIt, std::next(indexIt, length), operands.end());

303 }

304 for (unsigned i = 0; i != length; ++i)

305 operands[numOperands + i].~OpOperand();

306 }

307

310 assert(eraseIndices.size() == operands.size());

311

312

313 int firstErasedIndice = eraseIndices.find_first();

314 if (firstErasedIndice == -1)

315 return;

316

317

318 numOperands = firstErasedIndice;

319 for (unsigned i = firstErasedIndice + 1, e = operands.size(); i < e; ++i)

320 if (!eraseIndices.test(i))

321 operands[numOperands++] = std::move(operands[i]);

322 for (OpOperand &operand : operands.drop_front(numOperands))

323 operand.~OpOperand();

324 }

325

326

327

329 unsigned newSize) {

330

331

333 if (newSize <= numOperands) {

334

335

336 for (unsigned i = newSize; i != numOperands; ++i)

338 numOperands = newSize;

339 return origOperands.take_front(newSize);

340 }

341

342

343 if (newSize <= capacity) {

344 OpOperand *opBegin = origOperands.data();

345 for (unsigned e = newSize; numOperands != e; ++numOperands)

346 new (&opBegin[numOperands]) OpOperand(owner);

348 }

349

350

351 unsigned newCapacity =

352 std::max(unsigned(llvm::NextPowerOf2(capacity + 2)), newSize);

354 reinterpret_cast<OpOperand *>(malloc(sizeof(OpOperand) * newCapacity));

355

356

358 std::uninitialized_move(origOperands.begin(), origOperands.end(),

359 newOperands.begin());

360

361

362 for (auto &operand : origOperands)

363 operand.~OpOperand();

364

365

366 for (unsigned e = newSize; numOperands != e; ++numOperands)

367 new (&newOperands[numOperands]) OpOperand(owner);

368

369

370 if (isStorageDynamic)

371 free(operandStorage);

372

373

374 operandStorage = newOperandStorage;

375 capacity = newCapacity;

376 isStorageDynamic = true;

377 return newOperands;

378 }

379

380

381

382

383

384

385

386

387

389 assert(!empty() && "range must not be empty");

390 return base->getOperandNumber();

391 }

392

395 }

396

397

398

399

400

405 }

406

408 const OwnerT &owner = getBase();

409 ArrayRef<int32_t> sizeData = llvm::cast(owner.second);

411 std::accumulate(sizeData.begin(), sizeData.end(), 0));

412 }

413

414 OperandRange OperandRangeRange::dereference(const OwnerT &object,

415 ptrdiff_t index) {

416 ArrayRef<int32_t> sizeData = llvm::cast(object.second);

417 uint32_t startIndex =

418 std::accumulate(sizeData.begin(), sizeData.begin() + index, 0);

419 return OperandRange(object.first + startIndex, *(sizeData.begin() + index));

420 }

421

422

423

424

425

426

427

429 Operation *owner, unsigned start, unsigned length,

431 : owner(owner), start(start), length(length),

432 operandSegments(operandSegments) {

433 assert((start + length) <= owner->getNumOperands() && "invalid range");

434 }

437

438

441 opOperand.getOperandNumber(),

442 1) {}

443

444

447 std::optional segment) const {

448 assert((subStart + subLen) <= length && "invalid sub-range");

450 operandSegments);

451 if (segment)

452 subSlice.operandSegments.push_back(*segment);

453 return subSlice;

454 }

455

456

458 if (values.empty())

459 return;

461 updateLength(length + values.size());

462 }

463

464

466 owner->setOperands(start, length, values);

467 if (length != values.size())

468 updateLength(values.size());

469 }

470

471

473 if (length == 1) {

475 } else {

476 owner->setOperands(start, length, value);

477 updateLength(1);

478 }

479 }

480

481

483 assert((subStart + subLen) <= length && "invalid sub-range");

484 if (length == 0)

485 return;

487 updateLength(length - subLen);

488 }

489

490

492 if (length != 0) {

494 updateLength(0);

495 }

496 }

497

498

500 return owner->getOperands().slice(start, length);

501 }

502

503

505 return getAsOperandRange();

506 }

507

509 return owner->getOpOperands().slice(start, length);

510 }

511

515 }

516

517

518 void MutableOperandRange::updateLength(unsigned newLength) {

519 int32_t diff = int32_t(newLength) - int32_t(length);

520 length = newLength;

521

522

524 auto attr = llvm::cast(segment.second.getValue());

526 segments[segment.first] += diff;

527 segment.second.setValue(

529 owner->setAttr(segment.second.getName(), segment.second.getValue());

530 }

531 }

532

534 assert(index < length && "index is out of bounds");

536 }

537

539 return owner->getOpOperands().slice(start, length).begin();

540 }

541

543 return owner->getOpOperands().slice(start, length).end();

544 }

545

546

547

548

549

553 OwnerT(operands, operandSegmentAttr), 0,

555 }

556

559 }

560

563 }

564

565 MutableOperandRange MutableOperandRangeRange::dereference(const OwnerT &object,

566 ptrdiff_t index) {

568 llvm::cast(object.second.getValue());

569 uint32_t startIndex =

570 std::accumulate(sizeData.begin(), sizeData.begin() + index, 0);

571 return object.first.slice(

572 startIndex, *(sizeData.begin() + index),

574 }

575

576

577

578

579

581 : ResultRange(static_cast<detail::OpResultImpl *>(Value(result).getImpl()),

582 1) {}

583

586 }

589 }

592 }

595 }

598 }

601 }

602

604 : it(end ? results.end() : results.begin()), endIt(results.end()) {

605

606 if (it != endIt)

607 skipOverResultsWithNoUsers();

608 }

609

611

612

613 if (use != (*it).use_end())

614 ++use;

615 if (use == (*it).use_end()) {

616 ++it;

617 skipOverResultsWithNoUsers();

618 }

619 return *this;

620 }

621

622 void ResultRange::UseIterator::skipOverResultsWithNoUsers() {

623 while (it != endIt && (*it).use_empty())

624 ++it;

625

626

627

628 if (it == endIt)

629 use = {};

630 else

631 use = (*it).use_begin();

632 }

633

636 }

637

641 }

642

643

644

645

646

648 : ValueRange(values.data(), values.size()) {}

653

654

656 ptrdiff_t index) {

657 if (const auto *value = llvm::dyn_cast_if_present<const Value *>(owner))

658 return {value + index};

659 if (auto *operand = llvm::dyn_cast_if_present<OpOperand *>(owner))

660 return {operand + index};

661 return cast<detail::OpResultImpl *>(owner)->getNextResultAtOffset(index);

662 }

663

664 Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) {

665 if (const auto *value = llvm::dyn_cast_if_present<const Value *>(owner))

666 return value[index];

667 if (auto *operand = llvm::dyn_cast_if_present<OpOperand *>(owner))

668 return operand[index].get();

669 return cast<detail::OpResultImpl *>(owner)->getNextResultAtOffset(index);

670 }

671

672

673

674

675

679

680

681

682

683 DictionaryAttr dictAttrs;

684 if (!(flags & Flags::IgnoreDiscardableAttrs))

686 llvm::hash_code hash =

688 if (!(flags & Flags::IgnoreProperties))

689 hash = llvm::hash_combine(hash, op->hashProperties());

690

691

692 if (!(flags & Flags::IgnoreLocations))

693 hash = llvm::hash_combine(hash, op->getLoc());

694

695

698 size_t operandHash = hashOperands(op->getOperand(0));

699 for (auto operand : op->getOperands().drop_front())

700 operandHash += hashOperands(operand);

701 hash = llvm::hash_combine(hash, operandHash);

702 } else {

704 hash = llvm::hash_combine(hash, hashOperands(operand));

705 }

706

707

709 hash = llvm::hash_combine(hash, hashResults(result));

710 return hash;

711 }

712

719 checkCommutativeEquivalent) {

721 auto blocksEquivalent = [&](Block &lBlock, Block &rBlock) {

722

723 if (lBlock.getNumArguments() != rBlock.getNumArguments())

724 return false;

725

726

727 auto insertion = blocksMap.insert({&lBlock, &rBlock});

728 if (insertion.first->getSecond() != &rBlock)

729 return false;

730

731 for (auto argPair :

732 llvm::zip(lBlock.getArguments(), rBlock.getArguments())) {

733 Value curArg = std::get<0>(argPair);

734 Value otherArg = std::get<1>(argPair);

736 return false;

739 return false;

740

741 if (markEquivalent)

742 markEquivalent(curArg, otherArg);

743 }

744

746

748 markEquivalent, flags,

749 checkCommutativeEquivalent))

750 return false;

751

752 for (auto successorsPair :

753 llvm::zip(lOp.getSuccessors(), rOp.getSuccessors())) {

754 Block *curSuccessor = std::get<0>(successorsPair);

755 Block *otherSuccessor = std::get<1>(successorsPair);

756 auto insertion = blocksMap.insert({curSuccessor, otherSuccessor});

757 if (insertion.first->getSecond() != otherSuccessor)

758 return false;

759 }

760 return true;

761 };

762 return llvm::all_of_zip(lBlock, rBlock, opsEquivalent);

763 };

764 return llvm::all_of_zip(*lhs, *rhs, blocksEquivalent);

765 }

766

767

768

772 return success(lhsValue == rhsValue ||

773 equivalentValues.lookup(lhsValue) == rhsValue);

774 }

777

778 if (lhsRange.size() != rhsRange.size())

779 return failure();

780

781

782 auto lhsIt = lhsRange.begin();

783 auto rhsIt = rhsRange.begin();

784 for (; lhsIt != lhsRange.end(); ++lhsIt, ++rhsIt) {

785 if (failed(checkEquivalent(*lhsIt, *rhsIt)))

786 break;

787 }

788 if (lhsIt == lhsRange.end())

789 return success();

790

791

792

793

794 auto sortValues = [](ValueRange values) {

796 llvm::sort(sortedValues, [](Value a, Value b) {

798 });

799 return sortedValues;

800 };

801 auto lhsSorted = sortValues({lhsIt, lhsRange.end()});

802 auto rhsSorted = sortValues({rhsIt, rhsRange.end()});

803 return success(lhsSorted == rhsSorted);

804 }

806 auto insertion = equivalentValues.insert({lhsResult, rhsResult});

807

808

809 (void)insertion;

810 assert(insertion.first->second == rhsResult &&

811 "inconsistent OperationEquivalence state");

812 }

813 };

814

815 bool

820 lhs, rhs,

821 [&](Value lhsValue, Value rhsValue) -> LogicalResult {

823 },

824 [&](Value lhsResult, Value rhsResult) {

826 },

827 flags,

830 });

831 }

832

838 checkCommutativeEquivalent) {

839 if (lhs == rhs)

840 return true;

841

842

845 return false;

846

852 return false;

856 return false;

858 return false;

859

860

861 if (checkCommutativeEquivalent &&

865 if (failed(checkCommutativeEquivalent(lhsRange, rhsRange)))

866 return false;

867 } else {

868

870 Value curArg = std::get<0>(operandPair);

871 Value otherArg = std::get<1>(operandPair);

872 if (curArg == otherArg)

873 continue;

875 return false;

876 if (failed(checkEquivalent(curArg, otherArg)))

877 return false;

878 }

879 }

880

881

883 Value curArg = std::get<0>(resultPair);

884 Value otherArg = std::get<1>(resultPair);

886 return false;

887 if (markEquivalent)

888 markEquivalent(curArg, otherArg);

889 }

890

891

894 &std::get<1>(regionPair), checkEquivalent,

895 markEquivalent, flags))

896 return false;

897

898 return true;

899 }

900

906 lhs, rhs,

907 [&](Value lhsValue, Value rhsValue) -> LogicalResult {

909 },

910 [&](Value lhsResult, Value rhsResult) {

912 },

913 flags,

916 });

917 }

918

919

920

921

922

923 template

924 static void addDataToHash(llvm::SHA1 &hasher, const T &data) {

925 hasher.update(

926 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&data), sizeof(T)));

927 }

928

930 bool includeNested) {

931 llvm::SHA1 hasher;

932

933

934 auto addOperationToHash = [&](Operation *op) {

935

937

938 if (op != topOp)

940

942

944

946 for (Block &block : region) {

950 }

951 }

952

954

957

958 for (unsigned i = 0, e = op->getNumSuccessors(); i != e; ++i)

960

963 };

964

965 if (includeNested)

966 topOp->walk(addOperationToHash);

967 else

968 addOperationToHash(topOp);

969

970 hash = hasher.result();

971 }

static Value getBase(Value v)

Looks through known "view-like" ops to find the base memref.

static MLIRContext * getContext(OpFoldResult val)

static void addDataToHash(llvm::SHA1 &hasher, const T &data)

static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)

Attributes are known-constant values of operations.

MLIRContext * getContext() const

Return the context this attribute belongs to.

This class represents an argument of a Block.

This class provides an abstraction over the different types of ranges over Blocks.

Block represents an ordered list of Operations.

unsigned getNumArguments()

BlockArgListType getArguments()

This class represents a diagnostic that is inflight and set to be reported.

This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...

const void * getAsOpaquePointer() const

Methods for supporting PointerLikeTypeTraits.

MLIRContext is the top-level object for a collection of MLIR operations.

This class represents a contiguous range of mutable operand ranges, e.g.

MutableOperandRange join() const

Flatten all of the sub ranges into a single contiguous mutable operand range.

MutableOperandRangeRange(const MutableOperandRange &operands, NamedAttribute operandSegmentAttr)

Construct a range given a parent set of operands, and an I32 tensor elements attribute containing the...

This class provides a mutable adaptor for a range of operands.

OperandRange getAsOperandRange() const

Explicit conversion to an OperandRange.

void assign(ValueRange values)

Assign this range to the given values.

MutableOperandRange slice(unsigned subStart, unsigned subLen, std::optional< OperandSegment > segment=std::nullopt) const

Slice this range into a sub range, with the additional operand segment.

MutableArrayRef< OpOperand >::iterator end() const

void erase(unsigned subStart, unsigned subLen=1)

Erase the operands within the given sub-range.

void append(ValueRange values)

Append the given values to the range.

void clear()

Clear this range and erase all of the operands.

MutableOperandRange(Operation *owner, unsigned start, unsigned length, ArrayRef< OperandSegment > operandSegments=std::nullopt)

Construct a new mutable range from the given operand, operand start index, and range length.

MutableArrayRef< OpOperand >::iterator begin() const

Iterators enumerate OpOperands.

std::pair< unsigned, NamedAttribute > OperandSegment

A pair of a named attribute corresponding to an operand segment attribute, and the index within that ...

MutableOperandRangeRange split(NamedAttribute segmentSizes) const

Split this range into a set of contiguous subranges using the given elements attribute,...

OpOperand & operator[](unsigned index) const

Returns the OpOperand at the given index.

NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...

std::optional< NamedAttribute > getNamed(StringRef name) const

Return the specified named attribute if present, std::nullopt otherwise.

void assign(const_iterator inStart, const_iterator inEnd)

Replaces the attributes with new list of attributes.

SmallVectorImpl< NamedAttribute >::const_iterator const_iterator

ArrayRef< NamedAttribute > getAttrs() const

Return all of the attributes on this operation.

DictionaryAttr getDictionary(MLIRContext *context) const

Return a dictionary attribute for the underlying dictionary.

void push_back(NamedAttribute newAttribute)

Add an attribute with the specified name.

Attribute get(StringAttr name) const

Return the specified attribute if present, null otherwise.

Attribute erase(StringAttr name)

Erase the attribute with the given name from the list.

std::optional< NamedAttribute > findDuplicate() const

Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.

Attribute set(StringAttr name, Attribute value)

If the an attribute exists with the specified name, change it to the new value.

NamedAttrList & operator=(const SmallVectorImpl< NamedAttribute > &rhs)

NamedAttribute represents a combination of a name and an Attribute value.

This class represents an operand of an operation.

This is a value defined by a result of an operation.

This class adds property that the operation is commutative.

This class represents a contiguous range of operand ranges, e.g.

OperandRangeRange(OperandRange operands, Attribute operandSegments)

Construct a range given a parent set of operands, and an I32 elements attribute containing the sizes ...

OperandRange join() const

Flatten all of the sub ranges into a single contiguous operand range.

This class implements the operand iterators for the Operation class.

unsigned getBeginOperandIndex() const

Return the operand index of the first element of this range.

OperandRangeRange split(DenseI32ArrayAttr segmentSizes) const

Split this range into a set of contiguous subranges using the given elements attribute,...

OperationFingerPrint(Operation *topOp, bool includeNested=true)

bool compareOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const

Operation is the basic unit of execution within MLIR.

Value getOperand(unsigned idx)

bool hasTrait()

Returns true if the operation was registered with a particular trait, e.g.

void insertOperands(unsigned index, ValueRange operands)

Insert the given operands into the operand list at the given 'index'.

OpOperand & getOpOperand(unsigned idx)

void setOperand(unsigned idx, Value value)

Block * getSuccessor(unsigned index)

unsigned getNumSuccessors()

void eraseOperands(unsigned idx, unsigned length=1)

Erase the operands starting at position idx and ending at position 'idx'+'length'.

std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)

Walk the operation by calling the callback for each nested operation (including this one),...

unsigned getNumRegions()

Returns the number of regions held by this operation.

Location getLoc()

The source location the operation was defined or derived from.

DictionaryAttr getRawDictionaryAttrs()

Return all attributes that are not stored as properties.

unsigned getNumOperands()

Operation * getParentOp()

Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...

void setAttr(StringAttr name, Attribute value)

If the an attribute exists with the specified name, change it to the new value.

MutableArrayRef< Region > getRegions()

Returns the regions held by this operation.

OperationName getName()

The name of an operation is the key identifier for it.

LogicalResult setPropertiesFromAttribute(Attribute attr, function_ref< InFlightDiagnostic()> emitError)

Set the properties from the provided attribute.

MutableArrayRef< OpOperand > getOpOperands()

result_type_range getResultTypes()

operand_range getOperands()

Returns an iterator on the underlying Value's.

void setOperands(ValueRange operands)

Replace the current operands of this operation with the ones provided in 'operands'.

SuccessorRange getSuccessors()

result_range getResults()

llvm::hash_code hashProperties()

Compute a hash for the op properties (if any).

OpaqueProperties getPropertiesStorage()

Returns the properties storage.

unsigned getNumResults()

Return the number of results held by this operation.

This class contains a list of basic blocks and a link to the parent operation it is attached to.

This class implements a use iterator for a range of operation results.

UseIterator(ResultRange results, bool end=false)

Initialize the UseIterator.

UseIterator & operator++()

This class implements the result iterators for the Operation class.

use_range getUses() const

Returns a range of all uses of results within this range, which is useful for iterating over all uses...

use_iterator use_begin() const

user_range getUsers()

Returns a range of all users.

ValueUserIterator< use_iterator, OpOperand > user_iterator

ResultRange(OpResult result)

use_iterator use_end() const

std::enable_if_t<!std::is_convertible< ValuesT, Operation * >::value > replaceUsesWithIf(ValuesT &&values, function_ref< bool(OpOperand &)> shouldReplace)

Replace uses of results of this range with the provided 'values' if the given callback returns true.

std::enable_if_t<!std::is_convertible< ValuesT, Operation * >::value > replaceAllUsesWith(ValuesT &&values)

Replace all uses of results of this range with the provided 'values'.

user_iterator user_begin()

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.

PointerUnion< const Value *, OpOperand *, detail::OpResultImpl * > OwnerT

The type representing the owner of a ValueRange.

ValueRange(Arg &&arg LLVM_LIFETIME_BOUND)

An iterator over the users of an IRObject.

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.

void * getAsOpaquePointer() const

Methods for supporting PointerLikeTypeTraits.

Location getLoc() const

Return the location of this value.

static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)

Builder from ArrayRef.

void eraseOperands(unsigned start, unsigned length)

Erase the operands held by the storage within the given range.

void setOperands(Operation *owner, ValueRange values)

Replace the operands contained in the storage with the ones provided in 'values'.

OperandStorage(Operation *owner, OpOperand *trailingOperands, ValueRange values)

The OpAsmOpInterface, see OpAsmInterface.td for more details.

Include the generated interface declarations.

InFlightDiagnostic emitError(Location loc)

Utility method to emit an error message using this location.

auto get(MLIRContext *context, Ts &&...params)

Helper method that injects context only if needed, this helps unify some of the attribute constructio...

LogicalResult checkEquivalent(Value lhsValue, Value rhsValue)

void markEquivalent(Value lhsResult, Value rhsResult)

LogicalResult checkCommutativeEquivalent(ValueRange lhsRange, ValueRange rhsRange)

DenseMap< Value, Value > equivalentValues

static bool isRegionEquivalentTo(Region *lhs, Region *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent, OperationEquivalence::Flags flags, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)

Compare two regions (including their subregions) and return if they are equivalent.

static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)

Compare two operations (including their regions) and return if they are equivalent.

static llvm::hash_code computeHash(Operation *op, function_ref< llvm::hash_code(Value)> hashOperands=[](Value v) { return hash_value(v);}, function_ref< llvm::hash_code(Value)> hashResults=[](Value v) { return hash_value(v);}, Flags flags=Flags::None)

Compute a hash for the given operation.

This represents an operation in an abstracted form, suitable for use with the builder APIs.

void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)

Take ownership of a set of regions that should be attached to the Operation.

SmallVector< Block *, 1 > successors

Successors of this operation and their respective operands.

SmallVector< Value, 4 > operands

void addOperands(ValueRange newOperands)

void addSuccessors(Block *successor)

Adds a successor to the operation sate. successor must not be null.

SmallVector< std::unique_ptr< Region >, 1 > regions

Regions that the op will hold.

OperationState(Location location, StringRef name)

Attribute propertiesAttr

This Attribute is used to opaquely construct the properties of the operation.

Region * addRegion()

Create a region that should be attached to the operation.

LogicalResult setProperties(Operation *op, function_ref< InFlightDiagnostic()> emitError) const