| //===-- go-llvm.h - LLVM implementation of gofrontend 'Backend' class -----===// |
| // |
| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Defines Llvm_backend and related classes |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVMGOFRONTEND_GO_LLVM_H |
| #define LLVMGOFRONTEND_GO_LLVM_H |
| |
| // Currently these need to be included before backend.h |
| #include "go-llvm-linemap.h" |
| #include "go-location.h" |
| |
| // Definitions of Btype, Bexpression, and related B* classes. |
| #include "go-llvm-btype.h" |
| #include "go-llvm-bexpression.h" |
| #include "go-llvm-bstatement.h" |
| #include "go-llvm-bfunction.h" |
| #include "go-llvm-bvariable.h" |
| |
| // Other helper classes |
| #include "go-llvm-containertypes.h" |
| #include "go-llvm-tree-integrity.h" |
| #include "go-llvm-typemanager.h" |
| |
| #include "namegen.h" |
| |
| #include "backend.h" |
| |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| namespace llvm { |
| class Argument; |
| class ArrayType; |
| class BasicBlock; |
| class CallInst; |
| class Constant; |
| class ConstantFolder; |
| class DataLayout; |
| class DICompileUnit; |
| class DIFile; |
| class DIScope; |
| class DIBuilder; |
| class Function; |
| class Instruction; |
| class LLVMContext; |
| class Module; |
| class StructType; |
| class TargetLibraryInfo; |
| class Type; |
| class Value; |
| class raw_ostream; |
| } |
| |
| class BuiltinEntry; |
| class BuiltinTable; |
| class BlockLIRBuilder; |
| struct GenCallState; |
| |
| #include "llvm/IR/GlobalValue.h" |
| |
| // |
| // LLVM-specific implementation of the Backend class; the code in |
| // gofrontend instantiates an object of this class and then invokes |
| // the various methods to convert its IR into LLVM IR. Nearly all of |
| // the interesting methods below are virtual. |
| // |
| |
| class Llvm_backend : public Backend, public TypeManager, public NameGen { |
| public: |
| Llvm_backend(llvm::LLVMContext &context, |
| llvm::Module *module, |
| Llvm_linemap *linemap, |
| unsigned addrspace, |
| /* Temporarily set the parameter as optional to workaround the unit tests. */ |
| llvm::CallingConv::ID cconv=llvm::CallingConv::X86_64_SysV); |
| ~Llvm_backend(); |
| |
| // Types. |
| |
| Btype *error_type(); |
| |
| Btype *void_type(); |
| |
| Btype *bool_type(); |
| |
| Btype *integer_type(bool, int); |
| |
| Btype *float_type(int); |
| |
| Btype *complex_type(int); |
| |
| Btype *pointer_type(Btype *); |
| |
| Btype *function_type(const Btyped_identifier &, |
| const std::vector<Btyped_identifier> &, |
| const std::vector<Btyped_identifier> &, Btype *, |
| const Location); |
| |
| Btype *struct_type(const std::vector<Btyped_identifier> &); |
| |
| Btype *array_type(Btype *, Bexpression *); |
| |
| Btype *placeholder_pointer_type(const std::string &, Location, bool); |
| |
| bool set_placeholder_pointer_type(Btype *, Btype *); |
| |
| bool set_placeholder_function_type(Btype *, Btype *); |
| |
| Btype *placeholder_struct_type(const std::string &, Location); |
| |
| bool set_placeholder_struct_type(Btype *placeholder, |
| const std::vector<Btyped_identifier> &); |
| |
| Btype *placeholder_array_type(const std::string &, Location); |
| |
| bool set_placeholder_array_type(Btype *, Btype *, Bexpression *); |
| |
| Btype *named_type(const std::string &, Btype *, Location); |
| |
| Btype *circular_pointer_type(Btype *, bool); |
| |
| bool is_circular_pointer_type(Btype *); |
| |
| int64_t type_size(Btype *); |
| |
| int64_t type_alignment(Btype *); |
| |
| int64_t type_field_alignment(Btype *); |
| |
| int64_t type_field_offset(Btype *, size_t index); |
| |
| // Expressions. |
| |
| Bexpression *zero_expression(Btype *); |
| |
| Bexpression *error_expression(); |
| |
| Bexpression *nil_pointer_expression(); |
| |
| Bexpression *var_expression(Bvariable *var, Location); |
| |
| Bexpression *indirect_expression(Btype *, Bexpression *expr, bool known_valid, |
| Location); |
| |
| Bexpression *named_constant_expression(Btype *btype, const std::string &name, |
| Bexpression *val, Location); |
| |
| Bexpression *integer_constant_expression(Btype *btype, mpz_t val); |
| |
| Bexpression *float_constant_expression(Btype *btype, mpfr_t val); |
| |
| Bexpression *complex_constant_expression(Btype *btype, mpc_t val); |
| |
| Bexpression *string_constant_expression(const std::string &val); |
| |
| Bexpression *boolean_constant_expression(bool val); |
| |
| Bexpression *real_part_expression(Bexpression *bcomplex, Location); |
| |
| Bexpression *imag_part_expression(Bexpression *bcomplex, Location); |
| |
| Bexpression *complex_expression(Bexpression *breal, Bexpression *bimag, |
| Location); |
| |
| Bexpression *convert_expression(Btype *type, Bexpression *expr, Location); |
| |
| Bexpression *function_code_expression(Bfunction *, Location); |
| |
| Bexpression *address_expression(Bexpression *, Location); |
| |
| Bexpression *struct_field_expression(Bexpression *, size_t, Location); |
| |
| Bexpression *compound_expression(Bstatement *, Bexpression *, Location); |
| |
| Bexpression *conditional_expression(Bfunction *, |
| Btype *, Bexpression *, Bexpression *, |
| Bexpression *, Location); |
| |
| Bexpression *unary_expression(Operator, Bexpression *, Location); |
| |
| Bexpression *binary_expression(Operator, Bexpression *, Bexpression *, |
| Location); |
| |
| Bexpression * |
| constructor_expression(Btype *, const std::vector<Bexpression *> &, Location); |
| |
| Bexpression *array_constructor_expression(Btype *, |
| const std::vector<unsigned long> &, |
| const std::vector<Bexpression *> &, |
| Location); |
| |
| Bexpression *pointer_offset_expression(Bexpression *base, Bexpression *offset, |
| Location); |
| |
| Bexpression *array_index_expression(Bexpression *array, Bexpression *index, |
| Location); |
| |
| Bexpression *call_expression(Bfunction *caller, |
| Bexpression *fn, |
| const std::vector<Bexpression *> &args, |
| Bexpression *static_chain, |
| Location); |
| // Statements. |
| |
| Bstatement *error_statement(); |
| |
| Bstatement *expression_statement(Bfunction *, Bexpression *); |
| |
| Bstatement *init_statement(Bfunction*, Bvariable *var, Bexpression *init); |
| |
| Bstatement *assignment_statement(Bfunction*, |
| Bexpression *lhs, Bexpression *rhs, |
| Location); |
| |
| Bstatement *return_statement(Bfunction *, const std::vector<Bexpression *> &, |
| Location); |
| |
| Bstatement *if_statement(Bfunction *func, |
| Bexpression *condition, Bblock *then_block, |
| Bblock *else_block, Location); |
| |
| Bstatement * |
| switch_statement(Bfunction *function, Bexpression *value, |
| const std::vector<std::vector<Bexpression *>> &cases, |
| const std::vector<Bstatement *> &statements, Location); |
| |
| Bstatement *compound_statement(Bstatement *, Bstatement *); |
| |
| Bstatement *statement_list(const std::vector<Bstatement *> &); |
| |
| Bstatement *exception_handler_statement(Bstatement *bstat, |
| Bstatement *except_stmt, |
| Bstatement *finally_stmt, Location); |
| |
| // Blocks. |
| |
| Bblock *block(Bfunction *, Bblock *, const std::vector<Bvariable *> &, |
| Location, Location); |
| |
| void block_add_statements(Bblock *, const std::vector<Bstatement *> &); |
| |
| Bstatement *block_statement(Bblock *); |
| |
| // Variables. |
| |
| Bvariable *error_variable(); |
| |
| Bvariable *global_variable(const std::string &var_name, |
| const std::string &asm_name, Btype *btype, |
| bool is_external, bool is_hidden, |
| bool in_unique_section, Location location); |
| |
| void global_variable_set_init(Bvariable *, Bexpression *); |
| |
| Bvariable *local_variable(Bfunction *, const std::string &, Btype *, |
| Bvariable *, bool, Location); |
| |
| Bvariable *parameter_variable(Bfunction *, const std::string &, Btype *, bool, |
| Location); |
| |
| Bvariable *static_chain_variable(Bfunction *, const std::string &, Btype *, |
| Location); |
| |
| Bvariable *temporary_variable(Bfunction *, Bblock *, Btype *, Bexpression *, |
| bool, Location, Bstatement **); |
| |
| Bvariable *implicit_variable(const std::string &, const std::string &, |
| Btype *, bool, bool, bool, int64_t); |
| |
| void implicit_variable_set_init(Bvariable *, const std::string &, Btype *, |
| bool, bool, bool, Bexpression *); |
| |
| Bvariable *implicit_variable_reference(const std::string &, |
| const std::string &, Btype *); |
| |
| Bvariable *immutable_struct(const std::string &, const std::string &, bool, |
| bool, Btype *, Location); |
| |
| void immutable_struct_set_init(Bvariable *, const std::string &, bool, bool, |
| Btype *, Location, Bexpression *); |
| |
| Bvariable *immutable_struct_reference(const std::string &, |
| const std::string &, Btype *, Location); |
| |
| // Labels. |
| |
| Blabel *label(Bfunction *, const std::string &name, Location); |
| |
| Bstatement *label_definition_statement(Blabel *); |
| |
| Bstatement *goto_statement(Blabel *, Location); |
| |
| Bexpression *label_address(Blabel *, Location); |
| |
| // Functions. |
| |
| Bfunction *error_function(); |
| |
| Bfunction *function(Btype *fntype, const std::string &name, |
| const std::string &asm_name, unsigned flags, |
| Location); |
| |
| Bstatement *function_defer_statement(Bfunction *function, |
| Bexpression *undefer, Bexpression *defer, |
| Location); |
| |
| bool function_set_parameters(Bfunction *function, |
| const std::vector<Bvariable *> &); |
| |
| bool function_set_body(Bfunction *function, Bstatement *code_stmt); |
| |
| Bfunction *lookup_builtin(const std::string &); |
| |
| void write_global_definitions(const std::vector<Btype *> &, |
| const std::vector<Bexpression *> &, |
| const std::vector<Bfunction *> &, |
| const std::vector<Bvariable *> &); |
| |
| void write_export_data(const char *bytes, unsigned int size); |
| |
| Llvm_linemap *linemap() const { return linemap_; } |
| |
| // Module and datalayout |
| llvm::Module &module() { return *module_; } |
| const llvm::DataLayout &datalayout() { return *datalayout_; } |
| |
| // Type manager functionality |
| TypeManager *typeManager() const; |
| |
| // DI build helper. Will be NULL if debug meta-data generation disabled. |
| DIBuildHelper *dibuildhelper() { return dibuildhelper_.get(); } |
| |
| // Support for -fdebug-prefix= |
| void addDebugPrefix(std::pair<llvm::StringRef, llvm::StringRef> prefix); |
| |
| // Bnode builder |
| BnodeBuilder &nodeBuilder() { return nbuilder_; } |
| |
| // Finalize export data for the module. Exposed for unit testing. |
| void finalizeExportData(); |
| |
| // Run the module verifier. |
| void verifyModule(); |
| |
| // Dump LLVM IR for module |
| void dumpModule(); |
| |
| // Dump expression or stmt with line information. For debugging purposes. |
| void dumpExpr(Bexpression *); |
| void dumpStmt(Bstatement *); |
| void dumpVar(Bvariable *); |
| |
| // Exposed for unit testing |
| |
| // Helpers to check tree integrity. Checks to make sure that we |
| // don't have instructions that are parented by more than one |
| // Bexpression or Bstatement, or Bexpressions parented by more than |
| // one expr/stmt. Returns <TRUE,""> if tree is ok, otherwise returns |
| // <FALSE,descriptive_message>. |
| std::pair<bool, std::string> |
| checkTreeIntegrity(Bnode *n, TreeIntegCtl control); |
| |
| // Similar to the above, but prints message to std::cerr and aborts if fail |
| void enforceTreeIntegrity(Bnode *n); |
| |
| // Disable tree integrity checking. This is mainly |
| // so that we can unit test the integrity checker. |
| void disableIntegrityChecks(); |
| |
| // Disable debug meta-data generation. Should be used only during |
| // unit testing, where we're manufacturing IR that might not verify |
| // if meta-data is created. |
| void disableDebugMetaDataGeneration() { createDebugMetaData_ = false; } |
| |
| // Return true if this is a module-scope value such as a constant |
| bool moduleScopeValue(llvm::Value *val, Btype *btype) const; |
| |
| // For debugging |
| void setTraceLevel(unsigned level); |
| unsigned traceLevel() const { return traceLevel_; } |
| |
| // Disable inlining if set to true. |
| void setNoInline(bool b) { noInline_ = b; } |
| |
| // Disable frame pointer elimination if set to true. |
| void setNoFpElim(bool b) { noFpElim_ = b; } |
| |
| // Enable/disable the use of split stacks. |
| void setUseSplitStack(bool b) { useSplitStack_ = b; } |
| |
| // Target CPU and features |
| void setTargetCpuAttr(const std::string &cpu); |
| void setTargetFeaturesAttr(const std::string &attrs); |
| |
| // Set GC strategy |
| void setGCStrategy(std::string s) { gcStrategy_ = s; } |
| |
| // Whether we are compiling the runtime package |
| void setCompilingRuntime() { compilingRuntime_ = true; } |
| |
| // Personality function |
| llvm::Function *personalityFunction(); |
| |
| // Dummy personality function |
| llvm::Function *dummyPersonalityFunction(); |
| |
| // Inform bridge that we may be using AutoFDO. |
| void setEnableAutoFDO() { autoFDO_ = true; } |
| |
| private: |
| Bexpression *errorExpression() const { return errorExpression_; } |
| Bstatement *errorStatement() const { return errorStatement_; } |
| |
| // create a Bfunction for an intrinsic function with specified name |
| Bfunction *createIntrinsicFcn(const std::string &name, |
| llvm::Function *fcn); |
| |
| // create a Bfunction for a predefined builtin function. Used for |
| // libcall builtins and inlined builtins. |
| Bfunction *createBuiltinFcn(BuiltinEntry *be); |
| |
| // Certain Bexpressions we want to cache (constants for example, |
| // or lvalue references to global variables). This helper looks up |
| // the specified expr in a table keyed by <llvm::Value,Btype>. If |
| // the lookup succeeds, the cached value is returned, otherwise the |
| // specified Bexpression is installed in the table and returned. |
| Bexpression *makeGlobalExpression(Bexpression *expr, |
| llvm::Value *val, |
| Btype *btype, |
| Location location); |
| |
| enum ModVarConstant { MV_Constant, MV_NonConstant }; |
| enum ModVarSec { MV_UniqueSection, MV_DefaultSection }; |
| enum ModVarComdat { MV_InComdat, MV_NotInComdat }; |
| enum ModVarExtInit { MV_ExternallyInitialized, MV_NotExternallyInitialized }; |
| enum ModVarGenDebug { MV_GenDebug, MV_SkipDebug }; |
| |
| // Make a module-scope variable (static, global, or external). |
| Bvariable *makeModuleVar(Btype *btype, |
| const std::string &name, |
| const std::string &asm_name, |
| Location location, |
| ModVarConstant constant, |
| ModVarSec inUniqueSection, |
| ModVarComdat inComdat, |
| ModVarExtInit isExtInit, |
| ModVarGenDebug genDebug, |
| llvm::GlobalValue::LinkageTypes linkage, |
| llvm::Constant *initializer, |
| unsigned alignmentInBytes = 0); |
| |
| // Helper for creating a constant-valued array/struct expression. |
| Bexpression *makeConstCompositeExpr(Btype *btype, |
| llvm::Type *llct, |
| unsigned numElements, |
| const std::vector<unsigned long> *indexes, |
| const std::vector<Bexpression *> &vals, |
| Location location); |
| |
| // Helper for creating a non-constant-valued array or struct expression. |
| Bexpression *makeDelayedCompositeExpr(Btype *btype, |
| llvm::Type *llct, |
| unsigned numElements, |
| const std::vector<unsigned long> *idxs, |
| const std::vector<Bexpression *> &vals, |
| Location location); |
| |
| // Helper for creating a complex binary expression. |
| Bexpression *makeComplexBinaryExpr(Operator op, |
| Bexpression *left, |
| Bexpression *right, |
| Location location); |
| |
| // Helper for creating a complex conversion expression. |
| Bexpression *makeComplexConvertExpr(Btype *type, Bexpression *expr, |
| Location location); |
| |
| // Field GEP helper |
| llvm::Value *makeFieldGEP(unsigned fieldIndex, |
| llvm::Value *sptr); |
| |
| // Array indexing GEP helper |
| llvm::Value *makeArrayIndexGEP(llvm::ArrayType *at, |
| llvm::Value *idx, |
| llvm::Value *sptr); |
| |
| // Pointer indexing GEP helper |
| llvm::Value *makePointerOffsetGEP(llvm::PointerType *pt, |
| llvm::Value *idx, |
| llvm::Value *sptr); |
| |
| // Assignment helper |
| Bstatement *makeAssignment(Bfunction *function, llvm::Value *lvalue, |
| Bexpression *lhs, Bexpression *rhs, Location); |
| |
| // Helper to make init statement |
| Bstatement *makeInitStatement(Bfunction *bfunction, Bvariable *var, |
| Bexpression *init); |
| |
| // Helper to make a temporary variable holding the value of an |
| // expression |
| std::pair<Bvariable*, Bstatement*> makeTempVar(Bexpression *expr, |
| Location location); |
| |
| // Helper to set up entry block for function |
| llvm::BasicBlock *genEntryBlock(Bfunction *bfunction); |
| |
| // Helper to fix up epilog block for function (add return if needed) |
| void fixupEpilogBlock(Bfunction *bfunction, llvm::BasicBlock *epilog); |
| |
| // Load-generation helper. |
| // If resultTyp is null, this load is for resolving a pending |
| // var expression, and the result type will be the same type |
| // as space. |
| Bexpression *genLoad(Bexpression *space, |
| Btype *resultTyp, |
| Location loc, |
| const std::string &tag); |
| |
| // Store generation helper. Creates store or memcpy call. |
| Bexpression *genStore(Bfunction *func, |
| Bexpression *srcExpr, |
| Bexpression *dstExpr, |
| Location location); |
| |
| // Lower-level version of the above |
| llvm::Value *genStore(BlockLIRBuilder *builder, |
| Btype *srcType, |
| bool srcConstant, |
| llvm::Type *dstType, |
| llvm::Value *srcValue, |
| llvm::Value *dstLoc); |
| |
| // Returns TRUE if loads/stores to/from the specified type should be |
| // carried out via memcpy as opposed to concrete load/store |
| // instructions. |
| bool useCopyForLoadStore(Btype *typ) { |
| assert(typ); |
| assert(!typ->isPlaceholder()); |
| if (! typ->type()->isAggregateType()) |
| return false; |
| //if (typeSize(typ) <= compositeSizeThreshold_) |
| // return false; |
| return true; |
| } |
| |
| // Similar to above but operates on LLVM type. |
| bool useCopyForLoadStore(llvm::Type *typ) { |
| assert(typ); |
| if (! typ->isAggregateType()) |
| return false; |
| //if (llvmTypeAllocSize(typ) <= compositeSizeThreshold_) |
| // return false; |
| return true; |
| } |
| |
| // Return context disposition based on expression type. |
| // Composite values need to be referred to by address, |
| // whereas non-composite values can be used directly. |
| Varexpr_context varContextDisp(Bexpression *varexp); |
| |
| // Materialize a composite constant into a variable |
| Bvariable *genVarForConstant(llvm::Constant *conval, Btype *type); |
| |
| // Convert a constant to another type. Returns nullptr if the conversion is |
| // not allowed. Intended primarily for aggregate constants, where the two |
| // types are structurally identical but may differ due to the presence |
| // or absence of placeholders. |
| llvm::Constant *genConvertedConstant(llvm::Constant *fromVal, |
| llvm::Type *llToType); |
| |
| // Examine vector of values to test whether they are constants. |
| // Checks for and handles pending composite inits. |
| static bool |
| valuesAreConstant(const std::vector<Bexpression *> &vals); |
| |
| // Array init helper |
| Bexpression *genArrayInit(llvm::ArrayType *llat, |
| Bexpression *expr, |
| llvm::Value *storage); |
| |
| // Struct init helper |
| Bexpression *genStructInit(llvm::StructType *llst, |
| Bexpression *expr, |
| llvm::Value *storage); |
| |
| // Composite init management |
| Bexpression *resolveCompositeInit(Bexpression *expr, |
| llvm::Value *storage); |
| // Var expr management |
| Bexpression *resolveVarContext(Bexpression *expr, |
| Varexpr_context ctx=VE_rvalue); |
| |
| // General-purpose resolver, handles var expr context and |
| // composite init context. |
| Bexpression *resolve(Bexpression *expr, Varexpr_context ctx=VE_rvalue); |
| |
| // Check a vector of Bexpression's to see if any are the |
| // error expression, returning TRUE if so. |
| bool exprVectorHasError(const std::vector<Bexpression *> &vals); |
| |
| // Check a vector of Bstatement's to see if any are the |
| // error statement, returning TRUE if so. |
| bool stmtVectorHasError(const std::vector<Bstatement *> &stmts); |
| |
| // Converts value "src" for assignment to container of type |
| // "dstType" in assignment-like contexts. This helper exists to help |
| // with cases where the frontend is creating an assignment of form |
| // "X = Y" where X and Y's types are considered matching by the |
| // front end, but are non-matching in an LLVM context. For example, |
| // |
| // type Ifi func(int) int |
| // ... |
| // var fp Ifi = myfunctionfoobar |
| // |
| // Here the right hand side will come out as pointer-to-descriptor, |
| // whereas variable "fp" will have type "pointer to functon", which are |
| // not the same. Another example is assignments involving nil, e.g. |
| // |
| // var ip *float32 |
| // ... |
| // ip = nil |
| // |
| // The type of the right hand side of the assignment will be a |
| // generic "*i64" as opposed to "*float32", since the backend |
| // "nil_pointer_expression" does not allow for creation of nil |
| // pointers of specific types. |
| // |
| // Return value will be a new convert Bexpression if a convert is |
| // needed, NULL otherwise. |
| llvm::Value *convertForAssignment(Bexpression *src, |
| llvm::Type *dstToType); |
| // lower-level version of the routine above |
| llvm::Value *convertForAssignment(Btype *srcType, |
| llvm::Value *srcVal, |
| llvm::Type *dstToType, |
| BlockLIRBuilder *builder); |
| |
| |
| // Apply type conversion for a binary operation. This helper exists |
| // to resolve situations where expressions are created by the front |
| // end have incomplete or "polymorphic" type. A good example is pointer |
| // comparison with nil, e.g. |
| // |
| // var ip *A = foobar() |
| // if ip == nil { ... |
| // |
| // The type of the right hand side of the '==' above will be a generic |
| // "*i64" as opposed to "*A", since the backend "nil_pointer_expression" |
| // does not allow for creation of nil pointers of specific types. |
| // |
| // Input expressions 'left' and 'right' correspond to the original |
| // uncoerced expressions; if conversions are needed, any additional |
| // instructions will be added to the args and the resulting LLVM |
| // values will be returned. |
| std::pair<llvm::Value *, llvm::Value *> |
| convertForBinary(Operator op, Bexpression *left, Bexpression *right); |
| |
| // Generate a conversion induced by the use of a circular pointer type. |
| Bexpression *genCircularConversion(Btype *toType, Bexpression *expr, |
| Location loc); |
| |
| // Helpers for call sequence generation. |
| void genCallProlog(GenCallState &state); |
| void genCallAttributes(GenCallState &state, llvm::CallInst *call); |
| void genCallMarshallArgs(const std::vector<Bexpression *> &fn_args, |
| GenCallState &state); |
| void genCallEpilog(GenCallState &state, llvm::Instruction *callInst, |
| Bexpression *callExpr); |
| |
| // Store the value in question to a temporary, returning the alloca |
| // for the temp. |
| llvm::Instruction *storeToTemporary(Bfunction *func, llvm::Value *val); |
| |
| // Generate a "late" type conversion (e.g. during materialization, |
| // hence no delayed value creation). |
| Bexpression *lateConvert(Btype *type, Bexpression *expr, Location); |
| |
| // Manufacture a floating point constant corresponding to -0.0 |
| Bexpression *minusZeroExpr(BFloatType *typ); |
| |
| // Create integer constant 1 (for use with type creation) |
| Bexpression *makeIntegerOneExpr(); |
| |
| public: |
| |
| // Performs a bottom-up walk to materialize LLVM values for each |
| // node in the expression tree. Made public for unit testing. |
| Bexpression *materialize(Bexpression *expr, |
| Varexpr_context lvalueContext=VE_rvalue); |
| |
| // Helper routines to materialize llvm::Value's for expression nodes, |
| // invoked by routine above. Public primarily because we need to call |
| // them from MaterializeVisitor (could be privatized if the materializer |
| // was added as a friend). |
| Bexpression *materializeIndirect(Bexpression *indExpr, bool isLHS); |
| Bexpression *materializeAddress(Bexpression *addrExpr); |
| Bexpression *materializeConversion(Bexpression *convExpr); |
| Bexpression *materializeStructField(Bexpression *fieldExpr); |
| Bexpression *materializeConditional(Bexpression *condExpr); |
| Bexpression *materializeUnary(Bexpression *unaryExpr); |
| Bexpression *materializeBinary(Bexpression *binExpr); |
| Bexpression *materializeConstructor(Bexpression *conExpr); |
| Bexpression *materializeComposite(Bexpression *comExpr); |
| Bexpression *materializeCompound(Bexpression *comExpr); |
| Bexpression *materializePointerOffset(Bexpression *ptroffExpr); |
| Bexpression *materializeArrayIndex(Bexpression *arindExpr); |
| Bexpression *materializeCall(Bexpression *callExpr); |
| |
| private: |
| typedef std::pair<llvm::Value *, Btype *> valbtype; |
| typedef pairvalmap<llvm::Value *, Btype *, Bexpression *> |
| btyped_value_expr_maptyp; |
| |
| // Context information needed for the LLVM backend. |
| llvm::LLVMContext &context_; |
| |
| // The LLVM module we're emitting IR into. If client did not supply |
| // a module during construction, then ownModule_ is filled in. |
| llvm::Module *module_; |
| std::unique_ptr<llvm::Module> ownModule_; |
| |
| // Data layout info from the module. |
| const llvm::DataLayout *datalayout_; |
| |
| // Builder for constructing Bexpressions and Bstatements. |
| BnodeBuilder nbuilder_; |
| |
| // Debug info builder. |
| std::unique_ptr<DIBuildHelper> dibuildhelper_; |
| |
| // Linemap to use. If client did not supply a linemap during |
| // construction, then ownLinemap_ is filled in. |
| Llvm_linemap *linemap_; |
| std::unique_ptr<Llvm_linemap> ownLinemap_; |
| |
| // Address space designator for pointer types. |
| unsigned addressSpace_; |
| |
| // Debug trace level |
| unsigned traceLevel_; |
| |
| // Whether to disable inlining. |
| bool noInline_; |
| |
| // Whether to disable frame pointer elimination. |
| bool noFpElim_; |
| |
| // Whether to use split stacks. |
| bool useSplitStack_; |
| |
| // Whether we are compiling the runtime. |
| bool compilingRuntime_; |
| |
| // Whether to check for unexpected node sharing (e.g. same Bexpression |
| // or statement pointed to by multiple parents). |
| bool checkIntegrity_; |
| |
| // Whether to create debug meta data. On by default, can be |
| // disabled for unit testing. |
| bool createDebugMetaData_; |
| |
| // Whether we've started / finalized export data for the module. |
| bool exportDataStarted_; |
| bool exportDataFinalized_; |
| |
| // This counter gets incremented when the FE requests an error |
| // object (error variable, error type, etc). We check to see whether |
| // it is non-zero before walking function bodies to emit debug |
| // meta-data (the idea being that there is no point going through |
| // that process if there were errors). |
| unsigned errorCount_; |
| |
| // Composite value load/store size threshold. Tells the bridge |
| // that for any composite value whose size in bytes is greater than X, |
| // emit memcpy operations for loads and stores as opposed to |
| // emitting direct load/store instructions. |
| unsigned compositeSizeThreshold_; |
| |
| // Target library info oracle |
| llvm::TargetLibraryInfo *TLI_; |
| |
| // maps name to entry storing info on builtin function |
| std::unique_ptr<BuiltinTable> builtinTable_; |
| |
| // Error function |
| std::unique_ptr<Bfunction> errorFunction_; |
| |
| // Error expression |
| Bexpression *errorExpression_; |
| |
| // Error statement |
| Bstatement *errorStatement_; |
| |
| // Error variable |
| std::unique_ptr<Bvariable> errorVariable_; |
| |
| // Map from LLVM-value/Btype pair to Bexpression. This is |
| // used to cache + reuse things like global constants. |
| btyped_value_expr_maptyp valueExprmap_; |
| |
| // Map from LLVM values to Bvariable. This is used for |
| // module-scope variables, not vars local to a function. |
| std::unordered_map<llvm::Value *, Bvariable *> valueVarMap_; |
| |
| // This is used to cache compiler-constructed vars to capture |
| // constant values (created in genVarForConstant). |
| std::unordered_map<llvm::Value *, Bvariable *> genVarConstMap_; |
| |
| // This table is a cache for converted constants; key is a pair |
| // [FromVal,ToType] and value is a constant value equivalent |
| // to FromVal but converted to ToType. |
| pairvalmap<llvm::Constant *, llvm::Type *, llvm::Constant *> genConvConstMap_; |
| |
| // Table for commoning strings by value. String constants have |
| // concrete types like "[5 x i8]", whereas we would like to return |
| // things that have type "i8*". To manage this, we eagerly create |
| // module-scope vars with strings, but this tends to defeat the |
| // caching mechanisms, so here we have a map from constant string |
| // value to Bexpression holding that string const. |
| std::unordered_map<llvm::Value *, Bexpression*> stringConstantMap_; |
| |
| // For caching of immutable struct references. Similar situation here |
| // as above, in that we can't look for such things in valueVarMap_ |
| // without creating what it is we're looking for. |
| std::unordered_map<std::string, Bvariable *> immutableStructRefs_; |
| |
| typedef std::pair<BFunctionType *, std::string> fcnNameAndType; |
| typedef pairvalmap<BFunctionType *, std::string, Bfunction*> fcnDeclMapTyp; |
| |
| // This maps from <name, type> pairs to Bfunction object; it is used |
| // to cache declarations of external functions (for example, |
| // well-known functions in the runtime). Only declarations will be |
| // placed in this map-- if a function is being defined, it will only |
| // be added to the functions_ list below. |
| fcnDeclMapTyp fcnDeclMap_; |
| |
| // Currently we don't do any commoning of Bfunction objects created |
| // by the frontend, so here we keep track of all returned Bfunctions |
| // so that we can free them on exit. |
| std::vector<Bfunction *> functions_; |
| |
| // Personality function |
| llvm::Function *personalityFunction_; |
| llvm::Function *dummyPersonalityFunction_; |
| |
| // Target cpu and attributes to be attached to any generated fcns. |
| std::string targetCpuAttr_; |
| std::string targetFeaturesAttr_; |
| |
| // GC strategy |
| std::string gcStrategy_; |
| |
| // Prepare for use of AutoFDO. |
| bool autoFDO_; |
| }; |
| |
| #endif |