blob: 6e9da715d9a29feab994e970dca1c6ab70086e5c [file] [log] [blame]
//===-- Generate Random Test Cases ------------------------------*- 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 tools/hlvm-gentestcase/Generate.cpp
/// @author Reid Spencer <reid@hlvm.org> (original author)
/// @date 2006/05/04
/// @since 0.1.0
/// @brief Implements the test case generator for hlvm-gentestcase
//===----------------------------------------------------------------------===//
#include <hlvm/Base/Assert.h>
#include <hlvm/AST/AST.h>
#include <hlvm/AST/Constants.h>
#include <hlvm/AST/Linkables.h>
#include <hlvm/AST/Arithmetic.h>
#include <hlvm/AST/BooleanOps.h>
#include <hlvm/AST/ControlFlow.h>
#include <hlvm/AST/MemoryOps.h>
#include <hlvm/AST/InputOutput.h>
#include <hlvm/AST/RealMath.h>
#include <hlvm/AST/StringOps.h>
#include <hlvm/AST/Bundle.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/ADT/StringExtras.h>
#include <stdlib.h>
#include <time.h>
using namespace llvm;
using namespace hlvm;
static cl::opt<unsigned>
Complexity("complexity",
cl::init(5),
cl::desc("Specify complexity of generated code"),
cl::value_desc("num"));
static cl::opt<unsigned>
TypeComplexity("type-complexity",
cl::init(4),
cl::desc("Specify type complexity of generated code"),
cl::value_desc("num"));
static cl::opt<unsigned>
Seed("seed",
cl::init(unsigned(time(0))),
cl::desc("Specify random number generator seed"),
cl::value_desc("num"));
static cl::opt<unsigned>
Size("size",cl::desc("Specify size of generated code"),
cl::value_desc("num"));
typedef std::vector<Value*> ValueList;
typedef std::map<const Type*,ValueList> TypeValueMap;
typedef std::vector<Type*> TypeList;
static AST* ast = 0;
static URI* uri = 0;
static Bundle* bundle = 0;
static Program* program = 0;
static unsigned line = 0;
static TypeValueMap values;
static TypeList types;
inline Locator*
getLocator()
{
return ast->new_Locator(uri,++line);
}
inline
int64_t randRange(int64_t low, int64_t high)
{
if (high > low)
return int64_t(random()) % (high-low) + low;
else if (low > high)
return int64_t(random()) % (low-high) + high;
else
return low;
}
inline
uint64_t randRange(uint64_t low, uint64_t high, bool discriminate)
{
if (high > low)
return uint64_t(random()) % (high-low) + low;
else if (low > high)
return uint64_t(random()) % (low-high) + high;
else
return low;
}
static Type*
genType(unsigned limit)
{
Type* result = 0;
bool intrinsic_type = randRange(0,TypeComplexity) < TypeComplexity/3;
if (--limit == 0)
intrinsic_type = true;
if (intrinsic_type) {
IntrinsicTypes theType = IntrinsicTypes(
randRange(FirstIntrinsicType,LastIntrinsicType));
// FIXME: Don't allow things we can't code gen right now
if (theType == u128Ty)
theType = u64Ty;
else if (theType == s128Ty)
theType = s64Ty;
else if (theType == f128Ty || theType == f96Ty || theType == f80Ty)
theType = f64Ty;
else if (theType == bufferTy || theType == streamTy || theType == textTy)
theType = s32Ty;
else if (theType >= qs16Ty && theType <= qu128Ty)
theType = u32Ty;
return bundle->getIntrinsicType(theType);
}
NodeIDs id = NodeIDs(randRange(FirstTypeID,LastTypeID));
switch (id) {
case BooleanTypeID:
result = bundle->getIntrinsicType(boolTy);
break;
case CharacterTypeID:
result = bundle->getIntrinsicType(charTy);
break;
case StringTypeID:
result = bundle->getIntrinsicType(stringTy);
break;
case AnyTypeID:
case BufferTypeID:
case StreamTypeID:
case TextTypeID:
/* FALL THROUGH (unimplemented) */
case SignatureTypeID:
/* FALL THROUGH (unimplemented) */
case RationalTypeID:
/* FALL THROUGH (unimplemented) */
case IntegerTypeID:
{
Locator* loc = getLocator();
std::string name = "int_" + utostr(line);
bool isSigned = randRange(0,TypeComplexity+2,true) < (TypeComplexity+2)/2;
result =
ast->new_IntegerType(name,bundle,randRange(4,64,true),isSigned,loc);
break;
}
case RangeTypeID:
{
Locator* loc = getLocator();
std::string name = "range_" + utostr(line);
int64_t limit = randRange(0,8000000);
result = ast->new_RangeType(name,bundle,-limit,limit,loc);
break;
}
case EnumerationTypeID:
{
Locator* loc = getLocator();
std::string name = "enum_" + utostr(line);
EnumerationType* E = ast->new_EnumerationType(name,bundle,loc);
unsigned numEnums = randRange(1,TypeComplexity,true);
for (unsigned i = 0; i < numEnums; i++)
E->addEnumerator(name + "_" + utostr(i));
result = E;
break;
}
case RealTypeID:
{
Locator* loc = getLocator();
std::string name = "real_" + utostr(line);
result =
ast->new_RealType(name,bundle,randRange(8,52),randRange(8,11),loc);
break;
}
case PointerTypeID:
{
Locator* loc = getLocator();
std::string name = "ptr_" + utostr(line);
result = ast->new_PointerType(name,bundle,genType(limit),loc);
break;
}
case ArrayTypeID:
{
Locator* loc = getLocator();
std::string name = "array_" + utostr(line);
result = ast->new_ArrayType(name,bundle,
genType(limit),randRange(1,Size*10),loc);
break;
}
case VectorTypeID:
{
Locator* loc = getLocator();
std::string name = "vector_" + utostr(line);
result = ast->new_VectorType(name,bundle,
genType(limit),randRange(1,Size*10),loc);
break;
}
case OpaqueTypeID:
case ContinuationTypeID:
/* FALL THROUGH (not implemented) */
case StructureTypeID:
{
Locator* loc = getLocator();
std::string name = "struct_" + utostr(line);
StructureType* S = ast->new_StructureType(name,bundle,loc);
unsigned numFields = randRange(1,Size,true);
for (unsigned i = 0; i < numFields; ++i) {
Field* fld = ast->new_Field(name+"_"+utostr(i),
genType(limit),getLocator());
S->addField(fld);
}
result = S;
break;
}
default:
hlvmAssert(!"Invalid Type?");
}
hlvmAssert(result && "No type defined?");
return result;
}
static Type*
genType()
{
bool shouldGenNewType = randRange(0,5) < TypeComplexity;
if (types.empty() || shouldGenNewType) {
Type* Ty = genType(TypeComplexity);
types.push_back(Ty);
return Ty;
}
return types[ randRange(0,types.size()-1) ];
}
static ConstantString*
getConstantString(const std::string& str)
{
typedef std::map<std::string,ConstantString*> strmap;
static strmap stringmap;
strmap::iterator I = stringmap.find(str);
if (I == stringmap.end()) {
Locator* loc = getLocator();
Type* Ty = bundle->getIntrinsicType(stringTy);
ConstantString* cstr = ast->new_ConstantString(
std::string("cstr_")+utostr(line),bundle,Ty,str,loc);
stringmap[str] = cstr;
return cstr;
}
return I->second;
}
static ConstantInteger*
getConstantInteger(int32_t val)
{
typedef std::map<int32_t,ConstantInteger*> intmap;
static intmap integermap;
intmap::iterator I = integermap.find(val);
if (I == integermap.end()) {
Locator* loc = getLocator();
Type* Ty = bundle->getIntrinsicType(intTy);
std::string val_str = itostr(val);
ConstantInteger* cint = ast->new_ConstantInteger(
std::string("cint_")+utostr(line),bundle,Ty,val_str,10,loc);
integermap[val] = cint;
return cint;
}
return I->second;
}
static Value*
genValue(const Type* Ty, bool is_constant = false)
{
if (!is_constant && randRange(0,Complexity) < Complexity/2) {
// First look up an existing value in the map
TypeValueMap::iterator VI = values.find(Ty);
if (VI != values.end()) {
ValueList& VL = VI->second;
unsigned index = randRange(0,VL.size()-1,true);
Value* result = VL[index];
hlvmAssert(result->getType() == Ty);
return result;
}
}
// Didn't find one in the map, so generate a variable or constant
ConstantValue* C = 0;
Locator* loc = getLocator();
NodeIDs id = Ty->getID();
switch (id) {
case BooleanTypeID:
{
bool val = randRange(0,Complexity+2) < (Complexity+2)/2;
C = ast->new_ConstantBoolean(
std::string("cbool_") + utostr(line), bundle,Ty, val, loc);
break;
}
case CharacterTypeID:
{
std::string val;
if ( randRange(0,20) < Complexity ) {
static char hexDigits[16] = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
val = '#';
val += hexDigits[ randRange(0,15) ];
val += hexDigits[ randRange(0,15) ];
val += hexDigits[ randRange(0,15) ];
val += hexDigits[ randRange(0,15) ];
} else {
val += char(randRange(36,126));
}
C = ast->new_ConstantCharacter(
std::string("cchar_") + utostr(line), bundle,Ty, val, loc);
break;
}
case StringTypeID:
{
std::string val;
unsigned numChars = randRange(1,Size+Complexity,true);
for (unsigned i = 0 ; i < numChars; i++)
val += char(randRange(35,126));
C = getConstantString(val);
break;
}
case BufferTypeID:
case StreamTypeID:
case TextTypeID:
case AnyTypeID:
// hlvmAssert("Can't get constant for these types");
/* FALL THROUGH (unimplemented) */
case SignatureTypeID:
/* FALL THROUGH (unimplemented) */
case RationalTypeID:
/* FALL THROUGH (unimplemented) */
case IntegerTypeID:
{
std::string name = "cint_" + utostr(line);
const IntegerType* IntTy = llvm::cast<IntegerType>(Ty);
unsigned bits = (IntTy->getBits() < 63 ? IntTy->getBits() : 63) - 2;
int64_t max = 1 << bits;
std::string val_str;
if (IntTy->isSigned()) {
int64_t val = randRange(int64_t(-max),int64_t(max-1));
val_str = itostr(val);
} else {
uint64_t val = randRange(uint64_t(0),uint64_t(max),true);
val_str = utostr(val);
}
C = ast->new_ConstantInteger(name,bundle,Ty,val_str,10,loc);
break;
}
case RangeTypeID:
{
std::string name = "crange_" + utostr(line);
const RangeType* RngTy = llvm::cast<RangeType>(Ty);
int64_t val = randRange(RngTy->getMin(),RngTy->getMax());
std::string val_str( itostr(val) );
C = ast->new_ConstantInteger(name,bundle,RngTy,val_str,10,loc);
break;
}
case EnumerationTypeID:
{
std::string name = "cenum_" + utostr(line);
const EnumerationType* ETy = llvm::cast<EnumerationType>(Ty);
unsigned val = randRange(0,ETy->size()-1);
EnumerationType::const_iterator I = ETy->begin() + val;
C = ast->new_ConstantEnumerator(name,bundle,ETy,*I,loc);
break;
}
case RealTypeID:
{
double val = double(randRange(-10000000,10000000));
std::string val_str(ftostr(val));
C = ast->new_ConstantReal(
std::string("cf32_")+utostr(line),bundle,Ty,val_str,loc);
break;
}
case PointerTypeID:
{
const PointerType* PT = llvm::cast<PointerType>(Ty);
const Type* refType = PT->getElementType();
std::string name = std::string("cptr_") + utostr(line);
Value* refValue = genValue(refType,true);
C = ast->new_ConstantPointer(name, bundle,PT,
cast<ConstantValue>(refValue),loc);
break;
}
case ArrayTypeID:
{
const ArrayType* AT = llvm::cast<ArrayType>(Ty);
const Type* elemTy = AT->getElementType();
unsigned nElems = randRange(1,AT->getMaxSize(),true);
std::vector<ConstantValue*> elems;
std::string name = "cptr_" + utostr(line);
for (unsigned i = 0; i < nElems; i++)
elems.push_back(cast<ConstantValue>(genValue(elemTy,true)));
C = ast->new_ConstantArray(name, bundle,AT,elems, loc);
break;
}
case VectorTypeID:
{
const VectorType* VT = llvm::cast<VectorType>(Ty);
const Type* elemTy = VT->getElementType();
uint64_t nElems = VT->getSize();
std::string name = "cvect_" + utostr(line);
std::vector<ConstantValue*> elems;
for (unsigned i = 0; i < nElems; i++)
elems.push_back(cast<ConstantValue>(genValue(elemTy,true)));
C = ast->new_ConstantVector(name, bundle, VT, elems, loc);
break;
}
case OpaqueTypeID:
/* FALL THROUGH (not implemented) */
case ContinuationTypeID:
/* FALL THROUGH (not implemented) */
case StructureTypeID:
{
const StructureType* ST = llvm::cast<StructureType>(Ty);
std::string name = "cstruct_" + utostr(line);
std::vector<ConstantValue*> elems;
for (StructureType::const_iterator I = ST->begin(), E = ST->end();
I != E; ++I) {
const Type* Ty = (*I)->getType();
Value* V = genValue(Ty,true);
elems.push_back(cast<ConstantValue>(V));
}
C = ast->new_ConstantStructure(name, bundle, ST, elems, loc);
break;
}
default:
hlvmAssert(!"Invalid Type?");
}
// Give the constant a home
C->setParent(bundle);
// Make it either an initialized variable or just the constant itself.
Value* result = 0;
if (is_constant || (randRange(0,Complexity+2) < (Complexity+2)/2))
result = C;
else {
Variable* var =
ast->new_Variable(C->getName()+"_var",bundle,C->getType(),loc);
var->setIsConstant(false);
var->setInitializer(C);
var->setParent(bundle);
result = var;
}
// Memoize the result
values[result->getType()].push_back(result);
return result;
}
static inline GetOp*
getReference(const Value* val)
{
hlvmAssert(isa<Linkable>(val) || isa<Constant>(val) || isa<AutoVarOp>(val));
return ast->new_GetOp(val,getLocator());
}
static inline Operator*
genValueAsOperator(const Type *Ty, bool is_constant = false)
{
Value* V = genValue(Ty,is_constant);
Operator* O = getReference(V);
if (isa<Linkable>(V))
O = ast->new_UnaryOp<LoadOp>(O,bundle,getLocator());
return O;
}
static CallOp*
genCallTo(Function* F)
{
std::vector<Operator*> args;
Operator* O = ast->new_GetOp(F,getLocator());
args.push_back(O);
const SignatureType* sig = F->getSignature();
for (SignatureType::const_iterator I = sig->begin(), E = sig->end();
I != E; ++I)
{
const Type* argTy = (*I)->getType();
Operator* O = genValueAsOperator(argTy);
hlvmAssert(argTy == O->getType());
args.push_back(O);
}
return ast->new_MultiOp<CallOp>(args,bundle,getLocator());
}
static Operator*
genIndex(Operator* V)
{
if (V->typeis<StructureType>()) {
const StructureType* Ty = cast<StructureType>(V->getType());
const NamedType* fldname = Ty->getField(randRange(0,Ty->size()-1));
return ast->new_GetFieldOp(V,fldname->getName(),getLocator());
} else if (V->typeis<ArrayType>()) {
const ArrayType* Ty = cast<ArrayType>(V->getType());
Constant* cindex = getConstantInteger(0); //FIXME: gen rand at runtime
GetOp* index = getReference(cindex);
return ast->new_GetIndexOp(V,index,getLocator());
} else if (V->typeis<VectorType>()) {
const VectorType* Ty = cast<VectorType>(V->getType());
int64_t idx = randRange(0,Ty->getSize()-1);
Constant* cindex = getConstantInteger(idx);
GetOp* index = getReference(cindex);
return ast->new_GetIndexOp(V,index,getLocator());
} else if (V->typeis<StringType>()) {
const StringType* Ty = cast<StringType>(V->getType());
Constant* cindex = getConstantInteger(0); //FIXME: gen rand at runtime
GetOp* index = getReference(cindex);
return ast->new_GetIndexOp(V,index,getLocator());
} else if (V->typeis<PointerType>()) {
Constant* cindex = getConstantInteger(0);
GetOp* index = getReference(cindex);
return ast->new_GetIndexOp(V,index,getLocator());
} else
hlvmAssert(!"Can't index this type!");
return 0;
}
static Operator* genExpression(Operator* Val, int depth);
static Operator* genUnaryExpression(Operator* Val);
static Operator* genBinaryExpression(Operator* V1, Operator*V2);
static Operator*
genBooleanUnary(Operator* V1)
{
hlvmAssert(V1->getType()->getID() == BooleanTypeID);
return ast->new_UnaryOp<NotOp>(V1,bundle,getLocator());
}
static Operator*
genBooleanBinary(Operator* V1, Operator* V2)
{
hlvmAssert(V1->getType()->getID() == BooleanTypeID);
hlvmAssert(V2->getType()->getID() == BooleanTypeID);
Operator* result = 0;
NodeIDs id = NodeIDs(randRange(AndOpID,InequalityOpID));
switch (id) {
case AndOpID:
result = ast->new_BinaryOp<AndOp>(V1,V2,bundle,getLocator());
break;
case OrOpID:
result = ast->new_BinaryOp<OrOp>(V1,V2,bundle,getLocator());
break;
case NorOpID:
result = ast->new_BinaryOp<NorOp>(V1,V2,bundle,getLocator());
break;
case XorOpID:
result = ast->new_BinaryOp<XorOp>(V1,V2,bundle,getLocator());
break;
case LessThanOpID:
result = ast->new_BinaryOp<LessThanOp>(V1,V2,bundle,getLocator());
break;
case GreaterThanOpID:
result = ast->new_BinaryOp<GreaterThanOp>(V1,V2,bundle,getLocator());
break;
case LessEqualOpID:
result = ast->new_BinaryOp<LessEqualOp>(V1,V2,bundle,getLocator());
break;
case GreaterEqualOpID:
result = ast->new_BinaryOp<GreaterEqualOp>(V1,V2,bundle,getLocator());
break;
case EqualityOpID:
result = ast->new_BinaryOp<EqualityOp>(V1,V2,bundle,getLocator());
break;
case InequalityOpID:
result = ast->new_BinaryOp<InequalityOp>(V1,V2,bundle,getLocator());
break;
default:
hlvmAssert(!"Invalid boolean op ID");
}
return result;
}
static Operator*
genCharacterUnary(Operator* V1)
{
hlvmAssert(V1->getType()->getID() == CharacterTypeID);
return 0;
}
static Operator*
genCharacterBinary(Operator* V1, Operator* V2)
{
hlvmAssert(V1->getType()->getID() == CharacterTypeID);
hlvmAssert(V2->getType()->getID() == CharacterTypeID);
return 0;
}
static Operator*
genIntegerUnary(Operator* V1)
{
hlvmAssert(V1->getType()->isIntegralType());
Operator* result = 0;
NodeIDs id = NodeIDs(randRange(NegateOpID, PostDecrOpID));
switch (id) {
case PreIncrOpID:
case PostIncrOpID:
case PreDecrOpID:
case PostDecrOpID:
case NegateOpID:
result = ast->new_UnaryOp<NegateOp>(V1,bundle,getLocator());
break;
case ComplementOpID:
result = ast->new_UnaryOp<ComplementOp>(V1,bundle,getLocator());
break;
default:
hlvmAssert(!"Invalid unary op id for integer");
result = ast->new_UnaryOp<ComplementOp>(V1,bundle,getLocator());
}
return result;
}
static Operator*
genIntegerBinary(Operator* V1, Operator* V2)
{
hlvmAssert(V1->getType()->isIntegralType());
hlvmAssert(V2->getType()->isIntegralType());
Operator* result = 0;
NodeIDs id = NodeIDs(randRange(AddOpID, BNorOpID));
switch (id) {
case AddOpID:
result = ast->new_BinaryOp<AddOp>(V1,V2,bundle,getLocator());
break;
case SubtractOpID:
result = ast->new_BinaryOp<SubtractOp>(V1,V2,bundle,getLocator());
break;
case MultiplyOpID:
result = ast->new_BinaryOp<MultiplyOp>(V1,V2,bundle,getLocator());
break;
case DivideOpID:
result = ast->new_BinaryOp<DivideOp>(V1,V2,bundle,getLocator());
break;
case ModuloOpID:
result = ast->new_BinaryOp<ModuloOp>(V1,V2,bundle,getLocator());
break;
case BAndOpID:
result = ast->new_BinaryOp<BAndOp>(V1,V2,bundle,getLocator());
break;
case BOrOpID:
result = ast->new_BinaryOp<BOrOp>(V1,V2,bundle,getLocator());
break;
case BXorOpID:
result = ast->new_BinaryOp<BXorOp>(V1,V2,bundle,getLocator());
break;
case BNorOpID:
result = ast->new_BinaryOp<BNorOp>(V1,V2,bundle,getLocator());
break;
default:
hlvmAssert(!"Invalid binary op id for integer");
result = ast->new_BinaryOp<AddOp>(V1,V2,bundle,getLocator());
}
return result;
}
static Operator*
genRealUnary(Operator* V1)
{
hlvmAssert(V1->getType()->getID() == RealTypeID);
Operator* result = 0;
NodeIDs id = NodeIDs(randRange(TruncOpID,FactorialOpID));
switch (id) {
case TruncOpID:
result = ast->new_UnaryOp<TruncOp>(V1,bundle,getLocator());
break;
case RoundOpID:
result = ast->new_UnaryOp<RoundOp>(V1,bundle,getLocator());
break;
case FloorOpID:
result = ast->new_UnaryOp<FloorOp>(V1,bundle,getLocator());
break;
case CeilingOpID:
result = ast->new_UnaryOp<CeilingOp>(V1,bundle,getLocator());
break;
case LogEOpID:
result = ast->new_UnaryOp<LogEOp>(V1,bundle,getLocator());
break;
case Log2OpID:
result = ast->new_UnaryOp<Log2Op>(V1,bundle,getLocator());
break;
case Log10OpID:
result = ast->new_UnaryOp<Log10Op>(V1,bundle,getLocator());
break;
case SquareRootOpID:
result = ast->new_UnaryOp<SquareRootOp>(V1,bundle,getLocator());
break;
case CubeRootOpID:
result = ast->new_UnaryOp<CubeRootOp>(V1,bundle,getLocator());
break;
case FactorialOpID:
result = ast->new_UnaryOp<FactorialOp>(V1,bundle,getLocator());
break;
default:
hlvmAssert(!"Invalid unary op id for integer");
result = ast->new_UnaryOp<CeilingOp>(V1,bundle,getLocator());
}
return result;
}
static Operator*
genRealBinary(Operator* V1, Operator* V2)
{
hlvmAssert(V1->getType()->getID() == RealTypeID);
hlvmAssert(V2->getType()->getID() == RealTypeID);
Operator* result = 0;
NodeIDs id = hlvm::NodeIDs(randRange(PowerOpID, LCMOpID));
switch (id) {
case PowerOpID:
result = ast->new_BinaryOp<PowerOp>(V1,V2,bundle,getLocator());
break;
case RootOpID:
result = ast->new_BinaryOp<RootOp>(V1,V2,bundle,getLocator());
break;
case GCDOpID:
result = ast->new_BinaryOp<GCDOp>(V1,V2,bundle,getLocator());
break;
case LCMOpID:
result = ast->new_BinaryOp<LCMOp>(V1,V2,bundle,getLocator());
break;
default:
hlvmAssert(!"Invalid binary op id for integer");
result = ast->new_BinaryOp<PowerOp>(V1,V2,bundle,getLocator());
}
return result;
}
static Operator*
genStringUnary(Operator* V1)
{
hlvmAssert(isa<StringType>(V1->getType()));
Operator* str = genValueAsOperator(bundle->getIntrinsicType(stringTy));
return ast->new_BinaryOp<StrConcatOp>(V1,str,bundle,getLocator());
}
static Operator*
genStringBinary(Operator* V1, Operator* V2)
{
hlvmAssert(isa<StringType>(V1->getType()));
hlvmAssert(isa<StringType>(V2->getType()));
ConstantInteger* CI = getConstantInteger(0);
GetOp* get = ast->new_GetOp(CI,getLocator());
return ast->new_BinaryOp<StrConcatOp>(V1,V2,bundle,getLocator());
}
static Operator*
genArrayUnary(Operator* V1)
{
hlvmAssert(isa<ArrayType>(V1->getType()));
const ArrayType* Ty = cast<ArrayType>(V1->getType());
Block* blk = ast->new_Block(getLocator());
AutoVarOp* val1 = ast->new_AutoVarOp("val1",Ty,getLocator());
V1->setParent(val1);
AutoVarOp* result = ast->new_AutoVarOp("result",Ty,getLocator());
blk->addOperand(result);
Type* ptr_type = bundle->getPointerTo(Ty->getElementType());
ConstantInteger* null = getConstantInteger(0);
GetOp* getNull1 = ast->new_GetOp(null,getLocator());
AutoVarOp* ptr1 = ast->new_AutoVarOp("ptr1",ptr_type,getLocator());
blk->addOperand(ptr1);
GetIndexOp* idx1 =
ast->new_GetIndexOp(val1,getNull1,getLocator());
idx1->setParent(ptr1);
GetOp* getNull2 = ast->new_GetOp(null,getLocator());
AutoVarOp* ptr2 = ast->new_AutoVarOp("ptr2",ptr_type,getLocator());
blk->addOperand(ptr2);
Value* val2 = genValue(Ty);
GetOp* getVal2 = ast->new_GetOp(val2,getLocator());
GetIndexOp* idx2 =
ast->new_GetIndexOp(getVal2,getNull2,getLocator());
idx2->setParent(ptr2);
GetOp* getNull3 = ast->new_GetOp(null,getLocator());
AutoVarOp* ptr3 = ast->new_AutoVarOp("ptr3",ptr_type,getLocator());
blk->addOperand(ptr3);
GetIndexOp* idx3 =
ast->new_GetIndexOp(result,getNull3,getLocator());
idx3->setParent(ptr3);
AutoVarOp* end = ast->new_AutoVarOp("end",ptr_type,getLocator());
blk->addOperand(end);
GetOp* get1 = ast->new_GetOp(val1,getLocator());
LengthOp* len1 = ast->new_UnaryOp<LengthOp>(get1,bundle,getLocator());
GetOp* get2 = ast->new_GetOp(val2,getLocator());
LengthOp* len2 = ast->new_UnaryOp<LengthOp>(get2,bundle,getLocator());
LessThanOp* le = ast->new_BinaryOp<LessThanOp>(len1,len2,bundle,getLocator());
GetOp* get3 = ast->new_GetOp(val1,getLocator());
LengthOp* len3 = ast->new_UnaryOp<LengthOp>(get3,bundle,getLocator());
GetOp* get4 = ast->new_GetOp(val2,getLocator());
LengthOp* len4 = ast->new_UnaryOp<LengthOp>(get4,bundle,getLocator());
SelectOp* sel =
ast->new_TernaryOp<SelectOp>(le,len3,len4,bundle,getLocator());
GetIndexOp* endIndex =
ast->new_GetIndexOp(val1,sel,getLocator());
endIndex->setParent(end);
LessThanOp* cond =
ast->new_BinaryOp<LessThanOp>(ptr1,end,bundle,getLocator());
Block* whileBlock = ast->new_Block(getLocator());
GetOp* get5 = ast->new_GetOp(ptr1,getLocator());
PostIncrOp* incr1 = ast->new_UnaryOp<PostIncrOp>(get5,bundle,getLocator());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(incr1,bundle,getLocator());
GetOp* get6 = ast->new_GetOp(ptr2,getLocator());
PostIncrOp* incr2 = ast->new_UnaryOp<PostIncrOp>(get6,bundle,getLocator());
LoadOp* load2 = ast->new_UnaryOp<LoadOp>(incr2,bundle,getLocator());
Operator* expr = genBinaryExpression(load1,load2);
GetOp* get7 = ast->new_GetOp(ptr3,getLocator());
PostIncrOp* incr3 = ast->new_UnaryOp<PostIncrOp>(get7,bundle,getLocator());
StoreOp* store = ast->new_BinaryOp<StoreOp>(incr3,expr,bundle,getLocator());
whileBlock->addOperand(store);
WhileOp* whilst =
ast->new_BinaryOp<WhileOp>(cond,whileBlock,bundle,getLocator());
blk->addOperand(whilst);
GetOp* get = ast->new_GetOp(result,getLocator());
ResultOp* rslt = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
blk->addOperand(rslt);
return blk;
}
static Operator*
genArrayBinary(Operator* V1, Operator* V2)
{
hlvmAssert(isa<ArrayType>(V1->getType()));
hlvmAssert(isa<ArrayType>(V2->getType()));
hlvmAssert(V1->getType() == V2->getType());
const ArrayType* Ty = cast<ArrayType>(V1->getType());
Block* blk = ast->new_Block(getLocator());
AutoVarOp* val1 = ast->new_AutoVarOp("val1",Ty,getLocator());
V1->setParent(val1);
AutoVarOp* val2 = ast->new_AutoVarOp("val2",Ty,getLocator());
V2->setParent(val2);
AutoVarOp* result = ast->new_AutoVarOp("result",Ty,getLocator());
blk->addOperand(result);
Type* ptr_type = bundle->getPointerTo(Ty->getElementType());
ConstantInteger* null = getConstantInteger(0);
GetOp* getNull1 = ast->new_GetOp(null,getLocator());
AutoVarOp* ptr1 = ast->new_AutoVarOp("ptr1",ptr_type,getLocator());
blk->addOperand(ptr1);
GetOp* val1get = ast->new_GetOp(val1,getLocator());
GetIndexOp* idx1 =
ast->new_GetIndexOp(val1get,getNull1,getLocator());
idx1->setParent(ptr1);
GetOp* getNull2 = ast->new_GetOp(null,getLocator());
AutoVarOp* ptr2 = ast->new_AutoVarOp("ptr2",ptr_type,getLocator());
blk->addOperand(ptr2);
GetOp* val2get = ast->new_GetOp(val2,getLocator());
GetIndexOp* idx2 =
ast->new_GetIndexOp(val2get,getNull2,getLocator());
idx2->setParent(ptr2);
GetOp* getNull3 = ast->new_GetOp(null,getLocator());
AutoVarOp* ptr3 = ast->new_AutoVarOp("ptr3",ptr_type,getLocator());
blk->addOperand(ptr3);
GetIndexOp* idx3 =
ast->new_GetIndexOp(result,getNull3,getLocator());
idx3->setParent(ptr3);
AutoVarOp* end = ast->new_AutoVarOp("end",ptr_type,getLocator());
blk->addOperand(end);
GetOp* get1 = ast->new_GetOp(val1,getLocator());
LengthOp* len1 = ast->new_UnaryOp<LengthOp>(get1,bundle,getLocator());
GetOp* get2 = ast->new_GetOp(val2,getLocator());
LengthOp* len2 = ast->new_UnaryOp<LengthOp>(val2,bundle,getLocator());
LessThanOp* le = ast->new_BinaryOp<LessThanOp>(len1,len2,bundle,getLocator());
GetOp* get3 = ast->new_GetOp(val1,getLocator());
LengthOp* len3 = ast->new_UnaryOp<LengthOp>(get3,bundle,getLocator());
GetOp* get4 = ast->new_GetOp(val2,getLocator());
LengthOp* len4 = ast->new_UnaryOp<LengthOp>(get4,bundle,getLocator());
SelectOp* sel =
ast->new_TernaryOp<SelectOp>(le,len3,len4,bundle,getLocator());
GetIndexOp* endIndex =
ast->new_GetIndexOp(ast->new_GetOp(val1,getLocator()),sel,getLocator());
endIndex->setParent(end);
LessThanOp* cond =
ast->new_BinaryOp<LessThanOp>(ptr1,end,bundle,getLocator());
Block* whileBlock = ast->new_Block(getLocator());
GetOp* get5 = ast->new_GetOp(ptr1,getLocator());
PostIncrOp* incr1 = ast->new_UnaryOp<PostIncrOp>(get5,bundle,getLocator());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(incr1,bundle,getLocator());
GetOp* get6 = ast->new_GetOp(ptr2,getLocator());
PostIncrOp* incr2 = ast->new_UnaryOp<PostIncrOp>(get6,bundle,getLocator());
LoadOp* load2 = ast->new_UnaryOp<LoadOp>(incr2,bundle,getLocator());
Operator* expr = genBinaryExpression(load1,load2);
GetOp* get7 = ast->new_GetOp(ptr3,getLocator());
PostIncrOp* incr3 = ast->new_UnaryOp<PostIncrOp>(get7,bundle,getLocator());
StoreOp* store = ast->new_BinaryOp<StoreOp>(incr3,expr,bundle,getLocator());
whileBlock->addOperand(store);
WhileOp* whilst =
ast->new_BinaryOp<WhileOp>(cond,whileBlock,bundle,getLocator());
blk->addOperand(whilst);
GetOp* get = ast->new_GetOp(result,getLocator());
ResultOp* rslt = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
blk->addOperand(rslt);
return blk;
}
static Operator*
genVectorUnary(Operator* V1)
{
hlvmAssert(isa<VectorType>(V1->getType()));
const VectorType* Ty = cast<VectorType>(V1->getType());
Block* blk = ast->new_Block(getLocator());
AutoVarOp* autovar = ast->new_AutoVarOp("result",Ty,getLocator());
autovar->setParent(blk);
AutoVarOp* val1 = ast->new_AutoVarOp("val1",Ty,getLocator());
V1->setParent(val1);
for (unsigned i = 0; i < Ty->getSize(); ++i) {
ConstantInteger* cst = getConstantInteger(i);
GetOp* index = ast->new_GetOp(cst,getLocator());
GetIndexOp* elem =
ast->new_GetIndexOp(ast->new_GetOp(val1,getLocator()),index,getLocator());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(elem,bundle,getLocator());
Operator* expr = genUnaryExpression(load1);
GetOp* get = ast->new_GetOp(autovar,getLocator());
GetIndexOp* elem2 =
ast->new_GetIndexOp(get,index,getLocator());
StoreOp* store =
ast->new_BinaryOp<StoreOp>(elem2,expr,bundle,getLocator());
blk->addOperand(store);
}
GetOp* get = ast->new_GetOp(autovar,getLocator());
ResultOp* result = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
blk->addOperand(result);
return blk;
}
static Operator*
genVectorBinary(Operator* V1, Operator* V2)
{
hlvmAssert(isa<VectorType>(V1->getType()));
hlvmAssert(isa<VectorType>(V2->getType()));
hlvmAssert(V1->getType() == V2->getType());
const VectorType* Ty = llvm::cast<VectorType>(V1->getType());
Block* blk = ast->new_Block(getLocator());
AutoVarOp* autovar = ast->new_AutoVarOp("result",Ty,getLocator());
autovar->setParent(blk);
AutoVarOp* val1 = ast->new_AutoVarOp("val1",Ty,getLocator());
V1->setParent(val1);
AutoVarOp* val2 = ast->new_AutoVarOp("val2",Ty,getLocator());
V2->setParent(val2);
for (unsigned i = 0; i < Ty->getSize(); ++i)
{
ConstantInteger* cst = getConstantInteger(i);
GetOp* index = ast->new_GetOp(cst,getLocator());
GetIndexOp* elem1 =
ast->new_GetIndexOp(ast->new_GetOp(val1,getLocator()),index,getLocator());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(elem1,bundle,getLocator());
GetIndexOp* elem2 =
ast->new_GetIndexOp(val2,index,getLocator());
LoadOp* load2 = ast->new_UnaryOp<LoadOp>(elem1,bundle,getLocator());
Operator* expr = genBinaryExpression(load1,load2);
GetOp* get = ast->new_GetOp(autovar,getLocator());
GetIndexOp* elem3 =
ast->new_GetIndexOp(get,index,getLocator());
StoreOp* store =
ast->new_BinaryOp<StoreOp>(elem3,expr,bundle,getLocator());
blk->addOperand(store);
}
GetOp* get = ast->new_GetOp(autovar,getLocator());
ResultOp* result = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
blk->addOperand(result);
return blk;
}
static Operator*
genStructureUnary(Operator* V1)
{
hlvmAssert(V1->getType()->getID() == StructureTypeID);
const StructureType* Ty = llvm::cast<StructureType>(V1->getType());
Block* blk = ast->new_Block(getLocator());
AutoVarOp* autovar = ast->new_AutoVarOp("result",Ty,getLocator());
autovar->setParent(blk);
AutoVarOp* val1 = ast->new_AutoVarOp("val1",Ty,getLocator());
V1->setParent(val1);
for (StructureType::const_iterator I = Ty->begin(), E = Ty->end();
I != E; ++I)
{
const std::string& fldName = (*I)->getName();
GetFieldOp* getField1 =
ast->new_GetFieldOp(val1,fldName,getLocator());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(getField1,bundle,getLocator());
Operator* expr = genUnaryExpression(load1);
GetOp* get = ast->new_GetOp(autovar,getLocator());
GetFieldOp* getField3 =
ast->new_GetFieldOp(get,fldName,getLocator());
StoreOp* store =
ast->new_BinaryOp<StoreOp>(getField3,expr,bundle,getLocator());
blk->addOperand(store);
}
GetOp* get = ast->new_GetOp(autovar,getLocator());
ResultOp* result = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
blk->addOperand(result);
return blk;
}
static Operator*
genStructureBinary(Operator* V1, Operator* V2)
{
hlvmAssert(V1->getType()->getID() == StructureTypeID);
hlvmAssert(V2->getType()->getID() == StructureTypeID);
hlvmAssert(V1->getType() == V2->getType());
const StructureType* Ty = llvm::cast<StructureType>(V1->getType());
Block* blk = ast->new_Block(getLocator());
AutoVarOp* autovar = ast->new_AutoVarOp("result",Ty,getLocator());
autovar->setParent(blk);
AutoVarOp* val1 = ast->new_AutoVarOp("val1",Ty,getLocator());
V1->setParent(val1);
AutoVarOp* val2 = ast->new_AutoVarOp("val2",Ty,getLocator());
V2->setParent(val2);
for (StructureType::const_iterator I = Ty->begin(), E = Ty->end();
I != E; ++I)
{
GetFieldOp* getField1 =
ast->new_GetFieldOp(val1,(*I)->getName(),getLocator());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(getField1,bundle,getLocator());
GetFieldOp* getField2 =
ast->new_GetFieldOp(val2,(*I)->getName(),getLocator());
LoadOp* load2 = ast->new_UnaryOp<LoadOp>(getField2,bundle,getLocator());
Operator* expr = genBinaryExpression(load1,load2);
GetOp* get = ast->new_GetOp(autovar,getLocator());
GetFieldOp* getField3 =
ast->new_GetFieldOp(get,(*I)->getName(),getLocator());
StoreOp* store =
ast->new_BinaryOp<StoreOp>(getField3,expr,bundle,getLocator());
blk->addOperand(store);
}
GetOp* get = ast->new_GetOp(autovar,getLocator());
ResultOp* result = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
blk->addOperand(result);
return blk;
}
static Operator*
genPointerUnary(Operator* V1)
{
hlvmAssert(V1->getType()->getID() == PointerTypeID);
LoadOp* load = ast->new_UnaryOp<LoadOp>(V1,bundle,getLocator());
return genUnaryExpression(load);
}
static Operator*
genPointerBinary(Operator* V1, Operator* V2)
{
hlvmAssert(V1->getType()->getID() == PointerTypeID);
hlvmAssert(V2->getType()->getID() == PointerTypeID);
hlvmAssert(V1->getType() == V2->getType());
LoadOp* load1 = ast->new_UnaryOp<LoadOp>(V1,bundle,getLocator());
LoadOp* load2 = ast->new_UnaryOp<LoadOp>(V2,bundle,getLocator());
return genBinaryExpression(load1,load2);
}
static Operator*
genUnaryExpression(Operator* Val)
{
switch(Val->getType()->getID()) {
case BooleanTypeID: return genBooleanUnary(Val); break;
case CharacterTypeID: return genCharacterUnary(Val); break;
case AnyTypeID:
case BufferTypeID:
case StreamTypeID:
case TextTypeID:
case SignatureTypeID:
case RationalTypeID:
// FALL THROUGH: Not Implemented
case RangeTypeID:
case IntegerTypeID:
case EnumerationTypeID: return genIntegerUnary(Val); break;
case RealTypeID: return genRealUnary(Val); break;
case StringTypeID: return genStringUnary(Val); break;
case PointerTypeID: return genPointerUnary(Val); break;
case ArrayTypeID: return genArrayUnary(Val); break;
case VectorTypeID: return genVectorUnary(Val); break;
case OpaqueTypeID:
case ContinuationTypeID:
case StructureTypeID: return genStructureUnary(Val); break;
default:
hlvmDeadCode("Invalid type?");
return 0;
break;
}
}
static Operator*
genBinaryExpression(Operator* V1, Operator*V2)
{
switch (V1->getType()->getID()) {
case BooleanTypeID: return genBooleanBinary(V1,V2); break;
case CharacterTypeID: return genCharacterBinary(V1,V2); break;
case AnyTypeID:
case BufferTypeID:
case StreamTypeID:
case TextTypeID:
case SignatureTypeID:
case RationalTypeID:
// FALL THROUGH: Not Implemented
case RangeTypeID:
case IntegerTypeID:
case EnumerationTypeID: return genIntegerBinary(V1,V2);break;
case RealTypeID: return genRealBinary(V1,V2); break;
case StringTypeID: return genStringBinary(V1,V2); break;
case PointerTypeID: return genPointerBinary(V1,V2); break;
case ArrayTypeID: return genArrayBinary(V1,V2); break;
case VectorTypeID: return genVectorBinary(V1,V2); break;
case OpaqueTypeID:
case ContinuationTypeID:
case StructureTypeID: return genStructureBinary(V1,V2);break;
default: hlvmDeadCode("Invalid Type");
return 0;
}
}
// Forward declare
static Function* genFunction(const Type* resultType, int depth);
static Operator*
genExpression(Operator* Val, int depth)
{
if (depth > 0) {
// Generate a function
Function* F = genFunction(Val->getType(), depth-1);
// Generate a call to that function
return genCallTo(F);
}
// 50% Randomly generate a unary expression
if (5 <= randRange(1,10))
return genUnaryExpression(Val);
// Otherwise generate a binary expression
return genBinaryExpression(Val,genValueAsOperator(Val->getType()));
}
static void
genMergeExpression(AutoVarOp* op1, Operator* op2, Block* B)
{
// Assert precondition
hlvmAssert(op1->getType() == op2->getType());
// Get the type of the thing to be merged
const Type* Ty = op2->getType();
// If its just a numeric type, simply add the merged value into the autovar
if (Ty->isNumericType()) {
Operator* get1 = ast->new_GetOp(op1,getLocator());
Operator* avload = ast->new_UnaryOp<LoadOp>(get1,bundle,getLocator());
Operator* add = ast->new_BinaryOp<AddOp>(avload,op2,bundle,getLocator());
Operator* get2 = ast->new_GetOp(op1,getLocator());
Operator* store = ast->new_BinaryOp<StoreOp>(get2,add,bundle,getLocator());
store->setParent(B);
return;
}
// If its a VectorType or ArrayType then add all the elements, if possible
if (const UniformContainerType* UCT =
llvm::dyn_cast<UniformContainerType>(op2->getType())) {
const Type* elemType = UCT->getElementType();
if (elemType->isNumericType()) {
Operator* get1 = ast->new_GetOp(op1,getLocator());
Operator* avload = ast->new_UnaryOp<LoadOp>(get1,bundle,getLocator());
Operator* add = ast->new_BinaryOp<AddOp>(avload,op2,bundle,getLocator());
Operator* get2 = ast->new_GetOp(op1,getLocator());
Operator* store =ast->new_BinaryOp<StoreOp>(get2,add,bundle,getLocator());
store->setParent(B);
return;
}
}
// For everything else, just store the result
Operator* get = ast->new_GetOp(op1,getLocator());
Operator* op = ast->new_BinaryOp<StoreOp>(get,op2,bundle,getLocator());
op->setParent(B);
return;
}
static Block*
genFunctionBody(Function* F, int depth)
{
// Create the function body block and initialize it
Block* B = ast->new_Block(getLocator());
B->setParent(F);
B->setLabel(F->getName() + "_body");
// Create an autovar for the function result
AutoVarOp* result =
ast->new_AutoVarOp(F->getName() + "_result",
F->getResultType(),getLocator());
result->setParent(B);
// Generate "Size" expressions
for (unsigned i = 0; i < Size; i++) {
// Get a value for the basis of the expression
Operator* theValue = 0;
if (F->size() > 0) {
// Pick an argument randomly to use in the expression
unsigned argNum = randRange(0,F->size()-1);
Argument* arg = F->getArgument(argNum);
theValue = ast->new_GetOp(arg,getLocator());
} else {
theValue = genValueAsOperator(F->getResultType());
}
// Generate the expression
Operator* expr = genExpression(theValue,depth);
// Merge the current value of the autovar result with the generated
// expression.
genMergeExpression(result,expr,B);
}
// Create the block result.
GetOp* get = ast->new_GetOp(result,getLocator());
ResultOp* rslt = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
rslt->setParent(B);
// Done, Return the new block
return B;
}
static Function*
genFunction(const Type* resultType, int depth)
{
// Get the function name
Locator* loc = getLocator();
std::string name = "func_" + utostr(line);
// Generate a random number of arguments
unsigned numArgs = int(randRange(0,int(Complexity)));
// Get the signature
std::string sigName = name + "_type";
SignatureType* sig = ast->new_SignatureType(sigName,bundle,resultType,loc);
if (randRange(0,Complexity) > int(Complexity/3))
sig->setIsVarArgs(true);
for (unsigned i = 0; i < numArgs; ++i )
{
std::string name = "arg_" + utostr(i+1);
Parameter* param = ast->new_Parameter(name,resultType,loc);
sig->addParameter(param);
}
sig->setParent(bundle);
// Determine the kind of linkage for this function
LinkageKinds LK = LinkageKinds(randRange(ExternalLinkage,InternalLinkage));
if (LK == AppendingLinkage)
LK = InternalLinkage;
// Create the function and set its linkage kind
Function* F = ast->new_Function(name,bundle,sig,loc);
F->setLinkageKind(LK);
// Create the body of the function
Block* blk = genFunctionBody(F,depth-1);
// Insert the return operator
ReturnOp* ret = ast->new_NilaryOp<ReturnOp>(bundle,getLocator());
ret->setParent(blk);
// Install the function in the value map
values[sig].push_back(F);
// Make the function belong to the bundle
F->setParent(bundle);
return F;
}
AST*
GenerateTestCase(const std::string& pubid, const std::string& bundleName)
{
// Seed the random number generator
srandom(Seed);
// Create the top level node of the tree
ast = AST::create();
ast->setPublicID(pubid);
ast->setSystemID(bundleName);
// Get a URI for this tree
uri = ast->new_URI(pubid);
// Create a bundle to place the program in.
bundle = ast->new_Bundle(bundleName,getLocator());
// Create a program node for the generated test program
program = ast->new_Program(bundleName,bundle,getLocator());
const SignatureType* SigTy = program->getSignature();
// Create the function body block and initialize it
Block* B = ast->new_Block(getLocator());
B->setParent(program);
B->setLabel(program->getName() + "_body");
// Create an autovar for the function result
AutoVarOp* result =
ast->new_AutoVarOp(program->getName() + "_result",
program->getResultType(),getLocator());
result->setParent(B);
// Generate calls to "Size" random functions
for (unsigned i = 0; i < Size; i++) {
// Generate a function to a random type
Type* Ty = genType();
Function* F = genFunction(Ty, Complexity);
// Generate a call to that function
CallOp* call = genCallTo(F);
// Coalesce the result of the random function into the autovar we
// created for the result of this block.
if (Ty->isNumericType()) {
Operator* cvt =
ast->new_ConvertOp(call,program->getResultType(),getLocator());
genMergeExpression(result,cvt,B);
}
}
// Create the block result.
GetOp* get = ast->new_GetOp(result,getLocator());
ResultOp* rslt = ast->new_UnaryOp<ResultOp>(get,bundle,getLocator());
rslt->setParent(B);
// Insert the return instruction in that block
ReturnOp* ret = ast->new_NilaryOp<ReturnOp>(bundle,getLocator());
ret->setParent(B);
// Make the program a child of the bundle last so it is output last.
program->setParent(bundle);
// Done.
return ast;
}