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