Introduce stubs for long-vector support (#638)
* Ensure DeclVisitor and IsSupportedType fully recurse
Add test cases covering errors on long-vector types.
Ensure all the children of clang::Decl are visited by implementing more
specific methods of RecursiveASTVisitor.
Update IsSupportedType to cover additional cases and to abort on type
not explicitly covered.
* Add stubs for lowering long-vector types
Add a new, experimental command line option, --long-vector, to turn on
support for lowering long-vector types which is implemented by
LongVectorLoweringPass. For now, this pass does nothing; subsequent
commits will gradually bring in new features.
When this option is provided, accept long-vector types except when used
as kernel parameters. This feature is intentionally left unsupported for
now and should be revisited when there is definite proof that kernel
parameters can be safely lowered as well.
Add tests covering the frontend changes.
Introduce CustomDiagnosticUnsupportedKernelArgs. Remove explicit
diagnostic ID and rely on C++ to generate appropriate values for the
CustomDiagnosticType enumeration.
Update options.ll test to ensure it can be used with clspv-opt.
Signed-off-by: Marco Antognini <marco.antognini@arm.com>
diff --git a/lib/FrontendPlugin.cpp b/lib/FrontendPlugin.cpp
index a2f7eb8..df655cd 100644
--- a/lib/FrontendPlugin.cpp
+++ b/lib/FrontendPlugin.cpp
@@ -20,6 +20,8 @@
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Debug.h"
+
#include "clspv/Option.h"
#include "FrontendPlugin.h"
@@ -40,29 +42,30 @@
enum Layout { UBO, SSBO };
enum CustomDiagnosticType {
- CustomDiagnosticVectorsMoreThan4Elements = 0,
- CustomDiagnosticVoidPointer = 1,
- CustomDiagnosticUnalignedScalar = 2,
- CustomDiagnosticUnalignedVec2 = 3,
- CustomDiagnosticUnalignedVec4 = 4,
- CustomDiagnosticUBOUnalignedArray = 5,
- CustomDiagnosticUBOUnalignedStruct = 6,
- CustomDiagnosticSmallStraddle = 7,
- CustomDiagnosticLargeStraddle = 8,
- CustomDiagnosticUnalignedStructMember = 9,
- CustomDiagnosticUBORestrictedSize = 10,
- CustomDiagnosticUBORestrictedStruct = 11,
- CustomDiagnosticUBOArrayStride = 12,
- CustomDiagnosticLocationInfo = 13,
- CustomDiagnosticSSBOUnalignedArray = 14,
- CustomDiagnosticSSBOUnalignedStruct = 15,
- CustomDiagnosticOverloadedKernel = 16,
- CustomDiagnosticStructContainsPointer = 17,
- CustomDiagnosticRecursiveStruct = 18,
- CustomDiagnosticPushConstantSizeExceeded = 19,
- CustomDiagnosticPushConstantContainsArray = 20,
- CustomDiagnosticUnsupported16BitStorage = 21,
- CustomDiagnosticUnsupported8BitStorage = 22,
+ CustomDiagnosticVectorsMoreThan4Elements,
+ CustomDiagnosticUnsupportedKernelParameter,
+ CustomDiagnosticVoidPointer,
+ CustomDiagnosticUnalignedScalar,
+ CustomDiagnosticUnalignedVec2,
+ CustomDiagnosticUnalignedVec4,
+ CustomDiagnosticUBOUnalignedArray,
+ CustomDiagnosticUBOUnalignedStruct,
+ CustomDiagnosticSmallStraddle,
+ CustomDiagnosticLargeStraddle,
+ CustomDiagnosticUnalignedStructMember,
+ CustomDiagnosticUBORestrictedSize,
+ CustomDiagnosticUBORestrictedStruct,
+ CustomDiagnosticUBOArrayStride,
+ CustomDiagnosticLocationInfo,
+ CustomDiagnosticSSBOUnalignedArray,
+ CustomDiagnosticSSBOUnalignedStruct,
+ CustomDiagnosticOverloadedKernel,
+ CustomDiagnosticStructContainsPointer,
+ CustomDiagnosticRecursiveStruct,
+ CustomDiagnosticPushConstantSizeExceeded,
+ CustomDiagnosticPushConstantContainsArray,
+ CustomDiagnosticUnsupported16BitStorage,
+ CustomDiagnosticUnsupported8BitStorage,
CustomDiagnosticTotal
};
std::vector<unsigned> CustomDiagnosticsIDMap;
@@ -168,7 +171,7 @@
return false;
}
- bool IsSupportedType(QualType QT, SourceRange SR) {
+ bool IsSupportedType(QualType QT, SourceRange SR, bool IsKernelParameter) {
auto *Ty = QT.getTypePtr();
// First check if we have a pointer type.
@@ -181,19 +184,29 @@
return false;
}
// Otherwise check recursively.
- return IsSupportedType(Ty->getPointeeType(), SR);
+ return IsSupportedType(Ty->getPointeeType(), SR, IsKernelParameter);
}
const auto &canonicalType = QT.getCanonicalType();
if (auto *VT = llvm::dyn_cast<ExtVectorType>(canonicalType)) {
- // We don't support vectors with more than 4 elements.
+ // We don't support vectors with more than 4 elements under all
+ // circumstances.
if (4 < VT->getNumElements()) {
- Instance.getDiagnostics().Report(
- SR.getBegin(),
- CustomDiagnosticsIDMap[CustomDiagnosticVectorsMoreThan4Elements]);
- return false;
+ if (clspv::Option::LongVectorSupport()) {
+ if (IsKernelParameter) {
+ Report(CustomDiagnosticUnsupportedKernelParameter, SR, SR);
+ return false;
+ }
+ } else {
+ Report(CustomDiagnosticVectorsMoreThan4Elements, SR, SR);
+ return false;
+ }
}
- } else if (canonicalType->isRecordType()) {
+
+ return true;
+ }
+
+ if (auto *RT = llvm::dyn_cast<RecordType>(canonicalType)) {
// Do not allow recursive struct definitions.
llvm::DenseSet<const Type *> seen;
if (IsRecursiveType(canonicalType, &seen)) {
@@ -202,9 +215,48 @@
CustomDiagnosticsIDMap[CustomDiagnosticRecursiveStruct]);
return false;
}
+
+ // To avoid infinite recursion, first verify that the record is not
+ // recursive and then that its fields are supported.
+ for (auto *field_decl : RT->getDecl()->fields()) {
+ if (!IsSupportedType(field_decl->getType(), SR, IsKernelParameter)) {
+ return false;
+ }
+ }
+
+ return true;
}
- return true;
+ if (auto *AT = llvm::dyn_cast<ArrayType>(canonicalType)) {
+ return IsSupportedType(AT->getElementType(), SR, IsKernelParameter);
+ }
+
+ // For function prototypes, recurse on return type and parameter types.
+ if (auto *FT = llvm::dyn_cast<FunctionProtoType>(canonicalType)) {
+ IsKernelParameter =
+ IsKernelParameter || (FT->getCallConv() == CC_OpenCLKernel);
+ for (auto param : FT->getParamTypes()) {
+ if (!IsSupportedType(param, SR, IsKernelParameter)) {
+ return false;
+ }
+ }
+
+ if (!IsSupportedType(FT->getReturnType(), SR, IsKernelParameter)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (QT->isBuiltinType()) {
+ return true;
+ }
+
+#ifndef NDEBUG
+ llvm::dbgs() << "IsSupportedType lacks support for QualType: "
+ << QT.getAsString() << '\n';
+#endif
+ llvm_unreachable("Type not covered by IsSupportedType.");
}
// Report a diagnostic using |diag|. If |arg_range| and |specific_range|
@@ -439,16 +491,16 @@
// Visits a declaration. Emits a diagnostic and returns false if the
// declaration represents an unsupported vector value or vector type.
// Otherwise returns true.
- bool VisitDecl(Decl *D) {
- // Looking at the Decl class hierarchy, it seems ValueDecl and TypeDecl
- // are the only two that might represent an unsupported vector type.
- if (auto *VD = dyn_cast<ValueDecl>(D)) {
- return consumer.IsSupportedType(VD->getType(), D->getSourceRange());
- } else if (auto *TD = dyn_cast<TypeDecl>(D)) {
- QualType DefinedType = TD->getASTContext().getTypeDeclType(TD);
- return consumer.IsSupportedType(DefinedType, TD->getSourceRange());
- }
- return true;
+ //
+ // Looking at the Decl class hierarchy, it seems ValueDecl and TypeDecl
+ // are the only two that might represent an unsupported vector type.
+ bool VisitValueDecl(ValueDecl *VD) {
+ return consumer.IsSupportedType(VD->getType(), VD->getSourceRange(),
+ false);
+ }
+ bool VisitValueDecl(TypeDecl *TD) {
+ QualType DefinedType = TD->getASTContext().getTypeDeclType(TD);
+ return consumer.IsSupportedType(DefinedType, TD->getSourceRange(), false);
}
};
@@ -466,6 +518,10 @@
DE.getCustomDiagID(
DiagnosticsEngine::Error,
"vectors with more than 4 elements are not supported");
+ CustomDiagnosticsIDMap[CustomDiagnosticUnsupportedKernelParameter] =
+ DE.getCustomDiagID(DiagnosticsEngine::Error,
+ "vectors with more than 4 elements are not "
+ "supported as kernel parameters");
CustomDiagnosticsIDMap[CustomDiagnosticVoidPointer] = DE.getCustomDiagID(
DiagnosticsEngine::Error, "pointer-to-void is not supported");
CustomDiagnosticsIDMap[CustomDiagnosticUnalignedScalar] =
@@ -557,7 +613,7 @@
// function.
if (FD->hasBody()) {
if (!IsSupportedType(FD->getReturnType(),
- FD->getReturnTypeSourceRange())) {
+ FD->getReturnTypeSourceRange(), false)) {
return false;
}
@@ -587,7 +643,8 @@
}
for (auto *P : FD->parameters()) {
auto type = P->getType();
- if (!IsSupportedType(P->getOriginalType(), P->getSourceRange())) {
+ if (!IsSupportedType(P->getOriginalType(), P->getSourceRange(),
+ is_opencl_kernel)) {
return false;
}