use std::collections::HashMap;
use std::hash::BuildHasher;
use panproto_gat::Theory;
use panproto_schema::{EdgeRule, Protocol};
#[must_use]
pub fn protocol() -> Protocol {
Protocol {
name: "llvm_ir".into(),
schema_theory: "ThLLVMIRSchema".into(),
instance_theory: "ThLLVMIRInstance".into(),
edge_rules: edge_rules(),
obj_kinds: vertex_kinds(),
constraint_sorts: constraint_sorts(),
has_order: true,
has_coproducts: false,
has_recursion: false,
has_causal: false,
nominal_identity: false,
has_defaults: false,
has_coercions: false,
has_mergers: false,
has_policies: false,
}
}
pub fn register_theories<S: BuildHasher>(registry: &mut HashMap<String, Theory, S>) {
panproto_protocols::theories::register_constrained_multigraph_wtype(
registry,
"ThLLVMIRSchema",
"ThLLVMIRInstance",
);
}
fn vertex_kinds() -> Vec<String> {
vec![
"module".into(),
"function".into(),
"global-variable".into(),
"alias".into(),
"comdat".into(),
"metadata-node".into(),
"named-metadata".into(),
"attribute-group".into(),
"basic-block".into(),
"parameter".into(),
"instruction".into(),
"void-type".into(),
"integer-type".into(),
"float-type".into(),
"pointer-type".into(),
"array-type".into(),
"vector-type".into(),
"struct-type".into(),
"function-type".into(),
"label-type".into(),
"metadata-type".into(),
"token-type".into(),
"constant".into(),
"undef".into(),
"poison".into(),
"null".into(),
"zero-initializer".into(),
"constant-array".into(),
"constant-struct".into(),
"constant-vector".into(),
"constant-expr".into(),
"block-address".into(),
"inline-asm".into(),
]
}
fn constraint_sorts() -> Vec<String> {
vec![
"opcode".into(),
"linkage".into(),
"visibility".into(),
"calling-convention".into(),
"param-attribute".into(),
"function-attribute".into(),
"return-attribute".into(),
"alignment".into(),
"address-space".into(),
"bit-width".into(),
"float-kind".into(),
"struct-name".into(),
"element-count".into(),
"constant-value".into(),
"is-constant".into(),
"thread-local-mode".into(),
"unnamed-addr".into(),
"fast-math-flags".into(),
"metadata-kind".into(),
"block-label".into(),
"ssa-name".into(),
"predicate".into(),
"ordering".into(),
]
}
fn edge_rules() -> Vec<EdgeRule> {
vec![
EdgeRule {
edge_kind: "contains-function".into(),
src_kinds: vec!["module".into()],
tgt_kinds: vec!["function".into()],
},
EdgeRule {
edge_kind: "contains-global".into(),
src_kinds: vec!["module".into()],
tgt_kinds: vec!["global-variable".into()],
},
EdgeRule {
edge_kind: "contains-block".into(),
src_kinds: vec!["function".into()],
tgt_kinds: vec!["basic-block".into()],
},
EdgeRule {
edge_kind: "contains-instruction".into(),
src_kinds: vec!["basic-block".into()],
tgt_kinds: vec!["instruction".into()],
},
EdgeRule {
edge_kind: "contains-parameter".into(),
src_kinds: vec!["function".into()],
tgt_kinds: vec!["parameter".into()],
},
EdgeRule {
edge_kind: "operand".into(),
src_kinds: vec!["instruction".into()],
tgt_kinds: vec![], },
EdgeRule {
edge_kind: "successor".into(),
src_kinds: vec!["basic-block".into()],
tgt_kinds: vec!["basic-block".into()],
},
EdgeRule {
edge_kind: "entry-block".into(),
src_kinds: vec!["function".into()],
tgt_kinds: vec!["basic-block".into()],
},
EdgeRule {
edge_kind: "type-of".into(),
src_kinds: vec![], tgt_kinds: vec![], },
EdgeRule {
edge_kind: "element-type".into(),
src_kinds: vec![
"array-type".into(),
"vector-type".into(),
"pointer-type".into(),
],
tgt_kinds: vec![], },
EdgeRule {
edge_kind: "return-type".into(),
src_kinds: vec!["function-type".into()],
tgt_kinds: vec![], },
EdgeRule {
edge_kind: "param-type".into(),
src_kinds: vec!["function-type".into()],
tgt_kinds: vec![], },
EdgeRule {
edge_kind: "struct-field-type".into(),
src_kinds: vec!["struct-type".into()],
tgt_kinds: vec![], },
]
}
#[must_use]
pub fn instruction_opcodes() -> Vec<&'static str> {
vec![
"ret",
"br",
"switch",
"indirectbr",
"invoke",
"resume",
"unreachable",
"cleanupret",
"catchret",
"catchswitch",
"callbr",
"fneg",
"add",
"fadd",
"sub",
"fsub",
"mul",
"fmul",
"udiv",
"sdiv",
"fdiv",
"urem",
"srem",
"frem",
"shl",
"lshr",
"ashr",
"and",
"or",
"xor",
"alloca",
"load",
"store",
"fence",
"cmpxchg",
"atomicrmw",
"getelementptr",
"trunc",
"zext",
"sext",
"fptrunc",
"fpext",
"fptoui",
"fptosi",
"uitofp",
"sitofp",
"ptrtoint",
"inttoptr",
"bitcast",
"addrspacecast",
"icmp",
"fcmp",
"phi",
"select",
"freeze",
"call",
"va_arg",
"landingpad",
"catchpad",
"cleanuppad",
"extractvalue",
"insertvalue",
"extractelement",
"insertelement",
"shufflevector",
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn protocol_def() {
let proto = protocol();
assert_eq!(proto.name, "llvm_ir");
assert!(proto.obj_kinds.len() > 20, "expected 20+ vertex kinds");
assert!(proto.edge_rules.len() > 10, "expected 10+ edge rules");
assert!(
proto.constraint_sorts.len() > 15,
"expected 15+ constraint sorts"
);
assert!(proto.has_order);
}
#[test]
fn register_theories_works() {
let mut registry = HashMap::new();
register_theories(&mut registry);
assert!(registry.contains_key("ThLLVMIRSchema"));
assert!(registry.contains_key("ThLLVMIRInstance"));
}
#[test]
fn instruction_opcode_coverage() {
let opcodes = instruction_opcodes();
assert!(
opcodes.len() > 50,
"expected 50+ opcodes, got {}",
opcodes.len()
);
assert!(opcodes.contains(&"add"));
assert!(opcodes.contains(&"ret"));
assert!(opcodes.contains(&"phi"));
assert!(opcodes.contains(&"getelementptr"));
assert!(opcodes.contains(&"call"));
}
}