-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Extend MemoryEffects to Support Target-Specific Memory Locations #148650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
958984a
f4bf13d
6f9ba55
f55128e
99b3b77
f113135
4cb454e
853f657
09a9b00
f4fc0b7
e8fc7eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -203,6 +203,8 @@ enum Kind { | |
kw_readwrite, | ||
kw_argmem, | ||
kw_inaccessiblemem, | ||
kw_aarch64_fpmr, | ||
kw_aarch64_za, | ||
Comment on lines
+206
to
+207
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had in mind that these would be part of the follow-on PR as well? The idea being this PR keeps everything generic and fully supports There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need a token to be used when describing the memory: There are 3 solutions:
Do you have a preferred solution? Or do you see another way of doing this? |
||
kw_errnomem, | ||
|
||
// Legacy attributes: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,11 @@ enum class ModRefInfo : uint8_t { | |
/// Debug print ModRefInfo. | ||
LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR); | ||
|
||
enum class InaccessibleTargetMemLocation { | ||
|
||
TargetMem0 = 3, | ||
TargetMem1 = 4, | ||
}; | ||
|
||
/// The locations at which a function might access memory. | ||
enum class IRMemLocation { | ||
/// Access to memory via argument pointers. | ||
|
@@ -65,7 +70,7 @@ enum class IRMemLocation { | |
/// Errno memory. | ||
ErrnoMem = 2, | ||
/// Any other memory. | ||
Other = 3, | ||
Other = 5, | ||
|
||
/// Helpers to iterate all locations in the MemoryEffectsBase class. | ||
First = ArgMem, | ||
|
@@ -152,6 +157,40 @@ template <typename LocationEnum> class MemoryEffectsBase { | |
return MemoryEffectsBase(Location::Other, MR); | ||
} | ||
|
||
/// Create MemoryEffectsBase that can only read inaccessible memory. | ||
static MemoryEffectsBase | ||
inaccessibleReadMemOnly(Location Loc = Location::InaccessibleMem) { | ||
return MemoryEffectsBase(Loc, ModRefInfo::Ref); | ||
} | ||
|
||
/// Create MemoryEffectsBase that can only write inaccessible memory. | ||
static MemoryEffectsBase | ||
inaccessibleWriteMemOnly(Location Loc = Location::InaccessibleMem) { | ||
return MemoryEffectsBase(Loc, ModRefInfo::Mod); | ||
} | ||
|
||
/// Checks if only target-specific memory locations are set. | ||
/// Ignores standard locations like ArgMem or InaccessibleMem. | ||
/// Needed because `Data` may be non-zero by default unless explicitly | ||
/// cleared. | ||
bool onlyAccessTargetMemoryLocation() { | ||
MemoryEffectsBase ME = *this; | ||
for (unsigned I = static_cast<int>(LocationEnum::ErrnoMem); | ||
I < static_cast<int>(LocationEnum::Last); I++) | ||
ME = ME.getWithoutLoc(static_cast<IRMemLocation>(I)); | ||
return ME.doesNotAccessMemory(); | ||
} | ||
|
||
/// Create MemoryEffectsBase that can only access Target Memory Locations | ||
static MemoryEffectsBase | ||
setTargetMemLocationModRef(ModRefInfo MR = ModRefInfo::NoModRef) { | ||
MemoryEffectsBase FRMB = none(); | ||
for (unsigned I = static_cast<int>(LocationEnum::ErrnoMem); | ||
I < static_cast<int>(LocationEnum::Last); I++) | ||
FRMB.setModRef(static_cast<Location>(I), MR); | ||
return FRMB; | ||
} | ||
|
||
/// Create MemoryEffectsBase that can only access inaccessible or argument | ||
/// memory. | ||
static MemoryEffectsBase | ||
|
@@ -178,6 +217,11 @@ template <typename LocationEnum> class MemoryEffectsBase { | |
return MemoryEffectsBase(Data); | ||
} | ||
|
||
bool isTargetMemLoc(IRMemLocation Loc) { | ||
return static_cast<unsigned>(Loc) > | ||
static_cast<unsigned>(Location::ErrnoMem); | ||
} | ||
|
||
/// Convert MemoryEffectsBase into an encoded integer value (used by memory | ||
/// attribute). | ||
uint32_t toIntValue() const { | ||
|
@@ -232,7 +276,12 @@ template <typename LocationEnum> class MemoryEffectsBase { | |
|
||
/// Whether this function only (at most) accesses inaccessible memory. | ||
bool onlyAccessesInaccessibleMem() const { | ||
return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory(); | ||
return getWithoutLoc(static_cast<IRMemLocation>( | ||
llvm::InaccessibleTargetMemLocation::TargetMem0)) | ||
.getWithoutLoc(static_cast<IRMemLocation>( | ||
llvm::InaccessibleTargetMemLocation::TargetMem1)) | ||
.getWithoutLoc(Location::InaccessibleMem) | ||
.doesNotAccessMemory(); | ||
} | ||
|
||
/// Whether this function only (at most) accesses errno memory. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
; RUN: llvm-as < %s | llvm-dis | FileCheck %s | ||
|
||
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" | ||
target triple = "aarch64" | ||
|
||
; CHECK: Function Attrs: memory(target_mem1 : write) | ||
; CHECK: @fn_inaccessiblemem_write_aarch64_za() [[ATTR0:#.*]] | ||
declare void @fn_inaccessiblemem_write_aarch64_za() | ||
memory(aarch64_za: write) | ||
|
||
; CHECK: Function Attrs: memory(target_mem1 : read) | ||
; CHECK: @fn_inaccessiblemem_read_aarch64_za() [[ATTR1:#.*]] | ||
declare void @fn_inaccessiblemem_read_aarch64_za() | ||
memory(aarch64_za: read) | ||
|
||
; CHECK: Function Attrs: memory(target_mem0 : write) | ||
; CHECK: @fn_inaccessiblemem_write_aarch64_fpmr() [[ATTR2:#.*]] | ||
declare void @fn_inaccessiblemem_write_aarch64_fpmr() | ||
memory(aarch64_fpmr: write) | ||
|
||
; CHECK: ; Function Attrs: memory(target_mem0 : read) | ||
; CHECK: @fn_inaccessiblemem_read_aarch64_fpmr() [[ATTR3:#.*]] | ||
declare void @fn_inaccessiblemem_read_aarch64_fpmr() | ||
memory(aarch64_fpmr: read) | ||
|
||
; CHECK: Function Attrs: memory(target_mem0 : read, target_mem1 : write) | ||
; CHECK: @fn_inaccessiblemem_read_aarch64_fpmr_write_aarch64_za() [[ATTR4:#.*]] | ||
declare void @fn_inaccessiblemem_read_aarch64_fpmr_write_aarch64_za() | ||
memory(aarch64_fpmr: read, aarch64_za: write) | ||
|
||
; CHECK: attributes [[ATTR0]] = { memory(target_mem1 : write) } | ||
; CHECK: attributes [[ATTR1]] = { memory(target_mem1 : read) } | ||
; CHECK: attributes [[ATTR2]] = { memory(target_mem0 : write) } | ||
; CHECK: attributes [[ATTR3]] = { memory(target_mem0 : read) } | ||
; CHECK: attributes [[ATTR4]] = { memory(target_mem0 : read, target_mem1 : write) } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include -DTEST_INTRINSICS_SUPPRESS_DEFS %s | FileCheck %s | ||
|
||
include "llvm/IR/Intrinsics.td" | ||
|
||
def int_aarch64_set_fpmr_2 : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrInaccessibleWriteMemOnly<AArch64_FPMR>]>; | ||
|
||
def int_aarch64_get_za_2 : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrInaccessibleReadMemOnly<AArch64_ZA>]>; | ||
|
||
def int_aarch64_get_fpmr_set_za : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrInaccessibleReadMemOnly<AArch64_FPMR>, IntrInaccessibleWriteMemOnly<AArch64_ZA>]>; | ||
|
||
// CHECK: static constexpr unsigned IntrinsicNameOffsetTable[] = { | ||
// CHECK-NEXT: 1, // not_intrinsic | ||
// CHECK-NEXT: 15, // llvm.aarch64.get.fpmr.set.za | ||
// CHECK-NEXT: 44, // llvm.aarch64.get.za.2 | ||
// CHECK-NEXT: 66, // llvm.aarch64.set.fpmr.2 | ||
|
||
// CHECK: static AttributeSet getIntrinsicFnAttributeSet(LLVMContext &C, unsigned ID) { | ||
// CHECK-NEXT: switch (ID) { | ||
// CHECK-NEXT: default: llvm_unreachable("Invalid attribute set number"); | ||
// CHECK-NEXT: case 0: | ||
// CHECK-NEXT: return AttributeSet::get(C, { | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoCallback), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoSync), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoFree), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::WillReturn), | ||
// CHECK-NEXT: // ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: NoModRef, TargetMem0: Ref, TargetMem1: Mod, Other: NoModRef | ||
// CHECK-NEXT: Attribute::getWithMemoryEffects(C, MemoryEffects::createFromIntValue(576)), | ||
// CHECK-NEXT: }); | ||
// CHECK-NEXT: case 1: | ||
// CHECK-NEXT: return AttributeSet::get(C, { | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoCallback), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoSync), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoFree), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::WillReturn), | ||
// CHECK-NEXT: // ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: NoModRef, TargetMem0: NoModRef, TargetMem1: Ref, Other: NoModRef | ||
// CHECK-NEXT: Attribute::getWithMemoryEffects(C, MemoryEffects::createFromIntValue(256)), | ||
// CHECK-NEXT: }); | ||
// CHECK-NEXT: case 2: | ||
// CHECK-NEXT: return AttributeSet::get(C, { | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoUnwind), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoCallback), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoSync), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::NoFree), | ||
// CHECK-NEXT: Attribute::get(C, Attribute::WillReturn), | ||
// CHECK-NEXT: // ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: NoModRef, TargetMem0: Mod, TargetMem1: NoModRef, Other: NoModRef | ||
// CHECK-NEXT: Attribute::getWithMemoryEffects(C, MemoryEffects::createFromIntValue(128)), | ||
|
||
// CHECK: static constexpr uint16_t IntrinsicsToAttributesMap[] = { | ||
// CHECK-NEXT: 0 << 8 | 0, // llvm.aarch64.get.fpmr.set.za | ||
// CHECK-NEXT: 1 << 8 | 0, // llvm.aarch64.get.za.2 | ||
// CHECK-NEXT: 2 << 8 | 0, // llvm.aarch64.set.fpmr.2 | ||
// CHECK-NEXT:}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll let @nikic comment, but are we really planning to extend LLVM IR syntax with arch specific keywords?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this new? There are many examples mainly linked to calling conventions and function/argument attributes.