blob: 1b9716894beece712df805d24cbf772c94bc6970 [file] [log] [blame]
//===-- go-llvm-bexpression.cpp - implementation of 'Bexpression' 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.
//
//===----------------------------------------------------------------------===//
//
// Methods for class Bexpression.
//
//===----------------------------------------------------------------------===//
#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/Instructions.h"
#include "llvm/IR/Value.h"
static void indent(llvm::raw_ostream &os, unsigned ilevel) {
for (unsigned i = 0; i < ilevel; ++i)
os << " ";
}
bool Binstructions::isValidInst(llvm::Instruction *inst)
{
if (llvm::isa<llvm::AllocaInst>(inst))
return false;
return true;
}
std::vector<llvm::Instruction *>
Binstructions::extractInstsAfter(llvm::Instruction *inst)
{
auto it = std::find(instructions_.begin(), instructions_.end(), inst);
assert(it != instructions_.end());
std::vector<llvm::Instruction *> rval(it, instructions_.end());
if (it != instructions_.end())
instructions_.erase(it, instructions_.end());
return rval;
}
Bexpression::Bexpression(NodeFlavor fl, const std::vector<Bnode *> &kids,
llvm::Value *val, Btype *typ, Location loc)
: Bnode(fl, kids, loc)
, value_(val)
, btype_(typ)
{
}
Bexpression::Bexpression(const Bexpression &src)
: Bnode(src)
, Binstructions()
, value_(src.value_)
, btype_(src.btype_)
, varContext_(src.varContext_)
{
}
Bexpression::~Bexpression()
{
}
bool Bexpression::varExprPending() const
{
return varContext_.pending();
}
const VarContext &Bexpression::varContext() const
{
return varContext_;
}
void Bexpression::setVarExprPending(bool lvalue, unsigned addrLevel)
{
varContext_.setPending(lvalue, addrLevel);
}
void Bexpression::setVarExprPending(const VarContext &src)
{
assert(src.pending());
varContext_ = src;
}
void Bexpression::resetVarExprContext()
{
varContext_.reset();
}
bool Bexpression::compositeInitPending() const
{
return flavor() == N_Composite && value() == nullptr;
}
const std::vector<Bexpression *> Bexpression::getChildExprs() const
{
std::vector<Bexpression *> rval;
for (auto &k : children()) {
Bexpression *e = k->castToBexpression();
assert(e);
rval.push_back(e);
}
return rval;
}
void Bexpression::setValue(llvm::Value *val)
{
assert(val);
value_ = val;
}
bool Bexpression::isConstant()
{
if (!value_)
return false;
if (!llvm::isa<llvm::Constant>(value_))
return false;
// Not a constant if there is a pending load
if (value_->getType()->isPointerTy() &&
value_->getType()->getPointerElementType() ==
btype()->type())
return false;
// In some cases, even the underlying value is an
// llvm::Constant, the expression may be not. For
// example, a var expression for a global variable,
// its value is an llvm::GlobalVariable, which is an
// llvm::Constant, but this is generally not what
// we want. Extra checking is needed.
switch (flavor()) {
case N_Var:
return false;
case N_Deref:
return false;
case N_Conversion: {
std::vector<Bexpression*> kids = getChildExprs();
assert(kids.size() == 1);
return kids[0]->isConstant();
}
case N_StructField: {
std::vector<Bexpression*> kids = getChildExprs();
assert(kids.size() == 1);
return kids[0]->isConstant();
}
case N_ArrayIndex: {
std::vector<Bexpression*> kids = getChildExprs();
assert(kids.size() == 2);
return kids[0]->isConstant() && kids[1]->isConstant();
}
default:
return true;
}
}
void Bexpression::srcDump(Llvm_linemap *linemap)
{
std::string s;
llvm::raw_string_ostream os(s);
osdump(os, 0, linemap, false);
std::cerr << os.str();
}
void Bexpression::dumpInstructions(llvm::raw_ostream &os, unsigned ilevel,
Llvm_linemap *linemap, bool terse) const {
bool hitValue = false;
for (auto inst : instructions()) {
indent(os, ilevel);
char c = ' ';
if (inst == value()) {
c = '*';
hitValue = true;
}
if (! terse)
os << c;
inst->print(os);
os << "\n";
}
if (!terse && !hitValue) {
indent(os, ilevel);
if (value())
value()->print(os);
else
os << "<nil value>";
os << "\n";
}
}