Skip to content

Commit c93f4fa

Browse files
committed
Track components per location
1 parent e6907e4 commit c93f4fa

File tree

7 files changed

+124
-54
lines changed

7 files changed

+124
-54
lines changed

llvm/docs/LangRef.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -1394,8 +1394,9 @@ Currently, only the following parameter attributes are defined:
13941394
- ``read_provenance`` (subset of ``provenance``): The ability to access the
13951395
pointer only for reads after the function returns.
13961396

1397-
Additionally, it is possible to specify that the pointer is captured via
1398-
the return value only, by using ``captures(ret: ...)``.
1397+
Additionally, it is possible to specify that some components are only
1398+
captured in certain locations. Currently only the return value (``ret``)
1399+
and other (default) locations are supported.
13991400

14001401
The `pointer capture section <pointercapture>` discusses these semantics
14011402
in more detail.
@@ -1410,6 +1411,9 @@ Currently, only the following parameter attributes are defined:
14101411
captured, but only for read-only access.
14111412
- ``captures(ret: address, provenance)``: Pointer captured through return
14121413
value only.
1414+
- ``captures(address_is_null, ret: address, provenance)``: The whole pointer
1415+
is captured through the return value, and additionally whether the pointer
1416+
is null is captured in some other way.
14131417

14141418
.. _nocapture:
14151419

llvm/include/llvm/Support/ModRef.h

+28-19
Original file line numberDiff line numberDiff line change
@@ -311,55 +311,64 @@ inline bool capturesFullProvenance(CaptureComponents CC) {
311311

312312
raw_ostream &operator<<(raw_ostream &OS, CaptureComponents CC);
313313

314-
/// Represents which components of the pointer may be captured and whether
315-
/// the capture is via the return value only. This represents the captures(...)
316-
/// attribute in IR.
314+
/// Represents which components of the pointer may be captured in which
315+
/// location. This represents the captures(...) attribute in IR.
317316
///
318317
/// For more information on the precise semantics see LangRef.
319318
class CaptureInfo {
320-
CaptureComponents Components;
321-
bool ReturnOnly;
319+
CaptureComponents OtherComponents;
320+
CaptureComponents RetComponents;
322321

323322
public:
324-
CaptureInfo(CaptureComponents Components, bool ReturnOnly = false)
325-
: Components(Components),
326-
ReturnOnly(capturesAnything(Components) && ReturnOnly) {}
323+
CaptureInfo(CaptureComponents OtherComponents,
324+
CaptureComponents RetComponents)
325+
: OtherComponents(OtherComponents), RetComponents(RetComponents) {}
326+
327+
CaptureInfo(CaptureComponents Components)
328+
: OtherComponents(Components), RetComponents(Components) {}
327329

328330
/// Create CaptureInfo that may capture all components of the pointer.
329331
static CaptureInfo all() { return CaptureInfo(CaptureComponents::All); }
330332

331-
/// Get the potentially captured components of the pointer.
332-
operator CaptureComponents() const { return Components; }
333+
/// Get components potentially captured by the return value.
334+
CaptureComponents getRetComponents() const { return RetComponents; }
335+
336+
/// Get components potentially captured through locations other than the
337+
/// return value.
338+
CaptureComponents getOtherComponents() const { return OtherComponents; }
333339

334-
/// Whether the pointer is captured through the return value only.
335-
bool isReturnOnly() const { return ReturnOnly; }
340+
/// Get the potentially captured components of the pointer (regardless of
341+
/// location).
342+
operator CaptureComponents() const { return OtherComponents | RetComponents; }
336343

337344
bool operator==(CaptureInfo Other) const {
338-
return Components == Other.Components && ReturnOnly == Other.ReturnOnly;
345+
return OtherComponents == Other.OtherComponents &&
346+
RetComponents == Other.RetComponents;
339347
}
340348

341349
bool operator!=(CaptureInfo Other) const { return !(*this == Other); }
342350

343351
/// Compute union of CaptureInfos.
344352
CaptureInfo operator|(CaptureInfo Other) const {
345-
return CaptureInfo(Components | Other.Components,
346-
ReturnOnly && Other.ReturnOnly);
353+
return CaptureInfo(OtherComponents | Other.OtherComponents,
354+
RetComponents | Other.RetComponents);
347355
}
348356

349357
/// Compute intersection of CaptureInfos.
350358
CaptureInfo operator&(CaptureInfo Other) const {
351-
return CaptureInfo(Components & Other.Components,
352-
ReturnOnly || Other.ReturnOnly);
359+
return CaptureInfo(OtherComponents & Other.OtherComponents,
360+
RetComponents & Other.RetComponents);
353361
}
354362

355363
static CaptureInfo createFromIntValue(uint32_t Data) {
356-
return CaptureInfo(CaptureComponents(Data >> 1), Data & 1);
364+
return CaptureInfo(CaptureComponents(Data >> 4),
365+
CaptureComponents(Data & 0xf));
357366
}
358367

359368
/// Convert CaptureInfo into an encoded integer value (used by captures
360369
/// attribute).
361370
uint32_t toIntValue() const {
362-
return (uint32_t(Components) << 1) | ReturnOnly;
371+
return (uint32_t(OtherComponents) << 4) | uint32_t(RetComponents);
363372
}
364373
};
365374

llvm/lib/AsmParser/LLParser.cpp

+33-23
Original file line numberDiff line numberDiff line change
@@ -3168,8 +3168,8 @@ bool LLParser::parseInitializesAttr(AttrBuilder &B) {
31683168
}
31693169

31703170
bool LLParser::parseCapturesAttr(AttrBuilder &B) {
3171-
CaptureComponents CC = CaptureComponents::None;
3172-
bool ReturnOnly = false;
3171+
CaptureComponents Other = CaptureComponents::None;
3172+
std::optional<CaptureComponents> Ret;
31733173

31743174
// We use syntax like captures(ret: address, provenance), so the colon
31753175
// should not be interpreted as a label terminator.
@@ -3180,39 +3180,49 @@ bool LLParser::parseCapturesAttr(AttrBuilder &B) {
31803180
if (parseToken(lltok::lparen, "expected '('"))
31813181
return true;
31823182

3183-
if (EatIfPresent(lltok::kw_ret)) {
3184-
if (parseToken(lltok::colon, "expected ':'"))
3185-
return true;
3183+
CaptureComponents *Current = &Other;
3184+
bool SeenComponent = false;
3185+
while (true) {
3186+
if (EatIfPresent(lltok::kw_ret)) {
3187+
if (parseToken(lltok::colon, "expected ':'"))
3188+
return true;
3189+
if (Ret)
3190+
return tokError("duplicate 'ret' location");
3191+
Ret = CaptureComponents::None;
3192+
Current = &*Ret;
3193+
SeenComponent = false;
3194+
}
31863195

3187-
ReturnOnly = true;
3188-
}
3196+
if (EatIfPresent(lltok::kw_none)) {
3197+
if (SeenComponent)
3198+
return tokError("cannot use 'none' with other component");
3199+
*Current = CaptureComponents::None;
3200+
} else {
3201+
if (SeenComponent && capturesNothing(*Current))
3202+
return tokError("cannot use 'none' with other component");
31893203

3190-
if (EatIfPresent(lltok::kw_none)) {
3191-
if (parseToken(lltok::rparen, "expected ')'"))
3192-
return true;
3193-
} else {
3194-
while (true) {
31953204
if (EatIfPresent(lltok::kw_address_is_null))
3196-
CC |= CaptureComponents::AddressIsNull;
3205+
*Current |= CaptureComponents::AddressIsNull;
31973206
else if (EatIfPresent(lltok::kw_address))
3198-
CC |= CaptureComponents::Address;
3207+
*Current |= CaptureComponents::Address;
31993208
else if (EatIfPresent(lltok::kw_provenance))
3200-
CC |= CaptureComponents::Provenance;
3209+
*Current |= CaptureComponents::Provenance;
32013210
else if (EatIfPresent(lltok::kw_read_provenance))
3202-
CC |= CaptureComponents::ReadProvenance;
3211+
*Current |= CaptureComponents::ReadProvenance;
32033212
else
3204-
return tokError("expected one of 'address', 'address_is_null', "
3213+
return tokError("expected one of 'none', 'address', 'address_is_null', "
32053214
"'provenance' or 'read_provenance'");
3215+
}
32063216

3207-
if (EatIfPresent(lltok::rparen))
3208-
break;
3217+
SeenComponent = true;
3218+
if (EatIfPresent(lltok::rparen))
3219+
break;
32093220

3210-
if (parseToken(lltok::comma, "expected ',' or ')'"))
3211-
return true;
3212-
}
3221+
if (parseToken(lltok::comma, "expected ',' or ')'"))
3222+
return true;
32133223
}
32143224

3215-
B.addCapturesAttr(CaptureInfo(CC, ReturnOnly));
3225+
B.addCapturesAttr(CaptureInfo(Other, Ret.value_or(Other)));
32163226
return false;
32173227
}
32183228

llvm/lib/Support/ModRef.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,15 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, CaptureComponents CC) {
7272
}
7373

7474
raw_ostream &llvm::operator<<(raw_ostream &OS, CaptureInfo CI) {
75+
ListSeparator LS;
76+
CaptureComponents Other = CI.getOtherComponents();
77+
CaptureComponents Ret = CI.getRetComponents();
78+
7579
OS << "captures(";
76-
if (CI.isReturnOnly())
77-
OS << "ret: ";
78-
OS << CaptureComponents(CI) << ")";
80+
if (!capturesNothing(Other) || Other == Ret)
81+
OS << LS << Other;
82+
if (Other != Ret)
83+
OS << LS << "ret: " << Ret;
84+
OS << ")";
7985
return OS;
8086
}

llvm/test/Assembler/captures-errors.ll

+26-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
; RUN: not llvm-as < %t/missing-rparen-none.ll 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-RPAREN-NONE
55
; RUN: not llvm-as < %t/missing-colon.ll 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-COLON
66
; RUN: not llvm-as < %t/invalid-component.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-COMPONENT
7+
; RUN: not llvm-as < %t/duplicate-ret.ll 2>&1 | FileCheck %s --check-prefix=CHECK-DUPLICATE-RET
8+
; RUN: not llvm-as < %t/none-after.ll 2>&1 | FileCheck %s --check-prefix=CHECK-NONE-AFTER
9+
; RUN: not llvm-as < %t/none-before.ll 2>&1 | FileCheck %s --check-prefix=CHECK-NONE-BEFORE
710

811
;--- missing-lparen.ll
912

@@ -21,7 +24,7 @@ define void @test(ptr captures(address %p) {
2124

2225
;--- missing-rparen-none.ll
2326

24-
; CHECK-MISSING-RPAREN-NONE: <stdin>:[[@LINE+1]]:37: error: expected ')'
27+
; CHECK-MISSING-RPAREN-NONE: <stdin>:[[@LINE+1]]:37: error: expected ',' or ')'
2528
define void @test(ptr captures(none %p) {
2629
ret void
2730
}
@@ -35,7 +38,28 @@ define void @test(ptr captures(ret address) %p) {
3538

3639
;--- invalid-component.ll
3740

38-
; CHECK-INVALID-COMPONENT: <stdin>:[[@LINE+1]]:32: error: expected one of 'address', 'address_is_null', 'provenance' or 'read_provenance'
41+
; CHECK-INVALID-COMPONENT: <stdin>:[[@LINE+1]]:32: error: expected one of 'none', 'address', 'address_is_null', 'provenance' or 'read_provenance'
3942
define void @test(ptr captures(foo) %p) {
4043
ret void
4144
}
45+
46+
;--- duplicate-ret.ll
47+
48+
; CHECK-DUPLICATE-RET: <stdin>:[[@LINE+1]]:51: error: duplicate 'ret' location
49+
define void @test(ptr captures(ret: address, ret: provenance) %p) {
50+
ret void
51+
}
52+
53+
;--- none-after.ll
54+
55+
; CHECK-NONE-AFTER: <stdin>:[[@LINE+1]]:45: error: cannot use 'none' with other component
56+
define void @test(ptr captures(address, none) %p) {
57+
ret void
58+
}
59+
60+
;--- none-before.ll
61+
62+
; CHECK-NONE-BEFORE: <stdin>:[[@LINE+1]]:38: error: cannot use 'none' with other component
63+
define void @test(ptr captures(none, address) %p) {
64+
ret void
65+
}

llvm/test/Assembler/captures.ll

+16
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ define void @test_ret(ptr captures(ret: address, provenance) %p) {
5050
ret void
5151
}
5252

53+
define void @test_address_is_null_and_ret(ptr captures(address_is_null, ret: address, provenance) %p) {
54+
; CHECK-LABEL: define void @test_address_is_null_and_ret(
55+
; CHECK-SAME: ptr captures(address_is_null, ret: address, provenance) [[P:%.*]]) {
56+
; CHECK-NEXT: ret void
57+
;
58+
ret void
59+
}
60+
61+
define void @test_address_and_ret_none(ptr captures(address, ret: none) %p) {
62+
; CHECK-LABEL: define void @test_address_and_ret_none(
63+
; CHECK-SAME: ptr captures(address, ret: none) [[P:%.*]]) {
64+
; CHECK-NEXT: ret void
65+
;
66+
ret void
67+
}
68+
5369
; Duplicates callpse into one.
5470
define void @test_duplicate(ptr captures(address, address) %p) {
5571
; CHECK-LABEL: define void @test_duplicate(

llvm/unittests/IR/AttributesTest.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,11 @@ TEST(Attributes, SetIntersect) {
438438
case Attribute::Range:
439439
break;
440440
case Attribute::Captures:
441-
V0 = CaptureInfo(CaptureComponents::Address, /*ReturnOnly=*/false)
441+
V0 = CaptureInfo(CaptureComponents::AddressIsNull,
442+
CaptureComponents::None)
442443
.toIntValue();
443-
V1 = CaptureInfo(CaptureComponents::ReadProvenance, /*ReturnOnly=*/true)
444+
V1 = CaptureInfo(CaptureComponents::None,
445+
CaptureComponents::ReadProvenance)
444446
.toIntValue();
445447
break;
446448
default:
@@ -524,9 +526,8 @@ TEST(Attributes, SetIntersect) {
524526
break;
525527
case Attribute::Captures:
526528
ASSERT_EQ(Res->getCaptureInfo(),
527-
CaptureInfo(CaptureComponents::Address |
528-
CaptureComponents::ReadProvenance,
529-
/*ReturnOnly=*/false));
529+
CaptureInfo(CaptureComponents::AddressIsNull,
530+
CaptureComponents::ReadProvenance));
530531
break;
531532
default:
532533
ASSERT_FALSE(true);

0 commit comments

Comments
 (0)