LLVM: lib/Analysis/HashRecognize.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

69

70using namespace llvm;

73

74#define DEBUG_TYPE "hash-recognize"

75

76

77

78

83

85 while (!Worklist.empty()) {

88

90 continue;

91

92 for (const Use &U : I->operands()) {

94 if (!L.contains(UI))

95 return true;

97 }

98 }

99 }

100 return Latch->size() != Visited.size();

101}

102

103

104

105

113

115 operator bool() const { return BO; }

116

118 OS.indent(Indent) << "Phi: ";

119 Phi->print(OS);

120 OS << "\n";

121 OS.indent(Indent) << "BinaryOperator: ";

122 BO->print(OS);

123 OS << "\n";

124 OS.indent(Indent) << "Start: ";

125 Start->print(OS);

126 OS << "\n";

127 OS.indent(Indent) << "Step: ";

128 Step->print(OS);

129 OS << "\n";

131 OS.indent(Indent) << "ExtraConst: ";

133 OS << "\n";

134 }

135 }

136

137#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

139#endif

140

145

146private:

150};

151

152

153

154

155

156

157

158

159

160

161

162

163

164static bool

167 bool ByteOrderSwapped) {

175 return false;

176

177

178

183 bool LWellFormed = ByteOrderSwapped ? match(L, MatchPred)

185 if (!LWellFormed)

186 return false;

187

195

197 if (AllowedByR == CheckAllowedByR)

198 return TV == BitShift &&

201 if (AllowedByR.inverse() == CheckAllowedByR)

202 return FV == BitShift &&

205 return false;

206}

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

226 return true;

227 }

228 return false;

229}

230

231

232

234RecurrenceInfo::digRecurrence(Instruction *V,

238 while (!Worklist.empty()) {

240

241

243 continue;

244

245

246

249

250

251 if (I->getOpcode() == BOWithConstOpToMatch) {

253 return nullptr;

254 const APInt *C = nullptr;

257 }

258

259

260 for (Use &U : I->operands())

262 if (L.contains(UI))

264 }

265 return nullptr;

266}

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

286 if (Phi->getNumIncomingValues() != 2)

287 return false;

288

289 for (unsigned Idx = 0; Idx != 2; ++Idx) {

290 Value *FoundStep = Phi->getIncomingValue(Idx);

291 Value *FoundStart = Phi->getIncomingValue(!Idx);

292

294 if (match(FoundStep,

296 continue;

297

298

299

300 BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);

301 BinaryOperator *AltBO = digRecurrence(FV, BOWithConstOpToMatch);

302 if (!FoundBO || FoundBO != AltBO)

303 return false;

304

305 if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && ExtraConst) {

306 LLVM_DEBUG(dbgs() << "HashRecognize: Unable to match single BinaryOp "

307 "with constant in conditional recurrence\n");

308 return false;

309 }

310

311 BO = FoundBO;

312 Start = FoundStart;

313 Step = FoundStep;

314 return true;

315 }

316 return false;

317}

318

319

320

321static std::optional<std::pair<RecurrenceInfo, RecurrenceInfo>>

323 auto Phis = LoopLatch->phis();

324 unsigned NumPhis = std::distance(Phis.begin(), Phis.end());

325 if (NumPhis != 2 && NumPhis != 3)

326 return {};

327

331 if (&P == IndVar)

332 continue;

333 if (!SimpleRecurrence)

335 if (!ConditionalRecurrence)

337 &P, Instruction::BinaryOps::Xor);

338 }

339 if (NumPhis == 3 && (!SimpleRecurrence || !ConditionalRecurrence))

340 return {};

341 return std::make_pair(SimpleRecurrence, ConditionalRecurrence);

342}

343

349

350

351

352

354 bool ByteOrderSwapped) {

358

359 if (ByteOrderSwapped) {

361 for (unsigned I = 1; I < 256; I <<= 1) {

362 CRCInit = CRCInit.shl(1) ^

364 for (unsigned J = 0; J < I; ++J)

365 Table[I + J] = CRCInit ^ Table[J];

366 }

367 return Table;

368 }

369

370 APInt CRCInit(BW, 1);

371 for (unsigned I = 128; I; I >>= 1) {

372 CRCInit = CRCInit.lshr(1) ^ (CRCInit[0] ? GenPoly : APInt::getZero(BW));

373 for (unsigned J = 0; J < 256; J += (I << 1))

374 Table[I + J] = CRCInit ^ Table[J];

375 }

376 return Table;

377}

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

396

397

398

400

401 while (!Worklist.empty()) {

403

404

406 continue;

407

408

411 return true;

412

413

414 for (const Use &U : I->operands())

416 if (L.contains(UI))

418 }

419 return false;

420}

421

422

423

424

425

427 if (!V->getType()->isIntegerTy())

428 return {};

429

432 return false;

434 return true;

435 return {};

436}

437

438

439

441 if (!L.isInnermost())

442 return "Loop is not innermost";

443 BasicBlock *Latch = L.getLoopLatch();

445 const PHINode *IndVar = L.getCanonicalInductionVariable();

446 if (!Latch || !Exit || !IndVar || L.getNumBlocks() != 1)

447 return "Loop not in canonical form";

448 unsigned TC = SE.getSmallConstantTripCount(&L);

449 if (!TC || TC % 8)

450 return "Unable to find a small constant byte-multiple trip count";

451

453 if (!R)

454 return "Found stray PHI";

455 auto [SimpleRecurrence, ConditionalRecurrence] = *R;

456 if (!ConditionalRecurrence)

457 return "Unable to find conditional recurrence";

458

459

460

461 std::optional ByteOrderSwapped =

463 if (!ByteOrderSwapped)

464 return "Loop with non-unit bitshifts";

465 if (SimpleRecurrence) {

467 return "Loop with non-unit bitshifts";

468

469

470

471

472

473 if (!ConditionalRecurrence.Phi->hasNUses(2) ||

474 !SimpleRecurrence.Phi->hasNUses(2) ||

475 SimpleRecurrence.BO->getUniqueUndroppableUser() != SimpleRecurrence.Phi)

476 return "Recurrences have stray uses";

477

478

479

481 SimpleRecurrence.Phi,

482 ConditionalRecurrence.Phi, L))

483 return "Recurrences not intertwined with XOR";

484 }

485

486

487 Value *LHS = ConditionalRecurrence.Start;

488 Value *LHSAux = SimpleRecurrence ? SimpleRecurrence.Start : nullptr;

490 : LHS->getType()->getIntegerBitWidth()))

491 return "Loop iterations exceed bitwidth of data";

492

493

494

495

496 auto *ComputedValue = cast(ConditionalRecurrence.Step);

497 if (none_of(ComputedValue->users(), [Exit](User *U) {

498 auto *UI = dyn_cast(U);

499 return UI && UI->getParent() == Exit;

500 }))

501 return "Unable to find use of computed value in loop exit block";

502

503 assert(ConditionalRecurrence.ExtraConst &&

504 "Expected ExtraConst in conditional recurrence");

505 const APInt &GenPoly = *ConditionalRecurrence.ExtraConst;

506

508 *ByteOrderSwapped))

509 return "Malformed significant-bit check";

510

512 {ComputedValue,

515 if (SimpleRecurrence)

516 Roots.push_back(SimpleRecurrence.BO);

518 return "Found stray unvisited instructions";

519

520 return PolynomialInfo(TC, LHS, GenPoly, ComputedValue, *ByteOrderSwapped,

521 LHSAux);

522}

523

525 for (unsigned I = 0; I < 256; I++) {

526 (*this)[I].print(OS, false);

527 OS << (I % 16 == 15 ? '\n' : ' ');

528 }

529}

530

531#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

533#endif

534

536 if (!L.isInnermost())

537 return;

538 OS << "HashRecognize: Checking a loop in '"

539 << L.getHeader()->getParent()->getName() << "' from " << L.getLocStr()

540 << "\n";

542 if (!std::holds_alternative(Ret)) {

543 OS << "Did not find a hash algorithm\n";

544 if (std::holds_alternative(Ret))

545 OS << "Reason: " << std::get(Ret) << "\n";

546 return;

547 }

548

549 auto Info = std::get(Ret);

550 OS << "Found" << (Info.ByteOrderSwapped ? " big-endian " : " little-endian ")

551 << "CRC-" << Info.RHS.getBitWidth() << " loop with trip count "

552 << Info.TripCount << "\n";

553 OS.indent(2) << "Initial CRC: ";

554 Info.LHS->print(OS);

555 OS << "\n";

556 OS.indent(2) << "Generating polynomial: ";

557 Info.RHS.print(OS, false);

558 OS << "\n";

559 OS.indent(2) << "Computed CRC: ";

560 Info.ComputedValue->print(OS);

561 OS << "\n";

562 if (Info.LHSAux) {

563 OS.indent(2) << "Auxiliary data: ";

564 Info.LHSAux->print(OS);

565 OS << "\n";

566 }

567 OS.indent(2) << "Computed CRC lookup table:\n";

569}

570

571#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

573#endif

574

577 if (std::holds_alternative(Res))

578 return std::get(Res);

579 return std::nullopt;

580}

581

584

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< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

#define LLVM_DUMP_METHOD

Mark debug helper function definitions like dump() that should not be stripped from debug builds.

static bool containsUnreachable(const Loop &L, ArrayRef< const Instruction * > Roots)

Checks if there's a stray instruction in the loop L outside of the use-def chains from Roots,...

Definition HashRecognize.cpp:79

static bool isSignificantBitCheckWellFormed(const RecurrenceInfo &ConditionalRecurrence, const RecurrenceInfo &SimpleRecurrence, bool ByteOrderSwapped)

Check the well-formedness of the (most|least) significant bit check given ConditionalRecurrence,...

Definition HashRecognize.cpp:165

static bool isConditionalOnXorOfPHIs(const SelectInst *SI, const PHINode *P1, const PHINode *P2, const Loop &L)

Checks that P1 and P2 are used together in an XOR in the use-def chain of SI's condition,...

Definition HashRecognize.cpp:393

static std::optional< std::pair< RecurrenceInfo, RecurrenceInfo > > getRecurrences(BasicBlock *LoopLatch, const PHINode *IndVar, const Loop &L)

Iterates over all the phis in LoopLatch, and attempts to extract a Conditional Recurrence and an opti...

Definition HashRecognize.cpp:322

static std::optional< bool > isBigEndianBitShift(Value *V, ScalarEvolution &SE)

Definition HashRecognize.cpp:426

This header provides classes for managing per-loop analyses.

Class for arbitrary precision integers.

unsigned getBitWidth() const

Return the number of bits in the APInt.

static APInt getSignedMinValue(unsigned numBits)

Gets minimum signed value of APInt for a specific bit width.

APInt shl(unsigned shiftAmt) const

Left-shift function.

bool isSignBitSet() const

Determine if sign bit of this APInt is set.

static APInt getZero(unsigned numBits)

Get the '0' value for the specified bit-width.

APInt lshr(unsigned shiftAmt) const

Logical right-shift function.

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

LLVM Basic Block Representation.

iterator_range< const_phi_iterator > phis() const

Returns a range that iterates over the phis in the basic block.

const Instruction * getTerminator() const LLVM_READONLY

Returns the terminator instruction if the block is well formed or null if the block is not well forme...

An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...

This class represents a range of values.

static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)

Initialize a range based on a known bits constraint.

static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)

Produce the smallest range such that all values that may satisfy the given predicate with any value c...

PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &)

Definition HashRecognize.cpp:585

static CRCTable genSarwateTable(const APInt &GenPoly, bool ByteOrderSwapped)

Generate a lookup table of 256 entries by interleaving the generating polynomial.

Definition HashRecognize.cpp:353

std::optional< PolynomialInfo > getResult() const

Definition HashRecognize.cpp:575

LLVM_DUMP_METHOD void dump() const

Definition HashRecognize.cpp:572

HashRecognize(const Loop &L, ScalarEvolution &SE)

Definition HashRecognize.cpp:582

void print(raw_ostream &OS) const

Definition HashRecognize.cpp:535

std::variant< PolynomialInfo, StringRef > recognizeCRC() const

The main entry point for analyzing a loop and recognizing the CRC algorithm.

Definition HashRecognize.cpp:440

This class provides an interface for updating the loop pass manager based on mutations to the loop ne...

Represents a single loop in the control flow graph.

Value * getIncomingValueForBlock(const BasicBlock *BB) const

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

This class represents an analyzed expression in the program.

The main scalar evolution driver.

LLVM_ABI const SCEV * getSCEV(Value *V)

Return a SCEV expression for the full generality of the specified expression.

This class represents the LLVM 'select' instruction.

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

LLVM_ABI unsigned getIntegerBitWidth() const

A Use represents the edge between a Value definition and its users.

LLVM Value Representation.

Type * getType() const

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

This class implements an extremely fast bulk output stream that can only output to a stream.

raw_ostream & indent(unsigned NumSpaces)

indent - Insert 'NumSpaces' spaces.

@ C

The default llvm calling convention, compatible with C.

ap_match< APInt > m_APInt(const APInt *&Res)

Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.

BinaryOp_match< LHS, RHS, Instruction::And, true > m_c_And(const LHS &L, const RHS &R)

Matches an And with LHS and RHS in either order.

specific_intval< false > m_SpecificInt(const APInt &V)

Match a specific integer value or vector with all elements equal to the value.

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

bind_ty< Instruction > m_Instruction(Instruction *&I)

Match an instruction, capturing it if we match.

specificval_ty m_Specific(const Value *V)

Match if we have a specific specified value.

cst_pred_ty< is_one > m_One()

Match an integer 1 or a vector with all elements equal to 1.

ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)

Matches SelectInst.

BinaryOp_match< LHS, RHS, Instruction::Xor, true > m_c_Xor(const LHS &L, const RHS &R)

Matches an Xor with LHS and RHS in either order.

class_match< CmpInst > m_Cmp()

Matches any compare instruction and ignore it.

class_match< Value > m_Value()

Match an arbitrary value and ignore it.

AnyBinaryOp_match< LHS, RHS, true > m_c_BinOp(const LHS &L, const RHS &R)

Matches a BinaryOperator with LHS and RHS in either order.

CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)

match_combine_or< match_combine_or< CastInst_match< OpTy, ZExtInst >, CastInst_match< OpTy, TruncInst > >, OpTy > m_ZExtOrTruncOrSelf(const OpTy &Op)

match_combine_or< LTy, RTy > m_CombineOr(const LTy &L, const RTy &R)

Combine two pattern matchers matching L || R.

bind_ty< const SCEVMulExpr > m_scev_Mul(const SCEVMulExpr *&V)

bool match(const SCEV *S, const Pattern &P)

SCEVBinaryExpr_match< SCEVUDivExpr, Op0_t, Op1_t > m_scev_UDiv(const Op0_t &Op0, const Op1_t &Op1)

cst_pred_ty< is_specific_cst > m_scev_SpecificInt(uint64_t V)

Match an SCEV constant with a plain unsigned integer.

class_match< const SCEV > m_SCEV()

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

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

AnalysisManager< Loop, LoopStandardAnalysisResults & > LoopAnalysisManager

The loop analysis manager.

LLVM_ABI bool matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO, Value *&Start, Value *&Step)

Attempt to match a simple first order recurrence cycle of the form: iv = phi Ty [Start,...

LLVM_ABI raw_ostream & dbgs()

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

bool none_of(R &&Range, UnaryPredicate P)

Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.

bool isa(const From &Val)

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

decltype(auto) cast(const From &Val)

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

A structure that can hold either a Simple Recurrence or a Conditional Recurrence.

Definition HashRecognize.cpp:106

Value * Step

Definition HashRecognize.cpp:111

const Loop & L

Definition HashRecognize.cpp:107

const PHINode * Phi

Definition HashRecognize.cpp:108

LLVM_DUMP_METHOD void dump() const

Definition HashRecognize.cpp:138

bool matchConditionalRecurrence(const PHINode *P, Instruction::BinaryOps BOWithConstOpToMatch=Instruction::BinaryOpsEnd)

A Conditional Recurrence is a recurrence of the form:

Definition HashRecognize.cpp:283

void print(raw_ostream &OS, unsigned Indent=0) const

Definition HashRecognize.cpp:117

std::optional< APInt > ExtraConst

Definition HashRecognize.cpp:112

bool matchSimpleRecurrence(const PHINode *P)

Wraps llvm::matchSimpleRecurrence.

Definition HashRecognize.cpp:223

Value * Start

Definition HashRecognize.cpp:110

BinaryOperator * BO

Definition HashRecognize.cpp:109

RecurrenceInfo(const Loop &L)

Definition HashRecognize.cpp:114

A custom std::array with 256 entries, that also has a print function.

LLVM_DUMP_METHOD void dump() const

Definition HashRecognize.cpp:532

void print(raw_ostream &OS) const

Definition HashRecognize.cpp:524

static KnownBits makeConstant(const APInt &C)

Create known bits from a known constant.

unsigned getBitWidth() const

Get the bit width of this value.

The adaptor from a function pass to a loop pass computes these analyses and makes them available to t...

The structure that is returned when a polynomial algorithm was recognized by the analysis.

PolynomialInfo(unsigned TripCount, Value *LHS, const APInt &RHS, Value *ComputedValue, bool ByteOrderSwapped, Value *LHSAux=nullptr)

Definition HashRecognize.cpp:344