Skip to content

Commit

Permalink
Support complex target features combinations
Browse files Browse the repository at this point in the history
This patch is mainly doing two things:

1. Adding support for parentheses, making the combination of target features
   more diverse;
2. Making the priority of ’,‘ is higher than that of '|' by default. So I need
   to make some change with PTX Builtin function.

Differential Revision: https://reviews.llvm.org/D89184
  • Loading branch information
MoringLiu committed Oct 30, 2020
1 parent 30e7df0 commit 00090a2
Show file tree
Hide file tree
Showing 7 changed files with 496 additions and 406 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/BuiltinsNVPTX.def
Expand Up @@ -43,7 +43,7 @@
#define PTX60 "ptx60|" PTX61

#pragma push_macro("AND")
#define AND(a, b) a "," b
#define AND(a, b) "(" a "),(" b ")"

// Special Registers

Expand Down
55 changes: 17 additions & 38 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Expand Up @@ -2307,34 +2307,6 @@ void CGBuilderInserter::InsertHelper(
CGF->InsertHelper(I, Name, BB, InsertPt);
}

static bool hasRequiredFeatures(const SmallVectorImpl<StringRef> &ReqFeatures,
CodeGenModule &CGM, const FunctionDecl *FD,
std::string &FirstMissing) {
// If there aren't any required features listed then go ahead and return.
if (ReqFeatures.empty())
return false;

// Now build up the set of caller features and verify that all the required
// features are there.
llvm::StringMap<bool> CallerFeatureMap;
CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD);

// If we have at least one of the features in the feature list return
// true, otherwise return false.
return std::all_of(
ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef Feature) {
SmallVector<StringRef, 1> OrFeatures;
Feature.split(OrFeatures, '|');
return llvm::any_of(OrFeatures, [&](StringRef Feature) {
if (!CallerFeatureMap.lookup(Feature)) {
FirstMissing = Feature.str();
return false;
}
return true;
});
});
}

// Emits an error if we don't have a valid set of target features for the
// called function.
void CodeGenFunction::checkTargetFeatures(const CallExpr *E,
Expand All @@ -2361,19 +2333,20 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
// listed cpu and any listed features.
unsigned BuiltinID = TargetDecl->getBuiltinID();
std::string MissingFeature;
llvm::StringMap<bool> CallerFeatureMap;
CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD);
if (BuiltinID) {
SmallVector<StringRef, 1> ReqFeatures;
const char *FeatureList =
CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);
StringRef FeatureList(
CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID));
// Return if the builtin doesn't have any required features.
if (!FeatureList || StringRef(FeatureList) == "")
if (FeatureList.empty())
return;
StringRef(FeatureList).split(ReqFeatures, ',');
if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature))
assert(FeatureList.find(' ') == StringRef::npos &&
"Space in feature list");
TargetFeatures TF(CallerFeatureMap);
if (!TF.hasRequiredFeatures(FeatureList))
CGM.getDiags().Report(Loc, diag::err_builtin_needs_feature)
<< TargetDecl->getDeclName()
<< CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID);

<< TargetDecl->getDeclName() << FeatureList;
} else if (!TargetDecl->isMultiVersion() &&
TargetDecl->hasAttr<TargetAttr>()) {
// Get the required features for the callee.
Expand All @@ -2396,7 +2369,13 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
if (F.getValue())
ReqFeatures.push_back(F.getKey());
}
if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature))
if (!llvm::all_of(ReqFeatures, [&](StringRef Feature) {
if (!CallerFeatureMap.lookup(Feature)) {
MissingFeature = Feature.str();
return false;
}
return true;
}))
CGM.getDiags().Report(Loc, diag::err_function_needs_feature)
<< FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
}
Expand Down
71 changes: 71 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Expand Up @@ -4688,6 +4688,77 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO);
};

/// TargetFeatures - This class is used to check whether the builtin function
/// has the required tagert specific features. It is able to support the
/// combination of ','(and), '|'(or), and '()'. By default, the priority of
/// ',' is higher than that of '|' .
/// E.g:
/// A,B|C means the builtin function requires both A and B, or C.
/// If we want the builtin function requires both A and B, or both A and C,
/// there are two ways: A,B|A,C or A,(B|C).
/// The FeaturesList should not contain spaces, and brackets must appear in
/// pairs.
class TargetFeatures {
struct FeatureListStatus {
bool HasFeatures;
StringRef CurFeaturesList;
};

const llvm::StringMap<bool> &CallerFeatureMap;

FeatureListStatus getAndFeatures(StringRef FeatureList) {
int InParentheses = 0;
bool HasFeatures = true;
size_t SubexpressionStart = 0;
for (size_t i = 0, e = FeatureList.size(); i < e; ++i) {
char CurrentToken = FeatureList[i];
switch (CurrentToken) {
default:
break;
case '(':
if (InParentheses == 0)
SubexpressionStart = i + 1;
++InParentheses;
break;
case ')':
--InParentheses;
assert(InParentheses >= 0 && "Parentheses are not in pair");
LLVM_FALLTHROUGH;
case '|':
case ',':
if (InParentheses == 0) {
if (HasFeatures && i != SubexpressionStart) {
StringRef F = FeatureList.slice(SubexpressionStart, i);
HasFeatures = CurrentToken == ')' ? hasRequiredFeatures(F)
: CallerFeatureMap.lookup(F);
}
SubexpressionStart = i + 1;
if (CurrentToken == '|') {
return {HasFeatures, FeatureList.substr(SubexpressionStart)};
}
}
break;
}
}
assert(InParentheses == 0 && "Parentheses are not in pair");
if (HasFeatures && SubexpressionStart != FeatureList.size())
HasFeatures =
CallerFeatureMap.lookup(FeatureList.substr(SubexpressionStart));
return {HasFeatures, StringRef()};
}

public:
bool hasRequiredFeatures(StringRef FeatureList) {
FeatureListStatus FS = {false, FeatureList};
while (!FS.HasFeatures && !FS.CurFeaturesList.empty())
FS = getAndFeatures(FS.CurFeaturesList);
return FS.HasFeatures;
}

TargetFeatures(const llvm::StringMap<bool> &CallerFeatureMap)
: CallerFeatureMap(CallerFeatureMap) {}
};

inline DominatingLLVMValue::saved_type
DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) {
if (!needsSaving(value)) return saved_type(value, false);
Expand Down

0 comments on commit 00090a2

Please sign in to comment.