1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
21
22 #ifdef WIN32
23 #pragma warning(disable : 4146 4244 4275)
24 #endif
25
26 #include "llvm_code_container.hh"
27 #include "compatibility.hh"
28 #include "exception.hh"
29 #include "fir_to_fir.hh"
30 #include "global.hh"
31 #include "llvm_dynamic_dsp_aux.hh"
32 #include "llvm_instructions.hh"
33
34 /*
35 LLVM module description:
36
37 - 'clone' method is implemented in the 'llvm_dsp' wrapping code
38
39 TODO: in -mem mode, classInit and classDestroy will have to be called once at factory init and destroy time
40 */
41
42 // Helper functions
43 bool linkModules(Module* dst, ModulePTR src, string& error);
44 ModulePTR loadModule(const string& module_name, LLVMContext* context);
45 Module* linkAllModules(LLVMContext* context, Module* dst, string& error);
46
createScalarContainer(const string & name,int sub_container_type)47 CodeContainer* LLVMCodeContainer::createScalarContainer(const string& name, int sub_container_type)
48 {
49 return new LLVMScalarCodeContainer(name, 0, 1, fModule, fContext, sub_container_type);
50 }
51
LLVMCodeContainer(const string & name,int numInputs,int numOutputs)52 LLVMCodeContainer::LLVMCodeContainer(const string& name, int numInputs, int numOutputs)
53 {
54 LLVMContext* context = new LLVMContext();
55 stringstream compile_options;
56 gGlobal->printCompilationOptions(compile_options);
57 Module* module = new Module(compile_options.str() + ", v" + string(FAUSTVERSION), *context);
58
59 init(name, numInputs, numOutputs, module, context);
60 }
61
LLVMCodeContainer(const string & name,int numInputs,int numOutputs,Module * module,LLVMContext * context)62 LLVMCodeContainer::LLVMCodeContainer(const string& name, int numInputs, int numOutputs, Module* module,
63 LLVMContext* context)
64 {
65 init(name, numInputs, numOutputs, module, context);
66 }
67
init(const string & name,int numInputs,int numOutputs,Module * module,LLVMContext * context)68 void LLVMCodeContainer::init(const string& name, int numInputs, int numOutputs, Module* module,
69 LLVMContext* context)
70 {
71 initialize(numInputs, numOutputs);
72
73 fKlassName = name;
74 fModule = module;
75 fContext = context;
76 fBuilder = new IRBuilder<>(*fContext);
77
78 // Set "-fast-math"
79 FastMathFlags FMF;
80 #if defined(LLVM_80) || defined(LLVM_90) || defined(LLVM_100) || defined(LLVM_110) || defined(LLVM_120) || \
81 defined(LLVM_130) || defined(LLVM_140)
82 FMF.setFast(); // has replaced the following function
83 #else
84 FMF.setUnsafeAlgebra();
85 #endif
86 fBuilder->setFastMathFlags(FMF);
87 fModule->setTargetTriple(sys::getDefaultTargetTriple());
88 }
89
~LLVMCodeContainer()90 LLVMCodeContainer::~LLVMCodeContainer()
91 {
92 delete fBuilder;
93 }
94
createContainer(const string & name,int numInputs,int numOutputs)95 CodeContainer* LLVMCodeContainer::createContainer(const string& name, int numInputs, int numOutputs)
96 {
97 gGlobal->gDSPStruct = true;
98 CodeContainer* container;
99
100 if (gGlobal->gFloatSize == 3) {
101 throw faustexception("ERROR : quad format not supported for LLVM\n");
102 }
103 if (gGlobal->gOpenCLSwitch) {
104 throw faustexception("ERROR : OpenCL not supported for LLVM\n");
105 }
106 if (gGlobal->gCUDASwitch) {
107 throw faustexception("ERROR : CUDA not supported for LLVM\n");
108 }
109
110 if (gGlobal->gOpenMPSwitch) {
111 throw faustexception("ERROR : OpenMP not supported for LLVM\n");
112 } else if (gGlobal->gSchedulerSwitch) {
113 container = new LLVMWorkStealingCodeContainer(name, numInputs, numOutputs);
114 } else if (gGlobal->gVectorSwitch) {
115 container = new LLVMVectorCodeContainer(name, numInputs, numOutputs);
116 } else {
117 container = new LLVMScalarCodeContainer(name, numInputs, numOutputs);
118 }
119
120 return container;
121 }
122
generateDspStruct()123 PointerType* LLVMCodeContainer::generateDspStruct()
124 {
125 // Generate DSP structure
126 LLVMTypeHelper type_helper(fModule);
127 generateDeclarations(&fStructVisitor);
128
129 DeclareStructTypeInst* dec_type = fStructVisitor.getStructType(fKlassName);
130
131 LLVMType dsp_type = type_helper.convertFIRType(dec_type->fType);
132 return PointerType::get(dsp_type, 0);
133 }
134
generateFunMaps()135 void LLVMCodeContainer::generateFunMaps()
136 {
137 if (gGlobal->gFastMath) {
138 generateFunMap("fabs", "fast_fabs", 1);
139 generateFunMap("acos", "fast_acos", 1);
140 generateFunMap("asin", "fast_asin", 1);
141 generateFunMap("atan", "fast_atan", 1);
142 generateFunMap("atan2", "fast_atan2", 2);
143 generateFunMap("ceil", "fast_ceil", 1);
144 generateFunMap("cos", "fast_cos", 1);
145 generateFunMap("exp", "fast_exp", 1);
146 generateFunMap("exp2", "fast_exp2", 1);
147 generateFunMap("exp10", "fast_exp10", 1);
148 generateFunMap("floor", "fast_floor", 1);
149 generateFunMap("fmod", "fast_fmod", 2);
150 generateFunMap("log", "fast_log", 1);
151 generateFunMap("log2", "fast_log2", 1);
152 generateFunMap("log10", "fast_log10", 1);
153 generateFunMap("pow", "fast_pow", 2);
154 generateFunMap("remainder", "fast_remainder", 2);
155 generateFunMap("rint", "fast_rint", 1);
156 generateFunMap("round", "fast_round", 1);
157 generateFunMap("sin", "fast_sin", 1);
158 generateFunMap("sqrt", "fast_sqrt", 1);
159 generateFunMap("tan", "fast_tan", 1);
160 } else {
161 #ifdef __APPLE__
162 generateFunMap("exp10", "__exp10", 1, true);
163 #endif
164 }
165 }
166
generateFunMap(const string & fun1_aux,const string & fun2_aux,int num_args,bool body)167 void LLVMCodeContainer::generateFunMap(const string& fun1_aux, const string& fun2_aux, int num_args, bool body)
168 {
169 Typed::VarType type = itfloat();
170 string fun1 = fun1_aux + isuffix();
171 string fun2 = fun2_aux + isuffix();
172
173 list<NamedTyped*> args1;
174 list<ValueInst*> args2;
175 for (int i = 0; i < num_args; i++) {
176 string var = gGlobal->getFreshID("val");
177 args1.push_back(InstBuilder::genNamedTyped(var, type));
178 args2.push_back(InstBuilder::genLoadFunArgsVar(var));
179 }
180
181 // Creates function
182 FunTyped* fun_type1 = InstBuilder::genFunTyped(args1, InstBuilder::genBasicTyped(type), FunTyped::kLocal);
183 FunTyped* fun_type2 = InstBuilder::genFunTyped(args1, InstBuilder::genBasicTyped(type), FunTyped::kDefault);
184
185 InstBuilder::genDeclareFunInst(fun2, fun_type2)->accept(fCodeProducer);
186 if (body) {
187 BlockInst* block = InstBuilder::genBlockInst();
188 block->pushBackInst(InstBuilder::genRetInst(InstBuilder::genFunCallInst(fun2, args2)));
189 InstBuilder::genDeclareFunInst(fun1, fun_type1, block)->accept(fCodeProducer);
190 }
191 }
192
produceInternal()193 void LLVMCodeContainer::produceInternal()
194 {
195 // Generate DSP structure
196 fCodeProducer = new LLVMInstVisitor(fModule, fBuilder, &fStructVisitor, generateDspStruct());
197
198 /// Memory methods
199 generateCalloc()->accept(fCodeProducer);
200 generateFree()->accept(fCodeProducer);
201
202 generateNewDsp("new" + fKlassName, fStructVisitor.getStructSize())->accept(fCodeProducer);
203 generateDeleteDsp("delete" + fKlassName, "dsp")->accept(fCodeProducer);
204
205 generateFunMaps();
206
207 // Global declarations
208 generateExtGlobalDeclarations(fCodeProducer);
209 generateGlobalDeclarations(fCodeProducer);
210
211 generateInstanceInitFun("instanceInit" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
212 generateFillFun("fill" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
213 }
214
produceFactory()215 dsp_factory_base* LLVMCodeContainer::produceFactory()
216 {
217 // Generate gub containers
218 generateSubContainers();
219
220 // Generate DSP structure
221 fCodeProducer = new LLVMInstVisitor(fModule, fBuilder, &fStructVisitor, generateDspStruct());
222
223 generateFunMaps();
224
225 // Global declarations
226 generateExtGlobalDeclarations(fCodeProducer);
227 generateGlobalDeclarations(fCodeProducer);
228
229 generateStaticInitFun("classInit" + fKlassName, false)->accept(fCodeProducer);
230 generateInstanceClear("instanceClear" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
231 generateInstanceConstants("instanceConstants" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
232 generateAllocate("allocate" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
233 generateDestroy("destroy" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
234
235 // generateGetJSON generation
236 if (gGlobal->gFloatSize == 1) {
237 generateGetJSON<float>();
238 } else {
239 generateGetJSON<double>();
240 }
241
242 // Compute
243 generateCompute();
244
245 // Link LLVM modules defined in 'ffunction'
246 set<string> S;
247 collectLibrary(S);
248 string error;
249
250 if (S.size() > 0) {
251 for (const auto& f : S) {
252 string module_name = unquote(f);
253 if (endWith(module_name, ".bc") || endWith(module_name, ".ll")) {
254 ModulePTR module = loadModule(module_name, fContext);
255 if (module) {
256 bool res = linkModules(fModule, MovePTR(module), error);
257 if (!res) cerr << "WARNING : " << error << endl;
258 }
259 }
260 }
261 }
262
263 // Possibly link with additional LLVM modules
264 if (!linkAllModules(fContext, fModule, error)) {
265 throw faustexception("ERROR : " + error);
266 }
267
268 return new llvm_dynamic_dsp_factory_aux("", fModule, fContext, "", -1);
269 }
270
271 // Scalar
LLVMScalarCodeContainer(const string & name,int numInputs,int numOutputs)272 LLVMScalarCodeContainer::LLVMScalarCodeContainer(const string& name, int numInputs, int numOutputs)
273 : LLVMCodeContainer(name, numInputs, numOutputs)
274 {
275 }
276
LLVMScalarCodeContainer(const string & name,int numInputs,int numOutputs,Module * module,LLVMContext * context,int sub_container_type)277 LLVMScalarCodeContainer::LLVMScalarCodeContainer(const string& name, int numInputs, int numOutputs, Module* module,
278 LLVMContext* context, int sub_container_type)
279 : LLVMCodeContainer(name, numInputs, numOutputs, module, context)
280 {
281 fSubContainerType = sub_container_type;
282 }
283
~LLVMScalarCodeContainer()284 LLVMScalarCodeContainer::~LLVMScalarCodeContainer()
285 {
286 }
287
generateCompute()288 void LLVMScalarCodeContainer::generateCompute()
289 {
290 generateComputeFun("compute" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
291 }
292
generateComputeAux()293 BlockInst* LLVMScalarCodeContainer::generateComputeAux()
294 {
295 BlockInst* block = InstBuilder::genBlockInst();
296 // Control
297 block->pushBackInst(fComputeBlockInstructions);
298 // Generates the DSP loop
299 block->pushBackInst(fCurLoop->generateScalarLoop(fFullCount));
300 // Generates post DSP loop code
301 block->pushBackInst(fPostComputeBlockInstructions);
302 return block;
303 }
304
305 // Vector
LLVMVectorCodeContainer(const string & name,int numInputs,int numOutputs)306 LLVMVectorCodeContainer::LLVMVectorCodeContainer(const string& name, int numInputs, int numOutputs)
307 : VectorCodeContainer(numInputs, numOutputs), LLVMCodeContainer(name, numInputs, numOutputs)
308 {
309 }
310
~LLVMVectorCodeContainer()311 LLVMVectorCodeContainer::~LLVMVectorCodeContainer()
312 {
313 }
314
generateCompute()315 void LLVMVectorCodeContainer::generateCompute()
316 {
317 // Possibly generate separated functions
318 generateComputeFunctions(fCodeProducer);
319
320 generateComputeFun("compute" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
321 }
322
generateComputeAux()323 BlockInst* LLVMVectorCodeContainer::generateComputeAux()
324 {
325 BlockInst* block = InstBuilder::genBlockInst();
326 // Control
327 block->pushBackInst(fComputeBlockInstructions);
328 // Generates the DSP loop
329 block->pushBackInst(fDAGBlock);
330 return block;
331 }
332
333 // OpenMP
LLVMOpenMPCodeContainer(const string & name,int numInputs,int numOutputs)334 LLVMOpenMPCodeContainer::LLVMOpenMPCodeContainer(const string& name, int numInputs, int numOutputs)
335 : OpenMPCodeContainer(numInputs, numOutputs), LLVMCodeContainer(name, numInputs, numOutputs)
336 {
337 }
338
~LLVMOpenMPCodeContainer()339 LLVMOpenMPCodeContainer::~LLVMOpenMPCodeContainer()
340 {
341 }
342
generateCompute()343 void LLVMOpenMPCodeContainer::generateCompute()
344 {
345 generateOMPDeclarations();
346
347 // Generates OMP thread function
348 generateOMPCompute();
349
350 // Generates OMP data struct
351
352 // Generates OMP thread function call
353 generateGOMP_parallel_start(); // TODO : add parameters
354 generateDSPOMPCompute();
355 generateGOMP_parallel_end();
356 }
357
generateComputeAux()358 BlockInst* LLVMOpenMPCodeContainer::generateComputeAux()
359 {
360 // TODO
361 return nullptr;
362 }
363
generateOMPCompute()364 void LLVMOpenMPCodeContainer::generateOMPCompute()
365 {
366 // TODO
367 }
368
generateDSPOMPCompute()369 void LLVMOpenMPCodeContainer::generateDSPOMPCompute()
370 {
371 }
372
generateGOMP_parallel_start()373 void LLVMOpenMPCodeContainer::generateGOMP_parallel_start()
374 {
375 }
376
generateGOMP_parallel_end()377 void LLVMOpenMPCodeContainer::generateGOMP_parallel_end()
378 {
379 }
380
generateGOMP_single_start()381 LLVMValue LLVMOpenMPCodeContainer::generateGOMP_single_start()
382 {
383 return nullptr;
384 }
385
generateGOMP_barrier()386 void LLVMOpenMPCodeContainer::generateGOMP_barrier()
387 {
388 }
389
generateGOMP_sections_start(LLVMValue num)390 void LLVMOpenMPCodeContainer::generateGOMP_sections_start(LLVMValue num)
391 {
392 }
393
generateGOMP_sections_end()394 void LLVMOpenMPCodeContainer::generateGOMP_sections_end()
395 {
396 }
397
generateGOMP_sections_next()398 void LLVMOpenMPCodeContainer::generateGOMP_sections_next()
399 {
400 }
401
generateOMPDeclarations()402 void LLVMOpenMPCodeContainer::generateOMPDeclarations()
403 {
404 }
405
406 // Works stealing scheduler
LLVMWorkStealingCodeContainer(const string & name,int numInputs,int numOutputs)407 LLVMWorkStealingCodeContainer::LLVMWorkStealingCodeContainer(const string& name, int numInputs, int numOutputs)
408 : WSSCodeContainer(numInputs, numOutputs, "dsp"), LLVMCodeContainer(name, numInputs, numOutputs)
409 {
410 }
411
~LLVMWorkStealingCodeContainer()412 LLVMWorkStealingCodeContainer::~LLVMWorkStealingCodeContainer()
413 {
414 }
415
generateCompute()416 void LLVMWorkStealingCodeContainer::generateCompute()
417 {
418 // Possibly generate separated functions
419 generateComputeFunctions(fCodeProducer);
420
421 // Generates "computeThread" code
422 generateComputeThread("computeThread" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
423
424 // Generates prototype to be used by worker threads
425 generateComputeThreadExternal("computeThreadExternal", "dsp")->accept(fCodeProducer);
426
427 // Generates compute
428 generateComputeFun("compute" + fKlassName, "dsp", false, false)->accept(fCodeProducer);
429 }
430
generateComputeAux()431 BlockInst* LLVMWorkStealingCodeContainer::generateComputeAux()
432 {
433 BlockInst* block = InstBuilder::genBlockInst();
434 // Control
435 block->pushBackInst(fComputeBlockInstructions);
436 return block;
437 }
438