Skip to content

Commit 93d21e2

Browse files
[IR][ModRef] Introduce errno memory location
Model C/C++ `errno` macro by adding a corresponding `errno` memory location kind to the IR. Preliminary work to separate `errno` writes from other memory accesses, to the benefit of alias analyses and optimization correctness. Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972.
1 parent 3019e49 commit 93d21e2

File tree

17 files changed

+256
-18
lines changed

17 files changed

+256
-18
lines changed

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ enum Kind {
201201
kw_readwrite,
202202
kw_argmem,
203203
kw_inaccessiblemem,
204+
kw_errnomem,
204205

205206
// Legacy attributes:
206207
kw_argmemonly,

llvm/include/llvm/IR/Function.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,31 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
581581
bool onlyAccessesInaccessibleMemory() const;
582582
void setOnlyAccessesInaccessibleMemory();
583583

584+
/// Determine if the function may only access errno memory.
585+
bool onlyAccessesErrnoMemory() const;
586+
void setOnlyAccessesErrnoMemory();
587+
584588
/// Determine if the function may only access memory that is
585589
/// either inaccessible from the IR or pointed to by its arguments.
586590
bool onlyAccessesInaccessibleMemOrArgMem() const;
587591
void setOnlyAccessesInaccessibleMemOrArgMem();
588592

593+
/// Determine if the function may only access memory that is
594+
/// either pointed to by its arguments or errno memory.
595+
bool onlyAccessesArgMemOrErrnoMem() const;
596+
void setOnlyAccessesArgMemOrErrnoMem();
597+
598+
/// Determine if the function may only access memory that is
599+
/// either inaccessible from the IR or errno memory.
600+
bool onlyAccessesInaccessibleMemOrErrnoMem() const;
601+
void setOnlyAccessesInaccessibleMemOrErrnoMem();
602+
603+
/// Determine if the function may only access memory that is
604+
/// either inaccessible from the IR, pointed to by its arguments, or errno
605+
/// memory.
606+
bool onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const;
607+
void setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem();
608+
589609
/// Determine if the function cannot return.
590610
bool doesNotReturn() const {
591611
return hasFnAttribute(Attribute::NoReturn);

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,11 +1915,31 @@ class CallBase : public Instruction {
19151915
bool onlyAccessesInaccessibleMemory() const;
19161916
void setOnlyAccessesInaccessibleMemory();
19171917

1918+
/// Determine if the function may only access errno memory.
1919+
bool onlyAccessesErrnoMemory() const;
1920+
void setOnlyAccessesErrnoMemory();
1921+
19181922
/// Determine if the function may only access memory that is
19191923
/// either inaccessible from the IR or pointed to by its arguments.
19201924
bool onlyAccessesInaccessibleMemOrArgMem() const;
19211925
void setOnlyAccessesInaccessibleMemOrArgMem();
19221926

1927+
/// Determine if the function may only access memory that is
1928+
/// either inaccessible from the IR or errno memory.
1929+
bool onlyAccessesInaccessibleMemOrErrnoMem() const;
1930+
void setOnlyAccessesInaccessibleMemOrErrnoMem();
1931+
1932+
/// Determine if the function may only access memory that is
1933+
/// either pointed to by its arguments or errno memory.
1934+
bool onlyAccessesArgMemOrErrnoMem() const;
1935+
void setOnlyAccessesArgMemOrErrnoMem();
1936+
1937+
/// Determine if the function may only access memory that is
1938+
/// either inaccessible from the IR, pointed to by its arguments, or errno
1939+
/// memory.
1940+
bool onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const;
1941+
void setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem();
1942+
19231943
/// Determine if the call cannot return.
19241944
bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); }
19251945
void setDoesNotReturn() { addFnAttr(Attribute::NoReturn); }

llvm/include/llvm/Support/ModRef.h

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ enum class IRMemLocation {
6161
ArgMem = 0,
6262
/// Memory that is inaccessible via LLVM IR.
6363
InaccessibleMem = 1,
64+
/// Errno memory.
65+
ErrnoMem = 2,
6466
/// Any other memory.
65-
Other = 2,
67+
Other = 3,
6668

6769
/// Helpers to iterate all locations in the MemoryEffectsBase class.
6870
First = ArgMem,
@@ -139,6 +141,11 @@ template <typename LocationEnum> class MemoryEffectsBase {
139141
return MemoryEffectsBase(Location::InaccessibleMem, MR);
140142
}
141143

144+
/// Create MemoryEffectsBase that can only access errno memory.
145+
static MemoryEffectsBase errnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
146+
return MemoryEffectsBase(Location::ErrnoMem, MR);
147+
}
148+
142149
/// Create MemoryEffectsBase that can only access inaccessible or argument
143150
/// memory.
144151
static MemoryEffectsBase
@@ -149,6 +156,36 @@ template <typename LocationEnum> class MemoryEffectsBase {
149156
return FRMB;
150157
}
151158

159+
/// Create MemoryEffectsBase that can only access inaccessible or errno
160+
/// memory.
161+
static MemoryEffectsBase
162+
inaccessibleOrErrnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
163+
MemoryEffectsBase FRMB = none();
164+
FRMB.setModRef(Location::ErrnoMem, MR);
165+
FRMB.setModRef(Location::InaccessibleMem, MR);
166+
return FRMB;
167+
}
168+
169+
/// Create MemoryEffectsBase that can only access argument or errno memory.
170+
static MemoryEffectsBase
171+
argumentOrErrnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
172+
MemoryEffectsBase FRMB = none();
173+
FRMB.setModRef(Location::ArgMem, MR);
174+
FRMB.setModRef(Location::ErrnoMem, MR);
175+
return FRMB;
176+
}
177+
178+
/// Create MemoryEffectsBase that can only access inaccessible, argument or
179+
/// errno memory.
180+
static MemoryEffectsBase
181+
inaccessibleOrArgOrErrnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
182+
MemoryEffectsBase FRMB = none();
183+
FRMB.setModRef(Location::ArgMem, MR);
184+
FRMB.setModRef(Location::ErrnoMem, MR);
185+
FRMB.setModRef(Location::InaccessibleMem, MR);
186+
return FRMB;
187+
}
188+
152189
/// Create MemoryEffectsBase from an encoded integer value (used by memory
153190
/// attribute).
154191
static MemoryEffectsBase createFromIntValue(uint32_t Data) {
@@ -212,6 +249,11 @@ template <typename LocationEnum> class MemoryEffectsBase {
212249
return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
213250
}
214251

252+
/// Whether this function only (at most) accesses errno memory.
253+
bool onlyAccessesErrnoMem() const {
254+
return getWithoutLoc(Location::ErrnoMem).doesNotAccessMemory();
255+
}
256+
215257
/// Whether this function only (at most) accesses argument and inaccessible
216258
/// memory.
217259
bool onlyAccessesInaccessibleOrArgMem() const {
@@ -220,6 +262,30 @@ template <typename LocationEnum> class MemoryEffectsBase {
220262
.doesNotAccessMemory();
221263
}
222264

265+
/// Whether this function only (at most) accesses inaccessible and errno
266+
/// memory.
267+
bool onlyAccessesInaccessibleOrErrnoMem() const {
268+
return getWithoutLoc(Location::InaccessibleMem)
269+
.getWithoutLoc(Location::ErrnoMem)
270+
.doesNotAccessMemory();
271+
}
272+
273+
/// Whether this function only (at most) accesses argument and errno memory.
274+
bool onlyAccessesArgumentOrErrnoMem() const {
275+
return getWithoutLoc(Location::ArgMem)
276+
.getWithoutLoc(Location::ErrnoMem)
277+
.doesNotAccessMemory();
278+
}
279+
280+
/// Whether this function only (at most) accesses inaccessible, argument and
281+
/// errno memory.
282+
bool onlyAccessesInaccessibleOrArgOrErrnoMem() const {
283+
return getWithoutLoc(Location::InaccessibleMem)
284+
.getWithoutLoc(Location::ArgMem)
285+
.getWithoutLoc(Location::ErrnoMem)
286+
.doesNotAccessMemory();
287+
}
288+
223289
/// Intersect with other MemoryEffectsBase.
224290
MemoryEffectsBase operator&(MemoryEffectsBase Other) const {
225291
return MemoryEffectsBase(Data & Other.Data);

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ lltok::Kind LLLexer::LexIdentifier() {
701701
KEYWORD(readwrite);
702702
KEYWORD(argmem);
703703
KEYWORD(inaccessiblemem);
704+
KEYWORD(errnomem);
704705
KEYWORD(argmemonly);
705706
KEYWORD(inaccessiblememonly);
706707
KEYWORD(inaccessiblemem_or_argmemonly);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2497,6 +2497,8 @@ static std::optional<MemoryEffects::Location> keywordToLoc(lltok::Kind Tok) {
24972497
return IRMemLocation::ArgMem;
24982498
case lltok::kw_inaccessiblemem:
24992499
return IRMemLocation::InaccessibleMem;
2500+
case lltok::kw_errnomem:
2501+
return IRMemLocation::ErrnoMem;
25002502
default:
25012503
return std::nullopt;
25022504
}
@@ -2545,7 +2547,7 @@ std::optional<MemoryEffects> LLParser::parseMemoryAttr() {
25452547
std::optional<ModRefInfo> MR = keywordToModRef(Lex.getKind());
25462548
if (!MR) {
25472549
if (!Loc)
2548-
tokError("expected memory location (argmem, inaccessiblemem) "
2550+
tokError("expected memory location (argmem, inaccessiblemem, errnomem) "
25492551
"or access kind (none, read, write, readwrite)");
25502552
else
25512553
tokError("expected access kind (none, read, write, readwrite)");

llvm/lib/IR/Attributes.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
647647
case IRMemLocation::InaccessibleMem:
648648
OS << "inaccessiblemem: ";
649649
break;
650+
case IRMemLocation::ErrnoMem:
651+
OS << "errnomem: ";
652+
break;
650653
case IRMemLocation::Other:
651654
llvm_unreachable("This is represented as the default access kind");
652655
}

llvm/lib/IR/Function.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,14 @@ void Function::setOnlyAccessesInaccessibleMemory() {
922922
setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly());
923923
}
924924

925+
/// Determine if the function may only access errno memory.
926+
bool Function::onlyAccessesErrnoMemory() const {
927+
return getMemoryEffects().onlyAccessesErrnoMem();
928+
}
929+
void Function::setOnlyAccessesErrnoMemory() {
930+
setMemoryEffects(getMemoryEffects() & MemoryEffects::errnoMemOnly());
931+
}
932+
925933
/// Determine if the function may only access memory that is
926934
/// either inaccessible from the IR or pointed to by its arguments.
927935
bool Function::onlyAccessesInaccessibleMemOrArgMem() const {
@@ -932,6 +940,37 @@ void Function::setOnlyAccessesInaccessibleMemOrArgMem() {
932940
MemoryEffects::inaccessibleOrArgMemOnly());
933941
}
934942

943+
/// Determine if the function may only access memory that is
944+
/// either inaccessible from the IR or errno memory.
945+
bool Function::onlyAccessesInaccessibleMemOrErrnoMem() const {
946+
return getMemoryEffects().onlyAccessesInaccessibleOrErrnoMem();
947+
}
948+
void Function::setOnlyAccessesInaccessibleMemOrErrnoMem() {
949+
setMemoryEffects(getMemoryEffects() &
950+
MemoryEffects::inaccessibleOrErrnoMemOnly());
951+
}
952+
953+
/// Determine if the function may only access memory that is
954+
/// either pointed to by its arguments or errno memory.
955+
bool Function::onlyAccessesArgMemOrErrnoMem() const {
956+
return getMemoryEffects().onlyAccessesArgumentOrErrnoMem();
957+
}
958+
void Function::setOnlyAccessesArgMemOrErrnoMem() {
959+
setMemoryEffects(getMemoryEffects() &
960+
MemoryEffects::argumentOrErrnoMemOnly());
961+
}
962+
963+
/// Determine if the function may only access memory that is
964+
/// either inaccessible from the IR, pointed to by its arguments or errno
965+
/// memory.
966+
bool Function::onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const {
967+
return getMemoryEffects().onlyAccessesInaccessibleOrArgOrErrnoMem();
968+
}
969+
void Function::setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem() {
970+
setMemoryEffects(getMemoryEffects() &
971+
MemoryEffects::inaccessibleOrArgOrErrnoMemOnly());
972+
}
973+
935974
bool Function::isTargetIntrinsic() const {
936975
return Intrinsic::isTargetIntrinsic(IntID);
937976
}

llvm/lib/IR/Instructions.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,14 @@ void CallBase::setOnlyAccessesInaccessibleMemory() {
682682
setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly());
683683
}
684684

685+
/// Determine if the function may only access errno memory.
686+
bool CallBase::onlyAccessesErrnoMemory() const {
687+
return getMemoryEffects().onlyAccessesErrnoMem();
688+
}
689+
void CallBase::setOnlyAccessesErrnoMemory() {
690+
setMemoryEffects(getMemoryEffects() & MemoryEffects::errnoMemOnly());
691+
}
692+
685693
/// Determine if the function may only access memory that is
686694
/// either inaccessible from the IR or pointed to by its arguments.
687695
bool CallBase::onlyAccessesInaccessibleMemOrArgMem() const {
@@ -692,6 +700,37 @@ void CallBase::setOnlyAccessesInaccessibleMemOrArgMem() {
692700
MemoryEffects::inaccessibleOrArgMemOnly());
693701
}
694702

703+
/// Determine if the function may only access memory that is
704+
/// either inaccessible from the IR or errno memory.
705+
bool CallBase::onlyAccessesInaccessibleMemOrErrnoMem() const {
706+
return getMemoryEffects().onlyAccessesInaccessibleOrErrnoMem();
707+
}
708+
void CallBase::setOnlyAccessesInaccessibleMemOrErrnoMem() {
709+
setMemoryEffects(getMemoryEffects() &
710+
MemoryEffects::inaccessibleOrErrnoMemOnly());
711+
}
712+
713+
/// Determine if the function may only access memory that is
714+
/// either pointed to by its arguments or errno memory.
715+
bool CallBase::onlyAccessesArgMemOrErrnoMem() const {
716+
return getMemoryEffects().onlyAccessesArgumentOrErrnoMem();
717+
}
718+
void CallBase::setOnlyAccessesArgMemOrErrnoMem() {
719+
setMemoryEffects(getMemoryEffects() &
720+
MemoryEffects::argumentOrErrnoMemOnly());
721+
}
722+
723+
/// Determine if the function may only access memory that is
724+
/// either inaccessible from the IR, pointed to by its arguments or errno
725+
/// memory.
726+
bool CallBase::onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const {
727+
return getMemoryEffects().onlyAccessesInaccessibleOrArgOrErrnoMem();
728+
}
729+
void CallBase::setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem() {
730+
setMemoryEffects(getMemoryEffects() &
731+
MemoryEffects::inaccessibleOrArgOrErrnoMemOnly());
732+
}
733+
695734
CaptureInfo CallBase::getCaptureInfo(unsigned OpNo) const {
696735
if (OpNo < arg_size()) {
697736
// If the argument is passed byval, the callee does not have access to the

llvm/lib/Support/ModRef.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) {
4343
case IRMemLocation::InaccessibleMem:
4444
OS << "InaccessibleMem: ";
4545
break;
46+
case IRMemLocation::ErrnoMem:
47+
OS << "ErrnoMem: ";
48+
break;
4649
case IRMemLocation::Other:
4750
OS << "Other: ";
4851
break;

0 commit comments

Comments
 (0)