blob: 4bceaeb33d6c5a8d848e386bb5ad5a8b4c74faf8 [file] [log] [blame]
//===-- go-llvm-btype.cpp - LLVM implementation of 'Btype' ---------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// Methods for class Btype and its derived classes.
//
//===----------------------------------------------------------------------===//
#include "go-llvm-btype.h"
#include "go-llvm-bexpression.h"
#include "go-system.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Constants.h"
static void indent(llvm::raw_ostream &os, unsigned ilevel) {
for (unsigned i = 0; i < ilevel; ++i)
os << " ";
}
void Btype::dump() const
{
std::string s;
llvm::raw_string_ostream os(s);
osdump(os, 0);
std::cerr << os.str() << "\n";
}
void Btype::osdump(llvm::raw_ostream &os, unsigned ilevel) const {
indent(os, ilevel);
if (isPlaceholder())
os << "[ph] ";
const BIntegerType *bit = castToBIntegerType();
if (bit && bit->isUnsigned())
os << "[uns] ";
if (! name_.empty())
os << "'" << name_ << "' ";
if (type_)
type_->print(os);
else
os << "<nil type_>\n";
}
bool Btype::equal(const Btype &other) const
{
return equalImpl(other, Default);
}
bool Btype::equivalent(const Btype &other) const
{
return equalImpl(other, IgnoreNames);
}
bool Btype::equalImpl(const Btype &other, CompareCtl ctl) const
{
if (this == &other)
return true;
if (flavor() != other.flavor())
return false;
if ((ctl & IgnoreNames) == 0 && name() != other.name())
return false;
if (isPlaceholder() != other.isPlaceholder())
return false;
bool compareLlvmType = true;
if ((ctl & IgnoreNames) != 0 && type()->isStructTy() && flavor_ != ComplexT)
compareLlvmType = false;
if (compareLlvmType && type() != other.type())
return false;
switch(flavor_) {
case AuxT:
case ComplexT:
case FloatT: {
// Ordinarily it would make sense to compare number of bits
// when checking to see if complex/float types are equal, but
// this will already be taken care of by the llvm type equality
// test above.
return true;
}
case IntegerT: {
const BIntegerType *bit = castToBIntegerType();
const BIntegerType *obit = other.castToBIntegerType();
return bit->isUnsigned() == obit->isUnsigned();
}
case PointerT: {
const BPointerType *bpt = castToBPointerType();
const BPointerType *obpt = other.castToBPointerType();
if ((bpt->toType() != nullptr) != (obpt->toType() != nullptr))
return false;
return bpt->toType()->equalImpl(*obpt->toType(), ctl);
}
case ArrayT: {
const BArrayType *bat = castToBArrayType();
const BArrayType *obat = other.castToBArrayType();
if ((bat->elemType() != nullptr) != (obat->elemType() != nullptr))
return false;
return (bat->nelSize() == obat->nelSize() &&
bat->elemType()->equalImpl(*obat->elemType(), ctl));
}
case StructT: {
const BStructType *bst = castToBStructType();
const BStructType *obst = other.castToBStructType();
const std::vector<Backend::Btyped_identifier> &ft = bst->fields();
const std::vector<Backend::Btyped_identifier> &fo = obst->fields();
if (ft.size() != fo.size())
return false;
for (unsigned i = 0; i < ft.size(); ++i) {
if (! ft[i].btype->equalImpl(*fo[i].btype, ctl))
return false;
// NB: IgnoreNames applies to top-level type names, not field names
if (ft[i].name != fo[i].name)
return false;
if (! (ft[i].location == fo[i].location))
return false;
}
return true;
}
case FunctionT: {
const BFunctionType *bft = castToBFunctionType();
const BFunctionType *obft = other.castToBFunctionType();
if ((bft->receiverType() != nullptr) !=
(obft->receiverType() != nullptr))
return false;
if (bft->receiverType() &&
! bft->receiverType()->equalImpl(*obft->receiverType(), ctl))
return false;
if (! bft->resultType()->equalImpl(*obft->resultType(), ctl))
return false;
const std::vector<Btype *> &pt = bft->paramTypes();
const std::vector<Btype *> &po = obft->paramTypes();
if (pt.size() != po.size())
return false;
for (unsigned i = 0; i < pt.size(); ++i) {
if (! pt[i]->equalImpl(*po[i], ctl))
return false;
}
if (bft->followsCabi() != obft->followsCabi())
return false;
return true;
}
}
// unreached
return false;
}
unsigned Btype::hash() const
{
unsigned hv = static_cast<unsigned>(flavor());
std::size_t hn = std::hash<std::string>{}(name());
std::size_t ht = std::hash<llvm::Type *>{}(type());
unsigned h = ((hn + ht) << 3) | hv;
return h;
}
Btype *Btype::clone() const
{
Btype *rval = nullptr;
switch(flavor_) {
case AuxT: {
rval = new Btype(flavor(), type(), location());
break;
}
case ComplexT: {
const BComplexType *bct = castToBComplexType();
rval = bct->clone();
break;
}
case FloatT: {
const BFloatType *bft = castToBFloatType();
rval = bft->clone();
break;
}
case IntegerT: {
const BIntegerType *bit = castToBIntegerType();
rval = bit->clone();
break;
}
case PointerT: {
const BPointerType *bpt = castToBPointerType();
rval = bpt->clone();
break;
}
case ArrayT: {
const BArrayType *bat = castToBArrayType();
rval = bat->clone();
break;
}
case StructT: {
const BStructType *bst = castToBStructType();
rval = bst->clone();
break;
}
case FunctionT: {
const BFunctionType *bft = castToBFunctionType();
rval = bft->clone();
break;
}
}
if (type())
rval->setType(type());
rval->setPlaceholder(isPlaceholder());
rval->setName(name());
return rval;
}
bool Btype::isUnresolvedPlaceholder() const {
if (flavor() == StructT)
return false;
return isPlaceholder();
}
uint64_t BArrayType::nelSize() const
{
llvm::ConstantInt *lc =
llvm::dyn_cast<llvm::ConstantInt>(nelements_->value());
assert(lc);
uint64_t asize = lc->getValue().getZExtValue();
return asize;
}