blob: d6203be3c2425048eebb971e4249785dde4bea76 [file] [log] [blame]
//===-- AST Validation Pass -------------------------------------*- C++ -*-===//
//
// High Level Virtual Machine (HLVM)
//
// Copyright (C) 2006 Reid Spencer. All Rights Reserved.
//
// This software is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This software is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library in the file named LICENSE.txt; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
//
//===----------------------------------------------------------------------===//
/// @file hlvm/Pass/Validate.cpp
/// @author Reid Spencer <rspencer@reidspencer.org> (original author)
/// @date 2006/05/18
/// @since 0.1.0
/// @brief Implements the functions of class hlvm::Pass::Validate.
//===----------------------------------------------------------------------===//
#include <hlvm/Pass/Pass.h>
#include <hlvm/Base/Assert.h>
#include <hlvm/AST/AST.h>
#include <hlvm/AST/Bundle.h>
#include <hlvm/AST/ControlFlow.h>
#include <hlvm/AST/MemoryOps.h>
#include <hlvm/AST/InputOutput.h>
#include <hlvm/AST/Arithmetic.h>
#include <hlvm/AST/RealMath.h>
#include <hlvm/AST/BooleanOps.h>
#include <hlvm/AST/StringOps.h>
#include <hlvm/AST/Linkables.h>
#include <hlvm/AST/Constants.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/MathExtras.h>
#include <llvm/ADT/StringExtras.h>
#include <iostream>
#include <cfloat>
#include <cmath>
#include <cerrno>
using namespace hlvm;
using namespace llvm;
namespace {
class ValidateImpl : public Pass
{
AST* ast;
public:
ValidateImpl() : Pass(0,Pass::PostOrderTraversal), ast(0) {}
virtual void handleInitialize(AST* tree) { ast = tree; }
virtual void handle(Node* b,Pass::TraversalKinds k);
inline void error(const Node*n, const std::string& msg);
inline void warning(const Node*n, const std::string& msg);
inline bool checkNode(Node*);
inline bool checkType(Type*,NodeIDs id);
inline bool checkValue(Value*,NodeIDs id);
inline bool checkConstant(Constant*,NodeIDs id);
inline bool checkOperator(
Operator*,NodeIDs id,unsigned numOps, bool exact = true);
inline bool checkTerminator(Operator* op);
inline bool checkUniformContainer(UniformContainerType* T, NodeIDs id);
inline bool checkDisparateContainer(DisparateContainerType* T, NodeIDs id);
inline bool checkLinkable(Linkable* LI, NodeIDs id);
inline bool checkExpression(const Operator* op);
inline bool checkBooleanExpression(const Operator* op);
inline bool checkIntegralExpression(const Operator* op);
inline bool checkResult(const Operator* op);
template <class NodeClass>
inline void validate(NodeClass* C);
};
void
ValidateImpl::warning(const Node* n, const std::string& msg)
{
if (n) {
const Locator* loc = n->getLocator();
if (loc) {
std::string location;
loc->getLocation(location);
std::cerr << location << ": ";
} else
std::cerr << "Unknown Location: ";
}
std::cerr << msg << "\n";
}
void
ValidateImpl::error(const Node* n, const std::string& msg)
{
if (n) {
const Locator* loc = n->getLocator();
if (loc) {
std::string location;
loc->getLocation(location);
std::cerr << location << ": ";
} else
std::cerr << "Unknown Location: ";
}
if (const ConstantValue* CV = dyn_cast<ConstantValue>(n)) {
std::cerr << CV->getName() << ": ";
} else if (const Linkable *L = dyn_cast<Linkable>(n)) {
std::cerr << L->getName() << ": ";
} else if (const Type* Ty = dyn_cast<Type>(n)) {
std::cerr << Ty->getName() << ": ";
} else if (const NamedType* Ty = dyn_cast<NamedType>(n)) {
std::cerr << Ty->getName() << ": ";
}
std::cerr << msg << "\n";
passed_ = false;
}
bool
ValidateImpl::checkNode(Node* n)
{
if (n->getParent() == 0) {
error(n,"Node has no parent");
return false;
}
if (n->getID() < FirstNodeID || n->getID() > LastNodeID) {
error(n,"Node ID out of range");
return false;
}
return true;
}
bool
ValidateImpl::checkType(Type* t,NodeIDs id)
{
bool result = checkNode(t);
if (t->getID() != id) {
error(t,"Unexpected NodeID for Type");
result = false;
} else if (!t->isType()) {
error(t,"Bad ID for a Type");
result = false;
}
if (!t->hasName()) {
error(t, "Empty type name");
result = false;
}
return result;
}
bool
ValidateImpl::checkValue(Value* v, NodeIDs id)
{
bool result = checkNode(v);
if (v->getID() != id) {
error(v,"Unexpected NodeID for Value");
result = false;
} else if (!v->isValue()) {
error(v,"Bad ID for a Value");
result = false;
}
return result;
}
bool
ValidateImpl::checkConstant(Constant* C,NodeIDs id)
{
if (checkValue(C,id)) {
if (!C->hasName() && llvm::isa<Linkable>(C)) {
error(C,"Linkables must not have an empty name");
return false;
}
}
return true;
}
bool
ValidateImpl::checkOperator(Operator*n, NodeIDs id, unsigned num, bool exact)
{
bool result = checkValue(n,id);
if (result)
if (num > n->getNumOperands()) {
error(n,"Too few operands");
result = false;
} else if (exact && num != n->getNumOperands()) {
error(n, "Too many operands");
result = false;
}
return result;
}
bool
ValidateImpl::checkTerminator(Operator *n)
{
if (Block* b = llvm::dyn_cast<Block>(n->getParent())) {
if (b->back() != n) {
error(n,"Terminating operator is not last operator in block");
return false;
}
}
return true;
}
bool
ValidateImpl::checkUniformContainer(UniformContainerType* n, NodeIDs id)
{
bool result = true;
if (!checkType(n,id))
result = false;
else if (n->getElementType() == 0) {
error(n,"UniformContainerType without element type");
result = false;
} else if (n->getElementType() == n) {
error(n,"Self-referential UniformContainerType");
result = false;
} else if (n->getName() == n->getElementType()->getName()) {
error(n,"UniformCOontainerType has same name as its element type");
result = false;
}
return result;
}
bool
ValidateImpl::checkDisparateContainer(DisparateContainerType* n, NodeIDs id)
{
bool result = true;
if (!checkType(n,id))
result = false;
else if (n->size() == 0 && !llvm::isa<SignatureType>(n)) {
error(n,"DisparateContainerType without elements");
result = false;
} else {
for (DisparateContainerType::iterator I = n->begin(), E = n->end();
I != E; ++I) {
if (!(*I)->getType()) {
error(n,std::string("Null type not permited in DisparateContainerType")
+ " for '" + (*I)->getName() + "'");
result = false;
} else if (!(*I)->hasName()) {
error((*I)->getType(),"Type has no field name");
result = false;
}
}
}
return result;
}
bool
ValidateImpl::checkLinkable(Linkable* LI, NodeIDs id)
{
bool result = checkConstant(LI,id);
if (result) {
if (LI->getLinkageKind() < ExternalLinkage ||
LI->getLinkageKind() > InternalLinkage) {
error(LI,"Invalid LinkageKind for Linkable");
result = false;
}
if (LI->getName().length() == 0) {
error(LI,"Zero length name for Linkable");
result = false;
}
}
return result;
}
bool
ValidateImpl::checkExpression(const Operator* op)
{
bool result = true;
if (const Block* B = dyn_cast<Block>(op)) {
if (const Operator* block_result = B->getResult()) {
if (!block_result->getType()) {
error(op,"Block with void result used where expression expected");
result = false;
}
} else {
error(op,"Block without result used where expression expected");
result = false;
}
if (B->isTerminated()){
error(op,"Terminator found in block used as an expression");
result = false;
}
} else if (!op->getType()) {
error(op,"Operator with void result used where expression expected");
result = false;
}
return result;
}
bool
ValidateImpl::checkBooleanExpression(const Operator* op)
{
if (checkExpression(op))
if (!op->typeis<BooleanType>()) {
error(op,std::string("Expecting boolean expression but type '") +
op->getType()->getName() + "' was found");
return false;
} else
return true;
return false;
}
bool
ValidateImpl::checkIntegralExpression(const Operator* op)
{
if (checkExpression(op))
if (!op->getType()->isIntegralType()) {
error(op,std::string("Expecting integral expression but type '") +
op->getType()->getName() + "' was found");
return false;
} else
return true;
return false;
}
bool
ValidateImpl::checkResult(const Operator* op)
{
if (const Block* B = dyn_cast<Block>(op)) {
if (!B->getResult() && !isa<Block>(B->getParent()->getParent())) {
error(B,"Block with no result used where an expression is expected");
return false;
}
} else if (!op->getType() && !isa<Block>(op->getParent()->getParent())) {
error(op,"Operator with void result used where an expression is expected");
return false;
}
return true;
}
template<> inline void
ValidateImpl::validate(AnyType* n)
{
checkType(n,AnyTypeID);
}
template<> inline void
ValidateImpl::validate(BooleanType* n)
{
checkType(n,BooleanTypeID);
}
template<> inline void
ValidateImpl::validate(CharacterType* n)
{
checkType(n,CharacterTypeID);
}
template<> inline void
ValidateImpl::validate(IntegerType* n)
{
if (checkNode(n))
if (!n->is(IntegerTypeID))
error(n,"Bad ID for IntegerType");
else if (n->getBits() == 0)
error(n,"Integer type cannot have zero bits");
}
template<> inline void
ValidateImpl::validate(OpaqueType* n)
{
checkType(n,OpaqueTypeID);
}
template<> inline void
ValidateImpl::validate(RangeType* n)
{
if (checkType(n,RangeTypeID))
if (n->getMin() > n->getMax())
error(n,"RangeType has negative range");
}
template<> inline void
ValidateImpl::validate(EnumerationType* n)
{
if (checkType(n,EnumerationTypeID))
for (EnumerationType::iterator I = n->begin(), E = n->end(); I != E; ++I )
if ((I)->length() == 0)
error(n,"Enumerator with zero length");
}
template<> inline void
ValidateImpl::validate(RealType* n)
{
if (checkNode(n))
if (!n->is(RealTypeID))
error(n,"Bad ID for RealType");
else {
uint64_t bits = n->getMantissa() + n->getExponent();
if (bits > UINT32_MAX)
error(n,"Too many bits in RealType");
}
}
template<> inline void
ValidateImpl::validate(RationalType* n)
{
if (checkNode(n))
if (!n->is(RationalTypeID))
error(n,"Bad ID for RationalType");
}
template<> inline void
ValidateImpl::validate(StringType* n)
{
checkType(n,StringTypeID);
}
template<> inline void
ValidateImpl::validate(TextType* n)
{
checkType(n,TextTypeID);
}
template<> inline void
ValidateImpl::validate(StreamType* n)
{
checkType(n,StreamTypeID);
}
template<> inline void
ValidateImpl::validate(BufferType* n)
{
checkType(n,BufferTypeID);
}
template<> inline void
ValidateImpl::validate(PointerType* n)
{
checkUniformContainer(n, PointerTypeID);
}
template<> inline void
ValidateImpl::validate(ArrayType* n)
{
if (checkUniformContainer(n, ArrayTypeID)) {
if (n->getMaxSize() == 0)
error(n,"Array of 0 elements not permited");
}
}
template<> inline void
ValidateImpl::validate(VectorType* n)
{
if (checkUniformContainer(n, VectorTypeID)) {
if (n->getSize() == 0)
error(n,"Vector of 0 elements not permited");
}
}
template<> inline void
ValidateImpl::validate(StructureType* n)
{
if (checkDisparateContainer(n, StructureTypeID)) {
if (n->size() == 0)
error(n,"Structure of 0 fields not permited");
}
}
template<> inline void
ValidateImpl::validate(ContinuationType* n)
{
if (checkDisparateContainer(n, ContinuationTypeID)) {
if (n->size() == 0)
error(n,"Continuation of 0 fields not permited");
}
}
template<> inline void
ValidateImpl::validate(SignatureType* n)
{
checkDisparateContainer(n, SignatureTypeID);
}
template<> inline void
ValidateImpl::validate(ConstantAny* n)
{
checkConstant(n,ConstantAnyID);
}
template<> inline void
ValidateImpl::validate(ConstantBoolean* n)
{
checkConstant(n,ConstantBooleanID);
}
template<> inline void
ValidateImpl::validate(ConstantCharacter* n)
{
if (checkConstant(n,ConstantCharacterID)) {
if (const CharacterType* CT = dyn_cast<CharacterType>(n->getType())) {
const std::string& cVal = n->getValue();
if (cVal.empty()) {
error(n,"Constant character of zero length not permitted");
} else if (cVal[0] == '#') {
const char* startptr = &cVal.c_str()[1];
char* endptr;
uint32_t val = strtoul(startptr, &endptr, 16);
if (endptr == startptr || (val == ULONG_MAX && errno != 0))
error(n,"Invalid numeric constant character '" + cVal + "'");
else if (val == 0)
error(n,"Zero valued character constant not permitted");
} else if (cVal.size() > 1) {
error(n,"Too many characters (" + utostr(cVal.size()) +
") for character constant");
}
}
}
}
template<> inline void
ValidateImpl::validate(ConstantEnumerator* n)
{
if (checkConstant(n,ConstantEnumeratorID)) {
uint64_t val;
if (const EnumerationType* ET = dyn_cast<EnumerationType>(n->getType())) {
if (!ET->getEnumValue( n->getValue(), val))
error(n, "Enumerator '" + n->getValue() + "' not valid for type '" +
ET->getName());
} else {
error(n,"Type for ConstantEnumerator is not EnumerationType");
}
}
}
template<> inline void
ValidateImpl::validate(ConstantInteger* CI)
{
if (checkConstant(CI,ConstantIntegerID)) {
const char* startp = CI->getValue().c_str();
char* endp = 0;
int64_t val = strtoll(startp,&endp,CI->getBase());
// Check that it can be converted to binary
if (!endp || startp == endp || *endp != '\0')
error(CI,"Invalid integer constant. Conversion failed.");
else if (const IntegerType* Ty = dyn_cast<IntegerType>(CI->getType())) {
if (val < 0 && !Ty->isSigned()) {
error(CI,"Invalid integer constant. "
"Signed value not accepted by unsigned type");
} else {
// It converted to binary okay, check that it is in range
uint64_t uval = (val < 0) ? -val : val;
unsigned leading_zeros = llvm::CountLeadingZeros_64(uval);
unsigned bits_required = (sizeof(uint64_t)*8 - leading_zeros) +
unsigned(Ty->isSigned());
unsigned bits_allowed = Ty->getBits();
if (bits_required > bits_allowed)
error(CI, "Invalid integer constant. Value requires " +
utostr(bits_required) + " bits, but type only holds " +
utostr(bits_allowed) + " bits.");
}
} else if (const RangeType* Ty = dyn_cast<RangeType>(CI->getType())) {
if (val < Ty->getMin() || val > Ty->getMax())
error(CI, "Integer constant out of range of RangeType");
} else {
error(CI,"Integer constant applied to non-integer type");
}
}
}
template<> inline void
ValidateImpl::validate(ConstantReal* CR)
{
if (checkConstant(CR,ConstantRealID)) {
const char* startp = CR->getValue().c_str();
char* endp = 0;
long double val = strtold(startp,&endp);
if (!endp || startp == endp || *endp != '\0')
error(CR,"Invalid real constant. Conversion failed.");
else {
// It converted to a double okay, check that it is in range
// But, first make sure its not one of the special values
if (__fpclassify(val) != FP_NORMAL)
return;
int exp = ilogbl(val);
uint64_t val_exp = (exp < 0 ? uint64_t(-exp) : uint64_t(exp));
unsigned leading_zeros = llvm::CountLeadingZeros_64(val_exp);
unsigned exp_bits_required = (sizeof(uint64_t)*8 - leading_zeros);
const RealType* Ty = llvm::cast<RealType>(CR->getType());
if (Ty->getExponent() < exp_bits_required) {
error(CR,"Real constant requires too many exponent bits (" +
llvm::utostr(exp_bits_required) + ") for type '" +
Ty->getName() + "'");
return;
}
unsigned numBits = Ty->getMantissa() + Ty->getExponent() + 1;
if (numBits <= sizeof(float)*8) {
float x = val;
long double x2 = x;
if (val != x2)
error(CR,"Real constant out of range for real requiring " +
utostr(numBits) + " bits");
}
else if (numBits <= sizeof(double)*8)
{
double x = val;
long double x2 = x;
if (val != x2)
error(CR,"Real constant out of range for real requiring " +
utostr(numBits) + " bits");
}
else if (numBits > sizeof(long double)*8)
warning(CR,"Don't know how to check range of real type > 128 bits");
}
}
}
template<> inline void
ValidateImpl::validate(ConstantString* n)
{
if (checkConstant(n,ConstantStringID))
if (std::string::npos != n->getValue().find('\0'))
error(n,"String constants may not contain a null byte");
}
template<> inline void
ValidateImpl::validate(ConstantPointer* n)
{
if (checkConstant(n,ConstantPointerID)) {
if (const PointerType* PT = dyn_cast<PointerType>(n->getType())) {
if (PT->getElementType() != n->getValue()->getType()) {
error(n,"ConstantPointer referent does not match pointer type");
}
} else {
error(n,"Constant pointer of type '" +
n->getType()->getName() + "' must have pointer type");
}
}
}
template<> inline void
ValidateImpl::validate(ConstantArray* n)
{
if (checkConstant(n,ConstantArrayID)) {
if (const ArrayType* AT = dyn_cast<ArrayType>(n->getType())) {
if (n->size() > AT->getMaxSize())
error(n,"Too many elements (" + utostr(n->size()) + ") for array "
"of size " + utostr(AT->getMaxSize()));
else if (n->size() == 0)
error(n,"Zero sized ConstantArray is not permited");
for (ConstantArray::iterator I = n->begin(), E = n->end(); I != E; ++I)
if ((*I)->getType() != AT->getElementType())
error(n,"Element #" + utostr(I-n->begin()) + "of type '" +
(*I)->getType()->getName() + "' does not conform to array "+
"element type (" + AT->getElementType()->getName() + ")");
} else
error(n,"ConstantArray must have array type");
}
}
template<> inline void
ValidateImpl::validate(ConstantVector* n)
{
if (checkConstant(n,ConstantVectorID)) {
if (const VectorType* VT = dyn_cast<VectorType>(n->getType())) {
if (n->size() != VT->getSize())
error(n,"Too " +
(n->size() < VT->getSize() ? std::string("few") :
std::string("many")) + " elements (" + utostr(n->size()) +
") for array of size " + utostr(VT->getSize()));
for (ConstantArray::iterator I = n->begin(), E = n->end(); I != E; ++I)
if ((*I)->getType() != VT->getElementType())
error(n,"Element #" + utostr(I-n->begin()) + "of type '" +
(*I)->getType()->getName() + "' does not conform to vector "+
"element type (" + VT->getElementType()->getName() + ")");
} else
error(n,"ConstantVector must have vector type");
}
}
template<> inline void
ValidateImpl::validate(ConstantStructure* n)
{
if (checkConstant(n,ConstantStructureID)) {
if (const StructureType* ST = dyn_cast<StructureType>(n->getType())) {
if (n->size() != ST->size())
error(n,"Too " +
(n->size() < ST->size() ? std::string("few") :
std::string("many")) + " elements (" + utostr(n->size()) +
") for structure with " + utostr(ST->size()) + " fields");
StructureType::const_iterator STI = ST->begin();
for (ConstantStructure::iterator I = n->begin(), E = n->end();
I != E; ++I) {
if ((*I)->getType() != (*STI)->getType())
error(n,"Field #" + utostr(I-n->begin()) + " of type '"
+ (*I)->getType()->getName() +
"' does not conform to type of structure field (" +
(*STI)->getName() + ") of type '" + (*STI)->getType()->getName() +
"'");
++STI;
}
} else
error(n,"ConstantStructure must have structure type");
}
}
template<> inline void
ValidateImpl::validate(ConstantContinuation* n)
{
if (checkConstant(n,ConstantContinuationID)) {
if (const ContinuationType* CT = dyn_cast<ContinuationType>(n->getType())) {
if (n->size() != CT->size())
error(n,"Too " +
(n->size() < CT->size() ? std::string("few") :
std::string("many")) + " elements (" + utostr(n->size()) +
") for continuation with " + utostr(CT->size()) + " fields");
ContinuationType::const_iterator CTI = CT->begin();
for (ConstantContinuation::iterator I = n->begin(), E = n->end();
I != E; ++I) {
if ((*I)->getType() != (*CTI)->getType())
error(n,"Field #" + utostr(I-n->begin()) + "of type '"
+ (*I)->getType()->getName() +
"' does not conform to type of continuation field (" +
(*CTI)->getName() + ") of type '" + (*CTI)->getType()->getName() +
"'");
++CTI;
}
} else
error(n,"ConstantContinuation must have continuation type");
}
}
template<> inline void
ValidateImpl::validate(ConstantExpression* n)
{
checkConstant(n,ConstantExpressionID);
// FIXME: validate opcodes and operands
}
template<> inline void
ValidateImpl::validate(Variable* n)
{
if (checkLinkable(n, VariableID))
if (n->hasInitializer())
if (n->getType() != n->getInitializer()->getType())
error(n,"Variable and its initializer do not agree in type");
}
template<> inline void
ValidateImpl::validate(Function* F)
{
if (checkLinkable(F, FunctionID)) {
if (F->getSignature() == 0)
error(F,"Function without signature");
else if (F->getSignature()->getID() != SignatureTypeID)
error(F,"Function does not have SignatureType signature");
if (F->getLinkageKind() != ExternalLinkage && F->getBlock() == 0)
error(F,"Non-external Function without defining block");
}
}
template<> inline void
ValidateImpl::validate(Program* P)
{
if (checkLinkable(P, ProgramID)) {
if (P->getSignature() == 0)
error(P,"Program without signature");
else if (P->getSignature()->getID() != SignatureTypeID)
error(P,"Program does not have SignatureType signature");
else if (P->getSignature() != P->getContainingBundle()->getProgramType())
error(P,"Program has wrong signature");
if (P->getLinkageKind() != ExternalLinkage && P->getBlock() == 0)
error(P,"Non-external Program without defining block");
}
}
template<> inline void
ValidateImpl::validate(Block* n)
{
if (checkValue(n,BlockID))
if (n->getNumOperands() == 0)
error(n,"Block with no operands");
else {
Operator* terminator = 0;
Operator* result = 0;
for (MultiOperator::iterator I = n->begin(), E = n->end(); I != E; ++I) {
if (llvm::isa<ResultOp>(*I))
result = *I;
else if ((*I)->isTerminator()) {
if (terminator)
error(n,"Block contains multiple terminators");
else
terminator = *I;
} else if (terminator)
error(n,"Block has operators after terminator");
else if (!llvm::isa<Operator>(*I))
error(n,"Block contains non-operator");
}
if (terminator) {
if (llvm::isa<ReturnOp>(terminator)) {
if (!result) {
Function* F= n->getContainingFunction();
if (F->getResultType())
error(terminator,"Missing result in return from function");
}
} else if (result) {
warning(result,"Result will not be used in terminated block");
}
} else if (result) {
if (n == n->getContainingFunction()->getBlock())
error(result,"Function's main block has result but no return");
}
}
}
template<> inline void
ValidateImpl::validate(ResultOp* n)
{
if (checkOperator(n,ResultOpID,1)) {
if (Block* B = dyn_cast<Block>(n->getParent())) {
if (Operator* res = n->getOperand(0)) {
if (const Operator* existing_result = B->getResult()) {
if (existing_result->getType() != res->getType()) {
error(n,"ResultOp does not match block result type");
}
} else {
error(n,"Block has no result type, but has ResultOp");
}
if (Function* F = n->getContainingFunction()) {
if (F->getBlock() == B) {
const SignatureType* SigTy = F->getSignature();
if (res->getType()) {
if (res->getType() != SigTy->getResultType())
error(n,"ResultOp does not agree in type with Function result");
} else if (SigTy->getResultType()) {
error(n,"Void function result for non-void function");
}
}
} else {
error(n,"ResultOP not in function?");
}
} else {
error(n,"ResultOp with no operand");
}
} else {
error(n, "ResultOp not in a Block");
}
}
}
template<> inline void
ValidateImpl::validate(ReturnOp* n)
{
if (checkOperator(n,ReturnOpID,0))
checkTerminator(n);
}
template<> inline void
ValidateImpl::validate(BreakOp* n)
{
if (checkOperator(n,BreakOpID,0))
if (checkTerminator(n))
if (!n->getContainingLoop())
error(n,"Break not within a loop scope");
}
template<> inline void
ValidateImpl::validate(ContinueOp* n)
{
if (checkOperator(n,ContinueOpID,0))
if (checkTerminator(n))
if (!n->getContainingLoop())
error(n,"Continue not within a loop scope");
}
template<> inline void
ValidateImpl::validate(SelectOp* n)
{
if (checkOperator(n,SelectOpID,3)) {
checkBooleanExpression(n->getOperand(0));
if (checkResult(n->getOperand(1)))
if (checkResult(n->getOperand(2)))
if (!isa<Block>(n->getParent()))
if (n->getOperand(1)->getType() != n->getOperand(2)->getType())
error(n,"SelectOp operands must have same type");
}
}
template<> inline void
ValidateImpl::validate(WhileOp* n)
{
if (checkOperator(n,WhileOpID,2)) {
checkBooleanExpression(n->getOperand(0));
checkResult(n->getOperand(1));
}
}
template<> inline void
ValidateImpl::validate(UnlessOp* n)
{
if (checkOperator(n,UnlessOpID,2)) {
checkBooleanExpression(n->getOperand(0));
checkResult(n->getOperand(1));
}
}
template<> inline void
ValidateImpl::validate(UntilOp* n)
{
if (checkOperator(n,UntilOpID,2)) {
checkResult(n->getOperand(0));
checkBooleanExpression(n->getOperand(1));
}
}
template<> inline void
ValidateImpl::validate(LoopOp* n)
{
if (checkOperator(n,LoopOpID,3)) {
checkBooleanExpression(n->getOperand(0));
checkResult(n->getOperand(1));
checkBooleanExpression(n->getOperand(2));
}
}
template<> inline void
ValidateImpl::validate(SwitchOp* n)
{
if (checkOperator(n,SwitchOpID,2,false))
{
if (n->getNumOperands() % 2 != 0)
error(n,"SwitchOp requires even number of operands");
else {
const Type* resultTy = n->getOperand(1)->getType();
for (SwitchOp::iterator I = n->begin(), E = n->end(); I != E; ++I ) {
checkIntegralExpression(*I++);
if (checkResult(*I))
if (resultTy != (*I)->getType())
error(*I,"Inconsistent result type for SwitchOp");
}
}
}
}
template<> inline void
ValidateImpl::validate(CallOp* op)
{
if (checkOperator(op,CallOpID,0,false))
{
hlvm::Function* F = op->getCalledFunction();
const SignatureType* sig = F->getSignature();
if (sig->isVarArgs() && (sig->size() >= op->getNumOperands()))
error(op,"Too few arguments for varargs function call");
else if (!sig->isVarArgs() && (sig->size() != op->getNumOperands()-1))
error(op,"Incorrect number of arguments for function call");
else
{
unsigned opNum = 1;
for (SignatureType::const_iterator I = sig->begin(), E = sig->end();
I != E; ++I)
if ((*I)->getType() != op->getOperand(opNum++)->getType())
error(op,std::string("Argument #") + utostr(opNum-1) +
" has wrong type for function");
}
}
}
template<> inline void
ValidateImpl::validate(AllocateOp* n)
{
if (checkOperator(n,AllocateOpID,2))
{
if (const PointerType* PT = llvm::dyn_cast<PointerType>(n->getType()))
{
if (!PT->getElementType())
error(n,"AllocateOp's pointer type has no element type!");
} else
error(n,"AllocateOp's type must be a pointer type");
if (!n->typeis<IntegerType>())
error(n,"AllocateOp's operand must be of integer type");
}
}
template<> inline void
ValidateImpl::validate(DeallocateOp* n)
{
if (checkOperator(n,DeallocateOpID,1)) {
if (const PointerType* PT = llvm::dyn_cast<PointerType>(n->getType())) {
if (!PT->getElementType())
error(n,"DeallocateOp's pointer type has no element type!");
} else
error(n,"DeallocateOp expects its first operand to be a pointer type");
}
}
template<> inline void
ValidateImpl::validate(LoadOp* n)
{
if (checkOperator(n,LoadOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getType();
if (Ty1 != Ty2)
error(n,"LoadOp type and operand type do not agree");
}
}
template<> inline void
ValidateImpl::validate(StoreOp* n)
{
if (checkOperator(n,StoreOpID,2)) {
Operator* op1 = n->getOperand(0);
Operator* op2 = n->getOperand(1);
const Type* Ty1 = op1->getType();
const Type* Ty2 = op2->getType();
if (Ty1 != Ty2) {
error(n,"StoreOp operands do not agree in type");
} else if (isa<AutoVarOp>(op1)) {
if (cast<AutoVarOp>(op1)->isConstant())
error(n,"Can't store to constant automatic variable");
} else if (const GetOp* ref = dyn_cast<GetOp>(n->getOperand(0))) {
const Value* R = ref->getReferent();
if (isa<Variable>(R) && cast<Variable>(R)->isConstant())
error(n,"Can't store to constant variable");
else if (isa<AutoVarOp>(R) && cast<AutoVarOp>(R)->isConstant())
error(n,"Can't store to constant automatic variable");
} else if (const GetIndexOp* ref = dyn_cast<GetIndexOp>(n)) {
/// FIXME: Implement this
} else if (const GetFieldOp* ref = dyn_cast<GetFieldOp>(n)) {
/// FIXME: Implement this
}
}
}
template<> inline void
ValidateImpl::validate(GetIndexOp* n)
{
if (checkOperator(n,GetIndexOpID,2)) {
// FIXME: Implement check for reference on first operand
// FIXME: Implement check for integer type on second operand
}
}
template<> inline void
ValidateImpl::validate(GetFieldOp* n)
{
if (checkOperator(n,GetFieldOpID,1)) {
// FIXME: Implement check for reference on first operand
// FIXME: Implement check for string type on second operand
}
}
template<> inline void
ValidateImpl::validate(AutoVarOp* n)
{
if (checkOperator(n,AutoVarOpID,0,false)) {
if (n->hasInitializer()) {
if (n->getType() != n->getInitializer()->getType()) {
error(n,"AutoVarOp's type does not agree with type of its Initializer");
}
}
}
}
template<> inline void
ValidateImpl::validate(GetOp* op)
{
if (checkOperator(op,GetOpID,0,true)) {
const Value* referent = op->getReferent();
Block* blk = op->getContainingBlock();
if (!blk)
error(op,"GetOp not in a block?");
else if (const AutoVarOp* ref = dyn_cast<AutoVarOp>(referent)) {
while (blk != 0) {
if (AutoVarOp* av = blk->getAutoVar(ref->getName()))
if (av == ref)
break;
blk = blk->getContainingBlock();
}
if (blk == 0)
error(ref,"Referent does not match name in scope");
} else if (const Argument* arg = dyn_cast<Argument>(referent)) {
Function* F = op->getContainingFunction();
if (!F)
error(op,"GetOp not in a function?");
else if (F->getArgument(arg->getName()) != arg)
error(F,"Referent does not match function argument");
} else if (const Constant* cval = dyn_cast<Constant>(referent)) {
Bundle* B = op->getContainingBundle();
if (!B)
error(op,"GetOp not in a bundle?");
else if (B->getConst(cval->getName()) != cval)
error(cval,"Constant not found in Bundle");
} else if (const Type* Ty = dyn_cast<Type>(referent)) {
Bundle* B = op->getContainingBundle();
if (!B)
error(op,"GetOp not in bundle?");
else if (B->getType(Ty->getName()) != Ty)
error(Ty,"Type not found in Bundle");
} else {
error(op,"Referent of unknown kind");
}
}
}
template<> inline void
ValidateImpl::validate(NegateOp* n)
{
if (checkOperator(n,NegateOpID,1)) {
const Type* Ty = n->getType();
if (!Ty->isNumericType())
error(n,"You can only negate objects of numeric type");
}
}
template<> inline void
ValidateImpl::validate(ComplementOp* n)
{
if (checkOperator(n,ComplementOpID,1)) {
const Type* Ty = n->getType();
if (!Ty->isIntegralType())
error(n,"You can only complement objects of integral type");
}
}
template<> inline void
ValidateImpl::validate(PreIncrOp* n)
{
if (checkOperator(n,PreIncrOpID,1)) {
if (GetOp* oprnd = llvm::dyn_cast<GetOp>(n->getOperand(0))) {
const Value* V = oprnd->getReferent();
if (V && (isa<AutoVarOp>(V) || isa<Variable>(V))) {
if (!llvm::cast<Value>(V)->getType()->isNumericType())
error(n,"Target of PostIncrOp is not numeric type");
} else
; // Handled elsewhere
} else
error(n,"Operand of PostIncrOp must be a GetOp");
}
}
template<> inline void
ValidateImpl::validate(PostIncrOp* n)
{
if (checkOperator(n,PostIncrOpID,1)) {
if (GetOp* oprnd = llvm::dyn_cast<GetOp>(n->getOperand(0))) {
const Value* V = oprnd->getReferent();
if (V && (isa<AutoVarOp>(V) || isa<Variable>(V))) {
if (!llvm::cast<Value>(V)->getType()->isNumericType())
error(n,"Target of PostIncrOp is not numeric type");
} else
; // Handled elsewhere
} else
error(n,"Operand of PostIncrOp must be a GetOp");
}
}
template<> inline void
ValidateImpl::validate(PreDecrOp* n)
{
if (checkOperator(n,PreDecrOpID,1)){
if (GetOp* oprnd = llvm::dyn_cast<GetOp>(n->getOperand(0))) {
const Value* V = oprnd->getReferent();
if (V && (isa<AutoVarOp>(V) || isa<Variable>(V))) {
if (!llvm::cast<Value>(V)->getType()->isNumericType())
error(n,"Target of PreDecrOp is not numeric type");
} else
; // Handled elsewhere
} else
error(n,"Operand of PreDecrOp must be a GetOp");
}
}
template<> inline void
ValidateImpl::validate(PostDecrOp* n)
{
if (checkOperator(n,PostDecrOpID,1)) {
if (GetOp* oprnd = llvm::dyn_cast<GetOp>(n->getOperand(0))) {
const Value* V = oprnd->getReferent();
if (V && (isa<AutoVarOp>(V) || isa<Variable>(V))) {
if (!llvm::cast<Value>(V)->getType()->isNumericType())
error(n,"Target of PostDecrOp is not numeric type");
} else
; // Handled elsewhere
} else
error(n,"Operand of PostDecrOp must be a GetOp");
}
}
template<> inline void
ValidateImpl::validate(SizeOfOp* n)
{
if (checkOperator(n,SizeOfOpID,1))
;
}
template<> inline void
ValidateImpl::validate(LengthOp* n)
{
if (checkOperator(n,LengthOpID,1))
;
}
template<> inline void
ValidateImpl::validate(ConvertOp* n)
{
if (checkOperator(n,ConvertOpID,1)) {
const Operator* Oprnd1 = n->getOperand(0);
/// FIXME: assure type of Oprnd1 is convertible to n->getType();
}
}
template<> inline void
ValidateImpl::validate(AddOp* n)
{
if (checkOperator(n,AddOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->isNumericType() || !Ty2->isNumericType())
error(n,"You can only add objects of numeric type");
}
}
template<> inline void
ValidateImpl::validate(SubtractOp* n)
{
if (checkOperator(n,SubtractOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->isNumericType() || !Ty2->isNumericType())
error(n,"You can only subtract objects of numeric type");
}
}
template<> inline void
ValidateImpl::validate(MultiplyOp* n)
{
if (checkOperator(n,MultiplyOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->isNumericType() || !Ty2->isNumericType())
error(n,"You can only multiply objects of numeric type");
}
}
template<> inline void
ValidateImpl::validate(DivideOp* n)
{
if (checkOperator(n,DivideOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->isNumericType() || !Ty2->isNumericType())
error(n,"You can only multiply objects of numeric type");
}
}
template<> inline void
ValidateImpl::validate(ModuloOp* n)
{
if (checkOperator(n,ModuloOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->isNumericType() || !Ty2->isNumericType())
error(n,"You can only multiply objects of numeric type");
}
}
template<> inline void
ValidateImpl::validate(BAndOp* n)
{
if (checkOperator(n,BAndOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(IntegerTypeID) || !Ty2->is(IntegerTypeID))
error(n,"You can only bitwise and objects of integer type");
}
}
template<> inline void
ValidateImpl::validate(BOrOp* n)
{
if (checkOperator(n,BOrOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(IntegerTypeID) || !Ty2->is(IntegerTypeID))
error(n,"You can only bitwise or objects of integer type");
}
}
template<> inline void
ValidateImpl::validate(BXorOp* n)
{
if (checkOperator(n,BXorOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(IntegerTypeID) || !Ty2->is(IntegerTypeID))
error(n,"You can only bitwise xor objects of integer type");
}
}
template<> inline void
ValidateImpl::validate(BNorOp* n)
{
if (checkOperator(n,BNorOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(IntegerTypeID) || !Ty2->is(IntegerTypeID))
error(n,"You can only bitwise nor objects of integer type");
}
}
template<> inline void
ValidateImpl::validate(NotOp* n)
{
if (checkOperator(n,NotOpID,1)) {
const Type* Ty = n->getOperand(0)->getType();
if (!Ty->is(BooleanTypeID))
error(n,"NotOp expects boolean typed operand");
}
}
template<> inline void
ValidateImpl::validate(AndOp* n)
{
if (checkOperator(n,AndOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(BooleanTypeID) || !Ty2->is(BooleanTypeID))
error(n,"AndOp expects two boolean typed operands");
}
}
template<> inline void
ValidateImpl::validate(OrOp* n)
{
if (checkOperator(n,OrOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(BooleanTypeID) || !Ty2->is(BooleanTypeID))
error(n,"OrOp expects two boolean typed operands");
}
}
template<> inline void
ValidateImpl::validate(NorOp* n)
{
if (checkOperator(n,NorOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(BooleanTypeID) || !Ty2->is(BooleanTypeID))
error(n,"NorOp expects two boolean typed operands");
}
}
template<> inline void
ValidateImpl::validate(XorOp* n)
{
if (checkOperator(n,XorOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(BooleanTypeID) || !Ty2->is(BooleanTypeID))
error(n,"XorOp expects two boolean typed operands");
}
}
template<> inline void
ValidateImpl::validate(LessThanOp* n)
{
if (checkOperator(n,LessThanOpID,2))
;
}
template<> inline void
ValidateImpl::validate(GreaterThanOp* n)
{
if (checkOperator(n,GreaterThanOpID,2))
;
}
template<> inline void
ValidateImpl::validate(LessEqualOp* n)
{
if (checkOperator(n,LessEqualOpID,2))
;
}
template<> inline void
ValidateImpl::validate(GreaterEqualOp* n)
{
if (checkOperator(n,GreaterEqualOpID,2))
;
}
template<> inline void
ValidateImpl::validate(EqualityOp* n)
{
if (checkOperator(n,EqualityOpID,2))
;
}
template<> inline void
ValidateImpl::validate(InequalityOp* n)
{
if (checkOperator(n,InequalityOpID,2))
;
}
template<> inline void
ValidateImpl::validate(IsPInfOp* n)
{
if (checkOperator(n,IsPInfOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"IsPInfoOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(IsNInfOp* n)
{
if (checkOperator(n,IsNInfOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"IsNInfoOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(IsNanOp* n)
{
if (checkOperator(n,IsNanOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"IsNanOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(TruncOp* n)
{
if (checkOperator(n,TruncOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"TruncOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(RoundOp* n)
{
if (checkOperator(n,RoundOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"RoundOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(FloorOp* n)
{
if (checkOperator(n,FloorOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"FloorOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(CeilingOp* n)
{
if (checkOperator(n,CeilingOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"CeilingOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(LogEOp* n)
{
if (checkOperator(n,LogEOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"LogEOpID requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(Log2Op* n)
{
if (checkOperator(n,Log2OpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"Log2OpID requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(Log10Op* n)
{
if (checkOperator(n,Log10OpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"Log10OpID requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(SquareRootOp* n)
{
if (checkOperator(n,SquareRootOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"SquareRootOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(CubeRootOp* n)
{
if (checkOperator(n,CubeRootOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"CubeRootOpID requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(FactorialOp* n)
{
if (checkOperator(n,FactorialOpID,1)) {
const Type* Ty1 = n->getOperand(0)->getType();
if (!Ty1->is(RealTypeID))
error(n,"FactorialOp requires real number operand");
}
}
template<> inline void
ValidateImpl::validate(PowerOp* n)
{
if (checkOperator(n,PowerOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(RealTypeID) || !Ty2->is(RealTypeID))
error(n,"LogEOpID requires two real number operands");
}
}
template<> inline void
ValidateImpl::validate(RootOp* n)
{
if (checkOperator(n,RootOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(RealTypeID) || !Ty2->is(RealTypeID))
error(n,"RootOp requires two real number operands");
}
}
template<> inline void
ValidateImpl::validate(GCDOp* n)
{
if (checkOperator(n,GCDOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(RealTypeID) || !Ty2->is(RealTypeID))
error(n,"GCDOp requires two real number operands");
}
}
template<> inline void
ValidateImpl::validate(LCMOp* n)
{
if (checkOperator(n,LCMOpID,2)) {
const Type* Ty1 = n->getOperand(0)->getType();
const Type* Ty2 = n->getOperand(1)->getType();
if (!Ty1->is(RealTypeID) || !Ty2->is(RealTypeID))
error(n,"LCMOp requires two real number operands");
}
}
template<> inline void
ValidateImpl::validate(StrInsertOp* n)
{
if (checkOperator(n,StrInsertOpID,3))
;
}
template<> inline void
ValidateImpl::validate(StrEraseOp* n)
{
if (checkOperator(n,StrEraseOpID,3))
;
}
template<> inline void
ValidateImpl::validate(StrReplaceOp* n)
{
if (checkOperator(n,StrReplaceOpID,4))
;
}
template<> inline void
ValidateImpl::validate(StrConcatOp* n)
{
if (checkOperator(n,StrConcatOpID,2))
;
}
template<> inline void
ValidateImpl::validate(OpenOp* n)
{
if (checkOperator(n,OpenOpID,1)) {
const Type* Ty = n->getOperand(0)->getType();
if (!isa<StringType>(Ty))
error(n,"OpenOp expects first operand to be a string");
}
}
template<> inline void
ValidateImpl::validate(CloseOp* n)
{
if (checkOperator(n,CloseOpID,1)) {
const Type* Ty = n->getOperand(0)->getType();
if (!isa<StreamType>(Ty))
error(n,"CloseOp expects first operand to be a stream");
}
}
template<> inline void
ValidateImpl::validate(ReadOp* n)
{
if (checkOperator(n,ReadOpID,2)) {
const Type* Ty = n->getOperand(0)->getType();
if (!isa<StreamType>(Ty))
error(n,"ReadOp expects first operand to be a stream");
Ty = n->getOperand(1)->getType();
if (!isa<BufferType>(Ty))
error(n,"ReadOp expects second operand to be a buffer");
}
}
template<> inline void
ValidateImpl::validate(WriteOp* n)
{
if (checkOperator(n,WriteOpID,2)) {
const Type* Ty = n->getOperand(0)->getType();
if (!isa<StreamType>(Ty))
error(n,"WriteOp expects first operand to be a stream");
Ty = n->getOperand(1)->getType();
switch (Ty->getID()) {
case BufferTypeID:
case TextTypeID:
case StringTypeID:
break;
default:
error(n,"WriteOp expects second operand to be a writable type");
break;
}
}
}
template<> inline void
ValidateImpl::validate(Bundle* n)
{
// FIXME: checkNode(n);
}
template<> inline void
ValidateImpl::validate(Import* n)
{
// FIXME: checkNode(n);
}
void
ValidateImpl::handle(Node* n,Pass::TraversalKinds k)
{
switch (n->getID())
{
case NoNodeID:
hlvmDeadCode("Invalid Node Kind");
break;
case AnyTypeID: validate(cast<AnyType>(n)); break;
case BooleanTypeID: validate(cast<BooleanType>(n)); break;
case CharacterTypeID: validate(cast<CharacterType>(n)); break;
case IntegerTypeID: validate(cast<IntegerType>(n)); break;
case RangeTypeID: validate(cast<RangeType>(n)); break;
case EnumerationTypeID: validate(cast<EnumerationType>(n)); break;
case RealTypeID: validate(cast<RealType>(n)); break;
case RationalTypeID: validate(cast<RationalType>(n)); break;
case TextTypeID: validate(cast<TextType>(n)); break;
case StringTypeID: validate(cast<StringType>(n)); break;
case StreamTypeID: validate(cast<StreamType>(n)); break;
case BufferTypeID: validate(cast<BufferType>(n)); break;
case PointerTypeID: validate(cast<PointerType>(n)); break;
case ArrayTypeID: validate(cast<ArrayType>(n)); break;
case VectorTypeID: validate(cast<VectorType>(n)); break;
case StructureTypeID: validate(cast<StructureType>(n)); break;
case SignatureTypeID: validate(cast<SignatureType>(n)); break;
case ContinuationTypeID: validate(cast<ContinuationType>(n)); break;
case OpaqueTypeID: validate(cast<OpaqueType>(n)); break;
case InterfaceID: /*validate(cast<InterfaceID>);*/ break;
case ClassID: /*validate(cast<ClassID>);*/ break;
case MethodID: /*validate(cast<MethodID>);*/ break;
case ImplementsID: /*validate(cast<ImplementsID>);*/ break;
case VariableID: validate(cast<Variable>(n)); break;
case FunctionID: validate(cast<Function>(n)); break;
case ProgramID: validate(cast<Program>(n)); break;
case BundleID: validate(cast<Bundle>(n)); break;
case BlockID: validate(cast<Block>(n)); break;
case ImportID: validate(cast<Import>(n)); break;
case CallOpID: validate(cast<CallOp>(n)); break;
case InvokeOpID: /*validate(cast<InvokeOp>(n));*/ break;
case DispatchOpID: /*validate(cast<DispatchOp>(n));*/ break;
case CreateContOpID: /*validate(cast<CreateContOp>(n));*/ break;
case CallWithContOpID: /*validate(cast<CallWithContOp>(n));*/ break;
case ThrowOpID: /*validate(cast<ThrowOp>(n));*/ break;
case ReturnOpID: validate(cast<ReturnOp>(n)); break;
case ResultOpID: validate(cast<ResultOp>(n)); break;
case ContinueOpID: validate(cast<ContinueOp>(n)); break;
case BreakOpID: validate(cast<BreakOp>(n)); break;
case SelectOpID: validate(cast<SelectOp>(n)); break;
case WhileOpID: validate(cast<WhileOp>(n)); break;
case UnlessOpID: validate(cast<UnlessOp>(n)); break;
case UntilOpID: validate(cast<UntilOp>(n)); break;
case LoopOpID: validate(cast<LoopOp>(n)); break;
case SwitchOpID: validate(cast<SwitchOp>(n)); break;
case LoadOpID: validate(cast<LoadOp>(n)); break;
case StoreOpID: validate(cast<StoreOp>(n)); break;
case GetIndexOpID: validate(cast<GetIndexOp>(n)); break;
case GetFieldOpID: validate(cast<GetFieldOp>(n)); break;
case AllocateOpID: validate(cast<AllocateOp>(n)); break;
case DeallocateOpID: validate(cast<DeallocateOp>(n)); break;
case ReallocateOpID: /*validate(cast<ReallocateOp>(n));*/ break;
case GetOpID: validate(cast<GetOp>(n)); break;
case AutoVarOpID: validate(cast<AutoVarOp>(n)); break;
case NegateOpID: validate(cast<NegateOp>(n)); break;
case ComplementOpID: validate(cast<ComplementOp>(n)); break;
case PreIncrOpID: validate(cast<PreIncrOp>(n)); break;
case PostIncrOpID: validate(cast<PostIncrOp>(n)); break;
case PreDecrOpID: validate(cast<PreDecrOp>(n)); break;
case PostDecrOpID: validate(cast<PostDecrOp>(n)); break;
case SizeOfOpID: validate(cast<SizeOfOp>(n)); break;
case ConvertOpID: validate(cast<ConvertOp>(n)); break;
case AddOpID: validate(cast<AddOp>(n)); break;
case SubtractOpID: validate(cast<SubtractOp>(n)); break;
case MultiplyOpID: validate(cast<MultiplyOp>(n)); break;
case DivideOpID: validate(cast<DivideOp>(n)); break;
case ModuloOpID: validate(cast<ModuloOp>(n)); break;
case BAndOpID: validate(cast<BAndOp>(n)); break;
case BOrOpID: validate(cast<BOrOp>(n)); break;
case BXorOpID: validate(cast<BXorOp>(n)); break;
case BNorOpID: validate(cast<BNorOp>(n)); break;
case NotOpID: validate(cast<NotOp>(n)); break;
case AndOpID: validate(cast<AndOp>(n)); break;
case OrOpID: validate(cast<OrOp>(n)); break;
case NorOpID: validate(cast<NorOp>(n)); break;
case XorOpID: validate(cast<XorOp>(n)); break;
case LessThanOpID: validate(cast<LessThanOp>(n)); break;
case GreaterThanOpID: validate(cast<GreaterThanOp>(n)); break;
case LessEqualOpID: validate(cast<LessEqualOp>(n)); break;
case GreaterEqualOpID: validate(cast<GreaterEqualOp>(n)); break;
case EqualityOpID: validate(cast<EqualityOp>(n)); break;
case InequalityOpID: validate(cast<InequalityOp>(n)); break;
case IsPInfOpID: validate(cast<IsPInfOp>(n)); break;
case IsNInfOpID: validate(cast<IsNInfOp>(n)); break;
case IsNanOpID: validate(cast<IsNanOp>(n)); break;
case TruncOpID: validate(cast<TruncOp>(n)); break;
case RoundOpID: validate(cast<RoundOp>(n)); break;
case FloorOpID: validate(cast<FloorOp>(n)); break;
case CeilingOpID: validate(cast<CeilingOp>(n)); break;
case LogEOpID: validate(cast<LogEOp>(n)); break;
case Log2OpID: validate(cast<Log2Op>(n)); break;
case Log10OpID: validate(cast<Log10Op>(n)); break;
case SquareRootOpID: validate(cast<SquareRootOp>(n)); break;
case CubeRootOpID: validate(cast<CubeRootOp>(n)); break;
case FactorialOpID: validate(cast<FactorialOp>(n)); break;
case PowerOpID: validate(cast<PowerOp>(n)); break;
case RootOpID: validate(cast<RootOp>(n)); break;
case GCDOpID: validate(cast<GCDOp>(n)); break;
case LCMOpID: validate(cast<LCMOp>(n)); break;
case StrInsertOpID: validate(cast<StrInsertOp>(n)); break;
case StrEraseOpID: validate(cast<StrEraseOp>(n)); break;
case StrReplaceOpID: validate(cast<StrReplaceOp>(n)); break;
case StrConcatOpID: validate(cast<StrConcatOp>(n)); break;
case LengthOpID: validate(cast<LengthOp>(n)); break;
case OpenOpID: validate(cast<OpenOp>(n)); break;
case CloseOpID: validate(cast<CloseOp>(n)); break;
case ReadOpID: validate(cast<ReadOp>(n)); break;
case WriteOpID: validate(cast<WriteOp>(n)); break;
case PositionOpID: /*validate(cast<PositionOp>(n));*/ break;
case ConstantAnyID: validate(cast<ConstantAny>(n)); break;
case ConstantBooleanID: validate(cast<ConstantBoolean>(n)); break;
case ConstantCharacterID: validate(cast<ConstantCharacter>(n)); break;
case ConstantEnumeratorID: validate(cast<ConstantEnumerator>(n)); break;
case ConstantIntegerID: validate(cast<ConstantInteger>(n)); break;
case ConstantRealID: validate(cast<ConstantReal>(n)); break;
case ConstantStringID: validate(cast<ConstantString>(n)); break;
case ConstantPointerID: validate(cast<ConstantPointer>(n)); break;
case ConstantArrayID: validate(cast<ConstantArray>(n)); break;
case ConstantVectorID: validate(cast<ConstantVector>(n)); break;
case ConstantStructureID: validate(cast<ConstantStructure>(n)); break;
case ConstantContinuationID: validate(cast<ConstantContinuation>(n)); break;
case ConstantExpressionID: validate(cast<ConstantExpression>(n)); break;
break; // Not implemented yet
case DocumentationID:
/// Nothing to validate (any doc is a good thing :)
break;
default:
hlvmDeadCode("Invalid Node Kind");
break;
}
}
}
Pass*
Pass::new_ValidatePass()
{
return new ValidateImpl();
}
bool
hlvm::validate(AST* tree)
{
PassManager* PM = PassManager::create();
Pass* pass = Pass::new_ValidatePass();
PM->addPass( pass );
PM->runOn(tree);
delete PM;
bool result = pass->passed();
delete pass;
return result;
}