I. Introduction▲
Si vous avez lu mon article précédent sur ce sujet (Compilateur C++ JIT avec LLVM - Partie 2) vous avez probablement noté qu’il y avait un sérieux problème avec l’implémentation de NervJIT que j’ai décrite (et aussi dans l’implémentation expérimentale de runClang
(
) décrite dans le tout premier article) : je ne pouvais pas libérer les ressources de la passe d’optimisation IR (Intermediate Representation : représentation intermédiaire), ni non plus l’objet llvm::orc::LLJIT, car tenter de le faire produisait des plantées silencieuses. Dans ce nouveau post, nous nous concentrerons sur les étapes que j’ai suivies pour me débarrasser finalement de ce problème.
Alors, allons-y !????
II. Mise à jour du mécanisme d’optimisation IR▲
Si vous vous en souvenez, dans le destructeur de notre NervJITImpl, nous devions explicitement « libérer » les pointeurs en question (en entrainant ainsi malheureusement une fuite de mémoire…) comme suit :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
NervJITImpl::
~
NervJITImpl()
{
// Note: the memory for the LLJIT object will leak here because we get a crash when we try to delete it.
std::
cout <<
"Releasing undestructible pointers."
<<
std::
endl;
lljit.release();
moduleAnalysisManager.release();
cGSCCAnalysisManager.release();
functionAnalysisManager.release();
loopAnalysisManager.release();
std::
cout <<
"Done releasing undestructible pointers."
<<
std::
endl;
}
Par conséquent, j’ai décidé d’examiner en premier lieu ces quatre objets AnalysisManager. Avant de me demander « pourquoi est-ce que je ne peux pas les supprimer proprement ? », je me suis plutôt posé la question : « Ai-je réellement besoin de ces trucs ? » Je suis donc parti à la recherche des techniques discutées en ligne sur l’optimisation des modules LLVM IR.
Le problème à ce niveau est que LLVM évolue continuellement (rapidement) et donc qu’il n’est pas simple de trouver quelque chose qui soit à jour avec la version Git que j’utilise. J’ai finalement trouvé cette page sur Stack Overflow : https://stackoverflow.com/questions/53738883/run-default-optimization-pipeline-using-modern-llvm/53739108.
Même si cela concernait LLVM version 7.0, la bonne chose était qu’il faisait référence à un des outils de LLVM fourni comme modèle de base : l’outil opt, que je peux trouver dans l’arborescence de la version courante des sources de LLVM !
J’ai jeté un coup d’œil rapide aux sources trouvées dans llvm\tool\opt (surtout le fichier opt.cpp) et, de là, vous pouvez facilement confirmer que le code présenté dans l’article de Stack Overflow était encore largement similaire à ce qui est actuellement fait dans opt. Ainsi, j’ai pu heureusement sauter, plein d’espoir, dans ce train et implémenter ma propre mise à jour de la logique de « l’optimisation de module » pour mon composant NervJIT :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
void
addOptPasses(
llvm::legacy::
PassManagerBase &
passes,
llvm::legacy::
FunctionPassManager &
fnPasses,
llvm::
TargetMachine *
machine
) {
llvm::
PassManagerBuilder builder;
builder.OptLevel =
3
;
builder.SizeLevel =
0
;
builder.Inliner =
llvm::
createFunctionInliningPass(3
, 0
, false
);
builder.LoopVectorize =
true
;
builder.DisableUnrollLoops =
false
;
builder.SLPVectorize =
true
;
machine->
adjustPassManager(builder);
builder.populateFunctionPassManager(fnPasses);
builder.populateModulePassManager(passes);
}
void
addLinkPasses(llvm::legacy::
PassManagerBase &
passes) {
llvm::
PassManagerBuilder builder;
builder.VerifyInput =
true
;
builder.Inliner =
llvm::
createFunctionInliningPass(3
, 0
, false
);
builder.populateLTOPassManager(passes);
}
void
NervJITImpl::
optimizeModule(llvm::
Module *
module
) {
module
->
setTargetTriple(targetMachine->
getTargetTriple().str());
module
->
setDataLayout(targetMachine->
createDataLayout());
// DEBUG_MSG("Creating legacy pass manager.");
llvm::legacy::
PassManager passes;
passes.add(new
llvm::
TargetLibraryInfoWrapperPass(targetMachine->
getTargetTriple()));
passes.add(llvm::
createTargetTransformInfoWrapperPass(targetMachine->
getTargetIRAnalysis()));
// DEBUG_MSG("Creating legacy function pass manager.");
llvm::legacy::
FunctionPassManager fnPasses(module
);
fnPasses.add(llvm::
createTargetTransformInfoWrapperPass(targetMachine->
getTargetIRAnalysis()));
addOptPasses(passes, fnPasses, targetMachine.get());
addLinkPasses(passes);
// DEBUG_MSG("Optimizing functions");
fnPasses.doInitialization();
for
(llvm::
Function &
func : *
module
) {
fnPasses.run(func);
}
fnPasses.doFinalization();
passes.add(llvm::
createVerifierPass());
// DEBUG_MSG("Running PassManager.");
passes.run(*
module
);
// DEBUG_MSG("Optimization done.");
}
Pour pouvoir compiler le code ci-dessus, la seule chose nouvelle dont j’ai eu besoin fut un pointeur llvm
:
:TargetMachine approprié : ça m’a pris un peu de temps pour trouver comment en obtenir un, mais à la fin c’est assez direct (de nouveau, je construis cet objet dans le constructeur de mon NervJITImpl) :
auto
jtmb =
CHECK_LLVM(JITTargetMachineBuilder::
detectHost());
targetMachine =
CHECK_LLVM(jtmb.createTargetMachine());
Puis, tout ce que j’ai dû faire fut de remplacer les appels à la fonction ModulePassManager
:
:run
(
) à l’intérieur de la méthode NervJITImpl
:
:loadModule
(
) par ma nouvelle fonction optimizeModule
(
):
2.
3.
4.
5.
6.
// We run the optimizations:
DEBUG_MSG("Optimizing module..."
);
//modulePassManager.run(*module, *moduleAnalysisManager);
optimizeModule(module
.get());
DEBUG_MSG("Module function list: "
);
… Et… cela a planté LAMENTABLEMENT… Un crash silencieux quelque part après l’affichage « Optimizing module… » (Arrff, je pense que mes espoirs étaient trop élevés…).
Donc, retour aux investigations, innombrables tests “changement/construction/exécution”, et j’ai finalement tracé le problème jusqu’à, une fois encore, que sa source soit liée au module pass manager! En fait, j’ai pu faire marcher l’étape d’optimisation en commentant ces deux lignes (respectivement tout à la fin de addOptPasses
(
)et addLinkPasses
(
)) :
2.
3.
4.
5.
// in addOptPasses():
// builder.populateModulePassManager(passes);
// in addLinkPasses():
// builder.populateLTOPassManager(passes);
Bien sûr ce n’était pas une solution acceptable ; ce code fonctionnait bien dans l’outil opt de LLVM, après tout ! Il était donc temps de changer ma perspective et de me focaliser plutôt sur l’outil opt lui-même en tentant de comprendre ce que je faisais faux dans mon propre projet.
III. Reconstruire l’outil LLVM opt▲
Pendant que je tournais autour de opt de LLVM, je l’ai exécuté avec succès depuis la ligne de commande sur un fichier de test LLVM pris au hasard (que j’ai trouvé ailleurs dans l’arborescence des sources de LLVM), en utilisant ce genre de commande :
opt --
O3 --
debugify-
each --
verify-
each bcsection.ll -
o result.bc
Ce qui a donné ce genre de résultat :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
CheckModuleDebugify [Force set function attributes]: PASS
CheckModuleDebugify [Infer set function attributes]: PASS
CheckFunctionDebugify [Call-
site splitting]: PASS
CheckModuleDebugify [Interprocedural Sparse Conditional Constant Propagation]: PASS
CheckModuleDebugify [Called Value Propagation]: PASS
CheckModuleDebugify [Global Variable Optimizer]: PASS
CheckFunctionDebugify [Promote Memory to Register]: PASS
CheckModuleDebugify [Dead Argument Elimination]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckModuleDebugify [Globals Alias Analysis]: PASS
CheckFunctionDebugify [SROA]: PASS
CheckFunctionDebugify [Early CSE w/
MemorySSA]: PASS
CheckFunctionDebugify [Speculatively execute instructions if
target has divergent branches]: PASS
CheckFunctionDebugify [Jump Threading]: PASS
CheckFunctionDebugify [Value Propagation]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Combine pattern based expressions]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Conditionally eliminate dead library calls]: PASS
CheckFunctionDebugify [PGOMemOPSize]: PASS
CheckFunctionDebugify [Tail Call Elimination]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Reassociate expressions]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [MergedLoadStoreMotion]: PASS
CheckFunctionDebugify [Global Value Numbering]: PASS
CheckFunctionDebugify [MemCpy Optimization]: PASS
CheckFunctionDebugify [Sparse Conditional Constant Propagation]: PASS
CheckFunctionDebugify [Bit-
Tracking Dead Code Elimination]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Jump Threading]: PASS
CheckFunctionDebugify [Value Propagation]: PASS
CheckFunctionDebugify [Dead Store Elimination]: PASS
CheckFunctionDebugify [Aggressive Dead Code Elimination]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckModuleDebugify [A No-
Op Barrier Pass]: PASS
CheckModuleDebugify [Eliminate Available Externally Globals]: PASS
CheckModuleDebugify [Deduce function attributes in RPO]: PASS
CheckModuleDebugify [Global Variable Optimizer]: PASS
CheckModuleDebugify [Dead Global Elimination]: PASS
CheckModuleDebugify [Globals Alias Analysis]: PASS
CheckFunctionDebugify [Float to int
]: PASS
CheckFunctionDebugify [Lower constant intrinsics]: PASS
CheckFunctionDebugify [Loop Distribution]: PASS
CheckFunctionDebugify [Loop Vectorization]: PASS
CheckFunctionDebugify [Optimize scalar/
vector ops]: PASS
CheckFunctionDebugify [Early CSE]: PASS
CheckFunctionDebugify [Loop Load Elimination]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [SLP Vectorizer]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Warn about non-
applied transformations]: PASS
CheckFunctionDebugify [Alignment from assumptions]: PASS
CheckModuleDebugify [Strip Unused Function Prototypes]: PASS
CheckModuleDebugify [Dead Global Elimination]: PASS
CheckModuleDebugify [Merge Duplicate Global Constants]: PASS
CheckFunctionDebugify [Remove redundant instructions]: PASS
CheckFunctionDebugify [Hoist/
decompose integer division and
remainder]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
Pour être honnête, je n’étais toujours pas sûr de si ce programme se terminait élégamment ou se plantait silencieusement après la dernière ligne « CheckFunctionDebugify » rapportée ci-dessus, mais c’était déjà un bon point de référence de toute façon et je devais pouvoir au moins reproduire ces résultats si je reconstruisais cet outil moi-même à partir des sources, non ?
IV. Configuration de construction naïve▲
À ce stade, on se référera naturellement aux fichiers CMake de l’outil opt de l’arborescence des sources de LLVM pour comprendre comment configurer un projet clone à partir « des sources LLVM ». Habituellement, CMake est un langage assez simple à utiliser, d’accord ? Eh bien… malheureusement, cette fois, sauf si vous êtes un gourou absolu de CMake, je crains que cette voie ne vous conduise pas bien loin : les fichiers CMake de LLVM sont réellement cryptiques, je vous souhaite donc bonne chance pour essayer d’extraire l’information dont vous avez besoin de ce type de contenu :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
set(LLVM_LINK_COMPONENTS
AllTargetsAsmParsers
AllTargetsCodeGens
AllTargetsDescs
AllTargetsInfos
AggressiveInstCombine
Analysis
BitWriter
CodeGen
Core
Coroutines
IPO
IRReader
InstCombine
Instrumentation
MC
ObjCARCOpts
Remarks
ScalarOpts
Support
Target
TransformUtils
Vectorize
Passes
)
add_llvm_tool(opt
AnalysisWrappers.cpp
BreakpointPrinter.cpp
GraphPrinters.cpp
NewPMDriver.cpp
PassPrinters.cpp
PrintSCC.cpp
opt.cpp
ENABLE_PLUGINS
DEPENDS
intrinsics_gen
SUPPORT_PLUGINS
)
export_executable_symbols_for_plugins(opt)
if
(LLVM_BUILD_EXAMPLES)
target_link_libraries(opt PRIVATE ExampleIRTransforms)
endif(LLVM_BUILD_EXAMPLES)
Si vous voulez vraiment tenter le coup et voulez trouver les définitions et le comportement de toutes les fonctions/macros utilisées dans ce fichier, un point de départ est le fichier ${votre répertoire d’installation de LLVM}/lib/cmake/llvm/AddLLVM.cmake. Mais vous aurez été prévenu… (Bon, amusement ! et assurez-vous d'arrêter de lire ce fichier avant de vous pendre dans votre salle de bain…)
J’ai donc décidé qu’il serait aussi bien de prendre juste les fichiers source de ce répertoire racine et de construire le fichier CMake moi-même : après tout, j’ai déjà pu construire un nvLLVM « fonctionnel » (bon, à l’exception d’un plantage silencieux de ton «module fonctionnel» ou d’une fuite mémoire, Manu, certes !) avec un fichier CMakeLists.txt fait main, je devrais donc peut-être pouvoir l’utiliser comme modèle et voir comment ça marche…
Et c’est exactement ce que j’ai fait : construire un sous-projet test que j’ai nommé test_llvm_opt , lier avec toutes les bibliothèques de LLVM et utiliser les mêmes paramètres CXX que dans mon précédent sous-projet nvLLVM .
Étonnamment, faire compiler ce clone de l’outil opt de LLVM n’a pas été trop difficile finalement, mais ensuite est venu le moment de l’essayer (en utilisant exactement la même entrée qu’avec le binaire officiel évidemment) :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
test_llvm_opt.exe --
O3 --
debugify-
each --
verify-
each bcsection.ll -
o result.bc
CheckModuleDebugify [Force set function attributes]: PASS
CheckModuleDebugify [Infer set function attributes]: PASS
CheckFunctionDebugify [Call-
site splitting]: PASS
CheckModuleDebugify [Interprocedural Sparse Conditional Constant Propagation]: PASS
CheckModuleDebugify [Called Value Propagation]: PASS
CheckModuleDebugify [Global Variable Optimizer]: PASS
CheckFunctionDebugify [Promote Memory to Register]: PASS
CheckModuleDebugify [Dead Argument Elimination]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckModuleDebugify [Globals Alias Analysis]: PASS
CheckFunctionDebugify [SROA]: PASS
CheckFunctionDebugify [Early CSE w/
MemorySSA]: PASS
CheckFunctionDebugify [Speculatively execute instructions if
target has divergent branches]: PASS
CheckFunctionDebugify [Jump Threading]: PASS
CheckFunctionDebugify [Value Propagation]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Combine pattern based expressions]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Conditionally eliminate dead library calls]: PASS
CheckFunctionDebugify [PGOMemOPSize]: PASS
CheckFunctionDebugify [Tail Call Elimination]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Reassociate expressions]: PASS
CheckFunctionDebugify [Simplify the CFG]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [MergedLoadStoreMotion]: PASS
CheckFunctionDebugify [Global Value Numbering]: PASS
CheckFunctionDebugify [MemCpy Optimization]: PASS
CheckFunctionDebugify [Sparse Conditional Constant Propagation]: PASS
CheckFunctionDebugify [Bit-
Tracking Dead Code Elimination]: PASS
CheckFunctionDebugify [Combine redundant instructions]: PASS
CheckFunctionDebugify [Jump Threading]: PASS
CheckFunctionDebugify [Value Propagation]: PASS
CheckFunctionDebugify [Dead Store Elimination]: PASS
Et CATABOUM ! Le processus meurt exactement à la même place à chaque fois que j’exécute cette commande (alors que l’outil opt officiel continue depuis ici avec beaucoup de passes additionnelles, comme [Aggressive Dead Code Elimination]).
Arrivé là, j’étais réellement convaincu que quelque chose était faux dans ma configuration de CMake, mais quoi ?
V. Configuration de construction correcte▲
J’ai repris les fichiers CMake officiels de opt, en essayant de me concentrer au maximum sur tous les éléments de configuration, les macros, les conditions, etc. C’était clairement énorme et ingérable. Je commençais à perdre la foi, mais j’ai alors réalisé quelque chose qui a sauvé ma journée : CMake finit par simplement écrire un Makefile (à peu près) « normal » ! (Au moins lorsqu’on utilise le générateur Nmake comme je le fais.)
De toute façon, il ne me restait pas d’autre option, je me suis donc plongé dans les fichiers de construction générés par CMake pour mes sources Git de LLVM, ceci m’a réellement ouvert les yeux !
J’ai d’abord trouvé le fichier tools\opt\CMakeFiles\opt.dir\build.make, dans lequel vous trouverez ce type de contenu :
2.
3.
4.
5.
6.
tools\opt\CMakeFiles\opt.dir\AnalysisWrappers.cpp.obj: tools\opt\CMakeFiles\opt.dir\flags.make
tools\opt\CMakeFiles\opt.dir\AnalysisWrappers.cpp.obj: W:\Projects\NervSeed\deps\build\llvm-
20200409
\llvm\tools\opt\AnalysisWrappers.cpp
@$(CMAKE_COMMAND) -
E cmake_echo_color --
switch
=
$(COLOR) --
green --
progress-
dir=
W:\Projects\NervSeed\deps\build\llvm-
20200409
\build\CMakeFiles --
progress-
num=
$(CMAKE_PROGRESS_1) "Building CXX object tools/opt/CMakeFiles/opt.dir/AnalysisWrappers.cpp.obj"
cd W:\Projects\NervSeed\deps\build\llvm-
20200409
\build\tools\opt
D
:
\Apps\VisualStudio2017_CE\VC\Tools\MSVC\14.16.27023
\bin\Hostx64\x64\cl.exe @<<
/
nologo /
TP $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) /
FoCMakeFiles\opt.dir\AnalysisWrappers.cpp.obj /
FdCMakeFiles\opt.dir\ /
FS -
c W:\Projects\NervSeed\deps\build\llvm-
20200409
\llvm\tools\opt\AnalysisWrappers.cpp
Et au début de ce fichier, nous avons :
2.
3.
4.
5.
6.
7.
8.
# Include any dependencies generated for this target.
include tools\opt\CMakeFiles\opt.dir\depend.make
# Include the progress variables for this target.
include tools\opt\CMakeFiles\opt.dir\progress.make
# Include the compile flags for this target's objects.
include tools\opt\CMakeFiles\opt.dir\flags.make
Donc, naturellement, vous vérifiez le fichier frère flags.make, et là, bingo !
2.
3.
4.
5.
6.
7.
# compile CXX with D:/Apps/VisualStudio2017_CE/VC/Tools/MSVC/14.16.27023/bin/Hostx64/x64/cl.exe
# compile RC with C:/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64/rc.exe
CXX_FLAGS =
/
DWIN32 /
D_WINDOWS /
Zc:inline
/
Zc:strictStrings /
Oi /
Zc:rvalueCast /
W4 -
wd4141 -
wd4146 -
wd4244 -
wd4267 -
wd4291 -
wd4351 -
wd4456 -
wd4457 -
wd4458 -
wd4459 -
wd4503 -
wd4624 -
wd4722 -
wd4100 -
wd4127 -
wd4512 -
wd4505 -
wd4610 -
wd4510 -
wd4702 -
wd4245 -
wd4706 -
wd4310 -
wd4701 -
wd4703 -
wd4389 -
wd4611 -
wd4805 -
wd4204 -
wd4577 -
wd4091 -
wd4592 -
wd4319 -
wd4709 -
wd4324 -
w14062 -
we4238 /
Gw /
MD /
O2 /
Ob2 /
DNDEBUG /
EHs-
c-
/
GR-
CXX_DEFINES =
-
DGTEST_HAS_RTTI=
0
-
DUNICODE -
D_CRT_NONSTDC_NO_DEPRECATE -
D_CRT_NONSTDC_NO_WARNINGS -
D_CRT_SECURE_NO_DEPRECATE -
D_CRT_SECURE_NO_WARNINGS -
D_HAS_EXCEPTIONS=
0
-
D_SCL_SECURE_NO_DEPRECATE -
D_SCL_SECURE_NO_WARNINGS -
D_UNICODE -
D__STDC_CONSTANT_MACROS -
D__STDC_FORMAT_MACROS -
D__STDC_LIMIT_MACROS
CXX_INCLUDES =
-
IW:\Projects\NervSeed\deps\build\llvm-
20200409
\build\tools\opt -
IW:\Projects\NervSeed\deps\build\llvm-
20200409
\llvm\tools\opt -
IW:\Projects\NervSeed\deps\build\llvm-
20200409
\build\include -
IW:\Projects\NervSeed\deps\build\llvm-
20200409
\llvm\include
- Avec ces lignes, vous savez exactement quelles commandes sont exécutées pour compiler les fichiers cpp du répertoire en fichiers objet.
Et finalement de retour à build.make, vous trouverez aussi la définition de la cible d’édition des liens :
bin\opt.exe: tools\opt\CMakeFiles\opt.dir\objects1.rsp
@$(CMAKE_COMMAND) -
E cmake_echo_color --
switch
=
$(COLOR) --
green --
bold --
progress-
dir=
W:\Projects\NervSeed\deps\build\llvm-
20200409
\build\CMakeFiles --
progress-
num=
$(CMAKE_PROGRESS_9) "Linking CXX executable ..\..
\b
in\opt.exe"
cd W:\Projects\NervSeed\deps\build\llvm-
20200409
\build\tools\opt
W
:
\Projects\NervSeed\tools\windows\cmake-
3.9.2
\bin\cmake.exe -
E vs_link_exe --
intdir=
CMakeFiles\opt.dir --
manifests --
D:\Apps\VisualStudio2017_CE\VC\Tools\MSVC\14.16.27023
\bin\Hostx64\x64\link.exe /
nologo @CMakeFiles\opt.dir\objects1.rsp @<<
/
out:..\..\bin\opt.exe /
implib:..\..\lib\opt.lib /
pdb:W:\Projects\NervSeed\deps\build\llvm-
20200409
\build\bin\opt.pdb /
version:0.0
/
machine:x64 /
STACK:10000000
/
INCREMENTAL:NO /
subsystem:console ..\..\lib\LLVMAArch64AsmParser.lib ..\..\lib\LLVMAMDGPUAsmParser.lib ..\..\lib\LLVMARMAsmParser.lib ..\..\lib\LLVMAVRAsmParser.lib ..\..\lib\LLVMBPFAsmParser.lib ..\..\lib\LLVMHexagonAsmParser.lib ..\..\lib\LLVMLanaiAsmParser.lib ..\..\lib\LLVMMipsAsmParser.lib ..\..\lib\LLVMMSP430AsmParser.lib ..\..\lib\LLVMPowerPCAsmParser.lib ..\..\lib\LLVMRISCVAsmParser.lib ..\..\lib\LLVMSparcAsmParser.lib ..\..\lib\LLVMSystemZAsmParser.lib ..\..\lib\LLVMWebAssemblyAsmParser.lib ..\..\lib\LLVMX86AsmParser.lib ..\..\lib\LLVMAArch64CodeGen.lib ..\..\lib\LLVMAMDGPUCodeGen.lib ..\..\lib\LLVMARMCodeGen.lib ..\..\lib\LLVMAVRCodeGen.lib ..\..\lib\LLVMBPFCodeGen.lib ..\..\lib\LLVMHexagonCodeGen.lib ..\..\lib\LLVMLanaiCodeGen.lib ..\..\lib\LLVMMipsCodeGen.lib ..\..\lib\LLVMMSP430CodeGen.lib ..\..\lib\LLVMNVPTXCodeGen.lib ..\..\lib\LLVMPowerPCCodeGen.lib ..\..\lib\LLVMRISCVCodeGen.lib ..\..\lib\LLVMSparcCodeGen.lib ..\..\lib\LLVMSystemZCodeGen.lib ..\..\lib\LLVMWebAssemblyCodeGen.lib ..\..\lib\LLVMX86CodeGen.lib ..\..\lib\LLVMXCoreCodeGen.lib ..\..\lib\LLVMAArch64Desc.lib ..\..\lib\LLVMAMDGPUDesc.lib ..\..\lib\LLVMARMDesc.lib ..\..\lib\LLVMAVRDesc.lib ..\..\lib\LLVMBPFDesc.lib ..\..\lib\LLVMHexagonDesc.lib ..\..\lib\LLVMLanaiDesc.lib ..\..\lib\LLVMMipsDesc.lib ..\..\lib\LLVMMSP430Desc.lib ..\..\lib\LLVMNVPTXDesc.lib ..\..\lib\LLVMPowerPCDesc.lib ..\..\lib\LLVMRISCVDesc.lib ..\..\lib\LLVMSparcDesc.lib ..\..\lib\LLVMSystemZDesc.lib ..\..\lib\LLVMWebAssemblyDesc.lib ..\..\lib\LLVMX86Desc.lib ..\..\lib\LLVMXCoreDesc.lib ..\..\lib\LLVMAArch64Info.lib ..\..\lib\LLVMAMDGPUInfo.lib ..\..\lib\LLVMARMInfo.lib ..\..\lib\LLVMAVRInfo.lib ..\..\lib\LLVMBPFInfo.lib ..\..\lib\LLVMHexagonInfo.lib ..\..\lib\LLVMLanaiInfo.lib ..\..\lib\LLVMMipsInfo.lib ..\..\lib\LLVMMSP430Info.lib ..\..\lib\LLVMNVPTXInfo.lib ..\..\lib\LLVMPowerPCInfo.lib ..\..\lib\LLVMRISCVInfo.lib ..\..\lib\LLVMSparcInfo.lib ..\..\lib\LLVMSystemZInfo.lib ..\..\lib\LLVMWebAssemblyInfo.lib ..\..\lib\LLVMX86Info.lib ..\..\lib\LLVMXCoreInfo.lib ..\..\lib\LLVMAggressiveInstCombine.lib ..\..\lib\LLVMAnalysis.lib ..\..\lib\LLVMBitWriter.lib ..\..\lib\LLVMCodeGen.lib ..\..\lib\LLVMCore.lib ..\..\lib\LLVMCoroutines.lib ..\..\lib\LLVMipo.lib ..\..\lib\LLVMIRReader.lib ..\..\lib\LLVMInstCombine.lib ..\..\lib\LLVMInstrumentation.lib ..\..\lib\LLVMMC.lib ..\..\lib\LLVMObjCARCOpts.lib ..\..\lib\LLVMRemarks.lib ..\..\lib\LLVMScalarOpts.lib ..\..\lib\LLVMSupport.lib ..\..\lib\LLVMTarget.lib ..\..\lib\LLVMTransformUtils.lib ..\..\lib\LLVMVectorize.lib ..\..\lib\LLVMPasses.lib ..\..\lib\LLVMAArch64Utils.lib ..\..\lib\LLVMAMDGPUUtils.lib ..\..\lib\LLVMMIRParser.lib ..\..\lib\LLVMARMUtils.lib ..\..\lib\LLVMHexagonAsmParser.lib ..\..\lib\LLVMHexagonDesc.lib ..\..\lib\LLVMHexagonInfo.lib ..\..\lib\LLVMLanaiAsmParser.lib ..\..\lib\LLVMLanaiDesc.lib ..\..\lib\LLVMLanaiInfo.lib ..\..\lib\LLVMRISCVUtils.lib ..\..\lib\LLVMMCDisassembler.lib ..\..\lib\LLVMCFGuard.lib ..\..\lib\LLVMGlobalISel.lib ..\..\lib\LLVMX86Utils.lib ..\..\lib\LLVMAsmPrinter.lib ..\..\lib\LLVMDebugInfoDWARF.lib ..\..\lib\LLVMSelectionDAG.lib ..\..\lib\LLVMCodeGen.lib ..\..\lib\LLVMCoroutines.lib ..\..\lib\LLVMipo.lib ..\..\lib\LLVMBitWriter.lib ..\..\lib\LLVMIRReader.lib ..\..\lib\LLVMAsmParser.lib ..\..\lib\LLVMFrontendOpenMP.lib ..\..\lib\LLVMLinker.lib ..\..\lib\LLVMInstrumentation.lib ..\..\lib\LLVMScalarOpts.lib ..\..\lib\LLVMAggressiveInstCombine.lib ..\..\lib\LLVMInstCombine.lib ..\..\lib\LLVMTarget.lib ..\..\lib\LLVMVectorize.lib ..\..\lib\LLVMTransformUtils.lib ..\..\lib\LLVMAnalysis.lib ..\..\lib\LLVMProfileData.lib ..\..\lib\LLVMObject.lib ..\..\lib\LLVMMCParser.lib ..\..\lib\LLVMMC.lib ..\..\lib\LLVMDebugInfoCodeView.lib ..\..\lib\LLVMDebugInfoMSF.lib ..\..\lib\LLVMBitReader.lib ..\..\lib\LLVMTextAPI.lib ..\..\lib\LLVMCore.lib ..\..\lib\LLVMRemarks.lib ..\..\lib\LLVMBitstreamReader.lib ..\..\lib\LLVMBinaryFormat.lib ..\..\lib\LLVMSupport.lib psapi.lib shell32.lib ole32.lib uuid.lib advapi32.lib delayimp.lib -
delayload:shell32.dll -
delayload:ole32.dll ..\..\lib\LLVMDemangle.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib
Je pense que c’est une leçon vraiment très importante que chaque développeur devrait garder à l’esprit avec ce genre d’expérience : si vous vous sentez dépassé par les fonctions CMake utilisées dans un projet donné que vous voulez répliquer quelque part ailleurs, vérifiez les fichiers générés par CMake pour trouver les commandes de construction brutes et les paramètres pour le compilateur et l’éditeur de liens.
Bien sûr, avec ces nouvelles informations, j’ai immédiatement mis à jour mon fichier CMakeLists.txt pour test_llvm_opt ainsi :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
SET(TARGET_NAME "test_llvm_opt"
)
SET(TARGET_DIR "./"
)
SET(LLVM_LIBS LLVMAArch64AsmParser.lib LLVMAMDGPUAsmParser.lib LLVMARMAsmParser.lib LLVMAVRAsmParser.lib LLVMBPFAsmParser.lib LLVMHexagonAsmParser.lib LLVMLanaiAsmParser.lib LLVMMipsAsmParser.lib LLVMMSP430AsmParser.lib LLVMPowerPCAsmParser.lib LLVMRISCVAsmParser.lib LLVMSparcAsmParser.lib LLVMSystemZAsmParser.lib LLVMWebAssemblyAsmParser.lib LLVMX86AsmParser.lib LLVMAArch64CodeGen.lib LLVMAMDGPUCodeGen.lib LLVMARMCodeGen.lib LLVMAVRCodeGen.lib LLVMBPFCodeGen.lib LLVMHexagonCodeGen.lib LLVMLanaiCodeGen.lib LLVMMipsCodeGen.lib LLVMMSP430CodeGen.lib LLVMNVPTXCodeGen.lib LLVMPowerPCCodeGen.lib LLVMRISCVCodeGen.lib LLVMSparcCodeGen.lib LLVMSystemZCodeGen.lib LLVMWebAssemblyCodeGen.lib LLVMX86CodeGen.lib LLVMXCoreCodeGen.lib LLVMAArch64Desc.lib LLVMAMDGPUDesc.lib LLVMARMDesc.lib LLVMAVRDesc.lib LLVMBPFDesc.lib LLVMHexagonDesc.lib LLVMLanaiDesc.lib LLVMMipsDesc.lib LLVMMSP430Desc.lib LLVMNVPTXDesc.lib LLVMPowerPCDesc.lib LLVMRISCVDesc.lib LLVMSparcDesc.lib LLVMSystemZDesc.lib LLVMWebAssemblyDesc.lib LLVMX86Desc.lib LLVMXCoreDesc.lib LLVMAArch64Info.lib LLVMAMDGPUInfo.lib LLVMARMInfo.lib LLVMAVRInfo.lib LLVMBPFInfo.lib LLVMHexagonInfo.lib LLVMLanaiInfo.lib LLVMMipsInfo.lib LLVMMSP430Info.lib LLVMNVPTXInfo.lib LLVMPowerPCInfo.lib LLVMRISCVInfo.lib LLVMSparcInfo.lib LLVMSystemZInfo.lib LLVMWebAssemblyInfo.lib LLVMX86Info.lib LLVMXCoreInfo.lib LLVMAggressiveInstCombine.lib LLVMAnalysis.lib LLVMBitWriter.lib LLVMCodeGen.lib LLVMCore.lib LLVMCoroutines.lib LLVMipo.lib LLVMIRReader.lib LLVMInstCombine.lib LLVMInstrumentation.lib LLVMMC.lib LLVMObjCARCOpts.lib LLVMRemarks.lib LLVMScalarOpts.lib LLVMSupport.lib LLVMTarget.lib LLVMTransformUtils.lib LLVMVectorize.lib LLVMPasses.lib LLVMAArch64Utils.lib LLVMAMDGPUUtils.lib LLVMMIRParser.lib LLVMARMUtils.lib LLVMHexagonAsmParser.lib LLVMHexagonDesc.lib LLVMHexagonInfo.lib LLVMLanaiAsmParser.lib LLVMLanaiDesc.lib LLVMLanaiInfo.lib LLVMRISCVUtils.lib LLVMMCDisassembler.lib LLVMCFGuard.lib LLVMGlobalISel.lib LLVMX86Utils.lib LLVMAsmPrinter.lib LLVMDebugInfoDWARF.lib LLVMSelectionDAG.lib LLVMCodeGen.lib LLVMCoroutines.lib LLVMipo.lib LLVMBitWriter.lib LLVMIRReader.lib LLVMAsmParser.lib LLVMFrontendOpenMP.lib LLVMLinker.lib LLVMInstrumentation.lib LLVMScalarOpts.lib LLVMAggressiveInstCombine.lib LLVMInstCombine.lib LLVMTarget.lib LLVMVectorize.lib LLVMTransformUtils.lib LLVMAnalysis.lib LLVMProfileData.lib LLVMObject.lib LLVMMCParser.lib LLVMMC.lib LLVMDebugInfoCodeView.lib LLVMDebugInfoMSF.lib LLVMBitReader.lib LLVMTextAPI.lib LLVMCore.lib LLVMRemarks.lib LLVMBitstreamReader.lib LLVMBinaryFormat.lib LLVMSupport.lib psapi.lib shell32.lib ole32.lib uuid.lib advapi32.lib delayimp.lib LLVMDemangle.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib)
SET(CMAKE_CXX_FLAGS "/std:c++14 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS /DWIN32 /D_WINDOWS /Zc:inline /Zc:strictStrings /Oi /Zc:rvalueCast /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd4324 -w14062 -we4238 /Gw /MD /O2 /Ob2 /DNDEBUG /EHs-c- /GR-"
)
include_directories(${
LLVM_CLANG_DIR}/
include)
LINK_DIRECTORIES(${
LLVM_CLANG_DIR}/
lib)
FILE(GLOB_RECURSE SOURCE_FILES "*.cpp"
)
set(SOURCE_FILES ${
SOURCE_FILES}
windows_version_resource.rc)
ADD_EXECUTABLE (${
TARGET_NAME}
${
SOURCE_FILES}
)
TARGET_LINK_LIBRARIES(${
TARGET_NAME}
${
LLVM_LIBS}
)
INSTALL(TARGETS ${
TARGET_NAME}
RUNTIME DESTINATION ${
TARGET_DIR}
LIBRARY DESTINATION ${
TARGET_DIR}
)
De nouveau, le projet test compile juste bien, mais, cette fois, en exécutant la commande test_llvm_opt.exe -
O3 -
debugify-
each -
verify-
each bcsection.ll -
o result.bc, on obtient le même résultat que celui produit par l’outil opt officiel de LLVM : yyeeeeepppeeee ! Victoire ! ????
VI. Mettre à jour la configuration de construction de nvLLVM▲
À partir de là, la voie a commencé à se déblayer d’elle-même : mettre à jour les fichiers de construction CMake a corrigé le plantage silencieux dans mon projet test_llvm_opt ; naturellement, la prochaine étape logique a été d’appliquer les mêmes mises à jour au projet nvLLVM et son fichier principal. À partir de là, la voie a commencé à se déblayer d’elle-même : mettre à jour les fichiers de construction CMake a corrigé le plantage silencieux dans mon projet test_llvm_opt ; naturellement, la prochaine étape logique a été d’appliquer les mêmes mises à jour au projet nvLLVM et son fichier principal CMakeLists.txt a donc été modifié ainsi :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
SET(TARGET_DIR "./"
)
include_directories(${
LLVM_CLANG_DIR}/
include)
LINK_DIRECTORIES(${
LLVM_CLANG_DIR}/
lib)
INCLUDE_DIRECTORIES(../
nvCore/
include)
SET(CMAKE_CXX_FLAGS "/std:c++14 -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS /DWIN32 /D_WINDOWS /Zc:inline /Zc:strictStrings /Oi /Zc:rvalueCast /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd4324 -w14062 -we4238 /Gw /MD /O2 /Ob2 /DNDEBUG /EHs-c- /GR-"
)
ADD_DEFINITIONS(-
D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-
DNOMINMAX)
# Note: used llvm-config.exe --libs to retrieve the list of libraries below:
# LLVM version 11.0.0git
SET(LLVM_LIBS LLVMXRay LLVMWindowsManifest LLVMTableGen LLVMSymbolize LLVMDebugInfoPDB LLVMOrcJIT LLVMOrcError LLVMJITLink LLVMObjectYAML LLVMMCA LLVMLTO LLVMPasses LLVMCoroutines LLVMObjCARCOpts LLVMLineEditor LLVMLibDriver LLVMInterpreter LLVMFuzzMutate LLVMMCJIT LLVMExecutionEngine LLVMRuntimeDyld LLVMDWARFLinker LLVMDlltoolDriver LLVMOption LLVMDebugInfoGSYM LLVMCoverage LLVMXCoreDisassembler LLVMXCoreCodeGen LLVMXCoreDesc LLVMXCoreInfo LLVMX86Disassembler LLVMX86AsmParser LLVMX86CodeGen LLVMX86Desc LLVMX86Utils LLVMX86Info LLVMWebAssemblyDisassembler LLVMWebAssemblyCodeGen LLVMWebAssemblyDesc LLVMWebAssemblyAsmParser LLVMWebAssemblyInfo LLVMSystemZDisassembler LLVMSystemZCodeGen LLVMSystemZAsmParser LLVMSystemZDesc LLVMSystemZInfo LLVMSparcDisassembler LLVMSparcCodeGen LLVMSparcAsmParser LLVMSparcDesc LLVMSparcInfo LLVMRISCVDisassembler LLVMRISCVCodeGen LLVMRISCVAsmParser LLVMRISCVDesc LLVMRISCVUtils LLVMRISCVInfo LLVMPowerPCDisassembler LLVMPowerPCCodeGen LLVMPowerPCAsmParser LLVMPowerPCDesc LLVMPowerPCInfo LLVMNVPTXCodeGen LLVMNVPTXDesc LLVMNVPTXInfo LLVMMSP430Disassembler LLVMMSP430CodeGen LLVMMSP430AsmParser LLVMMSP430Desc LLVMMSP430Info LLVMMipsDisassembler LLVMMipsCodeGen LLVMMipsAsmParser LLVMMipsDesc LLVMMipsInfo LLVMLanaiDisassembler LLVMLanaiCodeGen LLVMLanaiAsmParser LLVMLanaiDesc LLVMLanaiInfo LLVMHexagonDisassembler LLVMHexagonCodeGen LLVMHexagonAsmParser LLVMHexagonDesc LLVMHexagonInfo LLVMBPFDisassembler LLVMBPFCodeGen LLVMBPFAsmParser LLVMBPFDesc LLVMBPFInfo LLVMAVRDisassembler LLVMAVRCodeGen LLVMAVRAsmParser LLVMAVRDesc LLVMAVRInfo LLVMARMDisassembler LLVMARMCodeGen LLVMARMAsmParser LLVMARMDesc LLVMARMUtils LLVMARMInfo LLVMAMDGPUDisassembler LLVMAMDGPUCodeGen LLVMMIRParser LLVMipo LLVMInstrumentation LLVMVectorize LLVMLinker LLVMIRReader LLVMAsmParser LLVMFrontendOpenMP LLVMAMDGPUAsmParser LLVMAMDGPUDesc LLVMAMDGPUUtils LLVMAMDGPUInfo LLVMAArch64Disassembler LLVMMCDisassembler LLVMAArch64CodeGen LLVMCFGuard LLVMGlobalISel LLVMSelectionDAG LLVMAsmPrinter LLVMDebugInfoDWARF LLVMCodeGen LLVMTarget LLVMScalarOpts LLVMInstCombine LLVMAggressiveInstCombine LLVMTransformUtils LLVMBitWriter LLVMAnalysis LLVMProfileData LLVMObject LLVMTextAPI LLVMBitReader LLVMCore LLVMRemarks LLVMBitstreamReader LLVMAArch64AsmParser LLVMMCParser LLVMAArch64Desc LLVMMC LLVMDebugInfoCodeView LLVMDebugInfoMSF LLVMBinaryFormat LLVMAArch64Utils LLVMAArch64Info LLVMSupport LLVMDemangle)
SET(FLAVOR_LIBS psapi.lib shell32.lib ole32.lib uuid.lib advapi32.lib delayimp.lib LLVMDemangle.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib)
SET(CLANG_LIBS clangAST clangBasic clangLex clangCodeGen clangFrontend clangEdit
clangSerialization clangSema clangDriver clangParse clangAnalysis)
INCLUDE_DIRECTORIES (include)
FILE(GLOB_RECURSE PUBLIC_HEADERS "include/*.h"
)
FILE(GLOB_RECURSE SOURCE_FILES "src/*.cpp"
)
ADD_SUBDIRECTORY(src)
Notez que, dans le code ci-dessus, je n’ai même plus besoin que CMake appelle findPackage
(
) pour importer les macros utilitaires…
Une fois de plus, tout s’est très bien passé : j’ai juste dû faire quelques changements mineurs dans le code, et ensuite, l’appel à la fonction optimizeModule
(
) s’est exécuté juste parfaitement !
Et, cerise sur le gâteau, j’ai pu maintenant aussi supprimer le lljit.release
(
) dans le destructeur de NervJITImpl !
- Comme résultat, il semble que mon module nvLLVM et la nouvelle classe NervJIT que j’ai construits ici ne plantent plus silencieusement et n’ont plus de fuite de mémoire ! Liiiiibre… Ça m’a donné du mal : j’ai eu une dure journée, mais ça en valait la peine !
C’est tout pour aujourd’hui, les gars ! À nouveau, si quelqu’un veut voir le code plus en détail, voici un package ZIP mis à jour contenant la version courante du module nvLLVM ainsi que les projets test_nvLLVM et test_llvm_opt : nv_llvm_20200416.zip.
Je ne les ai pas mentionnées ci-dessus, mais le code fourni dans le package ZIP contient aussi certaines petites mises à jour additionnelles, telles qu’un mécanisme approprié pour spécifier le chemin de recherche des fichiers d’en-tête, la suppression de la dépendance au module nvCore (ainsi il devrait être beaucoup plus facile pour quiconque de reconstruire quelque chose d’après ce code) et d’autres nettoyages mineurs.
VII. Remerciements Developpez.com▲
Ce tutoriel est la traduction de JIT Compiler with LLVM - Part 3 - Fixing the ModulePassManager crash. Nous tenons à remercier Thierry Jeanneret pour la traduction, Thibaut Cuvelier pour la relecture technique, Malick pour la mise au gabarit et Claude Leloup pour la relecture orthographique.