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

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

Force UnsupportedPropertyObject? kind to be UnsupportedProperty?.

File size: 7.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>
51OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
52
53#ifdef ENABLE_MULTIPLEXING
54static cl::opt<bool> EnableMultiplexing("multiplexing", cl::init(false),
55                                        cl::desc("combine Advances whose inputs are mutual exclusive into the fewest number of advances possible (expensive)."));
56#endif
57
58/** ------------------------------------------------------------------------------------------------------------- *
59 * @brief compileUnicodeSet
60 ** ------------------------------------------------------------------------------------------------------------- */
61void compileUnicodeSet(std::string name, const UnicodeSet & set, PabloCompiler & pc, Module * module) {
62    PabloFunction function = PabloFunction::Create(std::move(name));
63    Encoding encoding(Encoding::Type::UTF_8, 8);
64    CC_Compiler ccCompiler(function, encoding);
65    UCDCompiler ucdCompiler(ccCompiler);
66    PabloBuilder builder(function.getEntryBlock());
67
68    std::cerr << "Compiling " << name << std::endl;
69
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    pc.compile(function, module);
82    releaseSlabAllocatorMemory();
83}
84
85/** ------------------------------------------------------------------------------------------------------------- *
86 * @brief generateUCDModule
87 ** ------------------------------------------------------------------------------------------------------------- */
88Module * generateUCDModule() {
89    PabloCompiler pc;
90    Module * module = new Module("ucd", getGlobalContext());
91    for (PropertyObject * obj : property_object_table) {
92
93        if (EnumeratedPropertyObject * enumObj = dyn_cast<EnumeratedPropertyObject>(obj)) {
94            for (const std::string value : *enumObj) {
95                const UnicodeSet & set = enumObj->GetCodepointSet(canonicalize_value_name(value));
96                std::string name = "__get_" + property_enum_name[enumObj->getPropertyCode()] + "_" + value;
97                compileUnicodeSet(name, set, pc, module);
98            }
99        }
100        else if (ExtensionPropertyObject * extObj = dyn_cast<ExtensionPropertyObject>(obj)) {
101            for (const std::string value : *extObj) {
102                const UnicodeSet & set = extObj->GetCodepointSet(canonicalize_value_name(value));
103                std::string name = "__get_" + property_enum_name[extObj->getPropertyCode()] + "_" + value;
104                compileUnicodeSet(name, set, pc, module);
105            }
106        }
107        else if (BinaryPropertyObject * binObj = dyn_cast<BinaryPropertyObject>(obj)) {
108            const UnicodeSet & set = binObj->GetCodepointSet(Binary_ns::Y);
109            std::string name = "__get_" + property_enum_name[binObj->getPropertyCode()] + "_Y";
110            compileUnicodeSet(name, set, pc, module);
111        }
112
113    }
114
115    // Print an error message if our module is malformed in any way.
116    verifyModule(*module, &dbgs());
117
118    return module;
119}
120
121/** ------------------------------------------------------------------------------------------------------------- *
122 * @brief compileUCDModule
123 ** ------------------------------------------------------------------------------------------------------------- */
124void compileUCDModule(Module * module) {
125    Triple TheTriple;
126
127    // Initialize targets first, so that --version shows registered targets.
128    InitializeAllTargets();
129    InitializeAllTargetMCs();
130    InitializeAllAsmPrinters();
131    InitializeAllAsmParsers();
132
133
134    TheTriple.setTriple(sys::getDefaultTargetTriple());
135
136    // Get the target specific parser.
137    std::string msg;
138    const Target * TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), msg);
139
140    if (TheTarget == nullptr) {
141        throw std::runtime_error(msg);
142    }
143
144    auto MCPU = llvm::sys::getHostCPUName();
145
146    TargetOptions Options;
147
148    std::unique_ptr<TargetMachine> Target(
149                TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, "", Options,
150                                               Reloc::Default, CodeModel::Small, CodeGenOpt::Aggressive));
151
152    if (Target == nullptr) {
153        throw std::runtime_error("Could not allocate target machine!");
154    }
155
156    if (OutputFilename.empty()) {
157        OutputFilename = "ucd.o";
158    }
159
160    #ifdef USE_LLVM_3_5
161    std::string error;
162    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(OutputFilename.c_str(), error, sys::fs::F_None);
163    if (!error.empty()) {
164        throw std::runtime_error(error);
165    }
166    #else
167    std::error_code error;
168    std::unique_ptr<tool_output_file> Out = make_unique<tool_output_file>(OutputFilename, error, sys::fs::F_None);
169    if (error) {
170        throw std::runtime_error(error.message());
171    }
172    #endif
173
174    // Build up all of the passes that we want to do to the module.
175    PassManager PM;
176
177    // Add an appropriate TargetLibraryInfo pass for the module's triple.
178    TargetLibraryInfo * TLI = new TargetLibraryInfo(TheTriple);
179
180    PM.add(TLI);
181
182    // Add the target data from the target machine, if it exists, or the module.
183    #ifdef USE_LLVM_3_5
184    const DataLayout * DL = Target->getDataLayout();
185    #else
186    const DataLayout * DL = Target->getSubtargetImpl()->getDataLayout();
187    #endif
188    if (DL) {
189        module->setDataLayout(DL);
190    }
191    PM.add(new DataLayoutPass());
192    PM.add(createReassociatePass());
193    PM.add(createInstructionCombiningPass());
194    PM.add(createSinkingPass());
195
196    formatted_raw_ostream FOS(Out->os());
197    // Ask the target to add backend passes as necessary.
198    if (Target->addPassesToEmitFile(PM, FOS, TargetMachine::CGFT_ObjectFile)) {
199        throw std::runtime_error("Target does not support generation of this file type!\n");
200    }
201
202    PM.run(*module);
203
204    Out->keep();
205}
206
207/** ------------------------------------------------------------------------------------------------------------- *
208 * @brief main
209 ** ------------------------------------------------------------------------------------------------------------- */
210int main(int argc, char *argv[]) {
211    cl::ParseCommandLineOptions(argc, argv, "UCD Compiler\n");
212    Module * module = generateUCDModule();
213    compileUCDModule(module);
214    return 0;
215}
Note: See TracBrowser for help on using the repository browser.