LLVM: lib/Target/Mips/MipsLegalizerInfo.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

18#include "llvm/IR/IntrinsicsMips.h"

19

20using namespace llvm;

21

28

29

30

34 if (MemSize > AlignInBits)

35 return true;

36 return false;

37}

38

39static bool

41 std::initializer_list SupportedValues) {

42 unsigned QueryMemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();

43

44

46 return false;

47

48 for (auto &Val : SupportedValues) {

49 if (Val.ValTy != Query.Types[0])

50 continue;

51 if (Val.PtrTy != Query.Types[1])

52 continue;

53 if (Val.MemSize != QueryMemSize)

54 continue;

55 if (!Val.SystemSupportsUnalignedAccess &&

57 return false;

58 return true;

59 }

60 return false;

61}

62

64 std::initializer_list SupportedValues) {

66}

67

70

81

84 if (CheckTyN(0, Query, {s32}))

85 return true;

86 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))

87 return true;

88 return false;

89 })

90 .clampScalar(0, s32, s32);

91

93 .lowerFor({{s32, s1}});

94

97 .maxScalar(0, s32);

98

99

100

101

102

103

104 bool NoAlignRequirements = true;

105

109 Query, {{s32, p0, 8, NoAlignRequirements},

110 {s32, p0, 16, ST.systemSupportsUnalignedAccess()},

111 {s32, p0, 32, NoAlignRequirements},

112 {p0, p0, 32, NoAlignRequirements},

113 {s64, p0, 64, ST.systemSupportsUnalignedAccess()}}))

114 return true;

116 Query, {{v16s8, p0, 128, NoAlignRequirements},

117 {v8s16, p0, 128, NoAlignRequirements},

118 {v4s32, p0, 128, NoAlignRequirements},

119 {v2s64, p0, 128, NoAlignRequirements}}))

120 return true;

121 return false;

122 })

123

124

125

127 if (!Query.Types[0].isScalar() || Query.Types[1] != p0 ||

128 Query.Types[0] == s1)

129 return false;

130

131 unsigned Size = Query.Types[0].getSizeInBits();

132 unsigned QueryMemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();

133 assert(QueryMemSize <= Size && "Scalar can't hold MemSize");

134

135 if (Size > 64 || QueryMemSize > 64)

136 return false;

137

139 return true;

140

141 if (!ST.systemSupportsUnalignedAccess() &&

143 Query.MMODescrs[0].AlignInBits)) {

144 assert(QueryMemSize != 32 && "4 byte load and store are legal");

145 return true;

146 }

147

148 return false;

149 })

150 .minScalar(0, s32)

152

155

158

161

163 .legalForTypesWithMemDesc({{s32, p0, s8, 8},

164 {s32, p0, s16, 8}})

165 .clampScalar(0, s32, s32);

166

168 .legalIf([](const LegalityQuery &Query) { return false; })

169 .maxScalar(0, s32);

170

173 .maxScalar(1, s32);

174

177 .minScalar(0, s32)

179

182 .minScalar(0, s32);

183

186

189

192 .minScalar(0, s32);

193

195 .legalFor({s32})

196 .clampScalar(0, s32, s32);

197

200 if (CheckTyN(0, Query, {s32}))

201 return true;

202 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))

203 return true;

204 return false;

205 })

206 .minScalar(0, s32)

208

210 .legalFor({{s32, s32}})

211 .clampScalar(1, s32, s32)

213

216 .clampScalar(1, s32, s32)

218

221 .clampScalar(0, s32, s32);

222

224 .legalFor({{p0, s32}});

225

228

231

233 .legalFor({p0});

234

237

240

243 if (ST.hasMips32r2() && CheckTyN(0, Query, {s32}))

244 return true;

245 return false;

246 })

248 if (!ST.hasMips32r2() && CheckTyN(0, Query, {s32}))

249 return true;

250 return false;

251 })

252 .maxScalar(0, s32);

253

256 .maxScalar(0, s32);

257

260 .maxScalar(0, s32)

264

267 .maxScalar(0, s32)

270 .lowerFor({{s32, s32}, {s64, s64}});

271

274 .clampScalar(0, s32, s32)

276

277

280

283 if (CheckTyN(0, Query, {s32, s64}))

284 return true;

285 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))

286 return true;

287 return false;

288 });

289

291 .legalFor({{s32, s32}, {s32, s64}})

292 .minScalar(0, s32);

293

295 .libcallFor({s32, s64});

296

299

302

303

306 .libcallForCartesianProduct({s64}, {s64, s32})

307 .minScalar(0, s32);

308

311 .lowerForCartesianProduct({s32}, {s64, s32})

312 .minScalar(0, s32);

313

314

317 .libcallForCartesianProduct({s64, s32}, {s64})

318 .minScalar(1, s32);

319

322 .customForCartesianProduct({s64, s32}, {s32})

323 .minScalar(1, s32);

324

326

328

330 verify(*ST.getInstrInfo());

331}

332

337

340

343

344 switch (MI.getOpcode()) {

345 case G_LOAD:

346 case G_STORE: {

347 unsigned MemSize = (**MI.memoperands_begin()).getSize().getValue();

348 Register Val = MI.getOperand(0).getReg();

349 unsigned Size = MRI.getType(Val).getSizeInBits();

350

352

353 assert(MemSize <= 8 && "MemSize is too large");

354 assert(Size <= 64 && "Scalar size is too large");

355

356

357

358 unsigned P2HalfMemSize, RemMemSize;

360 P2HalfMemSize = RemMemSize = MemSize / 2;

361 } else {

362 P2HalfMemSize = 1 << Log2_32(MemSize);

363 RemMemSize = MemSize - P2HalfMemSize;

364 }

365

366 Register BaseAddr = MI.getOperand(1).getReg();

367 LLT PtrTy = MRI.getType(BaseAddr);

369

372

373 if (MI.getOpcode() == G_STORE) {

374

375 if (Size < 32)

379

380 auto C_P2HalfMemSize = MIRBuilder.buildConstant(s32, P2HalfMemSize);

381 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, BaseAddr, C_P2HalfMemSize);

382

383 if (MI.getOpcode() == G_STORE && MemSize <= 4) {

384 MIRBuilder.buildStore(Val, BaseAddr, *P2HalfMemOp);

385 auto C_P2Half_InBits = MIRBuilder.buildConstant(s32, P2HalfMemSize * 8);

386 auto Shift = MIRBuilder.buildLShr(s32, Val, C_P2Half_InBits);

387 MIRBuilder.buildStore(Shift, Addr, *RemMemOp);

388 } else {

389 auto Unmerge = MIRBuilder.buildUnmerge(s32, Val);

390 MIRBuilder.buildStore(Unmerge.getReg(0), BaseAddr, *P2HalfMemOp);

391 MIRBuilder.buildStore(Unmerge.getReg(1), Addr, *RemMemOp);

392 }

393 }

394

395 if (MI.getOpcode() == G_LOAD) {

396

397 if (MemSize <= 4) {

398

400

401 if (Size == 32)

402 MIRBuilder.buildLoad(Val, BaseAddr, *Load4MMO);

403 else {

404 auto Load = MIRBuilder.buildLoad(s32, BaseAddr, *Load4MMO);

405 MIRBuilder.buildTrunc(Val, Load.getReg(0));

406 }

407

408 } else {

409 auto C_P2HalfMemSize = MIRBuilder.buildConstant(s32, P2HalfMemSize);

410 auto Addr = MIRBuilder.buildPtrAdd(PtrTy, BaseAddr, C_P2HalfMemSize);

411

412 auto Load_P2Half = MIRBuilder.buildLoad(s32, BaseAddr, *P2HalfMemOp);

413 auto Load_Rem = MIRBuilder.buildLoad(s32, Addr, *RemMemOp);

414

415 if (Size == 64)

417 else {

421 }

422 }

423 }

424 MI.eraseFromParent();

425 break;

426 }

427 case G_UITOFP: {

428 Register Dst = MI.getOperand(0).getReg();

429 Register Src = MI.getOperand(1).getReg();

430 LLT DstTy = MRI.getType(Dst);

431 LLT SrcTy = MRI.getType(Src);

432

433 if (SrcTy != s32)

434 return false;

435 if (DstTy != s32 && DstTy != s64)

436 return false;

437

438

439

440

441

442

443

444

445 auto C_HiMask = MIRBuilder.buildConstant(s32, UINT32_C(0x43300000));

446 auto Bitcast =

448

451

452 if (DstTy == s64)

453 MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP);

454 else {

457 }

458

459 MI.eraseFromParent();

460 break;

461 }

462 default:

463 return false;

464 }

465

466 return true;

467}

468

472 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");

474 .add(MI.getOperand(0))

475 .add(MI.getOperand(2))

476 .add(MI.getOperand(3))

478 *ST.getRegBankInfo()))

479 return false;

480 MI.eraseFromParent();

481 return true;

482}

483

487 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");

489 .add(MI.getOperand(0))

490 .add(MI.getOperand(2))

491 .add(MI.getOperand(3));

492 MI.eraseFromParent();

493 return true;

494}

495

499 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");

501 .add(MI.getOperand(0))

502 .add(MI.getOperand(2));

503 MI.eraseFromParent();

504 return true;

505}

506

511

513 case Intrinsic::vacopy: {

516 auto Tmp =

517 MIRBuilder.buildLoad(PtrTy, MI.getOperand(2),

518 *MI.getMF()->getMachineMemOperand(

521 *MI.getMF()->getMachineMemOperand(

523 MI.eraseFromParent();

524 return true;

525 }

526 case Intrinsic::mips_addv_b:

527 case Intrinsic::mips_addv_h:

528 case Intrinsic::mips_addv_w:

529 case Intrinsic::mips_addv_d:

531 case Intrinsic::mips_addvi_b:

533 case Intrinsic::mips_addvi_h:

535 case Intrinsic::mips_addvi_w:

537 case Intrinsic::mips_addvi_d:

539 case Intrinsic::mips_subv_b:

540 case Intrinsic::mips_subv_h:

541 case Intrinsic::mips_subv_w:

542 case Intrinsic::mips_subv_d:

544 case Intrinsic::mips_subvi_b:

546 case Intrinsic::mips_subvi_h:

548 case Intrinsic::mips_subvi_w:

550 case Intrinsic::mips_subvi_d:

552 case Intrinsic::mips_mulv_b:

553 case Intrinsic::mips_mulv_h:

554 case Intrinsic::mips_mulv_w:

555 case Intrinsic::mips_mulv_d:

557 case Intrinsic::mips_div_s_b:

558 case Intrinsic::mips_div_s_h:

559 case Intrinsic::mips_div_s_w:

560 case Intrinsic::mips_div_s_d:

562 case Intrinsic::mips_mod_s_b:

563 case Intrinsic::mips_mod_s_h:

564 case Intrinsic::mips_mod_s_w:

565 case Intrinsic::mips_mod_s_d:

567 case Intrinsic::mips_div_u_b:

568 case Intrinsic::mips_div_u_h:

569 case Intrinsic::mips_div_u_w:

570 case Intrinsic::mips_div_u_d:

572 case Intrinsic::mips_mod_u_b:

573 case Intrinsic::mips_mod_u_h:

574 case Intrinsic::mips_mod_u_w:

575 case Intrinsic::mips_mod_u_d:

577 case Intrinsic::mips_fadd_w:

578 case Intrinsic::mips_fadd_d:

580 case Intrinsic::mips_fsub_w:

581 case Intrinsic::mips_fsub_d:

583 case Intrinsic::mips_fmul_w:

584 case Intrinsic::mips_fmul_d:

586 case Intrinsic::mips_fdiv_w:

587 case Intrinsic::mips_fdiv_d:

589 case Intrinsic::mips_fmax_a_w:

591 case Intrinsic::mips_fmax_a_d:

593 case Intrinsic::mips_fsqrt_w:

595 case Intrinsic::mips_fsqrt_d:

597 default:

598 break;

599 }

600 return true;

601}

unsigned const MachineRegisterInfo * MRI

static unsigned getIntrinsicID(const SDNode *N)

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

Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...

This file declares the MachineIRBuilder class.

static bool CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query, std::initializer_list< TypesAndMemOps > SupportedValues)

Definition MipsLegalizerInfo.cpp:40

static bool CheckTyN(unsigned N, const LegalityQuery &Query, std::initializer_list< LLT > SupportedValues)

Definition MipsLegalizerInfo.cpp:63

static bool MSA2OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, MachineIRBuilder &MIRBuilder, const MipsSubtarget &ST)

Definition MipsLegalizerInfo.cpp:496

static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode, MachineIRBuilder &MIRBuilder, const MipsSubtarget &ST)

Definition MipsLegalizerInfo.cpp:469

static bool isUnalignedMemmoryAccess(uint64_t MemSize, uint64_t AlignInBits)

Definition MipsLegalizerInfo.cpp:31

static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, MachineIRBuilder &MIRBuilder, const MipsSubtarget &ST)

Definition MipsLegalizerInfo.cpp:484

This file declares the targeting of the Machinelegalizer class for Mips.

static constexpr LLT scalar(unsigned SizeInBits)

Get a low-level scalar or aggregate "bag of bits".

static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)

Get a low-level pointer in the given address space.

static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)

Get a low-level fixed-width vector of some number of elements and element width.

LLVM_ABI void computeTables()

Compute any ancillary tables needed to quickly decide how an operation should be handled.

LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)

Ensure the scalar is at least as wide as Ty.

LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)

The instruction is legal when type index 0 is any type in the given list.

LegalizeRuleSet & libcallFor(std::initializer_list< LLT > Types)

LegalizeRuleSet & maxScalar(unsigned TypeIdx, const LLT Ty)

Ensure the scalar is at most as wide as Ty.

LegalizeRuleSet & libcallForCartesianProduct(std::initializer_list< LLT > Types)

LegalizeRuleSet & lower()

The instruction is lowered.

LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)

The instruction is lowered when type index 0 is any type in the given list.

LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)

Limit the range of scalar sizes to MinTy and MaxTy.

LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)

The instruction is legal when type indexes 0 and 1 are both in the given list.

LegalizeRuleSet & legalIf(LegalityPredicate Predicate)

The instruction is legal if predicate is true.

MachineIRBuilder & MIRBuilder

Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.

LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)

Get the action definition builder for the given opcode.

const LegacyLegalizerInfo & getLegacyLegalizerInfo() const

MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)

getMachineMemOperand - Allocate a new MachineMemOperand.

Helper class to build MachineInstr.

MachineInstrBuilder buildFSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)

Build and insert Res = G_FSUB Op0, Op1.

MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)

Build and insert Res0, ... = G_UNMERGE_VALUES Op.

const TargetInstrInfo & getTII()

MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)

MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)

Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...

MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)

Build and insert Res = G_LOAD Addr, MMO.

MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)

Build and insert Res = G_PTR_ADD Op0, Op1.

virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)

Build and insert Res = G_FCONSTANT Val.

MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)

Build and insert G_STORE Val, Addr, MMO.

MachineInstrBuilder buildInstr(unsigned Opcode)

Build and insert = Opcode .

MachineFunction & getMF()

Getter for the function we currently build.

MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)

Build and insert Res = G_TRUNC Op.

MachineInstrBuilder buildAnyExt(const DstOp &Res, const SrcOp &Op)

Build and insert Res = G_ANYEXT Op0.

MachineRegisterInfo * getMRI()

Getter for MRI.

MachineInstrBuilder buildFPTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)

Build and insert Res = G_FPTRUNC Op.

virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)

Build and insert Res = G_CONSTANT Val.

Register getReg(unsigned Idx) const

Get the register for the operand index.

const MachineInstrBuilder & add(const MachineOperand &MO) const

bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const

Representation of each machine instruction.

A description of a memory reference used in the backend.

@ MOLoad

The memory access reads data.

@ MOStore

The memory access writes data.

MachineRegisterInfo - Keep track of information for virtual and physical registers,...

MipsLegalizerInfo(const MipsSubtarget &ST)

Definition MipsLegalizerInfo.cpp:68

bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override

Called for instructions with the Custom LegalizationAction.

Definition MipsLegalizerInfo.cpp:333

bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override

Definition MipsLegalizerInfo.cpp:507

Wrapper class representing virtual and physical registers.

Invariant opcodes: All instruction sets have these as their low opcodes.

This is an optimization pass for GlobalISel generic memory operations.

constexpr bool isPowerOf2_64(uint64_t Value)

Return true if the argument is a power of two > 0 (64 bit edition.)

unsigned Log2_32(uint32_t Value)

Return the floor log base 2 of the specified value, -1 if the value is zero.

To bit_cast(const From &from) noexcept

decltype(auto) cast(const From &Val)

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

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.

bool SystemSupportsUnalignedAccess

Definition MipsLegalizerInfo.cpp:26

LLT ValTy

Definition MipsLegalizerInfo.cpp:23

LLT PtrTy

Definition MipsLegalizerInfo.cpp:24

unsigned MemSize

Definition MipsLegalizerInfo.cpp:25

This struct is a compact representation of a valid (non-zero power of two) alignment.

The LegalityQuery object bundles together all the information that's needed to decide whether a given...

ArrayRef< MemDesc > MMODescrs

Operations which require memory can use this to place requirements on the memory type for each MMO.

This class contains a discriminated union of information about pointers in memory operands,...