1pub mod checking;
2pub mod check_utils;
3pub mod data_collection;
4pub mod loop_visitors;
5pub mod memory_cloning;
6pub mod report;
7
8#[macro_export]
9macro_rules! def_paths {
10 ($($field:ident : $path:literal),+ $(,)?) => {
11 static DEFPATHS: once_cell::sync::OnceCell<DefPaths> = once_cell::sync::OnceCell::new();
12 struct DefPaths {
13 $(pub $field: $crate::helpers::def_path::DefPath),+
14 }
15 impl DefPaths {
16 #[allow(dead_code)]
17 fn new(tcx: &rustc_middle::ty::TyCtxt<'_>) -> Self {
18 Self {
19 $($field: $crate::helpers::def_path::DefPath::new($path, tcx)),+
20 }
21 }
22 }
23 };
24}
25
26use rustc_middle::ty::TyCtxt;
27
28use crate::analysis::dataflow::{Graph, default::DataflowAnalyzer};
29use crate::helpers::mir_utils::has_crate;
30use checking::bounds_checking::BoundsCheck;
31use checking::encoding_checking::EncodingCheck;
32use data_collection::initialization::InitializationCheck;
33use data_collection::reallocation::ReservationCheck;
34use data_collection::suboptimal::SuboptimalCheck;
35use memory_cloning::used_as_immutable::UsedAsImmutableCheck;
36
37use lazy_static::lazy_static;
38use std::sync::Mutex;
39
40lazy_static! {
41 pub(crate) static ref NO_STD: Mutex<bool> = Mutex::new(false);
42 pub(crate) static ref LEVEL: Mutex<usize> = Mutex::new(0);
43}
44
45pub struct Opt<'tcx> {
46 pub tcx: TyCtxt<'tcx>,
47 pub level: usize,
48}
49
50pub trait OptCheck {
51 fn new() -> Self;
52 fn check(&mut self, graph: &Graph, tcx: &TyCtxt);
53 fn report(&self, graph: &Graph);
54 fn cnt(&self) -> usize;
55}
56
57impl<'tcx> Opt<'tcx> {
58 pub fn new(tcx: TyCtxt<'tcx>, level: usize) -> Self {
59 Self { tcx, level }
60 }
61
62 pub fn start(&mut self) {
63 let mut dataflow = DataflowAnalyzer::new(self.tcx, false);
64 dataflow.build_graphs();
65 {
66 let mut no_std = NO_STD.lock().unwrap();
67 *no_std = !has_crate(self.tcx, "std");
68 let mut level = LEVEL.lock().unwrap();
69 *level = self.level;
70 }
71 if !has_crate(self.tcx, "core") {
72 return;
74 }
75
76 let mut statistics = vec![0 as usize; 6];
77
78 dataflow.graphs.iter().for_each(|(_, graph)| {
79 let mut bounds_check = BoundsCheck::new();
80 bounds_check.check(graph, &self.tcx);
81 statistics[0] += bounds_check.cnt();
82
83 if self.level > 0 {
84 bounds_check.report(graph);
85 }
86
87 let no_std = NO_STD.lock().unwrap();
88 if !*no_std {
89 let mut encoding_check = EncodingCheck::new();
90 encoding_check.check(graph, &self.tcx);
91 statistics[1] += encoding_check.cnt();
92
93 let mut suboptimal_check = SuboptimalCheck::new();
94 suboptimal_check.check(graph, &self.tcx);
95 statistics[2] += suboptimal_check.cnt();
96
97 let mut initialization_check = InitializationCheck::new();
98 initialization_check.check(graph, &self.tcx);
99 statistics[3] += initialization_check.cnt();
100
101 let mut reservation_check = ReservationCheck::new();
102 reservation_check.check(graph, &self.tcx);
103 statistics[4] += reservation_check.cnt();
104
105 let mut used_as_immutable_check = UsedAsImmutableCheck::new();
106 used_as_immutable_check.check(graph, &self.tcx);
107 statistics[5] += used_as_immutable_check.cnt();
108
109 if self.level > 0 {
110 encoding_check.report(graph);
111 suboptimal_check.report(graph);
112 initialization_check.report(graph);
113 reservation_check.report(graph);
114 used_as_immutable_check.report(graph);
115 }
116 }
117 });
118
119 let bug_cnt: usize = statistics.iter().sum();
120 if bug_cnt > 0 {
121 rap_warn!("Potential optimizations detected.");
122 rap_info!(
123 " Bounds Checking: {}, Encoding Checking: {}, Suboptimal: {}, Initialization: {}, Reallocation: {}, Cloning: {}",
124 statistics[0],
125 statistics[1],
126 statistics[2],
127 statistics[3],
128 statistics[4],
129 statistics[5],
130 );
131 }
132 }
133}