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

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

UCD Generator bug fix for LLVM 3.5

File size: 8.8 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#include "llvm/Support/FileSystem.h"
36#include <llvm/Transforms/Scalar.h>
37#include <boost/algorithm/string/case_conv.hpp>
38#include <iostream>
39
40using namespace pablo;
41using namespace UCD;
42using namespace cc;
43using namespace llvm;
44
45inline std::string lowercase(const std::string & name) {
46    std::locale loc;
47    return boost::algorithm::to_lower_copy(name, loc);
48}
49
50static cl::opt<std::string>
51ObjectFilename("o", cl::desc("Output Object filename"), cl::value_desc("filename"));
52
53static cl::opt<std::string>
54PropertyFilename("p", cl::desc("Install Property filename"), cl::value_desc("filename"));
55
56#ifdef ENABLE_MULTIPLEXING
57static cl::opt<bool> EnableMultiplexing("multiplexing", cl::init(false),
58                                        cl::desc("combine Advances whose inputs are mutual exclusive into the fewest number of advances possible (expensive)."));
59#endif
60
61/** ------------------------------------------------------------------------------------------------------------- *
62 * @brief compileUnicodeSet
63 ** ------------------------------------------------------------------------------------------------------------- */
64void compileUnicodeSet(std::string name, const UnicodeSet & set, PabloCompiler & pc, Module * module, raw_ostream & out) {
65    PabloFunction function = PabloFunction::Create(std::move(name));
66    Encoding encoding(Encoding::Type::UTF_8, 8);
67    CC_Compiler ccCompiler(function, encoding);
68    UCDCompiler ucdCompiler(ccCompiler);
69    PabloBuilder builder(function.getEntryBlock());
70    // Build the unicode set function
71    ucdCompiler.generateWithDefaultIfHierarchy(set, builder);
72    // Optimize it at the pablo level
73    Simplifier::optimize(function);
74    CodeSinking::optimize(function);
75    #ifdef ENABLE_MULTIPLEXING
76    if (EnableMultiplexing) {
77        AutoMultiplexing::optimize(function);
78    }
79    #endif
80    // Now compile the function ...
81    auto func = pc.compile(function, module);
82    out << "    p.InstallExternalFunction(\"" + name + "\", &" + name + ", " + std::to_string(func.second) + ");\n";
83    releaseSlabAllocatorMemory();
84}
85
86/** ------------------------------------------------------------------------------------------------------------- *
87 * @brief generateUCDModule
88 ** ------------------------------------------------------------------------------------------------------------- */
89Module * generateUCDModule() {
90
91    #ifdef USE_LLVM_3_5
92    std::string error;
93    raw_fd_ostream out(PropertyFilename.c_str(), error, sys::fs::F_None);
94    if (!error.empty()) {
95        throw std::runtime_error(error);
96    }
97    #else
98    std::error_code error;
99    raw_fd_ostream out(PropertyFilename, error, sys::fs::F_None);
100    if (error) {
101        throw std::runtime_error(error.message());
102    }
103    #endif
104
105    out << "#ifndef PROPERTYINSTALL\n";
106    out << "#define PROPERTYINSTALL\n\n";
107    out << "#include <pablo/pablo_compiler.h>\n\n";
108    out << "void install_properties(pablo::PabloCompiler & p) {\n";
109
110    PabloCompiler pc;
111    Module * module = new Module("ucd", getGlobalContext());
112    for (PropertyObject * obj : property_object_table) {
113        if (EnumeratedPropertyObject * enumObj = dyn_cast<EnumeratedPropertyObject>(obj)) {
114            for (const std::string value : *enumObj) {
115                const UnicodeSet & set = enumObj->GetCodepointSet(canonicalize_value_name(value));
116                std::string name = "__get_" + property_enum_name[enumObj->getPropertyCode()] + "_" + value;
117                compileUnicodeSet(name, set, pc, module, out);
118            }
119        }
120        else if (ExtensionPropertyObject * extObj = dyn_cast<ExtensionPropertyObject>(obj)) {
121            for (const std::string value : *extObj) {
122                const UnicodeSet & set = extObj->GetCodepointSet(canonicalize_value_name(value));
123                std::string name = "__get_" + property_enum_name[extObj->getPropertyCode()] + "_" + value;
124                compileUnicodeSet(name, set, pc, module, out);
125            }
126        }
127        else if (BinaryPropertyObject * binObj = dyn_cast<BinaryPropertyObject>(obj)) {
128            const UnicodeSet & set = binObj->GetCodepointSet(Binary_ns::Y);
129            std::string name = "__get_" + property_enum_name[binObj->getPropertyCode()] + "_Y";
130            compileUnicodeSet(name, set, pc, module, out);
131        }
132    }
133
134    out << "}\n\n#endif\n"; out.close();
135
136    // Print an error message if our module is malformed in any way.
137    verifyModule(*module, &dbgs());
138
139    return module;
140}
141
142/** ------------------------------------------------------------------------------------------------------------- *
143 * @brief compileUCDModule
144 ** ------------------------------------------------------------------------------------------------------------- */
145void compileUCDModule(Module * module) {
146    Triple TheTriple;
147
148    // Initialize targets first, so that --version shows registered targets.
149    InitializeAllTargets();
150    InitializeAllTargetMCs();
151    InitializeAllAsmPrinters();
152    InitializeAllAsmParsers();
153
154    TheTriple.setTriple(sys::getDefaultTargetTriple());
155
156    // Get the target specific parser.
157    std::string msg;
158    const Target * TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), msg);
159    if (TheTarget == nullptr) {
160        throw std::runtime_error(msg);
161    }
162
163    auto MCPU = llvm::sys::getHostCPUName();
164
165    TargetOptions Options;
166
167    std::unique_ptr<TargetMachine> Target(
168                TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, "", Options,
169                                               Reloc::Default, CodeModel::Small, CodeGenOpt::Aggressive));
170
171    if (Target == nullptr) {
172        throw std::runtime_error("Could not allocate target machine!");
173    }
174
175    #ifdef USE_LLVM_3_5
176    std::string error;
177    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(ObjectFilename.c_str(), error, sys::fs::F_None);
178    if (!error.empty()) {
179        throw std::runtime_error(error);
180    }
181    #else
182    std::error_code error;
183    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(ObjectFilename, error, sys::fs::F_None);
184    if (error) {
185        throw std::runtime_error(error.message());
186    }
187    #endif
188
189    // Build up all of the passes that we want to do to the module.
190    PassManager PM;
191
192    // Add an appropriate TargetLibraryInfo pass for the module's triple.
193    PM.add(new TargetLibraryInfo(TheTriple));
194
195    // Add the target data from the target machine, if it exists, or the module.
196    #ifdef USE_LLVM_3_5
197    const DataLayout * DL = Target->getDataLayout();
198    #else
199    const DataLayout * DL = Target->getSubtargetImpl()->getDataLayout();
200    #endif
201    if (DL) {
202        module->setDataLayout(DL);
203    }
204    #ifdef USE_LLVM_3_5
205    PM.add(new DataLayoutPass(module));
206    #else
207    PM.add(new DataLayoutPass());
208    #endif
209    PM.add(createReassociatePass());
210    PM.add(createInstructionCombiningPass());
211    PM.add(createSinkingPass());
212
213    formatted_raw_ostream FOS(Out->os());
214    // Ask the target to add backend passes as necessary.
215    if (Target->addPassesToEmitFile(PM, FOS, TargetMachine::CGFT_ObjectFile)) {
216        throw std::runtime_error("Target does not support generation of this file type!\n");
217    }
218
219    PM.run(*module);
220
221    Out->keep();
222}
223
224/** ------------------------------------------------------------------------------------------------------------- *
225 * @brief main
226 ** ------------------------------------------------------------------------------------------------------------- */
227int main(int argc, char *argv[]) {
228    cl::ParseCommandLineOptions(argc, argv, "UCD Compiler\n");
229    if (PropertyFilename.empty()) {
230        PropertyFilename = "PropertyInstall.h";
231    }
232    if (ObjectFilename.empty()) {
233        ObjectFilename = "ucd.o";
234    }
235    Module * module = generateUCDModule();
236    compileUCDModule(module);
237    return 0;
238}
Note: See TracBrowser for help on using the repository browser.