LLVM: lib/Target/Hexagon/HexagonOptShuffleVector.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

23#include "llvm/IR/IntrinsicsHexagon.h"

29

30using namespace llvm;

32

33#define DEBUG_TYPE "hex-shuff-vec"

34

36 "shuffvec-max-search-count",

37 cl::desc("Maximum number of instructions traversed along def chain."),

39

40#ifndef NDEBUG

43 cl::desc("Maximum number of shuffles to be relocated."),

45#endif

46

47namespace llvm {

50}

51

52namespace {

53

54class HexagonOptShuffleVector : public FunctionPass {

55public:

56 static char ID;

57#ifndef NDEBUG

58 static int NumRelocated;

59#endif

62 }

63

64 HexagonOptShuffleVector(const HexagonTargetMachine *TM)

65 : FunctionPass(ID), TM(TM) {

67 }

68

69 StringRef getPassName() const override {

70 return "Hexagon Optimize Vector Shuffles";

71 }

72

74

75 void getAnalysisUsage(AnalysisUsage &AU) const override {

76 FunctionPass::getAnalysisUsage(AU);

77 }

78

79private:

80 using ValueVector = SmallVector<Value *, 8>;

81 const HexagonTargetMachine *TM = nullptr;

82 const HexagonSubtarget *HST = nullptr;

83 SmallPtrSet<Instruction *, 8> Visited;

84 using ShuffUseList =

85 SmallDenseMap<Instruction *, SmallVector<Instruction *, 2>>;

86 ShuffUseList ShuffUses;

87 int DefSearchCount;

88

89 bool visitBlock(BasicBlock *B);

90 bool findNewShuffLoc(Instruction *I, ArrayRef &ShuffMask,

92 bool isValidIntrinsic(IntrinsicInst *I);

93 bool relocateShuffVec(Instruction *I, ArrayRef &M, Value *NewLoc,

94 std::list<Instruction *> &WorkList);

95 bool getUseList(Instruction *I, ValueVector &UseList);

96 bool analyzeHiLoUse(Instruction *HI, Instruction *LO,

97 ArrayRef &ShuffMask, Value *&NewLoc,

98 ShuffUseList &CurShuffUses);

99 bool isHILo(Value *V, bool IsHI);

100 bool hasDefWithSameShuffMask(Value *V, SmallVector<Instruction *, 2> &ImmUse,

101 ArrayRef &ShuffMask,

102 ShuffUseList &CurShuffUses);

103 void FindHiLoUse(ValueVector &UseList, Instruction *&HI, Instruction *&LO);

104 bool isConcatMask(ArrayRef &Mask, Instruction *ShuffInst);

105 bool isValidUseInstr(ValueVector &UseList, Instruction *&UI);

106 bool areAllOperandsValid(Instruction *I, Instruction *UI,

107 ArrayRef &ShuffMask,

108 ShuffUseList &CurShuffUses);

109 Value *getOperand(Instruction *I, unsigned i);

111 static std::pair<Value *, Value *> stripCasts(Value *V);

112 static bool isConstantVectorSplat(Value *V);

113};

114

115}

116

117#ifndef NDEBUG

118int HexagonOptShuffleVector::NumRelocated = 0;

119#endif

120char HexagonOptShuffleVector::ID = 0;

121

123 "Hexagon Optimize Shuffle Vector", false, false)

127

130 Type *ShuffTy = ShuffInst->getType();

132 for (int i = 0; i < NumElts; i++) {

133 if (Mask[i] != i)

134 return false;

135 }

136 return true;

137}

138

139bool HexagonOptShuffleVector::isValidIntrinsic(IntrinsicInst *I) {

140 switch (I->getIntrinsicID()) {

141 default:

142 return false;

143 case Intrinsic::hexagon_V6_vaddubh_128B:

144 case Intrinsic::hexagon_V6_vadduhw_128B:

145 case Intrinsic::hexagon_V6_vaddhw_128B:

146 case Intrinsic::hexagon_V6_vaddh_dv_128B:

147 case Intrinsic::hexagon_V6_vsububh_128B:

148 case Intrinsic::hexagon_V6_vsubuhw_128B:

149 case Intrinsic::hexagon_V6_vsubhw_128B:

150 case Intrinsic::hexagon_V6_vsubh_dv_128B:

151 case Intrinsic::hexagon_V6_vmpyubv_128B:

152 case Intrinsic::hexagon_V6_vmpybv_128B:

153 case Intrinsic::hexagon_V6_vmpyuhv_128B:

154 case Intrinsic::hexagon_V6_vmpyhv_128B:

155 case Intrinsic::hexagon_V6_vmpybusv_128B:

156 case Intrinsic::hexagon_V6_vmpyhus_128B:

157 case Intrinsic::hexagon_V6_vavgb_128B:

158 case Intrinsic::hexagon_V6_vavgub_128B:

159 case Intrinsic::hexagon_V6_vavgh_128B:

160 case Intrinsic::hexagon_V6_vavguh_128B:

161 case Intrinsic::hexagon_V6_vavgw_128B:

162 case Intrinsic::hexagon_V6_vavguw_128B:

163 case Intrinsic::hexagon_V6_hi_128B:

164 case Intrinsic::hexagon_V6_lo_128B:

165 case Intrinsic::sadd_sat:

166 case Intrinsic::uadd_sat:

167

168 case Intrinsic::hexagon_vadd_su:

169 case Intrinsic::hexagon_vadd_uu:

170 case Intrinsic::hexagon_vadd_ss:

171 case Intrinsic::hexagon_vadd_us:

172 case Intrinsic::hexagon_vsub_su:

173 case Intrinsic::hexagon_vsub_uu:

174 case Intrinsic::hexagon_vsub_ss:

175 case Intrinsic::hexagon_vsub_us:

176 case Intrinsic::hexagon_vmpy_su:

177 case Intrinsic::hexagon_vmpy_uu:

178 case Intrinsic::hexagon_vmpy_ss:

179 case Intrinsic::hexagon_vmpy_us:

180 case Intrinsic::hexagon_vavgu:

181 case Intrinsic::hexagon_vavgs:

182 case Intrinsic::hexagon_vmpy_ub_b:

183 case Intrinsic::hexagon_vmpy_ub_ub:

184 case Intrinsic::hexagon_vmpy_uh_uh:

185 case Intrinsic::hexagon_vmpy_h_h:

186 return true;

187 }

189}

190

191bool HexagonOptShuffleVector::getUseList(Instruction *I, ValueVector &UseList) {

192 for (auto UI = I->user_begin(), UE = I->user_end(); UI != UE;) {

194 if (!J)

195 return false;

197 if (!getUseList(C, UseList))

198 return false;

199 } else

201 ++UI;

202 }

203 return true;

204}

205

206bool HexagonOptShuffleVector::isHILo(Value *V, bool IsHI) {

208 return false;

211 return false;

213 if (II)

214 return false;

215 if ((II->getIntrinsicID() == Intrinsic::hexagon_V6_hi_128B && IsHI) ||

216 (II->getIntrinsicID() == Intrinsic::hexagon_V6_lo_128B && !IsHI))

217 return true;

218 return false;

219}

220

221Value *HexagonOptShuffleVector::getOperand(Instruction *I, unsigned i) {

222 Value *V = I->getOperand(i);

224 return C->getOperand(0);

225 return V;

226}

227

229HexagonOptShuffleVector::getArgOperands(User *U) {

231 return CB->args();

232 return U->operands();

233}

234

235

236

237std::pair<Value *, Value *> HexagonOptShuffleVector::stripCasts(Value *V) {

238 Value *LastCast = nullptr;

240 LastCast = V;

241 V = C->getOperand(0);

242 }

243 return std::make_pair(V, LastCast);

244}

245

246bool HexagonOptShuffleVector::isConstantVectorSplat(Value *V) {

248 return CV->getSplatValue();

250 return CV->isSplat();

251 return false;

252}

253

254

255

256

257bool HexagonOptShuffleVector::analyzeHiLoUse(Instruction *HI, Instruction *LO,

258 ArrayRef &ShuffMask,

260 ShuffUseList &CurShuffUses) {

262 getUseList(HI, HiUseList);

263 getUseList(LO, LoUseList);

264

265

266

267

268 if (HiUseList.size() != 1 || LoUseList.size() != 1)

269 return false;

270

273 if (!HiUse || !LoUse)

274 return false;

275

276 bool IsUseIntrinsic = false;

279 return false;

280

283 if (!HiUseII || !LoUseII ||

285 !isValidIntrinsic(HiUseII))

286 return false;

287 IsUseIntrinsic = true;

288 HiUse = HiUseII;

289 LoUse = LoUseII;

290 }

292 return false;

293

294

295

296 if (HiUse == LoUse) {

297

298 ArrayRef M;

301 NewLoc = HiUse;

302 return true;

303 }

304 }

305 return false;

306 }

307

308

309

310 ArrayRef M1, M2;

313 M1.equals(M2))

314 return analyzeHiLoUse(HiUse, LoUse, ShuffMask, NewLoc, CurShuffUses);

315

316

317

318 if (!HiUse->isBinaryOp() && !IsUseIntrinsic)

319 return false;

320

321 ValueVector HiUseOperands, LoUseOperands;

322 int HiOpNum = -1, LoOpNum = -1;

323 for (unsigned i = 0; i < HiUse->getNumOperands(); i++) {

324 Value *V = getOperand(HiUse, i);

325 if (V == HI)

326 HiOpNum = i;

327 else

329 }

330 for (unsigned i = 0; i < LoUse->getNumOperands(); i++) {

331 Value *V = getOperand(LoUse, i);

332 if (V == LO)

333 LoOpNum = i;

334 else

336 }

337

338

339

340 if (HiOpNum < 0 || HiOpNum != LoOpNum ||

341 LoUseOperands.size() != HiUseOperands.size())

342 return false;

343

344 unsigned NumOperands = HiUseOperands.size();

345 for (unsigned i = 0; i < NumOperands; i++) {

346 if (HiUseOperands[i] == LoUseOperands[i])

347 continue;

348

349

350 if (!isHILo(HiUseOperands[i], true) || !isHILo(LoUseOperands[i], false))

351 return false;

352

355 if (!DefHiUse || DefHiUse != DefLoUse)

356 return false;

357 SmallVector<Instruction *, 2> ImmUseList;

360 else {

363 }

364

365

366 if (!hasDefWithSameShuffMask(DefHiUse, ImmUseList, ShuffMask, CurShuffUses))

367 return false;

368 }

369

370

371 return analyzeHiLoUse(HiUse, LoUse, ShuffMask, NewLoc, CurShuffUses);

372}

373

374bool HexagonOptShuffleVector::hasDefWithSameShuffMask(

375 Value *V, SmallVector<Instruction *, 2> &ImmUses, ArrayRef &ShuffMask,

376 ShuffUseList &CurShuffUses) {

377

378

380 return false;

381

382 ++DefSearchCount;

383 V = stripCasts(V).first;

385 if (I)

386 return false;

387 bool Found = true;

388 ArrayRef M;

390 M.equals(ShuffMask)) {

391 CurShuffUses[I] = ImmUses;

392 return true;

393 }

396 return true;

397

399 if (I->isBinaryOp() && (II || !isValidIntrinsic(II)))

400 return false;

401

402 for (Value *OpV : getArgOperands(I)) {

403 std::pair<Value *, Value *> P = stripCasts(OpV);

404 OpV = P.first;

405

406 SmallVector<Instruction *, 2> ImmUseList;

407 if (P.second)

409 else

411

413 continue;

414 if (isConstantVectorSplat(OpV))

415 continue;

417 return false;

420 continue;

421 Found &= hasDefWithSameShuffMask(OpV, ImmUseList, ShuffMask, CurShuffUses);

422 }

423 return Found;

424}

425

426void HexagonOptShuffleVector::FindHiLoUse(ValueVector &UseList,

427 Instruction *&HI, Instruction *&LO) {

428

429 for (unsigned i = 0; i < UseList.size(); i++) {

432 if (CI) {

434 if (II) {

436 if (IntID == Intrinsic::hexagon_V6_hi_128B)

437 HI = J;

438 if (IntID == Intrinsic::hexagon_V6_lo_128B)

439 LO = J;

440 }

441 }

442 }

443}

444

445bool HexagonOptShuffleVector::isValidUseInstr(ValueVector &UseList,

446 Instruction *&UI) {

447

448 if (UseList.size() != 1)

449 return false;

451 if (!UI)

452 return false;

453

456 if (II || !isValidIntrinsic(II))

457 return false;

458 UI = II;

460 return false;

461 return true;

462}

463

464

465

466

467

468

469bool HexagonOptShuffleVector::areAllOperandsValid(Instruction *I,

470 Instruction *Use,

471 ArrayRef &ShuffMask,

472 ShuffUseList &CurShuffUses) {

473 bool AllOperandsOK = true;

474 for (Value *OpV : getArgOperands(Use)) {

475 bool HasOneUse = OpV->hasOneUse();

476 std::pair<Value *, Value *> P = stripCasts(OpV);

477 OpV = P.first;

478

479 SmallVector<Instruction *, 2> ImmUseList;

480 if (P.second)

482 else

484

486 continue;

487 if (isConstantVectorSplat(OpV))

488 continue;

490 return false;

491

494 continue;

495 AllOperandsOK &=

496 hasDefWithSameShuffMask(OpV, ImmUseList, ShuffMask, CurShuffUses);

497 }

498 return AllOperandsOK;

499}

500

501

502bool HexagonOptShuffleVector::findNewShuffLoc(Instruction *I,

503 ArrayRef &ShuffMask,

504 Value *&NewLoc) {

505 DefSearchCount = 0;

507 if (!getUseList(I, UseList))

508 return false;

509

510 using ShuffUseList =

511 SmallDenseMap<Instruction *, SmallVector<Instruction *, 2>>;

512 ShuffUseList CurShuffUses;

513

515 FindHiLoUse(UseList, HI, LO);

516 if (UseList.size() == 2 && HI && LO) {

517

518

519

521 dbgs() << "\tFollowing the Hi/LO pair :\n";

522 dbgs() << "\t\tHI - ";

523 HI->dump();

524 dbgs() << "\t\tLO - ";

525 LO->dump();

526 });

527 if (!analyzeHiLoUse(HI, LO, ShuffMask, NewLoc, CurShuffUses))

528 return false;

529 for (auto &it : CurShuffUses)

530 ShuffUses[it.first] = it.second;

531 return true;

532 } else {

534 if (!isValidUseInstr(UseList, UI))

535 return false;

536 assert(UI && "Expected a valid use, but found none!!");

537

538 if (HI || LO) {

539

540 return false;

541 }

542

543 LLVM_DEBUG(dbgs() << "\tChecking operands in 'use' : \n\t\t"; UI->dump());

544 if (!areAllOperandsValid(I, UI, ShuffMask, CurShuffUses)) {

546 return false;

547 }

548 for (auto &it : CurShuffUses)

549 ShuffUses[it.first] = it.second;

550 NewLoc = UI;

551

552 findNewShuffLoc(UI, ShuffMask, NewLoc);

553 }

554 return true;

555}

556

557

558bool HexagonOptShuffleVector::relocateShuffVec(

559 Instruction *I, ArrayRef &M, Value *NewLoc,

560 std::list<Instruction *> &WorkList) {

561

562

563

564 std::map<Instruction *, Value *> InstrMap;

565 bool CanReplace = true;

566 unsigned ShuffInstCount = ShuffUses.size();

567 for (auto &it : ShuffUses) {

569 Visited.insert(J);

570 Value *ShuffleOP = nullptr;

574 if (JTy->getElementCount() != ShuffTy->getElementCount())

575 CanReplace = false;

576

577

578

579

581 if (ShuffInstCount == 1 &&

582 NewShuffTy->getElementType() > ShuffTy->getElementType())

583 CanReplace = false;

584 InstrMap[J] = ShuffleOP;

585 }

586 if (!CanReplace) {

588 return false;

589 }

590 for (auto IM : InstrMap) {

592 assert(ShuffUses.count(J));

593 SmallVector<Instruction *, 2> Uses = ShuffUses[J];

594 if (Uses.size() > 0) {

595 for (auto *U : Uses)

596 U->replaceUsesOfWith(IM.first, IM.second);

597 } else

598

599

600

601 IM.first->replaceAllUsesWith(IM.second);

602 }

603

608 Value *NewShuffV =

611 if (!NewInst) {

613 return false;

614 }

615 for (auto UI = NewLoc->user_begin(), UE = NewLoc->user_end(); UI != UE;) {

616 Use &TheUse = UI.getUse();

617 ++UI;

619 if (J && TheUse.getUser() != NewShuffV)

621 }

622 WorkList.push_back(NewInst);

623 LLVM_DEBUG(dbgs() << "\tRelocation Successfull!! \n");

625 return true;

626}

627

628bool HexagonOptShuffleVector::visitBlock(BasicBlock *B) {

630 ArrayRef M;

631 std::list<Instruction *> WorkList;

632 LLVM_DEBUG(dbgs() << "Preparing worklist for BB:\n");

634 for (auto &I : *B) {

636 continue;

638 WorkList.push_back(&I);

640 }

641 }

642

644 while (!WorkList.empty()) {

645#ifndef NDEBUG

647 if (Limit >= 0) {

650 dbgs() << "Reached maximum limit!! \n";

651 dbgs() << "Can't process any more shuffles.... \n";

652 });

654 }

655 }

656#endif

658 WorkList.pop_front();

659 LLVM_DEBUG(dbgs() << "\tProcessing instr - "; I->dump());

660 Value *NewLoc = nullptr;

661

662

663

664

665

666

667

668

669

670

671

672

673 ShuffUses.clear();

674 ShuffUses[I] = SmallVector<Instruction *, 2>();

675

676 if (!Visited.insert(I).second) {

677 LLVM_DEBUG(dbgs() << "\t\tSKIPPING - Already visited ...\n");

678 continue;

679 }

681 LLVM_DEBUG(dbgs() << "\t\tSKIPPING - Not a vector shuffle ...\n");

682 continue;

683 }

684 if (!findNewShuffLoc(I, M, NewLoc) || !NewLoc) {

685 LLVM_DEBUG(dbgs() << "\t\tSKIPPING - NewLoc not found ...\n");

686 continue;

687 }

689 Changed |= relocateShuffVec(I, M, NewLoc, WorkList);

690#ifndef NDEBUG

691 NumRelocated++;

692#endif

693 }

695}

696

697bool HexagonOptShuffleVector::runOnFunction(Function &F) {

699

701 return false;

702

704 for (auto &B : F)

706

708}

709

710FunctionPass *

712 return new HexagonOptShuffleVector(&TM);

713}

static bool isConcatMask(ArrayRef< int > Mask, EVT VT, bool SplitLHS)

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

This file implements a class to represent arbitrary precision integral constant values and operations...

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

This file contains the declarations for the subclasses of Constant, which represent the different fla...

static bool runOnFunction(Function &F, bool PostInlining)

static cl::opt< int > MaxDefSearchCount("shuffvec-max-search-count", cl::desc("Maximum number of instructions traversed along def chain."), cl::Hidden, cl::init(15))

A command line argument to limit the search space along def chain.

static cl::opt< int > ShuffVecLimit("shuff-vec-max", cl::desc("Maximum number of shuffles to be relocated."), cl::Hidden, cl::init(-1))

uint64_t IntrinsicInst * II

#define INITIALIZE_PASS_DEPENDENCY(depName)

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)

#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)

Remove Loads Into Fake Uses

SmallVector< Value *, 8 > ValueVector

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

Legacy analysis pass which computes a DominatorTree.

FunctionPass class - This class is used to implement most global optimizations.

bool useHVX128BOps() const

const HexagonSubtarget * getSubtargetImpl(const Function &F) const override

Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...

unsigned getOpcode() const

Returns a member of one of the enums like Instruction::Add.

A wrapper class for inspecting calls to intrinsic functions.

Intrinsic::ID getIntrinsicID() const

Return the intrinsic ID of this intrinsic.

PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...

static LLVM_ABI PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

static LLVM_ABI PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

void push_back(const T &Elt)

The instances of the Type class are immutable: once they are created, they are never changed.

User * getUser() const

Returns the User that contains this Use.

LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)

Replace uses of one Value with another.

unsigned getNumOperands() const

Type * getType() const

All values are typed, get the type of this value.

user_iterator user_begin()

LLVM_ABI void dump() const

Support for debugging, callable in GDB: V->dump()

NodeTy * getNextNode()

Get the next node, or nullptr for the list tail.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ C

The default llvm calling convention, compatible with C.

class_match< PoisonValue > m_Poison()

Match an arbitrary poison constant.

bool match(Val *V, const Pattern &P)

TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)

Matches ShuffleVectorInst independently of mask value.

class_match< Value > m_Value()

Match an arbitrary value and ignore it.

is_zero m_Zero()

Match any null constant or a vector with all elements equal to 0.

ThreeOps_match< Val_t, Elt_t, Idx_t, Instruction::InsertElement > m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx)

Matches InsertElementInst.

initializer< Ty > init(const Ty &Val)

NodeAddr< UseNode * > Use

friend class Instruction

Iterator for Instructions in a `BasicBlock.

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

FunctionPass * createHexagonOptShuffleVector(const HexagonTargetMachine &)

Definition HexagonOptShuffleVector.cpp:711

unsigned M1(unsigned Val)

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >

void initializeHexagonOptShuffleVectorPass(PassRegistry &)

IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.