vector_to_slice.rs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // SPDX-License-Identifier: Apache-2.0
  2. use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
  3. use super::reaching_definitions::{Def, Transfer};
  4. use crate::codegen::cfg::ASTFunction;
  5. use crate::codegen::Expression;
  6. use crate::sema::ast::{Namespace, Type};
  7. use indexmap::IndexMap;
  8. use std::collections::HashSet;
  9. /// A vector is a modifiable struct with a length, size and data. A slice is a readonly
  10. /// pointer to some data, plus the length. By using a slice, often a memcpy can be avoided.
  11. ///
  12. /// Codegen generates vectors. Here we walk the cfg to find all vectors which can be converted
  13. /// to slices. In addition, we add some notes to the namespace so the language server can display
  14. /// some information when hovering over a variable.
  15. pub fn vector_to_slice(cfg: &mut ControlFlowGraph, ns: &mut Namespace) {
  16. // first, we need to find all the defs which have modified their referent
  17. // note that variables can aliases
  18. let mut writable = HashSet::new();
  19. for block_no in 0..cfg.blocks.len() {
  20. let mut vars = cfg.blocks[block_no].defs.clone();
  21. find_writable_vectors(&cfg.blocks[block_no], &mut vars, &mut writable);
  22. }
  23. // Now we have a list of all vectors defs that get written two (via variables)
  24. // walk the cfg and expressions and update the type of vectors
  25. update_vectors_to_slice(&writable, cfg, ns);
  26. }
  27. fn find_writable_vectors(
  28. block: &BasicBlock,
  29. vars: &mut IndexMap<usize, IndexMap<Def, bool>>,
  30. writable: &mut HashSet<Def>,
  31. ) {
  32. for instr_no in 0..block.instr.len() {
  33. match &block.instr[instr_no].1 {
  34. Instr::Set {
  35. res,
  36. expr: Expression::Variable(_, _, var_no),
  37. ..
  38. } => {
  39. // is this aliasing a vector var
  40. if let Some(defs) = vars.get(var_no) {
  41. let defs = defs.clone();
  42. apply_transfers(&block.transfers[instr_no], vars, writable);
  43. vars.insert(*res, defs);
  44. } else {
  45. apply_transfers(&block.transfers[instr_no], vars, writable);
  46. }
  47. }
  48. // Call and return do not take slices
  49. Instr::Return { value: args } | Instr::Call { args, .. } => {
  50. for arg in args {
  51. if let Expression::Variable(_, _, var_no) = arg {
  52. if let Some(entry) = vars.get_mut(var_no) {
  53. writable.extend(entry.keys());
  54. }
  55. }
  56. }
  57. apply_transfers(&block.transfers[instr_no], vars, writable);
  58. }
  59. Instr::PushMemory { value, .. } => {
  60. if let Expression::Variable(_, _, var_no) = value.as_ref() {
  61. if let Some(entry) = vars.get_mut(var_no) {
  62. writable.extend(entry.keys());
  63. }
  64. }
  65. apply_transfers(&block.transfers[instr_no], vars, writable);
  66. }
  67. Instr::Store { data, .. } => {
  68. if let Expression::Variable(_, _, var_no) = data {
  69. if let Some(entry) = vars.get_mut(var_no) {
  70. writable.extend(entry.keys());
  71. }
  72. }
  73. apply_transfers(&block.transfers[instr_no], vars, writable);
  74. }
  75. Instr::MemCopy {
  76. destination: buf, ..
  77. }
  78. | Instr::WriteBuffer { buf, .. } => {
  79. if let Expression::Variable(_, _, var_no) = buf {
  80. if let Some(entry) = vars.get_mut(var_no) {
  81. writable.extend(entry.keys());
  82. }
  83. }
  84. apply_transfers(&block.transfers[instr_no], vars, writable);
  85. }
  86. // These instructions are fine with vectors
  87. Instr::Set { .. }
  88. | Instr::Nop
  89. | Instr::ReturnCode { .. }
  90. | Instr::Branch { .. }
  91. | Instr::BranchCond { .. }
  92. | Instr::Switch { .. }
  93. | Instr::PopMemory { .. }
  94. | Instr::LoadStorage { .. }
  95. | Instr::SetStorage { .. }
  96. | Instr::ClearStorage { .. }
  97. | Instr::SetStorageBytes { .. }
  98. | Instr::PushStorage { .. }
  99. | Instr::PopStorage { .. }
  100. | Instr::SelfDestruct { .. }
  101. | Instr::EmitEvent { .. }
  102. | Instr::AbiDecode { .. }
  103. | Instr::ExternalCall { .. }
  104. | Instr::Constructor { .. }
  105. | Instr::Unreachable
  106. | Instr::Print { .. }
  107. | Instr::AssertFailure { .. }
  108. | Instr::ReturnData { .. }
  109. | Instr::ValueTransfer { .. } => {
  110. apply_transfers(&block.transfers[instr_no], vars, writable);
  111. }
  112. }
  113. }
  114. }
  115. fn apply_transfers(
  116. transfers: &[Transfer],
  117. vars: &mut IndexMap<usize, IndexMap<Def, bool>>,
  118. writable: &mut HashSet<Def>,
  119. ) {
  120. for transfer in transfers {
  121. match transfer {
  122. Transfer::Kill { var_no } => {
  123. vars.remove(var_no);
  124. }
  125. Transfer::Mod { var_no } => {
  126. if let Some(entry) = vars.get_mut(var_no) {
  127. for e in entry.values_mut() {
  128. *e = true;
  129. }
  130. writable.extend(entry.keys());
  131. }
  132. }
  133. Transfer::Copy { var_no, src } => {
  134. if let Some(defs) = vars.get(src) {
  135. let defs = defs.clone();
  136. vars.insert(*var_no, defs);
  137. }
  138. }
  139. Transfer::Gen { var_no, def } => {
  140. if let Some(entry) = vars.get_mut(var_no) {
  141. entry.insert(*def, false);
  142. } else {
  143. let mut v = IndexMap::new();
  144. v.insert(*def, false);
  145. vars.insert(*var_no, v);
  146. }
  147. }
  148. }
  149. }
  150. }
  151. fn update_vectors_to_slice(
  152. writable: &HashSet<Def>,
  153. cfg: &mut ControlFlowGraph,
  154. ns: &mut Namespace,
  155. ) {
  156. let mut defs_to_be_updated: HashSet<Def> = HashSet::new();
  157. for block_no in 0..cfg.blocks.len() {
  158. for instr_no in 0..cfg.blocks[block_no].instr.len() {
  159. if let Instr::Set {
  160. expr: Expression::AllocDynamicArray(..),
  161. ..
  162. } = &cfg.blocks[block_no].instr[instr_no].1
  163. {
  164. let cur = Def {
  165. block_no,
  166. instr_no,
  167. assignment_no: 0,
  168. };
  169. if !writable.contains(&cur) {
  170. defs_to_be_updated.insert(cur);
  171. }
  172. }
  173. }
  174. }
  175. for block_no in 0..cfg.blocks.len() {
  176. if let Some(phis) = &cfg.blocks[block_no].phis {
  177. for phi in phis {
  178. // if any of the defs is not going to be updated ...
  179. // note that unreachable blocks do not have reaching defs calculated
  180. if cfg.blocks[block_no].defs.contains_key(phi)
  181. && cfg.blocks[block_no].defs[phi]
  182. .iter()
  183. .any(|(def, _)| !defs_to_be_updated.contains(def))
  184. {
  185. // don't update any of them
  186. for (def, _) in &cfg.blocks[block_no].defs[phi] {
  187. defs_to_be_updated.remove(def);
  188. }
  189. }
  190. }
  191. }
  192. }
  193. for def in defs_to_be_updated {
  194. if let Instr::Set {
  195. loc,
  196. res,
  197. expr: Expression::AllocDynamicArray(_, _, len, Some(bs)),
  198. } = &cfg.blocks[def.block_no].instr[def.instr_no].1
  199. {
  200. let res = *res;
  201. cfg.blocks[def.block_no].instr[def.instr_no].1 = Instr::Set {
  202. loc: *loc,
  203. res,
  204. expr: Expression::AllocDynamicArray(
  205. *loc,
  206. Type::Slice(Box::new(Type::Bytes(1))),
  207. len.clone(),
  208. Some(bs.clone()),
  209. ),
  210. };
  211. if let ASTFunction::SolidityFunction(function_no) = cfg.function_no {
  212. if let Some(var) = ns.functions[function_no].symtable.vars.get_mut(&res) {
  213. var.slice = true;
  214. }
  215. }
  216. }
  217. }
  218. }