r210667 - Add loop unroll pragma support

David Blaikie dblaikie at gmail.com
Thu Jun 12 10:32:13 PDT 2014


On Thu, Jun 12, 2014 at 9:22 AM, Eli Bendersky <eliben at google.com> wrote:
>
>
>
> On Thu, Jun 12, 2014 at 9:19 AM, Craig Topper <craig.topper at gmail.com>
> wrote:
>>
>> I believe -Wmissing-field-initializers is part of the -Wextra in clang.
>> Which looks to be on by default in our cmake files. Tough it also looks to
>> be explicitly enabled for clang too
>>
>>
>>   if (LLVM_ENABLE_WARNINGS)
>>     append("-Wall -W -Wno-unused-parameter -Wwrite-strings" CMAKE_C_FLAGS
>> CMAKE_CXX_FLAGS)
>>
>>     # Turn off missing field initializer warnings for gcc to avoid noise
>> from
>>     # false positives with empty {}. Turn them on otherwise (they're off
>> by
>>     # default for clang).
>>     check_cxx_compiler_flag("-Wmissing-field-initializers"
>> CXX_SUPPORTS_MISSING_FIELD_INITIALIZERS_FLAG)
>>     if (CXX_SUPPORTS_MISSING_FIELD_INITIALIZERS_FLAG)
>>       if (CMAKE_COMPILER_IS_GNUCXX)
>>         append("-Wno-missing-field-initializers" CMAKE_C_FLAGS
>> CMAKE_CXX_FLAGS)
>>       else()
>>         append("-Wmissing-field-initializers" CMAKE_C_FLAGS
>> CMAKE_CXX_FLAGS)
>>       endif()
>>     endif()
>
>
> Ah, OK. I'm usually building with gcc 4.8.2 so I go through the GNUCXX
> branch, and have teh -Wno-missing-field-initializers flag tacked on (which
> overrides -Wextra)

Yep - if you don't use a near-ToT Clang you'll get both false
positives (warnings we don't clean up and possibly have no intention
of doing so) and negatives (code that doesn't warn for you, but you'll
find people quick to fix (or just complain at you) because it breaks
the clang -Werror build).

Also we only tend to care about the performance of clang/LLVM when
build with itself.

In short, it's generally recommended/encouraged that you dev Clang with Clang.

- David

>
> Eli
>
>
>
>
>>
>>
>>
>> On Thu, Jun 12, 2014 at 8:57 AM, Eli Bendersky <eliben at google.com> wrote:
>>>
>>>
>>>
>>>
>>> On Thu, Jun 12, 2014 at 8:35 AM, Eli Bendersky <eliben at google.com> wrote:
>>>>
>>>> Looking into it...
>>>>
>>>>
>>>> On Wed, Jun 11, 2014 at 8:40 PM, Craig Topper <craig.topper at gmail.com>
>>>> wrote:
>>>>>
>>>>> I seem to be getting this build failure after this commit with -Werror
>>>>> enabled
>>>>>
>>>>> lib/Sema/SemaStmtAttr.cpp:132:59: error: missing field 'EnabledIsSet'
>>>>> initializer [-Werror,-Wmissing-field-initializers]
>>>>>
>>>>>     {LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth},
>>>>>
>>>>>                                                           ^
>>>>>
>>>>> lib/Sema/SemaStmtAttr.cpp:133:61: error: missing field 'EnabledIsSet'
>>>>> initializer [-Werror,-Wmissing-field-initializers]
>>>>>
>>>>>     {LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount},
>>>>>
>>>>>                                                             ^
>>>>>
>>>>> lib/Sema/SemaStmtAttr.cpp:134:53: error: missing field 'EnabledIsSet'
>>>>> initializer [-Werror,-Wmissing-field-initializers]
>>>>>
>>>>>     {LoopHintAttr::Unroll, LoopHintAttr::UnrollCount}
>>>
>>> Fixed in r210791.
>>>
>>> Out of curiosity - our standard makefiles/ninja don't seem to turn this
>>> warning on (-Wmissing-field-initializers); is this a build you configure
>>> specially?
>>> Also, how do you manage to build all of clang with -Werror? I always get
>>> a bunch of warnings with gcc 4.8.2, e.g. -Wstrict-aliasing on APValue.h
>>>
>>> Eli
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Modified: cfe/trunk/include/clang/Basic/Attr.td
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/include/clang/Basic/Attr.td (original)
>>>>>> +++ cfe/trunk/include/clang/Basic/Attr.td Wed Jun 11 12:56:26 2014
>>>>>> @@ -1766,6 +1766,8 @@ def LoopHint : Attr {
>>>>>>    /// vectorize_width: vectorize loop operations with width 'value'.
>>>>>>    /// interleave: interleave multiple loop iterations if 'value !=
>>>>>> 0'.
>>>>>>    /// interleave_count: interleaves 'value' loop interations.
>>>>>> +  /// unroll: unroll loop if 'value != 0'.
>>>>>> +  /// unroll_count: unrolls loop 'value' times.
>>>>>>
>>>>>>    /// FIXME: Add Pragma spelling to tablegen and
>>>>>>    /// use it here.
>>>>>> @@ -1773,8 +1775,10 @@ def LoopHint : Attr {
>>>>>>
>>>>>>    /// State of the loop optimization specified by the spelling.
>>>>>>    let Args = [EnumArgument<"Option", "OptionType",
>>>>>> -                          ["vectorize", "vectorize_width",
>>>>>> "interleave", "interleave_count"],
>>>>>> -                          ["Vectorize", "VectorizeWidth",
>>>>>> "Interleave", "InterleaveCount"]>,
>>>>>> +                          ["vectorize", "vectorize_width",
>>>>>> "interleave", "interleave_count",
>>>>>> +                           "unroll", "unroll_count"],
>>>>>> +                          ["Vectorize", "VectorizeWidth",
>>>>>> "Interleave", "InterleaveCount",
>>>>>> +                           "Unroll", "UnrollCount"]>,
>>>>>>                DefaultIntArgument<"Value", 1>];
>>>>>>
>>>>>>    let AdditionalMembers = [{
>>>>>> @@ -1784,6 +1788,8 @@ def LoopHint : Attr {
>>>>>>      case VectorizeWidth: return "vectorize_width";
>>>>>>      case Interleave: return "interleave";
>>>>>>      case InterleaveCount: return "interleave_count";
>>>>>> +    case Unroll: return "unroll";
>>>>>> +    case UnrollCount: return "unroll_count";
>>>>>>      }
>>>>>>      llvm_unreachable("Unhandled LoopHint option.");
>>>>>>    }
>>>>>> @@ -1797,7 +1803,8 @@ def LoopHint : Attr {
>>>>>>    // FIXME: Modify pretty printer to print this pragma.
>>>>>>    void print(raw_ostream &OS, const PrintingPolicy &Policy) const {
>>>>>>      OS << "#pragma clang loop " << getOptionName(option) << "(";
>>>>>> -    if (option == VectorizeWidth || option == InterleaveCount)
>>>>>> +    if (option == VectorizeWidth || option == InterleaveCount ||
>>>>>> +        option == UnrollCount)
>>>>>>        OS << value;
>>>>>>      else
>>>>>>        OS << getValueName(value);
>>>>>>
>>>>>> Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
>>>>>> +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed Jun 11
>>>>>> 12:56:26 2014
>>>>>> @@ -895,7 +895,8 @@ def err_omp_more_one_clause : Error<
>>>>>>
>>>>>>  // Pragma loop support.
>>>>>>  def err_pragma_loop_invalid_option : Error<
>>>>>> -  "%select{invalid|missing}0 option%select{ %1|}0; expected
>>>>>> vectorize, vectorize_width, interleave, or interleave_count">;
>>>>>> +  "%select{invalid|missing}0 option%select{ %1|}0; expected
>>>>>> vectorize, "
>>>>>> +  "vectorize_width, interleave, interleave_count, unroll, or
>>>>>> unroll_count">;
>>>>>>  } // end of Parse Issue category.
>>>>>>
>>>>>>  let CategoryName = "Modules Issue" in {
>>>>>>
>>>>>> Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
>>>>>> +++ cfe/trunk/lib/CodeGen/CGStmt.cpp Wed Jun 11 12:56:26 2014
>>>>>> @@ -550,6 +550,12 @@ void CodeGenFunction::EmitCondBrHints(ll
>>>>>>      case LoopHintAttr::InterleaveCount:
>>>>>>        MetadataName = "llvm.vectorizer.unroll";
>>>>>>        break;
>>>>>> +    case LoopHintAttr::Unroll:
>>>>>> +      MetadataName = "llvm.loopunroll.enable";
>>>>>> +      break;
>>>>>> +    case LoopHintAttr::UnrollCount:
>>>>>> +      MetadataName = "llvm.loopunroll.count";
>>>>>> +      break;
>>>>>>      }
>>>>>>
>>>>>>      llvm::Value *Value;
>>>>>> @@ -572,6 +578,14 @@ void CodeGenFunction::EmitCondBrHints(ll
>>>>>>        Name = llvm::MDString::get(Context, MetadataName);
>>>>>>        Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
>>>>>>        break;
>>>>>> +    case LoopHintAttr::Unroll:
>>>>>> +      Name = llvm::MDString::get(Context, MetadataName);
>>>>>> +      Value = (ValueInt == 0) ? Builder.getFalse() :
>>>>>> Builder.getTrue();
>>>>>> +      break;
>>>>>> +    case LoopHintAttr::UnrollCount:
>>>>>> +      Name = llvm::MDString::get(Context, MetadataName);
>>>>>> +      Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
>>>>>> +      break;
>>>>>>      }
>>>>>>
>>>>>>      SmallVector<llvm::Value *, 2> OpValues;
>>>>>>
>>>>>> Modified: cfe/trunk/lib/Parse/ParsePragma.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParsePragma.cpp?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/lib/Parse/ParsePragma.cpp (original)
>>>>>> +++ cfe/trunk/lib/Parse/ParsePragma.cpp Wed Jun 11 12:56:26 2014
>>>>>> @@ -1641,8 +1641,10 @@ void PragmaOptimizeHandler::HandlePragma
>>>>>>  ///  loop-hint:
>>>>>>  ///    'vectorize' '(' loop-hint-keyword ')'
>>>>>>  ///    'interleave' '(' loop-hint-keyword ')'
>>>>>> +///    'unroll' '(' loop-hint-keyword ')'
>>>>>>  ///    'vectorize_width' '(' loop-hint-value ')'
>>>>>>  ///    'interleave_count' '(' loop-hint-value ')'
>>>>>> +///    'unroll_count' '(' loop-hint-value ')'
>>>>>>  ///
>>>>>>  ///  loop-hint-keyword:
>>>>>>  ///    'enable'
>>>>>> @@ -1661,6 +1663,13 @@ void PragmaOptimizeHandler::HandlePragma
>>>>>>  /// possible and profitable, and 0 is invalid. The loop vectorizer
>>>>>> currently
>>>>>>  /// only works on inner loops.
>>>>>>  ///
>>>>>> +/// The unroll and unroll_count directives control the concatenation
>>>>>> +/// unroller. Specifying unroll(enable) instructs llvm to try to
>>>>>> +/// unroll the loop completely, and unroll(disable) disables
>>>>>> unrolling
>>>>>> +/// for the loop. Specifying unroll_count(_value_) instructs llvm to
>>>>>> +/// try to unroll the loop the number of times indicated by the
>>>>>> value.
>>>>>> +/// If unroll(enable) and unroll_count are both specified only
>>>>>> +/// unroll_count takes effect.
>>>>>>  void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
>>>>>>                                           PragmaIntroducerKind
>>>>>> Introducer,
>>>>>>                                           Token &Tok) {
>>>>>> @@ -1679,9 +1688,15 @@ void PragmaLoopHintHandler::HandlePragma
>>>>>>      Token Option = Tok;
>>>>>>      IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
>>>>>>
>>>>>> -    if (!OptionInfo->isStr("vectorize") &&
>>>>>> !OptionInfo->isStr("interleave") &&
>>>>>> -        !OptionInfo->isStr("vectorize_width") &&
>>>>>> -        !OptionInfo->isStr("interleave_count")) {
>>>>>> +    bool OptionValid =
>>>>>> llvm::StringSwitch<bool>(OptionInfo->getName())
>>>>>> +        .Case("vectorize", true)
>>>>>> +        .Case("interleave", true)
>>>>>> +        .Case("unroll", true)
>>>>>> +        .Case("vectorize_width", true)
>>>>>> +        .Case("interleave_count", true)
>>>>>> +        .Case("unroll_count", true)
>>>>>> +        .Default(false);
>>>>>> +    if (!OptionValid) {
>>>>>>        PP.Diag(Tok.getLocation(),
>>>>>> diag::err_pragma_loop_invalid_option)
>>>>>>            << /*MissingOption=*/false << OptionInfo;
>>>>>>        return;
>>>>>>
>>>>>> Modified: cfe/trunk/lib/Sema/SemaStmtAttr.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAttr.cpp?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/lib/Sema/SemaStmtAttr.cpp (original)
>>>>>> +++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp Wed Jun 11 12:56:26 2014
>>>>>> @@ -67,10 +67,13 @@ static Attr *handleLoopHintAttr(Sema &S,
>>>>>>            .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
>>>>>>            .Case("interleave", LoopHintAttr::Interleave)
>>>>>>            .Case("interleave_count", LoopHintAttr::InterleaveCount)
>>>>>> +          .Case("unroll", LoopHintAttr::Unroll)
>>>>>> +          .Case("unroll_count", LoopHintAttr::UnrollCount)
>>>>>>            .Default(LoopHintAttr::Vectorize);
>>>>>>
>>>>>>    int ValueInt;
>>>>>> -  if (Option == LoopHintAttr::Vectorize || Option ==
>>>>>> LoopHintAttr::Interleave) {
>>>>>> +  if (Option == LoopHintAttr::Vectorize || Option ==
>>>>>> LoopHintAttr::Interleave ||
>>>>>> +      Option == LoopHintAttr::Unroll) {
>>>>>>      if (!ValueInfo) {
>>>>>>        S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
>>>>>>            << /*MissingKeyword=*/true << "";
>>>>>> @@ -87,7 +90,8 @@ static Attr *handleLoopHintAttr(Sema &S,
>>>>>>        return nullptr;
>>>>>>      }
>>>>>>    } else if (Option == LoopHintAttr::VectorizeWidth ||
>>>>>> -             Option == LoopHintAttr::InterleaveCount) {
>>>>>> +             Option == LoopHintAttr::InterleaveCount ||
>>>>>> +             Option == LoopHintAttr::UnrollCount) {
>>>>>>      // FIXME: We should support template parameters for the loop hint
>>>>>> value.
>>>>>>      // See bug report #19610.
>>>>>>      llvm::APSInt ValueAPS;
>>>>>> @@ -111,9 +115,24 @@ static Attr *handleLoopHintAttr(Sema &S,
>>>>>>
>>>>>>  static void
>>>>>>  CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *>
>>>>>> &Attrs) {
>>>>>> -  int PrevOptionValue[4] = {-1, -1, -1, -1};
>>>>>> -  int OptionId[4] = {LoopHintAttr::Vectorize,
>>>>>> LoopHintAttr::VectorizeWidth,
>>>>>> -                     LoopHintAttr::Interleave,
>>>>>> LoopHintAttr::InterleaveCount};
>>>>>> +  // There are 3 categories of loop hints: vectorize, interleave, and
>>>>>> +  // unroll. Each comes in two variants: an enable/disable form and a
>>>>>> +  // form which takes a numeric argument. For example:
>>>>>> +  // unroll(enable|disable) and unroll_count(N). The following array
>>>>>> +  // accumulate the hints encountered while iterating through the
>>>>>> +  // attributes to check for compatibility.
>>>>>> +  struct {
>>>>>> +    int EnableOptionId;
>>>>>> +    int NumericOptionId;
>>>>>> +    bool EnabledIsSet;
>>>>>> +    bool ValueIsSet;
>>>>>> +    bool Enabled;
>>>>>> +    int Value;
>>>>>> +  } Options[] = {
>>>>>> +    {LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth},
>>>>>> +    {LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount},
>>>>>> +    {LoopHintAttr::Unroll, LoopHintAttr::UnrollCount}
>>>>>> +  };
>>>>>>
>>>>>>    for (const auto *I : Attrs) {
>>>>>>      const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
>>>>>> @@ -122,76 +141,64 @@ CheckForIncompatibleAttributes(Sema &S,
>>>>>>      if (!LH)
>>>>>>        continue;
>>>>>>
>>>>>> -    int State, Value;
>>>>>>      int Option = LH->getOption();
>>>>>>      int ValueInt = LH->getValue();
>>>>>>
>>>>>> +    int Category;
>>>>>>      switch (Option) {
>>>>>>      case LoopHintAttr::Vectorize:
>>>>>>      case LoopHintAttr::VectorizeWidth:
>>>>>> -      State = 0;
>>>>>> -      Value = 1;
>>>>>> +      Category = 0;
>>>>>>        break;
>>>>>>      case LoopHintAttr::Interleave:
>>>>>>      case LoopHintAttr::InterleaveCount:
>>>>>> -      State = 2;
>>>>>> -      Value = 3;
>>>>>> +      Category = 1;
>>>>>>        break;
>>>>>> -    }
>>>>>> +    case LoopHintAttr::Unroll:
>>>>>> +    case LoopHintAttr::UnrollCount:
>>>>>> +      Category = 2;
>>>>>> +      break;
>>>>>> +    };
>>>>>>
>>>>>> +    auto &CategoryState = Options[Category];
>>>>>>      SourceLocation ValueLoc = LH->getRange().getEnd();
>>>>>> -
>>>>>> -    // Compatibility testing is split into two cases.
>>>>>> -    // 1. if the current loop hint sets state (enable/disable) -
>>>>>> check against
>>>>>> -    // previous state and value.
>>>>>> -    // 2. if the current loop hint sets a value - check against
>>>>>> previous state
>>>>>> -    // and value.
>>>>>> -
>>>>>> -    if (Option == State) {
>>>>>> -      if (PrevOptionValue[State] != -1) {
>>>>>> -        // Cannot specify state twice.
>>>>>> -        int PrevValue = PrevOptionValue[State];
>>>>>> +    if (Option == LoopHintAttr::Vectorize ||
>>>>>> +        Option == LoopHintAttr::Interleave || Option ==
>>>>>> LoopHintAttr::Unroll) {
>>>>>> +      // Enable|disable hint.  For example, vectorize(enable).
>>>>>> +      if (CategoryState.EnabledIsSet) {
>>>>>> +        // Cannot specify enable/disable state twice.
>>>>>>          S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
>>>>>>              << /*Duplicate=*/true <<
>>>>>> LoopHintAttr::getOptionName(Option)
>>>>>> -            << LoopHintAttr::getValueName(PrevValue)
>>>>>> +            << LoopHintAttr::getValueName(CategoryState.Enabled)
>>>>>>              << LoopHintAttr::getOptionName(Option)
>>>>>> -            << LoopHintAttr::getValueName(Value);
>>>>>> -      }
>>>>>> -
>>>>>> -      if (PrevOptionValue[Value] != -1) {
>>>>>> -        // Compare state with previous width/count.
>>>>>> -        int PrevOption = OptionId[Value];
>>>>>> -        int PrevValueInt = PrevOptionValue[Value];
>>>>>> -        if ((ValueInt == 0 && PrevValueInt > 1) ||
>>>>>> -            (ValueInt == 1 && PrevValueInt <= 1))
>>>>>> -          S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
>>>>>> -              << /*Duplicate=*/false <<
>>>>>> LoopHintAttr::getOptionName(PrevOption)
>>>>>> -              << PrevValueInt << LoopHintAttr::getOptionName(Option)
>>>>>> -              << LoopHintAttr::getValueName(ValueInt);
>>>>>> +            << LoopHintAttr::getValueName(ValueInt);
>>>>>>        }
>>>>>> +      CategoryState.EnabledIsSet = true;
>>>>>> +      CategoryState.Enabled = ValueInt;
>>>>>>      } else {
>>>>>> -      if (PrevOptionValue[State] != -1) {
>>>>>> -        // Compare width/count value with previous state.
>>>>>> -        int PrevOption = OptionId[State];
>>>>>> -        int PrevValueInt = PrevOptionValue[State];
>>>>>> -        if ((ValueInt > 1 && PrevValueInt == 0) ||
>>>>>> -            (ValueInt <= 1 && PrevValueInt == 1))
>>>>>> -          S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
>>>>>> -              << /*Duplicate=*/false <<
>>>>>> LoopHintAttr::getOptionName(PrevOption)
>>>>>> -              << LoopHintAttr::getValueName(PrevValueInt)
>>>>>> -              << LoopHintAttr::getOptionName(Option) << ValueInt;
>>>>>> -      }
>>>>>> -
>>>>>> -      if (PrevOptionValue[Value] != -1) {
>>>>>> -        // Cannot specify a width/count twice.
>>>>>> -        int PrevValueInt = PrevOptionValue[Value];
>>>>>> +      // Numeric hint.  For example, unroll_count(8).
>>>>>> +      if (CategoryState.ValueIsSet) {
>>>>>> +        // Cannot specify numeric hint twice.
>>>>>>          S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
>>>>>>              << /*Duplicate=*/true <<
>>>>>> LoopHintAttr::getOptionName(Option)
>>>>>> -            << PrevValueInt << LoopHintAttr::getOptionName(Option) <<
>>>>>> ValueInt;
>>>>>> +            << CategoryState.Value <<
>>>>>> LoopHintAttr::getOptionName(Option)
>>>>>> +            << ValueInt;
>>>>>>        }
>>>>>> +      CategoryState.ValueIsSet = true;
>>>>>> +      CategoryState.Value = ValueInt;
>>>>>>      }
>>>>>>
>>>>>> -    PrevOptionValue[Option] = ValueInt;
>>>>>> +    if (CategoryState.EnabledIsSet && !CategoryState.Enabled &&
>>>>>> +        CategoryState.ValueIsSet) {
>>>>>> +      // Disable hints are not compatible with numeric hints of the
>>>>>> +      // same category.
>>>>>> +      S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
>>>>>> +          << /*Duplicate=*/false
>>>>>> +          <<
>>>>>> LoopHintAttr::getOptionName(CategoryState.EnableOptionId)
>>>>>> +          << LoopHintAttr::getValueName(CategoryState.Enabled)
>>>>>> +          <<
>>>>>> LoopHintAttr::getOptionName(CategoryState.NumericOptionId)
>>>>>> +          << CategoryState.Value;
>>>>>> +    }
>>>>>>    }
>>>>>>  }
>>>>>>
>>>>>>
>>>>>> Modified: cfe/trunk/test/CodeGen/pragma-loop.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/pragma-loop.cpp?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/CodeGen/pragma-loop.cpp (original)
>>>>>> +++ cfe/trunk/test/CodeGen/pragma-loop.cpp Wed Jun 11 12:56:26 2014
>>>>>> @@ -8,6 +8,7 @@ void while_test(int *List, int Length) {
>>>>>>  #pragma clang loop vectorize(enable)
>>>>>>  #pragma clang loop interleave_count(4)
>>>>>>  #pragma clang loop vectorize_width(4)
>>>>>> +#pragma clang loop unroll(enable)
>>>>>>    while (i < Length) {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_1:.*]]
>>>>>>      List[i] = i * 2;
>>>>>> @@ -19,7 +20,7 @@ void while_test(int *List, int Length) {
>>>>>>  void do_test(int *List, int Length) {
>>>>>>    int i = 0;
>>>>>>
>>>>>> -#pragma clang loop vectorize_width(8) interleave_count(4)
>>>>>> +#pragma clang loop vectorize_width(8) interleave_count(4)
>>>>>> unroll(disable)
>>>>>>    do {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_2:.*]]
>>>>>>      List[i] = i * 2;
>>>>>> @@ -31,6 +32,7 @@ void do_test(int *List, int Length) {
>>>>>>  void for_test(int *List, int Length) {
>>>>>>  #pragma clang loop interleave(enable)
>>>>>>  #pragma clang loop interleave_count(4)
>>>>>> +#pragma clang loop unroll_count(8)
>>>>>>    for (int i = 0; i < Length; i++) {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_3:.*]]
>>>>>>      List[i] = i * 2;
>>>>>> @@ -51,7 +53,7 @@ void for_range_test() {
>>>>>>
>>>>>>  // Verify disable pragma clang loop directive generates correct
>>>>>> metadata
>>>>>>  void disable_test(int *List, int Length) {
>>>>>> -#pragma clang loop vectorize(disable)
>>>>>> +#pragma clang loop vectorize(disable) unroll(disable)
>>>>>>    for (int i = 0; i < Length; i++) {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_5:.*]]
>>>>>>      List[i] = i * 2;
>>>>>> @@ -60,10 +62,12 @@ void disable_test(int *List, int Length)
>>>>>>
>>>>>>  #define VECWIDTH 2
>>>>>>  #define INTCOUNT 2
>>>>>> +#define UNROLLCOUNT 8
>>>>>>
>>>>>>  // Verify defines are correctly resolved in pragma clang loop
>>>>>> directive
>>>>>>  void for_define_test(int *List, int Length, int Value) {
>>>>>>  #pragma clang loop vectorize_width(VECWIDTH)
>>>>>> interleave_count(INTCOUNT)
>>>>>> +#pragma clang loop unroll_count(UNROLLCOUNT)
>>>>>>    for (int i = 0; i < Length; i++) {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_6:.*]]
>>>>>>      List[i] = i * Value;
>>>>>> @@ -74,7 +78,7 @@ void for_define_test(int *List, int Leng
>>>>>>  template <typename A>
>>>>>>  void for_template_test(A *List, int Length, A Value) {
>>>>>>
>>>>>> -#pragma clang loop vectorize_width(8) interleave_count(8)
>>>>>> +#pragma clang loop vectorize_width(8) interleave_count(8)
>>>>>> unroll_count(8)
>>>>>>    for (int i = 0; i < Length; i++) {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_7:.*]]
>>>>>>      List[i] = i * Value;
>>>>>> @@ -85,6 +89,7 @@ void for_template_test(A *List, int Leng
>>>>>>  template <typename A>
>>>>>>  void for_template_define_test(A *List, int Length, A Value) {
>>>>>>  #pragma clang loop vectorize_width(VECWIDTH)
>>>>>> interleave_count(INTCOUNT)
>>>>>> +#pragma clang loop unroll_count(UNROLLCOUNT)
>>>>>>    for (int i = 0; i < Length; i++) {
>>>>>>      // CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop
>>>>>> ![[LOOP_8:.*]]
>>>>>>      List[i] = i * Value;
>>>>>> @@ -93,6 +98,7 @@ void for_template_define_test(A *List, i
>>>>>>
>>>>>>  #undef VECWIDTH
>>>>>>  #undef INTCOUNT
>>>>>> +#undef UNROLLCOUNT
>>>>>>
>>>>>>  // Use templates defined above. Test verifies metadata is generated
>>>>>> correctly.
>>>>>>  void template_test(double *List, int Length) {
>>>>>> @@ -102,19 +108,22 @@ void template_test(double *List, int Len
>>>>>>    for_template_define_test<double>(List, Length, Value);
>>>>>>  }
>>>>>>
>>>>>> -// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata
>>>>>> ![[WIDTH_4:.*]], metadata ![[UNROLL_4:.*]], metadata ![[ENABLE_1:.*]]}
>>>>>> +// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata
>>>>>> ![[UNROLLENABLE_1:.*]], metadata ![[WIDTH_4:.*]], metadata
>>>>>> ![[INTERLEAVE_4:.*]], metadata ![[INTENABLE_1:.*]]}
>>>>>> +// CHECK: ![[UNROLLENABLE_1]] = metadata !{metadata
>>>>>> !"llvm.loopunroll.enable", i1 true}
>>>>>>  // CHECK: ![[WIDTH_4]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.width", i32 4}
>>>>>> -// CHECK: ![[UNROLL_4]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.unroll", i32 4}
>>>>>> -// CHECK: ![[ENABLE_1]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.enable", i1 true}
>>>>>> -// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata
>>>>>> ![[UNROLL_4:.*]], metadata ![[WIDTH_8:.*]]}
>>>>>> +// CHECK: ![[INTERLEAVE_4]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.unroll", i32 4}
>>>>>> +// CHECK: ![[INTENABLE_1]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.enable", i1 true}
>>>>>> +// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata
>>>>>> ![[UNROLLENABLE_0:.*]], metadata ![[INTERLEAVE_4:.*]], metadata
>>>>>> ![[WIDTH_8:.*]]}
>>>>>> +// CHECK: ![[UNROLLENABLE_0]] = metadata !{metadata
>>>>>> !"llvm.loopunroll.enable", i1 false}
>>>>>>  // CHECK: ![[WIDTH_8]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.width", i32 8}
>>>>>> -// CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata
>>>>>> ![[UNROLL_4:.*]], metadata ![[ENABLE_1:.*]]}
>>>>>> -// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata
>>>>>> ![[UNROLL_2:.*]], metadata ![[WIDTH_2:.*]]}
>>>>>> -// CHECK: ![[UNROLL_2]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.unroll", i32 2}
>>>>>> +// CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata
>>>>>> ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[ENABLE_1:.*]]}
>>>>>> +// CHECK: ![[UNROLL_8]] = metadata !{metadata
>>>>>> !"llvm.loopunroll.count", i32 8}
>>>>>> +// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata
>>>>>> ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
>>>>>> +// CHECK: ![[INTERLEAVE_2]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.unroll", i32 2}
>>>>>>  // CHECK: ![[WIDTH_2]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.width", i32 2}
>>>>>> -// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata
>>>>>> ![[WIDTH_1:.*]]}
>>>>>> +// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata
>>>>>> ![[UNROLLENABLE_0:.*]], metadata ![[WIDTH_1:.*]]}
>>>>>>  // CHECK: ![[WIDTH_1]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.width", i32 1}
>>>>>> -// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata
>>>>>> ![[UNROLL_2:.*]], metadata ![[WIDTH_2:.*]]}
>>>>>> -// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata
>>>>>> ![[UNROLL_8:.*]], metadata ![[WIDTH_8:.*]]}
>>>>>> -// CHECK: ![[UNROLL_8]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.unroll", i32 8}
>>>>>> -// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata
>>>>>> ![[UNROLL_2:.*]], metadata ![[WIDTH_2:.*]]}
>>>>>> +// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata
>>>>>> ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
>>>>>> +// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata
>>>>>> ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}
>>>>>> +// CHECK: ![[INTERLEAVE_8]] = metadata !{metadata
>>>>>> !"llvm.vectorizer.unroll", i32 8}
>>>>>> +// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata
>>>>>> ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
>>>>>>
>>>>>> Modified: cfe/trunk/test/PCH/pragma-loop.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/pragma-loop.cpp?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/PCH/pragma-loop.cpp (original)
>>>>>> +++ cfe/trunk/test/PCH/pragma-loop.cpp Wed Jun 11 12:56:26 2014
>>>>>> @@ -4,10 +4,13 @@
>>>>>>  // FIXME: A bug in ParsedAttributes causes the order of the
>>>>>> attributes to be
>>>>>>  // reversed. The checks are consequently in the reverse order below.
>>>>>>
>>>>>> +// CHECK: #pragma clang loop unroll_count(16)
>>>>>>  // CHECK: #pragma clang loop interleave_count(8)
>>>>>>  // CHECK: #pragma clang loop vectorize_width(4)
>>>>>> +// CHECK: #pragma clang loop unroll(disable)
>>>>>>  // CHECK: #pragma clang loop interleave(disable)
>>>>>>  // CHECK: #pragma clang loop vectorize(enable)
>>>>>> +// CHECK: #pragma clang loop unroll(enable)
>>>>>>  // CHECK: #pragma clang loop interleave(enable)
>>>>>>  // CHECK: #pragma clang loop vectorize(disable)
>>>>>>
>>>>>> @@ -20,6 +23,7 @@ public:
>>>>>>      int i = 0;
>>>>>>  #pragma clang loop vectorize_width(4)
>>>>>>  #pragma clang loop interleave_count(8)
>>>>>> +#pragma clang loop unroll_count(16)
>>>>>>      while (i < Length) {
>>>>>>        List[i] = i;
>>>>>>        i++;
>>>>>> @@ -30,6 +34,7 @@ public:
>>>>>>      int i = 0;
>>>>>>  #pragma clang loop vectorize(enable)
>>>>>>  #pragma clang loop interleave(disable)
>>>>>> +#pragma clang loop unroll(disable)
>>>>>>      while (i - 1 < Length) {
>>>>>>        List[i] = i;
>>>>>>        i++;
>>>>>> @@ -40,6 +45,7 @@ public:
>>>>>>      int i = 0;
>>>>>>  #pragma clang loop vectorize(disable)
>>>>>>  #pragma clang loop interleave(enable)
>>>>>> +#pragma clang loop unroll(enable)
>>>>>>      while (i - 3 < Length) {
>>>>>>        List[i] = i;
>>>>>>        i++;
>>>>>>
>>>>>> Modified: cfe/trunk/test/Parser/pragma-loop.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-loop.cpp?rev=210667&r1=210666&r2=210667&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- cfe/trunk/test/Parser/pragma-loop.cpp (original)
>>>>>> +++ cfe/trunk/test/Parser/pragma-loop.cpp Wed Jun 11 12:56:26 2014
>>>>>> @@ -8,23 +8,26 @@ void test(int *List, int Length) {
>>>>>>
>>>>>>  #pragma clang loop vectorize(enable)
>>>>>>  #pragma clang loop interleave(enable)
>>>>>> +#pragma clang loop unroll(enable)
>>>>>>    while (i + 1 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>>  #pragma clang loop vectorize_width(4)
>>>>>>  #pragma clang loop interleave_count(8)
>>>>>> +#pragma clang loop unroll_count(16)
>>>>>>    while (i < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>>  #pragma clang loop vectorize(disable)
>>>>>>  #pragma clang loop interleave(disable)
>>>>>> +#pragma clang loop unroll(disable)
>>>>>>    while (i - 1 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>> -#pragma clang loop vectorize_width(4) interleave_count(8)
>>>>>> +#pragma clang loop vectorize_width(4) interleave_count(8)
>>>>>> unroll_count(16)
>>>>>>    while (i - 2 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>> @@ -35,19 +38,22 @@ void test(int *List, int Length) {
>>>>>>    }
>>>>>>
>>>>>>    int VList[Length];
>>>>>> -#pragma clang loop vectorize(disable) interleave(disable)
>>>>>> +#pragma clang loop vectorize(disable) interleave(disable)
>>>>>> unroll(disable)
>>>>>>    for (int j : VList) {
>>>>>>      VList[j] = List[j];
>>>>>>    }
>>>>>>
>>>>>>  /* expected-error {{expected '('}} */ #pragma clang loop vectorize
>>>>>>  /* expected-error {{expected '('}} */ #pragma clang loop interleave
>>>>>> +/* expected-error {{expected '('}} */ #pragma clang loop unroll
>>>>>>
>>>>>>  /* expected-error {{expected ')'}} */ #pragma clang loop
>>>>>> vectorize(enable
>>>>>>  /* expected-error {{expected ')'}} */ #pragma clang loop
>>>>>> interleave(enable
>>>>>> +/* expected-error {{expected ')'}} */ #pragma clang loop
>>>>>> unroll(enable
>>>>>>
>>>>>>  /* expected-error {{expected ')'}} */ #pragma clang loop
>>>>>> vectorize_width(4
>>>>>>  /* expected-error {{expected ')'}} */ #pragma clang loop
>>>>>> interleave_count(4
>>>>>> +/* expected-error {{expected ')'}} */ #pragma clang loop
>>>>>> unroll_count(4
>>>>>>
>>>>>>  /* expected-error {{missing option}} */ #pragma clang loop
>>>>>>  /* expected-error {{invalid option 'badkeyword'}} */ #pragma clang
>>>>>> loop badkeyword
>>>>>> @@ -61,24 +67,28 @@ void test(int *List, int Length) {
>>>>>>
>>>>>>  /* expected-error {{invalid value 0; expected a positive integer
>>>>>> value}} */ #pragma clang loop vectorize_width(0)
>>>>>>  /* expected-error {{invalid value 0; expected a positive integer
>>>>>> value}} */ #pragma clang loop interleave_count(0)
>>>>>> +/* expected-error {{invalid value 0; expected a positive integer
>>>>>> value}} */ #pragma clang loop unroll_count(0)
>>>>>>    while (i-5 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>>  /* expected-error {{invalid value -1294967296; expected a positive
>>>>>> integer value}} */ #pragma clang loop vectorize_width(3000000000)
>>>>>>  /* expected-error {{invalid value -1294967296; expected a positive
>>>>>> integer value}} */ #pragma clang loop interleave_count(3000000000)
>>>>>> +/* expected-error {{invalid value -1294967296; expected a positive
>>>>>> integer value}} */ #pragma clang loop unroll_count(3000000000)
>>>>>>    while (i-6 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>>  /* expected-error {{missing value; expected a positive integer
>>>>>> value}} */ #pragma clang loop vectorize_width(badvalue)
>>>>>>  /* expected-error {{missing value; expected a positive integer
>>>>>> value}} */ #pragma clang loop interleave_count(badvalue)
>>>>>> +/* expected-error {{missing value; expected a positive integer
>>>>>> value}} */ #pragma clang loop unroll_count(badvalue)
>>>>>>    while (i-6 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>>  /* expected-error {{invalid keyword 'badidentifier'; expected
>>>>>> 'enable' or 'disable'}} */ #pragma clang loop vectorize(badidentifier)
>>>>>>  /* expected-error {{invalid keyword 'badidentifier'; expected
>>>>>> 'enable' or 'disable'}} */ #pragma clang loop interleave(badidentifier)
>>>>>> +/* expected-error {{invalid keyword 'badidentifier'; expected
>>>>>> 'enable' or 'disable'}} */ #pragma clang loop unroll(badidentifier)
>>>>>>    while (i-7 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>> @@ -100,6 +110,8 @@ void test(int *List, int Length) {
>>>>>>  #pragma clang loop vectorize(disable)
>>>>>>  /* expected-error {{incompatible directives 'interleave(disable)' and
>>>>>> 'interleave_count(4)'}} */ #pragma clang loop interleave_count(4)
>>>>>>  #pragma clang loop interleave(disable)
>>>>>> +/* expected-error {{incompatible directives 'unroll(disable)' and
>>>>>> 'unroll_count(4)'}} */ #pragma clang loop unroll_count(4)
>>>>>> +#pragma clang loop unroll(disable)
>>>>>>    while (i-8 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>> @@ -108,14 +120,18 @@ void test(int *List, int Length) {
>>>>>>  #pragma clang loop vectorize(disable)
>>>>>>  /* expected-error {{duplicate directives 'interleave(disable)' and
>>>>>> 'interleave(enable)'}} */ #pragma clang loop interleave(enable)
>>>>>>  #pragma clang loop interleave(disable)
>>>>>> +/* expected-error {{duplicate directives 'unroll(disable)' and
>>>>>> 'unroll(enable)'}} */ #pragma clang loop unroll(enable)
>>>>>> +#pragma clang loop unroll(disable)
>>>>>>    while (i-9 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>> -/* expected-error {{incompatible directives 'vectorize_width(4)' and
>>>>>> 'vectorize(disable)'}} */ #pragma clang loop vectorize(disable)
>>>>>> +/* expected-error {{incompatible directives 'vectorize(disable)' and
>>>>>> 'vectorize_width(4)'}} */ #pragma clang loop vectorize(disable)
>>>>>>  #pragma clang loop vectorize_width(4)
>>>>>> -/* expected-error {{incompatible directives 'interleave_count(4)' and
>>>>>> 'interleave(disable)'}} */ #pragma clang loop interleave(disable)
>>>>>> +/* expected-error {{incompatible directives 'interleave(disable)' and
>>>>>> 'interleave_count(4)'}} */ #pragma clang loop interleave(disable)
>>>>>>  #pragma clang loop interleave_count(4)
>>>>>> +/* expected-error {{incompatible directives 'unroll(disable)' and
>>>>>> 'unroll_count(4)'}} */ #pragma clang loop unroll(disable)
>>>>>> +#pragma clang loop unroll_count(4)
>>>>>>    while (i-10 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>> @@ -124,6 +140,8 @@ void test(int *List, int Length) {
>>>>>>  #pragma clang loop vectorize_width(4)
>>>>>>  /* expected-error {{duplicate directives 'interleave_count(4)' and
>>>>>> 'interleave_count(8)'}} */ #pragma clang loop interleave_count(8)
>>>>>>  #pragma clang loop interleave_count(4)
>>>>>> +/* expected-error {{duplicate directives 'unroll_count(4)' and
>>>>>> 'unroll_count(8)'}} */ #pragma clang loop unroll_count(8)
>>>>>> +#pragma clang loop unroll_count(4)
>>>>>>    while (i-11 < Length) {
>>>>>>      List[i] = i;
>>>>>>    }
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> cfe-commits mailing list
>>>>>> cfe-commits at cs.uiuc.edu
>>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> ~Craig
>>>>
>>>>
>>>
>>
>>
>>
>> --
>> ~Craig
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>



More information about the cfe-commits mailing list