LLVM: lib/Target/AArch64/AArch64ExpandImm.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

16

17using namespace llvm;

19

20

21

23 assert(ChunkIdx < 4 && "Out of range chunk index specified!");

24

25 return (Imm >> (ChunkIdx * 16)) & 0xFFFF;

26}

27

28

29

31 Chunk = (Chunk << 48) | (Chunk << 32) | (Chunk << 16) | Chunk;

32

34}

35

36

37

38

39

40

41

42

46

47 CountMap Counts;

48

49

50 for (unsigned Idx = 0; Idx < 4; ++Idx)

51 ++Counts[getChunk(UImm, Idx)];

52

53

54 for (const auto &Chunk : Counts) {

55 const uint64_t ChunkVal = Chunk.first;

56 const unsigned Count = Chunk.second;

57

59

60

61

63 continue;

64

65 const bool CountThree = Count == 3;

66

67 Insn.push_back({ AArch64::ORRXri, 0, Encoding });

68

69 unsigned ShiftAmt = 0;

71

72 for (; ShiftAmt < 64; ShiftAmt += 16) {

73 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;

74

75 if (Imm16 != ChunkVal)

76 break;

77 }

78

79

80 Insn.push_back({ AArch64::MOVKXi, Imm16,

82

83

84

85 if (CountThree)

86 return true;

87

88

89 for (ShiftAmt += 16; ShiftAmt < 64; ShiftAmt += 16) {

90 Imm16 = (UImm >> ShiftAmt) & 0xFFFF;

91

92 if (Imm16 != ChunkVal)

93 break;

94 }

95 Insn.push_back({ AArch64::MOVKXi, Imm16,

97 return true;

98 }

99

100 return false;

101}

102

103

104

105

107 if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())

108 return false;

109

111}

112

113

114

115

117 if (Chunk == 0 || Chunk == std::numeric_limits<uint64_t>::max())

118 return false;

119

121}

122

123

125 const uint64_t Mask = 0xFFFF;

126

127 if (Clear)

128

129 Imm &= ~(Mask << (Idx * 16));

130 else

131

132 Imm |= Mask << (Idx * 16);

133

134 return Imm;

135}

136

137

138

139

140

141

142

143

144

145

146

147

148

149

152 const int NotSet = -1;

153 const uint64_t Mask = 0xFFFF;

154

155 int StartIdx = NotSet;

156 int EndIdx = NotSet;

157

158 for (int Idx = 0; Idx < 4; ++Idx) {

159 int64_t Chunk = getChunk(UImm, Idx);

160

161 Chunk = (Chunk << 48) >> 48;

162

164 StartIdx = Idx;

166 EndIdx = Idx;

167 }

168

169

170 if (StartIdx == NotSet || EndIdx == NotSet)

171 return false;

172

173

175

177

178

179

180

181 if (StartIdx > EndIdx) {

184 }

185

187 int FirstMovkIdx = NotSet;

188 int SecondMovkIdx = NotSet;

189

190

191

192 for (int Idx = 0; Idx < 4; ++Idx) {

194

195

196

197 if ((Idx < StartIdx || EndIdx < Idx) && Chunk != Outside) {

198 OrrImm = updateImm(OrrImm, Idx, Outside == 0);

199

200

201 if (FirstMovkIdx == NotSet)

202 FirstMovkIdx = Idx;

203 else

204 SecondMovkIdx = Idx;

205

206

207

208 } else if (Idx > StartIdx && Idx < EndIdx && Chunk != Inside) {

209 OrrImm = updateImm(OrrImm, Idx, Inside != Mask);

210

211

212 if (FirstMovkIdx == NotSet)

213 FirstMovkIdx = Idx;

214 else

215 SecondMovkIdx = Idx;

216 }

217 }

218 assert(FirstMovkIdx != NotSet && "Constant materializable with single ORR!");

219

220

223 Insn.push_back({ AArch64::ORRXri, 0, Encoding });

224

225 const bool SingleMovk = SecondMovkIdx == NotSet;

228 FirstMovkIdx * 16) });

229

230

231 if (SingleMovk)

232 return true;

233

234

237 SecondMovkIdx * 16) });

238

239 return true;

240}

241

244

246 if (NumOnes == 64) {

247 UnshiftedOnes = ~0ULL;

248 } else {

249 UnshiftedOnes = (1ULL << NumOnes) - 1;

250 }

251 return UnshiftedOnes << StartPosition;

252}

253

256

257

258 for (uint64_t i = 0; i < 6; ++i) {

259 uint64_t Rotation = 1ULL << (6 - i);

261 if (Closure != (Closure & V)) {

262 break;

263 }

264 Result = Closure;

265 }

266

267 return Result;

268}

269

270

271

274

276

277

279

280

281

283

284 return MaximalImm;

285}

286

287static std::optional<std::pair<uint64_t, uint64_t>>

289 if (UImm == 0 || ~UImm == 0)

290 return std::nullopt;

291

292

295

296

298

299

300 uint64_t RemainingBits = RotatedBits & ~MaximalImm1;

301

302

303

305

306

307 if (RemainingBits & ~MaximalImm2)

308 return std::nullopt;

309

310

311 return std::make_pair(rotl(MaximalImm1, InitialTrailingOnes),

312 rotl(MaximalImm2, InitialTrailingOnes));

313}

314

315

319 if (MaybeDecomposition == std::nullopt)

320 return false;

321 uint64_t Imm1 = MaybeDecomposition->first;

322 uint64_t Imm2 = MaybeDecomposition->second;

323

324 uint64_t Encoding1, Encoding2;

327

328 if (Imm1Success && Imm2Success) {

329

330 Insn.push_back({AArch64::ORRXri, 0, Encoding1});

331 Insn.push_back({AArch64::ORRXri, 1, Encoding2});

332 return true;

333 }

334

335 return false;

336}

337

338

339

340

343

345 if (MaybeDecomposition == std::nullopt)

346 return false;

347 uint64_t Imm1 = MaybeDecomposition->first;

348 uint64_t Imm2 = MaybeDecomposition->second;

349

350 uint64_t Encoding1, Encoding2;

353

354 if (Imm1Success && Imm2Success) {

355

356 Insn.push_back({AArch64::ORRXri, 0, Encoding1});

357

358 Insn.push_back({AArch64::ANDXri, 1, Encoding2});

359 return true;

360 }

361

362 return false;

363}

364

365

366

367

368

369

370

371

372

375

376

377 unsigned BigSize = 64;

378

379 do {

380 BigSize /= 2;

381 uint64_t Mask = (1ULL << BigSize) - 1;

382

383 if ((Imm & Mask) != ((Imm >> BigSize) & Mask)) {

384 BigSize *= 2;

385 break;

386 }

387 } while (BigSize > 2);

388

390

391

392

393

395

396

397

398

399

400

401 int RunsPerBigChunk = popcount(RunStarts & BigMask);

402

403 static const int8_t BigToSmallSizeTable[32] = {

404 -1, -1, 0, 1, 2, 2, -1, 3, 3, 3, -1, -1, -1, -1, -1, 4,

405 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5,

406 };

407

408 int BigToSmallShift = BigToSmallSizeTable[RunsPerBigChunk];

409

410

411

412 if (BigToSmallShift == -1)

413 return false;

414

415 unsigned SmallSize = BigSize >> BigToSmallShift;

416

417

418 static const uint64_t RepeatedOnesTable[] = {

419 0xffffffffffffffff, 0x5555555555555555, 0x1111111111111111,

420 0x0101010101010101, 0x0001000100010001, 0x0000000100000001,

421 0x0000000000000001,

422 };

423

424

425

426

427

429

430

431

432

433

434

437 for (int Attempt = 0; Attempt < 3; ++Attempt) {

438 unsigned RunLength = countr_one(RotatedImm);

439

440

441

442

444 rotl<uint64_t>((SmallOnes << RunLength) - SmallOnes, Rotation);

445 uint64_t BigImm = Imm ^ SmallImm;

446

451 Insn.push_back({AArch64::ORRXri, 0, SmallEncoding});

452 Insn.push_back({AArch64::EORXri, 1, BigEncoding});

453 return true;

454 }

455

456

459 }

460

461 return false;

462}

463

464

465

467 unsigned OneChunks, unsigned ZeroChunks,

469 const unsigned Mask = 0xFFFF;

470

471

472

473

474 bool isNeg = false;

475

476

477

478 if (OneChunks > ZeroChunks) {

480 Imm = ~Imm;

481 }

482

483 unsigned FirstOpc;

484 if (BitSize == 32) {

485 Imm &= (1LL << 32) - 1;

486 FirstOpc = (isNeg ? AArch64::MOVNWi : AArch64::MOVZWi);

487 } else {

488 FirstOpc = (isNeg ? AArch64::MOVNXi : AArch64::MOVZXi);

489 }

490 unsigned Shift = 0;

491 unsigned LastShift = 0;

492 if (Imm != 0) {

495 Shift = (TZ / 16) * 16;

496 LastShift = ((63 - LZ) / 16) * 16;

497 }

498 unsigned Imm16 = (Imm >> Shift) & Mask;

499

500 Insn.push_back({ FirstOpc, Imm16,

502

503 if (Shift == LastShift)

504 return;

505

506

507

509 Imm = ~Imm;

510

511 unsigned Opc = (BitSize == 32 ? AArch64::MOVKWi : AArch64::MOVKXi);

512 while (Shift < LastShift) {

513 Shift += 16;

514 Imm16 = (Imm >> Shift) & Mask;

515 if (Imm16 == (isNeg ? Mask : 0))

516 continue;

517

520 }

521

522

523

524 if (Insn.size() > 2 && (Imm >> 32) == (Imm & 0xffffffffULL)) {

527 Insn.push_back({AArch64::ORRXrs, 0, 32});

528 }

529}

530

531

532

535 const unsigned Mask = 0xFFFF;

536

537

538

539 unsigned OneChunks = 0;

540 unsigned ZeroChunks = 0;

541 for (unsigned Shift = 0; Shift < BitSize; Shift += 16) {

542 const unsigned Chunk = (Imm >> Shift) & Mask;

543 if (Chunk == Mask)

544 OneChunks++;

545 else if (Chunk == 0)

546 ZeroChunks++;

547 }

548

549

550 if ((BitSize / 16) - OneChunks <= 1 || (BitSize / 16) - ZeroChunks <= 1) {

553 "Move of immediate should have expanded to a single MOVZ/MOVN");

554 return;

555 }

556

557

558 uint64_t UImm = Imm << (64 - BitSize) >> (64 - BitSize);

561 unsigned Opc = (BitSize == 32 ? AArch64::ORRWri : AArch64::ORRXri);

563 return;

564 }

565

566

567

568

569

570 if (OneChunks >= (BitSize / 16) - 2 || ZeroChunks >= (BitSize / 16) - 2) {

572 return;

573 }

574

575 assert(BitSize == 64 && "All 32-bit immediates can be expanded with a"

576 "MOVZ/MOVK pair");

577

578

579

580

581

582

583

584

585

586 for (unsigned Shift = 0; Shift < BitSize; Shift += 16) {

587 uint64_t ShiftedMask = (0xFFFFULL << Shift);

588 uint64_t ZeroChunk = UImm & ~ShiftedMask;

589 uint64_t OneChunk = UImm | ShiftedMask;

591 uint64_t ReplicateChunk = ZeroChunk | (RotatedImm & ShiftedMask);

595 Encoding)) {

596

597 Insn.push_back({ AArch64::ORRXri, 0, Encoding });

598

599

600 const unsigned Imm16 = getChunk(UImm, Shift / 16);

601 Insn.push_back({ AArch64::MOVKXi, Imm16,

603 return;

604 }

605 }

606

607

609 return;

610

611

613 return;

614

615

617 return;

618

619

620

621

622

623

624

625

626

627 if (OneChunks || ZeroChunks) {

629 return;

630 }

631

632

633

634

636 return;

637

638

639

640

641

642

644 return;

645

646

647

649}

static uint64_t GetRunOfOnesStartingAt(uint64_t V, uint64_t StartPosition)

Definition AArch64ExpandImm.cpp:242

static void expandMOVImmSimple(uint64_t Imm, unsigned BitSize, unsigned OneChunks, unsigned ZeroChunks, SmallVectorImpl< ImmInsnModel > &Insn)

Expand a MOVi32imm or MOVi64imm pseudo instruction to a MOVZ or MOVN of width BitSize followed by up ...

Definition AArch64ExpandImm.cpp:466

static uint64_t updateImm(uint64_t Imm, unsigned Idx, bool Clear)

Clear or set all bits in the chunk at the given index.

Definition AArch64ExpandImm.cpp:124

static bool canUseOrr(uint64_t Chunk, uint64_t &Encoding)

Check whether the given 16-bit chunk replicated to full 64-bit width can be materialized with an ORR ...

Definition AArch64ExpandImm.cpp:30

static bool tryToreplicateChunks(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)

Check for identical 16-bit chunks within the constant and if so materialize them with a single ORR in...

Definition AArch64ExpandImm.cpp:43

static bool trySequenceOfOnes(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)

Check whether the constant contains a sequence of contiguous ones, which might be interrupted by one ...

Definition AArch64ExpandImm.cpp:150

static uint64_t MaximallyReplicateSubImmediate(uint64_t V, uint64_t Subset)

Definition AArch64ExpandImm.cpp:254

static bool tryAndOfLogicalImmediates(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)

Definition AArch64ExpandImm.cpp:341

static uint64_t getChunk(uint64_t Imm, unsigned ChunkIdx)

Helper function which extracts the specified 16-bit chunk from a 64-bit value.

Definition AArch64ExpandImm.cpp:22

static bool tryEorOfLogicalImmediates(uint64_t Imm, SmallVectorImpl< ImmInsnModel > &Insn)

Definition AArch64ExpandImm.cpp:373

static uint64_t maximalLogicalImmWithin(uint64_t RemainingBits, uint64_t OriginalBits)

Definition AArch64ExpandImm.cpp:272

static bool isStartChunk(uint64_t Chunk)

Check whether this chunk matches the pattern '1...0...'.

Definition AArch64ExpandImm.cpp:106

static bool isEndChunk(uint64_t Chunk)

Check whether this chunk matches the pattern '0...1...' This pattern ends a contiguous sequence of on...

Definition AArch64ExpandImm.cpp:116

static bool tryOrrOfLogicalImmediates(uint64_t UImm, SmallVectorImpl< ImmInsnModel > &Insn)

Definition AArch64ExpandImm.cpp:316

static std::optional< std::pair< uint64_t, uint64_t > > decomposeIntoOrrOfLogicalImmediates(uint64_t UImm)

Definition AArch64ExpandImm.cpp:288

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

static bool isNeg(Value *V)

Returns true if the operation is a negation of V, and it works for both integers and floats.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

static bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, uint64_t &Encoding)

processLogicalImmediate - Determine if an immediate value can be encoded as the immediate operand of ...

static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)

getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...

void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)

Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...

Definition AArch64ExpandImm.cpp:533

This is an optimization pass for GlobalISel generic memory operations.

constexpr T rotr(T V, int R)

int countr_one(T Value)

Count the number of ones from the least significant bit to the first zero bit.

constexpr int popcount(T Value) noexcept

Count the number of set bits in a value.

int countr_zero(T Val)

Count number of 0's from the least significant bit to the most stopping at the first 1.

int countl_zero(T Val)

Count number of 0's from the most significant bit to the least stopping at the first 1.

constexpr bool isMask_64(uint64_t Value)

Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...

FunctionAddr VTableAddr Count

constexpr T rotl(T V, int R)

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.