[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-21 Thread Sven van Haastregt via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe2b3b89bf1ce: [OpenCL] Do not add builtins with unavailable 
types (authored by svenvh).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

Files:
  clang/lib/Sema/OpenCLBuiltins.td
  clang/lib/Sema/SemaLookup.cpp
  clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
  clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
===
--- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
+++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
@@ -727,34 +727,45 @@
 
   // Switch cases for generic types.
   for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
-OS << "case OCLT_" << GenType->getValueAsString("Name") << ":\n";
-OS << "  QT.append({";
+OS << "case OCLT_" << GenType->getValueAsString("Name") << ": {\n";
 
 // Build the Cartesian product of (vector sizes) x (types).  Only insert
 // the plain scalar types for now; other type information such as vector
 // size and type qualifiers will be added after the switch statement.
-for (unsigned I = 0; I < GenType->getValueAsDef("VectorList")
- ->getValueAsListOfInts("List")
- .size();
- I++) {
-  for (const auto *T :
-   GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) {
-OS << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ", ";
+std::vector BaseTypes =
+GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List");
+
+// Collect all QualTypes for a single vector size into TypeList.
+OS << "  SmallVector TypeList;\n";
+for (const auto *T : BaseTypes) {
+  StringRef Ext =
+  T->getValueAsDef("Extension")->getValueAsString("ExtName");
+  if (!Ext.empty()) {
+OS << "  if (S.getPreprocessor().isMacroDefined(\"" << Ext
+   << "\")) {\n  ";
+  }
+  OS << "  TypeList.push_back("
+ << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ");\n";
+  if (!Ext.empty()) {
+OS << "  }\n";
   }
 }
-OS << "});\n";
-// GenTypeNumTypes is the number of types in the GenType
-// (e.g. float/double/half).
-OS << "  GenTypeNumTypes = "
-   << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")
-  .size()
-   << ";\n";
+OS << "  GenTypeNumTypes = TypeList.size();\n";
+
+// Duplicate the TypeList for every vector size.
+std::vector VectorList =
+GenType->getValueAsDef("VectorList")->getValueAsListOfInts("List");
+OS << "  QT.reserve(" << VectorList.size() * BaseTypes.size() << ");\n"
+   << "  for (unsigned I = 0; I < " << VectorList.size() << "; I++) {\n"
+   << "QT.append(TypeList);\n"
+   << "  }\n";
+
 // GenVectorSizes is the list of vector sizes for this GenType.
-// QT contains GenTypeNumTypes * #GenVectorSizes elements.
 OS << "  GenVectorSizes = List"
<< GenType->getValueAsDef("VectorList")->getValueAsString("Name")
-   << ";\n";
-OS << "  break;\n";
+   << ";\n"
+   << "  break;\n"
+   << "}\n";
   }
 
   // Switch cases for non generic, non image types (int, int4, float, ...).
@@ -777,9 +788,20 @@
 if (QT->getValueAsBit("IsAbstract") == 1)
   continue;
 // Emit the cases for non generic, non image types.
-OS << "case OCLT_" << T->getValueAsString("Name") << ":\n"
-   << "  QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n"
-   << "  break;\n";
+OS << "case OCLT_" << T->getValueAsString("Name") << ":\n";
+
+StringRef Ext = T->getValueAsDef("Extension")->getValueAsString("ExtName");
+// If this type depends on an extension, ensure the extension macro is
+// defined.
+if (!Ext.empty()) {
+  OS << "  if (S.getPreprocessor().isMacroDefined(\"" << Ext
+ << "\")) {\n  ";
+}
+OS << "  QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n";
+if (!Ext.empty()) {
+  OS << "  }\n";
+}
+OS << "  break;\n";
   }
 
   // End of switch statement.
Index: clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
===
--- clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
+++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
@@ -6,6 +6,7 @@
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CL2.0 -fdeclare-opencl-builtins -finclude-default-header
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ 

[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-15 Thread Anastasia Stulova via Phabricator via cfe-commits
Anastasia accepted this revision.
Anastasia added a comment.
This revision is now accepted and ready to land.

LGTM! Thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-15 Thread Sven van Haastregt via Phabricator via cfe-commits
svenvh added inline comments.



Comment at: clang/lib/Sema/OpenCLBuiltins.td:54
+// Extension associated to a type.
+class TypeExtension : AbstractExtension<_Ext>;
+

Anastasia wrote:
> svenvh wrote:
> > Anastasia wrote:
> > > I am trying to understand why would we need a special abstraction for the 
> > > type? Would it not be easier if we just guard the BIFs by the extensions 
> > > that allow the use of the type? 
> > > 
> > > We would need to separate the definitions of course but this can be more 
> > > helpful in order to understand what overloads are available conditionally?
> > Yes, it is possible to achieve the same with the current 
> > `FunctionExtension` class.
> > 
> > However, that would require a lot of duplication in the Builtin 
> > descriptions, as for example many math builtins have overloads for `half` 
> > and `double` that will have to be conditionalized.  The purpose of 
> > `TypeExtension` is precisely to avoid separating and duplicating the 
> > definitions.  For example, `acos` is currently more or less defined as:
> > 
> > ```
> > def FGenTypeN : GenericType<"FGenTypeN", TypeList<[Float, Double, Half]>, 
> > VecAndScalar>;
> > def : Builtin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;
> > ```
> > with `double` and `half` conditionalization conveniently handled in a 
> > single place through a `TypeExtension`.
> > 
> > If we would only use `FunctionExtension`s, the definition would become more 
> > like the following:
> > ```
> > def FGenTypeN : GenericType<"FGenTypeN", TypeList<[Float]>, VecAndScalar>;
> > def : Builtin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;
> > 
> > let Extension = Fp64 in {
> >   def DGenTypeN : GenericType<"DGenTypeN", TypeList<[Double]>, 
> > VecAndScalar>;
> >   def : Builtin<"acos", [DGenTypeN, DGenTypeN], Attr.Const>;
> > }
> > 
> > let Extension = Fp16 in {
> >   def HGenTypeN : GenericType<"HGenTypeN", TypeList<[Half]>, VecAndScalar>;
> >   def : Builtin<"acos", [HGenTypeN, HGenTypeN], Attr.Const>;
> > }
> > ```
> > 
> > I personally don't think there is value in adding these explicit guards for 
> > every conditional builtin, as the duplication makes the definitions harder 
> > to maintain.  In addition, I expect it would also increase the size of the 
> > generated tables, as the `GenericType`s have to be split up (though I have 
> > not measured this).
> Ok I see. Yeah it looks quite a lot of duplication indeed for some types. 
> However, this patch provides extra flexibility and doesn't enforce to use the 
> new approach evrywhere so I think it is very reasonable.
> 
> Could you just provide a bit more documentation and especially the difference 
> to the other approach here?
> 
> Do you think it is work extending the online documentation for that too?
> Do you think it is work extending the online documentation for that too?

Yes we should, but it is perhaps worth waiting until we have clarified the 
design wrt feature optionality.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-15 Thread Sven van Haastregt via Phabricator via cfe-commits
svenvh updated this revision to Diff 337663.
svenvh added a comment.

Adding some more comments / explanation.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

Files:
  clang/lib/Sema/OpenCLBuiltins.td
  clang/lib/Sema/SemaLookup.cpp
  clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
  clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
===
--- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
+++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
@@ -727,34 +727,45 @@
 
   // Switch cases for generic types.
   for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
-OS << "case OCLT_" << GenType->getValueAsString("Name") << ":\n";
-OS << "  QT.append({";
+OS << "case OCLT_" << GenType->getValueAsString("Name") << ": {\n";
 
 // Build the Cartesian product of (vector sizes) x (types).  Only insert
 // the plain scalar types for now; other type information such as vector
 // size and type qualifiers will be added after the switch statement.
-for (unsigned I = 0; I < GenType->getValueAsDef("VectorList")
- ->getValueAsListOfInts("List")
- .size();
- I++) {
-  for (const auto *T :
-   GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) {
-OS << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ", ";
+std::vector BaseTypes =
+GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List");
+
+// Collect all QualTypes for a single vector size into TypeList.
+OS << "  SmallVector TypeList;\n";
+for (const auto *T : BaseTypes) {
+  StringRef Ext =
+  T->getValueAsDef("Extension")->getValueAsString("ExtName");
+  if (!Ext.empty()) {
+OS << "  if (S.getPreprocessor().isMacroDefined(\"" << Ext
+   << "\")) {\n  ";
+  }
+  OS << "  TypeList.push_back("
+ << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ");\n";
+  if (!Ext.empty()) {
+OS << "  }\n";
   }
 }
-OS << "});\n";
-// GenTypeNumTypes is the number of types in the GenType
-// (e.g. float/double/half).
-OS << "  GenTypeNumTypes = "
-   << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")
-  .size()
-   << ";\n";
+OS << "  GenTypeNumTypes = TypeList.size();\n";
+
+// Duplicate the TypeList for every vector size.
+std::vector VectorList =
+GenType->getValueAsDef("VectorList")->getValueAsListOfInts("List");
+OS << "  QT.reserve(" << VectorList.size() * BaseTypes.size() << ");\n"
+   << "  for (unsigned I = 0; I < " << VectorList.size() << "; I++) {\n"
+   << "QT.append(TypeList);\n"
+   << "  }\n";
+
 // GenVectorSizes is the list of vector sizes for this GenType.
-// QT contains GenTypeNumTypes * #GenVectorSizes elements.
 OS << "  GenVectorSizes = List"
<< GenType->getValueAsDef("VectorList")->getValueAsString("Name")
-   << ";\n";
-OS << "  break;\n";
+   << ";\n"
+   << "  break;\n"
+   << "}\n";
   }
 
   // Switch cases for non generic, non image types (int, int4, float, ...).
@@ -777,9 +788,20 @@
 if (QT->getValueAsBit("IsAbstract") == 1)
   continue;
 // Emit the cases for non generic, non image types.
-OS << "case OCLT_" << T->getValueAsString("Name") << ":\n"
-   << "  QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n"
-   << "  break;\n";
+OS << "case OCLT_" << T->getValueAsString("Name") << ":\n";
+
+StringRef Ext = T->getValueAsDef("Extension")->getValueAsString("ExtName");
+// If this type depends on an extension, ensure the extension macro is
+// defined.
+if (!Ext.empty()) {
+  OS << "  if (S.getPreprocessor().isMacroDefined(\"" << Ext
+ << "\")) {\n  ";
+}
+OS << "  QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n";
+if (!Ext.empty()) {
+  OS << "  }\n";
+}
+OS << "  break;\n";
   }
 
   // End of switch statement.
Index: clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
===
--- clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
+++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
@@ -6,6 +6,7 @@
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CL2.0 -fdeclare-opencl-builtins -finclude-default-header
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ -fdeclare-opencl-builtins -DNO_HEADER
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ -fdeclare-opencl-builtins 

[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-13 Thread Anastasia Stulova via Phabricator via cfe-commits
Anastasia added inline comments.



Comment at: clang/lib/Sema/OpenCLBuiltins.td:54
+// Extension associated to a type.
+class TypeExtension : AbstractExtension<_Ext>;
+

svenvh wrote:
> Anastasia wrote:
> > I am trying to understand why would we need a special abstraction for the 
> > type? Would it not be easier if we just guard the BIFs by the extensions 
> > that allow the use of the type? 
> > 
> > We would need to separate the definitions of course but this can be more 
> > helpful in order to understand what overloads are available conditionally?
> Yes, it is possible to achieve the same with the current `FunctionExtension` 
> class.
> 
> However, that would require a lot of duplication in the Builtin descriptions, 
> as for example many math builtins have overloads for `half` and `double` that 
> will have to be conditionalized.  The purpose of `TypeExtension` is precisely 
> to avoid separating and duplicating the definitions.  For example, `acos` is 
> currently more or less defined as:
> 
> ```
> def FGenTypeN : GenericType<"FGenTypeN", TypeList<[Float, Double, Half]>, 
> VecAndScalar>;
> def : Builtin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;
> ```
> with `double` and `half` conditionalization conveniently handled in a single 
> place through a `TypeExtension`.
> 
> If we would only use `FunctionExtension`s, the definition would become more 
> like the following:
> ```
> def FGenTypeN : GenericType<"FGenTypeN", TypeList<[Float]>, VecAndScalar>;
> def : Builtin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;
> 
> let Extension = Fp64 in {
>   def DGenTypeN : GenericType<"DGenTypeN", TypeList<[Double]>, VecAndScalar>;
>   def : Builtin<"acos", [DGenTypeN, DGenTypeN], Attr.Const>;
> }
> 
> let Extension = Fp16 in {
>   def HGenTypeN : GenericType<"HGenTypeN", TypeList<[Half]>, VecAndScalar>;
>   def : Builtin<"acos", [HGenTypeN, HGenTypeN], Attr.Const>;
> }
> ```
> 
> I personally don't think there is value in adding these explicit guards for 
> every conditional builtin, as the duplication makes the definitions harder to 
> maintain.  In addition, I expect it would also increase the size of the 
> generated tables, as the `GenericType`s have to be split up (though I have 
> not measured this).
Ok I see. Yeah it looks quite a lot of duplication indeed for some types. 
However, this patch provides extra flexibility and doesn't enforce to use the 
new approach evrywhere so I think it is very reasonable.

Could you just provide a bit more documentation and especially the difference 
to the other approach here?

Do you think it is work extending the online documentation for that too?



Comment at: clang/lib/Sema/SemaLookup.cpp:762
 
+  if (RetTypes.size() == 0)
+return;

This deserved the comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-13 Thread Sven van Haastregt via Phabricator via cfe-commits
svenvh added inline comments.



Comment at: clang/lib/Sema/OpenCLBuiltins.td:54
+// Extension associated to a type.
+class TypeExtension : AbstractExtension<_Ext>;
+

Anastasia wrote:
> I am trying to understand why would we need a special abstraction for the 
> type? Would it not be easier if we just guard the BIFs by the extensions that 
> allow the use of the type? 
> 
> We would need to separate the definitions of course but this can be more 
> helpful in order to understand what overloads are available conditionally?
Yes, it is possible to achieve the same with the current `FunctionExtension` 
class.

However, that would require a lot of duplication in the Builtin descriptions, 
as for example many math builtins have overloads for `half` and `double` that 
will have to be conditionalized.  The purpose of `TypeExtension` is precisely 
to avoid separating and duplicating the definitions.  For example, `acos` is 
currently more or less defined as:

```
def FGenTypeN : GenericType<"FGenTypeN", TypeList<[Float, Double, Half]>, 
VecAndScalar>;
def : Builtin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;
```
with `double` and `half` conditionalization conveniently handled in a single 
place through a `TypeExtension`.

If we would only use `FunctionExtension`s, the definition would become more 
like the following:
```
def FGenTypeN : GenericType<"FGenTypeN", TypeList<[Float]>, VecAndScalar>;
def : Builtin<"acos", [FGenTypeN, FGenTypeN], Attr.Const>;

let Extension = Fp64 in {
  def DGenTypeN : GenericType<"DGenTypeN", TypeList<[Double]>, VecAndScalar>;
  def : Builtin<"acos", [DGenTypeN, DGenTypeN], Attr.Const>;
}

let Extension = Fp16 in {
  def HGenTypeN : GenericType<"HGenTypeN", TypeList<[Half]>, VecAndScalar>;
  def : Builtin<"acos", [HGenTypeN, HGenTypeN], Attr.Const>;
}
```

I personally don't think there is value in adding these explicit guards for 
every conditional builtin, as the duplication makes the definitions harder to 
maintain.  In addition, I expect it would also increase the size of the 
generated tables, as the `GenericType`s have to be split up (though I have not 
measured this).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-13 Thread Anastasia Stulova via Phabricator via cfe-commits
Anastasia added inline comments.



Comment at: clang/lib/Sema/OpenCLBuiltins.td:54
+// Extension associated to a type.
+class TypeExtension : AbstractExtension<_Ext>;
+

I am trying to understand why would we need a special abstraction for the type? 
Would it not be easier if we just guard the BIFs by the extensions that allow 
the use of the type? 

We would need to separate the definitions of course but this can be more 
helpful in order to understand what overloads are available conditionally?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100209/new/

https://reviews.llvm.org/D100209

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D100209: [OpenCL] Do not add builtins with unavailable types

2021-04-09 Thread Sven van Haastregt via Phabricator via cfe-commits
svenvh created this revision.
svenvh added a reviewer: Anastasia.
svenvh added a project: clang.
Herald added subscribers: ldrumm, yaxunl.
svenvh requested review of this revision.
Herald added a subscriber: cfe-commits.

Add functionality to assign extensions to types in `OpenCLBuiltins.td` and use 
that information to filter candidates that should not be exposed if a type is 
not available.

Most of the changes affect the addition of scalar base types into the `QT` 
vector in the generated `OCL2Qual` function (that is, the switch statement as 
described in step 1 in the `OCL2Qual` top comment).  For types that are 
associated with an extension, the QualType is now added only if the 
corresponding extension macro is defined.

The old code was as follows for the `FGenTypeN` GenericType, which represents 
all floating point types for all vector sizes.

  case OCLT_FGenTypeN:
QT.append({Context.FloatTy, Context.DoubleTy, Context.HalfTy, 
Context.FloatTy, Context.DoubleTy, Context.HalfTy, Context.FloatTy, ...
GenTypeNumTypes = 3;
GenVectorSizes = ListVecAndScalar;
break;

With this patch, the generated code becomes:

  case OCLT_FGenTypeN: {
SmallVector TypeList;
TypeList.push_back(Context.FloatTy);
if (S.getPreprocessor().isMacroDefined("cl_khr_fp64")) {
  TypeList.push_back(Context.DoubleTy);
}
if (S.getPreprocessor().isMacroDefined("cl_khr_fp16")) {
  TypeList.push_back(Context.HalfTy);
}
GenTypeNumTypes = TypeList.size();
QT.reserve(18);
for (unsigned I = 0; I < 6; I++) {
  QT.append(TypeList);
}
GenVectorSizes = ListVecAndScalar;
break;
  }


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100209

Files:
  clang/lib/Sema/OpenCLBuiltins.td
  clang/lib/Sema/SemaLookup.cpp
  clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl
  clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
===
--- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
+++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
@@ -705,34 +705,45 @@
 
   // Switch cases for generic types.
   for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
-OS << "case OCLT_" << GenType->getValueAsString("Name") << ":\n";
-OS << "  QT.append({";
+OS << "case OCLT_" << GenType->getValueAsString("Name") << ": {\n";
 
 // Build the Cartesian product of (vector sizes) x (types).  Only insert
 // the plain scalar types for now; other type information such as vector
 // size and type qualifiers will be added after the switch statement.
-for (unsigned I = 0; I < GenType->getValueAsDef("VectorList")
- ->getValueAsListOfInts("List")
- .size();
- I++) {
-  for (const auto *T :
-   GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) {
-OS << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ", ";
+std::vector BaseTypes =
+GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List");
+
+// Collect all QualTypes for a single vector size into TypeList.
+OS << "  SmallVector TypeList;\n";
+for (const auto *T : BaseTypes) {
+  StringRef Ext =
+  T->getValueAsDef("Extension")->getValueAsString("ExtName");
+  if (!Ext.empty()) {
+OS << "  if (S.getPreprocessor().isMacroDefined(\"" << Ext
+   << "\")) {\n  ";
+  }
+  OS << "  TypeList.push_back("
+ << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ");\n";
+  if (!Ext.empty()) {
+OS << "  }\n";
   }
 }
-OS << "});\n";
-// GenTypeNumTypes is the number of types in the GenType
-// (e.g. float/double/half).
-OS << "  GenTypeNumTypes = "
-   << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")
-  .size()
-   << ";\n";
+OS << "  GenTypeNumTypes = TypeList.size();\n";
+
+// Duplicate the TypeList for every vector size.
+std::vector VectorList =
+GenType->getValueAsDef("VectorList")->getValueAsListOfInts("List");
+OS << "  QT.reserve(" << VectorList.size() * BaseTypes.size() << ");\n"
+   << "  for (unsigned I = 0; I < " << VectorList.size() << "; I++) {\n"
+   << "QT.append(TypeList);\n"
+   << "  }\n";
+
 // GenVectorSizes is the list of vector sizes for this GenType.
-// QT contains GenTypeNumTypes * #GenVectorSizes elements.
 OS << "  GenVectorSizes = List"
<< GenType->getValueAsDef("VectorList")->getValueAsString("Name")
-   << ";\n";
-OS << "  break;\n";
+   << ";\n"
+   << "  break;\n"
+   << "}\n";
   }
 
   // Switch cases for non generic, non image types (int, int4, float, ...).
@@ -755,9 +766,20 @@
 if (QT->getValueAsBit("IsAbstract") == 1)