use llvm_native_core::constants::MDNode;
use llvm_native_core::value::ValueRef;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MetadataKind {
Dbg = 0,
TBAA = 1,
TBAAStruct = 2,
Prof = 3,
FnEntryCount = 4,
Range = 5,
AliasScope = 6,
NoAlias = 7,
Loop = 8,
Type = 9,
SectionPrefix = 10,
AbsoluteSymbol = 11,
Associated = 12,
Callees = 13,
IrrLoop = 14,
MakeImplicitInline = 15,
Annotation = 16,
Callback = 17,
PreserveAccessIndex = 18,
FPContract = 19,
}
impl MetadataKind {
pub fn from_id(id: u32) -> Self {
match id {
0 => MetadataKind::Dbg,
1 => MetadataKind::TBAA,
2 => MetadataKind::TBAAStruct,
3 => MetadataKind::Prof,
4 => MetadataKind::FnEntryCount,
5 => MetadataKind::Range,
6 => MetadataKind::AliasScope,
7 => MetadataKind::NoAlias,
8 => MetadataKind::Loop,
9 => MetadataKind::Type,
10 => MetadataKind::SectionPrefix,
11 => MetadataKind::AbsoluteSymbol,
12 => MetadataKind::Associated,
13 => MetadataKind::Callees,
14 => MetadataKind::IrrLoop,
15 => MetadataKind::MakeImplicitInline,
16 => MetadataKind::Annotation,
17 => MetadataKind::Callback,
18 => MetadataKind::PreserveAccessIndex,
19 => MetadataKind::FPContract,
_ => MetadataKind::Annotation,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MetadataAttachmentMap {
pub attachments: HashMap<MetadataKind, Vec<MDNode>>,
}
impl MetadataAttachmentMap {
pub fn set_metadata(&mut self, kind: MetadataKind, node: MDNode) {
self.attachments.entry(kind).or_default().push(node);
}
pub fn get_metadata(&self, kind: MetadataKind) -> Option<&Vec<MDNode>> {
self.attachments.get(&kind)
}
pub fn erase_metadata(&mut self, kind: MetadataKind) {
self.attachments.remove(&kind);
}
pub fn has_metadata(&self) -> bool {
!self.attachments.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct NamedMetadata {
pub name: String,
pub operands: Vec<MDNode>,
}
impl NamedMetadata {
pub fn new(name: String) -> Self {
NamedMetadata {
name,
operands: Vec::new(),
}
}
pub fn add_operand(&mut self, node: MDNode) {
self.operands.push(node);
}
pub fn get_operand(&self, idx: usize) -> Option<&MDNode> {
self.operands.get(idx)
}
}
#[derive(Debug, Clone, Default)]
pub struct NamedMetadataStore {
pub named: HashMap<String, NamedMetadata>,
}
impl NamedMetadataStore {
pub fn get_or_create(&mut self, name: &str) -> &mut NamedMetadata {
self.named
.entry(name.to_string())
.or_insert_with(|| NamedMetadata::new(name.to_string()))
}
pub fn get(&self, name: &str) -> Option<&NamedMetadata> {
self.named.get(name)
}
}
#[derive(Debug, Clone)]
pub struct TBAANode {
pub parent: Option<Box<TBAANode>>,
pub identifier: String,
pub access_type: Option<u64>,
pub offset: u64,
pub size: u64,
pub is_constant: bool,
}
impl TBAANode {
pub fn root() -> Self {
TBAANode {
parent: None,
identifier: "Simple C/C++ TBAA".to_string(),
access_type: None,
offset: 0,
size: 0,
is_constant: false,
}
}
pub fn child(parent: TBAANode, identifier: String, size: u64) -> Self {
TBAANode {
parent: Some(Box::new(parent)),
identifier,
access_type: None,
offset: 0,
size,
is_constant: false,
}
}
}
#[derive(Debug, Clone)]
pub struct AliasScopeNode {
pub domain: u64,
pub scope: u64,
}
#[derive(Debug, Clone)]
pub struct AliasScopeList {
pub scopes: Vec<AliasScopeNode>,
}
#[derive(Debug, Clone)]
pub struct LoopMetadata {
pub unroll_enable: Option<bool>,
pub unroll_count: Option<u32>,
pub unroll_and_jam_enable: Option<bool>,
pub unroll_and_jam_count: Option<u32>,
pub vectorize_enable: Option<bool>,
pub vectorize_width: Option<u32>,
pub vectorize_predicate_enable: Option<bool>,
pub interleave_enable: Option<bool>,
pub interleave_count: Option<u32>,
pub distribution_enable: Option<bool>,
pub licm_versioning_disable: Option<bool>,
pub mustprogress: bool,
pub parallel_accesses: Vec<u64>,
}
impl Default for LoopMetadata {
fn default() -> Self {
LoopMetadata {
unroll_enable: None,
unroll_count: None,
unroll_and_jam_enable: None,
unroll_and_jam_count: None,
vectorize_enable: None,
vectorize_width: None,
vectorize_predicate_enable: None,
interleave_enable: None,
interleave_count: None,
distribution_enable: None,
licm_versioning_disable: None,
mustprogress: false,
parallel_accesses: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct BranchWeights {
pub weights: Vec<u64>,
}
impl BranchWeights {
pub fn new(weights: Vec<u64>) -> Self {
BranchWeights { weights }
}
pub fn get_num_weights(&self) -> usize {
self.weights.len()
}
pub fn get_weight(&self, idx: usize) -> u64 {
self.weights.get(idx).copied().unwrap_or(0)
}
}
#[derive(Debug, Clone)]
pub struct ValueProfile {
pub kind: u32,
pub values: Vec<(u64, u64)>, }
#[derive(Debug, Clone)]
pub struct FunctionEntryCount {
pub count: u64,
pub is_synthetic: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_metadata_kind_from_id() {
assert_eq!(MetadataKind::from_id(0), MetadataKind::Dbg);
assert_eq!(MetadataKind::from_id(1), MetadataKind::TBAA);
assert_eq!(MetadataKind::from_id(8), MetadataKind::Loop);
}
#[test]
fn test_named_metadata() {
let mut store = NamedMetadataStore::default();
let nm = store.get_or_create("llvm.module.flags");
nm.add_operand(MDNode {
operands: Vec::new(),
id: 1,
});
assert!(store.get("llvm.module.flags").is_some());
}
#[test]
fn test_loop_metadata_default() {
let lm = LoopMetadata::default();
assert!(lm.unroll_enable.is_none());
assert!(!lm.mustprogress);
}
#[test]
fn test_branch_weights() {
let bw = BranchWeights::new(vec![100, 1]);
assert_eq!(bw.get_num_weights(), 2);
assert_eq!(bw.get_weight(0), 100);
}
}