LLVM: lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

19

20using namespace llvm;

21

25 if (B == MBBEnd)

26 return true;

27 assert(A->getParent() == B->getParent() &&

28 "Iterators should be in same block");

29 const MachineBasicBlock *BBA = A->getParent();

31 for (; &*I != A && &*I != B; ++I)

32 ;

33 return &*I == A;

34}

35

38 void *&NodeInsertPos) {

40 assert(CSEInfo && "Can't get here without setting CSEInfo");

41 MachineBasicBlock *CurMBB = &getMBB();

42 MachineInstr *MI =

43 CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos);

44 if (MI) {

48 if (MII == CurrPos) {

49

50

52 } else if (!dominates(MI, CurrPos)) {

53

54

56 MI->setDebugLoc(Loc);

57 CurMBB->splice(CurrPos, CurMBB, MI);

58 }

59 return MachineInstrBuilder(getMF(), MI);

60 }

61 return MachineInstrBuilder();

62}

63

64bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const {

65 const GISelCSEInfo *CSEInfo = getCSEInfo();

67 return false;

68 return true;

69}

70

71void CSEMIRBuilder::profileDstOp(const DstOp &Op,

73 switch (Op.getDstOpKind()) {

75 B.addNodeIDRegType(Op.getRegClass());

76 break;

77 }

79

80 B.addNodeIDReg(Op.getReg());

81 break;

82 }

84 B.addNodeIDRegType(Op.getLLTTy(*getMRI()));

85 break;

86 }

88 B.addNodeIDRegType(Op.getVRegAttrs());

89 break;

90 }

91 }

92}

93

94void CSEMIRBuilder::profileSrcOp(const SrcOp &Op,

96 switch (Op.getSrcOpKind()) {

98 B.addNodeIDImmediate(Op.getImm());

99 break;

101 B.addNodeIDImmediate(static_cast<int64_t>(Op.getPredicate()));

102 break;

103 default:

104 B.addNodeIDRegType(Op.getReg());

105 break;

106 }

107}

108

110 unsigned Opc) const {

111

112 B.addNodeIDMBB(&getMBB());

113

114 B.addNodeIDOpcode(Opc);

115}

116

117void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef DstOps,

119 std::optional Flags,

121

122 profileMBBOpcode(B, Opc);

123

124 profileDstOps(DstOps, B);

125

126 profileSrcOps(SrcOps, B);

127

128 if (Flags)

129 B.addNodeIDFlag(*Flags);

130}

131

133 void *NodeInsertPos) {

135 "Attempting to CSE illegal op");

136 MachineInstr *MIBInstr = MIB;

137 getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos);

138 return MIB;

139}

140

141bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef DstOps) {

142 if (DstOps.size() == 1)

143 return true;

144

148 });

149}

150

152CSEMIRBuilder::generateCopiesIfRequired(ArrayRef DstOps,

154 assert(checkCopyToDefsPossible(DstOps) &&

155 "Impossible return a single MIB with copies to multiple defs");

156 if (DstOps.size() == 1) {

157 const DstOp &Op = DstOps[0];

160 }

161

162

163

164

165

168 if (Observer)

172 if (Observer)

174 }

175

176 return MIB;

177}

178

182 std::optional Flag) {

183 switch (Opc) {

184 default:

185 break;

186 case TargetOpcode::G_ICMP: {

187 assert(SrcOps.size() == 3 && "Invalid sources");

188 assert(DstOps.size() == 1 && "Invalid dsts");

189 LLT SrcTy = SrcOps[1].getLLTTy(*getMRI());

190 LLT DstTy = DstOps[0].getLLTTy(*getMRI());

191 auto BoolExtOp = getBoolExtOp(SrcTy.isVector(), false);

192

194 SrcOps[0].getPredicate(), SrcOps[1].getReg(), SrcOps[2].getReg(),

196 if (SrcTy.isVector())

199 }

200 break;

201 }

202 case TargetOpcode::G_ADD:

203 case TargetOpcode::G_PTR_ADD:

204 case TargetOpcode::G_AND:

205 case TargetOpcode::G_ASHR:

206 case TargetOpcode::G_LSHR:

207 case TargetOpcode::G_MUL:

208 case TargetOpcode::G_OR:

209 case TargetOpcode::G_SHL:

210 case TargetOpcode::G_SUB:

211 case TargetOpcode::G_XOR:

212 case TargetOpcode::G_UDIV:

213 case TargetOpcode::G_SDIV:

214 case TargetOpcode::G_UREM:

215 case TargetOpcode::G_SREM:

216 case TargetOpcode::G_SMIN:

217 case TargetOpcode::G_SMAX:

218 case TargetOpcode::G_UMIN:

219 case TargetOpcode::G_UMAX: {

220

221 assert(SrcOps.size() == 2 && "Invalid sources");

222 assert(DstOps.size() == 1 && "Invalid dsts");

223 LLT SrcTy = SrcOps[0].getLLTTy(*getMRI());

224

225 if (Opc == TargetOpcode::G_PTR_ADD &&

226 getDataLayout().isNonIntegralAddressSpace(SrcTy.getAddressSpace()))

227 break;

228

229 if (SrcTy.isVector()) {

230

233 if (!VecCst.empty())

235 break;

236 }

237

241 break;

242 }

243 case TargetOpcode::G_FADD:

244 case TargetOpcode::G_FSUB:

245 case TargetOpcode::G_FMUL:

246 case TargetOpcode::G_FDIV:

247 case TargetOpcode::G_FREM:

248 case TargetOpcode::G_FMINNUM:

249 case TargetOpcode::G_FMAXNUM:

250 case TargetOpcode::G_FMINNUM_IEEE:

251 case TargetOpcode::G_FMAXNUM_IEEE:

252 case TargetOpcode::G_FMINIMUM:

253 case TargetOpcode::G_FMAXIMUM:

254 case TargetOpcode::G_FCOPYSIGN: {

255

256 assert(SrcOps.size() == 2 && "Invalid sources");

257 assert(DstOps.size() == 1 && "Invalid dsts");

261 break;

262 }

263 case TargetOpcode::G_SEXT_INREG: {

264 assert(DstOps.size() == 1 && "Invalid dst ops");

265 assert(SrcOps.size() == 2 && "Invalid src ops");

266 const DstOp &Dst = DstOps[0];

267 const SrcOp &Src0 = SrcOps[0];

268 const SrcOp &Src1 = SrcOps[1];

269 if (auto MaybeCst =

272 break;

273 }

274 case TargetOpcode::G_SITOFP:

275 case TargetOpcode::G_UITOFP: {

276

277 assert(SrcOps.size() == 1 && "Invalid sources");

278 assert(DstOps.size() == 1 && "Invalid dsts");

282 break;

283 }

284 case TargetOpcode::G_CTLZ:

285 case TargetOpcode::G_CTTZ: {

286 assert(SrcOps.size() == 1 && "Expected one source");

287 assert(DstOps.size() == 1 && "Expected one dest");

289 if (Opc == TargetOpcode::G_CTLZ)

290 CB = [](APInt V) -> unsigned { return V.countl_zero(); };

291 else

292 CB = [](APInt V) -> unsigned { return V.countTrailingZeros(); };

294 if (!MaybeCsts)

295 break;

296 if (MaybeCsts->size() == 1)

297 return buildConstant(DstOps[0], (*MaybeCsts)[0]);

298

300 LLT VecTy = DstOps[0].getLLTTy(*getMRI());

301 for (unsigned Cst : *MaybeCsts)

305 }

306 }

307 bool CanCopy = checkCopyToDefsPossible(DstOps);

308 if (!canPerformCSEForOpc(Opc))

310

311

312 if (!CanCopy) {

314

315

317 return MIB;

318 }

321 void *InsertPos = nullptr;

322 profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder);

324 if (MIB) {

325

326 return generateCopiesIfRequired(DstOps, MIB);

327 }

328

331 return memoizeMI(NewMIB, InsertPos);

332}

333

336 constexpr unsigned Opc = TargetOpcode::G_CONSTANT;

337 if (!canPerformCSEForOpc(Opc))

339

340

342 if (Ty.isFixedVector())

344 if (Ty.isScalableVector())

346

349 void *InsertPos = nullptr;

350 profileMBBOpcode(ProfBuilder, Opc);

351 profileDstOp(Res, ProfBuilder);

354 if (MIB) {

355

356 return generateCopiesIfRequired({Res}, MIB);

357 }

358

360 return memoizeMI(NewMIB, InsertPos);

361}

362

365 constexpr unsigned Opc = TargetOpcode::G_FCONSTANT;

366 if (!canPerformCSEForOpc(Opc))

368

369

371 if (Ty.isVector())

373

376 void *InsertPos = nullptr;

377 profileMBBOpcode(ProfBuilder, Opc);

378 profileDstOp(Res, ProfBuilder);

381 if (MIB) {

382

383 return generateCopiesIfRequired({Res}, MIB);

384 }

386 return memoizeMI(NewMIB, InsertPos);

387}

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

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Provides analysis for continuously CSEing during GISel passes.

This file implements a version of MachineIRBuilder which CSEs insts within a MachineBasicBlock.

This contains common code to allow clients to notify changes to machine instr.

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

Class for arbitrary precision integers.

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

const T & front() const

front - Get the first element.

size_t size() const

size - Get the array size.

MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef< DstOp > DstOps, ArrayRef< SrcOp > SrcOps, std::optional< unsigned > Flag=std::nullopt) override

Definition CSEMIRBuilder.cpp:179

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

Build and insert Res = G_FCONSTANT Val.

Definition CSEMIRBuilder.cpp:363

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

Build and insert Res = G_CONSTANT Val.

Definition CSEMIRBuilder.cpp:334

ConstantFP - Floating Point Values [float, double].

This is the shared class of boolean and integer constants.

static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB)

When two instructions are combined into a single instruction we also need to combine the original loc...

LLT getLLTTy(const MachineRegisterInfo &MRI) const

FoldingSetNodeID - This class is used to gather all the unique data bits of a node.

bool shouldCSE(unsigned Opc) const

void countOpcodeHit(unsigned Opc)

void handleRemoveInst(MachineInstr *MI)

Remove this inst from the CSE map.

virtual void changingInstr(MachineInstr &MI)=0

This instruction is about to be mutated in some way.

virtual void changedInstr(MachineInstr &MI)=0

This instruction was mutated in some way.

LLVM_ABI const GISelInstProfileBuilder & addNodeIDMachineOperand(const MachineOperand &MO) const

constexpr unsigned getScalarSizeInBits() const

constexpr LLT getScalarType() const

MachineInstrBundleIterator< const MachineInstr > const_iterator

void splice(iterator Where, MachineBasicBlock *Other, iterator From)

Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...

MachineInstrBundleIterator< MachineInstr > iterator

void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)

Set the insertion point before the specified position.

GISelCSEInfo * getCSEInfo()

MachineBasicBlock::iterator getInsertPt()

Current insertion point for new instructions.

MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src)

Build and insert Res = G_BUILD_VECTOR with Src replicated to fill the number of elements.

unsigned getBoolExtOp(bool IsVec, bool IsFP) const

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

Build and insert Res = G_BUILD_VECTOR Op0, ...

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

Build and insert Res = G_FCONSTANT Val.

MachineInstrBuilder buildInstr(unsigned Opcode)

Build and insert = Opcode .

MachineInstrBuilder buildBuildVectorConstant(const DstOp &Res, ArrayRef< APInt > Ops)

Build and insert Res = G_BUILD_VECTOR Op0, ... where each OpN is built with G_CONSTANT.

MachineFunction & getMF()

Getter for the function we currently build.

const MachineBasicBlock & getMBB() const

Getter for the basic block we currently build.

const DebugLoc & getDebugLoc()

Get the current instruction's debug location.

MachineRegisterInfo * getMRI()

Getter for MRI.

MachineIRBuilderState & getState()

Getter for the State.

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

Build and insert Res = COPY Op.

const DataLayout & getDataLayout() const

MachineInstrBuilder buildSplatVector(const DstOp &Res, const SrcOp &Val)

Build and insert Res = G_SPLAT_VECTOR Val.

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.

unsigned getOpcode() const

Returns the opcode of this MachineInstr.

const DebugLoc & getDebugLoc() const

Returns the debug location id of this MachineInstr.

void setDebugLoc(DebugLoc DL)

Replace current source information with new such.

static MachineOperand CreateFPImm(const ConstantFP *CFP)

static MachineOperand CreateCImm(const ConstantInt *CI)

reference emplace_back(ArgTypes &&... Args)

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

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

This is an optimization pass for GlobalISel generic memory operations.

LLVM_ABI std::optional< SmallVector< APInt > > ConstantFoldICmp(unsigned Pred, const Register Op1, const Register Op2, unsigned DstScalarSizeInBits, unsigned ExtOp, const MachineRegisterInfo &MRI)

bool all_of(R &&range, UnaryPredicate P)

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

LLVM_ABI std::optional< APFloat > ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)

LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)

LLVM_ABI std::optional< SmallVector< unsigned > > ConstantFoldCountZeros(Register Src, const MachineRegisterInfo &MRI, std::function< unsigned(APInt)> CB)

Tries to constant fold a counting-zero operation (G_CTLZ or G_CTTZ) on Src.

LLVM_ABI std::optional< APInt > ConstantFoldExtOp(unsigned Opcode, const Register Op1, uint64_t Imm, const MachineRegisterInfo &MRI)

LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)

LLVM_ABI SmallVector< APInt > ConstantFoldVectorBinop(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)

Tries to constant fold a vector binop with sources Op1 and Op2.

DWARFExpression::Operation Op

GISelChangeObserver * Observer