| //===-- go-llvm.h - LLVM implementation of gofrontend 'Btype' 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_BTYPE_H |
| #define LLVMGOFRONTEND_GO_LLVM_BTYPE_H |
| |
| // Currently these need to be included before backend.h |
| #include "go-linemap.h" |
| #include "go-location.h" |
| #include "go-llvm-btype.h" |
| |
| #include "backend.h" |
| |
| namespace llvm { |
| class Type; |
| class Value; |
| class raw_ostream; |
| class DISubroutineType; |
| } |
| |
| class BStructType; |
| class BArrayType; |
| class BPointerType; |
| class BIntegerType; |
| class BComplexType; |
| class BFloatType; |
| class BFunctionType; |
| |
| // Btype wraps llvm::Type |
| |
| class Btype { |
| public: |
| enum TyFlavor { |
| ArrayT, ComplexT, FloatT, FunctionT, IntegerT, PointerT, StructT, AuxT |
| }; |
| Btype(TyFlavor flavor, llvm::Type *type, Location location) |
| : type_(type), location_(location), flavor_(flavor), |
| isPlaceholder_(false) { } |
| virtual ~Btype() { } |
| |
| TyFlavor flavor() const { return flavor_; } |
| Location location() const { return location_; } |
| void setLocation(Location loc) { location_ = loc; } |
| |
| // Underlying LLVM type. |
| llvm::Type *type() const { return type_; } |
| void setType(llvm::Type *t) { assert(t); type_ = t; } |
| |
| // Name of type if named. |
| const std::string &name() const { return name_; } |
| void setName(const std::string &name) { name_ = name; } |
| |
| // Whether this type is a placeholder. This can be set for type |
| // explicitly created as placeholders (for example, something |
| // returned from ::placeholder_pointer_type()) or it can be set in |
| // cases where a primary type creation call is made by some sub-type |
| // is a placeholder (for example, invoking ::pointer_type() with an |
| // element type that is still a placeholder). |
| bool isPlaceholder() const { return isPlaceholder_; } |
| void setPlaceholder(bool v) { isPlaceholder_ = v; } |
| |
| // Similar to the above, but returns true for placeholder |
| // struct types. |
| bool isUnresolvedPlaceholder() const; |
| |
| // Create a shallow copy of this type |
| Btype *clone() const; |
| |
| // debugging |
| void dump() const; |
| |
| // dump to raw ostream buffer |
| void osdump(llvm::raw_ostream &os, unsigned ilevel) const; |
| |
| // test for exact equality (including type names) |
| bool equal(const Btype &other) const; |
| |
| // test for structural equality (ignores type names) |
| bool equivalent(const Btype &other) const; |
| |
| // hash |
| unsigned hash() const; |
| |
| // Cast to derived class (these return NULL if the type |
| // does not have the appropriate flavor). |
| inline BStructType *castToBStructType(); |
| inline BArrayType *castToBArrayType(); |
| inline BPointerType *castToBPointerType(); |
| inline BIntegerType *castToBIntegerType(); |
| inline BComplexType *castToBComplexType(); |
| inline BFloatType *castToBFloatType(); |
| inline BFunctionType *castToBFunctionType(); |
| inline const BStructType *castToBStructType() const; |
| inline const BArrayType *castToBArrayType() const; |
| inline const BPointerType *castToBPointerType() const; |
| inline const BIntegerType *castToBIntegerType() const; |
| inline const BComplexType *castToBComplexType() const; |
| inline const BFloatType *castToBFloatType() const; |
| inline const BFunctionType *castToBFunctionType() const; |
| |
| private: |
| enum CompareCtl { Default=0, IgnoreNames=1 }; |
| bool equalImpl(const Btype &other, CompareCtl ctl) const; |
| Btype() : type_(NULL) {} |
| std::string name_; |
| llvm::Type *type_; |
| Location location_; |
| TyFlavor flavor_; |
| bool isPlaceholder_; |
| }; |
| |
| class BIntegerType : public Btype { |
| public: |
| BIntegerType(bool isUnsigned, unsigned bits, |
| llvm::Type *type, Location location) |
| : Btype(IntegerT, type, location), |
| bits_(bits), isUnsigned_(isUnsigned) { } |
| |
| bool isUnsigned() const { return isUnsigned_; } |
| unsigned bits() const { return bits_; } |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BIntegerType(isUnsigned_, bits_, type(), location()); |
| } |
| |
| private: |
| unsigned bits_; |
| bool isUnsigned_; |
| }; |
| |
| inline BIntegerType *Btype::castToBIntegerType() { |
| return (flavor_ == IntegerT ? static_cast<BIntegerType *>(this) |
| : nullptr); |
| } |
| |
| inline const BIntegerType *Btype::castToBIntegerType() const { |
| return (flavor_ == IntegerT ? static_cast<const BIntegerType *>(this) |
| : nullptr); |
| } |
| |
| class BComplexType : public Btype { |
| public: |
| BComplexType(unsigned bits, llvm::Type *type, Location location) |
| : Btype(ComplexT, type, location), bits_(bits) { } |
| |
| // Here 'bits' is for the entire object, not for each sub-part |
| unsigned bits() const { return bits_; } |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BComplexType(bits_, type(), location()); |
| } |
| |
| private: |
| unsigned bits_; |
| }; |
| |
| inline BComplexType *Btype::castToBComplexType() { |
| return (flavor_ == ComplexT ? static_cast<BComplexType *>(this) |
| : nullptr); |
| } |
| |
| inline const BComplexType *Btype::castToBComplexType() const { |
| return (flavor_ == ComplexT ? static_cast<const BComplexType *>(this) |
| : nullptr); |
| } |
| |
| class BFloatType : public Btype { |
| public: |
| BFloatType(unsigned bits, llvm::Type *type, Location location) |
| : Btype(FloatT, type, location), bits_(bits) { } |
| |
| unsigned bits() const { return bits_; } |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BFloatType(bits_, type(), location()); |
| } |
| |
| private: |
| unsigned bits_; |
| }; |
| |
| inline BFloatType *Btype::castToBFloatType() { |
| return (flavor_ == FloatT ? static_cast<BFloatType *>(this) |
| : nullptr); |
| } |
| |
| inline const BFloatType *Btype::castToBFloatType() const { |
| return (flavor_ == FloatT ? static_cast<const BFloatType *>(this) |
| : nullptr); |
| } |
| |
| class BStructType : public Btype { |
| public: |
| |
| // For concrete struct types |
| BStructType(const std::vector<Backend::Btyped_identifier> &fields, |
| llvm::Type *type, Location location) |
| : Btype(StructT, type, location), fields_(fields) { } |
| |
| // For placeholder struct types |
| BStructType(const std::string &name, Location location) |
| : Btype(StructT, nullptr, location) |
| { |
| setPlaceholder(true); |
| setName(name); |
| } |
| |
| Btype *fieldType(unsigned idx) const { |
| return fields_[idx].btype; |
| } |
| void setFieldType(unsigned idx, Btype *t) { |
| assert(t); |
| fields_[idx].btype = t; |
| } |
| const std::string &fieldName(unsigned idx) const { |
| return fields_[idx].name; |
| } |
| const std::vector<Backend::Btyped_identifier> &fields() const { |
| return fields_; |
| } |
| void setFields(const std::vector<Backend::Btyped_identifier> &fields) { |
| fields_ = fields; |
| } |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BStructType(fields_, type(), location()); |
| } |
| |
| private: |
| std::vector<Backend::Btyped_identifier> fields_; |
| }; |
| |
| inline BStructType *Btype::castToBStructType() { |
| return (flavor_ == StructT ? static_cast<BStructType *>(this) |
| : nullptr); |
| } |
| |
| inline const BStructType *Btype::castToBStructType() const { |
| return (flavor_ == StructT ? static_cast<const BStructType *>(this) |
| : nullptr); |
| } |
| |
| class BArrayType : public Btype { |
| public: |
| // For concrete array types |
| BArrayType(Btype *elemType, Bexpression *nelements, |
| llvm::Type *type, Location location) |
| : Btype(ArrayT, type, location), |
| elemType_(elemType), nelements_(nelements) |
| { |
| if (elemType_->isPlaceholder()) |
| setPlaceholder(true); |
| } |
| |
| // For placeholder array types |
| BArrayType(const std::string &name, Location location) |
| : Btype(ArrayT, nullptr, location), |
| elemType_(nullptr), nelements_(nullptr) |
| { |
| setPlaceholder(true); |
| setName(name); |
| } |
| |
| Btype *elemType() const { |
| return elemType_; |
| } |
| void setElemType(Btype *t) { |
| assert(t); |
| elemType_ = t; |
| if (elemType_->isPlaceholder()) |
| setPlaceholder(true); |
| } |
| Bexpression *nelements() const { |
| return nelements_; |
| } |
| void setNelements(Bexpression *nel) { nelements_ = nel; } |
| uint64_t nelSize() const; |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BArrayType(elemType_, nelements_, type(), location()); |
| } |
| |
| private: |
| Btype *elemType_; |
| Bexpression *nelements_; |
| }; |
| |
| inline BArrayType *Btype::castToBArrayType() { |
| return (flavor_ == ArrayT ? static_cast<BArrayType *>(this) |
| : nullptr); |
| } |
| |
| inline const BArrayType *Btype::castToBArrayType() const { |
| return (flavor_ == ArrayT ? static_cast<const BArrayType *>(this) |
| : nullptr); |
| } |
| |
| class BPointerType : public Btype { |
| public: |
| // For concrete pointer types |
| BPointerType(Btype *toType, llvm::Type *type, Location location) |
| : Btype(PointerT, type, location), toType_(toType) { |
| if (toType_->isPlaceholder()) |
| setPlaceholder(true); |
| } |
| |
| // For placeholder pointers |
| BPointerType(const std::string &name, Location location) |
| : Btype(PointerT, nullptr, location), toType_(nullptr) { |
| setPlaceholder(true); |
| setName(name); |
| } |
| |
| Btype *toType() const { |
| return toType_; |
| } |
| void setToType(Btype *to) { |
| toType_ = to; |
| } |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BPointerType(toType_, type(), location()); |
| } |
| |
| private: |
| Btype *toType_; |
| }; |
| |
| inline BPointerType *Btype::castToBPointerType() { |
| return (flavor_ == PointerT ? static_cast<BPointerType *>(this) |
| : nullptr); |
| } |
| |
| inline const BPointerType *Btype::castToBPointerType() const { |
| return (flavor_ == PointerT ? static_cast<const BPointerType *>(this) |
| : nullptr); |
| } |
| |
| class BFunctionType : public Btype { |
| public: |
| BFunctionType(Btype *receiverType, |
| const std::vector<Btype *> ¶mTypes, |
| const std::vector<Btype *> &resultTypes, |
| Btype *rtype, |
| llvm::Type *type, |
| bool followsCabi, |
| Location location) |
| : Btype(FunctionT, type, location), receiverType_(receiverType), |
| paramTypes_(paramTypes), resultTypes_(resultTypes), |
| rtype_(rtype), followsCabi_(followsCabi) { |
| assert(!receiverType || paramTypes[0] == receiverType); |
| } |
| |
| Btype *resultType() const { return rtype_; } |
| Btype *receiverType() const { return receiverType_; } |
| |
| // Does this function type follow ABI rules? |
| bool followsCabi() const { return followsCabi_; } |
| |
| // Note that if the receiver type is non-null, it will |
| // occupy the first slot in paramTypes. |
| const std::vector<Btype *> ¶mTypes() const { return paramTypes_; } |
| |
| // Create a shallow copy of this type |
| Btype *clone() const { |
| return new BFunctionType(receiverType_, paramTypes_, resultTypes_, rtype_, |
| type(), followsCabi(), location()); |
| } |
| |
| private: |
| Btype *receiverType_; |
| std::vector<Btype *> paramTypes_; |
| std::vector<Btype *> resultTypes_; |
| Btype *rtype_; |
| bool followsCabi_; |
| }; |
| |
| inline BFunctionType *Btype::castToBFunctionType() { |
| return (flavor_ == FunctionT ? static_cast<BFunctionType *>(this) |
| : nullptr); |
| } |
| inline const BFunctionType *Btype::castToBFunctionType() const { |
| return (flavor_ == FunctionT ? static_cast<const BFunctionType *>(this) |
| : nullptr); |
| } |
| |
| #endif // LLVMGOFRONTEND_GO_LLVM_BTYPE_H |