Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
//
2
// Copyright 2012 Francisco Jerez
3
//
4
// Permission is hereby granted, free of charge, to any person obtaining a
5
// copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
// OTHER DEALINGS IN THE SOFTWARE.
21
//
22
 
23
#include "core/compiler.hpp"
24
 
25
#include 
26
#include 
27
#include 
28
#include 
29
#include 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include 
37
#include 
38
#include 
39
#include 
40
#if HAVE_LLVM >= 0x0307
41
#include 
42
#else
43
#include 
44
#endif
45
#include 
46
#include 
47
#include 
48
#include 
49
#include 
50
#include 
51
#include 
52
#include 
53
 
54
 
55
#include 
56
#if HAVE_LLVM >= 0x0307
57
#include 
58
#else
59
#include 
60
#endif
61
#include 
62
#include 
63
 
64
#include 
65
#include 
66
#include 
67
 
68
#include "pipe/p_state.h"
69
#include "util/u_memory.h"
70
#include "util/u_math.h"
71
 
72
#include 
73
#include 
74
#include 
75
#include 
76
#include 
77
#include 
78
#include 
79
 
80
using namespace clover;
81
 
82
namespace {
83
#if 0
84
   void
85
   build_binary(const std::string &source, const std::string &target,
86
                const std::string &name) {
87
      clang::CompilerInstance c;
88
      clang::EmitObjAction act(&llvm::getGlobalContext());
89
      std::string log;
90
      llvm::raw_string_ostream s_log(log);
91
 
92
      LLVMInitializeTGSITarget();
93
      LLVMInitializeTGSITargetInfo();
94
      LLVMInitializeTGSITargetMC();
95
      LLVMInitializeTGSIAsmPrinter();
96
 
97
      c.getFrontendOpts().Inputs.push_back(
98
         std::make_pair(clang::IK_OpenCL, name));
99
      c.getHeaderSearchOpts().UseBuiltinIncludes = false;
100
      c.getHeaderSearchOpts().UseStandardIncludes = false;
101
      c.getLangOpts().NoBuiltin = true;
102
      c.getTargetOpts().Triple = target;
103
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
104
      c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter(
105
                             s_log, c.getDiagnosticOpts()));
106
 
107
      c.getPreprocessorOpts().addRemappedFile(
108
         name, llvm::MemoryBuffer::getMemBuffer(source));
109
 
110
      if (!c.ExecuteAction(act))
111
         throw build_error(log);
112
   }
113
 
114
   module
115
   load_binary(const char *name) {
116
      std::ifstream fs((name));
117
      std::vector str((std::istreambuf_iterator(fs)),
118
                                     (std::istreambuf_iterator()));
119
      compat::istream cs(str);
120
      return module::deserialize(cs);
121
   }
122
#endif
123
   void debug_log(const std::string &msg, const std::string &suffix) {
124
      const char *dbg_file = debug_get_option("CLOVER_DEBUG_FILE", "stderr");
125
      if (!strcmp("stderr", dbg_file)) {
126
         std::cerr << msg;
127
       } else {
128
        std::ofstream file(dbg_file + suffix, std::ios::app);
129
        file << msg;
130
       }
131
   }
132
 
133
   llvm::Module *
134
   compile_llvm(llvm::LLVMContext &llvm_ctx, const std::string &source,
135
                const header_map &headers,
136
                const std::string &name, const std::string &triple,
137
                const std::string &processor, const std::string &opts,
138
                clang::LangAS::Map& address_spaces, unsigned &optimization_level,
139
                std::string &r_log) {
140
 
141
      clang::CompilerInstance c;
142
      clang::EmitLLVMOnlyAction act(&llvm_ctx);
143
      std::string log;
144
      llvm::raw_string_ostream s_log(log);
145
      std::string libclc_path = LIBCLC_LIBEXECDIR + processor + "-"
146
                                                  + triple + ".bc";
147
 
148
      // Parse the compiler options:
149
      std::vector opts_array;
150
      std::istringstream ss(opts);
151
 
152
      while (!ss.eof()) {
153
         std::string opt;
154
         getline(ss, opt, ' ');
155
         opts_array.push_back(opt);
156
      }
157
 
158
      opts_array.push_back(name);
159
 
160
      std::vector opts_carray;
161
      for (unsigned i = 0; i < opts_array.size(); i++) {
162
         opts_carray.push_back(opts_array.at(i).c_str());
163
      }
164
 
165
      llvm::IntrusiveRefCntPtr DiagID;
166
      llvm::IntrusiveRefCntPtr DiagOpts;
167
      clang::TextDiagnosticBuffer *DiagsBuffer;
168
 
169
      DiagID = new clang::DiagnosticIDs();
170
      DiagOpts = new clang::DiagnosticOptions();
171
      DiagsBuffer = new clang::TextDiagnosticBuffer();
172
 
173
      clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
174
      bool Success;
175
 
176
      Success = clang::CompilerInvocation::CreateFromArgs(c.getInvocation(),
177
                                        opts_carray.data(),
178
                                        opts_carray.data() + opts_carray.size(),
179
                                        Diags);
180
      if (!Success) {
181
         throw error(CL_INVALID_COMPILER_OPTIONS);
182
      }
183
      c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
184
      c.getHeaderSearchOpts().UseBuiltinIncludes = true;
185
      c.getHeaderSearchOpts().UseStandardSystemIncludes = true;
186
      c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR;
187
 
188
      // Add libclc generic search path
189
      c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR,
190
                                      clang::frontend::Angled,
191
                                      false, false
192
                                      );
193
 
194
      // Add libclc include
195
      c.getPreprocessorOpts().Includes.push_back("clc/clc.h");
196
 
197
      // clc.h requires that this macro be defined:
198
      c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
199
 
200
      c.getLangOpts().NoBuiltin = true;
201
      c.getTargetOpts().Triple = triple;
202
      c.getTargetOpts().CPU = processor;
203
 
204
      // This is a workaround for a Clang bug which causes the number
205
      // of warnings and errors to be printed to stderr.
206
      // http://www.llvm.org/bugs/show_bug.cgi?id=19735
207
      c.getDiagnosticOpts().ShowCarets = false;
208
      c.getInvocation().setLangDefaults(c.getLangOpts(), clang::IK_OpenCL,
209
                                        clang::LangStandard::lang_opencl11);
210
      c.createDiagnostics(
211
                          new clang::TextDiagnosticPrinter(
212
                                 s_log,
213
                                 &c.getDiagnosticOpts()));
214
 
215
#if HAVE_LLVM >= 0x0306
216
      c.getPreprocessorOpts().addRemappedFile(name,
217
                                              llvm::MemoryBuffer::getMemBuffer(source).release());
218
#else
219
      c.getPreprocessorOpts().addRemappedFile(name,
220
                                      llvm::MemoryBuffer::getMemBuffer(source));
221
#endif
222
 
223
      if (headers.size()) {
224
         const std::string tmp_header_path = "/tmp/clover/";
225
 
226
         c.getHeaderSearchOpts().AddPath(tmp_header_path,
227
                                         clang::frontend::Angled,
228
                                         false, false
229
                                         );
230
 
231
         for (header_map::const_iterator it = headers.begin();
232
              it != headers.end(); ++it) {
233
            const std::string path = tmp_header_path + std::string(it->first);
234
            c.getPreprocessorOpts().addRemappedFile(path,
235
#if HAVE_LLVM >= 0x0306
236
                    llvm::MemoryBuffer::getMemBuffer(it->second.c_str()).release());
237
#else
238
                    llvm::MemoryBuffer::getMemBuffer(it->second.c_str()));
239
#endif
240
         }
241
      }
242
 
243
      // Setting this attribute tells clang to link this file before
244
      // performing any optimizations.  This is required so that
245
      // we can replace calls to the OpenCL C barrier() builtin
246
      // with calls to target intrinsics that have the noduplicate
247
      // attribute.  This attribute will prevent Clang from creating
248
      // illegal uses of barrier() (e.g. Moving barrier() inside a conditional
249
      // that is no executed by all threads) during its optimizaton passes.
250
      c.getCodeGenOpts().LinkBitcodeFile = libclc_path;
251
 
252
      optimization_level = c.getCodeGenOpts().OptimizationLevel;
253
 
254
      // Compile the code
255
      bool ExecSuccess = c.ExecuteAction(act);
256
      r_log = log;
257
 
258
      if (!ExecSuccess)
259
         throw build_error();
260
 
261
      // Get address spaces map to be able to find kernel argument address space
262
      memcpy(address_spaces, c.getTarget().getAddressSpaceMap(),
263
                                                        sizeof(address_spaces));
264
 
265
#if HAVE_LLVM >= 0x0306
266
      return act.takeModule().release();
267
#else
268
      return act.takeModule();
269
#endif
270
   }
271
 
272
   void
273
   find_kernels(llvm::Module *mod, std::vector &kernels) {
274
      const llvm::NamedMDNode *kernel_node =
275
                                 mod->getNamedMetadata("opencl.kernels");
276
      // This means there are no kernels in the program.  The spec does not
277
      // require that we return an error here, but there will be an error if
278
      // the user tries to pass this program to a clCreateKernel() call.
279
      if (!kernel_node) {
280
         return;
281
      }
282
 
283
      for (unsigned i = 0; i < kernel_node->getNumOperands(); ++i) {
284
#if HAVE_LLVM >= 0x0306
285
         kernels.push_back(llvm::mdconst::dyn_extract(
286
#else
287
         kernels.push_back(llvm::dyn_cast(
288
#endif
289
                                    kernel_node->getOperand(i)->getOperand(0)));
290
      }
291
   }
292
 
293
   void
294
   optimize(llvm::Module *mod, unsigned optimization_level,
295
            const std::vector &kernels) {
296
 
297
#if HAVE_LLVM >= 0x0307
298
      llvm::legacy::PassManager PM;
299
#else
300
      llvm::PassManager PM;
301
#endif
302
 
303
      // Add a function internalizer pass.
304
      //
305
      // By default, the function internalizer pass will look for a function
306
      // called "main" and then mark all other functions as internal.  Marking
307
      // functions as internal enables the optimizer to perform optimizations
308
      // like function inlining and global dead-code elimination.
309
      //
310
      // When there is no "main" function in a module, the internalize pass will
311
      // treat the module like a library, and it won't internalize any functions.
312
      // Since there is no "main" function in our kernels, we need to tell
313
      // the internalizer pass that this module is not a library by passing a
314
      // list of kernel functions to the internalizer.  The internalizer will
315
      // treat the functions in the list as "main" functions and internalize
316
      // all of the other functions.
317
      std::vector export_list;
318
      for (std::vector::const_iterator I = kernels.begin(),
319
                                                         E = kernels.end();
320
                                                         I != E; ++I) {
321
         llvm::Function *kernel = *I;
322
         export_list.push_back(kernel->getName().data());
323
      }
324
#if HAVE_LLVM < 0x0306
325
      PM.add(new llvm::DataLayoutPass(mod));
326
#elif HAVE_LLVM < 0x0307
327
      PM.add(new llvm::DataLayoutPass());
328
#endif
329
      PM.add(llvm::createInternalizePass(export_list));
330
 
331
      llvm::PassManagerBuilder PMB;
332
      PMB.OptLevel = optimization_level;
333
#if HAVE_LLVM < 0x0307
334
      PMB.LibraryInfo = new llvm::TargetLibraryInfo(
335
#else
336
      PMB.LibraryInfo = new llvm::TargetLibraryInfoImpl(
337
#endif
338
            llvm::Triple(mod->getTargetTriple()));
339
      PMB.populateModulePassManager(PM);
340
      PM.run(*mod);
341
   }
342
 
343
   std::vector
344
   get_kernel_args(const llvm::Module *mod, const std::string &kernel_name,
345
                   const clang::LangAS::Map &address_spaces) {
346
 
347
      std::vector args;
348
      llvm::Function *kernel_func = mod->getFunction(kernel_name);
349
 
350
      llvm::DataLayout TD(mod);
351
 
352
      for (llvm::Function::const_arg_iterator I = kernel_func->arg_begin(),
353
                                      E = kernel_func->arg_end(); I != E; ++I) {
354
         const llvm::Argument &arg = *I;
355
 
356
         llvm::Type *arg_type = arg.getType();
357
         const unsigned arg_store_size = TD.getTypeStoreSize(arg_type);
358
 
359
         // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data
360
         // type that is not a power of two bytes in size must be
361
         // aligned to the next larger power of two".  We need this
362
         // alignment for three element vectors, which have
363
         // non-power-of-2 store size.
364
         const unsigned arg_api_size = util_next_power_of_two(arg_store_size);
365
 
366
         llvm::Type *target_type = arg_type->isIntegerTy() ?
367
               TD.getSmallestLegalIntType(mod->getContext(), arg_store_size * 8)
368
               : arg_type;
369
         unsigned target_size = TD.getTypeStoreSize(target_type);
370
         unsigned target_align = TD.getABITypeAlignment(target_type);
371
 
372
         if (llvm::isa(arg_type) && arg.hasByValAttr()) {
373
            arg_type =
374
                  llvm::dyn_cast(arg_type)->getElementType();
375
         }
376
 
377
         if (arg_type->isPointerTy()) {
378
            unsigned address_space = llvm::cast(arg_type)->getAddressSpace();
379
            if (address_space == address_spaces[clang::LangAS::opencl_local
380
                                                     - clang::LangAS::Offset]) {
381
               args.push_back(module::argument(module::argument::local,
382
                                               arg_api_size, target_size,
383
                                               target_align,
384
                                               module::argument::zero_ext));
385
            } else {
386
               // XXX: Correctly handle constant address space.  There is no
387
               // way for r600g to pass a handle for constant buffers back
388
               // to clover like it can for global buffers, so
389
               // creating constant arguments will break r600g.  For now,
390
               // continue treating constant buffers as global buffers
391
               // until we can come up with a way to create handles for
392
               // constant buffers.
393
               args.push_back(module::argument(module::argument::global,
394
                                               arg_api_size, target_size,
395
                                               target_align,
396
                                               module::argument::zero_ext));
397
           }
398
 
399
         } else {
400
            llvm::AttributeSet attrs = kernel_func->getAttributes();
401
            enum module::argument::ext_type ext_type =
402
                  (attrs.hasAttribute(arg.getArgNo() + 1,
403
                                     llvm::Attribute::SExt) ?
404
                   module::argument::sign_ext :
405
                   module::argument::zero_ext);
406
 
407
            args.push_back(
408
               module::argument(module::argument::scalar, arg_api_size,
409
                                target_size, target_align, ext_type));
410
         }
411
      }
412
 
413
      // Append implicit arguments.  XXX - The types, ordering and
414
      // vector size of the implicit arguments should depend on the
415
      // target according to the selected calling convention.
416
      llvm::Type *size_type =
417
         TD.getSmallestLegalIntType(mod->getContext(), sizeof(cl_uint) * 8);
418
 
419
      args.push_back(
420
         module::argument(module::argument::scalar, sizeof(cl_uint),
421
                          TD.getTypeStoreSize(size_type),
422
                          TD.getABITypeAlignment(size_type),
423
                          module::argument::zero_ext,
424
                          module::argument::grid_dimension));
425
 
426
      args.push_back(
427
         module::argument(module::argument::scalar, sizeof(cl_uint),
428
                          TD.getTypeStoreSize(size_type),
429
                          TD.getABITypeAlignment(size_type),
430
                          module::argument::zero_ext,
431
                          module::argument::grid_offset));
432
 
433
      return args;
434
   }
435
 
436
   module
437
   build_module_llvm(llvm::Module *mod,
438
                     const std::vector &kernels,
439
                     clang::LangAS::Map& address_spaces) {
440
 
441
      module m;
442
      struct pipe_llvm_program_header header;
443
 
444
      llvm::SmallVector llvm_bitcode;
445
      llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
446
      llvm::BitstreamWriter writer(llvm_bitcode);
447
      llvm::WriteBitcodeToFile(mod, bitcode_ostream);
448
      bitcode_ostream.flush();
449
 
450
      for (unsigned i = 0; i < kernels.size(); ++i) {
451
         std::string kernel_name = kernels[i]->getName();
452
         std::vector args =
453
               get_kernel_args(mod, kernel_name, address_spaces);
454
 
455
         m.syms.push_back(module::symbol(kernel_name, 0, i, args ));
456
      }
457
 
458
      header.num_bytes = llvm_bitcode.size();
459
      std::vector data;
460
      data.insert(data.end(), (char*)(&header),
461
                              (char*)(&header) + sizeof(header));
462
      data.insert(data.end(), llvm_bitcode.begin(),
463
                                  llvm_bitcode.end());
464
      m.secs.push_back(module::section(0, module::section::text,
465
                                       header.num_bytes, data));
466
 
467
      return m;
468
   }
469
 
470
   void
471
   emit_code(LLVMTargetMachineRef tm, LLVMModuleRef mod,
472
             LLVMCodeGenFileType file_type,
473
             LLVMMemoryBufferRef *out_buffer,
474
             std::string &r_log) {
475
      LLVMBool err;
476
      char *err_message = NULL;
477
 
478
      err = LLVMTargetMachineEmitToMemoryBuffer(tm, mod, file_type,
479
                                                &err_message, out_buffer);
480
 
481
      if (err) {
482
         r_log = std::string(err_message);
483
      }
484
 
485
      LLVMDisposeMessage(err_message);
486
 
487
      if (err) {
488
         throw build_error();
489
      }
490
   }
491
 
492
   std::vector
493
   compile_native(const llvm::Module *mod, const std::string &triple,
494
                  const std::string &processor, unsigned dump_asm,
495
                  std::string &r_log) {
496
 
497
      std::string log;
498
      LLVMTargetRef target;
499
      char *error_message;
500
      LLVMMemoryBufferRef out_buffer;
501
      unsigned buffer_size;
502
      const char *buffer_data;
503
      LLVMModuleRef mod_ref = wrap(mod);
504
 
505
      if (LLVMGetTargetFromTriple(triple.c_str(), &target, &error_message)) {
506
         r_log = std::string(error_message);
507
         LLVMDisposeMessage(error_message);
508
         throw build_error();
509
      }
510
 
511
      LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
512
            target, triple.c_str(), processor.c_str(), "",
513
            LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);
514
 
515
      if (!tm) {
516
         r_log = "Could not create TargetMachine: " + triple;
517
         throw build_error();
518
      }
519
 
520
      if (dump_asm) {
521
         LLVMSetTargetMachineAsmVerbosity(tm, true);
522
         LLVMModuleRef debug_mod = wrap(llvm::CloneModule(mod));
523
         emit_code(tm, debug_mod, LLVMAssemblyFile, &out_buffer, r_log);
524
         buffer_size = LLVMGetBufferSize(out_buffer);
525
         buffer_data = LLVMGetBufferStart(out_buffer);
526
         debug_log(std::string(buffer_data, buffer_size), ".asm");
527
 
528
         LLVMSetTargetMachineAsmVerbosity(tm, false);
529
         LLVMDisposeMemoryBuffer(out_buffer);
530
         LLVMDisposeModule(debug_mod);
531
      }
532
 
533
      emit_code(tm, mod_ref, LLVMObjectFile, &out_buffer, r_log);
534
 
535
      buffer_size = LLVMGetBufferSize(out_buffer);
536
      buffer_data = LLVMGetBufferStart(out_buffer);
537
 
538
      std::vector code(buffer_data, buffer_data + buffer_size);
539
 
540
      LLVMDisposeMemoryBuffer(out_buffer);
541
      LLVMDisposeTargetMachine(tm);
542
 
543
      return code;
544
   }
545
 
546
   std::map
547
   get_kernel_offsets(std::vector &code,
548
                      const std::vector &kernels,
549
                      std::string &r_log) {
550
 
551
      // One of the libelf implementations
552
      // (http://www.mr511.de/software/english.htm) requires calling
553
      // elf_version() before elf_memory().
554
      //
555
      elf_version(EV_CURRENT);
556
 
557
      Elf *elf = elf_memory(&code[0], code.size());
558
      size_t section_str_index;
559
      elf_getshdrstrndx(elf, §ion_str_index);
560
      Elf_Scn *section = NULL;
561
      Elf_Scn *symtab = NULL;
562
      GElf_Shdr symtab_header;
563
 
564
      // Find the symbol table
565
      try {
566
         while ((section = elf_nextscn(elf, section))) {
567
            const char *name;
568
            if (gelf_getshdr(section, &symtab_header) != &symtab_header) {
569
               r_log = "Failed to read ELF section header.";
570
               throw build_error();
571
            }
572
            name = elf_strptr(elf, section_str_index, symtab_header.sh_name);
573
           if (!strcmp(name, ".symtab")) {
574
               symtab = section;
575
               break;
576
           }
577
         }
578
         if (!symtab) {
579
            r_log = "Unable to find symbol table.";
580
            throw build_error();
581
         }
582
      } catch (build_error &e) {
583
         elf_end(elf);
584
         throw e;
585
      }
586
 
587
 
588
      // Extract symbol information from the table
589
      Elf_Data *symtab_data = NULL;
590
      GElf_Sym *symbol;
591
      GElf_Sym s;
592
 
593
      std::map kernel_offsets;
594
      symtab_data = elf_getdata(symtab, symtab_data);
595
 
596
      // Determine the offsets for each kernel
597
      for (int i = 0; (symbol = gelf_getsym(symtab_data, i, &s)); i++) {
598
         char *name = elf_strptr(elf, symtab_header.sh_link, symbol->st_name);
599
         for (std::vector::const_iterator it = kernels.begin(),
600
              e = kernels.end(); it != e; ++it) {
601
            llvm::Function *f = *it;
602
            if (f->getName() == std::string(name))
603
               kernel_offsets[f->getName()] = symbol->st_value;
604
         }
605
      }
606
      elf_end(elf);
607
      return kernel_offsets;
608
   }
609
 
610
   module
611
   build_module_native(std::vector &code,
612
                       const llvm::Module *mod,
613
                       const std::vector &kernels,
614
                       const clang::LangAS::Map &address_spaces,
615
                       std::string &r_log) {
616
 
617
      std::map kernel_offsets =
618
            get_kernel_offsets(code, kernels, r_log);
619
 
620
      // Begin building the clover module
621
      module m;
622
      struct pipe_llvm_program_header header;
623
 
624
      // Store the generated ELF binary in the module's text section.
625
      header.num_bytes = code.size();
626
      std::vector data;
627
      data.insert(data.end(), (char*)(&header),
628
                              (char*)(&header) + sizeof(header));
629
      data.insert(data.end(), code.begin(), code.end());
630
      m.secs.push_back(module::section(0, module::section::text,
631
                                       header.num_bytes, data));
632
 
633
      for (std::map::iterator i = kernel_offsets.begin(),
634
           e = kernel_offsets.end(); i != e; ++i) {
635
         std::vector args =
636
               get_kernel_args(mod, i->first, address_spaces);
637
         m.syms.push_back(module::symbol(i->first, 0, i->second, args ));
638
      }
639
 
640
      return m;
641
   }
642
 
643
   void
644
   diagnostic_handler(const llvm::DiagnosticInfo &di, void *data) {
645
      if (di.getSeverity() == llvm::DS_Error) {
646
         std::string message = *(std::string*)data;
647
         llvm::raw_string_ostream stream(message);
648
         llvm::DiagnosticPrinterRawOStream dp(stream);
649
         di.print(dp);
650
         stream.flush();
651
         *(std::string*)data = message;
652
 
653
         throw build_error();
654
      }
655
   }
656
 
657
   void
658
   init_targets() {
659
      static bool targets_initialized = false;
660
      if (!targets_initialized) {
661
         LLVMInitializeAllTargets();
662
         LLVMInitializeAllTargetInfos();
663
         LLVMInitializeAllTargetMCs();
664
         LLVMInitializeAllAsmPrinters();
665
         targets_initialized = true;
666
      }
667
   }
668
 
669
#define DBG_CLC  (1 << 0)
670
#define DBG_LLVM (1 << 1)
671
#define DBG_ASM  (1 << 2)
672
 
673
   unsigned
674
   get_debug_flags() {
675
      static const struct debug_named_value debug_options[] = {
676
         {"clc", DBG_CLC, "Dump the OpenCL C code for all kernels."},
677
         {"llvm", DBG_LLVM, "Dump the generated LLVM IR for all kernels."},
678
         {"asm", DBG_ASM, "Dump kernel assembly code for targets specifying "
679
          "PIPE_SHADER_IR_NATIVE"},
680
         DEBUG_NAMED_VALUE_END // must be last
681
      };
682
      static const unsigned debug_flags =
683
         debug_get_flags_option("CLOVER_DEBUG", debug_options, 0);
684
 
685
      return debug_flags;
686
   }
687
 
688
} // End anonymous namespace
689
 
690
module
691
clover::compile_program_llvm(const std::string &source,
692
                             const header_map &headers,
693
                             enum pipe_shader_ir ir,
694
                             const std::string &target,
695
                             const std::string &opts,
696
                             std::string &r_log) {
697
 
698
   init_targets();
699
 
700
   std::vector kernels;
701
   size_t processor_str_len = std::string(target).find_first_of("-");
702
   std::string processor(target, 0, processor_str_len);
703
   std::string triple(target, processor_str_len + 1,
704
                      target.size() - processor_str_len - 1);
705
   clang::LangAS::Map address_spaces;
706
   llvm::LLVMContext llvm_ctx;
707
   unsigned optimization_level;
708
 
709
   llvm_ctx.setDiagnosticHandler(diagnostic_handler, &r_log);
710
 
711
   if (get_debug_flags() & DBG_CLC)
712
      debug_log(source, ".cl");
713
 
714
   // The input file name must have the .cl extension in order for the
715
   // CompilerInvocation class to recognize it as an OpenCL source file.
716
   llvm::Module *mod = compile_llvm(llvm_ctx, source, headers, "input.cl",
717
                                    triple, processor, opts, address_spaces,
718
                                    optimization_level, r_log);
719
 
720
   find_kernels(mod, kernels);
721
 
722
   optimize(mod, optimization_level, kernels);
723
 
724
   if (get_debug_flags() & DBG_LLVM) {
725
      std::string log;
726
      llvm::raw_string_ostream s_log(log);
727
      mod->print(s_log, NULL);
728
      s_log.flush();
729
      debug_log(log, ".ll");
730
    }
731
 
732
   module m;
733
   // Build the clover::module
734
   switch (ir) {
735
      case PIPE_SHADER_IR_TGSI:
736
         //XXX: Handle TGSI
737
         assert(0);
738
         m = module();
739
         break;
740
      case PIPE_SHADER_IR_LLVM:
741
         m = build_module_llvm(mod, kernels, address_spaces);
742
         break;
743
      case PIPE_SHADER_IR_NATIVE: {
744
         std::vector code = compile_native(mod, triple, processor,
745
                                                 get_debug_flags() & DBG_ASM,
746
                                                 r_log);
747
         m = build_module_native(code, mod, kernels, address_spaces, r_log);
748
         break;
749
      }
750
   }
751
#if HAVE_LLVM >= 0x0306
752
   // LLVM 3.6 and newer, the user takes ownership of the module.
753
   delete mod;
754
#endif
755
 
756
   return m;
757
}