source: icGREP/icgrep-devel/icgrep/generate_predefined_ucd_functions.cpp @ 4665

Last change on this file since 4665 was 4665, checked in by nmedfort, 4 years ago

Made pablo compiler reenterant through alternate compile method that takes a Module parameter.

File size: 7.2 KB
Line 
1/*
2 *  Copyright (c) 2015 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include <cc/cc_compiler.h>
8#include <UCD/unicode_set.h>
9#include <UCD/PropertyObjectTable.h>
10#include <UCD/ucd_compiler.hpp>
11#include <pablo/pablo_compiler.h>
12#include <pablo/builder.hpp>
13#include <pablo/function.h>
14#include <llvm/Support/CommandLine.h>
15#include <utf_encoding.h>
16#include <pablo/optimizers/pablo_simplifier.hpp>
17#include <pablo/optimizers/pablo_codesinking.hpp>
18#ifdef ENABLE_MULTIPLEXING
19#include <pablo/optimizers/pablo_automultiplexing.hpp>
20#endif
21#include <llvm/IR/Verifier.h>
22#include <llvm/Support/Debug.h>
23#include <llvm/Support/TargetRegistry.h>
24#include <llvm/Support/TargetSelect.h>
25#include <llvm/Target/TargetLibraryInfo.h>
26#include <llvm/Target/TargetMachine.h>
27#include <llvm/Support/Host.h>
28#include <llvm/ADT/Triple.h>
29#include <llvm/Support/ToolOutputFile.h>
30#include <llvm/Pass.h>
31#include <llvm/PassManager.h>
32#include <llvm/ADT/STLExtras.h>
33#include <llvm/Target/TargetSubtargetInfo.h>
34#include <llvm/Support/FormattedStream.h>
35
36#include "llvm/Support/FileSystem.h"
37
38#include <boost/algorithm/string/case_conv.hpp>
39#include <iostream>
40
41using namespace pablo;
42using namespace UCD;
43using namespace cc;
44using namespace llvm;
45
46inline std::string lowercase(const std::string & name) {
47    std::locale loc;
48    return boost::algorithm::to_lower_copy(name, loc);
49}
50
51static cl::opt<std::string>
52OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
53
54/** ------------------------------------------------------------------------------------------------------------- *
55 * @brief compileUnicodeSet
56 ** ------------------------------------------------------------------------------------------------------------- */
57void compileUnicodeSet(std::string name, const UnicodeSet & set, PabloCompiler & pc, Module * module) {
58    PabloFunction function = PabloFunction::Create(std::move(name));
59    Encoding encoding(Encoding::Type::UTF_8, 8);
60    CC_Compiler ccCompiler(function, encoding);
61    UCDCompiler ucdCompiler(ccCompiler);
62    PabloBuilder builder(function.getEntryBlock());
63    // Build the unicode set function
64    ucdCompiler.generateWithDefaultIfHierarchy(set, builder);
65    // Optimize it at the pablo level
66    Simplifier::optimize(function);
67    CodeSinking::optimize(function);
68    #ifdef ENABLE_MULTIPLEXING
69    AutoMultiplexing::optimize(function);
70    #endif
71    // Now compile the function ...
72    pc.compile(function, module);
73    releaseSlabAllocatorMemory();
74}
75
76/** ------------------------------------------------------------------------------------------------------------- *
77 * @brief generateUCDModule
78 ** ------------------------------------------------------------------------------------------------------------- */
79Module * generateUCDModule() {
80    PabloCompiler pc;
81    Module * module = new Module("ucd", getGlobalContext());
82    for (PropertyObject * obj : property_object_table) {
83
84        if (isa<UnsupportedPropertyObject>(obj)) continue;
85
86        if (auto * enumObj = dyn_cast<EnumeratedPropertyObject>(obj)) {
87            for (const std::string value : *enumObj) {
88                const UnicodeSet & set = enumObj->GetCodepointSet(canonicalize_value_name(value));
89                std::string name = "__get_" + property_enum_name[enumObj->getPropertyCode()] + "_" + lowercase(value);
90                compileUnicodeSet(name, set, pc, module);
91            }
92            break;
93        }
94        else if (auto * extObj = dyn_cast<ExtensionPropertyObject>(obj)) {
95            for (const std::string value : *extObj) {
96                const UnicodeSet & set = extObj->GetCodepointSet(canonicalize_value_name(value));
97                std::string name = "__get_" + property_enum_name[extObj->getPropertyCode()] + "_" + lowercase(value);
98                compileUnicodeSet(name, set, pc, module);
99            }
100        }
101        else if (auto * binObj = dyn_cast<BinaryPropertyObject>(obj)) {
102            const UnicodeSet & set = binObj->GetCodepointSet(Binary_ns::Y);
103            std::string name = "__get_" + property_enum_name[binObj->getPropertyCode()] + "_y";
104            compileUnicodeSet(name, set, pc, module);
105        }
106    }
107
108    // Print an error message if our module is malformed in any way.
109    verifyModule(*module, &dbgs());
110
111    return module;
112}
113
114/** ------------------------------------------------------------------------------------------------------------- *
115 * @brief compileUCDModule
116 ** ------------------------------------------------------------------------------------------------------------- */
117void compileUCDModule(Module * module) {
118    Triple TheTriple;
119
120    if (TheTriple.getTriple().empty()) {
121        TheTriple.setTriple(sys::getDefaultTargetTriple());
122    }
123
124    // Get the target specific parser.
125    std::string msg;
126    const Target * TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), msg);
127
128    if (TheTarget == nullptr) {
129        throw std::runtime_error(msg);
130    }
131
132    auto MCPU = llvm::sys::getHostCPUName();
133
134    TargetOptions Options;
135
136    std::unique_ptr<TargetMachine> Target(
137                TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, "", Options,
138                                               Reloc::Default, CodeModel::Small, CodeGenOpt::Aggressive));
139
140    if (Target == nullptr) {
141        throw std::runtime_error("Could not allocate target machine!");
142    }
143
144    #ifdef USE_LLVM_3_5
145    std::string error;
146    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(OutputFilename.c_str(), error, sys::fs::F_None);
147    if (!error.empty()) {
148        throw std::runtime_error(error);
149    }
150    #else
151    std::error_code error;
152    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(OutputFilename, error, sys::fs::F_None);
153    if (error) {
154        throw std::runtime_error(error.message());
155    }
156    #endif
157
158    // Build up all of the passes that we want to do to the module.
159    PassManager PM;
160
161    // Add an appropriate TargetLibraryInfo pass for the module's triple.
162    TargetLibraryInfo * TLI = new TargetLibraryInfo(TheTriple);
163
164    PM.add(TLI);
165
166    // Add the target data from the target machine, if it exists, or the module.
167    #ifdef USE_LLVM_3_5
168    const DataLayout * DL = Target->getDataLayout();
169    #else
170    const DataLayout * DL = Target->getSubtargetImpl()->getDataLayout();
171    #endif
172    if (DL) {
173        module->setDataLayout(DL);
174    }
175    PM.add(new DataLayoutPass());
176
177    formatted_raw_ostream FOS(Out->os());
178    // Ask the target to add backend passes as necessary.
179    if (Target->addPassesToEmitFile(PM, FOS, TargetMachine::CGFT_ObjectFile)) {
180        throw std::runtime_error("Target does not support generation of this file type!\n");
181    }
182
183    PM.run(*module);
184
185    Out->keep();
186}
187
188/** ------------------------------------------------------------------------------------------------------------- *
189 * @brief main
190 ** ------------------------------------------------------------------------------------------------------------- */
191int main(int argc, char *argv[]) {
192    cl::ParseCommandLineOptions(argc, argv, "UCD Compiler\n");
193    Module * module = generateUCDModule();
194    compileUCDModule(module);
195    return 0;
196}
Note: See TracBrowser for help on using the repository browser.