LLVM: lib/Target/ARM/ARMLegalizerInfo.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

24

25using namespace llvm;

26using namespace LegalizeActions;

27

29 return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();

30}

31

33 using namespace TargetOpcode;

34

36

42

44 if (ST.isThumb1Only()) {

45

46 LegacyInfo.computeTables();

47 verify(*ST.getInstrInfo());

48 return;

49 }

50

52 .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});

53

55

57 .legalFor({s32})

58 .clampScalar(0, s32, s32);

59

60 if (ST.hasNEON())

62 .legalFor({s32, s64})

63 .minScalar(0, s32);

64 else

66 .legalFor({s32})

67 .minScalar(0, s32);

68

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

71 .minScalar(0, s32)

73

74 bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||

75 (ST.isThumb() && ST.hasDivideInThumbMode());

76 if (HasHWDivide)

78 .legalFor({s32})

79 .clampScalar(0, s32, s32);

80 else

82 .libcallFor({s32})

83 .clampScalar(0, s32, s32);

84

85 auto &REMBuilder =

87 if (HasHWDivide)

88 REMBuilder.lowerFor({s32});

89 else if (AEABI(ST))

90 REMBuilder.customFor({s32});

91 else

92 REMBuilder.libcallFor({s32});

93

96 .minScalar(1, s32);

99 .minScalar(0, s32);

100

103 .clampScalar(0, s32, s32);

104

106

109 .minScalar(1, s32);

110

113 .minScalar(0, s32);

114

115

116

118 .legalForTypesWithMemDesc({{s8, p0, s8, 8},

119 {s16, p0, s16, 8},

120 {s32, p0, s32, 8},

121 {p0, p0, p0, 8}})

122 .unsupportedIfMemSizeNotPow2();

123

126

127 auto &PhiBuilder =

130 .minScalar(0, s32);

131

134 .minScalar(1, s32);

135

137

138 if (!ST.useSoftFloat() && ST.hasVFP2Base()) {

140 {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})

141 .legalFor({s32, s64});

142

143 LoadStoreBuilder

145 .maxScalar(0, s32);

147

149 {s32, s64});

150

153

156

158 .legalForCartesianProduct({s32}, {s32, s64});

160 .legalForCartesianProduct({s32, s64}, {s32});

161

163 .legalFor({s32});

167 } else {

169 .libcallFor({s32, s64});

170

171 LoadStoreBuilder.maxScalar(0, s32);

172

174

176

178 {s32, s64});

179

181 setFCmpLibcallsAEABI();

182 else

183 setFCmpLibcallsGNU();

184

187

189 .libcallForCartesianProduct({s32}, {s32, s64});

191 .libcallForCartesianProduct({s32, s64}, {s32});

192

197 }

198

199

200 LoadStoreBuilder.lower();

201

202 if (!ST.useSoftFloat() && ST.hasVFP4Base())

204 else

206

208

209 if (ST.hasV5TOps()) {

212 .clampScalar(1, s32, s32)

216 .clampScalar(1, s32, s32)

218 } else {

221 .clampScalar(1, s32, s32)

225 .clampScalar(1, s32, s32)

227 }

228

229 LegacyInfo.computeTables();

230 verify(*ST.getInstrInfo());

231}

232

233void ARMLegalizerInfo::setFCmpLibcallsAEABI() {

234

235

261

287}

288

289void ARMLegalizerInfo::setFCmpLibcallsGNU() {

290

291

309

327}

328

331 unsigned Size) const {

333 if (Size == 32)

334 return FCmp32Libcalls[Predicate];

335 if (Size == 64)

336 return FCmp64Libcalls[Predicate];

338}

339

342 using namespace TargetOpcode;

343

347

348 switch (MI.getOpcode()) {

349 default:

350 return false;

351 case G_SREM:

352 case G_UREM: {

353 Register OriginalResult = MI.getOperand(0).getReg();

354 auto Size = MRI.getType(OriginalResult).getSizeInBits();

355 if (Size != 32)

356 return false;

357

359 MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;

360

361

362

363

367 OriginalResult};

369 {{MI.getOperand(1).getReg(), ArgTy, 0},

370 {MI.getOperand(2).getReg(), ArgTy, 0}},

371 LocObserver, &MI);

373 return false;

374 break;

375 }

376 case G_FCMP: {

377 assert(MRI.getType(MI.getOperand(2).getReg()) ==

378 MRI.getType(MI.getOperand(3).getReg()) &&

379 "Mismatched operands for G_FCMP");

380 auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();

381

382 auto OriginalResult = MI.getOperand(0).getReg();

383 auto Predicate =

385 auto Libcalls = getFCmpLibcalls(Predicate, OpSize);

386

387 if (Libcalls.empty()) {

390 "Predicate needs libcalls, but none specified");

393 MI.eraseFromParent();

394 return true;

395 }

396

397 assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");

400

402 for (auto Libcall : Libcalls) {

403 auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));

405 {LibcallResult, RetTy, 0},

406 {{MI.getOperand(2).getReg(), ArgTy, 0},

407 {MI.getOperand(3).getReg(), ArgTy, 0}},

408 LocObserver, &MI);

409

411 return false;

412

413 auto ProcessedResult =

414 Libcalls.size() == 1

415 ? OriginalResult

416 : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));

417

418

419

420

423

424

425 MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);

426 } else {

427

430 MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);

431 }

432 Results.push_back(ProcessedResult);

433 }

434

438 }

439 break;

440 }

441 case G_CONSTANT: {

442 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();

446 return true;

447 }

448 case G_FCONSTANT: {

449

450 auto AsInteger =

451 MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();

453 *ConstantInt::get(Ctx, AsInteger));

454 break;

455 }

456 case G_SET_FPMODE: {

457

459 auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);

460 Register Modes = MI.getOperand(0).getReg();

463 auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);

464 auto NotStatusBitMask =

466 auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);

467 auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);

469 break;

470 }

471 case G_RESET_FPMODE: {

472

473

478 auto NewFPSCR = MIRBuilder.buildAnd(FPEnvTy, FPEnv, NotModeBitMask);

480 break;

481 }

482 }

483

484 MI.eraseFromParent();

485 return true;

486}

unsigned const MachineRegisterInfo * MRI

This file describes how to lower LLVM calls to machine code calls.

static bool AEABI(const ARMSubtarget &ST)

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

Function Alias Analysis Results

Implement a low-level type suitable for MachineInstr level instruction selection.

This file declares the MachineIRBuilder class.

static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

ARMLegalizerInfo(const ARMSubtarget &ST)

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

Called for instructions with the Custom LegalizationAction.

Predicate

This enumeration lists the possible predicates for CmpInst subclasses.

@ FCMP_OEQ

0 0 0 1 True if ordered and equal

@ FCMP_TRUE

1 1 1 1 Always true (always folded)

@ ICMP_SLT

signed less than

@ ICMP_SLE

signed less or equal

@ FCMP_OLT

0 1 0 0 True if ordered and less than

@ FCMP_ULE

1 1 0 1 True if unordered, less than, or equal

@ FCMP_OGT

0 0 1 0 True if ordered and greater than

@ FCMP_OGE

0 0 1 1 True if ordered and greater than or equal

@ ICMP_SGT

signed greater than

@ FCMP_ULT

1 1 0 0 True if unordered or less than

@ FCMP_ONE

0 1 1 0 True if ordered and operands are unequal

@ FCMP_UEQ

1 0 0 1 True if unordered or equal

@ FCMP_UGT

1 0 1 0 True if unordered or greater than

@ FCMP_OLE

0 1 0 1 True if ordered and less than or equal

@ FCMP_ORD

0 1 1 1 True if ordered (no nans)

@ ICMP_SGE

signed greater or equal

@ FCMP_UNE

1 1 1 0 True if unordered or not equal

@ FCMP_UGE

1 0 1 1 True if unordered, greater than, or equal

@ FCMP_FALSE

0 0 0 0 Always false (always folded)

@ FCMP_UNO

1 0 0 0 True if unordered: isnan(X) | isnan(Y)

bool isFPPredicate() const

bool isIntPredicate() const

This is the shared class of boolean and integer constants.

uint64_t getZExtValue() const

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

LLVMContext & getContext() const

getContext - Return a reference to the LLVMContext associated with this function.

void resize(typename StorageT::size_type s)

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.

This is an important class for using LLVM in a threaded context.

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 & customForCartesianProduct(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 & custom()

Unconditionally custom lower.

LegalizeRuleSet & alwaysLegal()

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

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

LegalizeRuleSet & legalForTypesWithMemDesc(std::initializer_list< LegalityPredicates::TypePairAndMemDesc > TypesAndMemDesc)

The instruction is legal when type indexes 0 and 1 along with the memory size and minimum alignment i...

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

@ Legalized

Instruction has been legalized and the MachineFunction changed.

MachineIRBuilder & MIRBuilder

Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.

LegalizeResult lowerConstant(MachineInstr &MI)

LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)

Get the action definition builder for the given opcode.

const LegacyLegalizerInfo & getLegacyLegalizerInfo() const

Function & getFunction()

Return the LLVM function that this machine code represents.

Helper class to build MachineInstr.

MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)

Build and insert Res = G_AND Op0, Op1.

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

Build and insert a Res = G_ICMP Pred, Op0, Op1.

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 buildGetFPEnv(const DstOp &Dst)

Build and insert Dst = G_GET_FPENV.

MachineRegisterInfo * getMRI()

Getter for MRI.

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

Build and insert Res = G_OR Op0, Op1.

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

Build and insert Res = G_CONSTANT Val.

MachineInstrBuilder buildSetFPEnv(const SrcOp &Src)

Build and insert G_SET_FPENV Src.

Representation of each machine instruction.

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

Wrapper class representing virtual and physical registers.

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

Class to represent struct types.

static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)

This static method is the primary way to create a literal StructType.

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

static Type * getDoubleTy(LLVMContext &C)

static IntegerType * getInt32Ty(LLVMContext &C)

static Type * getFloatTy(LLVMContext &C)

#define llvm_unreachable(msg)

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

const unsigned FPStatusBits

const unsigned FPReservedBits

@ Libcall

The operation should be implemented as a call to some kind of runtime support library.

Predicate

Predicate - These are "(BI << 5) | BO" for various predicates.

This is an optimization pass for GlobalISel generic memory operations.

LegalizerHelper::LegalizeResult createLibcall(MachineIRBuilder &MIRBuilder, const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr)

Helper function that creates a libcall to the given Name using the given calling convention CC.

unsigned ConstantMaterializationCost(unsigned Val, const ARMSubtarget *Subtarget, bool ForCodesize=false)

Returns the number of instructions required to materialize the given constant in a register,...