Add support for "new" and "delete" to the language.

Issue #139.
This commit is contained in:
Matt Pharr
2012-01-27 14:47:06 -08:00
parent bdba3cd97d
commit 664dc3bdda
26 changed files with 938 additions and 167 deletions

240
stmt.cpp
View File

@@ -119,153 +119,6 @@ DeclStmt::DeclStmt(const std::vector<VariableDeclaration> &v, SourcePos p)
}
static bool
lPossiblyResolveFunctionOverloads(Expr *expr, const Type *type) {
FunctionSymbolExpr *fse = NULL;
const FunctionType *funcType = NULL;
if (dynamic_cast<const PointerType *>(type) != NULL &&
(funcType = dynamic_cast<const FunctionType *>(type->GetBaseType())) &&
(fse = dynamic_cast<FunctionSymbolExpr *>(expr)) != NULL) {
// We're initializing a function pointer with a function symbol,
// which in turn may represent an overloaded function. So we need
// to try to resolve the overload based on the type of the symbol
// we're initializing here.
std::vector<const Type *> paramTypes;
for (int i = 0; i < funcType->GetNumParameters(); ++i)
paramTypes.push_back(funcType->GetParameterType(i));
if (fse->ResolveOverloads(expr->pos, paramTypes) == false)
return false;
}
return true;
}
/** Utility routine that emits code to initialize a symbol given an
initializer expression.
@param lvalue Memory location of storage for the symbol's data
@param symName Name of symbol (used in error messages)
@param symType Type of variable being initialized
@param initExpr Expression for the initializer
@param ctx FunctionEmitContext to use for generating instructions
@param pos Source file position of the variable being initialized
*/
static void
lInitSymbol(llvm::Value *lvalue, const char *symName, const Type *symType,
Expr *initExpr, FunctionEmitContext *ctx, SourcePos pos) {
if (initExpr == NULL)
// leave it uninitialized
return;
// If the initializer is a straight up expression that isn't an
// ExprList, then we'll see if we can type convert it to the type of
// the variable.
if (dynamic_cast<ExprList *>(initExpr) == NULL) {
if (lPossiblyResolveFunctionOverloads(initExpr, symType) == false)
return;
initExpr = TypeConvertExpr(initExpr, symType, "initializer");
if (initExpr != NULL) {
llvm::Value *initializerValue = initExpr->GetValue(ctx);
if (initializerValue != NULL)
// Bingo; store the value in the variable's storage
ctx->StoreInst(initializerValue, lvalue);
return;
}
}
// Atomic types and enums can't be initialized with { ... } initializer
// expressions, so print an error and return if that's what we've got
// here..
if (dynamic_cast<const AtomicType *>(symType) != NULL ||
dynamic_cast<const EnumType *>(symType) != NULL ||
dynamic_cast<const PointerType *>(symType) != NULL) {
ExprList *elist = dynamic_cast<ExprList *>(initExpr);
if (elist != NULL) {
if (elist->exprs.size() == 1)
lInitSymbol(lvalue, symName, symType, elist->exprs[0], ctx,
pos);
else
Error(initExpr->pos, "Expression list initializers can't be used for "
"variable \"%s\' with type \"%s\".", symName,
symType->GetString().c_str());
}
return;
}
const ReferenceType *rt = dynamic_cast<const ReferenceType *>(symType);
if (rt) {
if (!Type::Equal(initExpr->GetType(), rt)) {
Error(initExpr->pos, "Initializer for reference type \"%s\" must have same "
"reference type itself. \"%s\" is incompatible.",
rt->GetString().c_str(), initExpr->GetType()->GetString().c_str());
return;
}
llvm::Value *initializerValue = initExpr->GetValue(ctx);
if (initializerValue)
ctx->StoreInst(initializerValue, lvalue);
return;
}
// There are two cases for initializing structs, arrays and vectors;
// either a single initializer may be provided (float foo[3] = 0;), in
// which case all of the elements are initialized to the given value,
// or an initializer list may be provided (float foo[3] = { 1,2,3 }),
// in which case the elements are initialized with the corresponding
// values.
const CollectionType *collectionType =
dynamic_cast<const CollectionType *>(symType);
if (collectionType != NULL) {
std::string name;
if (dynamic_cast<const StructType *>(symType) != NULL)
name = "struct";
else if (dynamic_cast<const ArrayType *>(symType) != NULL)
name = "array";
else if (dynamic_cast<const VectorType *>(symType) != NULL)
name = "vector";
else
FATAL("Unexpected CollectionType in lInitSymbol()");
ExprList *exprList = dynamic_cast<ExprList *>(initExpr);
if (exprList != NULL) {
// The { ... } case; make sure we have the same number of
// expressions in the ExprList as we have struct members
int nInits = exprList->exprs.size();
if (nInits != collectionType->GetElementCount()) {
Error(initExpr->pos, "Initializer for %s \"%s\" requires "
"%d values; %d provided.", name.c_str(), symName,
collectionType->GetElementCount(), nInits);
return;
}
// Initialize each element with the corresponding value from
// the ExprList
for (int i = 0; i < nInits; ++i) {
llvm::Value *ep;
if (dynamic_cast<const StructType *>(symType) != NULL)
ep = ctx->AddElementOffset(lvalue, i, NULL, "element");
else
ep = ctx->GetElementPtrInst(lvalue, LLVMInt32(0), LLVMInt32(i),
PointerType::GetUniform(collectionType->GetElementType(i)),
"gep");
lInitSymbol(ep, symName, collectionType->GetElementType(i),
exprList->exprs[i], ctx, pos);
}
}
else
Error(initExpr->pos, "Can't assign type \"%s\" to \"%s\".",
initExpr->GetType()->GetString().c_str(),
collectionType->GetString().c_str());
return;
}
FATAL("Unexpected Type in lInitSymbol()");
}
static bool
lHasUnsizedArrays(const Type *type) {
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
@@ -333,7 +186,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
// zero value.
llvm::Constant *cinit = NULL;
if (initExpr != NULL) {
if (lPossiblyResolveFunctionOverloads(initExpr, sym->type) == false)
if (PossiblyResolveFunctionOverloads(initExpr, sym->type) == false)
continue;
// FIXME: we only need this for function pointers; it was
// already done for atomic types and enums in
@@ -377,8 +230,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
// And then get it initialized...
sym->parentFunction = ctx->GetFunction();
lInitSymbol(sym->storagePtr, sym->name.c_str(), sym->type,
initExpr, ctx, sym->pos);
InitSymbol(sym->storagePtr, sym->type, initExpr, ctx, sym->pos);
}
}
}
@@ -646,6 +498,15 @@ lCheckAllOffSafety(ASTNode *node, void *data) {
return false;
}
if (dynamic_cast<NewExpr *>(node) != NULL ||
dynamic_cast<DeleteStmt *>(node) != NULL) {
// We definitely don't want to run the uniform variants of these if
// the mask is all off. It's also worth skipping the overhead of
// executing the varying versions of them in the all-off mask case.
*okPtr = false;
return false;
}
if (g->target.allOffMaskIsSafe == true)
// Don't worry about memory accesses if we have a target that can
// safely run them with the mask all off
@@ -2880,3 +2741,82 @@ AssertStmt::EstimateCost() const {
return COST_ASSERT;
}
///////////////////////////////////////////////////////////////////////////
// DeleteStmt
DeleteStmt::DeleteStmt(Expr *e, SourcePos p)
: Stmt(p) {
expr = e;
}
void
DeleteStmt::EmitCode(FunctionEmitContext *ctx) const {
const Type *exprType;
if (expr == NULL || ((exprType = expr->GetType()) == NULL)) {
Assert(m->errorCount > 0);
return;
}
llvm::Value *exprValue = expr->GetValue(ctx);
if (exprValue == NULL) {
Assert(m->errorCount > 0);
return;
}
// Typechecking should catch this
Assert(dynamic_cast<const PointerType *>(exprType) != NULL);
if (exprType->IsUniformType()) {
// For deletion of a uniform pointer, we just need to cast the
// pointer type to a void pointer type, to match what
// __delete_uniform() from the builtins expects.
exprValue = ctx->BitCastInst(exprValue, LLVMTypes::VoidPointerType,
"ptr_to_void");
llvm::Function *func = m->module->getFunction("__delete_uniform");
Assert(func != NULL);
ctx->CallInst(func, NULL, exprValue, "");
}
else {
// Varying pointers are arrays of ints, and __delete_varying()
// takes a vector of i64s (even for 32-bit targets). Therefore, we
// only need to extend to 64-bit values on 32-bit targets before
// calling it.
llvm::Function *func = m->module->getFunction("__delete_varying");
Assert(func != NULL);
if (g->target.is32Bit)
exprValue = ctx->ZExtInst(exprValue, LLVMTypes::Int64VectorType,
"ptr_to_64");
ctx->CallInst(func, NULL, exprValue, "");
}
}
void
DeleteStmt::Print(int indent) const {
printf("%*cDelete Stmt", indent, ' ');
}
Stmt *
DeleteStmt::TypeCheck() {
const Type *exprType;
if (expr == NULL || ((exprType = expr->GetType()) == NULL))
return NULL;
if (dynamic_cast<const PointerType *>(exprType) == NULL) {
Error(pos, "Illegal to delete non-pointer type \"%s\".",
exprType->GetString().c_str());
return NULL;
}
return this;
}
int
DeleteStmt::EstimateCost() const {
return COST_DELETE;
}