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 : 4141 4146 4244 4267 4275 4800)
24 //# define strdup _strdup
25 #endif
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <fstream>
30 #include <iostream>
31 #include <list>
32 #include <sstream>
33 
34 #include <llvm-c/Core.h>
35 #include <llvm/Bitcode/BitcodeReader.h>
36 #include <llvm/Bitcode/BitcodeWriter.h>
37 #include <llvm/ExecutionEngine/MCJIT.h>
38 #include <llvm/Support/FileSystem.h>
39 #include <llvm/Support/TargetSelect.h>
40 #include <llvm/Support/Host.h>
41 
42 #include "faust/gui/JSONUIDecoder.h"
43 #include "libfaust.h"
44 #include "llvm_dsp_aux.hh"
45 #include "rn_base64.h"
46 #include "lock_api.hh"
47 
48 using namespace llvm;
49 using namespace std;
50 
51 // Used by LLVM backend (for now)
52 Soundfile* dynamic_defaultsound = new Soundfile(64);
53 
54 #define LLVM_BACKEND_NAME "Faust LLVM backend"
55 
56 #ifdef LLVM_MACHINE
57 
faustassert(bool)58 void faustassert(bool)
59 {
60 }
getCLibFaustVersion()61 extern "C" EXPORT const char* getCLibFaustVersion()
62 {
63     return FAUSTVERSION;
64 }
65 
66 #endif
67 
68 // Debug tools
printInt32(int val)69 extern "C" EXPORT void printInt32(int val)
70 {
71     cout << "printInt32 : " << val << endl;
72 }
73 
printFloat(float val)74 extern "C" EXPORT void printFloat(float val)
75 {
76     cout << "printFloat : " << val << endl;
77 }
78 
printDouble(double val)79 extern "C" EXPORT void printDouble(double val)
80 {
81     cout << "printDouble : " << val << endl;
82 }
83 
printPtr(void * val)84 extern "C" EXPORT void printPtr(void* val)
85 {
86     cout << "printPtr : " << val << endl;
87 }
88 
89 // Factories instances management
90 int llvm_dsp_factory_aux::gInstance = 0;
91 
92 dsp_factory_table<SDsp_factory> llvm_dsp_factory_aux::gLLVMFactoryTable;
93 
loadOptimize(const string & function)94 uint64_t llvm_dsp_factory_aux::loadOptimize(const string& function)
95 {
96     uint64_t fun = fJIT->getFunctionAddress(function);
97     if (fun) {
98         return fun;
99     } else {
100         stringstream error;
101         error << "ERROR : loadOptimize failed for '" << function << "'\n";
102         throw faustexception(error.str());
103     }
104 }
105 
crossCompile(const string & target)106 bool llvm_dsp_factory_aux::crossCompile(const string& target)
107 {
108     delete fObjectCache;
109     fObjectCache = new FaustObjectCache();
110     setTarget(target);
111     string error;
112     return initJIT(error);
113 }
114 
startLLVMLibrary()115 void llvm_dsp_factory_aux::startLLVMLibrary()
116 {
117     if (llvm_dsp_factory_aux::gInstance++ == 0) {
118         LLVMInstallFatalErrorHandler(llvm_dsp_factory_aux::LLVMFatalErrorHandler);
119     }
120 }
121 
stopLLVMLibrary()122 void llvm_dsp_factory_aux::stopLLVMLibrary()
123 {
124     if (--llvm_dsp_factory_aux::gInstance == 0) {
125     // Remove the LLVM error handler
126     #if defined(__APPLE__) && (defined(LLVM_110) || defined(LLVM_120))
127         #warning Crash on OSX so deactivated in this case
128     #else
129         LLVMResetFatalErrorHandler();
130     #endif
131     }
132 }
133 
llvm_dsp_factory_aux(const string & sha_key,const string & machine_code,const string & target)134 llvm_dsp_factory_aux::llvm_dsp_factory_aux(const string& sha_key, const string& machine_code, const string& target)
135     : dsp_factory_imp("MachineDSP", sha_key, "")
136 {
137     startLLVMLibrary();
138 
139     init("MachineDSP", "");
140     fSHAKey = sha_key;
141     fTarget = (target == "") ? fTarget = (sys::getDefaultTargetTriple() + ":" + GET_CPU_NAME) : target;
142 
143     // Restoring the cache
144     fObjectCache = new FaustObjectCache(machine_code);
145 
146     // Creates module and context
147     fContext = new LLVMContext();
148     fModule  = new Module(string(LLVM_BACKEND_NAME) + ", v" + string(FAUSTVERSION), *fContext);
149     fDecoder = nullptr;
150 }
151 
llvm_dsp_factory_aux(const string & sha_key,Module * module,LLVMContext * context,const string & target,int opt_level)152 llvm_dsp_factory_aux::llvm_dsp_factory_aux(const string& sha_key, Module* module, LLVMContext* context,
153                                            const string& target, int opt_level)
154     : dsp_factory_imp("BitcodeDSP", sha_key, "")
155 {
156     startLLVMLibrary();
157 
158     init("BitcodeDSP", "");
159     fSHAKey = sha_key;
160     fTarget = (target == "") ? fTarget = (sys::getDefaultTargetTriple() + ":" + GET_CPU_NAME) : target;
161     setOptlevel(opt_level);
162 
163     fObjectCache = nullptr;
164     fContext = context;
165     fModule  = module;
166     fDecoder = nullptr;
167 }
168 
~llvm_dsp_factory_aux()169 llvm_dsp_factory_aux::~llvm_dsp_factory_aux()
170 {
171     delete fObjectCache;
172     if (fJIT) {
173         fJIT->runStaticConstructorsDestructors(true);
174         // fModule is kept and deleted by fJIT
175         delete fJIT;
176     }
177     delete fContext;
178     delete fDecoder;
179     stopLLVMLibrary();
180 }
181 
LLVMFatalErrorHandler(const char * reason)182 void llvm_dsp_factory_aux::LLVMFatalErrorHandler(const char* reason)
183 {
184     throw faustexception("ERROR : " + string(reason));
185 }
186 
init(const string & type_name,const string & dsp_name)187 void llvm_dsp_factory_aux::init(const string& type_name, const string& dsp_name)
188 {
189     fJIT               = nullptr;
190     fAllocate          = nullptr;
191     fDestroy           = nullptr;
192     fInstanceConstants = nullptr;
193     fInstanceClear     = nullptr;
194     fClassInit         = nullptr;
195     fCompute           = nullptr;
196     fClassName         = "mydsp";
197     fName              = dsp_name;
198     fTypeName          = type_name;
199     fExpandedDSP       = "";
200     fOptLevel          = 0;
201     fTarget            = "";
202 
203     // To keep Debug functions in generated code
204 #if 0
205     printInt32(1);
206     printFloat(0.5f);
207     printDouble(0.8);
208     printPtr(this);
209 #endif
210 }
211 
initJIT(string & error_msg)212 bool llvm_dsp_factory_aux::initJIT(string& error_msg)
213 {
214     startTiming("initJIT");
215 
216     // For host target support
217     InitializeNativeTarget();
218     InitializeNativeTargetAsmPrinter();
219     InitializeNativeTargetAsmParser();
220 
221     // For ObjectCache to work...
222     LLVMLinkInMCJIT();
223 
224     // Restoring from machine code
225     EngineBuilder builder((unique_ptr<Module>(fModule)));
226     string buider_error;
227     builder.setErrorStr(&buider_error);
228     TargetMachine* tm = builder.selectTarget();
229     fJIT              = builder.create(tm);
230     if (!fJIT) {
231         error_msg = "ERROR : " + buider_error;
232         return false;
233     }
234 
235     fJIT->setObjectCache(fObjectCache);
236     fJIT->finalizeObject();
237     return initJITAux();
238 }
239 
initJITAux()240 bool llvm_dsp_factory_aux::initJITAux()
241 {
242     // Run static constructors.
243     fJIT->runStaticConstructorsDestructors(false);
244     fJIT->DisableLazyCompilation(true);
245 
246     fAllocate          = (allocateDspFun)loadOptimize("allocate" + fClassName);
247     fDestroy           = (destroyDspFun)loadOptimize("destroy" + fClassName);
248     fInstanceConstants = (instanceConstantsFun)loadOptimize("instanceConstants" + fClassName);
249     fInstanceClear     = (instanceClearFun)loadOptimize("instanceClear" + fClassName);
250     fClassInit         = (classInitFun)loadOptimize("classInit" + fClassName);
251     fCompute           = (computeFun)loadOptimize("compute" + fClassName);
252     fGetJSON           = (getJSONFun)loadOptimize("getJSON" + fClassName);
253 
254     endTiming("initJIT");
255     return true;
256 }
257 
getOptlevel()258 int llvm_dsp_factory_aux::getOptlevel()
259 {
260     // TODO LLVM_36
261     /*
262     NamedMDNode* meta_data = fModule->getOrInsertNamedMetadata("OptLevel");
263     if (meta_data->getNumOperands() > 0) {
264         MDNode* node = meta_data->getOperand(0);
265         return (node) ? atoi(static_cast<MDString*>(node->getOperand(0))->getString().data()) : -1;
266     } else {
267         char opt_level[32];
268         sprintf(opt_level, "%d", fOptLevel);
269         Value* values[] = { MDString::get(fModule->getContext(), opt_level) };
270         meta_data->addOperand(MDNode::get(fModule->getContext(), values));
271         return -1;
272     }
273     */
274     return -1;
275 }
276 
metadata(Meta * m)277 void llvm_dsp_factory_aux::metadata(Meta* m)
278 {
279     checkDecoder();
280     fDecoder->metadata(m);
281 }
282 
metadata(MetaGlue * glue)283 void llvm_dsp_factory_aux::metadata(MetaGlue* glue)
284 {
285     checkDecoder();
286     fDecoder->metadata(glue);
287 }
288 
createDSPInstance(dsp_factory * factory_aux)289 llvm_dsp* llvm_dsp_factory_aux::createDSPInstance(dsp_factory* factory_aux)
290 {
291     llvm_dsp_factory* factory = static_cast<llvm_dsp_factory*>(factory_aux);
292     faustassert(factory);
293     checkDecoder();
294 
295     if (factory->getFactory()->getMemoryManager()) {
296         dsp_imp* dsp = static_cast<dsp_imp*>(factory->getFactory()->allocate(fDecoder->getDSPSize()));
297         return (dsp) ? new (factory->getFactory()->allocate(sizeof(llvm_dsp))) llvm_dsp(factory, dsp) : nullptr;
298     } else {
299         // LLVM module memory code
300         dsp_imp* dsp = static_cast<dsp_imp*>(calloc(1, fDecoder->getDSPSize()));
301         return (dsp) ? new llvm_dsp(factory, dsp) : nullptr;
302     }
303 }
304 
getCompileOptions()305 string llvm_dsp_factory_aux::getCompileOptions()
306 {
307     checkDecoder();
308     return fDecoder->getCompileOptions();
309 }
310 
getLibraryList()311 vector<string> llvm_dsp_factory_aux::getLibraryList()
312 {
313     checkDecoder();
314     return fDecoder->getLibraryList();
315 }
316 
getIncludePathnames()317 vector<string> llvm_dsp_factory_aux::getIncludePathnames()
318 {
319     checkDecoder();
320     return fDecoder->getIncludePathnames();
321 }
322 
323 // Instance
324 
llvm_dsp(llvm_dsp_factory * factory,dsp_imp * dsp)325 llvm_dsp::llvm_dsp(llvm_dsp_factory* factory, dsp_imp* dsp):fFactory(factory), fDSP(dsp)
326 {
327     // Used in -sch mode
328     fDecoder = createJSONUIDecoder(fFactory->getFactory()->fGetJSON());
329     fFactory->getFactory()->fAllocate(fDSP);
330 }
331 
~llvm_dsp()332 llvm_dsp::~llvm_dsp()
333 {
334     LOCK_API
335     llvm_dsp_factory_aux::gLLVMFactoryTable.removeDSP(fFactory, this);
336 
337     // Used in -sch mode
338     fFactory->getFactory()->fDestroy(fDSP);
339 
340     if (fFactory->getMemoryManager()) {
341         fFactory->getMemoryManager()->destroy(fDSP);
342     } else {
343         // LLVM module memory code
344         free(fDSP);
345     }
346     delete fDecoder;
347 }
348 
metadata(Meta * m)349 void llvm_dsp::metadata(Meta* m)
350 {
351     fFactory->getFactory()->fDecoder->metadata(m);
352 }
353 
metadata(MetaGlue * glue)354 void llvm_dsp::metadata(MetaGlue* glue)
355 {
356     fFactory->getFactory()->fDecoder->metadata(glue);
357 }
358 
getNumInputs()359 int llvm_dsp::getNumInputs()
360 {
361     return fFactory->getFactory()->fDecoder->getNumInputs();
362 }
363 
getNumOutputs()364 int llvm_dsp::getNumOutputs()
365 {
366     return fFactory->getFactory()->fDecoder->getNumOutputs();
367 }
368 
init(int sample_rate)369 void llvm_dsp::init(int sample_rate)
370 {
371     classInit(sample_rate);
372     instanceInit(sample_rate);
373 }
374 
classInit(int sample_rate)375 void llvm_dsp::classInit(int sample_rate)
376 {
377     fFactory->getFactory()->fClassInit(sample_rate);
378 }
379 
instanceInit(int sample_rate)380 void llvm_dsp::instanceInit(int sample_rate)
381 {
382     instanceConstants(sample_rate);
383     instanceResetUserInterface();
384     instanceClear();
385 }
386 
instanceConstants(int sample_rate)387 void llvm_dsp::instanceConstants(int sample_rate)
388 {
389     fFactory->getFactory()->fInstanceConstants(fDSP, sample_rate);
390 }
391 
instanceResetUserInterface()392 void llvm_dsp::instanceResetUserInterface()
393 {
394     // Reset the DSP proxy
395     fDecoder->resetUserInterface();
396     // Reset the real DSP
397     fDecoder->resetUserInterface(fDSP, dynamic_defaultsound);
398 }
399 
instanceClear()400 void llvm_dsp::instanceClear()
401 {
402     fFactory->getFactory()->fInstanceClear(fDSP);
403 }
404 
clone()405 llvm_dsp* llvm_dsp::clone()
406 {
407     return fFactory->createDSPInstance();
408 }
409 
getSampleRate()410 int llvm_dsp::getSampleRate()
411 {
412     return fDecoder->getSampleRate(fDSP);
413 }
414 
buildUserInterface(UI * ui_interface)415 void llvm_dsp::buildUserInterface(UI* ui_interface)
416 {
417     if (fDecoder->hasCompileOption("-double") && ui_interface->sizeOfFAUSTFLOAT() == 4) {
418         // Setup a DSP proxy
419         fDecoder->setupDSPProxy(ui_interface, fDSP);
420         fDecoder->buildUserInterface(ui_interface);
421     } else {
422         fDecoder->buildUserInterface(ui_interface, fDSP);
423     }
424 }
425 
buildUserInterface(UIGlue * glue)426 void llvm_dsp::buildUserInterface(UIGlue* glue)
427 {
428     fDecoder->buildUserInterface(glue, fDSP);
429 }
430 
compute(int count,FAUSTFLOAT ** input,FAUSTFLOAT ** output)431 void llvm_dsp::compute(int count, FAUSTFLOAT** input, FAUSTFLOAT** output)
432 {
433     if (fDecoder->hasDSPProxy()) {
434         // Update inputs control
435         for (const auto& i : fDecoder->getInputControls()) {
436             i->reflectZone();
437         }
438         fFactory->getFactory()->fCompute(fDSP, count, input, output);
439         // Update outputs control
440         for (const auto& i : fDecoder->getOutputControls()) {
441             i->modifyZone();
442         }
443     } else {
444         fFactory->getFactory()->fCompute(fDSP, count, input, output);
445     }
446 }
447 
writeDSPFactoryToMachineAux(const string & target)448 string llvm_dsp_factory_aux::writeDSPFactoryToMachineAux(const string& target)
449 {
450     if (target == "" || target == getTarget()) {
451         return fObjectCache->getMachineCode();
452     } else {
453         string old_target = getTarget();
454         if (crossCompile(target)) {     // Recompilation is required
455             string machine_code = fObjectCache->getMachineCode();
456             crossCompile(old_target);   // Restore old target
457             return machine_code;
458         } else {
459             return "";
460         }
461     }
462 }
463 
writeDSPFactoryToMachine(const string & target)464 string llvm_dsp_factory_aux::writeDSPFactoryToMachine(const string& target)
465 {
466     return base64_encode(writeDSPFactoryToMachineAux(target));
467 }
468 
writeDSPFactoryToMachineFile(const string & machine_code_path,const string & target)469 bool llvm_dsp_factory_aux::writeDSPFactoryToMachineFile(const string& machine_code_path, const string& target)
470 {
471     STREAM_ERROR   err;
472     raw_fd_ostream out(machine_code_path.c_str(), err, sysfs_binary_flag);
473     if (err) {
474         cerr << "ERROR : writeDSPFactoryToMachineFile could not open file : " << err.message();
475         return false;
476     }
477     out << writeDSPFactoryToMachineAux(target);
478     out.flush();
479     return true;
480 }
481 
readDSPFactoryFromMachineAux(MEMORY_BUFFER buffer,const string & target,string & error_msg)482 llvm_dsp_factory* llvm_dsp_factory_aux::readDSPFactoryFromMachineAux(MEMORY_BUFFER buffer, const string& target,
483                                                                      string& error_msg)
484 {
485     string sha_key = generateSHA1(MEMORY_BUFFER_GET(buffer).str());
486     dsp_factory_table<SDsp_factory>::factory_iterator it;
487 
488     if (llvm_dsp_factory_aux::gLLVMFactoryTable.getFactory(sha_key, it)) {
489         SDsp_factory sfactory = (*it).first;
490         sfactory->addReference();
491         return sfactory;
492     } else {
493         try {
494             llvm_dsp_factory_aux* factory_aux = new llvm_dsp_factory_aux(sha_key, MEMORY_BUFFER_GET(buffer).str(), target);
495             if (factory_aux->initJIT(error_msg)) {
496                 llvm_dsp_factory* factory = new llvm_dsp_factory(factory_aux);
497                 llvm_dsp_factory_aux::gLLVMFactoryTable.setFactory(factory);
498                 factory->setSHAKey(sha_key);
499                 return factory;
500             } else {
501                 delete factory_aux;
502                 return nullptr;
503             }
504         } catch (faustexception& e) {
505             error_msg = e.what();
506             return nullptr;
507         }
508     }
509 }
510 
getTarget()511 string llvm_dsp_factory_aux::getTarget()
512 {
513     return fTarget;
514 }
515 
516 // Public C++ API
517 
getDSPFactoryFromSHAKey(const string & sha_key)518 EXPORT llvm_dsp_factory* getDSPFactoryFromSHAKey(const string& sha_key)
519 {
520     LOCK_API
521     return static_cast<llvm_dsp_factory*>(llvm_dsp_factory_aux::gLLVMFactoryTable.getDSPFactoryFromSHAKey(sha_key));
522 }
523 
getAllDSPFactories()524 EXPORT vector<string> getAllDSPFactories()
525 {
526     LOCK_API
527     return llvm_dsp_factory_aux::gLLVMFactoryTable.getAllDSPFactories();
528 }
529 
deleteDSPFactory(llvm_dsp_factory * factory)530 EXPORT bool deleteDSPFactory(llvm_dsp_factory* factory)
531 {
532     LOCK_API
533     return (factory) ? llvm_dsp_factory_aux::gLLVMFactoryTable.deleteDSPFactory(factory) : false;
534 }
535 
getDSPMachineTarget()536 EXPORT string getDSPMachineTarget()
537 {
538     return (sys::getDefaultTargetTriple() + ":" + GET_CPU_NAME);
539 }
540 
getLibraryList(llvm_dsp_factory * factory)541 EXPORT vector<string> getLibraryList(llvm_dsp_factory* factory)
542 {
543     LOCK_API
544     return factory->getLibraryList();
545 }
546 
deleteAllDSPFactories()547 EXPORT void deleteAllDSPFactories()
548 {
549     LOCK_API
550     llvm_dsp_factory_aux::gLLVMFactoryTable.deleteAllDSPFactories();
551 }
552 
553 // machine <==> string
readDSPFactoryFromMachine(const string & machine_code,const string & target,string & error_msg)554 EXPORT llvm_dsp_factory* readDSPFactoryFromMachine(const string& machine_code, const string& target, string& error_msg)
555 {
556     LOCK_API
557     return llvm_dsp_factory_aux::readDSPFactoryFromMachineAux(
558         MEMORY_BUFFER_CREATE(StringRef(base64_decode(machine_code))), target, error_msg);
559 }
560 
561 // machine <==> file
readDSPFactoryFromMachineFile(const string & machine_code_path,const string & target,string & error_msg)562 EXPORT llvm_dsp_factory* readDSPFactoryFromMachineFile(const string& machine_code_path, const string& target,
563                                                        string& error_msg)
564 {
565     LOCK_API
566     ErrorOr<OwningPtr<MemoryBuffer>> buffer = MemoryBuffer::getFileOrSTDIN(machine_code_path);
567     if (error_code ec = buffer.getError()) {
568         error_msg = "ERROR : " + ec.message() + "\n";
569         return nullptr;
570     } else {
571         return llvm_dsp_factory_aux::readDSPFactoryFromMachineAux(MEMORY_BUFFER_GET_REF(buffer), target, error_msg);
572     }
573 }
574 
writeDSPFactoryToMachine(llvm_dsp_factory * factory,const string & target)575 EXPORT string writeDSPFactoryToMachine(llvm_dsp_factory* factory, const string& target)
576 {
577     LOCK_API
578     return factory->writeDSPFactoryToMachine(target);
579 }
580 
writeDSPFactoryToMachineFile(llvm_dsp_factory * factory,const string & machine_code_path,const string & target)581 EXPORT bool writeDSPFactoryToMachineFile(llvm_dsp_factory* factory, const string& machine_code_path,
582                                          const string& target)
583 {
584     LOCK_API
585     return (factory) ? factory->writeDSPFactoryToMachineFile(machine_code_path, target) : false;
586 }
587 
writeDSPFactoryToObjectcodeFile(llvm_dsp_factory * factory,const string & object_code_path,const string & target)588 EXPORT bool writeDSPFactoryToObjectcodeFile(llvm_dsp_factory* factory, const string& object_code_path,
589                                             const string& target)
590 {
591     LOCK_API
592     return (factory) ? factory->writeDSPFactoryToObjectcodeFile(object_code_path, target) : false;
593 }
594 
595 // Instance
createDSPInstance()596 EXPORT llvm_dsp* llvm_dsp_factory::createDSPInstance()
597 {
598     LOCK_API
599     dsp* dsp = fFactory->createDSPInstance(this);
600     llvm_dsp_factory_aux::gLLVMFactoryTable.addDSP(this, dsp);
601     return static_cast<llvm_dsp*>(dsp);
602 }
603 
604 // Use the memory manager if needed
operator delete(void * ptr)605 EXPORT void llvm_dsp::operator delete(void* ptr)
606 {
607     dsp_memory_manager* manager = static_cast<llvm_dsp*>(ptr)->fFactory->getMemoryManager();
608     if (manager) {
609         manager->destroy(ptr);
610     } else {
611         ::operator delete(ptr);
612     }
613 }
614 
615 // Public C interface : lock management is done by called C++ API
616 
617 #ifdef __cplusplus
618 extern "C" {
619 #endif
620 
getCDSPFactoryFromSHAKey(const char * sha_key)621 EXPORT llvm_dsp_factory* getCDSPFactoryFromSHAKey(const char* sha_key)
622 {
623     return getDSPFactoryFromSHAKey(sha_key);
624 }
625 
getAllCDSPFactories()626 EXPORT const char** getAllCDSPFactories()
627 {
628     vector<string> sha_key_list1 = getAllDSPFactories();
629     const char**   sha_key_list2 = (const char**)malloc(sizeof(char*) * (sha_key_list1.size() + 1));
630 
631     size_t i;
632     for (i = 0; i < sha_key_list1.size(); i++) {
633         sha_key_list2[i] = strdup(sha_key_list1[i].c_str());
634     }
635 
636     // Last element is NULL
637     sha_key_list2[i] = nullptr;
638     return sha_key_list2;
639 }
640 
deleteCDSPFactory(llvm_dsp_factory * factory)641 EXPORT bool deleteCDSPFactory(llvm_dsp_factory* factory)
642 {
643     return deleteDSPFactory(factory);
644 }
645 
getCName(llvm_dsp_factory * factory)646 EXPORT char* getCName(llvm_dsp_factory* factory)
647 {
648     if (factory) {
649         string name = factory->getName();
650         return strdup(name.c_str());
651     } else {
652         return nullptr;
653     }
654 }
655 
getCSHAKey(llvm_dsp_factory * factory)656 EXPORT char* getCSHAKey(llvm_dsp_factory* factory)
657 {
658     if (factory) {
659         string shakey = factory->getSHAKey();
660         return strdup(shakey.c_str());
661     } else {
662         return nullptr;
663     }
664 }
665 
getCTarget(llvm_dsp_factory * factory)666 EXPORT char* getCTarget(llvm_dsp_factory* factory)
667 {
668     if (factory) {
669         string target = factory->getTarget();
670         return strdup(target.c_str());
671     } else {
672         return nullptr;
673     }
674 }
675 
getCDSPCode(llvm_dsp_factory * factory)676 EXPORT char* getCDSPCode(llvm_dsp_factory* factory)
677 {
678     if (factory) {
679         string dspcode = factory->getDSPCode();
680         return strdup(dspcode.c_str());
681     } else {
682         return nullptr;
683     }
684 }
685 
getCDSPMachineTarget()686 EXPORT char* getCDSPMachineTarget()
687 {
688     string dspmachinetarget = getDSPMachineTarget();
689     return strdup(dspmachinetarget.c_str());
690 }
691 
getCDSPFactoryLibraryList(llvm_dsp_factory * factory)692 EXPORT const char** getCDSPFactoryLibraryList(llvm_dsp_factory* factory)
693 {
694     if (factory) {
695         vector<string> library_list1 = factory->getLibraryList();
696         const char**   library_list2 = (const char**)malloc(sizeof(char*) * (library_list1.size() + 1));
697 
698         size_t i;
699         for (i = 0; i < library_list1.size(); i++) {
700             library_list2[i] = strdup(library_list1[i].c_str());
701         }
702 
703         // Last element is NULL
704         library_list2[i] = nullptr;
705         return library_list2;
706     } else {
707         return nullptr;
708     }
709 }
710 
getCDSPFactoryIncludePathnames(llvm_dsp_factory * factory)711 EXPORT const char** getCDSPFactoryIncludePathnames(llvm_dsp_factory* factory)
712 {
713     if (factory) {
714         vector<string> include_list1 = factory->getIncludePathnames();
715         const char**   include_list2 = (const char**)malloc(sizeof(char*) * (include_list1.size() + 1));
716 
717         size_t i;
718         for (i = 0; i < include_list1.size(); i++) {
719             include_list2[i] = strdup(include_list1[i].c_str());
720         }
721 
722         // Last element is NULL
723         include_list2[i] = nullptr;
724         return include_list2;
725     } else {
726         return nullptr;
727     }
728 }
729 
getCDSPFactoryCompileOptions(llvm_dsp_factory * factory)730 EXPORT char* getCDSPFactoryCompileOptions(llvm_dsp_factory* factory)
731 {
732     if (factory) {
733         string options = factory->getCompileOptions();
734         return strdup(options.c_str());
735     } else {
736         return nullptr;
737     }
738 }
739 
deleteAllCDSPFactories()740 EXPORT void deleteAllCDSPFactories()
741 {
742     deleteAllDSPFactories();
743 }
744 
readCDSPFactoryFromMachine(const char * machine_code,const char * target,char * error_msg)745 EXPORT llvm_dsp_factory* readCDSPFactoryFromMachine(const char* machine_code, const char* target, char* error_msg)
746 {
747     string            error_msg_aux;
748     llvm_dsp_factory* factory = readDSPFactoryFromMachine(machine_code, target, error_msg_aux);
749     strncpy(error_msg, error_msg_aux.c_str(), 4096);
750     return factory;
751 }
752 
writeCDSPFactoryToMachine(llvm_dsp_factory * factory,const char * target)753 EXPORT char* writeCDSPFactoryToMachine(llvm_dsp_factory* factory, const char* target)
754 {
755     return (factory) ? strdup(writeDSPFactoryToMachine(factory, target).c_str()) : nullptr;
756 }
757 
readCDSPFactoryFromMachineFile(const char * machine_code_path,const char * target,char * error_msg)758 EXPORT llvm_dsp_factory* readCDSPFactoryFromMachineFile(const char* machine_code_path, const char* target,
759                                                         char* error_msg)
760 {
761     string            error_msg_aux;
762     llvm_dsp_factory* factory = readDSPFactoryFromMachineFile(machine_code_path, target, error_msg_aux);
763     strncpy(error_msg, error_msg_aux.c_str(), 4096);
764     return factory;
765 }
766 
writeCDSPFactoryToMachineFile(llvm_dsp_factory * factory,const char * machine_code_path,const char * target)767 EXPORT bool writeCDSPFactoryToMachineFile(llvm_dsp_factory* factory, const char* machine_code_path, const char* target)
768 {
769     return (factory) ? writeDSPFactoryToMachineFile(factory, machine_code_path, target) : false;
770 }
771 
writeCDSPFactoryToObjectcodeFile(llvm_dsp_factory * factory,const char * object_code_path,const char * target)772 EXPORT bool writeCDSPFactoryToObjectcodeFile(llvm_dsp_factory* factory, const char* object_code_path,
773                                              const char* target)
774 {
775     return (factory) ? writeDSPFactoryToObjectcodeFile(factory, object_code_path, target) : false;
776 }
777 
metadataCDSPInstance(llvm_dsp * dsp,MetaGlue * glue)778 EXPORT void metadataCDSPInstance(llvm_dsp* dsp, MetaGlue* glue)
779 {
780     if (dsp) {
781         dsp->metadata(glue);
782     }
783 }
784 
getNumInputsCDSPInstance(llvm_dsp * dsp)785 EXPORT int getNumInputsCDSPInstance(llvm_dsp* dsp)
786 {
787     return (dsp) ? dsp->getNumInputs() : -1;
788 }
789 
getNumOutputsCDSPInstance(llvm_dsp * dsp)790 EXPORT int getNumOutputsCDSPInstance(llvm_dsp* dsp)
791 {
792     return (dsp) ? dsp->getNumOutputs() : -1;
793 }
794 
initCDSPInstance(llvm_dsp * dsp,int sample_rate)795 EXPORT void initCDSPInstance(llvm_dsp* dsp, int sample_rate)
796 {
797     if (dsp) {
798         dsp->init(sample_rate);
799     }
800 }
801 
instanceInitCDSPInstance(llvm_dsp * dsp,int sample_rate)802 EXPORT void instanceInitCDSPInstance(llvm_dsp* dsp, int sample_rate)
803 {
804     if (dsp) {
805         dsp->instanceInit(sample_rate);
806     }
807 }
808 
instanceConstantsCDSPInstance(llvm_dsp * dsp,int sample_rate)809 EXPORT void instanceConstantsCDSPInstance(llvm_dsp* dsp, int sample_rate)
810 {
811     if (dsp) {
812         dsp->instanceConstants(sample_rate);
813     }
814 }
815 
instanceResetUserInterfaceCDSPInstance(llvm_dsp * dsp)816 EXPORT void instanceResetUserInterfaceCDSPInstance(llvm_dsp* dsp)
817 {
818     if (dsp) {
819         dsp->instanceResetUserInterface();
820     }
821 }
822 
instanceClearCDSPInstance(llvm_dsp * dsp)823 EXPORT void instanceClearCDSPInstance(llvm_dsp* dsp)
824 {
825     if (dsp) {
826         dsp->instanceClear();
827     }
828 }
829 
getSampleRateCDSPInstance(llvm_dsp * dsp)830 EXPORT int getSampleRateCDSPInstance(llvm_dsp* dsp)
831 {
832     return (dsp) ? dsp->getSampleRate() : 0;
833 }
834 
buildUserInterfaceCDSPInstance(llvm_dsp * dsp,UIGlue * glue)835 EXPORT void buildUserInterfaceCDSPInstance(llvm_dsp* dsp, UIGlue* glue)
836 {
837     if (dsp) {
838         dsp->buildUserInterface(glue);
839     }
840 }
841 
computeCDSPInstance(llvm_dsp * dsp,int count,FAUSTFLOAT ** input,FAUSTFLOAT ** output)842 EXPORT void computeCDSPInstance(llvm_dsp* dsp, int count, FAUSTFLOAT** input, FAUSTFLOAT** output)
843 {
844     if (dsp) {
845         dsp->compute(count, input, output);
846     }
847 }
848 
cloneCDSPInstance(llvm_dsp * dsp)849 EXPORT llvm_dsp* cloneCDSPInstance(llvm_dsp* dsp)
850 {
851     return (dsp) ? dsp->clone() : nullptr;
852 }
853 
setCMemoryManager(llvm_dsp_factory * factory,MemoryManagerGlue * manager)854 EXPORT void setCMemoryManager(llvm_dsp_factory* factory, MemoryManagerGlue* manager)
855 {
856     if (factory) {
857         factory->setMemoryManager(manager);
858     }
859 }
860 
createCDSPInstance(llvm_dsp_factory * factory)861 EXPORT llvm_dsp* createCDSPInstance(llvm_dsp_factory* factory)
862 {
863     return (factory) ? factory->createDSPInstance() : nullptr;
864 }
865 
deleteCDSPInstance(llvm_dsp * dsp)866 EXPORT void deleteCDSPInstance(llvm_dsp* dsp)
867 {
868     delete dsp;
869 }
870 
871 #ifdef __cplusplus
872 }
873 #endif
874