1pub mod checking;
2pub mod data_collection;
3pub mod iterator;
4pub mod memory_cloning;
5
6use rustc_middle::ty::TyCtxt;
7
8use crate::utils::log::span_to_source_code;
9
10use super::core::dataflow::{default::DataFlowAnalyzer, graph::Graph};
11use checking::bounds_checking::BoundsCheck;
12use checking::encoding_checking::EncodingCheck;
13use data_collection::initialization::InitializationCheck;
14use data_collection::reallocation::ReservationCheck;
15use data_collection::suboptimal::SuboptimalCheck;
16use memory_cloning::used_as_immutable::UsedAsImmutableCheck;
17
18use lazy_static::lazy_static;
19use rustc_span::symbol::Symbol;
20use std::sync::Mutex;
21
22lazy_static! {
23 pub static ref NO_STD: Mutex<bool> = Mutex::new(false);
24 pub static ref LEVEL: Mutex<usize> = Mutex::new(0);
25}
26
27pub struct Opt<'tcx> {
28 pub tcx: TyCtxt<'tcx>,
29 pub level: usize,
30}
31
32pub trait OptCheck {
33 fn new() -> Self;
34 fn check(&mut self, graph: &Graph, tcx: &TyCtxt);
35 fn report(&self, graph: &Graph);
36 fn cnt(&self) -> usize;
37}
38
39impl<'tcx> Opt<'tcx> {
40 pub fn new(tcx: TyCtxt<'tcx>, level: usize) -> Self {
41 Self { tcx, level }
42 }
43
44 fn has_crate(&self, name: &str) -> bool {
45 for num in self.tcx.crates(()) {
46 if self.tcx.crate_name(*num) == Symbol::intern(name) {
47 return true;
48 }
49 }
50 false
51 }
52
53 pub fn start(&mut self) {
54 let mut dataflow = DataFlowAnalyzer::new(self.tcx, false);
55 dataflow.build_graphs();
56 {
57 let mut no_std = NO_STD.lock().unwrap();
58 *no_std = !self.has_crate("std");
59 let mut level = LEVEL.lock().unwrap();
60 *level = self.level;
61 }
62 if !self.has_crate("core") {
63 return;
65 }
66
67 let mut statistics = vec![0 as usize; 6];
68
69 dataflow.graphs.iter().for_each(|(_, graph)| {
70 let mut bounds_check = BoundsCheck::new();
71 bounds_check.check(graph, &self.tcx);
72 statistics[0] += bounds_check.cnt();
73
74 if self.level > 0 {
75 bounds_check.report(graph);
76 }
77
78 let no_std = NO_STD.lock().unwrap();
79 if !*no_std {
80 let mut encoding_check = EncodingCheck::new();
81 encoding_check.check(graph, &self.tcx);
82 statistics[1] += encoding_check.cnt();
83
84 let mut suboptimal_check = SuboptimalCheck::new();
85 suboptimal_check.check(graph, &self.tcx);
86 statistics[2] += suboptimal_check.cnt();
87
88 let mut initialization_check = InitializationCheck::new();
89 initialization_check.check(graph, &self.tcx);
90 statistics[3] += initialization_check.cnt();
91
92 let mut reservation_check = ReservationCheck::new();
93 reservation_check.check(graph, &self.tcx);
94 statistics[4] += reservation_check.cnt();
95
96 let mut used_as_immutable_check = UsedAsImmutableCheck::new();
97 used_as_immutable_check.check(graph, &self.tcx);
98 statistics[5] += used_as_immutable_check.cnt();
99
100 if self.level > 0 {
101 encoding_check.report(graph);
102 suboptimal_check.report(graph);
103 initialization_check.report(graph);
104 reservation_check.report(graph);
105 used_as_immutable_check.report(graph);
106 }
107 }
108 });
109
110 let bug_cnt: usize = statistics.iter().sum();
111 let func_cnt: usize = dataflow.graphs.iter().count();
112 let line_cnt: usize = dataflow
113 .graphs
114 .iter()
115 .map(|(_, graph)| span_to_source_code(graph.span).lines().count())
116 .sum();
117 if bug_cnt > 0 {
118 rap_warn!("Potential optimizations detected.");
119 println!(
120 "RAPx detects {} code inefficiencies from {} functions ({} lines)",
121 bug_cnt, func_cnt, line_cnt,
122 );
123 println!(" Bounds Checking: {}", statistics[0]);
124 println!(" Encoding Checking: {}", statistics[1]);
125 println!(" Suboptimal: {}", statistics[2]);
126 println!(" Initialization: {}", statistics[3]);
127 println!(" Reallocation: {}", statistics[4]);
128 println!(" Cloning: {}", statistics[5]);
129 }
130 }
131}