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

1

2

3

4

5

6

7

8

9

10

11

12

13

36

37using namespace llvm;

38

39

40

41

43 "mem-intrinsic-expand-size",

44 cl::desc("Set minimum mem intrinsic size to expand in IR"), cl::init(-1),

46

47namespace {

48

49struct PreISelIntrinsicLowering {

53

54

55

56

57 const bool UseMemIntrinsicLibFunc;

58

59 explicit PreISelIntrinsicLowering(

63 bool UseMemIntrinsicLibFunc_ = true)

64 : TM(TM_), LookupTTI(LookupTTI_), LookupTLI(LookupTLI_),

65 UseMemIntrinsicLibFunc(UseMemIntrinsicLibFunc_) {}

66

67 static bool shouldExpandMemIntrinsicWithSize(Value *Size,

69 bool expandMemIntrinsicUses(Function &F) const;

70 bool lowerIntrinsics(Module &M) const;

71};

72

73}

74

76

77

78

79

80

81 Use *LastUse = nullptr;

82 bool Changed = false;

83 while (!Intrin.use_empty() && (!LastUse || LastUse->getNext())) {

84 Use *U = LastUse ? LastUse->getNext() : &*Intrin.use_begin();

85 bool Removed = false;

86

87

88 if (auto CI = dyn_cast(U->getUser()))

89 Changed |= Removed = Callback(CI);

90 if (!Removed)

91 LastUse = U;

92 }

93 return Changed;

94}

95

97 if (F.use_empty())

98 return false;

99

100 bool Changed = false;

102

104 auto CI = dyn_cast(U.getUser());

105 if (!CI || CI->getCalledOperand() != &F)

106 continue;

107

109 Value *OffsetPtr =

110 B.CreatePtrAdd(CI->getArgOperand(0), CI->getArgOperand(1));

111 Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtr, Align(4));

112

113 Value *ResultPtr = B.CreatePtrAdd(CI->getArgOperand(0), OffsetI32);

114

115 CI->replaceAllUsesWith(ResultPtr);

116 CI->eraseFromParent();

117 Changed = true;

118 }

119

120 return Changed;

121}

122

123

124

132}

133

137 "Pre-ISel intrinsics do lower into regular function calls");

138 if (F.use_empty())

139 return false;

140

141

142

143 Module *M = F.getParent();

144 FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());

145

147 Fn->setLinkage(F.getLinkage());

149

150

151 Fn->addFnAttr(Attribute::NonLazyBind);

152 }

153 }

154

156

158 auto *CB = cast(U.getUser());

159

160 if (CB->getCalledFunction() != &F) {

162 (void)Kind;

163 assert((Kind == objcarc::ARCInstKind::RetainRV ||

164 Kind == objcarc::ARCInstKind::UnsafeClaimRV) &&

165 "use expected to be the argument of operand bundle "

166 "\"clang.arc.attachedcall\"");

168 continue;

169 }

170

171 auto *CI = cast(CB);

172 assert(CI->getCalledFunction() && "Cannot lower an indirect call!");

173

174 IRBuilder<> Builder(CI->getParent(), CI->getIterator());

177 CI->getOperandBundlesAsDefs(BundleList);

179 NewCI->setName(CI->getName());

180

181

182

183

184

185

186

187

190

191

192

193

194

195 unsigned Index;

196 if (F.getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) &&

197 Index)

199 Attribute::Returned);

200

201 if (!CI->use_empty())

202 CI->replaceAllUsesWith(NewCI);

203 CI->eraseFromParent();

204 }

205

206 return true;

207}

208

209

210

211bool PreISelIntrinsicLowering::shouldExpandMemIntrinsicWithSize(

214 if (!CI)

215 return true;

220

221

222

223 return SizeVal > Threshold || Threshold == 0;

224}

225

228

229 if (!TM)

230 return true;

231 const TargetLowering *TLI = TM->getSubtargetImpl(*F)->getTargetLowering();

233}

234

235

236

237bool PreISelIntrinsicLowering::expandMemIntrinsicUses(Function &F) const {

239 bool Changed = false;

240

242 Instruction *Inst = cast(U);

243

244 switch (ID) {

245 case Intrinsic::memcpy: {

246 auto *Memcpy = cast(Inst);

249 if (shouldExpandMemIntrinsicWithSize(Memcpy->getLength(), TTI)) {

250 if (UseMemIntrinsicLibFunc &&

252 break;

253

254

256 Changed = true;

257 Memcpy->eraseFromParent();

258 }

259

260 break;

261 }

262 case Intrinsic::memcpy_inline: {

263

264

265

266 auto *Memcpy = cast(Inst);

267 if (isa(Memcpy->getLength()))

268 break;

269

273 Changed = true;

274 Memcpy->eraseFromParent();

275 break;

276 }

277 case Intrinsic::memmove: {

278 auto *Memmove = cast(Inst);

281 if (shouldExpandMemIntrinsicWithSize(Memmove->getLength(), TTI)) {

282 if (UseMemIntrinsicLibFunc &&

284 break;

285

287 Changed = true;

288 Memmove->eraseFromParent();

289 }

290 }

291

292 break;

293 }

294 case Intrinsic::memset: {

295 auto *Memset = cast(Inst);

298 if (shouldExpandMemIntrinsicWithSize(Memset->getLength(), TTI)) {

299 if (UseMemIntrinsicLibFunc &&

301 break;

302

304 Changed = true;

305 Memset->eraseFromParent();

306 }

307

308 break;

309 }

310 case Intrinsic::memset_inline: {

311

312

313

314 auto *Memset = cast(Inst);

315 if (isa(Memset->getLength()))

316 break;

317

319 Changed = true;

320 Memset->eraseFromParent();

321 break;

322 }

323 case Intrinsic::experimental_memset_pattern: {

324 auto *Memset = cast(Inst);

326 Changed = true;

327 Memset->eraseFromParent();

328 break;

329 }

330 default:

332 }

333 }

334

335 return Changed;

336}

337

338bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {

339 bool Changed = false;

341 switch (F.getIntrinsicID()) {

342 default:

343 break;

344 case Intrinsic::memcpy:

345 case Intrinsic::memcpy_inline:

346 case Intrinsic::memmove:

347 case Intrinsic::memset:

348 case Intrinsic::memset_inline:

349 case Intrinsic::experimental_memset_pattern:

350 Changed |= expandMemIntrinsicUses(F);

351 break;

352 case Intrinsic::load_relative:

354 break;

355 case Intrinsic::is_constant:

356 case Intrinsic::objectsize:

360

362 return Changed;

363 });

364 break;

365#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \

366 case Intrinsic::VPID:

367#include "llvm/IR/VPIntrinsics.def"

371 auto *VPI = cast(CI);

373

374

375

376 Changed |= ED != VPExpansionDetails::IntrinsicUnchanged;

377 bool Removed = ED == VPExpansionDetails::IntrinsicReplaced;

378 return Removed;

379 });

380 break;

381 case Intrinsic::objc_autorelease:

383 break;

384 case Intrinsic::objc_autoreleasePoolPop:

385 Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");

386 break;

387 case Intrinsic::objc_autoreleasePoolPush:

388 Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");

389 break;

390 case Intrinsic::objc_autoreleaseReturnValue:

391 Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");

392 break;

393 case Intrinsic::objc_copyWeak:

395 break;

396 case Intrinsic::objc_destroyWeak:

398 break;

399 case Intrinsic::objc_initWeak:

401 break;

402 case Intrinsic::objc_loadWeak:

404 break;

405 case Intrinsic::objc_loadWeakRetained:

406 Changed |= lowerObjCCall(F, "objc_loadWeakRetained");

407 break;

408 case Intrinsic::objc_moveWeak:

410 break;

411 case Intrinsic::objc_release:

413 break;

414 case Intrinsic::objc_retain:

416 break;

417 case Intrinsic::objc_retainAutorelease:

418 Changed |= lowerObjCCall(F, "objc_retainAutorelease");

419 break;

420 case Intrinsic::objc_retainAutoreleaseReturnValue:

421 Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");

422 break;

423 case Intrinsic::objc_retainAutoreleasedReturnValue:

424 Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");

425 break;

426 case Intrinsic::objc_retainBlock:

428 break;

429 case Intrinsic::objc_storeStrong:

431 break;

432 case Intrinsic::objc_storeWeak:

434 break;

435 case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:

436 Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");

437 break;

438 case Intrinsic::objc_retainedObject:

440 break;

441 case Intrinsic::objc_unretainedObject:

442 Changed |= lowerObjCCall(F, "objc_unretainedObject");

443 break;

444 case Intrinsic::objc_unretainedPointer:

445 Changed |= lowerObjCCall(F, "objc_unretainedPointer");

446 break;

447 case Intrinsic::objc_retain_autorelease:

448 Changed |= lowerObjCCall(F, "objc_retain_autorelease");

449 break;

450 case Intrinsic::objc_sync_enter:

452 break;

453 case Intrinsic::objc_sync_exit:

455 break;

456 }

457 }

458 return Changed;

459}

460

461namespace {

462

463class PreISelIntrinsicLoweringLegacyPass : public ModulePass {

464public:

465 static char ID;

466

467 PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}

468

473 }

474

477 return this->getAnalysis().getTTI(F);

478 };

480 return this->getAnalysis().getTLI(F);

481 };

482

483 const auto *TM = &getAnalysis().getTM<TargetMachine>();

484 PreISelIntrinsicLowering Lowering(TM, LookupTTI, LookupTLI);

485 return Lowering.lowerIntrinsics(M);

486 }

487};

488

489}

490

491char PreISelIntrinsicLoweringLegacyPass::ID;

492

494 "pre-isel-intrinsic-lowering",

495 "Pre-ISel Intrinsic Lowering", false, false)

502

504 return new PreISelIntrinsicLoweringLegacyPass();

505}

506

510

513 };

516 };

517

518 PreISelIntrinsicLowering Lowering(TM, LookupTTI, LookupTLI);

519 if (Lowering.lowerIntrinsics(M))

521 else

523}

static const Function * getParent(const Value *V)

static bool setNonLazyBind(Function &F)

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

Module.h This file contains the declarations for the Module class.

This defines the Use class.

The header file for the LowerConstantIntrinsics pass as used by the new pass manager.

This file defines ARC utility functions which are used by various parts of the compiler.

FunctionAnalysisManager FAM

#define INITIALIZE_PASS_DEPENDENCY(depName)

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

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

static cl::opt< int64_t > MemIntrinsicExpandSizeThresholdOpt("mem-intrinsic-expand-size", cl::desc("Set minimum mem intrinsic size to expand in IR"), cl::init(-1), cl::Hidden)

Threshold to leave statically sized memory intrinsic calls.

pre isel intrinsic lowering

static bool forEachCall(Function &Intrin, T Callback)

pre isel intrinsic Pre ISel Intrinsic Lowering

static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind=false)

static bool canEmitLibcall(const TargetMachine *TM, Function *F, RTLIB::Libcall LC)

static CallInst::TailCallKind getOverridingTailCallKind(const Function &F)

static bool lowerLoadRelative(Function &F)

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

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

Target-Independent Code Generator Pass Configuration Options pass.

This pass exposes codegen information to IR-level passes.

A container for analyses that lazily runs them and caches their results.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

Represent the analysis usage information of a pass.

AnalysisUsage & addRequired()

void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)

Adds the attribute to the indicated argument.

This class represents a function call, abstracting a target machine's calling convention.

void setTailCallKind(TailCallKind TCK)

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

A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...

const Function & getFunction() const

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

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...

static bool mayLowerToFunctionCall(Intrinsic::ID IID)

Check if the intrinsic might lower into a regular function call in the course of IR transformations.

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

virtual bool runOnModule(Module &M)=0

runOnModule - Virtual method overriden by subclasses to process the module being operated on.

A Module instance is used to store all the information related to an LLVM module.

virtual void getAnalysisUsage(AnalysisUsage &) const

getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

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

Analysis pass providing the TargetTransformInfo.

Analysis pass providing the TargetLibraryInfo.

Provides information about what library functions are available for the current target.

const char * getLibcallName(RTLIB::Libcall Call) const

Get the libcall routine name for the specified libcall.

This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...

Primary interface to the complete machine description for the target machine.

Target-Independent Code Generator Pass Configuration Options.

Wrapper pass for TargetTransformInfo.

This pass provides access to the codegen interfaces that are needed for IR-level transformations.

uint64_t getMaxMemIntrinsicInlineSizeThreshold() const

Returns the maximum memset / memcpy size in bytes that still makes it profitable to inline the call.

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

static IntegerType * getInt32Ty(LLVMContext &C)

A Use represents the edge between a Value definition and its users.

LLVM Value Representation.

void setName(const Twine &Name)

Change the name of the value.

An efficient, type-erasing, non-owning reference to a callable.

const ParentTy * getParent() const

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

Libcall

RTLIB::Libcall enum - This enum defines all of the runtime library calls the backend can emit.

initializer< Ty > init(const Ty &Val)

ARCInstKind getAttachedARCFunctionKind(const CallBase *CB)

This function returns the ARCInstKind of the function attached to operand bundle clang_arc_attachedca...

bool IsNeverTail(ARCInstKind Class)

Test if the given class represents instructions which are never safe to mark with the "tail" keyword.

bool IsAlwaysTail(ARCInstKind Class)

Test if the given class represents instructions which are always safe to mark with the "tail" keyword...

ARCInstKind

Equivalence classes of instructions in the ARC Model.

ARCInstKind GetFunctionClass(const Function *F)

Determine if F is one of the special known Functions.

This is an optimization pass for GlobalISel generic memory operations.

bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI, DominatorTree *DT)

void expandMemSetPatternAsLoop(MemSetPatternInst *MemSet)

Expand MemSetPattern as a loop. MemSet is not deleted.

bool expandMemMoveAsLoop(MemMoveInst *MemMove, const TargetTransformInfo &TTI)

Expand MemMove as a loop.

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

ModulePass * createPreISelIntrinsicLoweringPass()

This pass lowers the @llvm.load.relative and @llvm.objc.

VPExpansionDetails expandVectorPredicationIntrinsic(VPIntrinsic &VPI, const TargetTransformInfo &TTI)

Expand a vector predication intrinsic.

void expandMemCpyAsLoop(MemCpyInst *MemCpy, const TargetTransformInfo &TTI, ScalarEvolution *SE=nullptr)

Expand MemCpy as a loop. MemCpy is not deleted.

VPExpansionDetails

Represents the details the expansion of a VP intrinsic.

void expandMemSetAsLoop(MemSetInst *MemSet)

Expand MemSet as a loop. MemSet is not deleted.

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

PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)