1
- use std:: collections:: HashMap ;
1
+ use std:: { collections:: HashMap , sync :: Arc } ;
2
2
3
3
use acvm:: acir:: circuit:: ErrorSelector ;
4
4
5
5
use crate :: ssa:: {
6
6
function_builder:: FunctionBuilder ,
7
7
ir:: {
8
8
basic_block:: BasicBlockId ,
9
+ call_stack:: CallStackId ,
10
+ dfg:: GlobalsGraph ,
9
11
function:: { Function , FunctionId } ,
10
- instruction:: ConstrainError ,
12
+ instruction:: { ConstrainError , Instruction } ,
11
13
value:: ValueId ,
12
14
} ,
13
15
} ;
14
16
15
17
use super :: {
16
- ast:: AssertMessage , Identifier , ParsedBlock , ParsedFunction , ParsedInstruction , ParsedSsa ,
17
- ParsedTerminator , ParsedValue , RuntimeType , Ssa , SsaError ,
18
+ ast:: AssertMessage , Identifier , ParsedBlock , ParsedFunction , ParsedGlobal , ParsedGlobalValue ,
19
+ ParsedInstruction , ParsedSsa , ParsedTerminator , ParsedValue , RuntimeType , Ssa , SsaError , Type ,
18
20
} ;
19
21
20
22
impl ParsedSsa {
@@ -39,6 +41,17 @@ struct Translator {
39
41
/// will recreate the SSA step by step, which can result in a new ID layout.
40
42
variables : HashMap < FunctionId , HashMap < String , ValueId > > ,
41
43
44
+ /// The function that will hold the actual SSA globals.
45
+ globals_function : Function ,
46
+
47
+ /// The types of globals in the parsed SSA, in the order they were defined.
48
+ global_types : Vec < Type > ,
49
+
50
+ /// Maps names (e.g. "g0") in the parsed SSA to global IDs.
51
+ global_values : HashMap < String , ValueId > ,
52
+
53
+ globals_graph : Arc < GlobalsGraph > ,
54
+
42
55
error_selector_counter : u64 ,
43
56
}
44
57
@@ -74,13 +87,26 @@ impl Translator {
74
87
functions. insert ( function. internal_name . clone ( ) , function_id) ;
75
88
}
76
89
90
+ // Does not matter what ID we use here.
91
+ let globals = Function :: new ( "globals" . to_owned ( ) , main_id) ;
92
+
77
93
let mut translator = Self {
78
94
builder,
79
95
functions,
80
96
variables : HashMap :: new ( ) ,
81
97
blocks : HashMap :: new ( ) ,
98
+ globals_function : globals,
99
+ global_types : Vec :: new ( ) ,
100
+ global_values : HashMap :: new ( ) ,
101
+ globals_graph : Arc :: new ( GlobalsGraph :: default ( ) ) ,
82
102
error_selector_counter : 0 ,
83
103
} ;
104
+
105
+ translator. translate_globals ( std:: mem:: take ( & mut parsed_ssa. globals ) ) ?;
106
+
107
+ translator. globals_graph =
108
+ Arc :: new ( GlobalsGraph :: from_dfg ( translator. globals_function . dfg . clone ( ) ) ) ;
109
+
84
110
translator. translate_function_body ( main_function) ?;
85
111
86
112
Ok ( translator)
@@ -103,6 +129,8 @@ impl Translator {
103
129
}
104
130
105
131
fn translate_function_body ( & mut self , function : ParsedFunction ) -> Result < ( ) , SsaError > {
132
+ self . builder . set_globals ( self . globals_graph . clone ( ) ) ;
133
+
106
134
// First define all blocks so that they are known (a block might jump to a block that comes next)
107
135
for ( index, block) in function. blocks . iter ( ) . enumerate ( ) {
108
136
// The first block is the entry block and it was automatically created by the builder
@@ -297,8 +325,8 @@ impl Translator {
297
325
298
326
fn translate_value ( & mut self , value : ParsedValue ) -> Result < ValueId , SsaError > {
299
327
match value {
300
- ParsedValue :: NumericConstant { constant, typ } => {
301
- Ok ( self . builder . numeric_constant ( constant, typ. unwrap_numeric ( ) ) )
328
+ ParsedValue :: NumericConstant ( constant) => {
329
+ Ok ( self . builder . numeric_constant ( constant. value , constant . typ . unwrap_numeric ( ) ) )
302
330
}
303
331
ParsedValue :: Variable ( identifier) => self . lookup_variable ( & identifier) . or_else ( |e| {
304
332
self . lookup_function ( & identifier)
@@ -311,6 +339,45 @@ impl Translator {
311
339
}
312
340
}
313
341
342
+ fn translate_globals ( & mut self , globals : Vec < ParsedGlobal > ) -> Result < ( ) , SsaError > {
343
+ for global in globals {
344
+ self . translate_global ( global) ?;
345
+ }
346
+ Ok ( ( ) )
347
+ }
348
+
349
+ fn translate_global ( & mut self , global : ParsedGlobal ) -> Result < ( ) , SsaError > {
350
+ let value_id = match global. value {
351
+ ParsedGlobalValue :: NumericConstant ( constant) => self
352
+ . globals_function
353
+ . dfg
354
+ . make_constant ( constant. value , constant. typ . unwrap_numeric ( ) ) ,
355
+ ParsedGlobalValue :: MakeArray ( make_array) => {
356
+ let mut elements = im:: Vector :: new ( ) ;
357
+ for element in make_array. elements {
358
+ let element_id = match element {
359
+ ParsedValue :: NumericConstant ( constant) => self
360
+ . globals_function
361
+ . dfg
362
+ . make_constant ( constant. value , constant. typ . unwrap_numeric ( ) ) ,
363
+ ParsedValue :: Variable ( identifier) => self . lookup_global ( identifier) ?,
364
+ } ;
365
+ elements. push_back ( element_id) ;
366
+ }
367
+
368
+ let instruction = Instruction :: MakeArray { elements, typ : make_array. typ . clone ( ) } ;
369
+ let block = self . globals_function . entry_block ( ) ;
370
+ let call_stack = CallStackId :: root ( ) ;
371
+ self . globals_function
372
+ . dfg
373
+ . insert_instruction_and_results ( instruction, block, None , call_stack)
374
+ . first ( )
375
+ }
376
+ } ;
377
+
378
+ self . define_global ( global. name , value_id)
379
+ }
380
+
314
381
fn define_variable (
315
382
& mut self ,
316
383
identifier : Identifier ,
@@ -329,13 +396,40 @@ impl Translator {
329
396
}
330
397
331
398
fn lookup_variable ( & mut self , identifier : & Identifier ) -> Result < ValueId , SsaError > {
332
- if let Some ( value_id) = self . variables [ & self . current_function_id ( ) ] . get ( & identifier. name ) {
399
+ if let Some ( value_id) = self
400
+ . variables
401
+ . get ( & self . current_function_id ( ) )
402
+ . and_then ( |hash| hash. get ( & identifier. name ) )
403
+ {
404
+ Ok ( * value_id)
405
+ } else if let Some ( value_id) = self . global_values . get ( & identifier. name ) {
333
406
Ok ( * value_id)
334
407
} else {
335
408
Err ( SsaError :: UnknownVariable ( identifier. clone ( ) ) )
336
409
}
337
410
}
338
411
412
+ fn define_global ( & mut self , identifier : Identifier , value_id : ValueId ) -> Result < ( ) , SsaError > {
413
+ if self . global_values . contains_key ( & identifier. name ) {
414
+ return Err ( SsaError :: GlobalAlreadyDefined ( identifier) ) ;
415
+ }
416
+
417
+ self . global_values . insert ( identifier. name , value_id) ;
418
+
419
+ let typ = self . globals_function . dfg . type_of_value ( value_id) ;
420
+ self . global_types . push ( typ) ;
421
+
422
+ Ok ( ( ) )
423
+ }
424
+
425
+ fn lookup_global ( & mut self , identifier : Identifier ) -> Result < ValueId , SsaError > {
426
+ if let Some ( value_id) = self . global_values . get ( & identifier. name ) {
427
+ Ok ( * value_id)
428
+ } else {
429
+ Err ( SsaError :: UnknownGlobal ( identifier) )
430
+ }
431
+ }
432
+
339
433
fn lookup_block ( & mut self , identifier : & Identifier ) -> Result < BasicBlockId , SsaError > {
340
434
if let Some ( block_id) = self . blocks [ & self . current_function_id ( ) ] . get ( & identifier. name ) {
341
435
Ok ( * block_id)
@@ -354,13 +448,14 @@ impl Translator {
354
448
355
449
fn finish ( self ) -> Ssa {
356
450
let mut ssa = self . builder . finish ( ) ;
451
+ ssa. globals = self . globals_function ;
452
+
357
453
// Normalize the IDs so we have a better chance of matching the SSA we parsed
358
454
// after the step-by-step reconstruction done during translation. This assumes
359
455
// that the SSA we parsed was printed by the `SsaBuilder`, which normalizes
360
456
// before each print.
361
457
ssa. normalize_ids ( ) ;
362
- // Does not matter what ID we use here.
363
- ssa. globals = Function :: new ( "globals" . to_owned ( ) , ssa. main_id ) ;
458
+
364
459
ssa
365
460
}
366
461
0 commit comments