xref: /aosp_15_r20/external/mesa3d/src/gallium/auxiliary/gallivm/lp_bld_passmgr.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include "util/u_debug.h"
29 #include "util/u_memory.h"
30 #include "util/os_time.h"
31 #include "lp_bld_debug.h"
32 #include "lp_bld_passmgr.h"
33 #include "lp_bld_init.h"
34 
35 #if LLVM_VERSION_MAJOR >= 15
36 #define HAVE_CORO 0
37 #define USE_NEW_PASS 1
38 #elif LLVM_VERSION_MAJOR >= 8
39 #define HAVE_CORO 1
40 #define USE_NEW_PASS 0
41 #else
42 #define HAVE_CORO 0
43 #define USE_NEW_PASS 0
44 #endif
45 
46 #if USE_NEW_PASS == 1
47 #include <llvm-c/Transforms/PassBuilder.h>
48 #elif HAVE_CORO == 1
49 #include <llvm-c/Transforms/Scalar.h>
50 #if LLVM_VERSION_MAJOR >= 7
51 #include <llvm-c/Transforms/Utils.h>
52 #endif
53 #if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64)
54 #include <llvm-c/Transforms/IPO.h>
55 #endif
56 #include <llvm-c/Transforms/Coroutines.h>
57 #endif
58 
59 #if USE_NEW_PASS == 0
60 struct lp_passmgr {
61    LLVMPassManagerRef passmgr;
62 #if HAVE_CORO == 1
63    LLVMPassManagerRef cgpassmgr;
64 #endif
65 };
66 #else
67 struct lp_passmgr;
68 #endif
69 
70 bool
lp_passmgr_create(LLVMModuleRef module,struct lp_passmgr ** mgr_p)71 lp_passmgr_create(LLVMModuleRef module, struct lp_passmgr **mgr_p)
72 {
73    struct lp_passmgr *mgr = NULL;
74 #if USE_NEW_PASS == 0
75    mgr = CALLOC_STRUCT(lp_passmgr);
76    if (!mgr)
77       return false;
78 
79    mgr->passmgr = LLVMCreateFunctionPassManagerForModule(module);
80    if (!mgr->passmgr) {
81       free(mgr);
82       return false;
83    }
84 
85 #if HAVE_CORO == 1
86    mgr->cgpassmgr = LLVMCreatePassManager();
87 #endif
88    /*
89     * TODO: some per module pass manager with IPO passes might be helpful -
90     * the generated texture functions may benefit from inlining if they are
91     * simple, or constant propagation into them, etc.
92     */
93 
94 #if HAVE_CORO == 1
95 #if LLVM_VERSION_MAJOR <= 8 && (DETECT_ARCH_AARCH64 || DETECT_ARCH_ARM || DETECT_ARCH_S390 || DETECT_ARCH_MIPS64)
96    LLVMAddArgumentPromotionPass(mgr->cgpassmgr);
97    LLVMAddFunctionAttrsPass(mgr->cgpassmgr);
98 #endif
99    LLVMAddCoroEarlyPass(mgr->cgpassmgr);
100    LLVMAddCoroSplitPass(mgr->cgpassmgr);
101    LLVMAddCoroElidePass(mgr->cgpassmgr);
102 #endif
103 
104    if ((gallivm_perf & GALLIVM_PERF_NO_OPT) == 0) {
105       /*
106        * TODO: Evaluate passes some more - keeping in mind
107        * both quality of generated code and compile times.
108        */
109       /*
110        * NOTE: if you change this, don't forget to change the output
111        * with GALLIVM_DEBUG_DUMP_BC in gallivm_compile_module.
112        */
113       LLVMAddScalarReplAggregatesPass(mgr->passmgr);
114       LLVMAddEarlyCSEPass(mgr->passmgr);
115       LLVMAddCFGSimplificationPass(mgr->passmgr);
116       /*
117        * FIXME: LICM is potentially quite useful. However, for some
118        * rather crazy shaders the compile time can reach _hours_ per shader,
119        * due to licm implying lcssa (since llvm 3.5), which can take forever.
120        * Even for sane shaders, the cost of licm is rather high (and not just
121        * due to lcssa, licm itself too), though mostly only in cases when it
122        * can actually move things, so having to disable it is a pity.
123        * LLVMAddLICMPass(mgr->passmgr);
124        */
125       LLVMAddReassociatePass(mgr->passmgr);
126       LLVMAddPromoteMemoryToRegisterPass(mgr->passmgr);
127 #if LLVM_VERSION_MAJOR <= 11
128       LLVMAddConstantPropagationPass(mgr->passmgr);
129 #else
130       LLVMAddInstructionSimplifyPass(mgr->passmgr);
131 #endif
132       LLVMAddInstructionCombiningPass(mgr->passmgr);
133       LLVMAddGVNPass(mgr->passmgr);
134    }
135    else {
136       /* We need at least this pass to prevent the backends to fail in
137        * unexpected ways.
138        */
139       LLVMAddPromoteMemoryToRegisterPass(mgr->passmgr);
140    }
141 #if HAVE_CORO == 1
142    LLVMAddCoroCleanupPass(mgr->passmgr);
143 #endif
144 #endif
145    *mgr_p = mgr;
146    return true;
147 }
148 
149 void
lp_passmgr_run(struct lp_passmgr * mgr,LLVMModuleRef module,LLVMTargetMachineRef tm,const char * module_name)150 lp_passmgr_run(struct lp_passmgr *mgr,
151                LLVMModuleRef module,
152                LLVMTargetMachineRef tm,
153                const char *module_name)
154 {
155    int64_t time_begin;
156 
157    if (gallivm_debug & GALLIVM_DEBUG_PERF)
158       time_begin = os_time_get();
159 
160 #if USE_NEW_PASS == 1
161    char passes[1024];
162    passes[0] = 0;
163 
164    /*
165     * there should be some way to combine these two pass runs but I'm not seeing it,
166     * at the time of writing.
167     */
168    strcpy(passes, "default<O0>");
169 
170    LLVMPassBuilderOptionsRef opts = LLVMCreatePassBuilderOptions();
171    LLVMRunPasses(module, passes, tm, opts);
172 
173    if (!(gallivm_perf & GALLIVM_PERF_NO_OPT))
174 #if LLVM_VERSION_MAJOR >= 18
175       strcpy(passes, "sroa,early-cse,simplifycfg,reassociate,mem2reg,instsimplify,instcombine<no-verify-fixpoint>");
176 #else
177       strcpy(passes, "sroa,early-cse,simplifycfg,reassociate,mem2reg,instsimplify,instcombine");
178 #endif
179    else
180       strcpy(passes, "mem2reg");
181 
182    LLVMRunPasses(module, passes, tm, opts);
183    LLVMDisposePassBuilderOptions(opts);
184 #else
185 #if HAVE_CORO == 1
186    LLVMRunPassManager(mgr->cgpassmgr, module);
187 #endif
188    /* Run optimization passes */
189    LLVMInitializeFunctionPassManager(mgr->passmgr);
190    LLVMValueRef func;
191    func = LLVMGetFirstFunction(module);
192    while (func) {
193       if (0) {
194          debug_printf("optimizing func %s...\n", LLVMGetValueName(func));
195       }
196 
197    /* Disable frame pointer omission on debug/profile builds */
198    /* XXX: And workaround http://llvm.org/PR21435 */
199 #if MESA_DEBUG || defined(PROFILE) || DETECT_ARCH_X86 || DETECT_ARCH_X86_64
200       LLVMAddTargetDependentFunctionAttr(func, "no-frame-pointer-elim", "true");
201       LLVMAddTargetDependentFunctionAttr(func, "no-frame-pointer-elim-non-leaf", "true");
202 #endif
203 
204       LLVMRunFunctionPassManager(mgr->passmgr, func);
205       func = LLVMGetNextFunction(func);
206    }
207    LLVMFinalizeFunctionPassManager(mgr->passmgr);
208 #endif
209    if (gallivm_debug & GALLIVM_DEBUG_PERF) {
210       int64_t time_end = os_time_get();
211       int time_msec = (int)((time_end - time_begin) / 1000);
212       assert(module_name);
213       debug_printf("optimizing module %s took %d msec\n",
214                    module_name, time_msec);
215    }
216 }
217 
218 void
lp_passmgr_dispose(struct lp_passmgr * mgr)219 lp_passmgr_dispose(struct lp_passmgr *mgr)
220 {
221 #if USE_NEW_PASS == 0
222    if (mgr->passmgr) {
223       LLVMDisposePassManager(mgr->passmgr);
224       mgr->passmgr = NULL;
225    }
226 
227 #if HAVE_CORO == 1
228    if (mgr->cgpassmgr) {
229       LLVMDisposePassManager(mgr->cgpassmgr);
230       mgr->cgpassmgr = NULL;
231    }
232 #endif
233    FREE(mgr);
234 #endif
235 }
236