generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 135
Make --gen-c-runnable produce runnable C code
#334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
danielsn
merged 82 commits into
model-checking:main-154-2021-08-17
from
vecchiot-aws:gen-c-transformer
Aug 20, 2021
Merged
Changes from all commits
Commits
Show all changes
82 commits
Select commit
Hold shift + click to select a range
c1002a8
Added gen-c transformer.
vecchiot-aws e585575
Add --gen-c-readable flag
vecchiot-aws 5fe1784
Added extra gen-c support.
vecchiot-aws 033cc25
temporary commit/
vecchiot-aws 795e946
Add non_det functions to symbol table.
vecchiot-aws c5e04b0
Fix merge issues and compilation warnings.
vecchiot-aws e209c68
Force normalize_identifier to be injective.
vecchiot-aws b54cd12
Prevent padding from producing unused nondet function calls.
vecchiot-aws 1f59a96
Remove extra files.
vecchiot-aws 7b89303
Fix missing extern functions (translate to nondet).
vecchiot-aws c3d9bc4
Fixed implies operator not existing in C.
vecchiot-aws 4467f73
Moved removal of macros to after gotoc to avoid missing function error.
vecchiot-aws af681e2
Added __CPROVER_atomic_begin/end to gen_c library.
vecchiot-aws 104a33c
Add default to illegal identifiers.
vecchiot-aws 237e2f0
Add powi and powif to gen_c library.
vecchiot-aws a017493
Add POINTER_OBJECT macro.
vecchiot-aws 8ad60c1
Fix illegal default identifier.
vecchiot-aws 64ac31d
Fixed byte_extract_little_endian macro.
vecchiot-aws 011d288
Add c-lib to gen-c-runnable and dry_run to gen-c postprocess.
vecchiot-aws 1996c3e
Fix issue with name mapping memory, and don't remove '-' from 'tag-...'
vecchiot-aws 39a6f97
Fix u128 constants not being compilable.
vecchiot-aws 2c4fa0b
Add --gen-c-runnable back in after rebase.
vecchiot-aws 05a1f31
Fixed issue with tag- appearing in identifiers that weren't structs.
vecchiot-aws bded814
Fix SIMD vector access.
vecchiot-aws 231d27c
Fix generation of nondet functions with empty return type.
vecchiot-aws cc779b9
Add gen-c-runnable flag to cargo rmc, and rearrange scripts a bit.
vecchiot-aws 95af961
Add purpose flags.
vecchiot-aws bd2e650
Fix issue with extern functions having no return value.
vecchiot-aws c60b228
Fix issue with extern functions returning void.
vecchiot-aws 53801b0
Fix insert position for include.
vecchiot-aws a1e3083
Add sputc to list of removals.
vecchiot-aws 47ddf49
Initialize missing extern statics to nondet.
vecchiot-aws 0ef69a3
Change transformers to take mutable reference to self.
vecchiot-aws 6faa384
Remove statics.
vecchiot-aws b8523b2
Actually remember used names.
vecchiot-aws 9fc264b
Create owned getters for maps.
vecchiot-aws e5f0c56
Restructure gen-c transformer into three parts.
vecchiot-aws 220f265
Fixup documentation.
vecchiot-aws 9da4405
Fix bug with multiple missing parameter identifiers of same type.
vecchiot-aws 5de610c
Handle return type being empty.
vecchiot-aws 65275d0
Simplify logic of generating default values in non_det functions.
vecchiot-aws a5e9c8d
Revert accidental replacement.
vecchiot-aws 1d714ee
Simplify logic of generating default bodies for extern functions.
vecchiot-aws 8e45389
Correctly handle when no main function present.
vecchiot-aws 9566d1b
Minor comments and formatting.
vecchiot-aws 6022a1b
Add assert to avoid nondets returning empty.
vecchiot-aws fde17e4
Fixed bug with generated statics not being global.
vecchiot-aws 8e827c9
Fix issue with parameter names matching local variable names.
vecchiot-aws 396a4ed
Update type_to_string to be injective.
vecchiot-aws b5f54b0
Add docstring.
vecchiot-aws 5ab65a2
Fix short-circuiting issue with implies.
vecchiot-aws ccfd664
Clean up transform_symbol.
vecchiot-aws 4e792ec
Fix transforming bigints to use bit shifting.
vecchiot-aws 6059b04
Add test for bigints.
vecchiot-aws 1f77a84
Cleanup nondet transformer.
vecchiot-aws ad69d90
Cleanup name transformer.
vecchiot-aws a013a4d
Cleanup gen_c_lib
vecchiot-aws 715763c
Use binop constructor.
vecchiot-aws e4ace26
Move transforming 'main' to 'main_' into transform_symbol.
vecchiot-aws 3ab1884
Move type_to_string into typ.rs
vecchiot-aws 1b0b53d
Add is_c_integer method to Type.
vecchiot-aws d76983b
Clean up bignum_to_expr
vecchiot-aws 4c7df7d
Clean up some expr_transformer things.
vecchiot-aws eda36d6
Add pseudocode for SIMD transformation.
vecchiot-aws 4a8a111
Clarify remembering mapped names is for correctness, not just optimiz…
vecchiot-aws b5c90bb
Add clarification for used_names and mapped_names.
vecchiot-aws a27b6bc
Add issue for handling all reserved C names.
vecchiot-aws 6f0bd09
Add exapmle for transform_expr_nondet.
vecchiot-aws 3631f83
Add example for why we need to ignore padding in nondet transformer.
vecchiot-aws 7dddb2c
Add note that order matters to passes.rs
vecchiot-aws 68a4a99
Cleanup some stuff in gen_c_lib.c
vecchiot-aws acf6338
Switch to not use stcmp.
vecchiot-aws 8e45a7b
Change goto-instrument to directly pass in output file.
vecchiot-aws e618e35
Added examples to Type.to_identifier for code and variadic_code.
vecchiot-aws b2c8767
Add documentation to README.
vecchiot-aws 6480d3b
Replace match with if let.
vecchiot-aws 16c975b
Change .not().not() to cast to bool.
vecchiot-aws 084eb28
-Create tracking issue for SIMD vector indexing.
vecchiot-aws 6641afe
Switch overflow to use builtin overflow check functions.
vecchiot-aws 5392324
Fix compiler warnings.
vecchiot-aws 769215d
Switch imports to be absolute.
vecchiot-aws 5a8ce3f
Merge branch 'main-154-2021-08-17' into gen-c-transformer
danielsn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
268 changes: 268 additions & 0 deletions
268
...llvm/src/gotoc/cbmc/goto_program/symtab_transformer/gen_c_transformer/expr_transformer.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,268 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
|
||
| use std::ops::{BitAnd, Shl, Shr}; | ||
|
|
||
| use super::super::Transformer; | ||
| use crate::gotoc::cbmc::goto_program::{ | ||
| BinaryOperand, CIntType, Expr, Location, Parameter, Stmt, Symbol, SymbolTable, SymbolValues, | ||
| Type, | ||
| }; | ||
| use num::bigint::BigInt; | ||
| use rustc_data_structures::fx::FxHashMap; | ||
|
|
||
| /// Create an expr from an int constant using only values <= u64::MAX; | ||
| /// this is needed because gcc allows 128 bit int variables, but not 128 bit constants | ||
| fn bignum_to_expr(num: &BigInt, typ: &Type) -> Expr { | ||
| // CInteger types should already be valid in C | ||
| if typ.is_c_integer() { | ||
| return Expr::int_constant(num.clone(), typ.clone()); | ||
| } | ||
|
|
||
| // Only need to handle type wider than 64 bits | ||
| if let Some(width) = typ.width() { | ||
| if width <= 64 { | ||
| return Expr::int_constant(num.clone(), typ.clone()); | ||
| } | ||
| } | ||
|
|
||
| // Only types that should be left are i128 and u128 | ||
| assert_eq!(typ.width(), Some(128), "Unexpected int width: {:?}", typ.width()); | ||
|
|
||
| // Work with unsigned ints, and cast to original type at end | ||
| let unsigned_typ = Type::unsigned_int(128); | ||
|
|
||
| // To transform a 128 bit num, we break it into two 64 bit nums | ||
|
|
||
| // left_mask = 11..1100..00 (64 1's followed by 64 0's) | ||
| // left_mask = 00..0011..11 (64 0's followed by 64 1's) | ||
| let left_mask = BigInt::from(u64::MAX).shl(64); | ||
| let right_mask = BigInt::from(u64::MAX); | ||
|
|
||
| // Construct the two 64 bit ints such that | ||
| // num = (left_half << 64) | right_half | ||
| // = (left_half * 2^64) + right_half | ||
| let left_half = { | ||
| // Split into two parts to help type inference | ||
| let temp: BigInt = num.bitand(left_mask); | ||
| temp.shr(64) | ||
| }; | ||
| let right_half = num.bitand(right_mask); | ||
|
|
||
| // Create CBMC constants for the left and right halfs | ||
| let left_constant = Expr::int_constant(left_half, unsigned_typ.clone()); | ||
| let right_constant = Expr::int_constant(right_half, unsigned_typ); | ||
|
|
||
| // Construct CBMC expression: (typ) ((left << 64) | right) | ||
| left_constant | ||
| .shl(Expr::int_constant(64, Type::c_int())) | ||
| .bitor(right_constant) | ||
| .cast_to(typ.clone()) | ||
| } | ||
|
|
||
| /// Struct for handling the expression replacement transformations for --gen-c-runnable. | ||
| pub struct ExprTransformer { | ||
| new_symbol_table: SymbolTable, | ||
| /// The `empty_statics` field is used to track extern static variables; | ||
| /// when such a symbol is encountered, we add it to this map; | ||
| /// in postprocessing, we initialize each of these variables | ||
| /// with a default value to emphasize that these are externally defined. | ||
| empty_statics: FxHashMap<String, Expr>, | ||
vecchiot-aws marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| impl ExprTransformer { | ||
| /// Replace expressions which lead to invalid C with alternatives. | ||
| pub fn transform(original_symbol_table: &SymbolTable) -> SymbolTable { | ||
| let new_symbol_table = SymbolTable::new(original_symbol_table.machine_model().clone()); | ||
| ExprTransformer { new_symbol_table, empty_statics: FxHashMap::default() } | ||
| .transform_symbol_table(original_symbol_table) | ||
| } | ||
|
|
||
| /// Extract `empty_statics` map for final processing. | ||
| fn empty_statics_owned(&mut self) -> FxHashMap<String, Expr> { | ||
| std::mem::replace(&mut self.empty_statics, FxHashMap::default()) | ||
| } | ||
|
|
||
| /// Add identifier to a transformed parameter if it's missing; | ||
| /// necessary when function wasn't originally a definition, e.g. extern functions, | ||
| /// so that we can give them a function body. | ||
| fn add_parameter_identifier(&mut self, parameter: &Parameter) -> Parameter { | ||
| if parameter.identifier().is_some() { | ||
| parameter.clone() | ||
| } else { | ||
| let name = format!("__{}", parameter.typ().to_identifier()); | ||
| let parameter_sym = self.mut_symbol_table().ensure(&name, |_symtab, name| { | ||
| Symbol::variable( | ||
| name.to_string(), | ||
| name.to_string(), | ||
| parameter.typ().clone(), | ||
| Location::none(), | ||
| ) | ||
| }); | ||
| parameter_sym.to_function_parameter() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Transformer for ExprTransformer { | ||
| /// Get reference to symbol table. | ||
| fn symbol_table(&self) -> &SymbolTable { | ||
| &self.new_symbol_table | ||
| } | ||
|
|
||
| /// Get mutable reference to symbol table. | ||
| fn mut_symbol_table(&mut self) -> &mut SymbolTable { | ||
| &mut self.new_symbol_table | ||
| } | ||
|
|
||
| /// Get owned symbol table. | ||
| fn extract_symbol_table(self) -> SymbolTable { | ||
| self.new_symbol_table | ||
| } | ||
|
|
||
| /// Translate Implies into Or/Not. | ||
| fn transform_expr_bin_op( | ||
| &mut self, | ||
| _typ: &Type, | ||
| op: &BinaryOperand, | ||
| lhs: &Expr, | ||
| rhs: &Expr, | ||
| ) -> Expr { | ||
| let lhs = self.transform_expr(lhs); | ||
| let rhs = self.transform_expr(rhs); | ||
|
|
||
| match op { | ||
vecchiot-aws marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| BinaryOperand::Implies => lhs.not().bitor(rhs).cast_to(Type::bool()), | ||
| _ => lhs.binop(*op, rhs), | ||
| } | ||
| } | ||
|
|
||
| /// Prevent error for too large constants with u128. | ||
| fn transform_expr_int_constant(&mut self, typ: &Type, value: &BigInt) -> Expr { | ||
| let transformed_typ = self.transform_type(typ); | ||
| bignum_to_expr(value, &transformed_typ) | ||
| } | ||
|
|
||
| /// When indexing into a SIMD vector, cast to a pointer first to make legal indexing in C. | ||
vecchiot-aws marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// `typ __attribute__((vector_size (size * sizeof(typ)))) var;` | ||
| /// `((typ*) &var)[index]` | ||
vecchiot-aws marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// Tracking issue: https://github.com/model-checking/rmc/issues/444 | ||
| fn transform_expr_index(&mut self, _typ: &Type, array: &Expr, index: &Expr) -> Expr { | ||
| let transformed_array = self.transform_expr(array); | ||
| let transformed_index = self.transform_expr(index); | ||
| if transformed_array.typ().is_vector() { | ||
| let base_type = transformed_array.typ().base_type().unwrap().clone(); | ||
| transformed_array.address_of().cast_to(base_type.to_pointer()).index(transformed_index) | ||
| } else { | ||
| transformed_array.index(transformed_index) | ||
| } | ||
| } | ||
|
|
||
| /// Replace `extern` functions and values with `nondet` so linker doesn't break. | ||
| fn transform_symbol(&mut self, symbol: &Symbol) -> Symbol { | ||
| let mut new_symbol = symbol.clone(); | ||
|
|
||
| if symbol.is_extern { | ||
| if symbol.typ.is_code() || symbol.typ.is_variadic_code() { | ||
| // Replace `extern` function with one which returns `nondet` | ||
| assert!(symbol.value.is_none(), "Extern function should have no body."); | ||
|
|
||
| let transformed_typ = self.transform_type(&symbol.typ); | ||
|
|
||
| // Fill missing parameter names with dummy name | ||
| let parameters = transformed_typ | ||
| .parameters() | ||
| .unwrap() | ||
| .iter() | ||
| .map(|parameter| self.add_parameter_identifier(parameter)) | ||
| .collect(); | ||
| let ret_typ = transformed_typ.return_type().unwrap().clone(); | ||
| let new_typ = if transformed_typ.is_code() { | ||
| Type::code(parameters, ret_typ.clone()) | ||
| } else { | ||
| Type::variadic_code(parameters, ret_typ.clone()) | ||
| }; | ||
|
|
||
| // Create body, which returns nondet | ||
| let ret_e = if ret_typ.is_empty() { None } else { Some(Expr::nondet(ret_typ)) }; | ||
| let body = Stmt::ret(ret_e, Location::none()); | ||
| let new_value = SymbolValues::Stmt(body); | ||
|
|
||
| new_symbol.is_extern = false; | ||
| new_symbol.typ = new_typ; | ||
| new_symbol.value = new_value; | ||
| } else { | ||
| // Replace `extern static`s and initialize in `main` | ||
| assert!( | ||
| symbol.is_static_lifetime, | ||
| "Extern objects that aren't functions should be static variables." | ||
| ); | ||
| let new_typ = self.transform_type(&symbol.typ); | ||
| self.empty_statics.insert(symbol.name.clone(), Expr::nondet(new_typ.clone())); | ||
|
|
||
| // Symbol is no longer extern | ||
| new_symbol.is_extern = false; | ||
|
|
||
| // Set location to none so that it is a global static | ||
| new_symbol.location = Location::none(); | ||
|
|
||
| new_symbol.typ = new_typ; | ||
| new_symbol.value = SymbolValues::None; | ||
| } | ||
| } else if &symbol.name == "main" { | ||
| // Replace `main` with `main_` since it has the wrong return type | ||
| new_symbol.name = "main_".to_string(); | ||
| new_symbol.base_name = Some("main_".to_string()); | ||
| new_symbol.pretty_name = Some("main_".to_string()); | ||
|
|
||
| let new_typ = self.transform_type(&symbol.typ); | ||
| let new_value = self.transform_value(&symbol.value); | ||
|
|
||
| new_symbol.typ = new_typ; | ||
| new_symbol.value = new_value; | ||
| } else { | ||
| // Handle all other symbols normally | ||
| let new_typ = self.transform_type(&symbol.typ); | ||
| let new_value = self.transform_value(&symbol.value); | ||
| new_symbol.typ = new_typ; | ||
| new_symbol.value = new_value; | ||
| } | ||
|
|
||
| new_symbol | ||
| } | ||
|
|
||
| /// Move `main` to `main_`, and create a wrapper `main` to initialize statics and return `int`. | ||
vecchiot-aws marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| fn postprocess(&mut self) { | ||
| // The body of the new `main` function | ||
| let mut main_body = Vec::new(); | ||
|
|
||
| // Initialize statics | ||
| for (name, value) in self.empty_statics_owned() { | ||
| let sym_expr = Expr::symbol_expression(name, value.typ().clone()); | ||
| main_body.push(Stmt::assign(sym_expr, value, Location::none())); | ||
| } | ||
|
|
||
| // `main_();`, if it is present | ||
| if let Some(main_) = self.symbol_table().lookup("main_") { | ||
| main_body | ||
| .push(Stmt::code_expression(main_.to_expr().call(Vec::new()), Location::none())); | ||
| } | ||
|
|
||
| // `return 0;` | ||
| main_body.push(Stmt::ret( | ||
| Some(Expr::int_constant(0, Type::CInteger(CIntType::Int))), | ||
| Location::none(), | ||
| )); | ||
|
|
||
| // Create `main` symbol | ||
| let new_main = Symbol::function( | ||
| "main", | ||
| Type::code(Vec::new(), Type::CInteger(CIntType::Int)), | ||
| Some(Stmt::block(main_body, Location::none())), | ||
| Some("main".to_string()), | ||
| Location::none(), | ||
| ); | ||
|
|
||
| self.mut_symbol_table().insert(new_main); | ||
| } | ||
| } | ||
10 changes: 10 additions & 0 deletions
10
...ustc_codegen_llvm/src/gotoc/cbmc/goto_program/symtab_transformer/gen_c_transformer/mod.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
|
||
| mod expr_transformer; | ||
| mod name_transformer; | ||
| mod nondet_transformer; | ||
|
|
||
| pub use expr_transformer::ExprTransformer; | ||
| pub use name_transformer::NameTransformer; | ||
| pub use nondet_transformer::NondetTransformer; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.