blob: 8f32066d596052a72f0d21dd5e8e62828d78f90b [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef KUDU_CODEGEN_FUNCTION_BUILDER_H
#define KUDU_CODEGEN_FUNCTION_BUILDER_H
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
#include <llvm/IR/IRBuilder.h>
#include "kudu/gutil/macros.h"
#include "kudu/util/status.h"
namespace llvm {
class ExecutionEngine;
class Function;
class FunctionType;
class LLVMContext;
class Module;
class TargetMachine;
class Type;
class Value;
} // namespace llvm
namespace kudu {
namespace codegen {
// A ModuleBuilder provides an interface to generate code for procedures
// given a CodeGenerator to refer to. Builder can be used to create multiple
// functions. It is intended to make building functions easier than using
// LLVM's IRBuilder<> directly. Finally, a builder also provides an interface
// to precompiled functions and makes sure that the bytecode is linked to
// the working module.
//
// This class is not thread-safe. It is intended to be used by a single
// thread to build a set of functions.
//
// This class is just a helper for other classes within the codegen
// directory. It is intended to be used within *.cc files, and not to be
// included in outward-facing classes so other directories do not have a
// dependency on LLVM (this class is necessary because the templated
// IRBuilder<> cannot be forward-declared since it has default arguments).
// This class, however, can easily be forward-declared.
class ModuleBuilder {
private:
typedef void* FunctionAddress;
public:
// Provide alias so template arguments can be changed in one place
typedef llvm::IRBuilder<> LLVMBuilder;
// Creates a builder with a fresh module and context.
ModuleBuilder();
// Deletes own module and context if they have not been compiled.
~ModuleBuilder();
// Inits a new module with parsed precompiled IR from precompiled.cc.
// TODO: with multiple *.ll files, each file should be loaded on demand
Status Init();
// Create a new, empty function in the module with external linkage
llvm::Function* Create(llvm::FunctionType* fty, const std::string& name);
// Retrieve a precompiled type
llvm::Type* GetType(const std::string& name);
// Retrieve a precompiled function
llvm::Function* GetFunction(const std::string& name);
// Get the LLVM wrapper for a constant pointer value of type i8*
llvm::Value* GetPointerValue(void* ptr) const;
LLVMBuilder* builder() { return &builder_; }
// Once a function is complete, it may be offered to the module builder
// along with the location of the function pointer to be written to
// with the value of the JIT-compiled function pointer. Once the module
// builder's Compile() method is called, these value are filled.
// Requires that llvm::Function belong to this ModuleBuilder's module.
template<class FuncPtr>
void AddJITPromise(llvm::Function* llvm_f, FuncPtr* actual_f) {
// The below cast is technically yields undefined behavior for
// versions of the standard prior to C++0x. However, the llvm
// interface forces us to use object-pointer to function-pointer
// casting.
AddJITPromise(llvm_f, reinterpret_cast<FunctionAddress*>(actual_f));
}
// Compiles all promised functions. Builder may not be used after
// this method, only destructed. Upon success, releases ownership
// of the execution engine through the 'out' parameter.
//
// After this method has been called, the jit-compiled code may be
// called as long as 'out' remains alive. Once 'out' destructs,
// the code will be freed.
Status Compile(std::unique_ptr<llvm::ExecutionEngine>* out);
// Retrieves the TargetMachine that the engine builder guessed was
// the native target. Requires compilation is complete.
// Pointer is valid while Compile()'s ExecutionEngine is.
llvm::TargetMachine* GetTargetMachine() const;
private:
// The different states a ModuleBuilder can be in.
enum MBState {
kUninitialized,
kBuilding,
kCompiled
};
// Basic POD which associates an llvm::Function to the location where its
// function pointer should be written to after compilation.
struct JITFuture {
llvm::Function* llvm_f_;
FunctionAddress* actual_f_;
};
void AddJITPromise(llvm::Function* llvm_f, FunctionAddress* actual_f);
// Returns the function names for the functions stored in the JITFutures.
std::unordered_set<std::string> GetFunctionNames() const;
MBState state_;
std::vector<JITFuture> futures_;
std::unique_ptr<llvm::LLVMContext> context_;
std::unique_ptr<llvm::Module> module_;
LLVMBuilder builder_;
llvm::TargetMachine* target_; // not owned
DISALLOW_COPY_AND_ASSIGN(ModuleBuilder);
};
} // namespace codegen
} // namespace kudu
#endif