Add support for 'unmasked' function qualifier.

This commit is contained in:
Matt Pharr
2012-06-20 15:36:00 -07:00
parent 46716aada3
commit 007a734595
9 changed files with 91 additions and 53 deletions

21
ctx.cpp
View File

@@ -3235,11 +3235,9 @@ FunctionEmitContext::CallInst(llvm::Value *func, const FunctionType *funcType,
SetInternalMask(callMask);
// bitcast the i32/64 function pointer to the actual function
// pointer type (the variant that includes a mask).
llvm::Type *llvmFuncType =
funcType->LLVMFunctionType(g->ctx, true);
llvm::Type *llvmFPtrType =
llvm::PointerType::get(llvmFuncType, 0);
// pointer type.
llvm::Type *llvmFuncType = funcType->LLVMFunctionType(g->ctx);
llvm::Type *llvmFPtrType = llvm::PointerType::get(llvmFuncType, 0);
llvm::Value *fptrCast = IntToPtrInst(fptr, llvmFPtrType);
// Call the function: callResult = call ftpr(args, args, call mask)
@@ -3344,7 +3342,6 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
AssertPos(currentPos, llvm::StructType::classof(pt->getElementType()));
llvm::StructType *argStructType =
static_cast<llvm::StructType *>(pt->getElementType());
AssertPos(currentPos, argStructType->getNumElements() == argVals.size() + 1);
llvm::Function *falloc = m->module->getFunction("ISPCAlloc");
AssertPos(currentPos, falloc != NULL);
@@ -3371,11 +3368,13 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
StoreInst(argVals[i], ptr);
}
// copy in the mask
llvm::Value *mask = GetFullMask();
llvm::Value *ptr = AddElementOffset(argmem, argVals.size(), NULL,
"funarg_mask");
StoreInst(mask, ptr);
if (argStructType->getNumElements() == argVals.size() + 1) {
// copy in the mask
llvm::Value *mask = GetFullMask();
llvm::Value *ptr = AddElementOffset(argmem, argVals.size(), NULL,
"funarg_mask");
StoreInst(mask, ptr);
}
// And emit the call to the user-supplied task launch function, passing
// a pointer to the task function being called and a pointer to the

View File

@@ -57,6 +57,7 @@ lPrintTypeQualifiers(int typeQualifiers) {
if (typeQualifiers & TYPEQUAL_SIGNED) printf("signed ");
if (typeQualifiers & TYPEQUAL_UNSIGNED) printf("unsigned ");
if (typeQualifiers & TYPEQUAL_EXPORT) printf("export ");
if (typeQualifiers & TYPEQUAL_UNMASKED) printf("unmasked ");
}
@@ -296,6 +297,7 @@ Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0);
bool isExported = ((typeQualifiers & TYPEQUAL_EXPORT) != 0);
bool isConst = ((typeQualifiers & TYPEQUAL_CONST) != 0);
bool isUnmasked = ((typeQualifiers & TYPEQUAL_UNMASKED) != 0);
if (hasUniformQual && hasVaryingQual) {
Error(pos, "Can't provide both \"uniform\" and \"varying\" qualifiers.");
@@ -305,11 +307,15 @@ Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
Error(pos, "\"task\" qualifier illegal in variable declaration.");
return;
}
if (kind != DK_FUNCTION && isUnmasked) {
Error(pos, "\"unmasked\" qualifier illegal in variable declaration.");
return;
}
if (kind != DK_FUNCTION && isExported) {
Error(pos, "\"export\" qualifier illegal in variable declaration.");
return;
}
Variability variability(Variability::Unbound);
if (hasUniformQual)
variability = Variability::Uniform;
@@ -507,7 +513,8 @@ Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
bool isExternC = ds && (ds->storageClass == SC_EXTERN_C);
bool isExported = ds && ((ds->typeQualifiers & TYPEQUAL_EXPORT) != 0);
bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0);
bool isUnmasked = ds && ((ds->typeQualifiers & TYPEQUAL_UNMASKED) != 0);
if (isExported && isTask) {
Error(pos, "Function can't have both \"task\" and \"export\" "
"qualifiers");
@@ -523,6 +530,9 @@ Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
"qualifiers");
return;
}
if (isUnmasked && isExported)
Warning(pos, "\"unmasked\" qualifier is redundant for exported "
"functions.");
if (child == NULL) {
AssertPos(pos, m->errorCount > 0);
@@ -531,7 +541,7 @@ Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
const FunctionType *functionType =
new FunctionType(returnType, args, argNames, argDefaults,
argPos, isTask, isExported, isExternC);
argPos, isTask, isExported, isExternC, isUnmasked);
// handle any explicit __declspecs on the function
if (ds != NULL) {

1
decl.h
View File

@@ -74,6 +74,7 @@ class Declarator;
#define TYPEQUAL_UNSIGNED (1<<5)
#define TYPEQUAL_INLINE (1<<6)
#define TYPEQUAL_EXPORT (1<<7)
#define TYPEQUAL_UNMASKED (1<<8)
/** @brief Representation of the declaration specifiers in a declaration.

View File

@@ -223,13 +223,15 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
for (unsigned int i = 0; i < args.size(); ++i)
lCopyInTaskParameter(i, structParamPtr, args, ctx);
// Copy in the mask as well.
int nArgs = (int)args.size();
// The mask is the last parameter in the argument structure
llvm::Value *ptr = ctx->AddElementOffset(structParamPtr, nArgs, NULL,
"task_struct_mask");
llvm::Value *ptrval = ctx->LoadInst(ptr, "mask");
ctx->SetFunctionMask(ptrval);
if (type->isUnmasked == false) {
// Copy in the mask as well.
int nArgs = (int)args.size();
// The mask is the last parameter in the argument structure
llvm::Value *ptr = ctx->AddElementOffset(structParamPtr, nArgs, NULL,
"task_struct_mask");
llvm::Value *ptrval = ctx->LoadInst(ptr, "mask");
ctx->SetFunctionMask(ptrval);
}
// Copy threadIndex and threadCount into stack-allocated storage so
// that their symbols point to something reasonable.
@@ -270,9 +272,13 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
// don't have a mask parameter, so set it to be all on. This
// happens for exmaple with 'export'ed functions that the app
// calls.
if (argIter == function->arg_end())
if (argIter == function->arg_end()) {
Assert(type->isUnmasked || type->isExported);
ctx->SetFunctionMask(LLVMMaskAllOn);
}
else {
Assert(type->isUnmasked == false);
// Otherwise use the mask to set the entry mask value
argIter->setName("__mask");
Assert(argIter->getType() == LLVMTypes::MaskType);
@@ -297,9 +303,10 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
bool checkMask = (type->isTask == true) ||
((function->hasFnAttr(llvm::Attribute::AlwaysInline) == false) &&
costEstimate > CHECK_MASK_AT_FUNCTION_START_COST);
checkMask &= (type->isUnmasked == false);
checkMask &= (g->target.maskingIsFree == false);
checkMask &= (g->opt.disableCoherentControlFlow == false);
if (checkMask) {
llvm::Value *mask = ctx->GetFunctionMask();
llvm::Value *allOn = ctx->All(mask);
@@ -423,8 +430,7 @@ Function::GenerateIR() {
Assert(type != NULL);
if (type->isExported) {
if (!type->isTask) {
llvm::FunctionType *ftype =
type->LLVMFunctionType(g->ctx);
llvm::FunctionType *ftype = type->LLVMFunctionType(g->ctx, true);
llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::ExternalLinkage;
std::string functionName = sym->name;
if (g->mangleFunctionsWithTarget)

9
lex.ll
View File

@@ -71,9 +71,9 @@ static int allTokens[] = {
TOKEN_INT, TOKEN_INT8, TOKEN_INT16, TOKEN_INT, TOKEN_INT64, TOKEN_LAUNCH,
TOKEN_NEW, TOKEN_NULL, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SOA, TOKEN_SIGNED,
TOKEN_SIZEOF, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_SYNC,
TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM, TOKEN_UNSIGNED,
TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE, TOKEN_STRING_C_LITERAL,
TOKEN_DOTDOTDOT,
TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM, TOKEN_UNMASKED,
TOKEN_UNSIGNED, TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE,
TOKEN_STRING_C_LITERAL, TOKEN_DOTDOTDOT,
TOKEN_FLOAT_CONSTANT,
TOKEN_INT32_CONSTANT, TOKEN_UINT32_CONSTANT,
TOKEN_INT64_CONSTANT, TOKEN_UINT64_CONSTANT,
@@ -142,6 +142,7 @@ void ParserInit() {
tokenToName[TOKEN_TRUE] = "true";
tokenToName[TOKEN_TYPEDEF] = "typedef";
tokenToName[TOKEN_UNIFORM] = "uniform";
tokenToName[TOKEN_UNMASKED] = "unmasked";
tokenToName[TOKEN_UNSIGNED] = "unsigned";
tokenToName[TOKEN_VARYING] = "varying";
tokenToName[TOKEN_VOID] = "void";
@@ -253,6 +254,7 @@ void ParserInit() {
tokenNameRemap["TOKEN_TRUE"] = "\'true\'";
tokenNameRemap["TOKEN_TYPEDEF"] = "\'typedef\'";
tokenNameRemap["TOKEN_UNIFORM"] = "\'uniform\'";
tokenNameRemap["TOKEN_UNMASKED"] = "\'unmasked\'";
tokenNameRemap["TOKEN_UNSIGNED"] = "\'unsigned\'";
tokenNameRemap["TOKEN_VARYING"] = "\'varying\'";
tokenNameRemap["TOKEN_VOID"] = "\'void\'";
@@ -396,6 +398,7 @@ task { RT; return TOKEN_TASK; }
true { RT; return TOKEN_TRUE; }
typedef { RT; return TOKEN_TYPEDEF; }
uniform { RT; return TOKEN_UNIFORM; }
unmasked { RT; return TOKEN_UNMASKED; }
unsigned { RT; return TOKEN_UNSIGNED; }
varying { RT; return TOKEN_VARYING; }
void { RT; return TOKEN_VOID; }

View File

@@ -707,9 +707,9 @@ Module::AddFunctionDeclaration(const std::string &name,
}
// Get the LLVM FunctionType
bool includeMask = (storageClass != SC_EXTERN_C);
bool disableMask = (storageClass == SC_EXTERN_C);
llvm::FunctionType *llvmFunctionType =
functionType->LLVMFunctionType(g->ctx, includeMask);
functionType->LLVMFunctionType(g->ctx, disableMask);
if (llvmFunctionType == NULL)
return;

View File

@@ -121,8 +121,8 @@ static const char *lBuiltinTokens[] = {
"goto", "if", "in", "inline",
"int", "int8", "int16", "int32", "int64", "launch", "new", "NULL",
"print", "return", "signed", "sizeof", "static", "struct", "switch",
"sync", "task", "true", "typedef", "uniform", "unsigned", "varying",
"void", "while", NULL
"sync", "task", "true", "typedef", "uniform", "unmasked", "unsigned",
"varying", "void", "while", NULL
};
static const char *lParamListTokens[] = {
@@ -189,7 +189,7 @@ struct ForeachDimension {
%token TOKEN_SIZEOF TOKEN_NEW TOKEN_DELETE TOKEN_IN
%token TOKEN_EXTERN TOKEN_EXPORT TOKEN_STATIC TOKEN_INLINE TOKEN_TASK TOKEN_DECLSPEC
%token TOKEN_UNIFORM TOKEN_VARYING TOKEN_TYPEDEF TOKEN_SOA
%token TOKEN_UNIFORM TOKEN_VARYING TOKEN_TYPEDEF TOKEN_SOA TOKEN_UNMASKED
%token TOKEN_CHAR TOKEN_INT TOKEN_SIGNED TOKEN_UNSIGNED TOKEN_FLOAT TOKEN_DOUBLE
%token TOKEN_INT8 TOKEN_INT16 TOKEN_INT64 TOKEN_CONST TOKEN_VOID TOKEN_BOOL
%token TOKEN_ENUM TOKEN_STRUCT TOKEN_TRUE TOKEN_FALSE
@@ -1011,6 +1011,11 @@ specifier_qualifier_list
"function declarations.");
$$ = $2;
}
else if ($1 == TYPEQUAL_UNMASKED) {
Error(@1, "\"unmasked\" qualifier is illegal outside of "
"function declarations.");
$$ = $2;
}
else if ($1 == TYPEQUAL_EXPORT) {
Error(@1, "\"export\" qualifier is illegal outside of "
"function declarations.");
@@ -1148,6 +1153,7 @@ type_qualifier
| TOKEN_UNIFORM { $$ = TYPEQUAL_UNIFORM; }
| TOKEN_VARYING { $$ = TYPEQUAL_VARYING; }
| TOKEN_TASK { $$ = TYPEQUAL_TASK; }
| TOKEN_UNMASKED { $$ = TYPEQUAL_UNMASKED; }
| TOKEN_EXPORT { $$ = TYPEQUAL_EXPORT; }
| TOKEN_INLINE { $$ = TYPEQUAL_INLINE; }
| TOKEN_SIGNED { $$ = TYPEQUAL_SIGNED; }

View File

@@ -1131,10 +1131,7 @@ PointerType::LLVMType(llvm::LLVMContext *ctx) const {
llvm::Type *ptype = NULL;
const FunctionType *ftype = CastType<FunctionType>(baseType);
if (ftype != NULL)
// Get the type of the function variant that takes the mask as the
// last parameter--i.e. we don't allow taking function pointers of
// exported functions.
ptype = llvm::PointerType::get(ftype->LLVMFunctionType(ctx, true), 0);
ptype = llvm::PointerType::get(ftype->LLVMFunctionType(ctx), 0);
else {
if (baseType == AtomicType::Void)
ptype = LLVMTypes::VoidPointerType;
@@ -2625,10 +2622,12 @@ ReferenceType::GetDIType(llvm::DIDescriptor scope) const {
///////////////////////////////////////////////////////////////////////////
// FunctionType
FunctionType::FunctionType(const Type *r, const llvm::SmallVector<const Type *, 8> &a,
FunctionType::FunctionType(const Type *r,
const llvm::SmallVector<const Type *, 8> &a,
SourcePos p)
: Type(FUNCTION_TYPE), isTask(false), isExported(false), isExternC(false),
returnType(r), paramTypes(a), paramNames(llvm::SmallVector<std::string, 8>(a.size(), "")),
isUnmasked(false), returnType(r), paramTypes(a),
paramNames(llvm::SmallVector<std::string, 8>(a.size(), "")),
paramDefaults(llvm::SmallVector<Expr *, 8>(a.size(), NULL)),
paramPositions(llvm::SmallVector<SourcePos, 8>(a.size(), p)) {
Assert(returnType != NULL);
@@ -2637,13 +2636,15 @@ FunctionType::FunctionType(const Type *r, const llvm::SmallVector<const Type *,
}
FunctionType::FunctionType(const Type *r, const llvm::SmallVector<const Type *, 8> &a,
FunctionType::FunctionType(const Type *r,
const llvm::SmallVector<const Type *, 8> &a,
const llvm::SmallVector<std::string, 8> &an,
const llvm::SmallVector<Expr *, 8> &ad,
const llvm::SmallVector<SourcePos, 8> &ap,
bool it, bool is, bool ec)
: Type(FUNCTION_TYPE), isTask(it), isExported(is), isExternC(ec), returnType(r),
paramTypes(a), paramNames(an), paramDefaults(ad), paramPositions(ap) {
bool it, bool is, bool ec, bool ium)
: Type(FUNCTION_TYPE), isTask(it), isExported(is), isExternC(ec),
isUnmasked(ium), returnType(r), paramTypes(a), paramNames(an),
paramDefaults(ad), paramPositions(ap) {
Assert(paramTypes.size() == paramNames.size() &&
paramNames.size() == paramDefaults.size() &&
paramDefaults.size() == paramPositions.size());
@@ -2743,7 +2744,7 @@ FunctionType::ResolveUnboundVariability(Variability v) const {
FunctionType *ret = new FunctionType(rt, pt, paramNames, paramDefaults,
paramPositions, isTask, isExported,
isExternC);
isExternC, isUnmasked);
ret->isSafe = isSafe;
ret->costOverride = costOverride;
@@ -2784,6 +2785,9 @@ FunctionType::GetString() const {
std::string
FunctionType::Mangle() const {
std::string ret = "___";
if (isUnmasked)
ret += "UM_";
for (unsigned int i = 0; i < paramTypes.size(); ++i)
if (paramTypes[i] == NULL)
Assert(m->errorCount > 0);
@@ -2865,6 +2869,8 @@ FunctionType::GetReturnTypeString() const {
ret += "export ";
if (isExternC)
ret += "extern \"C\" ";
if (isUnmasked)
ret += "unmasked ";
if (isSafe)
ret += "/*safe*/ ";
if (costOverride > 0) {
@@ -2872,14 +2878,15 @@ FunctionType::GetReturnTypeString() const {
sprintf(buf, "/*cost=%d*/ ", costOverride);
ret += buf;
}
return ret + returnType->GetString();
}
llvm::FunctionType *
FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const {
FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool removeMask) const {
if (isTask == true)
Assert(includeMask == true);
Assert(removeMask == false);
// Get the LLVM Type *s for the function arguments
std::vector<llvm::Type *> llvmArgTypes;
@@ -2899,7 +2906,7 @@ FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const {
}
// And add the function mask, if asked for
if (includeMask)
if (!(removeMask || isUnmasked))
llvmArgTypes.push_back(LLVMTypes::MaskType);
std::vector<llvm::Type *> callTypes;
@@ -3263,7 +3270,8 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
if (fta->isTask != ftb->isTask ||
fta->isExported != ftb->isExported ||
fta->isExternC != ftb->isExternC)
fta->isExternC != ftb->isExternC ||
fta->isUnmasked != ftb->isUnmasked)
return false;
if (fta->GetNumParameters() != ftb->GetNumParameters())

15
type.h
View File

@@ -841,7 +841,7 @@ public:
const llvm::SmallVector<std::string, 8> &argNames,
const llvm::SmallVector<Expr *, 8> &argDefaults,
const llvm::SmallVector<SourcePos, 8> &argPos,
bool isTask, bool isExported, bool isExternC);
bool isTask, bool isExported, bool isExternC, bool isUnmasked);
Variability GetVariability() const;
@@ -873,11 +873,11 @@ public:
const std::string GetReturnTypeString() const;
/** This method returns the LLVM FunctionType that corresponds to this
function type. The \c includeMask parameter indicates whether the
llvm::FunctionType should have a mask as the last argument in its
function signature. */
function type. The \c disableMask parameter indicates whether the
llvm::FunctionType should have the trailing mask parameter, if
present, removed from the return function signature. */
llvm::FunctionType *LLVMFunctionType(llvm::LLVMContext *ctx,
bool includeMask = false) const;
bool disableMask = false) const;
int GetNumParameters() const { return (int)paramTypes.size(); }
const Type *GetParameterType(int i) const;
@@ -897,6 +897,11 @@ public:
function in the source program. */
const bool isExternC;
/** Indicates whether the function doesn't take an implicit mask
parameter (and thus should start execution with an "all on"
mask). */
const bool isUnmasked;
/** Indicates whether this function has been declared to be safe to run
with an all-off mask. */
bool isSafe;