Skip to content

Commit b714120

Browse files
committed
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. llvm-svn: 362128
1 parent 7fecdf3 commit b714120

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+497
-42
lines changed

llvm/docs/LangRef.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ Currently, only the following parameter attributes are defined:
10171017
opposed to memory, though some targets use it to distinguish between
10181018
two different kinds of registers). Use of this attribute is
10191019
target-specific.
1020-
``byval``
1020+
``byval`` or ``byval(<ty>)``
10211021
This indicates that the pointer parameter should really be passed by
10221022
value to the function. The attribute implies that a hidden copy of
10231023
the pointee is made between the caller and the callee, so the callee
@@ -1029,6 +1029,9 @@ Currently, only the following parameter attributes are defined:
10291029
``byval`` parameters). This is not a valid attribute for return
10301030
values.
10311031

1032+
The byval attribute also supports an optional type argument, which must be
1033+
the same as the pointee type of the argument.
1034+
10321035
The byval attribute also supports specifying an alignment with the
10331036
align attribute. It indicates the alignment of the stack slot to
10341037
form and the known alignment of the pointer specified to the call

llvm/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ Changes to the LLVM IR
6767
type is now mandatory. Specify `i8* null` to migrate from the obsoleted
6868
2-field form.
6969

70+
* The ``byval`` attribute can now take a type parameter:
71+
``byval(<ty>)``. If present it must be identical to the argument's
72+
pointee type. In the next release we intend to make this parameter
73+
mandatory in preparation for opaque pointer types.
74+
7075
Changes to the ARM Backend
7176
--------------------------
7277

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class TargetLoweringBase {
188188
bool IsSwiftSelf : 1;
189189
bool IsSwiftError : 1;
190190
uint16_t Alignment = 0;
191+
Type *ByValType = nullptr;
191192

192193
ArgListEntry()
193194
: IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false),

llvm/include/llvm/IR/Argument.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class Argument final : public Value {
7878
/// If this is a byval or inalloca argument, return its alignment.
7979
unsigned getParamAlignment() const;
8080

81+
/// If this is a byval argument, return its type.
82+
Type *getParamByValType() const;
83+
8184
/// Return true if this argument has the nest attribute.
8285
bool hasNestAttr() const;
8386

llvm/include/llvm/IR/Attributes.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class Attribute {
9090
static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val = 0);
9191
static Attribute get(LLVMContext &Context, StringRef Kind,
9292
StringRef Val = StringRef());
93+
static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
9394

9495
/// Return a uniquified Attribute object that has the specific
9596
/// alignment set.
@@ -102,6 +103,7 @@ class Attribute {
102103
static Attribute getWithAllocSizeArgs(LLVMContext &Context,
103104
unsigned ElemSizeArg,
104105
const Optional<unsigned> &NumElemsArg);
106+
static Attribute getWithByValType(LLVMContext &Context, Type *Ty);
105107

106108
//===--------------------------------------------------------------------===//
107109
// Attribute Accessors
@@ -117,6 +119,9 @@ class Attribute {
117119
/// attribute.
118120
bool isStringAttribute() const;
119121

122+
/// Return true if the attribute is a type attribute.
123+
bool isTypeAttribute() const;
124+
120125
/// Return true if the attribute is present.
121126
bool hasAttribute(AttrKind Val) const;
122127

@@ -139,6 +144,10 @@ class Attribute {
139144
/// attribute to be a string attribute.
140145
StringRef getValueAsString() const;
141146

147+
/// Return the attribute's value as a Type. This requires the attribute to be
148+
/// a type attribute.
149+
Type *getValueAsType() const;
150+
142151
/// Returns the alignment field of an attribute as a byte alignment
143152
/// value.
144153
unsigned getAlignment() const;
@@ -279,6 +288,7 @@ class AttributeSet {
279288
unsigned getStackAlignment() const;
280289
uint64_t getDereferenceableBytes() const;
281290
uint64_t getDereferenceableOrNullBytes() const;
291+
Type *getByValType() const;
282292
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
283293
std::string getAsString(bool InAttrGrp = false) const;
284294

@@ -598,6 +608,9 @@ class AttributeList {
598608
/// Return the alignment for the specified function parameter.
599609
unsigned getParamAlignment(unsigned ArgNo) const;
600610

611+
/// Return the byval type for the specified function parameter.
612+
Type *getParamByValType(unsigned ArgNo) const;
613+
601614
/// Get the stack alignment.
602615
unsigned getStackAlignment(unsigned Index) const;
603616

@@ -697,6 +710,7 @@ class AttrBuilder {
697710
uint64_t DerefBytes = 0;
698711
uint64_t DerefOrNullBytes = 0;
699712
uint64_t AllocSizeArgs = 0;
713+
Type *ByValType = nullptr;
700714

701715
public:
702716
AttrBuilder() = default;
@@ -772,6 +786,9 @@ class AttrBuilder {
772786
/// dereferenceable_or_null attribute exists (zero is returned otherwise).
773787
uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; }
774788

789+
/// Retrieve the byval type.
790+
Type *getByValType() const { return ByValType; }
791+
775792
/// Retrieve the allocsize args, if the allocsize attribute exists. If it
776793
/// doesn't exist, pair(0, 0) is returned.
777794
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
@@ -796,6 +813,9 @@ class AttrBuilder {
796813
AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg,
797814
const Optional<unsigned> &NumElemsArg);
798815

816+
/// This turns a byval type into the form used internally in Attribute.
817+
AttrBuilder &addByValAttr(Type *Ty);
818+
799819
/// Add an allocsize attribute, using the representation returned by
800820
/// Attribute.getIntValue().
801821
AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr);

llvm/include/llvm/IR/CallSite.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,11 @@ class CallSiteBase {
415415
CALLSITE_DELEGATE_GETTER(getParamAlignment(ArgNo));
416416
}
417417

418+
/// Extract the byval type for a call or parameter (nullptr=unknown).
419+
Type *getParamByValType(unsigned ArgNo) const {
420+
CALLSITE_DELEGATE_GETTER(getParamByValType(ArgNo));
421+
}
422+
418423
/// Extract the number of dereferenceable bytes for a call or parameter
419424
/// (0=unknown).
420425
uint64_t getDereferenceableBytes(unsigned i) const {

llvm/include/llvm/IR/Function.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,11 @@ class Function : public GlobalObject, public ilist_node<Function> {
431431
return AttributeSets.getParamAlignment(ArgNo);
432432
}
433433

434+
/// Extract the byval type for a parameter (nullptr=unknown).
435+
Type *getParamByValType(unsigned ArgNo) const {
436+
return AttributeSets.getParamByValType(ArgNo);
437+
}
438+
434439
/// Extract the number of dereferenceable bytes for a call or
435440
/// parameter (0=unknown).
436441
/// @param i AttributeList index, referring to a return value or argument.

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,6 +1560,11 @@ class CallBase : public Instruction {
15601560
return Attrs.getParamAlignment(ArgNo);
15611561
}
15621562

1563+
/// Extract the byval type for a call or parameter (nullptr=unknown).
1564+
Type *getParamByValType(unsigned ArgNo) const {
1565+
return Attrs.getParamByValType(ArgNo);
1566+
}
1567+
15631568
/// Extract the number of dereferenceable bytes for a call or
15641569
/// parameter (0=unknown).
15651570
uint64_t getDereferenceableBytes(unsigned i) const {

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1601,7 +1601,13 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
16011601
B.addAlignmentAttr(Alignment);
16021602
continue;
16031603
}
1604-
case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
1604+
case lltok::kw_byval: {
1605+
Type *Ty;
1606+
if (ParseByValWithOptionalType(Ty))
1607+
return true;
1608+
B.addByValAttr(Ty);
1609+
continue;
1610+
}
16051611
case lltok::kw_dereferenceable: {
16061612
uint64_t Bytes;
16071613
if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
@@ -2454,6 +2460,22 @@ bool LLParser::ParseParameterList(SmallVectorImpl<ParamInfo> &ArgList,
24542460
return false;
24552461
}
24562462

2463+
/// ParseByValWithOptionalType
2464+
/// ::= byval
2465+
/// ::= byval(<ty>)
2466+
bool LLParser::ParseByValWithOptionalType(Type *&Result) {
2467+
Result = nullptr;
2468+
if (!EatIfPresent(lltok::kw_byval))
2469+
return true;
2470+
if (!EatIfPresent(lltok::lparen))
2471+
return false;
2472+
if (ParseType(Result))
2473+
return true;
2474+
if (!EatIfPresent(lltok::rparen))
2475+
return Error(Lex.getLoc(), "expected ')'");
2476+
return false;
2477+
}
2478+
24572479
/// ParseOptionalOperandBundles
24582480
/// ::= /*empty*/
24592481
/// ::= '[' OperandBundle [, OperandBundle ]* ']'

llvm/lib/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ namespace llvm {
339339
bool ParseFnAttributeValuePairs(AttrBuilder &B,
340340
std::vector<unsigned> &FwdRefAttrGrps,
341341
bool inAttrGrp, LocTy &BuiltinLoc);
342+
bool ParseByValWithOptionalType(Type *&Result);
342343

343344
// Module Summary Index Parsing.
344345
bool SkipModuleSummaryEntry();

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,10 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
638638
return getFnValueByID(ValNo, Ty);
639639
}
640640

641+
/// Upgrades old-style typeless byval attributes by adding the corresponding
642+
/// argument's pointee type.
643+
void propagateByValTypes(CallBase *CB);
644+
641645
/// Converts alignment exponent (i.e. power of two (or zero)) to the
642646
/// corresponding alignment to use. If alignment is too large, returns
643647
/// a corresponding error code.
@@ -1492,6 +1496,12 @@ Error BitcodeReader::parseAttributeGroupBlock() {
14921496
if (Error Err = parseAttrKind(Record[++i], &Kind))
14931497
return Err;
14941498

1499+
// Upgrade old-style byval attribute to one with a type, even if it's
1500+
// nullptr. We will have to insert the real type when we associate
1501+
// this AttributeList with a function.
1502+
if (Kind == Attribute::ByVal)
1503+
B.addByValAttr(nullptr);
1504+
14951505
B.addAttribute(Kind);
14961506
} else if (Record[i] == 1) { // Integer attribute
14971507
Attribute::AttrKind Kind;
@@ -1507,9 +1517,7 @@ Error BitcodeReader::parseAttributeGroupBlock() {
15071517
B.addDereferenceableOrNullAttr(Record[++i]);
15081518
else if (Kind == Attribute::AllocSize)
15091519
B.addAllocSizeAttrFromRawRepr(Record[++i]);
1510-
} else { // String attribute
1511-
assert((Record[i] == 3 || Record[i] == 4) &&
1512-
"Invalid attribute group entry");
1520+
} else if (Record[i] == 3 || Record[i] == 4) { // String attribute
15131521
bool HasValue = (Record[i++] == 4);
15141522
SmallString<64> KindStr;
15151523
SmallString<64> ValStr;
@@ -1527,6 +1535,15 @@ Error BitcodeReader::parseAttributeGroupBlock() {
15271535
}
15281536

15291537
B.addAttribute(KindStr.str(), ValStr.str());
1538+
} else {
1539+
assert((Record[i] == 5 || Record[i] == 6) &&
1540+
"Invalid attribute group entry");
1541+
bool HasType = Record[i] == 6;
1542+
Attribute::AttrKind Kind;
1543+
if (Error Err = parseAttrKind(Record[++i], &Kind))
1544+
return Err;
1545+
if (Kind == Attribute::ByVal)
1546+
B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
15301547
}
15311548
}
15321549

@@ -3028,6 +3045,17 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
30283045
Func->setLinkage(getDecodedLinkage(RawLinkage));
30293046
Func->setAttributes(getAttributes(Record[4]));
30303047

3048+
// Upgrade any old-style byval without a type by propagating the argument's
3049+
// pointee type. There should be no opaque pointers where the byval type is
3050+
// implicit.
3051+
for (auto &Arg : Func->args()) {
3052+
if (Arg.hasByValAttr() && !Arg.getParamByValType()) {
3053+
Arg.removeAttr(Attribute::ByVal);
3054+
Arg.addAttr(Attribute::getWithByValType(
3055+
Context, Arg.getType()->getPointerElementType()));
3056+
}
3057+
}
3058+
30313059
unsigned Alignment;
30323060
if (Error Err = parseAlignmentValue(Record[5], Alignment))
30333061
return Err;
@@ -3441,6 +3469,19 @@ Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) {
34413469
return Error::success();
34423470
}
34433471

3472+
void BitcodeReader::propagateByValTypes(CallBase *CB) {
3473+
for (unsigned i = 0; i < CB->getNumArgOperands(); ++i) {
3474+
if (CB->paramHasAttr(i, Attribute::ByVal) &&
3475+
!CB->getAttribute(i, Attribute::ByVal).getValueAsType()) {
3476+
CB->removeParamAttr(i, Attribute::ByVal);
3477+
CB->addParamAttr(
3478+
i, Attribute::getWithByValType(
3479+
Context,
3480+
CB->getArgOperand(i)->getType()->getPointerElementType()));
3481+
}
3482+
}
3483+
}
3484+
34443485
/// Lazily parse the specified function body block.
34453486
Error BitcodeReader::parseFunctionBody(Function *F) {
34463487
if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID))
@@ -4256,6 +4297,8 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
42564297
cast<InvokeInst>(I)->setCallingConv(
42574298
static_cast<CallingConv::ID>(CallingConv::MaxID & CCInfo));
42584299
cast<InvokeInst>(I)->setAttributes(PAL);
4300+
propagateByValTypes(cast<CallBase>(I));
4301+
42594302
break;
42604303
}
42614304
case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval]
@@ -4731,6 +4774,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
47314774
TCK = CallInst::TCK_NoTail;
47324775
cast<CallInst>(I)->setTailCallKind(TCK);
47334776
cast<CallInst>(I)->setAttributes(PAL);
4777+
propagateByValTypes(cast<CallBase>(I));
47344778
if (FMF.any()) {
47354779
if (!isa<FPMathOperator>(I))
47364780
return error("Fast-math-flags specified for call without "

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
747747
Record.push_back(1);
748748
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
749749
Record.push_back(Attr.getValueAsInt());
750-
} else {
750+
} else if (Attr.isStringAttribute()) {
751751
StringRef Kind = Attr.getKindAsString();
752752
StringRef Val = Attr.getValueAsString();
753753

@@ -758,6 +758,13 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
758758
Record.append(Val.begin(), Val.end());
759759
Record.push_back(0);
760760
}
761+
} else {
762+
assert(Attr.isTypeAttribute());
763+
Type *Ty = Attr.getValueAsType();
764+
Record.push_back(Ty ? 6 : 5);
765+
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
766+
if (Ty)
767+
Record.push_back(VE.getTypeID(Attr.getValueAsType()));
761768
}
762769
}
763770

@@ -4126,15 +4133,15 @@ void ModuleBitcodeWriter::write() {
41264133
// Emit blockinfo, which defines the standard abbreviations etc.
41274134
writeBlockInfo();
41284135

4136+
// Emit information describing all of the types in the module.
4137+
writeTypeTable();
4138+
41294139
// Emit information about attribute groups.
41304140
writeAttributeGroupTable();
41314141

41324142
// Emit information about parameter attributes.
41334143
writeAttributeTable();
41344144

4135-
// Emit information describing all of the types in the module.
4136-
writeTypeTable();
4137-
41384145
writeComdats();
41394146

41404147
// Emit top-level description of module, including target triple, inline asm,

llvm/lib/Bitcode/Writer/ValueEnumerator.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -949,9 +949,11 @@ void ValueEnumerator::incorporateFunction(const Function &F) {
949949
incorporateFunctionMetadata(F);
950950

951951
// Adding function arguments to the value table.
952-
for (const auto &I : F.args())
952+
for (const auto &I : F.args()) {
953953
EnumerateValue(&I);
954-
954+
if (I.hasAttribute(Attribute::ByVal) && I.getParamByValType())
955+
EnumerateType(I.getParamByValType());
956+
}
955957
FirstFuncConstantID = Values.size();
956958

957959
// Add all function-level constants to the value table.

llvm/lib/CodeGen/GlobalISel/CallLowering.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,10 @@ void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx,
8787

8888
if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) {
8989
Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType();
90-
Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
90+
91+
auto Ty = Attrs.getAttribute(OpIdx, Attribute::ByVal).getValueAsType();
92+
Arg.Flags.setByValSize(DL.getTypeAllocSize(Ty ? Ty : ElementTy));
93+
9194
// For ByVal, alignment should be passed from FE. BE will guess if
9295
// this info is not there but there are cases it cannot get right.
9396
unsigned FrameAlign;

0 commit comments

Comments
 (0)