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

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

UCD Generator now creates an install property .h file.

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
160    if (TheTarget == nullptr) {
161        throw std::runtime_error(msg);
162    }
163
164    auto MCPU = llvm::sys::getHostCPUName();
165
166    TargetOptions Options;
167
168    std::unique_ptr<TargetMachine> Target(
169                TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, "", Options,
170                                               Reloc::Default, CodeModel::Small, CodeGenOpt::Aggressive));
171
172    if (Target == nullptr) {
173        throw std::runtime_error("Could not allocate target machine!");
174    }
175
176    #ifdef USE_LLVM_3_5
177    std::string error;
178    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(OutputFilename.c_str(), error, sys::fs::F_None);
179    if (!error.empty()) {
180        throw std::runtime_error(error);
181    }
182    #else
183    std::error_code error;
184    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(ObjectFilename, error, sys::fs::F_None);
185    if (error) {
186        throw std::runtime_error(error.message());
187    }
188    #endif
189
190    // Build up all of the passes that we want to do to the module.
191    PassManager PM;
192
193    // Add an appropriate TargetLibraryInfo pass for the module's triple.
194    TargetLibraryInfo * TLI = new TargetLibraryInfo(TheTriple);
195
196    PM.add(TLI);
197
198    // Add the target data from the target machine, if it exists, or the module.
199    #ifdef USE_LLVM_3_5
200    const DataLayout * DL = Target->getDataLayout();
201    #else
202    const DataLayout * DL = Target->getSubtargetImpl()->getDataLayout();
203    #endif
204    if (DL) {
205        module->setDataLayout(DL);
206    }
207    PM.add(new DataLayoutPass());
208    PM.add(createReassociatePass());
209    PM.add(createInstructionCombiningPass());
210    PM.add(createSinkingPass());
211
212    formatted_raw_ostream FOS(Out->os());
213    // Ask the target to add backend passes as necessary.
214    if (Target->addPassesToEmitFile(PM, FOS, TargetMachine::CGFT_ObjectFile)) {
215        throw std::runtime_error("Target does not support generation of this file type!\n");
216    }
217
218    PM.run(*module);
219
220    Out->keep();
221}
222
223/** ------------------------------------------------------------------------------------------------------------- *
224 * @brief main
225 ** ------------------------------------------------------------------------------------------------------------- */
226int main(int argc, char *argv[]) {
227    cl::ParseCommandLineOptions(argc, argv, "UCD Compiler\n");
228    if (PropertyFilename.empty()) {
229        PropertyFilename = "PropertyInstall.h";
230    }
231    if (ObjectFilename.empty()) {
232        ObjectFilename = "ucd.o";
233    }
234    Module * module = generateUCDModule();
235    compileUCDModule(module);
236    return 0;
237}
Note: See TracBrowser for help on using the repository browser.