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
RevLine 
[4657]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
[4661]7#include <cc/cc_compiler.h>
[4657]8#include <UCD/unicode_set.h>
[4661]9#include <UCD/PropertyObjectTable.h>
[4657]10#include <UCD/ucd_compiler.hpp>
11#include <pablo/pablo_compiler.h>
[4661]12#include <pablo/builder.hpp>
[4657]13#include <pablo/function.h>
14#include <llvm/Support/CommandLine.h>
[4661]15#include <utf_encoding.h>
16#include <pablo/optimizers/pablo_simplifier.hpp>
17#include <pablo/optimizers/pablo_codesinking.hpp>
[4665]18#ifdef ENABLE_MULTIPLEXING
[4661]19#include <pablo/optimizers/pablo_automultiplexing.hpp>
[4665]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"
[4666]36#include <llvm/Transforms/Scalar.h>
[4661]37#include <boost/algorithm/string/case_conv.hpp>
38#include <iostream>
39
[4657]40using namespace pablo;
[4661]41using namespace UCD;
42using namespace cc;
[4665]43using namespace llvm;
[4657]44
[4661]45inline std::string lowercase(const std::string & name) {
46    std::locale loc;
47    return boost::algorithm::to_lower_copy(name, loc);
48}
[4657]49
[4665]50static cl::opt<std::string>
[4668]51ObjectFilename("o", cl::desc("Output Object filename"), cl::value_desc("filename"));
[4657]52
[4668]53static cl::opt<std::string>
54PropertyFilename("p", cl::desc("Install Property filename"), cl::value_desc("filename"));
55
[4667]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
[4665]61/** ------------------------------------------------------------------------------------------------------------- *
62 * @brief compileUnicodeSet
63 ** ------------------------------------------------------------------------------------------------------------- */
[4668]64void compileUnicodeSet(std::string name, const UnicodeSet & set, PabloCompiler & pc, Module * module, raw_ostream & out) {
[4661]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);
[4665]75    #ifdef ENABLE_MULTIPLEXING
[4667]76    if (EnableMultiplexing) {
77        AutoMultiplexing::optimize(function);
78    }
[4665]79    #endif
[4661]80    // Now compile the function ...
[4668]81    auto func = pc.compile(function, module);
82    out << "    p.InstallExternalFunction(\"" + name + "\", &" + name + ", " + std::to_string(func.second) + ");\n";
[4665]83    releaseSlabAllocatorMemory();
[4661]84}
[4657]85
[4665]86/** ------------------------------------------------------------------------------------------------------------- *
87 * @brief generateUCDModule
88 ** ------------------------------------------------------------------------------------------------------------- */
89Module * generateUCDModule() {
[4668]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
[4661]110    PabloCompiler pc;
[4665]111    Module * module = new Module("ucd", getGlobalContext());
[4661]112    for (PropertyObject * obj : property_object_table) {
[4667]113        if (EnumeratedPropertyObject * enumObj = dyn_cast<EnumeratedPropertyObject>(obj)) {
[4661]114            for (const std::string value : *enumObj) {
115                const UnicodeSet & set = enumObj->GetCodepointSet(canonicalize_value_name(value));
[4667]116                std::string name = "__get_" + property_enum_name[enumObj->getPropertyCode()] + "_" + value;
[4668]117                compileUnicodeSet(name, set, pc, module, out);
[4661]118            }
119        }
[4667]120        else if (ExtensionPropertyObject * extObj = dyn_cast<ExtensionPropertyObject>(obj)) {
[4665]121            for (const std::string value : *extObj) {
122                const UnicodeSet & set = extObj->GetCodepointSet(canonicalize_value_name(value));
[4667]123                std::string name = "__get_" + property_enum_name[extObj->getPropertyCode()] + "_" + value;
[4668]124                compileUnicodeSet(name, set, pc, module, out);
[4665]125            }
126        }
[4667]127        else if (BinaryPropertyObject * binObj = dyn_cast<BinaryPropertyObject>(obj)) {
[4665]128            const UnicodeSet & set = binObj->GetCodepointSet(Binary_ns::Y);
[4667]129            std::string name = "__get_" + property_enum_name[binObj->getPropertyCode()] + "_Y";
[4668]130            compileUnicodeSet(name, set, pc, module, out);
[4665]131        }
132    }
[4657]133
[4668]134    out << "}\n\n#endif\n"; out.close();
135
[4665]136    // Print an error message if our module is malformed in any way.
137    verifyModule(*module, &dbgs());
[4657]138
[4665]139    return module;
140}
141
142/** ------------------------------------------------------------------------------------------------------------- *
143 * @brief compileUCDModule
144 ** ------------------------------------------------------------------------------------------------------------- */
145void compileUCDModule(Module * module) {
146    Triple TheTriple;
147
[4666]148    // Initialize targets first, so that --version shows registered targets.
149    InitializeAllTargets();
150    InitializeAllTargetMCs();
151    InitializeAllAsmPrinters();
152    InitializeAllAsmParsers();
[4661]153
[4666]154    TheTriple.setTriple(sys::getDefaultTargetTriple());
155
[4665]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;
[4669]177    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(ObjectFilename.c_str(), error, sys::fs::F_None);
[4665]178    if (!error.empty()) {
179        throw std::runtime_error(error);
180    }
181    #else
182    std::error_code error;
[4668]183    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(ObjectFilename, error, sys::fs::F_None);
[4665]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.
[4669]193    PM.add(new TargetLibraryInfo(TheTriple));
[4665]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    }
[4669]204    #ifdef USE_LLVM_3_5
205    PM.add(new DataLayoutPass(module));
206    #else
[4665]207    PM.add(new DataLayoutPass());
[4669]208    #endif
[4666]209    PM.add(createReassociatePass());
210    PM.add(createInstructionCombiningPass());
211    PM.add(createSinkingPass());
[4665]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");
[4668]229    if (PropertyFilename.empty()) {
230        PropertyFilename = "PropertyInstall.h";
231    }
232    if (ObjectFilename.empty()) {
233        ObjectFilename = "ucd.o";
234    }
[4665]235    Module * module = generateUCDModule();
236    compileUCDModule(module);
[4661]237    return 0;
[4657]238}
Note: See TracBrowser for help on using the repository browser.