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