use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Attribute {
AllocAlign = 1,
AllocatedPointer = 2,
AlwaysInline = 3,
Builtin = 4,
Cold = 5,
Convergent = 6,
CoroDestroyOnlyWhenComplete = 7,
CoroElideSafe = 8,
DeadOnReturn = 9,
DeadOnUnwind = 10,
DisableSanitizerInstrumentation = 11,
FnRetThunkExtern = 12,
Hot = 13,
HybridPatchable = 14,
ImmArg = 15,
InReg = 16,
InlineHint = 17,
JumpTable = 18,
MinSize = 19,
MustProgress = 20,
Naked = 21,
Nest = 22,
NoAlias = 23,
NoBuiltin = 24,
NoCallback = 25,
NoCfCheck = 26,
NoCreateUndefOrPoison = 27,
NoDivergenceSource = 28,
NoDuplicate = 29,
NoExt = 30,
NoFree = 31,
NoImplicitFloat = 32,
NoInline = 33,
NoMerge = 34,
NoProfile = 35,
NoRecurse = 36,
NoRedZone = 37,
NoReturn = 38,
NoSanitizeBounds = 39,
NoSanitizeCoverage = 40,
NoSync = 41,
NoUndef = 42,
NoUnwind = 43,
NonLazyBind = 44,
NonNull = 45,
NullPointerIsValid = 46,
OptForFuzzing = 47,
OptimizeForDebugging = 48,
OptimizeForSize = 49,
OptimizeNone = 50,
PresplitCoroutine = 51,
ReadNone = 52,
ReadOnly = 53,
Returned = 54,
ReturnsTwice = 55,
SExt = 56,
SafeStack = 57,
SanitizeAddress = 58,
SanitizeAllocToken = 59,
SanitizeHWAddress = 60,
SanitizeMemTag = 61,
SanitizeMemory = 62,
SanitizeNumericalStability = 63,
SanitizeRealtime = 64,
SanitizeRealtimeBlocking = 65,
SanitizeThread = 66,
SanitizeType = 67,
ShadowCallStack = 68,
SkipProfile = 69,
Speculatable = 70,
SpeculativeLoadHardening = 71,
StackProtect = 72,
StackProtectReq = 73,
StackProtectStrong = 74,
StrictFP = 75,
SwiftAsync = 76,
SwiftError = 77,
SwiftSelf = 78,
WillReturn = 79,
Writable = 80,
WriteOnly = 81,
ZExt = 82,
ByRef = 83,
ByVal = 84,
ElementType = 85,
InAlloca = 86,
Preallocated = 87,
StructRet = 88,
Alignment = 89,
AllocKind = 90,
AllocSize = 91,
Captures = 92,
Dereferenceable = 93,
DereferenceableOrNull = 94,
Memory = 95,
NoFPClass = 96,
StackAlignment = 97,
UWTable = 98,
VScaleRange = 99,
Range = 100,
Initializes = 101,
}
#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
enum ModRefInfo {
NoModRef = 0,
Ref = 1,
Mod = 2,
ModRef = 3,
}
#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
enum MemoryLocation {
ArgMem = 0,
InaccessibleMem = 1,
ErrnoMem = 2,
Other = 3,
}
const MEMORY_EFFECT_BITS_PER_LOCATION: u64 = 2;
const fn memory_location_pos(location: MemoryLocation) -> u64 {
(location as u64) * MEMORY_EFFECT_BITS_PER_LOCATION
}
const fn pack_memory_effect(location: MemoryLocation, mod_ref: ModRefInfo) -> u64 {
(mod_ref as u64) << memory_location_pos(location)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemoryEffect {
Unrestricted,
None,
ReadInaccessible,
ReadArgAndInaccessible,
WriteInaccessible,
ReadOther,
}
impl MemoryEffect {
pub const fn encoding(self) -> Option<u64> {
match self {
Self::Unrestricted => None,
Self::None => Some(0),
Self::ReadInaccessible => Some(pack_memory_effect(
MemoryLocation::InaccessibleMem,
ModRefInfo::Ref,
)),
Self::ReadArgAndInaccessible => Some(
pack_memory_effect(MemoryLocation::ArgMem, ModRefInfo::Ref)
| pack_memory_effect(MemoryLocation::InaccessibleMem, ModRefInfo::Ref),
),
Self::WriteInaccessible => Some(pack_memory_effect(
MemoryLocation::InaccessibleMem,
ModRefInfo::Mod,
)),
Self::ReadOther => Some(pack_memory_effect(MemoryLocation::Other, ModRefInfo::Ref)),
}
}
}
impl TryFrom<&str> for Attribute {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"AlwaysInline" => Ok(Attribute::AlwaysInline),
"Cold" => Ok(Attribute::Cold),
"Hot" => Ok(Attribute::Hot),
"MinSize" => Ok(Attribute::MinSize),
"OptimizeForSize" => Ok(Attribute::OptimizeForSize),
"NoInline" => Ok(Attribute::NoInline),
"WillReturn" => Ok(Attribute::WillReturn),
"NoReturn" => Ok(Attribute::NoReturn),
"MustProgress" => Ok(Attribute::MustProgress),
_ => Err(value.to_owned()),
}
}
}
#[cfg(test)]
mod memory_effect_tests {
use super::*;
#[test]
fn encoding_matches_llvm_21_layout() {
assert_eq!(MemoryEffect::Unrestricted.encoding(), None);
assert_eq!(MemoryEffect::None.encoding(), Some(0));
assert_eq!(MemoryEffect::ReadInaccessible.encoding(), Some(4));
assert_eq!(MemoryEffect::ReadArgAndInaccessible.encoding(), Some(5));
assert_eq!(MemoryEffect::WriteInaccessible.encoding(), Some(8));
assert_eq!(MemoryEffect::ReadOther.encoding(), Some(64));
}
}