blob: 778d39a8f193ab325536462abd2a4ccf10338ce8 [file] [log] [blame]
//===-- 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 *> &paramTypes,
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 *> &paramTypes() 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