-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[RFC] 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
d568c2b
13c7470
1987000
2dccfa1
4366ac7
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 |
---|---|---|
|
@@ -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 { | ||
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. Each Target should have an InaccessibleTargetMemLocation, but I am not sure if we should check which Target it is being used in Support, Attributes and so on. I would appreciate some suggestion if this is the right way to do this. And this is still using Data to model the Memory Locations with ModRef. Is this the only way to add new memory location? 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 wonder if we could have something around the following instead: enum class IRMemLocation {
ArgMem = 0,
InaccessibleMem = 1,
ErrnoMem = 2,
TargetSpecificMem = 3,
Other = 4,
First = ArgMem,
Last = Other,
}; And then extending struct TargetSpecificMemTag {
Triple::ArchType Arch;
uint8_t Kind;
}; This would lead to know easily if the location is target-specific: bool isTargetSpecific() const { return Loc == Location::TargetSpecificMem; } And I guess it would avoid having some 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. Hi @antoniofrighetto For instance: I am not sure I can have only one Kind. For instance, something like this: I imagine that the ModRefInfo for TargetSpecificMem will be 11, that is ModRef. I would also have to see how this will work in BasicAliasAnalysis.cpp/getModRefInfo and BitcodeReader.cpp(parseAttributeGroupBlock) |
||
AARCH64_FPMR = 3, | ||
AARCH64_ZA = 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 { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -640,6 +640,10 @@ std::string Attribute::getAsString(bool InAttrGrp) const { | |
if (MR == OtherMR) | ||
continue; | ||
|
||
// Dont want to print Target Location if NoModRef | ||
if (ME.isTargetMemLoc(Loc) && (MR == ModRefInfo::NoModRef)) | ||
continue; | ||
|
||
if (!First) | ||
OS << ", "; | ||
First = false; | ||
|
@@ -656,6 +660,15 @@ std::string Attribute::getAsString(bool InAttrGrp) const { | |
break; | ||
case IRMemLocation::Other: | ||
llvm_unreachable("This is represented as the default access kind"); | ||
default: { | ||
InaccessibleTargetMemLocation TargetLoc = | ||
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. How can we make this to not be target specific? Any suggestion? |
||
static_cast<InaccessibleTargetMemLocation>(Loc); | ||
if (TargetLoc == InaccessibleTargetMemLocation::AARCH64_FPMR) | ||
OS << "aarch64_fpmr: "; | ||
if (TargetLoc == InaccessibleTargetMemLocation::AARCH64_ZA) | ||
OS << "aarch64_za: "; | ||
break; | ||
} | ||
} | ||
OS << getModRefStr(MR); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3102,6 +3102,21 @@ Record::getValueAsListOfDefs(StringRef FieldName) const { | |
return Defs; | ||
} | ||
|
||
llvm::IRMemLocation Record::getLocationTypeAsInt(StringRef FieldName) const { | ||
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. This function does not belong here. It should be moved instead to the specific backend that uses it (intrinsic emitter I am assuming) |
||
const Record *LocRec = getValueAsDef(FieldName); | ||
StringRef Name = LocRec->getName(); | ||
if (Name == "AArch64_FPMR") | ||
return static_cast<IRMemLocation>( | ||
llvm::InaccessibleTargetMemLocation::AARCH64_FPMR); | ||
else if (Name == "AArch64_ZA") | ||
return static_cast<IRMemLocation>( | ||
llvm::InaccessibleTargetMemLocation::AARCH64_ZA); | ||
else if (Name == "InaccessibleMem") | ||
return llvm::IRMemLocation::InaccessibleMem; | ||
else | ||
PrintFatalError(getLoc(), "unknown IRMemLocation: " + Name); | ||
} | ||
|
||
int64_t Record::getValueAsInt(StringRef FieldName) const { | ||
const RecordVal *R = getValue(FieldName); | ||
if (!R || !R->getValue()) | ||
|
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, AARCH64_FPMR: Ref, AARCH64_ZA: 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, AARCH64_FPMR: NoModRef, AARCH64_ZA: 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, AARCH64_FPMR: Mod, AARCH64_ZA: 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.