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

1

2

3

4

5

6

7

8

9

10

11

12

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

28#include

29#include

30

31using namespace llvm;

32

33

34

36 "hexagon-widen-short-vector",

37 cl::desc("Generate widening instructions for short vectors."), cl::Hidden);

38

39namespace llvm {

42}

43

44namespace {

45

46class HexagonGenWideningVecInstr : public FunctionPass {

47public:

48 static char ID;

49

52 }

53

54 HexagonGenWideningVecInstr(const HexagonTargetMachine *TM)

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

57 }

58

59 StringRef getPassName() const override {

60 return "Hexagon generate widening vector instructions";

61 }

62

64

65 void getAnalysisUsage(AnalysisUsage &AU) const override {

66 FunctionPass::getAnalysisUsage(AU);

67 }

68

69private:

71 const HexagonTargetMachine *TM = nullptr;

72 const HexagonSubtarget *HST = nullptr;

73 unsigned HwVLen;

74 enum OPKind { OP_None = 0, OP_Add, OP_Sub, OP_Mul, OP_Shl };

75

76 struct OPInfo {

77 Value *OP = nullptr;

78 Value *ExtInOP = nullptr;

79 bool IsZExt = false;

80 unsigned ExtInSize = 0;

81 bool IsScalar = false;

82 };

83

84 bool visitBlock(BasicBlock *B);

85 bool processInstruction(Instruction *Inst);

86 bool replaceWithIntrinsic(Instruction *Inst, OPKind OPK, OPInfo &OP1Info,

87 OPInfo &OP2Info);

89 bool isExtendedConstant(Constant *C, bool IsSigned);

90 unsigned getElementSizeInBits(Value *V, bool IsZExt);

92

94 unsigned NewEltsize, unsigned NumElts);

95

96 Intrinsic::ID getIntrinsic(OPKind OPK, bool IsOP1ZExt, bool IsOP2ZExt,

97 unsigned NewOpEltSize, unsigned NewResEltSize,

98 bool IsConstScalar, int ConstOpNum);

99

100 std::pair<Value *, Value *> opSplit(Value *OP, Instruction *Inst,

101 Type *NewOpType);

102

104 Value *NewOP2, Type *ResType, unsigned NumElts,

105 bool Interleave);

106 bool processInstructionForVMPA(Instruction *Inst);

107 bool getVmpaOperandInfo(Value *V, OPInfo &OPI);

108 void reorderVmpaOperands(OPInfo *OPI);

109 bool replaceWithVmpaIntrinsic(Instruction *Inst, OPInfo *OPI);

110 bool genSaturatingInst(Instruction *Inst);

111 bool getMinMax(Constant *MinC, Constant *MaxC, std::pair<int, int> &MinMax);

112 bool isSaturatingVAsr(Instruction *Inst, Value *S, int MinV, int MaxV,

113 bool &IsResSigned);

115 Intrinsic::ID getVAsrIntrinsic(bool IsInSigned, bool IsResSigned);

116 Value *createVAsrIntrinsic(Instruction *Inst, Value *VecOP, Value *ShiftByVal,

117 bool IsResSigned);

118 bool genVAvg(Instruction *Inst);

119 bool checkConstantVector(Value *OP, int64_t &SplatVal, bool IsOPZExt);

120 void updateMPYConst(Intrinsic::ID IntId, int64_t &SplatVal, bool IsOPZExt,

124};

125

126}

127

128char HexagonGenWideningVecInstr::ID = 0;

129

131 "Hexagon generate "

132 "widening vector instructions",

133 false, false)

136 "Hexagon generate "

137 "widening vector instructions",

139

141 if (Value *SplatV = C->getSplatValue()) {

142 auto *CI = dyn_cast(SplatV);

143 assert(CI);

144 return CI->getValue().isNegative();

145 }

147 for (unsigned i = 0, e = NumElts; i != e; ++i) {

150 if (CI->getValue().isNegative())

151 return true;

152 continue;

153 }

154 return false;

155}

156

157bool HexagonGenWideningVecInstr::getOperandInfo(Value *V, OPInfo &OPI) {

158 using namespace PatternMatch;

159 OPI.OP = V;

160 Value *ExtV = nullptr;

162

163 bool Match = false;

167 m_Poison(), m_ZeroMask()))))) {

168 OPI.ExtInOP = ExtV;

169 OPI.IsZExt = true;

170 }

171

172 if (!Match &&

176 m_Poison(), m_ZeroMask()))))) {

177 OPI.ExtInOP = ExtV;

178 OPI.IsZExt = false;

179 }

180 if (!Match &&

181 (Match =

183 m_Poison(), m_ZeroMask()))))) {

185 OPI.ExtInOP = ExtV;

186 OPI.IsZExt = true;

187 OPI.ExtInSize = 8;

188 return true;

189 }

191 OPI.ExtInOP = ExtV;

192 OPI.IsZExt = true;

193 OPI.ExtInSize = 16;

194 return true;

195 }

196 return false;

197 }

198

200 if (!isExtendedConstant(C, false) && !isExtendedConstant(C, true))

201 return false;

202 OPI.ExtInOP = C;

204 }

205

206 if (!Match)

207 return false;

208

209

210 if (OPI.ExtInOP)

211 OPI.ExtInSize = getElementSizeInBits(OPI.ExtInOP, OPI.IsZExt);

212 return true;

213}

214

215bool HexagonGenWideningVecInstr::isExtendedConstant(Constant *C,

216 bool IsSigned) {

219 unsigned HalfSize = EltSize / 2;

220 if (Value *SplatV = C->getSplatValue()) {

222 return IsSigned ? isIntN(HalfSize, CI->getSExtValue())

223 : isUIntN(HalfSize, CI->getZExtValue());

224 return false;

225 }

227 for (unsigned i = 0, e = NumElts; i != e; ++i) {

229 if ((IsSigned && isIntN(HalfSize, CI->getSExtValue())) ||

230 (!IsSigned && isUIntN(HalfSize, CI->getZExtValue())))

231 return false;

232 continue;

233 }

234 return false;

235 }

236 return true;

237}

238

239unsigned HexagonGenWideningVecInstr::getElementSizeInBits(Value *V,

240 bool IsZExt = false) {

241 using namespace PatternMatch;

242 Type *ValTy = V->getType();

243 Type *EltTy = ValTy;

247 ->getElementType()

248 ->getPrimitiveSizeInBits()

249 .getKnownMinValue();

250 unsigned ReducedSize = EltSize / 2;

251

252 while (ReducedSize >= 8) {

253 for (unsigned i = 0, e = NumElts; i != e; ++i) {

255 if (IsZExt) {

256 if (isUIntN(ReducedSize, CI->getZExtValue()))

257 return EltSize;

258 } else if (isIntN(ReducedSize, CI->getSExtValue()))

259 return EltSize;

260 }

261 }

262 EltSize = ReducedSize;

263 ReducedSize = ReducedSize / 2;

264 }

265 return EltSize;

266 }

267

271}

272

273Value *HexagonGenWideningVecInstr::adjustExtensionForOp(OPInfo &OPI,

275 unsigned NewExtSize,

276 unsigned NumElts) {

277 Value *V = OPI.ExtInOP;

278 bool IsZExt = OPI.IsZExt;

279 unsigned EltSize = getElementSizeInBits(OPI.ExtInOP, OPI.IsZExt);

280 Type *EltType = getElementTy(NewExtSize, IRB);

282

285

286 if (V->getType()->isVectorTy()) {

287 if (NewExtSize == EltSize)

288 return V;

289 assert(NewExtSize == 16);

292 }

293

294

295

296

298 assert(I && I->getOpcode() == Instruction::ShuffleVector);

299

300 if (NewExtSize > EltSize)

302 else if (NewExtSize < EltSize)

304

307

309 for (unsigned i = 0; i < NumElts; ++i)

311

314}

315

316Intrinsic::ID HexagonGenWideningVecInstr::getIntrinsic(

317 OPKind OPK, bool IsOP1ZExt, bool IsOP2ZExt, unsigned InEltSize,

318 unsigned ResEltSize, bool IsConstScalar, int ConstOpNum) {

319

320 switch (OPK) {

321 case OP_Add:

322

323 assert(IsOP1ZExt == IsOP2ZExt);

324 if (InEltSize == 8 && ResEltSize == 16) {

325

326

327 assert(IsOP1ZExt && "Operands must be zero-extended");

328 return Intrinsic::hexagon_vadd_uu;

329 }

330 if (InEltSize == 16 && ResEltSize == 32)

331 return (IsOP1ZExt) ? Intrinsic::hexagon_vadd_uu

332 : Intrinsic::hexagon_vadd_ss;

333

334 llvm_unreachable("Incorrect input and output operand sizes");

335

336 case OP_Sub:

337

338 assert(IsOP1ZExt == IsOP2ZExt);

339 if (InEltSize == 8 && ResEltSize == 16) {

340

341

342 assert(IsOP1ZExt && "Operands must be zero-extended");

343 return Intrinsic::hexagon_vsub_uu;

344 }

345 if (InEltSize == 16 && ResEltSize == 32)

346 return (IsOP1ZExt) ? Intrinsic::hexagon_vsub_uu

347 : Intrinsic::hexagon_vsub_ss;

348

349 llvm_unreachable("Incorrect input and output operand sizes");

350

351 case OP_Mul:

352 assert(ResEltSize == 2 * InEltSize);

353

354 if (IsConstScalar) {

355

356 if (InEltSize == 8 && ResEltSize == 16) {

357

358

359 if (ConstOpNum == 2 && IsOP1ZExt) {

360

361

362 return (IsOP2ZExt) ? Intrinsic::hexagon_vmpy_ub_ub

363 : Intrinsic::hexagon_vmpy_ub_b;

364 } else if (ConstOpNum == 1 && IsOP2ZExt) {

365 return (IsOP1ZExt) ? Intrinsic::hexagon_vmpy_ub_ub

366 : Intrinsic::hexagon_vmpy_ub_b;

367 }

368 }

369

370

371 if (InEltSize == 16 && ResEltSize == 32) {

372 if (IsOP1ZExt && IsOP2ZExt) {

373

374

375 return Intrinsic::hexagon_vmpy_uh_uh;

376 } else if (!IsOP1ZExt && !IsOP2ZExt) {

377

378

379 return Intrinsic::hexagon_vmpy_h_h;

380 }

381 }

382 }

383 if (IsOP1ZExt)

384 return IsOP2ZExt ? Intrinsic::hexagon_vmpy_uu

385 : Intrinsic::hexagon_vmpy_us;

386 else

387 return IsOP2ZExt ? Intrinsic::hexagon_vmpy_su

388 : Intrinsic::hexagon_vmpy_ss;

389 default:

391 }

392}

393

394Type *HexagonGenWideningVecInstr::getElementTy(unsigned size,

396 switch (size) {

397 case 8:

399 case 16:

401 case 32:

403 default:

405 }

406}

407

408Value *HexagonGenWideningVecInstr::createIntrinsic(

410 Type *ResType, unsigned NumElts, bool Interleave = true) {

414 if (Interleave) {

415

417 unsigned HalfElts = NumElts / 2;

418 for (unsigned i = 0; i < HalfElts; ++i) {

421 }

424 }

425 return NewIn;

426}

427

428std::pair<Value *, Value *>

429HexagonGenWideningVecInstr::opSplit(Value *OP, Instruction *Inst,

430 Type *NewOpType) {

435

436

437

438

439

440 assert(NumElts % 2 == 0 && "Unexpected Vector Type!!");

441 unsigned HalfElts = NumElts / 2;

444 for (unsigned i = 0; i < HalfElts; ++i)

446 for (unsigned i = 0; i < HalfElts; ++i)

448

453 return std::pair<Value *, Value *>(Hi, Lo);

454 }

455

456 Intrinsic::ID IntHi = Intrinsic::hexagon_V6_hi_128B;

457 Intrinsic::ID IntLo = Intrinsic::hexagon_V6_lo_128B;

466 return std::pair<Value *, Value *>(Hi, Lo);

467}

468

469bool HexagonGenWideningVecInstr::checkConstantVector(Value *OP,

470 int64_t &SplatVal,

471 bool IsOPZExt) {

473 if (Value *SplatV = C1->getSplatValue()) {

475 if (IsOPZExt) {

476 SplatVal = CI->getZExtValue();

477 } else {

478 SplatVal = CI->getSExtValue();

479 }

480 return true;

481 }

482 }

483 return false;

484}

485

486void HexagonGenWideningVecInstr::updateMPYConst(Intrinsic::ID IntId,

487 int64_t &SplatVal,

488 bool IsOPZExt, Value *&OP,

490 if ((IntId == Intrinsic::hexagon_vmpy_uu ||

491 IntId == Intrinsic::hexagon_vmpy_us ||

492 IntId == Intrinsic::hexagon_vmpy_su ||

493 IntId == Intrinsic::hexagon_vmpy_ss) &&

494 OP->getType()->isVectorTy()) {

495

497 Value *scalar = IRB.getIntN(VecTy->getScalarSizeInBits(),

498 static_cast<uint32_t>(SplatVal));

501 OP = IsOPZExt ? IRB.CreateZExt(splatVector, VecTy)

502 : IRB.CreateSExt(splatVector, VecTy);

503 } else {

504 packConstant(IntId, SplatVal, OP, IRB);

505 }

506}

507

508void HexagonGenWideningVecInstr::packConstant(Intrinsic::ID IntId,

509 int64_t &SplatVal, Value *&OP,

511 uint32_t Val32 = static_cast<uint32_t>(SplatVal);

512 if (IntId == Intrinsic::hexagon_vmpy_ub_ub) {

513 assert(SplatVal >= 0 && SplatVal <= UINT8_MAX);

514 uint32_t packed = (Val32 << 24) | (Val32 << 16) | (Val32 << 8) | Val32;

516 } else if (IntId == Intrinsic::hexagon_vmpy_ub_b) {

517 assert(SplatVal >= INT8_MIN && SplatVal <= INT8_MAX);

518 uint32_t packed = (Val32 << 24) | ((Val32 << 16) & ((1 << 24) - 1)) |

519 ((Val32 << 8) & ((1 << 16) - 1)) |

520 (Val32 & ((1 << 8) - 1));

522 } else if (IntId == Intrinsic::hexagon_vmpy_uh_uh) {

523 assert(SplatVal >= 0 && SplatVal <= UINT16_MAX);

524 uint32_t packed = (Val32 << 16) | Val32;

526 } else if (IntId == Intrinsic::hexagon_vmpy_h_h) {

527 assert(SplatVal >= INT16_MIN && SplatVal <= INT16_MAX);

528 uint32_t packed = (Val32 << 16) | (Val32 & ((1 << 16) - 1));

530 }

531}

532

533bool HexagonGenWideningVecInstr::replaceWithIntrinsic(Instruction *Inst,

534 OPKind OPK,

535 OPInfo &OP1Info,

536 OPInfo &OP2Info) {

541

542 bool IsOP1ZExt = OP1Info.IsZExt;

543 bool IsOP2ZExt = OP2Info.IsZExt;

544

545

546 bool IsResZExt = (OPK == OP_Mul || OPK == OP_Shl)

547 ? (OP1Info.IsZExt && OP2Info.IsZExt)

548 : false;

549

550 unsigned MaxEltSize = std::max(OP1Info.ExtInSize, OP2Info.ExtInSize);

551 unsigned NewOpEltSize = MaxEltSize;

552 unsigned NewResEltSize = 2 * MaxEltSize;

553

554

555

556

557

558

559

560 if (OPK != OP_Mul && OPK != OP_Shl &&

561 (IsOP1ZExt != IsOP2ZExt || (!IsOP1ZExt && NewOpEltSize == 8)))

562 NewOpEltSize = 2 * NewOpEltSize;

563

564 unsigned ResVLen = NewResEltSize * NumElts;

566 return false;

567 if (NewOpEltSize > 16 || ((ResVLen > HwVLen) && (ResVLen % HwVLen) != 0))

568 return false;

569

571 Value *NewOP1 = adjustExtensionForOp(OP1Info, IRB, NewOpEltSize, NumElts);

572 Value *NewOP2 = adjustExtensionForOp(OP2Info, IRB, NewOpEltSize, NumElts);

573

574 if (NewOpEltSize == NewResEltSize) {

575 assert(OPK != OP_Mul && OPK != OP_Shl);

576

578 NewOP1, NewOP2);

579 if (InstEltSize > NewResEltSize)

580 NewIn = IRB.CreateSExt(NewIn, InstTy);

582 return true;

583 }

584

585 bool IsConstScalar = false;

586 int64_t SplatVal = 0;

587 int ConstOpNum = 1;

588 if (OPK == OP_Mul || OPK == OP_Shl) {

589 IsConstScalar = checkConstantVector(NewOP1, SplatVal, IsOP1ZExt);

590 if (!IsConstScalar) {

591 IsConstScalar = checkConstantVector(NewOP2, SplatVal, IsOP2ZExt);

592 ConstOpNum = 2;

593 }

594 }

595

596 if (IsConstScalar && OPK == OP_Shl) {

597 if (((NewOpEltSize == 8) && (SplatVal > 0) && (SplatVal < 8)) ||

598 ((NewOpEltSize == 16) && (SplatVal > 0) && (SplatVal < 16))) {

599 SplatVal = 1LL << SplatVal;

600 OPK = OP_Mul;

601 } else {

602 return false;

603 }

604 } else if (!IsConstScalar && OPK == OP_Shl) {

605 return false;

606 }

607

608 Intrinsic::ID IntId = getIntrinsic(OPK, IsOP1ZExt, IsOP2ZExt, NewOpEltSize,

609 NewResEltSize, IsConstScalar, ConstOpNum);

610

611 if (IsConstScalar) {

612 updateMPYConst(IntId, SplatVal, IsOP2ZExt, NewOP2, IRB);

613 }

614

615

616 if (ResVLen > 2 * HwVLen) {

617 assert(ResVLen == 4 * HwVLen);

618

619 unsigned HalfElts = NumElts / 2;

620 auto *NewOpType =

622 auto *ResType =

624 std::pair<Value *, Value *> SplitOP1 = opSplit(NewOP1, Inst, NewOpType);

625 std::pair<Value *, Value *> SplitOP2;

626 if (IsConstScalar && (IntId == Intrinsic::hexagon_vmpy_h_h ||

627 IntId == Intrinsic::hexagon_vmpy_uh_uh)) {

628 SplitOP2 = std::pair<Value *, Value *>(NewOP2, NewOP2);

629 } else {

630 SplitOP2 = opSplit(NewOP2, Inst, NewOpType);

631 }

632 Value *NewInHi = createIntrinsic(IntId, Inst, SplitOP1.first,

633 SplitOP2.first, ResType, HalfElts, true);

634 Value *NewInLo = createIntrinsic(IntId, Inst, SplitOP1.second,

635 SplitOP2.second, ResType, HalfElts, true);

636 assert(InstEltSize == NewResEltSize);

638 for (unsigned i = 0; i < NumElts; ++i)

640

643

645 return true;

646 }

647

648 auto *ResType =

651 createIntrinsic(IntId, Inst, NewOP1, NewOP2, ResType, NumElts, true);

652 if (InstEltSize > NewResEltSize)

653 NewIn = (IsResZExt) ? IRB.CreateZExt(NewIn, InstTy)

655

657

658 return true;

659}

660

661

662

663bool HexagonGenWideningVecInstr::processInstruction(Instruction *Inst) {

667 return false;

670 return false;

672 return false;

673

674 using namespace PatternMatch;

675

676 OPKind OPK;

679 OPK = OP_Sub;

681 OPK = OP_Add;

683 OPK = OP_Mul;

685 OPK = OP_Shl;

686 else

687 return false;

688

689 OPInfo OP1Info, OP2Info;

690

692 return false;

693

694

695 if (!OP1Info.ExtInOP || !OP2Info.ExtInOP)

696 return false;

697

698 return replaceWithIntrinsic(Inst, OPK, OP1Info, OP2Info);

699}

700

701bool HexagonGenWideningVecInstr::getVmpaOperandInfo(Value *V, OPInfo &OPI) {

702 using namespace PatternMatch;

703 OPI.OP = V;

705

708 m_Poison(), m_ZeroMask()))) ||

711 m_Poison(), m_ZeroMask()))) {

712 OPI.ExtInOP = ExtV;

713 OPI.IsZExt = true;

714 OPI.IsScalar = true;

716 return true;

717 }

718

719 ConstantInt *I = nullptr;

721 m_Poison(), m_ZeroMask())))) {

723 uint32_t IValue = I->getZExtValue();

724 if (IValue <= 255) {

725 OPI.ExtInOP = ExtV;

726 OPI.IsZExt = true;

727 OPI.ExtInSize = 8;

728 OPI.IsScalar = true;

729 return true;

730 }

731 }

732 }

733

734

736}

737

738

739bool HexagonGenWideningVecInstr::processInstructionForVMPA(Instruction *Inst) {

740 using namespace PatternMatch;

742

743

745 return false;

746

749 return false;

750

751 Value *OP[4] = {nullptr, nullptr, nullptr, nullptr};

754 return false;

755

756 OPInfo OP_Info[4];

757 for (unsigned i = 0; i < 4; i++)

758 if (!getVmpaOperandInfo(OP[i], OP_Info[i]) || !OP_Info[i].ExtInOP)

759 return false;

760

761 return replaceWithVmpaIntrinsic(Inst, OP_Info);

762}

763

764

765

766void HexagonGenWideningVecInstr::reorderVmpaOperands(OPInfo *OPI) {

767 for (unsigned i = 0; i < 2; i++)

768 if (!OPI[2 * i].ExtInOP->getType()->isVectorTy()) {

769 OPInfo Temp;

770 Temp = OPI[2 * i];

771 OPI[2 * i] = OPI[2 * i + 1];

772 OPI[2 * i + 1] = Temp;

773 }

774}

775

776

777

778

779bool HexagonGenWideningVecInstr::replaceWithVmpaIntrinsic(Instruction *Inst,

780 OPInfo *OPI) {

781 reorderVmpaOperands(OPI);

782

783

784

785 if (!OPI[1].IsScalar || !OPI[3].IsScalar || OPI[0].IsScalar ||

786 OPI[2].IsScalar)

787 return false;

788

789 OPInfo SOPI1 = OPI[1];

790 OPInfo SOPI2 = OPI[3];

791

792

793 if (SOPI1.ExtInSize != SOPI2.ExtInSize || SOPI1.ExtInSize != 8)

794 return false;

795

800

801 unsigned MaxVEltSize = std::max(OPI[0].ExtInSize, OPI[2].ExtInSize);

802 unsigned NewVOpEltSize = MaxVEltSize;

803 unsigned NewResEltSize = 2 * MaxVEltSize;

804

805 if (NumElts * NewVOpEltSize < HwVLen) {

806

807 NewVOpEltSize = 2 * NewVOpEltSize;

808 NewResEltSize = 2 * NewResEltSize;

809 }

810

812

813

814 Value *NewSOP1 = SOPI1.ExtInOP;

815 Value *NewSOP2 = SOPI2.ExtInOP;

816

823

826 Intrinsic::ID CombineIntID = Intrinsic::hexagon_A2_combine_ll;

829

830

831 Value *NewVOP1 = adjustExtensionForOp(OPI[0], IRB, NewVOpEltSize, NumElts);

832 Value *NewVOP2 = adjustExtensionForOp(OPI[2], IRB, NewVOpEltSize, NumElts);

833

834

835 Intrinsic::ID VCombineIntID = Intrinsic::hexagon_V6_vcombine_128B;

841

843 ? Intrinsic::hexagon_V6_vmpabus_128B

844 : Intrinsic::hexagon_V6_vmpauhb_128B;

846 auto *ResType =

850

851 if (InstEltSize > NewResEltSize)

852

853 NewIn = IRB.CreateSExt(NewIn, InstTy);

854

855

857 unsigned HalfElts = NumElts / 2;

858 for (unsigned i = 0; i < HalfElts; ++i) {

861 }

864

866 return true;

867}

868

869bool HexagonGenWideningVecInstr::genSaturatingInst(Instruction *Inst) {

873 return false;

874

875 using namespace PatternMatch;

876 CmpPredicate P1, P2;

877 Value *L1 = nullptr, *T1 = nullptr, *L2 = nullptr, *T2 = nullptr,

878 *L3 = nullptr;

879 Constant *RC1 = nullptr, *FC1 = nullptr, *RC2 = nullptr, *FC2 = nullptr,

880 *RC3 = nullptr;

881

882

883

886

888

890 std::pair<int, int> MinMax;

891

892 if (getMinMax(RC1, RC2, MinMax)) {

893 bool IsResSigned;

894

895 if (isSaturatingVAsr(Inst, L2, MinMax.first, MinMax.second,

896 IsResSigned)) {

897

898 ConstantInt *shift_val =

900 if (shift_val) {

902 createVAsrIntrinsic(Inst, L3, shift_val, IsResSigned);

904 return true;

905 }

906 }

907 }

908 }

909 }

910 }

911

914 (T1 != L1 || FC1 != RC1))

915 return false;

916

919 (T2 != L2 || FC2 != RC2))

920 return false;

921

924 return false;

925

926 std::pair<int, int> MinMax;

928 if (!getMinMax(RC1, RC2, MinMax))

929 return false;

930 } else if (!getMinMax(RC2, RC1, MinMax))

931 return false;

932

933 Value *S = L2;

934

935

936

937 Value *OP1 = nullptr, *ShiftByVal = nullptr;

942 return false;

943

944 bool IsResSigned;

945 if (!isSaturatingVAsr(Inst, S, MinMax.first, MinMax.second, IsResSigned))

946 return false;

947

948 Value *NewIn = createVAsrIntrinsic(Inst, OP1, ShiftByVal, IsResSigned);

950 return true;

951}

952

953Value *HexagonGenWideningVecInstr::extendShiftByVal(Value *ShiftByVal,

955 using namespace PatternMatch;

958 return A;

960}

961

962bool HexagonGenWideningVecInstr::getMinMax(Constant *MinC, Constant *MaxC,

963 std::pair<int, int> &MinMax) {

966 return false;

968 return false;

969

973 return true;

974}

975

976bool HexagonGenWideningVecInstr::isSaturatingVAsr(Instruction *Inst, Value *S,

977 int MinV, int MaxV,

978 bool &IsResSigned) {

979 if (MinV >= MaxV)

980 return false;

981

982 IsResSigned = true;

986

987 int MaxRange, MinRange;

988 if (MinV < 0) {

989 MaxRange = (1 << (TruncSize - 1)) - 1;

990 MinRange = -(1 << (TruncSize - 1));

991 } else if (MinV == 0) {

992 MaxRange = (1 << (TruncSize)) - 1;

993 MinRange = 0;

994 IsResSigned = false;

995 } else

996 return false;

997

998 if (MinV != MinRange || MaxV != MaxRange)

999 return false;

1000

1002 if (SInst->getOpcode() == Instruction::AShr) {

1003 Type *SInstTy = SInst->getType();

1006 if (SInstEltSize != 2 * TruncSize || TruncSize > 16)

1007 return false;

1008 }

1009 return true;

1010}

1011

1012Intrinsic::ID HexagonGenWideningVecInstr::getVAsrIntrinsic(bool IsInSigned,

1013 bool IsResSigned) {

1014 if (!IsResSigned)

1015 return (IsInSigned) ? Intrinsic::hexagon_vasrsat_su

1016 : Intrinsic::hexagon_vasrsat_uu;

1017 return Intrinsic::hexagon_vasrsat_ss;

1018}

1019

1020Value *HexagonGenWideningVecInstr::createVAsrIntrinsic(Instruction *Inst,

1022 Value *ShiftByVal,

1023 bool IsResSigned) {

1025 Type *ShiftByTy = ShiftByVal->getType();

1027 ShiftByVal = extendShiftByVal(ShiftByVal, IRB);

1028

1033

1034

1035

1036

1038 unsigned HalfElts = NumElts / 2;

1039

1040 for (unsigned i = 0; i < HalfElts; ++i)

1042

1043 for (unsigned i = 0; i < HalfElts; ++i)

1045

1048

1049 auto *InVecOPTy =

1051 std::pair<Value *, Value *> HiLo = opSplit(VecOP, Inst, InVecOPTy);

1052 Intrinsic::ID IntID = getVAsrIntrinsic(true, IsResSigned);

1054 Value *NewIn = IRB.CreateCall(F, {HiLo.first, HiLo.second, ShiftByVal});

1056}

1057

1058

1059bool HexagonGenWideningVecInstr::genVAvg(Instruction *Inst) {

1060 using namespace PatternMatch;

1063

1064 bool Match = false;

1066 bool IsSigned;

1070 IsSigned = false;

1071 if (!Match &&

1077 IsSigned = true;

1078

1079 if (!Match)

1080 return false;

1081

1082 unsigned OP1EltSize = getElementSizeInBits(OP1);

1083 unsigned OP2EltSize = getElementSizeInBits(OP2);

1084 unsigned NewEltSize = std::max(OP1EltSize, OP2EltSize);

1085

1089

1090

1091

1092 if (InstEltSize < NewEltSize || (InstLen > 2 * HwVLen))

1093 return false;

1094

1095 if ((InstLen > HwVLen) && (InstLen % HwVLen != 0))

1096 return false;

1097

1100 auto *AvgInstTy =

1102 if (OP1EltSize < NewEltSize)

1103 OP1 = (IsSigned) ? IRB.CreateSExt(OP1, AvgInstTy)

1105 if (OP2EltSize < NewEltSize)

1106 OP2 = (IsSigned) ? IRB.CreateSExt(OP2, AvgInstTy)

1108

1110 (IsSigned) ? Intrinsic::hexagon_vavgs : Intrinsic::hexagon_vavgu;

1111 Value *NewIn = nullptr;

1112

1113

1114 if (NewEltSize * NumElts > HwVLen) {

1115 unsigned HalfElts = NumElts / 2;

1116 auto *ResType =

1118 std::pair<Value *, Value *> SplitOP1 = opSplit(OP1, Inst, ResType);

1119 std::pair<Value *, Value *> SplitOP2 = opSplit(OP2, Inst, ResType);

1120 Value *NewHi = createIntrinsic(AvgIntID, Inst, SplitOP1.first,

1121 SplitOP2.first, ResType, NumElts, false);

1122 Value *NewLo = createIntrinsic(AvgIntID, Inst, SplitOP1.second,

1123 SplitOP2.second, ResType, NumElts, false);

1125 for (unsigned i = 0; i < NumElts; ++i)

1127

1128 NewIn =

1130 } else

1131 NewIn =

1132 createIntrinsic(AvgIntID, Inst, OP1, OP2, AvgInstTy, NumElts, false);

1133

1134 if (InstEltSize > NewEltSize)

1135

1136 NewIn = (IsSigned) ? IRB.CreateSExt(NewIn, InstTy)

1139 return true;

1140}

1141

1142bool HexagonGenWideningVecInstr::visitBlock(BasicBlock *B) {

1144 for (auto &I : *B) {

1145 Type *InstTy = I.getType();

1147 continue;

1148

1151 continue;

1152

1153 Changed |= processInstructionForVMPA(&I);

1154 Changed |= genSaturatingInst(&I);

1156 }

1157

1158 for (auto &I : *B)

1159 Changed |= processInstruction(&I);

1161}

1162

1163bool HexagonGenWideningVecInstr::runOnFunction(Function &F) {

1164 M = F.getParent();

1166

1167

1168

1169

1171 return false;

1172

1173 HwVLen = HST->getVectorLength() * 8;

1175 for (auto &B : F)

1177

1179}

1180

1181FunctionPass *

1183 return new HexagonGenWideningVecInstr(&TM);

1184}

for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))

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< ErlangGC > A("erlang", "erlang-compatible garbage collector")

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)

widening Hexagon generate widening vector static false bool hasNegativeValues(Constant *C)

Definition HexagonGenWideningVecInstr.cpp:140

static cl::opt< bool > WidenShortVector("hexagon-widen-short-vector", cl::desc("Generate widening instructions for short vectors."), cl::Hidden)

Machine Check Debug Module

#define INITIALIZE_PASS_DEPENDENCY(depName)

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

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

static std::optional< OperandInfo > getOperandInfo(const MachineOperand &MO)

static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)

Returns the opcode of Values or ~0 if they do not all agree.

@ ICMP_SLT

signed less than

@ ICMP_SGT

signed greater than

int64_t getSExtValue() const

Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...

static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)

Return a ConstantVector with the specified constant in each element.

static LLVM_ABI Constant * get(ArrayRef< Constant * > V)

This is an important base class in LLVM.

LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const

If all elements of the vector constant have the same value, return that value.

Legacy analysis pass which computes a DominatorTree.

static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)

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

unsigned getVectorLength() const

bool useHVX128BOps() const

bool isTypeForHVX(Type *VecTy, bool IncludeBool=false) const

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

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

Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")

Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")

IntegerType * getInt32Ty()

Fetch the type representing a 32-bit integer.

IntegerType * getInt16Ty()

Fetch the type representing a 16-bit integer.

ConstantInt * getInt32(uint32_t C)

Get a constant 32-bit value.

Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")

ConstantInt * getIntN(unsigned N, uint64_t C)

Get a constant N-bit value, zero extended or truncated from a 64-bit value.

Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)

Value * CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name="")

CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)

Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)

Value * CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)

Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)

IntegerType * getInt8Ty()

Fetch the type representing an 8-bit integer.

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)

bool isVectorTy() const

True if this is an instance of VectorType.

LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY

Return the basic size of this type if it is a primitive type.

LLVM Value Representation.

Type * getType() const

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

LLVM_ABI void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

#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.

@ SHL

Shift and rotation operations.

LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})

Look up the Function declaration of the intrinsic id in the Module M.

class_match< PoisonValue > m_Poison()

Match an arbitrary poison constant.

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

BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)

BinaryOp_match< LHS, RHS, Instruction::AShr > m_AShr(const LHS &L, const RHS &R)

class_match< Constant > m_Constant()

Match an arbitrary Constant and ignore it.

CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)

Matches Trunc.

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)

class_match< ConstantInt > m_ConstantInt()

Match an arbitrary ConstantInt and ignore it.

IntrinsicID_match m_Intrinsic()

Match intrinsic calls like this: m_IntrinsicIntrinsic::fabs(m_Value(X))

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::Mul > m_Mul(const LHS &L, const RHS &R)

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

Matches ShuffleVectorInst independently of mask value.

CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)

Matches ZExt.

class_match< Value > m_Value()

Match an arbitrary value and ignore it.

BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)

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

BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)

CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)

Matches SExt.

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.

BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)

support::detail::packed_endian_specific_integral< T, E, support::unaligned > packed

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)

Get the size of a range.

decltype(auto) dyn_cast(const From &Val)

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

constexpr bool isUIntN(unsigned N, uint64_t x)

Checks if an unsigned integer fits into the given (dynamic) bit width.

void initializeHexagonGenWideningVecInstrPass(PassRegistry &)

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

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.

constexpr bool isIntN(unsigned N, int64_t x)

Checks if an signed integer fits into the given (dynamic) bit width.

FunctionPass * createHexagonGenWideningVecInstr(const HexagonTargetMachine &)

Definition HexagonGenWideningVecInstr.cpp:1182