arsenm updated this revision to Diff 184147.
arsenm marked 2 inline comments as done.
arsenm retitled this revision from "OpenCL: Don't promote vector args to 
printf" to "OpenCL: Use length modifier for warning on vector printf arguments".
arsenm edited the summary of this revision.
arsenm added a comment.

Split revert into separate patch


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

https://reviews.llvm.org/D57390

Files:
  include/clang/AST/FormatString.h
  lib/AST/FormatString.cpp
  lib/AST/PrintfFormatString.cpp
  lib/AST/ScanfFormatString.cpp
  lib/Headers/opencl-c.h
  lib/Sema/SemaChecking.cpp
  test/Sema/format-strings.c
  test/SemaOpenCL/format-strings-fixit.cl
  test/SemaOpenCL/printf-format-string-warnings.cl
  test/SemaOpenCL/printf-format-strings.cl

Index: test/SemaOpenCL/printf-format-strings.cl
===================================================================
--- test/SemaOpenCL/printf-format-strings.cl
+++ test/SemaOpenCL/printf-format-strings.cl
@@ -1,22 +1,90 @@
 // RUN: %clang_cc1 -cl-std=CL1.2 -cl-ext=+cl_khr_fp64 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -cl-std=CL1.2 -cl-ext=-cl_khr_fp64 -fsyntax-only -verify %s
 
+typedef __attribute__((ext_vector_type(4))) half half4;
+
 typedef __attribute__((ext_vector_type(2))) float float2;
 typedef __attribute__((ext_vector_type(4))) float float4;
 
+#ifdef cl_khr_fp64
+typedef __attribute__((ext_vector_type(4))) double double4;
+#endif
+
+typedef __attribute__((ext_vector_type(4))) char char4;
+typedef __attribute__((ext_vector_type(4))) unsigned char uchar4;
+
+typedef __attribute__((ext_vector_type(4))) short short4;
+typedef __attribute__((ext_vector_type(4))) unsigned short ushort4;
+
 typedef __attribute__((ext_vector_type(2))) int int2;
 typedef __attribute__((ext_vector_type(4))) int int4;
 typedef __attribute__((ext_vector_type(16))) int int16;
 
+typedef __attribute__((ext_vector_type(4))) long long4;
+typedef __attribute__((ext_vector_type(4))) unsigned int uint4;
+typedef __attribute__((ext_vector_type(4))) unsigned long ulong4;
+
 int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
 
+
+#ifdef cl_khr_fp64
+kernel void format_v4f64(half4 arg_h, float4 arg_f, double4 arg_d)
+{
+  printf("%v4lf", arg_d);
+  printf("%v4lf", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lf", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lF", arg_d);
+  printf("%v4lF", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lF", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4le", arg_d);
+  printf("%v4le", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4le", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lE", arg_d);
+  printf("%v4lE", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lE", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lg", arg_d);
+  printf("%v4lg", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lg", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lG", arg_d);
+  printf("%v4lG", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lG", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4la", arg_d);
+  printf("%v4la", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4la", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lA", arg_d);
+  printf("%v4lA", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lA", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+}
+
+kernel void format_v4f16(half4 arg_h, float4 arg_f, double4 arg_d)
+{
+  printf("%v4hf\n", arg_d); // expected-warning{{format specifies type '__fp16 __attribute__((ext_vector_type(4)))' but the argument has type 'double4' (vector of 4 'double' values)}}
+  printf("%v4hf\n", arg_f); // expected-warning{{format specifies type '__fp16 __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4hf\n", arg_h);
+}
+
+kernel void no_length_modifier_scalar_fp(float f) {
+  printf("%hf", f); // expected-warning{{length modifier 'h' results in undefined behavior or no effect with 'f' conversion specifier}}
+  printf("%hlf", f); // expected-warning{{length modifier 'hl' results in undefined behavior or no effect with 'f' conversion specifier}}
+  printf("%lf", f); // expected-warning{{length modifier 'l' results in undefined behavior or no effect with 'f' conversion specifier}}
+}
+
+#endif
+
 kernel void format_v4f32(float4 arg)
 {
 #ifdef cl_khr_fp64
     printf("%v4f\n", arg); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
 
     // Precision modifier
-    printf("%.2v4f\n", arg); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+    printf("%.2v4f\n", arg); //expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
 #else
     // FIXME: These should not warn, and the type should be expected to be float.
     printf("%v4f\n", arg);  // expected-warning {{double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
@@ -92,3 +160,52 @@
 {
     printf("%v4s\n", arg);
 }
+
+
+kernel void printf_int_length_modifiers(char4 arg_c, short4 arg_s, int4 arg_i, long4 arg_l, uchar4 arg_uc, ushort4 arg_us, uint4 arg_ui, ulong4 arg_ul) {
+  printf("%v4hhd", arg_c);
+  printf("%v4hhd", arg_s);
+  printf("%v4hhd", arg_i);
+  printf("%v4hhd", arg_l);
+
+  printf("%v4hd", arg_c); // expected-warning{{format specifies type 'short __attribute__((ext_vector_type(4)))' but the argument has type 'char4' (vector of 4 'char' values)}}
+  printf("%v4hd", arg_s);
+  printf("%v4hd", arg_i); // expected-warning{{format specifies type 'short __attribute__((ext_vector_type(4)))' but the argument has type 'int4' (vector of 4 'int' values)}}
+  printf("%v4hd", arg_l); // expected-warning{{format specifies type 'short __attribute__((ext_vector_type(4)))' but the argument has type 'long4' (vector of 4 'long' values)}}
+
+  printf("%v4hld", arg_c); // expected-warning{{format specifies type 'int __attribute__((ext_vector_type(4)))' but the argument has type 'char4' (vector of 4 'char' values)}}
+  printf("%v4hld", arg_s); // expected-warning{{format specifies type 'int __attribute__((ext_vector_type(4)))' but the argument has type 'short4' (vector of 4 'short' values)}}
+  printf("%v4hld", arg_i);
+  printf("%v4hld", arg_l); // expected-warning{{format specifies type 'int __attribute__((ext_vector_type(4)))' but the argument has type 'long4' (vector of 4 'long' values)}}
+
+  printf("%v4ld", arg_c); // expected-warning{{format specifies type 'long __attribute__((ext_vector_type(4)))' but the argument has type 'char4' (vector of 4 'char' values)}}
+  printf("%v4ld", arg_s); // expected-warning{{format specifies type 'long __attribute__((ext_vector_type(4)))' but the argument has type 'short4' (vector of 4 'short' values)}}
+  printf("%v4ld", arg_i); // expected-warning{{format specifies type 'long __attribute__((ext_vector_type(4)))' but the argument has type 'int4' (vector of 4 'int' values)}}
+  printf("%v4ld", arg_l);
+
+
+
+  printf("%v4hhu", arg_uc);
+  printf("%v4hhu", arg_us); // expected-warning{{format specifies type 'unsigned char __attribute__((ext_vector_type(4)))' but the argument has type 'ushort4' (vector of 4 'unsigned short' values)}}
+  printf("%v4hhu", arg_ui); // expected-warning{{format specifies type 'unsigned char __attribute__((ext_vector_type(4)))' but the argument has type 'uint4' (vector of 4 'unsigned int' values)}}
+  printf("%v4hhu", arg_ul); // expected-warning{{format specifies type 'unsigned char __attribute__((ext_vector_type(4)))' but the argument has type 'ulong4' (vector of 4 'unsigned long' values)}}
+
+  printf("%v4hu", arg_uc); // expected-warning{{format specifies type 'unsigned short __attribute__((ext_vector_type(4)))' but the argument has type 'uchar4' (vector of 4 'unsigned char' values)}}
+  printf("%v4hu", arg_us);
+  printf("%v4hu", arg_ui); // expected-warning{{format specifies type 'unsigned short __attribute__((ext_vector_type(4)))' but the argument has type 'uint4' (vector of 4 'unsigned int' values)}}
+  printf("%v4hu", arg_ul); // expected-warning{{format specifies type 'unsigned short __attribute__((ext_vector_type(4)))' but the argument has type 'ulong4' (vector of 4 'unsigned long' values)}}
+
+  printf("%v4hlu", arg_uc); // expected-warning{{format specifies type 'unsigned int __attribute__((ext_vector_type(4)))' but the argument has type 'uchar4' (vector of 4 'unsigned char' values)}}
+  printf("%v4hlu", arg_us); // expected-warning{{format specifies type 'unsigned int __attribute__((ext_vector_type(4)))' but the argument has type 'ushort4' (vector of 4 'unsigned short' values)}}
+  printf("%v4hlu", arg_ui);
+  printf("%v4hlu", arg_ul); // expected-warning{{format specifies type 'unsigned int __attribute__((ext_vector_type(4)))' but the argument has type 'ulong4' (vector of 4 'unsigned long' values)}}
+
+  printf("%v4lu", arg_uc); // expected-warning{{format specifies type 'unsigned long __attribute__((ext_vector_type(4)))' but the argument has type 'uchar4' (vector of 4 'unsigned char' values)}}
+  printf("%v4lu", arg_us); // expected-warning{{format specifies type 'unsigned long __attribute__((ext_vector_type(4)))' but the argument has type 'ushort4' (vector of 4 'unsigned short' values)}}
+  printf("%v4lu", arg_ui); // expected-warning{{format specifies type 'unsigned long __attribute__((ext_vector_type(4)))' but the argument has type 'uint4' (vector of 4 'unsigned int' values)}}
+  printf("%v4lu", arg_ul);
+
+
+  printf("%v4n", &arg_i); // expected-warning{{invalid conversion specifier 'n'}}
+  printf("%v4hln", &arg_i); // expected-warning{{invalid conversion specifier 'n'}}
+}
Index: test/SemaOpenCL/printf-format-string-warnings.cl
===================================================================
--- test/SemaOpenCL/printf-format-string-warnings.cl
+++ test/SemaOpenCL/printf-format-string-warnings.cl
@@ -1,14 +1,12 @@
 // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 -finclude-default-header
 
-// FIXME: Make sure warnings are produced based on printf format strings.
-
-// expected-no-diagnostics
+// Make sure warnings are produced based on printf format strings.
 
 kernel void format_string_warnings(__constant char* arg) {
 
-  printf("%d", arg);
+  printf("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type '__constant char *'}}
 
-  printf("not enough arguments %d %d", 4);
+  printf("not enough arguments %d %d", 4); // expected-warning {{more '%' conversions than data arguments}}
 
-  printf("too many arguments", 4);
+  printf("too many arguments", 4); // expected-warning {{data argument not used by format string}}
 }
Index: test/SemaOpenCL/format-strings-fixit.cl
===================================================================
--- test/SemaOpenCL/format-strings-fixit.cl
+++ test/SemaOpenCL/format-strings-fixit.cl
@@ -3,22 +3,72 @@
 // RUN: %clang_cc1 -cl-std=CL1.2 -fsyntax-only -pedantic -Wall -Werror %t
 // RUN: %clang_cc1 -cl-std=CL1.2 -E -o - %t | FileCheck %s
 
+typedef __attribute__((ext_vector_type(4))) char char4;
+typedef __attribute__((ext_vector_type(4))) short short4;
 typedef __attribute__((ext_vector_type(4))) int int4;
+typedef __attribute__((ext_vector_type(4))) unsigned int uint4;
 typedef __attribute__((ext_vector_type(8))) int int8;
+typedef __attribute__((ext_vector_type(4))) long long4;
+typedef __attribute__((ext_vector_type(4))) float float4;
+typedef __attribute__((ext_vector_type(4))) double double4;
 
 int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
 
 
 void vector_fixits() {
   printf("%v4f", (int4) 123);
-  // CHECK: printf("%v4d", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
 
   printf("%v8d", (int4) 123);
-  // CHECK: printf("%v4d", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
 
   printf("%v4d", (int8) 123);
-  // CHECK: printf("%v8d", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
 
   printf("%v4f", (int8) 123);
-  // CHECK: printf("%v8d", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4ld", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4hlf", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
+
+  printf("%v8hld", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
+
+  printf("%v4hld", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4hlf", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4hd", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
+
+  printf("%v4hld", (short4) 123);
+  // CHECK: printf("%v4hd", (short4) 123);
+
+  printf("%v4ld", (short4) 123);
+  // CHECK: printf("%v4hd", (short4) 123);
+
+  printf("%v4hld", (long4) 123);
+  // CHECK: printf("%v4ld", (long4) 123);
+
+  printf("%v8f", (float4) 2.0f);
+  // CHECK: printf("%v4hlf", (float4) 2.0f);
+
+  printf("%v4f", (float4) 2.0f);
+  // CHECK: printf("%v4hlf", (float4) 2.0f);
+
+  printf("%v4lf", (double4) 2.0);
+  // CHECK: printf("%v4lf", (double4) 2.0);
+
+  /// FIXME: This should be fixed
+  printf("%v4hhd", (int4) 123);
+  // CHECK: printf("%v4hhd", (int4) 123);
+
+  /// FIXME: This should be fixed
+  printf("%v4hhd", (int8) 123);
+  // CHECK: printf("%v4hhd", (int8) 123);
 }
Index: test/Sema/format-strings.c
===================================================================
--- test/Sema/format-strings.c
+++ test/Sema/format-strings.c
@@ -617,6 +617,8 @@
   printf("%v4d", x); // expected-warning{{invalid conversion specifier 'v'}}
   printf("%vd", x); // expected-warning{{invalid conversion specifier 'v'}}
   printf("%0vd", x); // expected-warning{{invalid conversion specifier 'v'}}
+  printf("%hlf", x); // expected-warning{{invalid conversion specifier 'l'}}
+  printf("%hld", x); // expected-warning{{invalid conversion specifier 'l'}}
 }
 
 // Test that we correctly merge the format in both orders.
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -7650,7 +7650,8 @@
             startSpecifier, specifierLen);
 
   // Check the length modifier is valid with the given conversion specifier.
-  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+                                 S.getLangOpts()))
     HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
                                 diag::warn_format_nonsensical_length);
   else if (!FS.hasStandardLengthModifier())
@@ -8154,7 +8155,8 @@
   }
 
   // Check the length modifier is valid with the given conversion specifier.
-  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+                                 S.getLangOpts()))
     HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
                                 diag::warn_format_nonsensical_length);
   else if (!FS.hasStandardLengthModifier())
Index: lib/Headers/opencl-c.h
===================================================================
--- lib/Headers/opencl-c.h
+++ lib/Headers/opencl-c.h
@@ -14469,7 +14469,7 @@
 #if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
 // OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf
 
-int printf(__constant const char* st, ...);
+int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
 #endif
 
 // OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14 - Image Read and Write Functions
Index: lib/AST/ScanfFormatString.cpp
===================================================================
--- lib/AST/ScanfFormatString.cpp
+++ lib/AST/ScanfFormatString.cpp
@@ -261,9 +261,10 @@
         case LengthModifier::AsInt32:
         case LengthModifier::AsInt3264:
         case LengthModifier::AsWide:
+        case LengthModifier::AsShortLong:
           return ArgType::Invalid();
       }
-      llvm_unreachable("Unsupported LenghtModifier Type");
+      llvm_unreachable("Unsupported LengthModifier Type");
 
     // Unsigned int.
     case ConversionSpecifier::oArg:
@@ -301,9 +302,10 @@
         case LengthModifier::AsInt32:
         case LengthModifier::AsInt3264:
         case LengthModifier::AsWide:
+        case LengthModifier::AsShortLong:
           return ArgType::Invalid();
       }
-      llvm_unreachable("Unsupported LenghtModifier Type");
+      llvm_unreachable("Unsupported LengthModifier Type");
 
     // Float.
     case ConversionSpecifier::aArg:
@@ -396,6 +398,7 @@
         case LengthModifier::AsInt32:
         case LengthModifier::AsInt3264:
         case LengthModifier::AsWide:
+        case LengthModifier::AsShortLong:
           return ArgType::Invalid();
         }
 
@@ -501,7 +504,7 @@
     namedTypeToLengthModifier(PT, LM);
 
   // If fixing the length modifier was enough, we are done.
-  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+  if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
     const analyze_scanf::ArgType &AT = getArgType(Ctx);
     if (AT.isValid() && AT.matchesType(Ctx, QT))
       return true;
Index: lib/AST/PrintfFormatString.cpp
===================================================================
--- lib/AST/PrintfFormatString.cpp
+++ lib/AST/PrintfFormatString.cpp
@@ -315,7 +315,11 @@
     case 'f': k = ConversionSpecifier::fArg; break;
     case 'g': k = ConversionSpecifier::gArg; break;
     case 'i': k = ConversionSpecifier::iArg; break;
-    case 'n': k = ConversionSpecifier::nArg; break;
+    case 'n':
+      // Not handled, but reserved in OpenCL.
+      if (!LO.OpenCL)
+        k = ConversionSpecifier::nArg;
+      break;
     case 'o': k = ConversionSpecifier::oArg; break;
     case 'p': k = ConversionSpecifier::pArg; break;
     case 's': k = ConversionSpecifier::sArg; break;
@@ -486,10 +490,12 @@
         // GNU extension.
         return Ctx.LongLongTy;
       case LengthModifier::None:
+      case LengthModifier::AsShortLong:
         return Ctx.IntTy;
       case LengthModifier::AsInt32:
         return ArgType(Ctx.IntTy, "__int32");
-      case LengthModifier::AsChar: return ArgType::AnyCharTy;
+      case LengthModifier::AsChar:
+        return ArgType::AnyCharTy;
       case LengthModifier::AsShort: return Ctx.ShortTy;
       case LengthModifier::AsLong: return Ctx.LongTy;
       case LengthModifier::AsLongLong:
@@ -520,6 +526,7 @@
         // GNU extension.
         return Ctx.UnsignedLongLongTy;
       case LengthModifier::None:
+      case LengthModifier::AsShortLong:
         return Ctx.UnsignedIntTy;
       case LengthModifier::AsInt32:
         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
@@ -549,6 +556,18 @@
     }
 
   if (CS.isDoubleArg()) {
+    if (!VectorNumElts.isInvalid()) {
+      switch (LM.getKind()) {
+      case LengthModifier::AsShort:
+        return Ctx.HalfTy;
+      case LengthModifier::AsShortLong:
+        return Ctx.FloatTy;
+      case LengthModifier::AsLong:
+      default:
+        return Ctx.DoubleTy;
+      }
+    }
+
     if (LM.getKind() == LengthModifier::AsLongDouble)
       return Ctx.LongDoubleTy;
     return Ctx.DoubleTy;
@@ -582,6 +601,8 @@
       case LengthModifier::AsInt64:
       case LengthModifier::AsWide:
         return ArgType::Invalid();
+      case LengthModifier::AsShortLong:
+        llvm_unreachable("only used for OpenCL which doesn not handle nArg");
     }
   }
 
@@ -760,10 +781,13 @@
   case BuiltinType::UInt:
   case BuiltinType::Int:
   case BuiltinType::Float:
+    LM.setKind(VectorNumElts.isInvalid() ?
+               LengthModifier::None : LengthModifier::AsShortLong);
+    break;
   case BuiltinType::Double:
-    LM.setKind(LengthModifier::None);
+    LM.setKind(VectorNumElts.isInvalid() ?
+               LengthModifier::None : LengthModifier::AsLong);
     break;
-
   case BuiltinType::Char_U:
   case BuiltinType::UChar:
   case BuiltinType::Char_S:
@@ -796,7 +820,7 @@
     namedTypeToLengthModifier(QT, LM);
 
   // If fixing the length modifier was enough, we might be done.
-  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+  if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
     // If we're going to offer a fix anyway, make sure the sign matches.
     switch (CS.getKind()) {
     case ConversionSpecifier::uArg:
Index: lib/AST/FormatString.cpp
===================================================================
--- lib/AST/FormatString.cpp
+++ lib/AST/FormatString.cpp
@@ -223,6 +223,9 @@
       if (I != E && *I == 'h') {
         ++I;
         lmKind = LengthModifier::AsChar;
+      } else if (I != E && *I == 'l' && LO.OpenCL) {
+        ++I;
+        lmKind = LengthModifier::AsShortLong;
       } else {
         lmKind = LengthModifier::AsShort;
       }
@@ -487,7 +490,8 @@
 }
 
 ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
-  if (K != SpecificTy) // Won't be a valid vector element type.
+  // Check for valid vector element types.
+  if (T.isNull())
     return ArgType::Invalid();
 
   QualType Vec = C.getExtVectorType(T, NumElts);
@@ -572,6 +576,8 @@
     return "hh";
   case AsShort:
     return "h";
+  case AsShortLong:
+    return "hl";
   case AsLong: // or AsWideChar
     return "l";
   case AsLongLong:
@@ -707,13 +713,18 @@
   }
 }
 
-bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
+                                             const LangOptions &LO) const {
   switch (LM.getKind()) {
     case LengthModifier::None:
       return true;
 
     // Handle most integer flags
     case LengthModifier::AsShort:
+      // Length modifier only applies to FP vectors.
+      if (LO.OpenCL && CS.isDoubleArg())
+        return !VectorNumElts.isInvalid();
+
       if (Target.getTriple().isOSMSVCRT()) {
         switch (CS.getKind()) {
           case ConversionSpecifier::cArg:
@@ -752,8 +763,18 @@
           return false;
       }
 
+    case LengthModifier::AsShortLong:
+      return LO.OpenCL && !VectorNumElts.isInvalid();
+
     // Handle 'l' flag
     case LengthModifier::AsLong: // or AsWideChar
+      if (CS.isDoubleArg()) {
+        // Invalid for OpenCL FP scalars.
+        if (LO.OpenCL && VectorNumElts.isInvalid())
+          return false;
+        return true;
+      }
+
       switch (CS.getKind()) {
         case ConversionSpecifier::dArg:
         case ConversionSpecifier::DArg:
@@ -764,14 +785,6 @@
         case ConversionSpecifier::UArg:
         case ConversionSpecifier::xArg:
         case ConversionSpecifier::XArg:
-        case ConversionSpecifier::aArg:
-        case ConversionSpecifier::AArg:
-        case ConversionSpecifier::fArg:
-        case ConversionSpecifier::FArg:
-        case ConversionSpecifier::eArg:
-        case ConversionSpecifier::EArg:
-        case ConversionSpecifier::gArg:
-        case ConversionSpecifier::GArg:
         case ConversionSpecifier::nArg:
         case ConversionSpecifier::cArg:
         case ConversionSpecifier::sArg:
@@ -878,6 +891,7 @@
     case LengthModifier::AsInt3264:
     case LengthModifier::AsInt64:
     case LengthModifier::AsWide:
+    case LengthModifier::AsShortLong: // ???
       return false;
   }
   llvm_unreachable("Invalid LengthModifier Kind!");
Index: include/clang/AST/FormatString.h
===================================================================
--- include/clang/AST/FormatString.h
+++ include/clang/AST/FormatString.h
@@ -67,6 +67,7 @@
     None,
     AsChar,       // 'hh'
     AsShort,      // 'h'
+    AsShortLong,  // 'hl' (OpenCL float/int vector element)
     AsLong,       // 'l'
     AsLongLong,   // 'll'
     AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
@@ -436,7 +437,8 @@
 
   bool usesPositionalArg() const { return UsesPositionalArg; }
 
-  bool hasValidLengthModifier(const TargetInfo &Target) const;
+  bool hasValidLengthModifier(const TargetInfo &Target,
+                              const LangOptions &LO) const;
 
   bool hasStandardLengthModifier() const;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to