[llvm] r362012 - IR: add optional type to 'byval' function parameters

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Wed May 29 13:31:48 PDT 2019


Hey Tim,

Sorry about this, but Google-internal build testing is tripping over this
change when it comes to bootstrapping compiler-rt (with some "Attribute
'byval' type does not match parameter!"). Did you happen to test a
bootstrap? (that'd help me narrow this down to an internal-only issue,
versus an external issue - though I guess if it's an external issue you'll
be getting email from bootstrap buildbots soon enough?) Reckon it's worth
reverting while I investigate on my side? (or if you think the chances are
good it's only a Google internal issue, that's fair & I can just try to
figure out what's off with our internal build system)

- Dave

On Wed, May 29, 2019 at 12:09 PM Tim Northover via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: tnorthover
> Date: Wed May 29 12:12:48 2019
> New Revision: 362012
>
> URL: http://llvm.org/viewvc/llvm-project?rev=362012&view=rev
> Log:
> IR: add optional type to 'byval' function parameters
>
> When we switch to opaque pointer types we will need some way to describe
> how many bytes a 'byval' parameter should occupy on the stack. This adds
> a (for now) optional extra type parameter.
>
> If present, the type must match the pointee type of the argument.
>
> Note to front-end maintainers: if this causes test failures, it's probably
> because the "byval" attribute is printed after attributes without any
> parameter
> after this change.
>
> Added:
>     llvm/trunk/test/Assembler/byval-type-attr.ll
>     llvm/trunk/test/Assembler/invalid-byval-type1.ll
>     llvm/trunk/test/Assembler/invalid-byval-type2.ll
>     llvm/trunk/test/Assembler/invalid-byval-type3.ll
>     llvm/trunk/test/Bitcode/Inputs/byval-upgrade.bc   (with props)
>     llvm/trunk/test/Bitcode/byval-upgrade.test
>     llvm/trunk/test/CodeGen/AArch64/byval-type.ll
> Modified:
>     llvm/trunk/docs/LangRef.rst
>     llvm/trunk/include/llvm/CodeGen/TargetLowering.h
>     llvm/trunk/include/llvm/IR/Argument.h
>     llvm/trunk/include/llvm/IR/Attributes.h
>     llvm/trunk/include/llvm/IR/CallSite.h
>     llvm/trunk/include/llvm/IR/Function.h
>     llvm/trunk/include/llvm/IR/InstrTypes.h
>     llvm/trunk/lib/AsmParser/LLParser.cpp
>     llvm/trunk/lib/AsmParser/LLParser.h
>     llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>     llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>     llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
>     llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp
>     llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp
>     llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
>     llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp
>     llvm/trunk/lib/IR/AttributeImpl.h
>     llvm/trunk/lib/IR/Attributes.cpp
>     llvm/trunk/lib/IR/Function.cpp
>     llvm/trunk/lib/IR/Verifier.cpp
>     llvm/trunk/test/Bitcode/attributes-3.3.ll
>     llvm/trunk/test/Bitcode/attributes.ll
>     llvm/trunk/test/Bitcode/compatibility-3.6.ll
>     llvm/trunk/test/Bitcode/compatibility-3.7.ll
>     llvm/trunk/test/Bitcode/compatibility-3.8.ll
>     llvm/trunk/test/Bitcode/compatibility-3.9.ll
>     llvm/trunk/test/Bitcode/compatibility-4.0.ll
>     llvm/trunk/test/Bitcode/compatibility-5.0.ll
>     llvm/trunk/test/Bitcode/compatibility-6.0.ll
>     llvm/trunk/test/Bitcode/compatibility.ll
>     llvm/trunk/test/Bitcode/highLevelStructure.3.2.ll
>     llvm/trunk/test/Transforms/Inline/byval-tail-call.ll
>     llvm/trunk/unittests/IR/AttributesTest.cpp
>
> Modified: llvm/trunk/docs/LangRef.rst
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/docs/LangRef.rst (original)
> +++ llvm/trunk/docs/LangRef.rst Wed May 29 12:12:48 2019
> @@ -1017,7 +1017,7 @@ Currently, only the following parameter
>      opposed to memory, though some targets use it to distinguish between
>      two different kinds of registers). Use of this attribute is
>      target-specific.
> -``byval``
> +``byval`` or ``byval(<ty>)``
>      This indicates that the pointer parameter should really be passed by
>      value to the function. The attribute implies that a hidden copy of
>      the pointee is made between the caller and the callee, so the callee
> @@ -1029,6 +1029,9 @@ Currently, only the following parameter
>      ``byval`` parameters). This is not a valid attribute for return
>      values.
>
> +    The byval attribute also supports an optional type argument, which
> must be
> +    the same as the pointee type of the argument.
> +
>      The byval attribute also supports specifying an alignment with the
>      align attribute. It indicates the alignment of the stack slot to
>      form and the known alignment of the pointer specified to the call
>
> Modified: llvm/trunk/include/llvm/CodeGen/TargetLowering.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetLowering.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/TargetLowering.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/TargetLowering.h Wed May 29 12:12:48
> 2019
> @@ -188,6 +188,7 @@ public:
>      bool IsSwiftSelf : 1;
>      bool IsSwiftError : 1;
>      uint16_t Alignment = 0;
> +    Type *ByValType = nullptr;
>
>      ArgListEntry()
>          : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false),
>
> Modified: llvm/trunk/include/llvm/IR/Argument.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Argument.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/Argument.h (original)
> +++ llvm/trunk/include/llvm/IR/Argument.h Wed May 29 12:12:48 2019
> @@ -78,6 +78,9 @@ public:
>    /// If this is a byval or inalloca argument, return its alignment.
>    unsigned getParamAlignment() const;
>
> +  /// If this is a byval argument, return its type.
> +  Type *getParamByValType() const;
> +
>    /// Return true if this argument has the nest attribute.
>    bool hasNestAttr() const;
>
>
> Modified: llvm/trunk/include/llvm/IR/Attributes.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/Attributes.h (original)
> +++ llvm/trunk/include/llvm/IR/Attributes.h Wed May 29 12:12:48 2019
> @@ -90,6 +90,7 @@ public:
>    static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val
> = 0);
>    static Attribute get(LLVMContext &Context, StringRef Kind,
>                         StringRef Val = StringRef());
> +  static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
>
>    /// Return a uniquified Attribute object that has the specific
>    /// alignment set.
> @@ -102,6 +103,7 @@ public:
>    static Attribute getWithAllocSizeArgs(LLVMContext &Context,
>                                          unsigned ElemSizeArg,
>                                          const Optional<unsigned>
> &NumElemsArg);
> +  static Attribute getWithByValType(LLVMContext &Context, Type *Ty);
>
>
>  //===--------------------------------------------------------------------===//
>    // Attribute Accessors
> @@ -117,6 +119,9 @@ public:
>    /// attribute.
>    bool isStringAttribute() const;
>
> +  /// Return true if the attribute is a type attribute.
> +  bool isTypeAttribute() const;
> +
>    /// Return true if the attribute is present.
>    bool hasAttribute(AttrKind Val) const;
>
> @@ -139,6 +144,10 @@ public:
>    /// attribute to be a string attribute.
>    StringRef getValueAsString() const;
>
> +  /// Return the attribute's value as a Type. This requires the attribute
> to be
> +  /// a type attribute.
> +  Type *getValueAsType() const;
> +
>    /// Returns the alignment field of an attribute as a byte alignment
>    /// value.
>    unsigned getAlignment() const;
> @@ -279,6 +288,7 @@ public:
>    unsigned getStackAlignment() const;
>    uint64_t getDereferenceableBytes() const;
>    uint64_t getDereferenceableOrNullBytes() const;
> +  Type *getByValType() const;
>    std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
>    std::string getAsString(bool InAttrGrp = false) const;
>
> @@ -598,6 +608,9 @@ public:
>    /// Return the alignment for the specified function parameter.
>    unsigned getParamAlignment(unsigned ArgNo) const;
>
> +  /// Return the byval type for the specified function parameter.
> +  Type *getParamByValType(unsigned ArgNo) const;
> +
>    /// Get the stack alignment.
>    unsigned getStackAlignment(unsigned Index) const;
>
> @@ -697,6 +710,7 @@ class AttrBuilder {
>    uint64_t DerefBytes = 0;
>    uint64_t DerefOrNullBytes = 0;
>    uint64_t AllocSizeArgs = 0;
> +  Type *ByValType = nullptr;
>
>  public:
>    AttrBuilder() = default;
> @@ -772,6 +786,9 @@ public:
>    /// dereferenceable_or_null attribute exists (zero is returned
> otherwise).
>    uint64_t getDereferenceableOrNullBytes() const { return
> DerefOrNullBytes; }
>
> +  /// Retrieve the byval type.
> +  Type *getByValType() const { return ByValType; }
> +
>    /// Retrieve the allocsize args, if the allocsize attribute exists.  If
> it
>    /// doesn't exist, pair(0, 0) is returned.
>    std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
> @@ -796,6 +813,9 @@ public:
>    AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg,
>                                  const Optional<unsigned> &NumElemsArg);
>
> +  /// This turns a byval type into the form used internally in Attribute.
> +  AttrBuilder &addByValAttr(Type *Ty);
> +
>    /// Add an allocsize attribute, using the representation returned by
>    /// Attribute.getIntValue().
>    AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr);
>
> Modified: llvm/trunk/include/llvm/IR/CallSite.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/CallSite.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/CallSite.h (original)
> +++ llvm/trunk/include/llvm/IR/CallSite.h Wed May 29 12:12:48 2019
> @@ -415,6 +415,11 @@ public:
>      CALLSITE_DELEGATE_GETTER(getParamAlignment(ArgNo));
>    }
>
> +  /// Extract the byval type for a call or parameter (nullptr=unknown).
> +  Type *getParamByValType(unsigned ArgNo) const {
> +    CALLSITE_DELEGATE_GETTER(getParamByValType(ArgNo));
> +  }
> +
>    /// Extract the number of dereferenceable bytes for a call or parameter
>    /// (0=unknown).
>    uint64_t getDereferenceableBytes(unsigned i) const {
>
> Modified: llvm/trunk/include/llvm/IR/Function.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Function.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/Function.h (original)
> +++ llvm/trunk/include/llvm/IR/Function.h Wed May 29 12:12:48 2019
> @@ -431,6 +431,11 @@ public:
>      return AttributeSets.getParamAlignment(ArgNo);
>    }
>
> +  /// Extract the byval type for a parameter (nullptr=unknown).
> +  Type *getParamByValType(unsigned ArgNo) const {
> +    return AttributeSets.getParamByValType(ArgNo);
> +  }
> +
>    /// Extract the number of dereferenceable bytes for a call or
>    /// parameter (0=unknown).
>    /// @param i AttributeList index, referring to a return value or
> argument.
>
> Modified: llvm/trunk/include/llvm/IR/InstrTypes.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/InstrTypes.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/InstrTypes.h (original)
> +++ llvm/trunk/include/llvm/IR/InstrTypes.h Wed May 29 12:12:48 2019
> @@ -1560,6 +1560,11 @@ public:
>      return Attrs.getParamAlignment(ArgNo);
>    }
>
> +  /// Extract the byval type for a call or parameter (nullptr=unknown).
> +  Type *getParamByValType(unsigned ArgNo) const {
> +    return Attrs.getParamByValType(ArgNo);
> +  }
> +
>    /// Extract the number of dereferenceable bytes for a call or
>    /// parameter (0=unknown).
>    uint64_t getDereferenceableBytes(unsigned i) const {
>
> Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
> +++ llvm/trunk/lib/AsmParser/LLParser.cpp Wed May 29 12:12:48 2019
> @@ -1601,7 +1601,13 @@ bool LLParser::ParseOptionalParamAttrs(A
>        B.addAlignmentAttr(Alignment);
>        continue;
>      }
> -    case lltok::kw_byval:           B.addAttribute(Attribute::ByVal);
> break;
> +    case lltok::kw_byval: {
> +      Type *Ty;
> +      if (ParseByValWithOptionalType(Ty))
> +        return true;
> +      B.addByValAttr(Ty);
> +      continue;
> +    }
>      case lltok::kw_dereferenceable: {
>        uint64_t Bytes;
>        if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
> @@ -2454,6 +2460,22 @@ bool LLParser::ParseParameterList(SmallV
>    return false;
>  }
>
> +/// ParseByValWithOptionalType
> +///   ::= byval
> +///   ::= byval(<ty>)
> +bool LLParser::ParseByValWithOptionalType(Type *&Result) {
> +  Result = nullptr;
> +  if (!EatIfPresent(lltok::kw_byval))
> +    return true;
> +  if (!EatIfPresent(lltok::lparen))
> +    return false;
> +  if (ParseType(Result))
> +    return true;
> +  if (!EatIfPresent(lltok::rparen))
> +    return Error(Lex.getLoc(), "expected ')'");
> +  return false;
> +}
> +
>  /// ParseOptionalOperandBundles
>  ///    ::= /*empty*/
>  ///    ::= '[' OperandBundle [, OperandBundle ]* ']'
>
> Modified: llvm/trunk/lib/AsmParser/LLParser.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/AsmParser/LLParser.h (original)
> +++ llvm/trunk/lib/AsmParser/LLParser.h Wed May 29 12:12:48 2019
> @@ -339,6 +339,7 @@ namespace llvm {
>      bool ParseFnAttributeValuePairs(AttrBuilder &B,
>                                      std::vector<unsigned> &FwdRefAttrGrps,
>                                      bool inAttrGrp, LocTy &BuiltinLoc);
> +    bool ParseByValWithOptionalType(Type *&Result);
>
>      // Module Summary Index Parsing.
>      bool SkipModuleSummaryEntry();
>
> Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Wed May 29 12:12:48
> 2019
> @@ -638,6 +638,10 @@ private:
>      return getFnValueByID(ValNo, Ty);
>    }
>
> +  /// Upgrades old-style typeless byval attributes by adding the
> corresponding
> +  /// argument's pointee type.
> +  void propagateByValTypes(CallBase *CB);
> +
>    /// Converts alignment exponent (i.e. power of two (or zero)) to the
>    /// corresponding alignment to use. If alignment is too large, returns
>    /// a corresponding error code.
> @@ -1492,6 +1496,12 @@ Error BitcodeReader::parseAttributeGroup
>            if (Error Err = parseAttrKind(Record[++i], &Kind))
>              return Err;
>
> +          // Upgrade old-style byval attribute to one with a type, even
> if it's
> +          // nullptr. We will have to insert the real type when we
> associate
> +          // this AttributeList with a function.
> +          if (Kind == Attribute::ByVal)
> +            B.addByValAttr(nullptr);
> +
>            B.addAttribute(Kind);
>          } else if (Record[i] == 1) { // Integer attribute
>            Attribute::AttrKind Kind;
> @@ -1507,9 +1517,7 @@ Error BitcodeReader::parseAttributeGroup
>              B.addDereferenceableOrNullAttr(Record[++i]);
>            else if (Kind == Attribute::AllocSize)
>              B.addAllocSizeAttrFromRawRepr(Record[++i]);
> -        } else {                     // String attribute
> -          assert((Record[i] == 3 || Record[i] == 4) &&
> -                 "Invalid attribute group entry");
> +        } else if (Record[i] == 3 || Record[i] == 4) { // String attribute
>            bool HasValue = (Record[i++] == 4);
>            SmallString<64> KindStr;
>            SmallString<64> ValStr;
> @@ -1527,6 +1535,15 @@ Error BitcodeReader::parseAttributeGroup
>            }
>
>            B.addAttribute(KindStr.str(), ValStr.str());
> +        } else {
> +          assert((Record[i] == 5 || Record[i] == 6) &&
> +                 "Invalid attribute group entry");
> +          bool HasType = Record[i] == 6;
> +          Attribute::AttrKind Kind;
> +          if (Error Err = parseAttrKind(Record[++i], &Kind))
> +            return Err;
> +          if (Kind == Attribute::ByVal)
> +            B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
>          }
>        }
>
> @@ -3028,6 +3045,17 @@ Error BitcodeReader::parseFunctionRecord
>    Func->setLinkage(getDecodedLinkage(RawLinkage));
>    Func->setAttributes(getAttributes(Record[4]));
>
> +  // Upgrade any old-style byval without a type by propagating the
> argument's
> +  // pointee type. There should be no opaque pointers where the byval
> type is
> +  // implicit.
> +  for (auto &Arg : Func->args()) {
> +    if (Arg.hasByValAttr() && !Arg.getParamByValType()) {
> +      Arg.removeAttr(Attribute::ByVal);
> +      Arg.addAttr(Attribute::getWithByValType(
> +          Context, Arg.getType()->getPointerElementType()));
> +    }
> +  }
> +
>    unsigned Alignment;
>    if (Error Err = parseAlignmentValue(Record[5], Alignment))
>      return Err;
> @@ -3441,6 +3469,19 @@ Error BitcodeReader::typeCheckLoadStoreI
>    return Error::success();
>  }
>
> +void BitcodeReader::propagateByValTypes(CallBase *CB) {
> +  for (unsigned i = 0; i < CB->getNumArgOperands(); ++i) {
> +    if (CB->paramHasAttr(i, Attribute::ByVal) &&
> +        !CB->getAttribute(i, Attribute::ByVal).getValueAsType()) {
> +      CB->removeParamAttr(i, Attribute::ByVal);
> +      CB->addParamAttr(
> +          i, Attribute::getWithByValType(
> +                 Context,
> +
>  CB->getArgOperand(i)->getType()->getPointerElementType()));
> +    }
> +  }
> +}
> +
>  /// Lazily parse the specified function body block.
>  Error BitcodeReader::parseFunctionBody(Function *F) {
>    if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID))
> @@ -4256,6 +4297,8 @@ Error BitcodeReader::parseFunctionBody(F
>        cast<InvokeInst>(I)->setCallingConv(
>            static_cast<CallingConv::ID>(CallingConv::MaxID & CCInfo));
>        cast<InvokeInst>(I)->setAttributes(PAL);
> +      propagateByValTypes(cast<CallBase>(I));
> +
>        break;
>      }
>      case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval]
> @@ -4731,6 +4774,7 @@ Error BitcodeReader::parseFunctionBody(F
>          TCK = CallInst::TCK_NoTail;
>        cast<CallInst>(I)->setTailCallKind(TCK);
>        cast<CallInst>(I)->setAttributes(PAL);
> +      propagateByValTypes(cast<CallBase>(I));
>        if (FMF.any()) {
>          if (!isa<FPMathOperator>(I))
>            return error("Fast-math-flags specified for call without "
>
> Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Wed May 29 12:12:48
> 2019
> @@ -747,7 +747,7 @@ void ModuleBitcodeWriter::writeAttribute
>          Record.push_back(1);
>          Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
>          Record.push_back(Attr.getValueAsInt());
> -      } else {
> +      } else if (Attr.isStringAttribute()) {
>          StringRef Kind = Attr.getKindAsString();
>          StringRef Val = Attr.getValueAsString();
>
> @@ -758,6 +758,13 @@ void ModuleBitcodeWriter::writeAttribute
>            Record.append(Val.begin(), Val.end());
>            Record.push_back(0);
>          }
> +      } else {
> +        assert(Attr.isTypeAttribute());
> +        Type *Ty = Attr.getValueAsType();
> +        Record.push_back(Ty ? 6 : 5);
> +        Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
> +        if (Ty)
> +          Record.push_back(VE.getTypeID(Attr.getValueAsType()));
>        }
>      }
>
> @@ -4126,15 +4133,15 @@ void ModuleBitcodeWriter::write() {
>    // Emit blockinfo, which defines the standard abbreviations etc.
>    writeBlockInfo();
>
> +  // Emit information describing all of the types in the module.
> +  writeTypeTable();
> +
>    // Emit information about attribute groups.
>    writeAttributeGroupTable();
>
>    // Emit information about parameter attributes.
>    writeAttributeTable();
>
> -  // Emit information describing all of the types in the module.
> -  writeTypeTable();
> -
>    writeComdats();
>
>    // Emit top-level description of module, including target triple,
> inline asm,
>
> Modified: llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp Wed May 29 12:12:48
> 2019
> @@ -949,9 +949,11 @@ void ValueEnumerator::incorporateFunctio
>    incorporateFunctionMetadata(F);
>
>    // Adding function arguments to the value table.
> -  for (const auto &I : F.args())
> +  for (const auto &I : F.args()) {
>      EnumerateValue(&I);
> -
> +    if (I.hasAttribute(Attribute::ByVal) && I.getParamByValType())
> +      EnumerateType(I.getParamByValType());
> +  }
>    FirstFuncConstantID = Values.size();
>
>    // Add all function-level constants to the value table.
>
> Modified: llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp (original)
> +++ llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp Wed May 29 12:12:48
> 2019
> @@ -87,7 +87,10 @@ void CallLowering::setArgFlags(CallLower
>
>    if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) {
>      Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType();
> -    Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
> +
> +    auto Ty = Attrs.getAttribute(OpIdx,
> Attribute::ByVal).getValueAsType();
> +    Arg.Flags.setByValSize(DL.getTypeAllocSize(Ty ? Ty : ElementTy));
> +
>      // For ByVal, alignment should be passed from FE.  BE will guess if
>      // this info is not there but there are cases it cannot get right.
>      unsigned FrameAlign;
>
> Modified: llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp (original)
> +++ llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp Wed May 29 12:12:48
> 2019
> @@ -1204,9 +1204,11 @@ bool FastISel::lowerCallTo(CallLoweringI
>      if (Arg.IsByVal || Arg.IsInAlloca) {
>        PointerType *Ty = cast<PointerType>(Arg.Ty);
>        Type *ElementTy = Ty->getElementType();
> -      unsigned FrameSize = DL.getTypeAllocSize(ElementTy);
> -      // For ByVal, alignment should come from FE. BE will guess if this
> info is
> -      // not there, but there are cases it cannot get right.
> +      unsigned FrameSize =
> +          DL.getTypeAllocSize(Arg.ByValType ? Arg.ByValType : ElementTy);
> +
> +      // For ByVal, alignment should come from FE. BE will guess if this
> info
> +      // is not there, but there are cases it cannot get right.
>        unsigned FrameAlign = Arg.Alignment;
>        if (!FrameAlign)
>          FrameAlign = TLI.getByValTypeAlignment(ElementTy, DL);
>
> Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
> +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed May 29
> 12:12:48 2019
> @@ -9076,8 +9076,11 @@ TargetLowering::LowerCallTo(TargetLoweri
>        if (Args[i].IsByVal || Args[i].IsInAlloca) {
>          PointerType *Ty = cast<PointerType>(Args[i].Ty);
>          Type *ElementTy = Ty->getElementType();
> -        Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
> -        // For ByVal, alignment should come from FE.  BE will guess if
> this
> +
> +        unsigned FrameSize = DL.getTypeAllocSize(
> +            Args[i].ByValType ? Args[i].ByValType : ElementTy);
> +        Flags.setByValSize(FrameSize);
> +
>          // info is not there but there are cases it cannot get right.
>          unsigned FrameAlign;
>          if (Args[i].Alignment)
> @@ -9574,9 +9577,14 @@ void SelectionDAGISel::LowerArguments(co
>        if (Flags.isByVal() || Flags.isInAlloca()) {
>          PointerType *Ty = cast<PointerType>(Arg.getType());
>          Type *ElementTy = Ty->getElementType();
> -        Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
> -        // For ByVal, alignment should be passed from FE.  BE will guess
> if
> -        // this info is not there but there are cases it cannot get right.
> +
> +        // For ByVal, size and alignment should be passed from FE.  BE
> will
> +        // guess if this info is not there but there are cases it cannot
> get
> +        // right.
> +        unsigned FrameSize = DL.getTypeAllocSize(
> +            Arg.getParamByValType() ? Arg.getParamByValType() :
> ElementTy);
> +        Flags.setByValSize(FrameSize);
> +
>          unsigned FrameAlign;
>          if (Arg.getParamAlignment())
>            FrameAlign = Arg.getParamAlignment();
>
> Modified: llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp (original)
> +++ llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp Wed May 29
> 12:12:48 2019
> @@ -112,6 +112,7 @@ void TargetLoweringBase::ArgListEntry::s
>    IsSwiftSelf = Call->paramHasAttr(ArgIdx, Attribute::SwiftSelf);
>    IsSwiftError = Call->paramHasAttr(ArgIdx, Attribute::SwiftError);
>    Alignment = Call->getParamAlignment(ArgIdx);
> +  ByValType = Call->getParamByValType(ArgIdx);
>  }
>
>  /// Generate a libcall taking the given operands as arguments and
> returning a
>
> Modified: llvm/trunk/lib/IR/AttributeImpl.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/AttributeImpl.h?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/AttributeImpl.h (original)
> +++ llvm/trunk/lib/IR/AttributeImpl.h Wed May 29 12:12:48 2019
> @@ -29,6 +29,7 @@
>  namespace llvm {
>
>  class LLVMContext;
> +class Type;
>
>
>  //===----------------------------------------------------------------------===//
>  /// \class
> @@ -41,7 +42,8 @@ protected:
>    enum AttrEntryKind {
>      EnumAttrEntry,
>      IntAttrEntry,
> -    StringAttrEntry
> +    StringAttrEntry,
> +    TypeAttrEntry,
>    };
>
>    AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {}
> @@ -56,6 +58,7 @@ public:
>    bool isEnumAttribute() const { return KindID == EnumAttrEntry; }
>    bool isIntAttribute() const { return KindID == IntAttrEntry; }
>    bool isStringAttribute() const { return KindID == StringAttrEntry; }
> +  bool isTypeAttribute() const { return KindID == TypeAttrEntry; }
>
>    bool hasAttribute(Attribute::AttrKind A) const;
>    bool hasAttribute(StringRef Kind) const;
> @@ -66,16 +69,20 @@ public:
>    StringRef getKindAsString() const;
>    StringRef getValueAsString() const;
>
> +  Type *getValueAsType() const;
> +
>    /// Used when sorting the attributes.
>    bool operator<(const AttributeImpl &AI) const;
>
>    void Profile(FoldingSetNodeID &ID) const {
>      if (isEnumAttribute())
> -      Profile(ID, getKindAsEnum(), 0);
> +      Profile(ID, getKindAsEnum(), static_cast<uint64_t>(0));
>      else if (isIntAttribute())
>        Profile(ID, getKindAsEnum(), getValueAsInt());
> -    else
> +    else if (isStringAttribute())
>        Profile(ID, getKindAsString(), getValueAsString());
> +    else
> +      Profile(ID, getKindAsEnum(), getValueAsType());
>    }
>
>    static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
> @@ -88,6 +95,12 @@ public:
>      ID.AddString(Kind);
>      if (!Values.empty()) ID.AddString(Values);
>    }
> +
> +  static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
> +                      Type *Ty) {
> +    ID.AddInteger(Kind);
> +    ID.AddPointer(Ty);
> +  }
>  };
>
>
>  //===----------------------------------------------------------------------===//
> @@ -145,6 +158,18 @@ public:
>    StringRef getStringValue() const { return Val; }
>  };
>
> +class TypeAttributeImpl : public EnumAttributeImpl {
> +  virtual void anchor();
> +
> +  Type *Ty;
> +
> +public:
> +  TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty)
> +      : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {}
> +
> +  Type *getTypeValue() const { return Ty; }
> +};
> +
>
>  //===----------------------------------------------------------------------===//
>  /// \class
>  /// This class represents a group of attributes that apply to one
> @@ -189,6 +214,7 @@ public:
>    uint64_t getDereferenceableOrNullBytes() const;
>    std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
>    std::string getAsString(bool InAttrGrp) const;
> +  Type *getByValType() const;
>
>    using iterator = const Attribute *;
>
>
> Modified: llvm/trunk/lib/IR/Attributes.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/Attributes.cpp (original)
> +++ llvm/trunk/lib/IR/Attributes.cpp Wed May 29 12:12:48 2019
> @@ -121,6 +121,27 @@ Attribute Attribute::get(LLVMContext &Co
>    return Attribute(PA);
>  }
>
> +Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
> +                         Type *Ty) {
> +  LLVMContextImpl *pImpl = Context.pImpl;
> +  FoldingSetNodeID ID;
> +  ID.AddInteger(Kind);
> +  ID.AddPointer(Ty);
> +
> +  void *InsertPoint;
> +  AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID,
> InsertPoint);
> +
> +  if (!PA) {
> +    // If we didn't find any existing attributes of the same shape then
> create a
> +    // new one and insert it.
> +    PA = new TypeAttributeImpl(Kind, Ty);
> +    pImpl->AttrsSet.InsertNode(PA, InsertPoint);
> +  }
> +
> +  // Return the Attribute that we found or created.
> +  return Attribute(PA);
> +}
> +
>  Attribute Attribute::getWithAlignment(LLVMContext &Context, uint64_t
> Align) {
>    assert(isPowerOf2_32(Align) && "Alignment must be a power of two.");
>    assert(Align <= 0x40000000 && "Alignment too large.");
> @@ -146,6 +167,10 @@ Attribute Attribute::getWithDereferencea
>    return get(Context, DereferenceableOrNull, Bytes);
>  }
>
> +Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {
> +  return get(Context, ByVal, Ty);
> +}
> +
>  Attribute
>  Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned
> ElemSizeArg,
>                                  const Optional<unsigned> &NumElemsArg) {
> @@ -170,9 +195,13 @@ bool Attribute::isStringAttribute() cons
>    return pImpl && pImpl->isStringAttribute();
>  }
>
> +bool Attribute::isTypeAttribute() const {
> +  return pImpl && pImpl->isTypeAttribute();
> +}
> +
>  Attribute::AttrKind Attribute::getKindAsEnum() const {
>    if (!pImpl) return None;
> -  assert((isEnumAttribute() || isIntAttribute()) &&
> +  assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute()) &&
>           "Invalid attribute type to get the kind as an enum!");
>    return pImpl->getKindAsEnum();
>  }
> @@ -198,6 +227,14 @@ StringRef Attribute::getValueAsString()
>    return pImpl->getValueAsString();
>  }
>
> +Type *Attribute::getValueAsType() const {
> +  if (!pImpl) return {};
> +  assert(isTypeAttribute() &&
> +         "Invalid attribute type to get the value as a type!");
> +  return pImpl->getValueAsType();
> +}
> +
> +
>  bool Attribute::hasAttribute(AttrKind Kind) const {
>    return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
>  }
> @@ -252,8 +289,6 @@ std::string Attribute::getAsString(bool
>      return "argmemonly";
>    if (hasAttribute(Attribute::Builtin))
>      return "builtin";
> -  if (hasAttribute(Attribute::ByVal))
> -    return "byval";
>    if (hasAttribute(Attribute::Convergent))
>      return "convergent";
>    if (hasAttribute(Attribute::SwiftError))
> @@ -353,6 +388,19 @@ std::string Attribute::getAsString(bool
>    if (hasAttribute(Attribute::ImmArg))
>      return "immarg";
>
> +  if (hasAttribute(Attribute::ByVal)) {
> +    std::string Result;
> +    Result += "byval";
> +    if (Type *Ty = getValueAsType()) {
> +      raw_string_ostream OS(Result);
> +      Result += '(';
> +      Ty->print(OS, false, true);
> +      OS.flush();
> +      Result += ')';
> +    }
> +    return Result;
> +  }
> +
>    // FIXME: These should be output like this:
>    //
>    //   align=4
> @@ -451,6 +499,8 @@ void IntAttributeImpl::anchor() {}
>
>  void StringAttributeImpl::anchor() {}
>
> +void TypeAttributeImpl::anchor() {}
> +
>  bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const {
>    if (isStringAttribute()) return false;
>    return getKindAsEnum() == A;
> @@ -462,7 +512,7 @@ bool AttributeImpl::hasAttribute(StringR
>  }
>
>  Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
> -  assert(isEnumAttribute() || isIntAttribute());
> +  assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute());
>    return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
>  }
>
> @@ -481,6 +531,11 @@ StringRef AttributeImpl::getValueAsStrin
>    return static_cast<const StringAttributeImpl *>(this)->getStringValue();
>  }
>
> +Type *AttributeImpl::getValueAsType() const {
> +  assert(isTypeAttribute());
> +  return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();
> +}
> +
>  bool AttributeImpl::operator<(const AttributeImpl &AI) const {
>    // This sorts the attributes with Attribute::AttrKinds coming first
> (sorted
>    // relative to their enum value) and then strings.
> @@ -488,10 +543,23 @@ bool AttributeImpl::operator<(const Attr
>      if (AI.isEnumAttribute()) return getKindAsEnum() < AI.getKindAsEnum();
>      if (AI.isIntAttribute()) return true;
>      if (AI.isStringAttribute()) return true;
> +    if (AI.isTypeAttribute()) return true;
> +  }
> +
> +  if (isTypeAttribute()) {
> +    if (AI.isEnumAttribute()) return false;
> +    if (AI.isTypeAttribute()) {
> +      assert(getKindAsEnum() != AI.getKindAsEnum() &&
> +             "Comparison of types would be unstable");
> +      return getKindAsEnum() < AI.getKindAsEnum();
> +    }
> +    if (AI.isIntAttribute()) return true;
> +    if (AI.isStringAttribute()) return true;
>    }
>
>    if (isIntAttribute()) {
>      if (AI.isEnumAttribute()) return false;
> +    if (AI.isTypeAttribute()) return false;
>      if (AI.isIntAttribute()) {
>        if (getKindAsEnum() == AI.getKindAsEnum())
>          return getValueAsInt() < AI.getValueAsInt();
> @@ -500,7 +568,9 @@ bool AttributeImpl::operator<(const Attr
>      if (AI.isStringAttribute()) return true;
>    }
>
> +  assert(isStringAttribute());
>    if (AI.isEnumAttribute()) return false;
> +  if (AI.isTypeAttribute()) return false;
>    if (AI.isIntAttribute()) return false;
>    if (getKindAsString() == AI.getKindAsString())
>      return getValueAsString() < AI.getValueAsString();
> @@ -608,6 +678,10 @@ uint64_t AttributeSet::getDereferenceabl
>    return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;
>  }
>
> +Type *AttributeSet::getByValType() const {
> +  return SetNode ? SetNode->getByValType() : nullptr;
> +}
> +
>  std::pair<unsigned, Optional<unsigned>> AttributeSet::getAllocSizeArgs()
> const {
>    return SetNode ? SetNode->getAllocSizeArgs()
>                   : std::pair<unsigned, Optional<unsigned>>(0, 0);
> @@ -691,6 +765,9 @@ AttributeSetNode *AttributeSetNode::get(
>
>      Attribute Attr;
>      switch (Kind) {
> +    case Attribute::ByVal:
> +      Attr = Attribute::getWithByValType(C, B.getByValType());
> +      break;
>      case Attribute::Alignment:
>        Attr = Attribute::getWithAlignment(C, B.getAlignment());
>        break;
> @@ -760,6 +837,13 @@ unsigned AttributeSetNode::getStackAlign
>    return 0;
>  }
>
> +Type *AttributeSetNode::getByValType() const {
> +  for (const auto I : *this)
> +    if (I.hasAttribute(Attribute::ByVal))
> +      return I.getValueAsType();
> +  return 0;
> +}
> +
>  uint64_t AttributeSetNode::getDereferenceableBytes() const {
>    for (const auto I : *this)
>      if (I.hasAttribute(Attribute::Dereferenceable))
> @@ -1258,6 +1342,11 @@ unsigned AttributeList::getParamAlignmen
>    return getAttributes(ArgNo + FirstArgIndex).getAlignment();
>  }
>
> +Type *AttributeList::getParamByValType(unsigned Index) const {
> +  return getAttributes(Index+FirstArgIndex).getByValType();
> +}
> +
> +
>  unsigned AttributeList::getStackAlignment(unsigned Index) const {
>    return getAttributes(Index).getStackAlignment();
>  }
> @@ -1336,6 +1425,7 @@ void AttrBuilder::clear() {
>    TargetDepAttrs.clear();
>    Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0;
>    AllocSizeArgs = 0;
> +  ByValType = nullptr;
>  }
>
>  AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
> @@ -1360,6 +1450,8 @@ AttrBuilder &AttrBuilder::addAttribute(A
>      Alignment = Attr.getAlignment();
>    else if (Kind == Attribute::StackAlignment)
>      StackAlignment = Attr.getStackAlignment();
> +  else if (Kind == Attribute::ByVal)
> +    ByValType = Attr.getValueAsType();
>    else if (Kind == Attribute::Dereferenceable)
>      DerefBytes = Attr.getDereferenceableBytes();
>    else if (Kind == Attribute::DereferenceableOrNull)
> @@ -1382,6 +1474,8 @@ AttrBuilder &AttrBuilder::removeAttribut
>      Alignment = 0;
>    else if (Val == Attribute::StackAlignment)
>      StackAlignment = 0;
> +  else if (Val == Attribute::ByVal)
> +    ByValType = nullptr;
>    else if (Val == Attribute::Dereferenceable)
>      DerefBytes = 0;
>    else if (Val == Attribute::DereferenceableOrNull)
> @@ -1464,6 +1558,12 @@ AttrBuilder &AttrBuilder::addAllocSizeAt
>    return *this;
>  }
>
> +AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
> +  Attrs[Attribute::ByVal] = true;
> +  ByValType = Ty;
> +  return *this;
> +}
> +
>  AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
>    // FIXME: What if both have alignments, but they don't match?!
>    if (!Alignment)
>
> Modified: llvm/trunk/lib/IR/Function.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/Function.cpp (original)
> +++ llvm/trunk/lib/IR/Function.cpp Wed May 29 12:12:48 2019
> @@ -113,6 +113,11 @@ unsigned Argument::getParamAlignment() c
>    return getParent()->getParamAlignment(getArgNo());
>  }
>
> +Type *Argument::getParamByValType() const {
> +  assert(getType()->isPointerTy() && "Only pointers have byval types");
> +  return getParent()->getParamByValType(getArgNo());
> +}
> +
>  uint64_t Argument::getDereferenceableBytes() const {
>    assert(getType()->isPointerTy() &&
>           "Only pointers have dereferenceable bytes");
>
> Modified: llvm/trunk/lib/IR/Verifier.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/Verifier.cpp (original)
> +++ llvm/trunk/lib/IR/Verifier.cpp Wed May 29 12:12:48 2019
> @@ -1695,6 +1695,11 @@ void Verifier::verifyParameterAttrs(Attr
>           "'noinline and alwaysinline' are incompatible!",
>           V);
>
> +  if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) {
> +    Assert(Attrs.getByValType() ==
> cast<PointerType>(Ty)->getElementType(),
> +           "Attribute 'byval' type does not match parameter!");
> +  }
> +
>    AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
>    Assert(!AttrBuilder(Attrs).overlaps(IncompatibleAttrs),
>           "Wrong types for attribute: " +
>
> Added: llvm/trunk/test/Assembler/byval-type-attr.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/byval-type-attr.ll?rev=362012&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Assembler/byval-type-attr.ll (added)
> +++ llvm/trunk/test/Assembler/byval-type-attr.ll Wed May 29 12:12:48 2019
> @@ -0,0 +1,31 @@
> +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
> +
> +; CHECK: define void @foo(i32* byval(i32) align 4)
> +define void @foo(i32* byval(i32) align 4) {
> +  ret void
> +}
> +
> +; CHECK: define void @bar({ i32*, i8 }* byval({ i32*, i8 }) align 4)
> +define void @bar({i32*, i8}* byval({i32*, i8}) align 4) {
> +  ret void
> +}
> +
> +define void @caller({ i32*, i8 }* %ptr) personality i8* bitcast (i32
> (...)* @__gxx_personality_v0 to i8*) {
> +; CHECK: call void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
> +; CHECK: invoke void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
> +  call void @bar({i32*, i8}* byval %ptr)
> +  invoke void @bar({i32*, i8}* byval %ptr) to label %success unwind label
> %fail
> +
> +success:
> +  ret void
> +
> +fail:
> +  landingpad { i8*, i32 } cleanup
> +  ret void
> +}
> +
> +; CHECK: declare void @baz([8 x i8]* byval([8 x i8]))
> +%named_type = type [8 x i8]
> +declare void @baz(%named_type* byval(%named_type))
> +
> +declare i32 @__gxx_personality_v0(...)
>
> Added: llvm/trunk/test/Assembler/invalid-byval-type1.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/invalid-byval-type1.ll?rev=362012&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Assembler/invalid-byval-type1.ll (added)
> +++ llvm/trunk/test/Assembler/invalid-byval-type1.ll Wed May 29 12:12:48
> 2019
> @@ -0,0 +1,4 @@
> +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
> +
> +; CHECK: Attribute 'byval' type does not match parameter!
> +declare void @foo(i32* byval(i8))
>
> Added: llvm/trunk/test/Assembler/invalid-byval-type2.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/invalid-byval-type2.ll?rev=362012&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Assembler/invalid-byval-type2.ll (added)
> +++ llvm/trunk/test/Assembler/invalid-byval-type2.ll Wed May 29 12:12:48
> 2019
> @@ -0,0 +1,4 @@
> +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
> +
> +; CHECK: error: void type only allowed for function results
> +declare void @foo(i32* byval(void))
>
> Added: llvm/trunk/test/Assembler/invalid-byval-type3.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/invalid-byval-type3.ll?rev=362012&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Assembler/invalid-byval-type3.ll (added)
> +++ llvm/trunk/test/Assembler/invalid-byval-type3.ll Wed May 29 12:12:48
> 2019
> @@ -0,0 +1,4 @@
> +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
> +
> +; CHECK: Attributes 'byval' and 'inalloca' do not support unsized types!
> +declare void @foo(void()* byval(void()))
>
> Added: llvm/trunk/test/Bitcode/Inputs/byval-upgrade.bc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/Inputs/byval-upgrade.bc?rev=362012&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: llvm/trunk/test/Bitcode/Inputs/byval-upgrade.bc
>
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Modified: llvm/trunk/test/Bitcode/attributes-3.3.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/attributes-3.3.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/attributes-3.3.ll (original)
> +++ llvm/trunk/test/Bitcode/attributes-3.3.ll Wed May 29 12:12:48 2019
> @@ -48,7 +48,7 @@ define void @f7(i8* noalias)
>  }
>
>  define void @f8(i8* byval)
> -; CHECK: define void @f8(i8* byval)
> +; CHECK: define void @f8(i8* byval(i8))
>  {
>          ret void;
>  }
>
> Modified: llvm/trunk/test/Bitcode/attributes.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/attributes.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/attributes.ll (original)
> +++ llvm/trunk/test/Bitcode/attributes.ll Wed May 29 12:12:48 2019
> @@ -45,7 +45,7 @@ define void @f7(i8* noalias)
>  }
>
>  define void @f8(i8* byval)
> -; CHECK: define void @f8(i8* byval)
> +; CHECK: define void @f8(i8* byval(i8))
>  {
>          ret void;
>  }
>
> Added: llvm/trunk/test/Bitcode/byval-upgrade.test
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/byval-upgrade.test?rev=362012&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/byval-upgrade.test (added)
> +++ llvm/trunk/test/Bitcode/byval-upgrade.test Wed May 29 12:12:48 2019
> @@ -0,0 +1,7 @@
> +RUN: llvm-dis %p/Inputs/byval-upgrade.bc -o - | FileCheck %s
> +
> +Make sure we upgrade old-stile IntAttribute byval records to a fully typed
> +version correctly.
> +
> +CHECK: call void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
> +CHECK: invoke void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-3.6.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-3.6.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-3.6.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-3.6.ll Wed May 29 12:12:48 2019
> @@ -404,7 +404,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-3.7.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-3.7.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-3.7.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-3.7.ll Wed May 29 12:12:48 2019
> @@ -410,7 +410,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-3.8.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-3.8.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-3.8.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-3.8.ll Wed May 29 12:12:48 2019
> @@ -435,7 +435,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-3.9.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-3.9.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-3.9.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-3.9.ll Wed May 29 12:12:48 2019
> @@ -504,7 +504,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-4.0.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-4.0.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-4.0.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-4.0.ll Wed May 29 12:12:48 2019
> @@ -504,7 +504,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-5.0.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-5.0.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-5.0.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-5.0.ll Wed May 29 12:12:48 2019
> @@ -508,7 +508,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility-6.0.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility-6.0.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility-6.0.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility-6.0.ll Wed May 29 12:12:48 2019
> @@ -515,7 +515,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
>
> Modified: llvm/trunk/test/Bitcode/compatibility.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/compatibility.ll (original)
> +++ llvm/trunk/test/Bitcode/compatibility.ll Wed May 29 12:12:48 2019
> @@ -529,7 +529,7 @@ declare void @f.param.signext(i8 signext
>  declare void @f.param.inreg(i8 inreg)
>  ; CHECK: declare void @f.param.inreg(i8 inreg)
>  declare void @f.param.byval({ i8, i8 }* byval)
> -; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
> +; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
>  declare void @f.param.inalloca(i8* inalloca)
>  ; CHECK: declare void @f.param.inalloca(i8* inalloca)
>  declare void @f.param.sret(i8* sret)
> @@ -1735,6 +1735,15 @@ define i8** @constexpr() {
>  declare void @llvm.test.immarg.intrinsic(i32 immarg)
>  ; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)
>
> +; byval attribute with type
> +%named_type = type [8 x i8]
> +declare void @byval_type(i32* byval(i32) align 2)
> +declare void @byval_type2({ i8, i8* }* byval({ i8, i8* }))
> +declare void @byval_named_type(%named_type* byval(%named_type))
> +; CHECK: declare void @byval_type(i32* byval(i32) align 2)
> +; CHECK: declare void @byval_type2({ i8, i8* }* byval({ i8, i8* }))
> +; CHECK: declare void @byval_named_type([8 x i8]* byval([8 x i8]))
> +
>  ; CHECK: attributes #0 = { alignstack=4 }
>  ; CHECK: attributes #1 = { alignstack=8 }
>  ; CHECK: attributes #2 = { alwaysinline }
>
> Modified: llvm/trunk/test/Bitcode/highLevelStructure.3.2.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/highLevelStructure.3.2.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Bitcode/highLevelStructure.3.2.ll (original)
> +++ llvm/trunk/test/Bitcode/highLevelStructure.3.2.ll Wed May 29 12:12:48
> 2019
> @@ -41,7 +41,7 @@ declare void @ParamAttr3(i8* sret)
>  declare void @ParamAttr4(i8 signext)
>  ; CHECK: declare void @ParamAttr5(i8* inreg)
>  declare void @ParamAttr5(i8* inreg)
> -; CHECK: declare void @ParamAttr6(i8* byval)
> +; CHECK: declare void @ParamAttr6(i8* byval(i8))
>  declare void @ParamAttr6(i8* byval)
>  ; CHECK: declare void @ParamAttr7(i8* noalias)
>  declare void @ParamAttr7(i8* noalias)
> @@ -51,7 +51,7 @@ declare void @ParamAttr8(i8* nocapture)
>  declare void @ParamAttr9(i8* nest noalias nocapture)
>  ; CHECK: declare void @ParamAttr10{{[(i8* sret noalias nocapture) | (i8*
> noalias nocapture sret)]}}
>  declare void @ParamAttr10(i8* sret noalias nocapture)
> -;CHECK: declare void @ParamAttr11{{[(i8* byval noalias nocapture) | (i8*
> noalias nocapture byval)]}}
> +;CHECK: declare void @ParamAttr11{{[(i8* byval(i8) noalias nocapture) |
> (i8* noalias nocapture byval(i8))]}}
>  declare void @ParamAttr11(i8* byval noalias nocapture)
>  ;CHECK: declare void @ParamAttr12{{[(i8* inreg noalias nocapture) | (i8*
> noalias nocapture inreg)]}}
>  declare void @ParamAttr12(i8* inreg noalias nocapture)
>
> Added: llvm/trunk/test/CodeGen/AArch64/byval-type.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/byval-type.ll?rev=362012&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/AArch64/byval-type.ll (added)
> +++ llvm/trunk/test/CodeGen/AArch64/byval-type.ll Wed May 29 12:12:48 2019
> @@ -0,0 +1,37 @@
> +; RUN: llc -mtriple=aarch64-linux-gnu %s -o - | FileCheck %s
> +
> +define i8 @byval_match(i8* byval(i8) align 1, i8* byval %ptr) {
> +; CHECK-LABEL: byval_match:
> +; CHECK: ldrb w0, [sp, #8]
> +  %res = load i8, i8* %ptr
> +  ret i8 %res
> +}
> +
> +define void @caller_match(i8* %p0, i8* %p1) {
> +; CHECK-LABEL: caller_match:
> +; CHECK: ldrb [[P1:w[0-9]+]], [x1]
> +; CHECK: strb [[P1]], [sp, #8]
> +; CHECK: ldrb [[P0:w[0-9]+]], [x0]
> +; CHECK: strb [[P0]], [sp]
> +; CHECK: bl byval_match
> +  call i8 @byval_match(i8* byval(i8) align 1 %p0, i8* byval %p1)
> +  ret void
> +}
> +
> +define i8 @byval_large([3 x i64]* byval([3 x i64]) align 8, i8* byval
> %ptr) {
> +; CHECK-LABEL: byval_large:
> +; CHECK: ldrb w0, [sp, #24]
> +  %res = load i8, i8* %ptr
> +  ret i8 %res
> +}
> +
> +define void @caller_large([3 x i64]* %p0, i8* %p1) {
> +; CHECK-LABEL: caller_large:
> +; CHECK: ldr [[P0HI:x[0-9]+]], [x0, #16]
> +; CHECK: ldr [[P0LO:q[0-9]+]], [x0]
> +; CHECK: str [[P0HI]], [sp, #16]
> +; CHECK: str [[P0LO]], [sp]
> +; CHECK: bl byval_large
> +  call i8 @byval_large([3 x i64]* byval([3 x i64]) align 8 %p0, i8* byval
> %p1)
> +  ret void
> +}
>
> Modified: llvm/trunk/test/Transforms/Inline/byval-tail-call.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/byval-tail-call.ll?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/Inline/byval-tail-call.ll (original)
> +++ llvm/trunk/test/Transforms/Inline/byval-tail-call.ll Wed May 29
> 12:12:48 2019
> @@ -56,7 +56,7 @@ define void @foobar(i32* %x) {
>  ; CHECK: %[[POS:.*]] = alloca i32
>  ; CHECK: %[[VAL:.*]] = load i32, i32* %x
>  ; CHECK: store i32 %[[VAL]], i32* %[[POS]]
> -; CHECK: tail call void @ext2(i32* byval nonnull %[[POS]]
> +; CHECK: tail call void @ext2(i32* nonnull byval %[[POS]]
>  ; CHECK: ret void
>    tail call void @bar2(i32* byval %x)
>    ret void
> @@ -67,7 +67,7 @@ define void @barfoo() {
>  ; CHECK: %[[POS:.*]] = alloca i32
>  ; CHECK: %[[VAL:.*]] = load i32, i32* %x
>  ; CHECK: store i32 %[[VAL]], i32* %[[POS]]
> -; CHECK: tail call void @ext2(i32* byval nonnull %[[POS]]
> +; CHECK: tail call void @ext2(i32* nonnull byval %[[POS]]
>  ; CHECK: ret void
>    %x = alloca i32
>    tail call void @bar2(i32* byval %x)
>
> Modified: llvm/trunk/unittests/IR/AttributesTest.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/AttributesTest.cpp?rev=362012&r1=362011&r2=362012&view=diff
>
> ==============================================================================
> --- llvm/trunk/unittests/IR/AttributesTest.cpp (original)
> +++ llvm/trunk/unittests/IR/AttributesTest.cpp Wed May 29 12:12:48 2019
> @@ -8,6 +8,7 @@
>
>  #include "llvm/IR/Attributes.h"
>  #include "llvm/IR/LLVMContext.h"
> +#include "llvm/IR/DerivedTypes.h"
>  #include "gtest/gtest.h"
>  using namespace llvm;
>
> @@ -40,6 +41,10 @@ TEST(Attributes, Ordering) {
>    EXPECT_TRUE(Align4 < Deref5);
>    EXPECT_TRUE(Align5 < Deref4);
>
> +  Attribute ByVal = Attribute::get(C, Attribute::ByVal,
> Type::getInt32Ty(C));
> +  EXPECT_FALSE(ByVal < Attribute::get(C, Attribute::ZExt));
> +  EXPECT_TRUE(ByVal < Align4);
> +
>    AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt),
>                           AttributeList::get(C, 1, Attribute::SExt)};
>
> @@ -166,4 +171,19 @@ TEST(Attributes, OverflowGet) {
>    EXPECT_EQ(2U, AL.getNumAttrSets());
>  }
>
> +TEST(Attributes, StringRepresentation) {
> +  LLVMContext C;
> +  StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct");
> +
> +  // Insufficiently careful printing can result in byval(%mystruct = {
> i32 })
> +  Attribute A = Attribute::getWithByValType(C, Ty);
> +  EXPECT_EQ(A.getAsString(), "byval(%mystruct)");
> +
> +  A = Attribute::getWithByValType(C, nullptr);
> +  EXPECT_EQ(A.getAsString(), "byval");
> +
> +  A = Attribute::getWithByValType(C, Type::getInt32Ty(C));
> +  EXPECT_EQ(A.getAsString(), "byval(i32)");
> +}
> +
>  } // end anonymous namespace
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190529/e16aec49/attachment.html>


More information about the llvm-commits mailing list