// removeAttribute() currently does not work on Attribute::Alignment
// (it fails with an assertion error), so we have to take a more
// convoluted route to removing this attribute by recreating the
// AttributeSet.
AttributeSet RemoveAttrs(LLVMContext &Context, AttributeSet Attrs) {
  SmallVector<AttributeSet, 8> AttrList;
  for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
    unsigned Index = Attrs.getSlotIndex(Slot);
    AttrBuilder AB;
    for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot);
         Attr != E; ++Attr) {
      if (Attr->isEnumAttribute() &&
          Attr->getKindAsEnum() != Attribute::ByVal &&
          Attr->getKindAsEnum() != Attribute::StructRet) {
        AB.addAttribute(*Attr);
      }
      // IR semantics require that ByVal implies NoAlias.  However, IR
      // semantics do not require StructRet to imply NoAlias.  For
      // example, a global variable address can be passed as a
      // StructRet argument, although Clang does not do so and Clang
      // explicitly adds NoAlias to StructRet arguments.
      if (Attr->isEnumAttribute() &&
          Attr->getKindAsEnum() == Attribute::ByVal) {
        AB.addAttribute(Attribute::get(Context, Attribute::NoAlias));
      }
    }
    AttrList.push_back(AttributeSet::get(Context, Index, AB));
  }
  return AttributeSet::get(Context, AttrList);
}
static std::string getAttributesAsString(AttributeSet Attrs) {
  std::string AttrsAsString;
  for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
    for (AttributeSet::iterator Attr = Attrs.begin(Slot),
           E = Attrs.end(Slot); Attr != E; ++Attr) {
      AttrsAsString += " ";
      AttrsAsString += Attr->getAsString();
    }
  }
  return AttrsAsString;
}
// Most attributes are just hints which can safely be removed.  A few
// attributes can break programs if removed, so check all attributes
// before removing them, in case LLVM adds new attributes.
static void CheckAttributes(AttributeSet Attrs) {
  for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
    for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot);
         Attr != E; ++Attr) {
      if (!Attr->isEnumAttribute()) {
        continue;
      }
      switch (Attr->getKindAsEnum()) {
        // The following attributes can affect calling conventions.
        // Rather than complaining, we just strip these out.
        // ExpandSmallArguments should have rendered SExt/ZExt
        // meaningless since the function arguments will be at least
        // 32-bit.
        case Attribute::InReg:
        case Attribute::SExt:
        case Attribute::ZExt:
        // These attributes influence ABI decisions that should not be
        // visible to PNaCl pexes.
        case Attribute::NonLazyBind:  // Only relevant to dynamic linking.
        case Attribute::NoRedZone:
        case Attribute::StackAlignment:

        // The following attributes are just hints, which can be
        // safely removed.
        case Attribute::AlwaysInline:
        case Attribute::InlineHint:
        case Attribute::MinSize:
        case Attribute::NoAlias:
        case Attribute::NoBuiltin:
        case Attribute::NoCapture:
        case Attribute::NoDuplicate:
        case Attribute::NoImplicitFloat:
        case Attribute::NoInline:
        case Attribute::NoReturn:
        case Attribute::OptimizeForSize:
        case Attribute::ReadNone:
        case Attribute::ReadOnly:

        // PNaCl does not support -fstack-protector in the translator.
        case Attribute::StackProtect:
        case Attribute::StackProtectReq:
        case Attribute::StackProtectStrong:
        // PNaCl does not support ASan in the translator.
        case Attribute::SanitizeAddress:
        case Attribute::SanitizeThread:
        case Attribute::SanitizeMemory:

        // The Language References cites setjmp() as an example of a
        // function which returns twice, and says ReturnsTwice is
        // necessary to disable optimizations such as tail calls.
        // However, in the PNaCl ABI, setjmp() is an intrinsic, and
        // user-defined functions are not allowed to return twice.
        case Attribute::ReturnsTwice:

        // NoUnwind is not a hint if it causes unwind info to be
        // omitted, since this will prevent C++ exceptions from
        // propagating.  In the future, when PNaCl supports zero-cost
        // C++ exception handling using unwind info, we might allow
        // NoUnwind and UWTable.  Alternatively, we might continue to
        // disallow them, and just generate unwind info for all
        // functions.
        case Attribute::NoUnwind:
        case Attribute::UWTable:
          break;

        case Attribute::ByVal:
        case Attribute::StructRet:
        case Attribute::Alignment:
          Attrs.dump();
          report_fatal_error(
              "Attribute should already have been removed by ExpandByVal");

        case Attribute::Naked:
        case Attribute::Nest:
          Attrs.dump();
          report_fatal_error("Unsupported attribute");

        default:
          Attrs.dump();
          report_fatal_error("Unrecognized attribute");
      }
    }
  }
}