llvm.org GIT mirror llvm / a8aa168
Reapply: 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. The original commit did not remap byval types when linking modules, which broke LTO. This version fixes that. 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362128 91177308-0d34-0410-b5e6-96231b3b80d8 Tim Northover 1 year, 6 months ago
45 changed file(s) with 497 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
10161016 opposed to memory, though some targets use it to distinguish between
10171017 two different kinds of registers). Use of this attribute is
10181018 target-specific.
1019 ``byval``
1019 ``byval`` or ``byval()``
10201020 This indicates that the pointer parameter should really be passed by
10211021 value to the function. The attribute implies that a hidden copy of
10221022 the pointee is made between the caller and the callee, so the callee
10271027 callee (for example, ``readonly`` functions should not write to
10281028 ``byval`` parameters). This is not a valid attribute for return
10291029 values.
1030
1031 The byval attribute also supports an optional type argument, which must be
1032 the same as the pointee type of the argument.
10301033
10311034 The byval attribute also supports specifying an alignment with the
10321035 align attribute. It indicates the alignment of the stack slot to
6666 type is now mandatory. Specify `i8* null` to migrate from the obsoleted
6767 2-field form.
6868
69 * The ``byval`` attribute can now take a type parameter:
70 ``byval()``. If present it must be identical to the argument's
71 pointee type. In the next release we intend to make this parameter
72 mandatory in preparation for opaque pointer types.
73
6974 Changes to the ARM Backend
7075 --------------------------
7176
187187 bool IsSwiftSelf : 1;
188188 bool IsSwiftError : 1;
189189 uint16_t Alignment = 0;
190 Type *ByValType = nullptr;
190191
191192 ArgListEntry()
192193 : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false),
7777 /// If this is a byval or inalloca argument, return its alignment.
7878 unsigned getParamAlignment() const;
7979
80 /// If this is a byval argument, return its type.
81 Type *getParamByValType() const;
82
8083 /// Return true if this argument has the nest attribute.
8184 bool hasNestAttr() const;
8285
8989 static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val = 0);
9090 static Attribute get(LLVMContext &Context, StringRef Kind,
9191 StringRef Val = StringRef());
92 static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
9293
9394 /// Return a uniquified Attribute object that has the specific
9495 /// alignment set.
101102 static Attribute getWithAllocSizeArgs(LLVMContext &Context,
102103 unsigned ElemSizeArg,
103104 const Optional &NumElemsArg);
105 static Attribute getWithByValType(LLVMContext &Context, Type *Ty);
104106
105107 //===--------------------------------------------------------------------===//
106108 // Attribute Accessors
116118 /// attribute.
117119 bool isStringAttribute() const;
118120
121 /// Return true if the attribute is a type attribute.
122 bool isTypeAttribute() const;
123
119124 /// Return true if the attribute is present.
120125 bool hasAttribute(AttrKind Val) const;
121126
137142 /// Return the attribute's value as a string. This requires the
138143 /// attribute to be a string attribute.
139144 StringRef getValueAsString() const;
145
146 /// Return the attribute's value as a Type. This requires the attribute to be
147 /// a type attribute.
148 Type *getValueAsType() const;
140149
141150 /// Returns the alignment field of an attribute as a byte alignment
142151 /// value.
278287 unsigned getStackAlignment() const;
279288 uint64_t getDereferenceableBytes() const;
280289 uint64_t getDereferenceableOrNullBytes() const;
290 Type *getByValType() const;
281291 std::pair> getAllocSizeArgs() const;
282292 std::string getAsString(bool InAttrGrp = false) const;
283293
597607 /// Return the alignment for the specified function parameter.
598608 unsigned getParamAlignment(unsigned ArgNo) const;
599609
610 /// Return the byval type for the specified function parameter.
611 Type *getParamByValType(unsigned ArgNo) const;
612
600613 /// Get the stack alignment.
601614 unsigned getStackAlignment(unsigned Index) const;
602615
696709 uint64_t DerefBytes = 0;
697710 uint64_t DerefOrNullBytes = 0;
698711 uint64_t AllocSizeArgs = 0;
712 Type *ByValType = nullptr;
699713
700714 public:
701715 AttrBuilder() = default;
771785 /// dereferenceable_or_null attribute exists (zero is returned otherwise).
772786 uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; }
773787
788 /// Retrieve the byval type.
789 Type *getByValType() const { return ByValType; }
790
774791 /// Retrieve the allocsize args, if the allocsize attribute exists. If it
775792 /// doesn't exist, pair(0, 0) is returned.
776793 std::pair> getAllocSizeArgs() const;
794811 /// This turns one (or two) ints into the form used internally in Attribute.
795812 AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg,
796813 const Optional &NumElemsArg);
814
815 /// This turns a byval type into the form used internally in Attribute.
816 AttrBuilder &addByValAttr(Type *Ty);
797817
798818 /// Add an allocsize attribute, using the representation returned by
799819 /// Attribute.getIntValue().
412412 /// Extract the alignment for a call or parameter (0=unknown).
413413 unsigned getParamAlignment(unsigned ArgNo) const {
414414 CALLSITE_DELEGATE_GETTER(getParamAlignment(ArgNo));
415 }
416
417 /// Extract the byval type for a call or parameter (nullptr=unknown).
418 Type *getParamByValType(unsigned ArgNo) const {
419 CALLSITE_DELEGATE_GETTER(getParamByValType(ArgNo));
415420 }
416421
417422 /// Extract the number of dereferenceable bytes for a call or parameter
430430 return AttributeSets.getParamAlignment(ArgNo);
431431 }
432432
433 /// Extract the byval type for a parameter (nullptr=unknown).
434 Type *getParamByValType(unsigned ArgNo) const {
435 return AttributeSets.getParamByValType(ArgNo);
436 }
437
433438 /// Extract the number of dereferenceable bytes for a call or
434439 /// parameter (0=unknown).
435440 /// @param i AttributeList index, referring to a return value or argument.
15591559 return Attrs.getParamAlignment(ArgNo);
15601560 }
15611561
1562 /// Extract the byval type for a call or parameter (nullptr=unknown).
1563 Type *getParamByValType(unsigned ArgNo) const {
1564 return Attrs.getParamByValType(ArgNo);
1565 }
1566
15621567 /// Extract the number of dereferenceable bytes for a call or
15631568 /// parameter (0=unknown).
15641569 uint64_t getDereferenceableBytes(unsigned i) const {
16001600 B.addAlignmentAttr(Alignment);
16011601 continue;
16021602 }
1603 case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
1603 case lltok::kw_byval: {
1604 Type *Ty;
1605 if (ParseByValWithOptionalType(Ty))
1606 return true;
1607 B.addByValAttr(Ty);
1608 continue;
1609 }
16041610 case lltok::kw_dereferenceable: {
16051611 uint64_t Bytes;
16061612 if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
24532459 return false;
24542460 }
24552461
2462 /// ParseByValWithOptionalType
2463 /// ::= byval
2464 /// ::= byval()
2465 bool LLParser::ParseByValWithOptionalType(Type *&Result) {
2466 Result = nullptr;
2467 if (!EatIfPresent(lltok::kw_byval))
2468 return true;
2469 if (!EatIfPresent(lltok::lparen))
2470 return false;
2471 if (ParseType(Result))
2472 return true;
2473 if (!EatIfPresent(lltok::rparen))
2474 return Error(Lex.getLoc(), "expected ')'");
2475 return false;
2476 }
2477
24562478 /// ParseOptionalOperandBundles
24572479 /// ::= /*empty*/
24582480 /// ::= '[' OperandBundle [, OperandBundle ]* ']'
338338 bool ParseFnAttributeValuePairs(AttrBuilder &B,
339339 std::vector &FwdRefAttrGrps,
340340 bool inAttrGrp, LocTy &BuiltinLoc);
341 bool ParseByValWithOptionalType(Type *&Result);
341342
342343 // Module Summary Index Parsing.
343344 bool SkipModuleSummaryEntry();
636636 ValNo = InstNum - ValNo;
637637 return getFnValueByID(ValNo, Ty);
638638 }
639
640 /// Upgrades old-style typeless byval attributes by adding the corresponding
641 /// argument's pointee type.
642 void propagateByValTypes(CallBase *CB);
639643
640644 /// Converts alignment exponent (i.e. power of two (or zero)) to the
641645 /// corresponding alignment to use. If alignment is too large, returns
14911495 if (Error Err = parseAttrKind(Record[++i], &Kind))
14921496 return Err;
14931497
1498 // Upgrade old-style byval attribute to one with a type, even if it's
1499 // nullptr. We will have to insert the real type when we associate
1500 // this AttributeList with a function.
1501 if (Kind == Attribute::ByVal)
1502 B.addByValAttr(nullptr);
1503
14941504 B.addAttribute(Kind);
14951505 } else if (Record[i] == 1) { // Integer attribute
14961506 Attribute::AttrKind Kind;
15061516 B.addDereferenceableOrNullAttr(Record[++i]);
15071517 else if (Kind == Attribute::AllocSize)
15081518 B.addAllocSizeAttrFromRawRepr(Record[++i]);
1509 } else { // String attribute
1510 assert((Record[i] == 3 || Record[i] == 4) &&
1511 "Invalid attribute group entry");
1519 } else if (Record[i] == 3 || Record[i] == 4) { // String attribute
15121520 bool HasValue = (Record[i++] == 4);
15131521 SmallString<64> KindStr;
15141522 SmallString<64> ValStr;
15261534 }
15271535
15281536 B.addAttribute(KindStr.str(), ValStr.str());
1537 } else {
1538 assert((Record[i] == 5 || Record[i] == 6) &&
1539 "Invalid attribute group entry");
1540 bool HasType = Record[i] == 6;
1541 Attribute::AttrKind Kind;
1542 if (Error Err = parseAttrKind(Record[++i], &Kind))
1543 return Err;
1544 if (Kind == Attribute::ByVal)
1545 B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
15291546 }
15301547 }
15311548
30263043 uint64_t RawLinkage = Record[3];
30273044 Func->setLinkage(getDecodedLinkage(RawLinkage));
30283045 Func->setAttributes(getAttributes(Record[4]));
3046
3047 // Upgrade any old-style byval without a type by propagating the argument's
3048 // pointee type. There should be no opaque pointers where the byval type is
3049 // implicit.
3050 for (auto &Arg : Func->args()) {
3051 if (Arg.hasByValAttr() && !Arg.getParamByValType()) {
3052 Arg.removeAttr(Attribute::ByVal);
3053 Arg.addAttr(Attribute::getWithByValType(
3054 Context, Arg.getType()->getPointerElementType()));
3055 }
3056 }
30293057
30303058 unsigned Alignment;
30313059 if (Error Err = parseAlignmentValue(Record[5], Alignment))
34403468 return Error::success();
34413469 }
34423470
3471 void BitcodeReader::propagateByValTypes(CallBase *CB) {
3472 for (unsigned i = 0; i < CB->getNumArgOperands(); ++i) {
3473 if (CB->paramHasAttr(i, Attribute::ByVal) &&
3474 !CB->getAttribute(i, Attribute::ByVal).getValueAsType()) {
3475 CB->removeParamAttr(i, Attribute::ByVal);
3476 CB->addParamAttr(
3477 i, Attribute::getWithByValType(
3478 Context,
3479 CB->getArgOperand(i)->getType()->getPointerElementType()));
3480 }
3481 }
3482 }
3483
34433484 /// Lazily parse the specified function body block.
34443485 Error BitcodeReader::parseFunctionBody(Function *F) {
34453486 if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID))
42554296 cast(I)->setCallingConv(
42564297 static_cast(CallingConv::MaxID & CCInfo));
42574298 cast(I)->setAttributes(PAL);
4299 propagateByValTypes(cast(I));
4300
42584301 break;
42594302 }
42604303 case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval]
47304773 TCK = CallInst::TCK_NoTail;
47314774 cast(I)->setTailCallKind(TCK);
47324775 cast(I)->setAttributes(PAL);
4776 propagateByValTypes(cast(I));
47334777 if (FMF.any()) {
47344778 if (!isa(I))
47354779 return error("Fast-math-flags specified for call without "
746746 Record.push_back(1);
747747 Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
748748 Record.push_back(Attr.getValueAsInt());
749 } else {
749 } else if (Attr.isStringAttribute()) {
750750 StringRef Kind = Attr.getKindAsString();
751751 StringRef Val = Attr.getValueAsString();
752752
757757 Record.append(Val.begin(), Val.end());
758758 Record.push_back(0);
759759 }
760 } else {
761 assert(Attr.isTypeAttribute());
762 Type *Ty = Attr.getValueAsType();
763 Record.push_back(Ty ? 6 : 5);
764 Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
765 if (Ty)
766 Record.push_back(VE.getTypeID(Attr.getValueAsType()));
760767 }
761768 }
762769
41254132 // Emit blockinfo, which defines the standard abbreviations etc.
41264133 writeBlockInfo();
41274134
4135 // Emit information describing all of the types in the module.
4136 writeTypeTable();
4137
41284138 // Emit information about attribute groups.
41294139 writeAttributeGroupTable();
41304140
41314141 // Emit information about parameter attributes.
41324142 writeAttributeTable();
4133
4134 // Emit information describing all of the types in the module.
4135 writeTypeTable();
41364143
41374144 writeComdats();
41384145
948948 incorporateFunctionMetadata(F);
949949
950950 // Adding function arguments to the value table.
951 for (const auto &I : F.args())
951 for (const auto &I : F.args()) {
952952 EnumerateValue(&I);
953
953 if (I.hasAttribute(Attribute::ByVal) && I.getParamByValType())
954 EnumerateType(I.getParamByValType());
955 }
954956 FirstFuncConstantID = Values.size();
955957
956958 // Add all function-level constants to the value table.
8686
8787 if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) {
8888 Type *ElementTy = cast(Arg.Ty)->getElementType();
89 Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
89
90 auto Ty = Attrs.getAttribute(OpIdx, Attribute::ByVal).getValueAsType();
91 Arg.Flags.setByValSize(DL.getTypeAllocSize(Ty ? Ty : ElementTy));
92
9093 // For ByVal, alignment should be passed from FE. BE will guess if
9194 // this info is not there but there are cases it cannot get right.
9295 unsigned FrameAlign;
12031203 if (Arg.IsByVal || Arg.IsInAlloca) {
12041204 PointerType *Ty = cast(Arg.Ty);
12051205 Type *ElementTy = Ty->getElementType();
1206 unsigned FrameSize = DL.getTypeAllocSize(ElementTy);
1207 // For ByVal, alignment should come from FE. BE will guess if this info is
1208 // not there, but there are cases it cannot get right.
1206 unsigned FrameSize =
1207 DL.getTypeAllocSize(Arg.ByValType ? Arg.ByValType : ElementTy);
1208
1209 // For ByVal, alignment should come from FE. BE will guess if this info
1210 // is not there, but there are cases it cannot get right.
12091211 unsigned FrameAlign = Arg.Alignment;
12101212 if (!FrameAlign)
12111213 FrameAlign = TLI.getByValTypeAlignment(ElementTy, DL);
90759075 if (Args[i].IsByVal || Args[i].IsInAlloca) {
90769076 PointerType *Ty = cast(Args[i].Ty);
90779077 Type *ElementTy = Ty->getElementType();
9078 Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
9079 // For ByVal, alignment should come from FE. BE will guess if this
9078
9079 unsigned FrameSize = DL.getTypeAllocSize(
9080 Args[i].ByValType ? Args[i].ByValType : ElementTy);
9081 Flags.setByValSize(FrameSize);
9082
90809083 // info is not there but there are cases it cannot get right.
90819084 unsigned FrameAlign;
90829085 if (Args[i].Alignment)
95739576 if (Flags.isByVal() || Flags.isInAlloca()) {
95749577 PointerType *Ty = cast(Arg.getType());
95759578 Type *ElementTy = Ty->getElementType();
9576 Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
9577 // For ByVal, alignment should be passed from FE. BE will guess if
9578 // this info is not there but there are cases it cannot get right.
9579
9580 // For ByVal, size and alignment should be passed from FE. BE will
9581 // guess if this info is not there but there are cases it cannot get
9582 // right.
9583 unsigned FrameSize = DL.getTypeAllocSize(
9584 Arg.getParamByValType() ? Arg.getParamByValType() : ElementTy);
9585 Flags.setByValSize(FrameSize);
9586
95799587 unsigned FrameAlign;
95809588 if (Arg.getParamAlignment())
95819589 FrameAlign = Arg.getParamAlignment();
111111 IsSwiftSelf = Call->paramHasAttr(ArgIdx, Attribute::SwiftSelf);
112112 IsSwiftError = Call->paramHasAttr(ArgIdx, Attribute::SwiftError);
113113 Alignment = Call->getParamAlignment(ArgIdx);
114 ByValType = Call->getParamByValType(ArgIdx);
114115 }
115116
116117 /// Generate a libcall taking the given operands as arguments and returning a
2828 namespace llvm {
2929
3030 class LLVMContext;
31 class Type;
3132
3233 //===----------------------------------------------------------------------===//
3334 /// \class
4041 enum AttrEntryKind {
4142 EnumAttrEntry,
4243 IntAttrEntry,
43 StringAttrEntry
44 StringAttrEntry,
45 TypeAttrEntry,
4446 };
4547
4648 AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {}
5557 bool isEnumAttribute() const { return KindID == EnumAttrEntry; }
5658 bool isIntAttribute() const { return KindID == IntAttrEntry; }
5759 bool isStringAttribute() const { return KindID == StringAttrEntry; }
60 bool isTypeAttribute() const { return KindID == TypeAttrEntry; }
5861
5962 bool hasAttribute(Attribute::AttrKind A) const;
6063 bool hasAttribute(StringRef Kind) const;
6568 StringRef getKindAsString() const;
6669 StringRef getValueAsString() const;
6770
71 Type *getValueAsType() const;
72
6873 /// Used when sorting the attributes.
6974 bool operator<(const AttributeImpl &AI) const;
7075
7176 void Profile(FoldingSetNodeID &ID) const {
7277 if (isEnumAttribute())
73 Profile(ID, getKindAsEnum(), 0);
78 Profile(ID, getKindAsEnum(), static_cast(0));
7479 else if (isIntAttribute())
7580 Profile(ID, getKindAsEnum(), getValueAsInt());
81 else if (isStringAttribute())
82 Profile(ID, getKindAsString(), getValueAsString());
7683 else
77 Profile(ID, getKindAsString(), getValueAsString());
84 Profile(ID, getKindAsEnum(), getValueAsType());
7885 }
7986
8087 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
8693 static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) {
8794 ID.AddString(Kind);
8895 if (!Values.empty()) ID.AddString(Values);
96 }
97
98 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
99 Type *Ty) {
100 ID.AddInteger(Kind);
101 ID.AddPointer(Ty);
89102 }
90103 };
91104
144157 StringRef getStringValue() const { return Val; }
145158 };
146159
160 class TypeAttributeImpl : public EnumAttributeImpl {
161 virtual void anchor();
162
163 Type *Ty;
164
165 public:
166 TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty)
167 : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {}
168
169 Type *getTypeValue() const { return Ty; }
170 };
171
147172 //===----------------------------------------------------------------------===//
148173 /// \class
149174 /// This class represents a group of attributes that apply to one
188213 uint64_t getDereferenceableOrNullBytes() const;
189214 std::pair> getAllocSizeArgs() const;
190215 std::string getAsString(bool InAttrGrp) const;
216 Type *getByValType() const;
191217
192218 using iterator = const Attribute *;
193219
120120 return Attribute(PA);
121121 }
122122
123 Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
124 Type *Ty) {
125 LLVMContextImpl *pImpl = Context.pImpl;
126 FoldingSetNodeID ID;
127 ID.AddInteger(Kind);
128 ID.AddPointer(Ty);
129
130 void *InsertPoint;
131 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
132
133 if (!PA) {
134 // If we didn't find any existing attributes of the same shape then create a
135 // new one and insert it.
136 PA = new TypeAttributeImpl(Kind, Ty);
137 pImpl->AttrsSet.InsertNode(PA, InsertPoint);
138 }
139
140 // Return the Attribute that we found or created.
141 return Attribute(PA);
142 }
143
123144 Attribute Attribute::getWithAlignment(LLVMContext &Context, uint64_t Align) {
124145 assert(isPowerOf2_32(Align) && "Alignment must be a power of two.");
125146 assert(Align <= 0x40000000 && "Alignment too large.");
143164 uint64_t Bytes) {
144165 assert(Bytes && "Bytes must be non-zero.");
145166 return get(Context, DereferenceableOrNull, Bytes);
167 }
168
169 Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {
170 return get(Context, ByVal, Ty);
146171 }
147172
148173 Attribute
169194 return pImpl && pImpl->isStringAttribute();
170195 }
171196
197 bool Attribute::isTypeAttribute() const {
198 return pImpl && pImpl->isTypeAttribute();
199 }
200
172201 Attribute::AttrKind Attribute::getKindAsEnum() const {
173202 if (!pImpl) return None;
174 assert((isEnumAttribute() || isIntAttribute()) &&
203 assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute()) &&
175204 "Invalid attribute type to get the kind as an enum!");
176205 return pImpl->getKindAsEnum();
177206 }
196225 "Invalid attribute type to get the value as a string!");
197226 return pImpl->getValueAsString();
198227 }
228
229 Type *Attribute::getValueAsType() const {
230 if (!pImpl) return {};
231 assert(isTypeAttribute() &&
232 "Invalid attribute type to get the value as a type!");
233 return pImpl->getValueAsType();
234 }
235
199236
200237 bool Attribute::hasAttribute(AttrKind Kind) const {
201238 return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
251288 return "argmemonly";
252289 if (hasAttribute(Attribute::Builtin))
253290 return "builtin";
254 if (hasAttribute(Attribute::ByVal))
255 return "byval";
256291 if (hasAttribute(Attribute::Convergent))
257292 return "convergent";
258293 if (hasAttribute(Attribute::SwiftError))
352387 if (hasAttribute(Attribute::ImmArg))
353388 return "immarg";
354389
390 if (hasAttribute(Attribute::ByVal)) {
391 std::string Result;
392 Result += "byval";
393 if (Type *Ty = getValueAsType()) {
394 raw_string_ostream OS(Result);
395 Result += '(';
396 Ty->print(OS, false, true);
397 OS.flush();
398 Result += ')';
399 }
400 return Result;
401 }
402
355403 // FIXME: These should be output like this:
356404 //
357405 // align=4
450498
451499 void StringAttributeImpl::anchor() {}
452500
501 void TypeAttributeImpl::anchor() {}
502
453503 bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const {
454504 if (isStringAttribute()) return false;
455505 return getKindAsEnum() == A;
461511 }
462512
463513 Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
464 assert(isEnumAttribute() || isIntAttribute());
514 assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute());
465515 return static_cast(this)->getEnumKind();
466516 }
467517
478528 StringRef AttributeImpl::getValueAsString() const {
479529 assert(isStringAttribute());
480530 return static_cast(this)->getStringValue();
531 }
532
533 Type *AttributeImpl::getValueAsType() const {
534 assert(isTypeAttribute());
535 return static_cast(this)->getTypeValue();
481536 }
482537
483538 bool AttributeImpl::operator<(const AttributeImpl &AI) const {
487542 if (AI.isEnumAttribute()) return getKindAsEnum() < AI.getKindAsEnum();
488543 if (AI.isIntAttribute()) return true;
489544 if (AI.isStringAttribute()) return true;
545 if (AI.isTypeAttribute()) return true;
546 }
547
548 if (isTypeAttribute()) {
549 if (AI.isEnumAttribute()) return false;
550 if (AI.isTypeAttribute()) {
551 assert(getKindAsEnum() != AI.getKindAsEnum() &&
552 "Comparison of types would be unstable");
553 return getKindAsEnum() < AI.getKindAsEnum();
554 }
555 if (AI.isIntAttribute()) return true;
556 if (AI.isStringAttribute()) return true;
490557 }
491558
492559 if (isIntAttribute()) {
493560 if (AI.isEnumAttribute()) return false;
561 if (AI.isTypeAttribute()) return false;
494562 if (AI.isIntAttribute()) {
495563 if (getKindAsEnum() == AI.getKindAsEnum())
496564 return getValueAsInt() < AI.getValueAsInt();
499567 if (AI.isStringAttribute()) return true;
500568 }
501569
570 assert(isStringAttribute());
502571 if (AI.isEnumAttribute()) return false;
572 if (AI.isTypeAttribute()) return false;
503573 if (AI.isIntAttribute()) return false;
504574 if (getKindAsString() == AI.getKindAsString())
505575 return getValueAsString() < AI.getValueAsString();
605675
606676 uint64_t AttributeSet::getDereferenceableOrNullBytes() const {
607677 return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;
678 }
679
680 Type *AttributeSet::getByValType() const {
681 return SetNode ? SetNode->getByValType() : nullptr;
608682 }
609683
610684 std::pair> AttributeSet::getAllocSizeArgs() const {
690764
691765 Attribute Attr;
692766 switch (Kind) {
767 case Attribute::ByVal:
768 Attr = Attribute::getWithByValType(C, B.getByValType());
769 break;
693770 case Attribute::Alignment:
694771 Attr = Attribute::getWithAlignment(C, B.getAlignment());
695772 break;
759836 return 0;
760837 }
761838
839 Type *AttributeSetNode::getByValType() const {
840 for (const auto I : *this)
841 if (I.hasAttribute(Attribute::ByVal))
842 return I.getValueAsType();
843 return 0;
844 }
845
762846 uint64_t AttributeSetNode::getDereferenceableBytes() const {
763847 for (const auto I : *this)
764848 if (I.hasAttribute(Attribute::Dereferenceable))
12571341 return getAttributes(ArgNo + FirstArgIndex).getAlignment();
12581342 }
12591343
1344 Type *AttributeList::getParamByValType(unsigned Index) const {
1345 return getAttributes(Index+FirstArgIndex).getByValType();
1346 }
1347
1348
12601349 unsigned AttributeList::getStackAlignment(unsigned Index) const {
12611350 return getAttributes(Index).getStackAlignment();
12621351 }
13351424 TargetDepAttrs.clear();
13361425 Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0;
13371426 AllocSizeArgs = 0;
1427 ByValType = nullptr;
13381428 }
13391429
13401430 AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
13591449 Alignment = Attr.getAlignment();
13601450 else if (Kind == Attribute::StackAlignment)
13611451 StackAlignment = Attr.getStackAlignment();
1452 else if (Kind == Attribute::ByVal)
1453 ByValType = Attr.getValueAsType();
13621454 else if (Kind == Attribute::Dereferenceable)
13631455 DerefBytes = Attr.getDereferenceableBytes();
13641456 else if (Kind == Attribute::DereferenceableOrNull)
13811473 Alignment = 0;
13821474 else if (Val == Attribute::StackAlignment)
13831475 StackAlignment = 0;
1476 else if (Val == Attribute::ByVal)
1477 ByValType = nullptr;
13841478 else if (Val == Attribute::Dereferenceable)
13851479 DerefBytes = 0;
13861480 else if (Val == Attribute::DereferenceableOrNull)
14631557 return *this;
14641558 }
14651559
1560 AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
1561 Attrs[Attribute::ByVal] = true;
1562 ByValType = Ty;
1563 return *this;
1564 }
1565
14661566 AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
14671567 // FIXME: What if both have alignments, but they don't match?!
14681568 if (!Alignment)
14801580 if (!AllocSizeArgs)
14811581 AllocSizeArgs = B.AllocSizeArgs;
14821582
1583 if (!ByValType)
1584 ByValType = B.ByValType;
1585
14831586 Attrs |= B.Attrs;
14841587
14851588 for (auto I : B.td_attrs())
15041607
15051608 if (B.AllocSizeArgs)
15061609 AllocSizeArgs = 0;
1610
1611 if (B.ByValType)
1612 ByValType = nullptr;
15071613
15081614 Attrs &= ~B.Attrs;
15091615
15641670 return false;
15651671
15661672 return Alignment == B.Alignment && StackAlignment == B.StackAlignment &&
1567 DerefBytes == B.DerefBytes;
1673 DerefBytes == B.DerefBytes && ByValType == B.ByValType;
15681674 }
15691675
15701676 //===----------------------------------------------------------------------===//
110110 unsigned Argument::getParamAlignment() const {
111111 assert(getType()->isPointerTy() && "Only pointers have alignments");
112112 return getParent()->getParamAlignment(getArgNo());
113 }
114
115 Type *Argument::getParamByValType() const {
116 assert(getType()->isPointerTy() && "Only pointers have byval types");
117 return getParent()->getParamByValType(getArgNo());
113118 }
114119
115120 uint64_t Argument::getDereferenceableBytes() const {
16941694 "'noinline and alwaysinline' are incompatible!",
16951695 V);
16961696
1697 if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) {
1698 Assert(Attrs.getByValType() == cast(Ty)->getElementType(),
1699 "Attribute 'byval' type does not match parameter!");
1700 }
1701
16971702 AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
16981703 Assert(!AttrBuilder(Attrs).overlaps(IncompatibleAttrs),
16991704 "Wrong types for attribute: " +
488488 void linkAliasBody(GlobalAlias &Dst, GlobalAlias &Src);
489489 Error linkGlobalValueBody(GlobalValue &Dst, GlobalValue &Src);
490490
491 /// Replace all types in the source AttributeList with the
492 /// corresponding destination type.
493 AttributeList mapAttributeTypes(LLVMContext &C, AttributeList Attrs);
494
491495 /// Functions that take care of cloning a specific global value type
492496 /// into the destination module.
493497 GlobalVariable *copyGlobalVariableProto(const GlobalVariable *SGVar);
627631 return NewDGV;
628632 }
629633
634 AttributeList IRLinker::mapAttributeTypes(LLVMContext &C, AttributeList Attrs) {
635 for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
636 if (Attrs.hasAttribute(i, Attribute::ByVal)) {
637 Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType();
638 if (!Ty)
639 continue;
640
641 Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal);
642 Attrs = Attrs.addAttribute(
643 C, i, Attribute::getWithByValType(C, TypeMap.get(Ty)));
644 }
645 }
646 return Attrs;
647 }
648
630649 /// Link the function in the source module into the destination module if
631650 /// needed, setting up mapping information.
632651 Function *IRLinker::copyFunctionProto(const Function *SF) {
636655 Function::Create(TypeMap.get(SF->getFunctionType()),
637656 GlobalValue::ExternalLinkage, SF->getName(), &DstM);
638657 F->copyAttributesFrom(SF);
658 F->setAttributes(mapAttributeTypes(F->getContext(), F->getAttributes()));
639659 return F;
640660 }
641661
912912 Tys.push_back(TypeMapper->remapType(Ty));
913913 CS.mutateFunctionType(FunctionType::get(
914914 TypeMapper->remapType(I->getType()), Tys, FTy->isVarArg()));
915
916 LLVMContext &C = CS->getContext();
917 AttributeList Attrs = CS.getAttributes();
918 for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
919 if (Attrs.hasAttribute(i, Attribute::ByVal)) {
920 Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType();
921 if (!Ty)
922 continue;
923
924 Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal);
925 Attrs = Attrs.addAttribute(
926 C, i, Attribute::getWithByValType(C, TypeMapper->remapType(Ty)));
927 }
928 }
929 CS.setAttributes(Attrs);
915930 return;
916931 }
917932 if (auto *AI = dyn_cast(I))
0 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
1
2 ; CHECK: define void @foo(i32* byval(i32) align 4)
3 define void @foo(i32* byval(i32) align 4) {
4 ret void
5 }
6
7 ; CHECK: define void @bar({ i32*, i8 }* byval({ i32*, i8 }) align 4)
8 define void @bar({i32*, i8}* byval({i32*, i8}) align 4) {
9 ret void
10 }
11
12 define void @caller({ i32*, i8 }* %ptr) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
13 ; CHECK: call void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
14 ; CHECK: invoke void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
15 call void @bar({i32*, i8}* byval %ptr)
16 invoke void @bar({i32*, i8}* byval %ptr) to label %success unwind label %fail
17
18 success:
19 ret void
20
21 fail:
22 landingpad { i8*, i32 } cleanup
23 ret void
24 }
25
26 ; CHECK: declare void @baz([8 x i8]* byval([8 x i8]))
27 %named_type = type [8 x i8]
28 declare void @baz(%named_type* byval(%named_type))
29
30 declare i32 @__gxx_personality_v0(...)
0 ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
1
2 ; CHECK: Attribute 'byval' type does not match parameter!
3 declare void @foo(i32* byval(i8))
0 ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
1
2 ; CHECK: error: void type only allowed for function results
3 declare void @foo(i32* byval(void))
0 ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
1
2 ; CHECK: Attributes 'byval' and 'inalloca' do not support unsized types!
3 declare void @foo(void()* byval(void()))
4747 }
4848
4949 define void @f8(i8* byval)
50 ; CHECK: define void @f8(i8* byval)
50 ; CHECK: define void @f8(i8* byval(i8))
5151 {
5252 ret void;
5353 }
4444 }
4545
4646 define void @f8(i8* byval)
47 ; CHECK: define void @f8(i8* byval)
47 ; CHECK: define void @f8(i8* byval(i8))
4848 {
4949 ret void;
5050 }
0 RUN: llvm-dis %p/Inputs/byval-upgrade.bc -o - | FileCheck %s
1
2 Make sure we upgrade old-stile IntAttribute byval records to a fully typed
3 version correctly.
4
5 CHECK: call void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
6 CHECK: invoke void @bar({ i32*, i8 }* byval({ i32*, i8 }) %ptr)
403403 declare void @f.param.inreg(i8 inreg)
404404 ; CHECK: declare void @f.param.inreg(i8 inreg)
405405 declare void @f.param.byval({ i8, i8 }* byval)
406 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
406 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
407407 declare void @f.param.inalloca(i8* inalloca)
408408 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
409409 declare void @f.param.sret(i8* sret)
409409 declare void @f.param.inreg(i8 inreg)
410410 ; CHECK: declare void @f.param.inreg(i8 inreg)
411411 declare void @f.param.byval({ i8, i8 }* byval)
412 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
412 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
413413 declare void @f.param.inalloca(i8* inalloca)
414414 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
415415 declare void @f.param.sret(i8* sret)
434434 declare void @f.param.inreg(i8 inreg)
435435 ; CHECK: declare void @f.param.inreg(i8 inreg)
436436 declare void @f.param.byval({ i8, i8 }* byval)
437 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
437 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
438438 declare void @f.param.inalloca(i8* inalloca)
439439 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
440440 declare void @f.param.sret(i8* sret)
503503 declare void @f.param.inreg(i8 inreg)
504504 ; CHECK: declare void @f.param.inreg(i8 inreg)
505505 declare void @f.param.byval({ i8, i8 }* byval)
506 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
506 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
507507 declare void @f.param.inalloca(i8* inalloca)
508508 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
509509 declare void @f.param.sret(i8* sret)
503503 declare void @f.param.inreg(i8 inreg)
504504 ; CHECK: declare void @f.param.inreg(i8 inreg)
505505 declare void @f.param.byval({ i8, i8 }* byval)
506 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
506 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
507507 declare void @f.param.inalloca(i8* inalloca)
508508 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
509509 declare void @f.param.sret(i8* sret)
507507 declare void @f.param.inreg(i8 inreg)
508508 ; CHECK: declare void @f.param.inreg(i8 inreg)
509509 declare void @f.param.byval({ i8, i8 }* byval)
510 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
510 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
511511 declare void @f.param.inalloca(i8* inalloca)
512512 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
513513 declare void @f.param.sret(i8* sret)
514514 declare void @f.param.inreg(i8 inreg)
515515 ; CHECK: declare void @f.param.inreg(i8 inreg)
516516 declare void @f.param.byval({ i8, i8 }* byval)
517 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
517 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
518518 declare void @f.param.inalloca(i8* inalloca)
519519 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
520520 declare void @f.param.sret(i8* sret)
528528 declare void @f.param.inreg(i8 inreg)
529529 ; CHECK: declare void @f.param.inreg(i8 inreg)
530530 declare void @f.param.byval({ i8, i8 }* byval)
531 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval)
531 ; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
532532 declare void @f.param.inalloca(i8* inalloca)
533533 ; CHECK: declare void @f.param.inalloca(i8* inalloca)
534534 declare void @f.param.sret(i8* sret)
17341734 declare void @llvm.test.immarg.intrinsic(i32 immarg)
17351735 ; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)
17361736
1737 ; byval attribute with type
1738 %named_type = type [8 x i8]
1739 declare void @byval_type(i32* byval(i32) align 2)
1740 declare void @byval_type2({ i8, i8* }* byval({ i8, i8* }))
1741 declare void @byval_named_type(%named_type* byval(%named_type))
1742 ; CHECK: declare void @byval_type(i32* byval(i32) align 2)
1743 ; CHECK: declare void @byval_type2({ i8, i8* }* byval({ i8, i8* }))
1744 ; CHECK: declare void @byval_named_type([8 x i8]* byval([8 x i8]))
1745
17371746 ; CHECK: attributes #0 = { alignstack=4 }
17381747 ; CHECK: attributes #1 = { alignstack=8 }
17391748 ; CHECK: attributes #2 = { alwaysinline }
4040 declare void @ParamAttr4(i8 signext)
4141 ; CHECK: declare void @ParamAttr5(i8* inreg)
4242 declare void @ParamAttr5(i8* inreg)
43 ; CHECK: declare void @ParamAttr6(i8* byval)
43 ; CHECK: declare void @ParamAttr6(i8* byval(i8))
4444 declare void @ParamAttr6(i8* byval)
4545 ; CHECK: declare void @ParamAttr7(i8* noalias)
4646 declare void @ParamAttr7(i8* noalias)
5050 declare void @ParamAttr9(i8* nest noalias nocapture)
5151 ; CHECK: declare void @ParamAttr10{{[(i8* sret noalias nocapture) | (i8* noalias nocapture sret)]}}
5252 declare void @ParamAttr10(i8* sret noalias nocapture)
53 ;CHECK: declare void @ParamAttr11{{[(i8* byval noalias nocapture) | (i8* noalias nocapture byval)]}}
53 ;CHECK: declare void @ParamAttr11{{[(i8* byval(i8) noalias nocapture) | (i8* noalias nocapture byval(i8))]}}
5454 declare void @ParamAttr11(i8* byval noalias nocapture)
5555 ;CHECK: declare void @ParamAttr12{{[(i8* inreg noalias nocapture) | (i8* noalias nocapture inreg)]}}
5656 declare void @ParamAttr12(i8* inreg noalias nocapture)
0 ; RUN: llc -mtriple=aarch64-linux-gnu %s -o - | FileCheck %s
1
2 define i8 @byval_match(i8* byval(i8) align 1, i8* byval %ptr) {
3 ; CHECK-LABEL: byval_match:
4 ; CHECK: ldrb w0, [sp, #8]
5 %res = load i8, i8* %ptr
6 ret i8 %res
7 }
8
9 define void @caller_match(i8* %p0, i8* %p1) {
10 ; CHECK-LABEL: caller_match:
11 ; CHECK: ldrb [[P1:w[0-9]+]], [x1]
12 ; CHECK: strb [[P1]], [sp, #8]
13 ; CHECK: ldrb [[P0:w[0-9]+]], [x0]
14 ; CHECK: strb [[P0]], [sp]
15 ; CHECK: bl byval_match
16 call i8 @byval_match(i8* byval(i8) align 1 %p0, i8* byval %p1)
17 ret void
18 }
19
20 define i8 @byval_large([3 x i64]* byval([3 x i64]) align 8, i8* byval %ptr) {
21 ; CHECK-LABEL: byval_large:
22 ; CHECK: ldrb w0, [sp, #24]
23 %res = load i8, i8* %ptr
24 ret i8 %res
25 }
26
27 define void @caller_large([3 x i64]* %p0, i8* %p1) {
28 ; CHECK-LABEL: caller_large:
29 ; CHECK: ldr [[P0HI:x[0-9]+]], [x0, #16]
30 ; CHECK: ldr [[P0LO:q[0-9]+]], [x0]
31 ; CHECK: str [[P0HI]], [sp, #16]
32 ; CHECK: str [[P0LO]], [sp]
33 ; CHECK: bl byval_large
34 call i8 @byval_large([3 x i64]* byval([3 x i64]) align 8 %p0, i8* byval %p1)
35 ret void
36 }
0 %struct = type {i32, i8}
1
2 declare void @baz(%struct* byval(%struct))
3
4 define void @foo(%struct* byval(%struct) %a) {
5 call void @baz(%struct* byval(%struct) %a)
6 ret void
7 }
0 ; RUN: llvm-link %s %p/Inputs/byval-types-1.ll -S | FileCheck %s
1
2 %struct = type {i32, i8}
3
4 declare void @foo(%struct* byval(%struct) %a)
5
6 define void @bar() {
7 %ptr = alloca %struct
8 ; CHECK: call void @foo(%struct* byval(%struct) %ptr)
9 call void @foo(%struct* byval(%struct) %ptr)
10 ret void
11 }
12
13 ; CHECK: define void @foo(%struct* byval(%struct) %a)
14 ; CHECK-NEXT: call void @baz(%struct* byval(%struct) %a)
15
16 ; CHECK: declare void @baz(%struct* byval(%struct))
5555 ; CHECK: %[[POS:.*]] = alloca i32
5656 ; CHECK: %[[VAL:.*]] = load i32, i32* %x
5757 ; CHECK: store i32 %[[VAL]], i32* %[[POS]]
58 ; CHECK: tail call void @ext2(i32* byval nonnull %[[POS]]
58 ; CHECK: tail call void @ext2(i32* nonnull byval %[[POS]]
5959 ; CHECK: ret void
6060 tail call void @bar2(i32* byval %x)
6161 ret void
6666 ; CHECK: %[[POS:.*]] = alloca i32
6767 ; CHECK: %[[VAL:.*]] = load i32, i32* %x
6868 ; CHECK: store i32 %[[VAL]], i32* %[[POS]]
69 ; CHECK: tail call void @ext2(i32* byval nonnull %[[POS]]
69 ; CHECK: tail call void @ext2(i32* nonnull byval %[[POS]]
7070 ; CHECK: ret void
7171 %x = alloca i32
7272 tail call void @bar2(i32* byval %x)
77
88 #include "llvm/IR/Attributes.h"
99 #include "llvm/IR/LLVMContext.h"
10 #include "llvm/IR/DerivedTypes.h"
1011 #include "gtest/gtest.h"
1112 using namespace llvm;
1213
3839 EXPECT_TRUE(Align4 < Deref4);
3940 EXPECT_TRUE(Align4 < Deref5);
4041 EXPECT_TRUE(Align5 < Deref4);
42
43 Attribute ByVal = Attribute::get(C, Attribute::ByVal, Type::getInt32Ty(C));
44 EXPECT_FALSE(ByVal < Attribute::get(C, Attribute::ZExt));
45 EXPECT_TRUE(ByVal < Align4);
4146
4247 AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt),
4348 AttributeList::get(C, 1, Attribute::SExt)};
165170 EXPECT_EQ(2U, AL.getNumAttrSets());
166171 }
167172
173 TEST(Attributes, StringRepresentation) {
174 LLVMContext C;
175 StructType *Ty = StructType::create(Type::getInt32Ty(C), "mystruct");
176
177 // Insufficiently careful printing can result in byval(%mystruct = { i32 })
178 Attribute A = Attribute::getWithByValType(C, Ty);
179 EXPECT_EQ(A.getAsString(), "byval(%mystruct)");
180
181 A = Attribute::getWithByValType(C, nullptr);
182 EXPECT_EQ(A.getAsString(), "byval");
183
184 A = Attribute::getWithByValType(C, Type::getInt32Ty(C));
185 EXPECT_EQ(A.getAsString(), "byval(i32)");
186 }
187
168188 } // end anonymous namespace