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

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

Minor simplification of generate_predefined_ucd_functions.

File size: 11.1 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 <iostream>
38
39using namespace pablo;
40using namespace UCD;
41using namespace cc;
42using namespace llvm;
43
44static cl::opt<std::string>
45ObjectFilename("o", cl::desc("Output object filename"), cl::value_desc("filename"), cl::Required);
46
47static cl::opt<std::string>
48UCDSourcePath("dir", cl::desc("UCD source code directory"), cl::value_desc("directory"), cl::Required);
49
50#ifdef ENABLE_MULTIPLEXING
51static cl::opt<bool> EnableMultiplexing("multiplexing", cl::init(false),
52                                        cl::desc("combine Advances whose inputs are mutual exclusive into the fewest number of advances possible (expensive)."));
53#endif
54
55using property_list = std::vector<std::pair<std::string, size_t>>;
56
57/** ------------------------------------------------------------------------------------------------------------- *
58 * @brief compileUnicodeSet
59 ** ------------------------------------------------------------------------------------------------------------- */
60size_t compileUnicodeSet(std::string name, const UnicodeSet & set, PabloCompiler & pc, Module * module) {
61    PabloFunction function = PabloFunction::Create(std::move(name), 8, 1);
62    Encoding encoding(Encoding::Type::UTF_8, 8);
63    CC_Compiler ccCompiler(function, encoding);
64    UCDCompiler ucdCompiler(ccCompiler);
65    PabloBuilder builder(function.getEntryBlock());
66    // Build the unicode set function
67    PabloAST * target = ucdCompiler.generateWithDefaultIfHierarchy(set, builder);
68    function.setResult(0, builder.createAssign("matches", target));
69    // Optimize it at the pablo level
70    Simplifier::optimize(function);
71    CodeSinking::optimize(function);
72    #ifdef ENABLE_MULTIPLEXING
73    if (EnableMultiplexing) {
74        AutoMultiplexing::optimize(function);
75        Simplifier::optimize(function);
76    }
77    #endif
78    // Now compile the function ...
79    auto func = pc.compile(function, module);
80    releaseSlabAllocatorMemory();
81
82    return func.second;
83}
84
85/** ------------------------------------------------------------------------------------------------------------- *
86 * @brief writePropertyInstaller
87 ** ------------------------------------------------------------------------------------------------------------- */
88
89void writePrecompiledProperties(property_list && properties) {
90
91    const std::string headerFilename = UCDSourcePath + "/precompiled_properties.h";
92    #ifdef USE_LLVM_3_5
93    std::string error;
94    raw_fd_ostream header(headerFilename.c_str(), error, sys::fs::F_None);
95    if (!error.empty()) {
96        throw std::runtime_error(error);
97    }
98    #else
99    std::error_code error;
100    raw_fd_ostream header(headerFilename, error, sys::fs::F_None);
101    if (error) {
102        throw std::runtime_error(error.message());
103    }
104    #endif
105
106    header << "#ifndef PRECOMPILED_PROPERTIES\n";
107    header << "#define PRECOMPILED_PROPERTIES\n\n";
108    header << "#include <string>\n\n";
109    header << "#include <tuple>\n";
110    header << "namespace UCD {\n\n";
111    header << "using ExternalProperty = std::tuple<void *, unsigned, unsigned, size_t>;\n\n";
112    header << "const ExternalProperty & resolveExternalProperty(const std::string & name);\n\n";
113    header << "}\n\n";
114    header << "#endif\n";
115    header.close();
116
117    const std::string cppFilename = UCDSourcePath + "/precompiled_properties.cpp";
118    #ifdef USE_LLVM_3_5
119    raw_fd_ostream cpp(cppFilename.c_str(), error, sys::fs::F_None);
120    if (!error.empty()) {
121        throw std::runtime_error(error);
122    }
123    #else
124    raw_fd_ostream cpp(cppFilename, error, sys::fs::F_None);
125    if (error) {
126        throw std::runtime_error(error.message());
127    }
128    #endif
129
130    cpp << "#include \"precompiled_properties.h\"\n";
131    cpp << "#include <include/simd-lib/bitblock.hpp>\n";
132    cpp << "#include <stdexcept>\n";
133    cpp << "#include <unordered_map>\n\n";
134    cpp << "namespace UCD {\n\n";
135    cpp << "struct Input {\n    BitBlock bit[8];\n};\n\n";
136    cpp << "struct Output {\n    BitBlock bit[1];\n};\n\n";
137    for (auto prop : properties) {
138        cpp << "extern \"C\" void " + prop.first + "(const Input &, BitBlock *, Output &);\n";
139    }
140
141    cpp << "\nconst static std::unordered_map<std::string, ExternalProperty> ExternalPropertyMap = {\n";
142    for (auto itr = properties.begin(); itr != properties.end(); ) {
143        cpp << "    {\"" + itr->first + "\", std::make_tuple(reinterpret_cast<void *>(&" + itr->first + "), 8, 1, " + std::to_string(itr->second) + ")}";
144        if (++itr != properties.end()) {
145            cpp << ",";
146        }
147        cpp << "\n";
148    }
149    cpp << "};\n\n";
150
151    cpp << "const ExternalProperty & resolveExternalProperty(const std::string & name) {\n";
152    cpp << "    auto f = ExternalPropertyMap.find(name);\n";
153    cpp << "    if (f == ExternalPropertyMap.end())\n";
154    cpp << "        throw std::runtime_error(\"No external property named \\\"\" + name + \"\\\" found!\");\n";
155    cpp << "    return f->second;\n";
156    cpp << "}\n\n}\n";
157
158    cpp.close();
159
160}
161
162
163/** ------------------------------------------------------------------------------------------------------------- *
164 * @brief generateUCDModule
165 ** ------------------------------------------------------------------------------------------------------------- */
166Module * generateUCDModule() {
167
168    property_list properties;
169
170    PabloCompiler pc;
171    Module * module = new Module("ucd", getGlobalContext());
172    for (PropertyObject * obj : property_object_table) {
173        if (EnumeratedPropertyObject * enumObj = dyn_cast<EnumeratedPropertyObject>(obj)) {
174            for (const std::string value : *enumObj) {
175                const UnicodeSet & set = enumObj->GetCodepointSet(canonicalize_value_name(value));
176                std::string name = "__get_" + property_enum_name[enumObj->getPropertyCode()] + "_" + value;
177                properties.emplace_back(name, compileUnicodeSet(name, set, pc, module));
178            }
179        }
180        else if (ExtensionPropertyObject * extObj = dyn_cast<ExtensionPropertyObject>(obj)) {
181            for (const std::string value : *extObj) {
182                const UnicodeSet & set = extObj->GetCodepointSet(canonicalize_value_name(value));
183                std::string name = "__get_" + property_enum_name[extObj->getPropertyCode()] + "_" + value;
184                properties.emplace_back(name, compileUnicodeSet(name, set, pc, module));
185            }
186        }
187        else if (BinaryPropertyObject * binObj = dyn_cast<BinaryPropertyObject>(obj)) {
188            const UnicodeSet & set = binObj->GetCodepointSet(Binary_ns::Y);
189            std::string name = "__get_" + property_enum_name[binObj->getPropertyCode()] + "_Y";
190            properties.emplace_back(name, compileUnicodeSet(name, set, pc, module));
191        }
192    }
193
194    // Print an error message if our module is malformed in any way.
195    verifyModule(*module, &dbgs());
196
197    writePrecompiledProperties(std::move(properties));
198
199    return module;
200}
201
202/** ------------------------------------------------------------------------------------------------------------- *
203 * @brief compileUCDModule
204 ** ------------------------------------------------------------------------------------------------------------- */
205void compileUCDModule(Module * module) {
206    Triple TheTriple;
207
208    // Initialize targets first, so that --version shows registered targets.
209    InitializeAllTargets();
210    InitializeAllTargetMCs();
211    InitializeAllAsmPrinters();
212    InitializeAllAsmParsers();
213
214    TheTriple.setTriple(sys::getDefaultTargetTriple());
215
216    // Get the target specific parser.
217    std::string msg;
218    const Target * TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), msg);
219    if (TheTarget == nullptr) {
220        throw std::runtime_error(msg);
221    }
222
223    TargetOptions Options;
224
225    std::unique_ptr<TargetMachine> Target(
226                TheTarget->createTargetMachine(TheTriple.getTriple(), sys::getHostCPUName(), "", Options,
227                                               Reloc::Default, CodeModel::Small, CodeGenOpt::Aggressive));
228
229    if (Target == nullptr) {
230        throw std::runtime_error("Could not allocate target machine!");
231    }
232
233    #ifdef USE_LLVM_3_5
234    std::string error;
235    std::unique_ptr<tool_output_file> out = make_unique<tool_output_file>(ObjectFilename.c_str(), error, sys::fs::F_None);
236    if (!error.empty()) {
237        throw std::runtime_error(error);
238    }
239    #else
240    std::error_code error;
241    std::unique_ptr<tool_output_file> out = make_unique<tool_output_file>(ObjectFilename, error, sys::fs::F_None);
242    if (error) {
243        throw std::runtime_error(error.message());
244    }
245    #endif
246
247    // Build up all of the passes that we want to do to the module.
248    PassManager PM;
249
250    // Add an appropriate TargetLibraryInfo pass for the module's triple.
251    PM.add(new TargetLibraryInfo(TheTriple));
252
253    // Add the target data from the target machine, if it exists, or the module.
254    #ifdef USE_LLVM_3_5
255    const DataLayout * DL = Target->getDataLayout();
256    #else
257    const DataLayout * DL = Target->getSubtargetImpl()->getDataLayout();
258    #endif
259    if (DL) {
260        module->setDataLayout(DL);
261    }
262    #ifdef USE_LLVM_3_5
263    PM.add(new DataLayoutPass(module));
264    #else
265    PM.add(new DataLayoutPass());
266    #endif
267    PM.add(createReassociatePass());
268    PM.add(createInstructionCombiningPass());
269    PM.add(createSinkingPass());
270
271    formatted_raw_ostream FOS(out->os());
272    // Ask the target to add backend passes as necessary.
273    if (Target->addPassesToEmitFile(PM, FOS, TargetMachine::CGFT_ObjectFile)) {
274        throw std::runtime_error("Target does not support generation of object file type!\n");
275    }
276
277    PM.run(*module);
278
279    out->keep();
280}
281
282/** ------------------------------------------------------------------------------------------------------------- *
283 * @brief main
284 ** ------------------------------------------------------------------------------------------------------------- */
285int main(int argc, char *argv[]) {
286    cl::ParseCommandLineOptions(argc, argv, "UCD Compiler\n");
287    Module * module = generateUCDModule();
288    compileUCDModule(module);
289    return 0;
290}
Note: See TracBrowser for help on using the repository browser.