1 //===-- AMDGPULowerIntrinsics.cpp -----------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "AMDGPUSubtarget.h"
11 #include "llvm/Analysis/TargetTransformInfo.h"
12 #include "llvm/CodeGen/TargetPassConfig.h"
13 #include "llvm/IR/Constants.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/IR/IntrinsicInst.h"
16 #include "llvm/IR/IntrinsicsAMDGPU.h"
17 #include "llvm/IR/IntrinsicsR600.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Target/TargetMachine.h"
21 #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
23 #define DEBUG_TYPE "amdgpu-lower-intrinsics"
29 static int MaxStaticSize
;
31 static cl::opt
<int, true> MemIntrinsicExpandSizeThresholdOpt(
32 "amdgpu-mem-intrinsic-expand-size",
33 cl::desc("Set minimum mem intrinsic size to expand in IR"),
34 cl::location(MaxStaticSize
),
39 class AMDGPULowerIntrinsics
: public ModulePass
{
41 bool makeLIDRangeMetadata(Function
&F
) const;
46 AMDGPULowerIntrinsics() : ModulePass(ID
) {}
48 bool runOnModule(Module
&M
) override
;
49 bool expandMemIntrinsicUses(Function
&F
);
50 StringRef
getPassName() const override
{
51 return "AMDGPU Lower Intrinsics";
54 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
55 AU
.addRequired
<TargetTransformInfoWrapperPass
>();
61 char AMDGPULowerIntrinsics::ID
= 0;
63 char &llvm::AMDGPULowerIntrinsicsID
= AMDGPULowerIntrinsics::ID
;
65 INITIALIZE_PASS(AMDGPULowerIntrinsics
, DEBUG_TYPE
, "Lower intrinsics", false,
68 // TODO: Should refine based on estimated number of accesses (e.g. does it
69 // require splitting based on alignment)
70 static bool shouldExpandOperationWithSize(Value
*Size
) {
71 ConstantInt
*CI
= dyn_cast
<ConstantInt
>(Size
);
72 return !CI
|| (CI
->getSExtValue() > MaxStaticSize
);
75 bool AMDGPULowerIntrinsics::expandMemIntrinsicUses(Function
&F
) {
76 Intrinsic::ID ID
= F
.getIntrinsicID();
79 for (auto I
= F
.user_begin(), E
= F
.user_end(); I
!= E
;) {
80 Instruction
*Inst
= cast
<Instruction
>(*I
);
84 case Intrinsic::memcpy
: {
85 auto *Memcpy
= cast
<MemCpyInst
>(Inst
);
86 if (shouldExpandOperationWithSize(Memcpy
->getLength())) {
87 Function
*ParentFunc
= Memcpy
->getParent()->getParent();
88 const TargetTransformInfo
&TTI
=
89 getAnalysis
<TargetTransformInfoWrapperPass
>().getTTI(*ParentFunc
);
90 expandMemCpyAsLoop(Memcpy
, TTI
);
92 Memcpy
->eraseFromParent();
97 case Intrinsic::memmove
: {
98 auto *Memmove
= cast
<MemMoveInst
>(Inst
);
99 if (shouldExpandOperationWithSize(Memmove
->getLength())) {
100 expandMemMoveAsLoop(Memmove
);
102 Memmove
->eraseFromParent();
107 case Intrinsic::memset
: {
108 auto *Memset
= cast
<MemSetInst
>(Inst
);
109 if (shouldExpandOperationWithSize(Memset
->getLength())) {
110 expandMemSetAsLoop(Memset
);
112 Memset
->eraseFromParent();
125 bool AMDGPULowerIntrinsics::makeLIDRangeMetadata(Function
&F
) const {
126 auto *TPC
= getAnalysisIfAvailable
<TargetPassConfig
>();
130 const TargetMachine
&TM
= TPC
->getTM
<TargetMachine
>();
131 bool Changed
= false;
133 for (auto *U
: F
.users()) {
134 auto *CI
= dyn_cast
<CallInst
>(U
);
138 Function
*Caller
= CI
->getParent()->getParent();
139 const AMDGPUSubtarget
&ST
= AMDGPUSubtarget::get(TM
, *Caller
);
140 Changed
|= ST
.makeLIDRangeMetadata(CI
);
145 bool AMDGPULowerIntrinsics::runOnModule(Module
&M
) {
146 bool Changed
= false;
148 for (Function
&F
: M
) {
149 if (!F
.isDeclaration())
152 switch (F
.getIntrinsicID()) {
153 case Intrinsic::memcpy
:
154 case Intrinsic::memmove
:
155 case Intrinsic::memset
:
156 if (expandMemIntrinsicUses(F
))
160 case Intrinsic::amdgcn_workitem_id_x
:
161 case Intrinsic::r600_read_tidig_x
:
162 case Intrinsic::amdgcn_workitem_id_y
:
163 case Intrinsic::r600_read_tidig_y
:
164 case Intrinsic::amdgcn_workitem_id_z
:
165 case Intrinsic::r600_read_tidig_z
:
166 case Intrinsic::r600_read_local_size_x
:
167 case Intrinsic::r600_read_local_size_y
:
168 case Intrinsic::r600_read_local_size_z
:
169 Changed
|= makeLIDRangeMetadata(F
);
180 ModulePass
*llvm::createAMDGPULowerIntrinsicsPass() {
181 return new AMDGPULowerIntrinsics();