__declspec support for function declarations.

safe: indicates that the function can safely be called with an "all off"
execution mask.

costN: (N an integer) overrides the cost estimate for the function with
the given value.
This commit is contained in:
Matt Pharr
2012-03-21 15:37:04 -07:00
parent ddf350839a
commit ccd550dc52
5 changed files with 88 additions and 23 deletions

20
ast.cpp
View File

@@ -323,15 +323,23 @@ static bool
lCheckAllOffSafety(ASTNode *node, void *data) {
bool *okPtr = (bool *)data;
if (dynamic_cast<FunctionCallExpr *>(node) != NULL) {
// FIXME: If we could somehow determine that the function being
// called was safe (and all of the args Exprs were safe, then it'd
// be nice to be able to return true here. (Consider a call to
// e.g. floatbits() in the stdlib.) Unfortunately for now we just
// have to be conservative.
FunctionCallExpr *fce;
if ((fce = dynamic_cast<FunctionCallExpr *>(node)) != NULL) {
if (fce->func == NULL)
return false;
const Type *type = fce->func->GetType();
const PointerType *pt = dynamic_cast<const PointerType *>(type);
if (pt != NULL)
type = pt->GetBaseType();
const FunctionType *ftype = dynamic_cast<const FunctionType *>(type);
Assert(ftype != NULL);
if (ftype->isSafe == false) {
*okPtr = false;
return false;
}
}
if (dynamic_cast<AssertStmt *>(node) != NULL) {
// While it's fine to run the assert for varying tests, it's not

View File

@@ -538,10 +538,31 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
return NULL;
}
const Type *functionType =
const FunctionType *functionType =
new FunctionType(returnType, args, argNames, argDefaults,
argPos, isTask, isExported, isExternC);
functionType = functionType->ResolveUnboundVariability(Variability::Varying);
// handle any explicit __declspecs on the function
if (ds != NULL) {
for (int i = 0; i < (int)ds->declSpecList.size(); ++i) {
std::string str = ds->declSpecList[i].first;
SourcePos pos = ds->declSpecList[i].second;
if (str == "safe")
(const_cast<FunctionType *>(functionType))->isSafe = true;
else if (!strncmp(str.c_str(), "cost", 4)) {
int cost = atoi(str.c_str() + 4);
if (cost < 0)
Error(pos, "Negative function cost %d is illegal.",
cost);
(const_cast<FunctionType *>(functionType))->costOverride = cost;
}
else
Error(pos, "__declspec parameter \"%s\" unknown.", str.c_str());
}
}
return child->GetType(functionType, ds);
}
default:
@@ -555,6 +576,14 @@ const Type *
Declarator::GetType(DeclSpecs *ds) const {
const Type *baseType = ds->GetBaseType(pos);
const Type *type = GetType(baseType, ds);
if (ds->declSpecList.size() > 0 &&
type != NULL &
dynamic_cast<const FunctionType *>(type) == NULL) {
Error(pos, "__declspec specifiers for non-function type \"%s\" are "
"not used.", type->GetString().c_str());
}
return type;
}

View File

@@ -3518,17 +3518,22 @@ int
FunctionCallExpr::EstimateCost() const {
if (isLaunch)
return COST_TASK_LAUNCH;
else if (dynamic_cast<FunctionSymbolExpr *>(func) == NULL) {
// it's going through a function pointer
const Type *fpType = func->GetType();
if (fpType != NULL) {
Assert(dynamic_cast<const PointerType *>(fpType) != NULL);
if (fpType->IsUniformType())
return COST_FUNPTR_UNIFORM;
const Type *type = func->GetType();
if (type == NULL)
return 0;
const PointerType *pt = dynamic_cast<const PointerType *>(type);
if (pt != NULL)
type = type->GetBaseType();
const FunctionType *ftype = dynamic_cast<const FunctionType *>(type);
if (ftype->costOverride > -1)
return ftype->costOverride;
if (pt != NULL)
return pt->IsUniformType() ? COST_FUNPTR_UNIFORM : COST_FUNPTR_VARYING;
else
return COST_FUNPTR_VARYING;
}
}
return COST_FUNCALL;
}

View File

@@ -2329,6 +2329,8 @@ FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
paramDefaults(std::vector<ConstExpr *>(a.size(), NULL)),
paramPositions(std::vector<SourcePos>(a.size(), p)) {
Assert(returnType != NULL);
isSafe = false;
costOverride = -1;
}
@@ -2343,6 +2345,8 @@ FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
paramNames.size() == paramDefaults.size() &&
paramDefaults.size() == paramPositions.size());
Assert(returnType != NULL);
isSafe = false;
costOverride = -1;
}
@@ -2434,8 +2438,13 @@ FunctionType::ResolveUnboundVariability(Variability v) const {
pt.push_back(paramTypes[i]->ResolveUnboundVariability(v));
}
return new FunctionType(rt, pt, paramNames, paramDefaults,
paramPositions, isTask, isExported, isExternC);
FunctionType *ret = new FunctionType(rt, pt, paramNames, paramDefaults,
paramPositions, isTask, isExported,
isExternC);
ret->isSafe = isSafe;
ret->costOverride = costOverride;
return ret;
}
@@ -2457,6 +2466,12 @@ std::string
FunctionType::GetString() const {
std::string ret;
if (isTask) ret += "task ";
if (isSafe) ret += "/*safe*/ ";
if (costOverride > 0) {
char buf[32];
sprintf(buf, "/*cost=%d*/ ", costOverride);
ret += buf;
}
if (returnType != NULL)
ret += returnType->GetString();
else

8
type.h
View File

@@ -801,6 +801,14 @@ public:
function in the source program. */
const bool isExternC;
/** Indicates whether this function has been declared to be safe to run
with an all-off mask. */
bool isSafe;
/** If non-negative, this provides a user-supplied override to the cost
function estimate for the function. */
int costOverride;
private:
const Type * const returnType;