Issue homework 2: irgen

This commit is contained in:
Jeehoon Kang
2020-04-01 10:54:46 +09:00
parent 2a5a5e71ed
commit 93a1d767a5
18 changed files with 1009 additions and 588 deletions

87
Cargo.lock generated
View File

@@ -13,29 +13,34 @@ name = "atty"
version = "0.2.14" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.45" version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "backtrace-sys" name = "backtrace-sys"
version = "0.1.34" version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -78,7 +83,7 @@ name = "failure"
version = "0.1.7" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -87,9 +92,9 @@ name = "failure_derive"
version = "0.1.7" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -99,16 +104,16 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.8" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -126,20 +131,37 @@ dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lang-c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lang-c 0.8.0 (git+https://github.com/kaist-cp/lang-c)",
"ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "lang-c" name = "lang-c"
version = "0.8.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/kaist-cp/lang-c#44687707f07fb8c5869936dfc549459ecb30d3be"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.67" version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num-traits"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ordered-float"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.6" version = "0.2.6"
@@ -147,7 +169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.9" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -158,7 +180,7 @@ name = "quote"
version = "1.0.3" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -167,7 +189,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -223,10 +245,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.16" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -236,9 +258,9 @@ name = "synstructure"
version = "0.12.3" version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -248,7 +270,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -310,8 +332,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [metadata]
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" "checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
"checksum backtrace-sys 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
@@ -320,12 +343,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" "checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" "checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
"checksum lang-c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "86efc420d5d7407655eb2ff1a77d7c81463307f1b204c886f7608cc2e6506d55" "checksum lang-c 0.8.0 (git+https://github.com/kaist-cp/lang-c)" = "<none>"
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" "checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" "checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
@@ -335,7 +360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"

View File

@@ -25,7 +25,9 @@ path = "bin/fuzz.rs"
[dependencies] [dependencies]
clap = { version = "2.33.0", features = ["yaml"] } clap = { version = "2.33.0", features = ["yaml"] }
lang-c = "0.8.0" # TODO: use crates.io version when https://github.com/vickenty/lang-c/pull/16 is merged
lang-c = { git = "https://github.com/kaist-cp/lang-c" }
itertools = "0.9.0" itertools = "0.9.0"
failure = "0.1.7" failure = "0.1.7"
tempfile = "3.1.0" tempfile = "3.1.0"
ordered-float = "1.0"

9
examples/array.c Normal file
View File

@@ -0,0 +1,9 @@
int sum(int len, int p[2][3]) {
return 0;
}
int main() {
int a[2][3];
return 0;
}

View File

@@ -1,4 +1,4 @@
int f(int i, int const a[const i]) { int f(int i, int const a[i]) {
int temp = 0; int temp = 0;
const float temp2 = 0.f, temp3 = 0.f; const float temp2 = 0.f, temp3 = 0.f;
temp = sizeof(unsigned char); temp = sizeof(unsigned char);

10
examples/test.c Normal file
View File

@@ -0,0 +1,10 @@
int main() {
long int l = 1;
long l2 = 2;
short int s = 3;
short s2 = 4;
int i = 5;
char c = 6;
return l + l2 + s + s2 + i + c;
}

10
examples/typedef.c Normal file
View File

@@ -0,0 +1,10 @@
typedef int i32_t;
typedef i32_t* p_i32_t;
int main() {
i32_t a = 0;
p_i32_t const b = &a;
*b = 1;
return *b;
}

View File

@@ -76,7 +76,20 @@ impl AssertSupported for TranslationUnit {
impl AssertSupported for ExternalDeclaration { impl AssertSupported for ExternalDeclaration {
fn assert_supported(&self) { fn assert_supported(&self) {
match self { match self {
Self::Declaration(decl) => decl.assert_supported(), Self::Declaration(decl) => {
for spec in &decl.node.specifiers {
if let DeclarationSpecifier::StorageClass(storage_class) = &spec.node {
// `typedef` is allowed only when it is used in the external declaration.
if StorageClassSpecifier::Typedef != storage_class.node {
panic!("`StorageClassifier` other than `Typedef`")
}
} else {
spec.assert_supported();
}
}
decl.node.declarators.assert_supported();
}
Self::StaticAssert(_) => panic!("ExternalDeclaration::StaticAssert"), Self::StaticAssert(_) => panic!("ExternalDeclaration::StaticAssert"),
Self::FunctionDefinition(fdef) => fdef.assert_supported(), Self::FunctionDefinition(fdef) => fdef.assert_supported(),
} }
@@ -102,9 +115,7 @@ impl AssertSupported for FunctionDefinition {
impl AssertSupported for DeclarationSpecifier { impl AssertSupported for DeclarationSpecifier {
fn assert_supported(&self) { fn assert_supported(&self) {
match self { match self {
Self::StorageClass(storage_class_specifier) => { Self::StorageClass(_) => panic!("DeclarationSpecifier::StorageClass"),
storage_class_specifier.assert_supported()
}
Self::TypeSpecifier(type_specifier) => type_specifier.assert_supported(), Self::TypeSpecifier(type_specifier) => type_specifier.assert_supported(),
Self::TypeQualifier(type_qualifier) => type_qualifier.assert_supported(), Self::TypeQualifier(type_qualifier) => type_qualifier.assert_supported(),
Self::Function(_) => panic!("DeclarationSpecifier::Function"), Self::Function(_) => panic!("DeclarationSpecifier::Function"),
@@ -114,15 +125,6 @@ impl AssertSupported for DeclarationSpecifier {
} }
} }
impl AssertSupported for StorageClassSpecifier {
fn assert_supported(&self) {
match self {
Self::Typedef => (),
_ => panic!("StorageClassifier other than Typedef"),
}
}
}
impl AssertSupported for TypeSpecifier { impl AssertSupported for TypeSpecifier {
fn assert_supported(&self) { fn assert_supported(&self) {
match self { match self {
@@ -242,7 +244,11 @@ impl AssertSupported for PointerQualifier {
impl AssertSupported for ArrayDeclarator { impl AssertSupported for ArrayDeclarator {
fn assert_supported(&self) { fn assert_supported(&self) {
self.qualifiers.assert_supported(); // In C99, type qualifier(e.g., const) is allowed when
// array declarator is used as function parameter.
// However, KECC does not allow this feature because
// it complicates IR generating logic.
assert!(self.qualifiers.is_empty());
self.size.assert_supported(); self.size.assert_supported();
} }
} }

View File

@@ -1,12 +1,13 @@
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::ops::Deref; use core::ops::Deref;
use itertools::izip; use failure::Fail;
use lang_c::ast; use lang_c::ast;
use lang_c::span::Node; use lang_c::span::Node;
use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use failure::Fail; use crate::ir::*;
#[derive(Debug, PartialEq, Fail)] #[derive(Debug, PartialEq, Fail)]
pub enum DtypeError { pub enum DtypeError {
@@ -22,8 +23,11 @@ pub trait HasDtype {
#[derive(Default)] #[derive(Default)]
struct BaseDtype { struct BaseDtype {
scalar: Option<ast::TypeSpecifier>, scalar: Option<ast::TypeSpecifier>,
size_modifiers: Option<ast::TypeSpecifier>,
signed_option: Option<ast::TypeSpecifier>, signed_option: Option<ast::TypeSpecifier>,
typedef_name: Option<String>,
is_const: bool, is_const: bool,
is_typedef: bool,
} }
#[derive(Debug, PartialEq, Eq, Hash, Clone)] #[derive(Debug, PartialEq, Eq, Hash, Clone)]
@@ -52,9 +56,40 @@ pub enum Dtype {
ret: Box<Dtype>, ret: Box<Dtype>,
params: Vec<Dtype>, params: Vec<Dtype>,
}, },
Typedef {
name: String,
is_const: bool,
},
} }
impl BaseDtype { impl BaseDtype {
/// Apply `StorageClassSpecifier` to `BaseDtype`
///
/// let's say declaration is `typedef int i32_t;`, if `self` represents `int`
/// and `type_qualifier` represents `typedef`, `self` is transformed to
/// representing `typedef int` after function performs.
///
/// # Arguments
///
/// * `self` - Part that has been converted to 'BaseDtype' on the declaration
/// * `storage_class` - storage class requiring apply to 'self' immediately
///
#[inline]
fn apply_storage_class(
&mut self,
storage_class: &ast::StorageClassSpecifier,
) -> Result<(), DtypeError> {
match storage_class {
ast::StorageClassSpecifier::Typedef => {
// duplicate `typedef` is allowed
self.is_typedef = true;
}
_ => panic!("unsupported storage class"),
}
Ok(())
}
/// Apply `TypeSpecifier` to `BaseDtype` /// Apply `TypeSpecifier` to `BaseDtype`
/// ///
/// let's say declaration is `const int a;`, if `self` represents `int` /// let's say declaration is `const int a;`, if `self` represents `int`
@@ -81,9 +116,11 @@ impl BaseDtype {
self.signed_option = Some(type_specifier.clone()); self.signed_option = Some(type_specifier.clone());
} }
ast::TypeSpecifier::Void ast::TypeSpecifier::Void
| ast::TypeSpecifier::Bool
| ast::TypeSpecifier::Char | ast::TypeSpecifier::Char
| ast::TypeSpecifier::Int | ast::TypeSpecifier::Int
| ast::TypeSpecifier::Float => { | ast::TypeSpecifier::Float
| ast::TypeSpecifier::Double => {
if self.scalar.is_some() { if self.scalar.is_some() {
return Err(DtypeError::Misc { return Err(DtypeError::Misc {
message: "two or more scalar types in declaration specifiers".to_string(), message: "two or more scalar types in declaration specifiers".to_string(),
@@ -91,7 +128,23 @@ impl BaseDtype {
} }
self.scalar = Some(type_specifier.clone()); self.scalar = Some(type_specifier.clone());
} }
_ => todo!("support more like `double` in the future"), ast::TypeSpecifier::Short | ast::TypeSpecifier::Long => {
if self.size_modifiers.is_some() {
return Err(DtypeError::Misc {
message: "two or more size modifiers in declaration specifiers".to_string(),
});
}
self.size_modifiers = Some(type_specifier.clone());
}
ast::TypeSpecifier::TypedefName(identifier) => {
if self.typedef_name.is_some() {
return Err(DtypeError::Misc {
message: "two or more typedef names in declaration specifiers".to_string(),
});
}
self.typedef_name = Some(identifier.node.name.clone());
}
_ => todo!("apply_type_specifier: support {:?}", type_specifier),
} }
Ok(()) Ok(())
@@ -145,9 +198,8 @@ impl BaseDtype {
declaration_specifier: &ast::DeclarationSpecifier, declaration_specifier: &ast::DeclarationSpecifier,
) -> Result<(), DtypeError> { ) -> Result<(), DtypeError> {
match declaration_specifier { match declaration_specifier {
// TODO: `dtype` must be defined taking into account all specifier information. ast::DeclarationSpecifier::StorageClass(storage_class) => {
ast::DeclarationSpecifier::StorageClass(_storage_class_spec) => { self.apply_storage_class(&storage_class.node)?
todo!("analyze storage class specifier keyword to create correct `dtype`")
} }
ast::DeclarationSpecifier::TypeSpecifier(type_specifier) => { ast::DeclarationSpecifier::TypeSpecifier(type_specifier) => {
self.apply_type_specifier(&type_specifier.node)? self.apply_type_specifier(&type_specifier.node)?
@@ -221,48 +273,80 @@ impl TryFrom<BaseDtype> for Dtype {
/// # Example /// # Example
/// ///
/// For declaration is `const unsigned int * p`, `specifiers` is `const unsigned int`, /// For declaration is `const unsigned int * p`, `specifiers` is `const unsigned int`,
/// and the result is `Dtype::Int{ width: 32, is_signed: false, is_const: ture }` /// and the result is `Dtype::Int{ width: 4, is_signed: false, is_const: ture }`
fn try_from(spec: BaseDtype) -> Result<Self, DtypeError> { fn try_from(spec: BaseDtype) -> Result<Self, DtypeError> {
assert!( assert!(
!(spec.scalar.is_none() && spec.signed_option.is_none() && !spec.is_const), !(spec.scalar.is_none()
&& spec.size_modifiers.is_none()
&& spec.signed_option.is_none()
&& spec.typedef_name.is_none()
&& !spec.is_const),
"BaseDtype is empty" "BaseDtype is empty"
); );
// Creates `dtype` from scalar. let mut dtype = if let Some(name) = spec.typedef_name {
let mut dtype = if let Some(t) = spec.scalar { if spec.scalar.is_some() || spec.signed_option.is_some() {
match t { return Err(DtypeError::Misc {
ast::TypeSpecifier::Void => Self::unit(), message: "typedef' cannot be used with scalar type or signed option"
ast::TypeSpecifier::Unsigned | ast::TypeSpecifier::Signed => { .to_string(),
panic!("Signed option to scalar is not supported") });
}
ast::TypeSpecifier::Bool => Self::BOOL,
ast::TypeSpecifier::Char => Self::CHAR,
ast::TypeSpecifier::Short => Self::SHORT,
ast::TypeSpecifier::Int => Self::INT,
ast::TypeSpecifier::Long => Self::LONG,
ast::TypeSpecifier::Float => Self::FLOAT,
ast::TypeSpecifier::Double => Self::DOUBLE,
_ => panic!("Unsupported ast::TypeSpecifier"),
} }
} else {
Dtype::default()
};
// Applies signedness. Self::typedef(name)
if let Some(signed_option) = spec.signed_option { } else {
let is_signed = match signed_option { // Creates `dtype` from scalar.
ast::TypeSpecifier::Signed => true, let mut dtype = if let Some(t) = spec.scalar {
ast::TypeSpecifier::Unsigned => false, match t {
_ => panic!( ast::TypeSpecifier::Void => Self::unit(),
"`signed_option` must be `TypeSpecifier::Signed` or `TypeSpecifier::Unsigned`" ast::TypeSpecifier::Bool => Self::BOOL,
), ast::TypeSpecifier::Char => Self::CHAR,
ast::TypeSpecifier::Int => Self::INT,
ast::TypeSpecifier::Float => Self::FLOAT,
ast::TypeSpecifier::Double => Self::DOUBLE,
ast::TypeSpecifier::Unsigned | ast::TypeSpecifier::Signed => {
panic!("Signed option to scalar is not supported")
}
_ => panic!("Dtype::try_from::<BaseDtype>: {:?} is not a scalar type", t),
}
} else {
Self::default()
}; };
dtype = dtype.set_signed(is_signed); // Applies size modifier
} if let Some(size_modifiers) = spec.size_modifiers {
if dtype != Self::INT {
return Err(DtypeError::Misc {
message: "size modifier can only be used with `int`".to_string(),
});
}
dtype = match size_modifiers {
ast::TypeSpecifier::Short => Self::SHORT,
ast::TypeSpecifier::Long => Self::LONG,
_ => panic!(
"Dtype::try_from::<BaseDtype>: {:?} is not a size modifier",
size_modifiers
),
}
}
// Applies signedness.
if let Some(signed_option) = spec.signed_option {
let is_signed = match signed_option {
ast::TypeSpecifier::Signed => true,
ast::TypeSpecifier::Unsigned => false,
_ => panic!(
"Dtype::try_from::<BaseDtype>: {:?} is not a signed option",
signed_option
),
};
dtype = dtype.set_signed(is_signed);
}
dtype
};
// Applies constness.
assert!(!dtype.is_const());
dtype = dtype.set_const(spec.is_const); dtype = dtype.set_const(spec.is_const);
Ok(dtype) Ok(dtype)
@@ -296,25 +380,48 @@ impl TryFrom<&ast::ParameterDeclaration> for Dtype {
if let Some(declarator) = &parameter_decl.declarator { if let Some(declarator) = &parameter_decl.declarator {
dtype = dtype.with_ast_declarator(&declarator.node)?; dtype = dtype.with_ast_declarator(&declarator.node)?;
// A function call with an array argument performs array-to-pointer conversion.
// For this reason, when `declarator` is from function parameter declaration
// and `base_dtype` is `Dtype::Array`, `base_dtype` is transformed to pointer type.
// https://www.eskimo.com/~scs/cclass/notes/sx10f.html
if let Some(inner) = dtype.get_array_inner() {
dtype = Self::pointer(inner.clone());
}
} }
Ok(dtype) Ok(dtype)
} }
} }
impl Dtype { impl Dtype {
pub const BOOL: Self = Self::int(1); pub const BITS_OF_BYTE: usize = 8;
pub const CHAR: Self = Self::int(8); pub const SIZE_OF_BYTE: usize = 1;
pub const SHORT: Self = Self::int(16);
pub const INT: Self = Self::int(32);
pub const LONG: Self = Self::int(64);
pub const LONGLONG: Self = Self::int(64);
pub const FLOAT: Self = Self::float(32);
pub const DOUBLE: Self = Self::float(64);
const WIDTH_OF_BYTE: usize = 8;
// TODO: consider architecture dependency in the future // TODO: consider architecture dependency in the future
const WIDTH_OF_POINTER: usize = 32; pub const SIZE_OF_POINTER: usize = 4;
pub const SIZE_OF_CHAR: usize = 1;
pub const SIZE_OF_SHORT: usize = 2;
pub const SIZE_OF_INT: usize = 4;
pub const SIZE_OF_LONG: usize = 8;
pub const SIZE_OF_LONGLONG: usize = 8;
pub const SIZE_OF_FLOAT: usize = 4;
pub const SIZE_OF_DOUBLE: usize = 8;
// signed option cannot be applied to boolean value
pub const BOOL: Self = Self::Int {
width: 1,
is_signed: false,
is_const: false,
};
pub const CHAR: Self = Self::int(Self::SIZE_OF_CHAR * Self::BITS_OF_BYTE);
pub const SHORT: Self = Self::int(Self::SIZE_OF_SHORT * Self::BITS_OF_BYTE);
pub const INT: Self = Self::int(Self::SIZE_OF_INT * Self::BITS_OF_BYTE);
pub const LONG: Self = Self::int(Self::SIZE_OF_LONG * Self::BITS_OF_BYTE);
pub const LONGLONG: Self = Self::int(Self::SIZE_OF_LONGLONG * Self::BITS_OF_BYTE);
pub const FLOAT: Self = Self::float(Self::SIZE_OF_FLOAT * Self::BITS_OF_BYTE);
pub const DOUBLE: Self = Self::float(Self::SIZE_OF_DOUBLE * Self::BITS_OF_BYTE);
#[inline] #[inline]
pub const fn unit() -> Self { pub const fn unit() -> Self {
@@ -378,6 +485,14 @@ impl Dtype {
} }
} }
#[inline]
pub fn typedef(name: String) -> Self {
Self::Typedef {
name,
is_const: false,
}
}
#[inline] #[inline]
pub fn get_int_width(&self) -> Option<usize> { pub fn get_int_width(&self) -> Option<usize> {
if let Self::Int { width, .. } = self { if let Self::Int { width, .. } = self {
@@ -405,6 +520,15 @@ impl Dtype {
} }
} }
#[inline]
pub fn get_array_inner(&self) -> Option<&Dtype> {
if let Self::Array { inner, .. } = self {
Some(inner.deref())
} else {
None
}
}
#[inline] #[inline]
pub fn get_function_inner(&self) -> Option<(&Dtype, &Vec<Dtype>)> { pub fn get_function_inner(&self) -> Option<(&Dtype, &Vec<Dtype>)> {
if let Self::Function { ret, params } = self { if let Self::Function { ret, params } = self {
@@ -441,6 +565,7 @@ impl Dtype {
Self::Pointer { is_const, .. } => *is_const, Self::Pointer { is_const, .. } => *is_const,
Self::Array { .. } => true, Self::Array { .. } => true,
Self::Function { .. } => true, Self::Function { .. } => true,
Self::Typedef { .. } => panic!("typedef should be replaced by real dtype"),
} }
} }
@@ -458,6 +583,7 @@ impl Dtype {
Self::Pointer { inner, .. } => Self::Pointer { inner, is_const }, Self::Pointer { inner, .. } => Self::Pointer { inner, is_const },
Self::Array { .. } => self, Self::Array { .. } => self,
Self::Function { .. } => self, Self::Function { .. } => self,
Self::Typedef { name, .. } => Self::Typedef { name, is_const },
} }
} }
@@ -465,17 +591,12 @@ impl Dtype {
match self { match self {
Self::Unit { .. } => Ok((0, 1)), Self::Unit { .. } => Ok((0, 1)),
Self::Int { width, .. } | Self::Float { width, .. } => { Self::Int { width, .. } | Self::Float { width, .. } => {
let align_of = *width / Self::WIDTH_OF_BYTE; let size_of = (*width + Self::BITS_OF_BYTE - 1) / Self::BITS_OF_BYTE;
let size_of = align_of; let align_of = size_of;
Ok((size_of, align_of))
}
Self::Pointer { .. } => {
let align_of = Self::WIDTH_OF_POINTER / Self::WIDTH_OF_BYTE;
let size_of = align_of;
Ok((size_of, align_of)) Ok((size_of, align_of))
} }
Self::Pointer { .. } => Ok((Self::SIZE_OF_POINTER, Self::SIZE_OF_POINTER)),
Self::Array { inner, size, .. } => { Self::Array { inner, size, .. } => {
let (size_of_inner, align_of_inner) = inner.size_align_of()?; let (size_of_inner, align_of_inner) = inner.size_align_of()?;
@@ -484,9 +605,8 @@ impl Dtype {
align_of_inner, align_of_inner,
)) ))
} }
Self::Function { .. } => Err(DtypeError::Misc { Self::Function { .. } => Ok((0, 1)),
message: "`size_align_of` cannot be used with function types".to_string(), Self::Typedef { .. } => panic!("typedef should be replaced by real dtype"),
}),
} }
} }
@@ -506,22 +626,26 @@ impl Dtype {
/// Derive a data type from declaration specifiers. /// Derive a data type from declaration specifiers.
pub fn try_from_ast_declaration_specifiers( pub fn try_from_ast_declaration_specifiers(
specifiers: &[Node<ast::DeclarationSpecifier>], specifiers: &[Node<ast::DeclarationSpecifier>],
) -> Result<Self, DtypeError> { ) -> Result<(Self, bool), DtypeError> {
let mut spec = BaseDtype::default(); let mut spec = BaseDtype::default();
BaseDtype::apply_declaration_specifiers(&mut spec, specifiers)?; BaseDtype::apply_declaration_specifiers(&mut spec, specifiers)?;
Self::try_from(spec) let is_typedef = spec.is_typedef;
let dtype = Self::try_from(spec)?;
Ok((dtype, is_typedef))
} }
/// Generate `Dtype` based on declarator and `base_dtype` which has scalar type. /// Generate `Dtype` based on declarator and `self` which has scalar type.
/// ///
/// let's say declaration is `const int * const * const a;`. /// let's say declaration is `const int * const * const a;`.
/// In general `base_dtype` start with `const int` which has scalar type and /// In general `self` start with `const int` which has scalar type and
/// `declarator` represents `* const * const` with `ast::Declarator` /// `declarator` represents `* const * const` with `ast::Declarator`
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `declarator` - Parts requiring conversion to 'Dtype' on the declaration /// * `declarator` - Parts requiring conversion to 'Dtype' on the declaration
/// * `base_dtype` - Part that has been converted to 'Dtype' on the declaration /// * `decl_spec` - Containing information that should be referenced
/// when creating `Dtype` from `Declarator`.
/// ///
pub fn with_ast_declarator(mut self, declarator: &ast::Declarator) -> Result<Self, DtypeError> { pub fn with_ast_declarator(mut self, declarator: &ast::Declarator) -> Result<Self, DtypeError> {
for derived_decl in &declarator.derived { for derived_decl in &declarator.derived {
@@ -533,7 +657,10 @@ impl Dtype {
} }
Self::pointer(self).set_const(specifier.is_const) Self::pointer(self).set_const(specifier.is_const)
} }
ast::DerivedDeclarator::Array(_array_decl) => todo!(), ast::DerivedDeclarator::Array(array_decl) => {
assert!(array_decl.node.qualifiers.is_empty());
self.with_ast_array_size(&array_decl.node.size)?
}
ast::DerivedDeclarator::Function(func_decl) => { ast::DerivedDeclarator::Function(func_decl) => {
let params = func_decl let params = func_decl
.node .node
@@ -561,37 +688,81 @@ impl Dtype {
} }
} }
/// Check whether type conflict exists between the two `Dtype` objects. /// Generates `Dtype` based on declarator and `self` which has scalar type.
/// ///
/// let's say expression is `const int a = 0; int b = 0; int c = a + b`. /// Let's say the AST declaration is `int a[2][3]`; `self` represents `int [2]`; and
/// Although `const int` of `a` and `int` of `b` looks different, `Plus`(+) operations between /// `array_size` is `[3]`. Then this function should return `int [2][3]`.
/// these two types are possible without any type-casting. There is no conflict between
/// `const int` and `int`.
/// ///
/// However, only the outermost const is ignored. /// # Arguments
/// If check equivalence between `const int *const` and `int *`, result is false. Because ///
/// the second `const` (means left most `const`) of the `const int *const` is missed in `int *`. /// * `array_size` - the array size to add to the dtype `self`
/// By the way, outermost `const` (means right most `const`) is not a consideration here. ///
pub fn is_compatible(&self, other: &Self) -> bool { pub fn with_ast_array_size(self, array_size: &ast::ArraySize) -> Result<Self, DtypeError> {
match (self, other) { let expr = if let ast::ArraySize::VariableExpression(expr) = array_size {
(Self::Unit { .. }, Self::Unit { .. }) &expr.node
| (Self::Int { .. }, Self::Int { .. }) } else {
| (Self::Float { .. }, Self::Float { .. }) panic!("`ArraySize` is unsupported except `ArraySize::VariableExpression`")
| (Self::Pointer { .. }, Self::Pointer { .. }) => { };
self.clone().set_const(false) == other.clone().set_const(false)
let constant = Constant::try_from(expr)
.expect("expression of `ArraySize::VariableExpression` must be constant value");
let (value, _, is_signed) = constant.get_int().ok_or_else(|| DtypeError::Misc {
message: "expression is not an integer constant expression".to_string(),
})?;
if is_signed && (value as i128) < 0 {
return Err(DtypeError::Misc {
message: "declared as an array with a negative size".to_string(),
});
}
Ok(Self::array(self, value as usize))
}
pub fn resolve_typedefs(self, typedefs: &HashMap<String, Dtype>) -> Result<Self, DtypeError> {
let dtype = match &self {
Self::Unit { .. } | Self::Int { .. } | Self::Float { .. } => self,
Self::Pointer { inner, is_const } => {
let inner = inner.deref().clone().resolve_typedefs(typedefs)?;
Dtype::pointer(inner).set_const(*is_const)
} }
( Self::Array { inner, size } => {
Self::Function { ret, params }, let inner = inner.deref().clone().resolve_typedefs(typedefs)?;
Self::Function { Dtype::array(inner, *size)
ret: other_ret,
params: other_params,
},
) => {
ret == other_ret
&& params.len() == other_params.len()
&& izip!(params, other_params).all(|(l, r)| l.is_compatible(r))
} }
_ => false, Self::Function { ret, params } => {
let ret = ret.deref().clone().resolve_typedefs(typedefs)?;
let params = params
.iter()
.map(|p| p.clone().resolve_typedefs(typedefs))
.collect::<Result<Vec<_>, _>>()?;
Dtype::function(ret, params)
}
Self::Typedef { name, is_const } => {
let dtype = typedefs
.get(name)
.ok_or_else(|| DtypeError::Misc {
message: format!("unknown type name `{}`", name),
})?
.clone();
let is_const = dtype.is_const() || *is_const;
dtype.set_const(is_const)
}
};
Ok(dtype)
}
pub fn merge(self, other: Self) -> Result<Self, DtypeError> {
if self == other {
Ok(self)
} else {
Err(DtypeError::Misc {
message: format!("Dtype::merge({:?}, {:?}) failed", self, other),
})
} }
} }
} }
@@ -615,7 +786,7 @@ impl fmt::Display for Dtype {
write!(f, "{}f{}", if *is_const { "const " } else { "" }, width) write!(f, "{}f{}", if *is_const { "const " } else { "" }, width)
} }
Self::Pointer { inner, is_const } => { Self::Pointer { inner, is_const } => {
write!(f, "{}* {}", inner, if *is_const { "const" } else { "" }) write!(f, "{}*{}", inner, if *is_const { "const" } else { "" })
} }
Self::Array { inner, size, .. } => write!(f, "[{} x {}]", size, inner,), Self::Array { inner, size, .. } => write!(f, "[{} x {}]", size, inner,),
Self::Function { ret, params } => write!( Self::Function { ret, params } => write!(
@@ -628,6 +799,9 @@ impl fmt::Display for Dtype {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Self::Typedef { name, is_const } => {
write!(f, "{}{}", if *is_const { "const " } else { "" }, name)
}
} }
} }
} }

View File

@@ -1,4 +1,5 @@
use core::fmt; use core::fmt;
use core::iter;
use core::mem; use core::mem;
use failure::Fail; use failure::Fail;
use std::collections::HashMap; use std::collections::HashMap;
@@ -31,11 +32,39 @@ pub enum Value {
}, },
Pointer { Pointer {
bid: Option<usize>, bid: Option<usize>,
offset: usize, offset: isize,
dtype: Dtype,
},
Array {
inner_dtype: Dtype,
values: Vec<Value>,
}, },
} }
impl HasDtype for Value {
fn dtype(&self) -> Dtype {
match self {
Self::Undef { dtype } => dtype.clone(),
Self::Unit => Dtype::unit(),
Self::Int {
width, is_signed, ..
} => Dtype::int(*width).set_signed(*is_signed),
Self::Float { width, .. } => Dtype::float(*width),
Self::Pointer { dtype, .. } => Dtype::pointer(dtype.clone()),
Self::Array {
inner_dtype,
values,
} => Dtype::array(inner_dtype.clone(), values.len()),
}
}
}
impl Value { impl Value {
#[inline]
fn undef(dtype: Dtype) -> Self {
Self::Undef { dtype }
}
#[inline] #[inline]
fn unit() -> Self { fn unit() -> Self {
Self::Unit Self::Unit
@@ -56,8 +85,8 @@ impl Value {
} }
#[inline] #[inline]
fn pointer(bid: Option<usize>, offset: usize) -> Self { fn pointer(bid: Option<usize>, offset: isize, dtype: Dtype) -> Self {
Self::Pointer { bid, offset } Self::Pointer { bid, offset, dtype }
} }
#[inline] #[inline]
@@ -75,19 +104,20 @@ impl Value {
} }
#[inline] #[inline]
fn get_pointer(self) -> Option<(Option<usize>, usize)> { fn get_pointer(&self) -> Option<(&Option<usize>, &isize, &Dtype)> {
if let Value::Pointer { bid, offset } = self { if let Value::Pointer { bid, offset, dtype } = self {
Some((bid, offset)) Some((bid, offset, dtype))
} else { } else {
None None
} }
} }
#[inline] #[inline]
fn nullptr() -> Self { fn nullptr(dtype: Dtype) -> Self {
Self::Pointer { Self::Pointer {
bid: None, bid: None,
offset: 0, offset: 0,
dtype,
} }
} }
@@ -99,9 +129,10 @@ impl Value {
width, is_signed, .. width, is_signed, ..
} => Self::int(u128::default(), *width, *is_signed), } => Self::int(u128::default(), *width, *is_signed),
ir::Dtype::Float { width, .. } => Self::float(f64::default(), *width), ir::Dtype::Float { width, .. } => Self::float(f64::default(), *width),
ir::Dtype::Pointer { .. } => Self::nullptr(), ir::Dtype::Pointer { inner, .. } => Self::nullptr(inner.deref().clone()),
ir::Dtype::Array { .. } => panic!("array type does not have a default value"), ir::Dtype::Array { .. } => panic!("array type does not have a default value"),
ir::Dtype::Function { .. } => panic!("function type does not have a default value"), ir::Dtype::Function { .. } => panic!("function type does not have a default value"),
ir::Dtype::Typedef { .. } => panic!("typedef should be replaced by real dtype"),
} }
} }
} }
@@ -248,9 +279,11 @@ mod calculator {
assert_eq!(lhs_s, rhs_s); assert_eq!(lhs_s, rhs_s);
match op { match op {
// TODO: consider signed value in the future
ast::BinaryOperator::Plus => Ok(Value::int(lhs + rhs, lhs_w, lhs_s)), ast::BinaryOperator::Plus => Ok(Value::int(lhs + rhs, lhs_w, lhs_s)),
ast::BinaryOperator::Minus => Ok(Value::int(lhs - rhs, lhs_w, lhs_s)), ast::BinaryOperator::Minus => Ok(Value::int(lhs - rhs, lhs_w, lhs_s)),
ast::BinaryOperator::Multiply => Ok(Value::int(lhs * rhs, lhs_w, lhs_s)), ast::BinaryOperator::Multiply => Ok(Value::int(lhs * rhs, lhs_w, lhs_s)),
ast::BinaryOperator::Modulo => Ok(Value::int(lhs % rhs, lhs_w, lhs_s)),
ast::BinaryOperator::Equals => { ast::BinaryOperator::Equals => {
let result = if lhs == rhs { 1 } else { 0 }; let result = if lhs == rhs { 1 } else { 0 };
Ok(Value::int(result, 1, lhs_s)) Ok(Value::int(result, 1, lhs_s))
@@ -263,11 +296,28 @@ mod calculator {
let result = if lhs < rhs { 1 } else { 0 }; let result = if lhs < rhs { 1 } else { 0 };
Ok(Value::int(result, 1, lhs_s)) Ok(Value::int(result, 1, lhs_s))
} }
ast::BinaryOperator::Greater => {
let result = if lhs > rhs { 1 } else { 0 };
Ok(Value::int(result, 1, lhs_s))
}
ast::BinaryOperator::LessOrEqual => {
let result = if lhs <= rhs { 1 } else { 0 };
Ok(Value::int(result, 1, lhs_s))
}
ast::BinaryOperator::GreaterOrEqual => { ast::BinaryOperator::GreaterOrEqual => {
let result = if lhs >= rhs { 1 } else { 0 }; let result = if lhs >= rhs { 1 } else { 0 };
Ok(Value::int(result, 1, lhs_s)) Ok(Value::int(result, 1, lhs_s))
} }
_ => todo!("will be covered all operator"), ast::BinaryOperator::LogicalAnd => {
assert!(lhs < 2);
assert!(rhs < 2);
let result = lhs | rhs;
Ok(Value::int(result, 1, lhs_s))
}
_ => todo!(
"calculate_binary_operator_expression: not supported operator {:?}",
op
),
} }
} }
_ => todo!(), _ => todo!(),
@@ -336,45 +386,246 @@ mod calculator {
} }
} }
// TODO
#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
enum Byte {
Undef,
Concrete(u8),
Pointer {
bid: usize,
offset: isize,
index: usize,
},
}
#[derive(Default, Debug, PartialEq)] #[derive(Default, Debug, PartialEq)]
struct Memory { struct Memory {
// TODO: memory type should change to Vec<Vec<Byte>> inner: Vec<Option<Vec<Byte>>>,
inner: Vec<Vec<Value>>, }
impl Byte {
#[inline]
fn concrete(byte: u8) -> Self {
Self::Concrete(byte)
}
#[inline]
fn pointer(bid: usize, offset: isize, index: usize) -> Self {
Self::Pointer { bid, offset, index }
}
fn get_concrete(&self) -> Option<u8> {
if let Self::Concrete(byte) = self {
Some(*byte)
} else {
None
}
}
fn get_pointer(&self) -> Option<(usize, isize, usize)> {
if let Self::Pointer { bid, offset, index } = self {
Some((*bid, *offset, *index))
} else {
None
}
}
fn block_from_dtype(dtype: &Dtype) -> Vec<Self> {
let size = dtype.size_align_of().unwrap().0;
iter::repeat(Self::Undef).take(size).collect()
}
fn u128_to_bytes(mut value: u128, size: usize) -> Vec<u8> {
let divisor = 1u128 << Dtype::BITS_OF_BYTE;
let mut bytes = Vec::new();
for _ in 0..size {
bytes.push((value % divisor) as u8);
value /= divisor;
}
bytes
}
fn bytes_to_u128(bytes: &[u8], is_signed: bool) -> u128 {
let width = bytes.len();
assert!(0 < width && width <= 16);
let is_negative = is_signed && *bytes.last().unwrap() >= 128;
let mut array = [if is_negative { 255 } else { 0 }; 16];
array[0..width].copy_from_slice(bytes);
u128::from_le_bytes(array)
}
fn bytes_to_value<'b, I>(bytes: &mut I, dtype: &Dtype) -> Result<Value, InterpreterError>
where
I: Iterator<Item = &'b Self>,
{
match dtype {
ir::Dtype::Unit { .. } => Ok(Value::Unit),
ir::Dtype::Int {
width, is_signed, ..
} => {
let value = some_or!(
bytes
.by_ref()
.take(*width)
.map(|b| b.get_concrete())
.collect::<Option<Vec<_>>>(),
return Ok(Value::undef(dtype.clone()))
);
let value = Self::bytes_to_u128(&value, *is_signed);
Ok(Value::int(value, *width, *is_signed))
}
ir::Dtype::Float { width, .. } => {
let value = some_or!(
bytes
.by_ref()
.take(*width)
.map(|b| b.get_concrete())
.collect::<Option<Vec<_>>>(),
return Ok(Value::undef(dtype.clone()))
);
let value = Self::bytes_to_u128(&value, false);
let value = if *width == Dtype::SIZE_OF_FLOAT {
f32::from_bits(value as u32) as f64
} else {
f64::from_bits(value as u64)
};
Ok(Value::float(value, *width))
}
ir::Dtype::Pointer { inner, .. } => {
let value = some_or!(
bytes
.by_ref()
.take(Dtype::SIZE_OF_POINTER)
.map(|b| b.get_pointer())
.collect::<Option<Vec<_>>>(),
return Ok(Value::undef(dtype.clone()))
);
let (bid, offset, _) = value.first().expect("not empty");
Ok(
if !value
.iter()
.enumerate()
.all(|(idx, ptr)| *ptr == (*bid, *offset, idx))
{
Value::undef(inner.deref().clone())
} else {
Value::pointer(Some(*bid), *offset, inner.deref().clone())
},
)
}
ir::Dtype::Array { inner, size } => {
let (inner_size, inner_align) = inner.size_align_of().unwrap();
let padding = std::cmp::max(inner_size, inner_align) - inner_size;
let values = (0..*size)
.map(|_| {
let value = Self::bytes_to_value(bytes, inner)?;
let _ = bytes.by_ref().take(padding);
Ok(value)
})
.collect::<Result<Vec<_>, InterpreterError>>()?;
Ok(Value::Array {
inner_dtype: inner.deref().clone(),
values,
})
}
ir::Dtype::Function { .. } => panic!("function value cannot be constructed from bytes"),
ir::Dtype::Typedef { .. } => panic!("typedef should be replaced by real dtype"),
}
}
fn value_to_bytes(value: &Value) -> Vec<Self> {
match value {
Value::Undef { dtype } => Self::block_from_dtype(dtype),
Value::Unit => Vec::new(),
Value::Int { value, width, .. } => {
let size = (*width + Dtype::BITS_OF_BYTE - 1) / Dtype::BITS_OF_BYTE;
Self::u128_to_bytes(*value, size)
.iter()
.map(|b| Self::concrete(*b))
.collect::<Vec<_>>()
}
Value::Float { value, width } => {
let size = (*width + Dtype::BITS_OF_BYTE - 1) / Dtype::BITS_OF_BYTE;
let value: u128 = match size {
Dtype::SIZE_OF_FLOAT => (*value as f32).to_bits() as u128,
Dtype::SIZE_OF_DOUBLE => (*value as f64).to_bits() as u128,
_ => panic!("value_to_bytes: {} is not a valid float size", size),
};
Self::u128_to_bytes(value, size)
.iter()
.map(|b| Self::concrete(*b))
.collect::<Vec<_>>()
}
Value::Pointer { bid, offset, .. } => (0..Dtype::SIZE_OF_POINTER)
.map(|i| Self::pointer(bid.unwrap(), *offset, i))
.collect(),
Value::Array {
inner_dtype,
values,
} => {
let (inner_size, inner_align) = inner_dtype.size_align_of().unwrap();
let padding = std::cmp::max(inner_size, inner_align) - inner_size;
values
.iter()
.map(|v| {
let mut result = Self::value_to_bytes(v);
result.extend(iter::repeat(Byte::Undef).take(padding));
result
})
.flatten()
.collect()
}
}
}
} }
impl Memory { impl Memory {
fn alloc(&mut self, dtype: &Dtype) -> Result<usize, InterpreterError> { fn alloc(&mut self, dtype: &Dtype) -> Result<usize, InterpreterError> {
let memory_block = Self::block_from_dtype(dtype); let bid = self.inner.len();
self.inner.push(memory_block); self.inner.push(Some(Byte::block_from_dtype(dtype)));
Ok(bid)
Ok(self.inner.len() - 1)
} }
fn load(&self, bid: usize, offset: usize) -> &Value { fn dealloc(
&self.inner[bid][offset] &mut self,
bid: usize,
offset: isize,
dtype: &Dtype,
) -> Result<(), InterpreterError> {
let block = &mut self.inner[bid];
assert_eq!(offset, 0);
assert_eq!(
block.as_mut().unwrap().len(),
dtype.size_align_of().unwrap().0
);
*block = None;
Ok(())
} }
fn store(&mut self, bid: usize, offset: usize, value: Value) { fn load(&self, bid: usize, offset: isize, dtype: &Dtype) -> Result<Value, InterpreterError> {
self.inner[bid][offset] = value; assert!(0 <= offset);
let offset = offset as usize;
let size = dtype.size_align_of().unwrap().0;
let mut iter = self.inner[bid].as_ref().unwrap()[offset..(offset + size)].iter();
Byte::bytes_to_value(&mut iter, dtype)
} }
fn block_from_dtype(dtype: &Dtype) -> Vec<Value> { fn store(&mut self, bid: usize, offset: isize, value: &Value) {
match dtype { assert!(0 <= offset);
ir::Dtype::Unit { .. } => vec![], let offset = offset as usize;
ir::Dtype::Int { .. } | ir::Dtype::Float { .. } | ir::Dtype::Pointer { .. } => { let size = value.dtype().size_align_of().unwrap().0;
vec![Value::Undef { let bytes = Byte::value_to_bytes(value);
dtype: dtype.clone(), self.inner[bid]
}] .as_mut()
} .unwrap()
ir::Dtype::Array { inner, size, .. } => { .splice(offset..(offset + size), bytes.iter().cloned());
let sub_vec = Self::block_from_dtype(inner.deref());
(0..*size).fold(vec![], |mut result, _| {
result.append(&mut sub_vec.clone());
result
})
}
ir::Dtype::Function { .. } => vec![],
}
} }
} }
@@ -443,10 +694,11 @@ impl<'i> State<'i> {
Value::default_from_dtype(&dtype) Value::default_from_dtype(&dtype)
}; };
self.memory.store(bid, 0, value); self.memory.store(bid, 0, &value);
} }
ir::Dtype::Array { .. } => todo!("Initializer::List is needed"), ir::Dtype::Array { .. } => todo!("Initializer::List is needed"),
ir::Dtype::Function { .. } => panic!("function variable does not exist"), ir::Dtype::Function { .. } => panic!("function variable does not exist"),
ir::Dtype::Typedef { .. } => panic!("typedef should be replaced by real dtype"),
}, },
// If functin declaration, skip initialization // If functin declaration, skip initialization
Declaration::Function { .. } => (), Declaration::Function { .. } => (),
@@ -460,8 +712,8 @@ impl<'i> State<'i> {
// add alloc register // add alloc register
for (id, allocation) in self.stack_frame.func_def.allocations.iter().enumerate() { for (id, allocation) in self.stack_frame.func_def.allocations.iter().enumerate() {
let bid = self.memory.alloc(&allocation)?; let bid = self.memory.alloc(&allocation)?;
let ptr = Value::pointer(Some(bid), 0); let ptr = Value::pointer(Some(bid), 0, allocation.deref().clone());
let rid = RegisterId::local("".to_string(), id); let rid = RegisterId::local(id);
self.stack_frame.registers.write(rid, ptr) self.stack_frame.registers.write(rid, ptr)
} }
@@ -498,7 +750,17 @@ impl<'i> State<'i> {
// If it's returning from a function, pop the stack frame. // If it's returning from a function, pop the stack frame.
// TODO: free memory allocated in the callee // Frees memory allocated in the callee
for (i, d) in self.stack_frame.func_def.allocations.iter().enumerate() {
let (bid, offset, dtype) = self
.stack_frame
.registers
.read(RegisterId::local(i))
.get_pointer()
.unwrap();
assert_eq!(d.deref(), dtype);
self.memory.dealloc(bid.unwrap(), *offset, dtype)?;
}
// restore previous state // restore previous state
let prev_stack_frame = some_or!(self.stack.pop(), return Ok(Some(return_value))); let prev_stack_frame = some_or!(self.stack.pop(), return Ok(Some(return_value)));
@@ -526,7 +788,8 @@ impl<'i> State<'i> {
) -> Result<Vec<Value>, InterpreterError> { ) -> Result<Vec<Value>, InterpreterError> {
// Check that the dtype of each args matches the expected // Check that the dtype of each args matches the expected
if !(args.len() == signature.params.len() if !(args.len() == signature.params.len()
&& izip!(args, &signature.params).all(|(a, d)| a.dtype().is_compatible(d))) && izip!(args, &signature.params)
.all(|(a, d)| a.dtype().set_const(false) == d.clone().set_const(false)))
{ {
panic!("dtype of args and params must be compatible") panic!("dtype of args and params must be compatible")
} }
@@ -546,16 +809,14 @@ impl<'i> State<'i> {
assert_eq!(arg.args.len(), block.phinodes.len()); assert_eq!(arg.args.len(), block.phinodes.len());
for (a, d) in izip!(&arg.args, &block.phinodes) { for (a, d) in izip!(&arg.args, &block.phinodes) {
assert!(a.dtype().is_compatible(&d)); assert!(a.dtype().set_const(false) == d.deref().clone().set_const(false));
} }
for (i, a) in arg.args.iter().enumerate() { for (i, a) in arg.args.iter().enumerate() {
let v = self.interp_operand(a.clone()).unwrap(); let v = self.interp_operand(a.clone()).unwrap();
self.stack_frame self.stack_frame
.registers .registers
.inner .write(RegisterId::arg(arg.bid, i), v);
.insert(RegisterId::arg(arg.bid, i), v)
.unwrap();
} }
self.stack_frame.pc = Pc::new(arg.bid); self.stack_frame.pc = Pc::new(arg.bid);
@@ -629,21 +890,20 @@ impl<'i> State<'i> {
Instruction::Store { ptr, value, .. } => { Instruction::Store { ptr, value, .. } => {
let ptr = self.interp_operand(ptr.clone())?; let ptr = self.interp_operand(ptr.clone())?;
let value = self.interp_operand(value.clone())?; let value = self.interp_operand(value.clone())?;
let (bid, offset) = self.interp_ptr(ptr)?; let (bid, offset, _) = self.interp_ptr(&ptr)?;
self.memory.store(bid, offset, value); self.memory.store(bid, offset, &value);
Value::Unit Value::Unit
} }
Instruction::Load { ptr, .. } => { Instruction::Load { ptr, .. } => {
let ptr = self.interp_operand(ptr.clone())?; let ptr = self.interp_operand(ptr.clone())?;
let (bid, offset) = self.interp_ptr(ptr)?; let (bid, offset, dtype) = self.interp_ptr(&ptr)?;
self.memory.load(bid, offset).clone() self.memory.load(bid, offset, &dtype)?
} }
Instruction::Call { callee, args, .. } => { Instruction::Call { callee, args, .. } => {
let ptr = self.interp_operand(callee.clone())?; let ptr = self.interp_operand(callee.clone())?;
// Get function name from pointer // Get function name from pointer
let (bid, _) = ptr.get_pointer().expect("`ptr` must be `Value::Pointer`"); let (bid, _, _) = ptr.get_pointer().expect("`ptr` must be `Value::Pointer`");
let bid = bid.expect("pointer for global variable must have bid value"); let bid = bid.expect("pointer for global variable must have bid value");
let callee_name = self let callee_name = self
.global_map .global_map
@@ -721,8 +981,11 @@ impl<'i> State<'i> {
width, width,
is_signed, is_signed,
}, },
Constant::Float { value, width } => Value::Float { value, width }, Constant::Float { value, width } => Value::Float {
Constant::GlobalVariable { name, .. } => { value: value.into_inner(),
width,
},
Constant::GlobalVariable { name, dtype } => {
let bid = self let bid = self
.global_map .global_map
.get_bid(&name) .get_bid(&name)
@@ -732,13 +995,14 @@ impl<'i> State<'i> {
Value::Pointer { Value::Pointer {
bid: Some(bid), bid: Some(bid),
offset: 0, offset: 0,
dtype,
} }
} }
} }
} }
fn interp_ptr(&mut self, pointer: Value) -> Result<(usize, usize), InterpreterError> { fn interp_ptr(&mut self, pointer: &Value) -> Result<(usize, isize, Dtype), InterpreterError> {
let (bid, offset) = pointer let (bid, offset, dtype) = pointer
.get_pointer() .get_pointer()
.ok_or_else(|| InterpreterError::Misc { .ok_or_else(|| InterpreterError::Misc {
func_name: self.stack_frame.func_name.clone(), func_name: self.stack_frame.func_name.clone(),
@@ -752,7 +1016,7 @@ impl<'i> State<'i> {
msg: "Accessing memory with constant pointer".into(), msg: "Accessing memory with constant pointer".into(),
})?; })?;
Ok((bid, offset)) Ok((bid, *offset, dtype.clone()))
} }
} }

View File

@@ -4,8 +4,9 @@ mod write_ir;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::ops::Deref; use core::ops::{Deref, DerefMut};
use lang_c::ast; use lang_c::ast;
use ordered_float::OrderedFloat;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@@ -60,6 +61,7 @@ impl TryFrom<Dtype> for Declaration {
signature: FunctionSignature::new(dtype), signature: FunctionSignature::new(dtype),
definition: None, definition: None,
}), }),
Dtype::Typedef { .. } => panic!("typedef should be replaced by real dtype"),
} }
} }
} }
@@ -100,10 +102,6 @@ impl Declaration {
} }
/// Check if type is conflicting for pre-declared one /// Check if type is conflicting for pre-declared one
///
/// In case of `Variable`, need to check if the two types are exactly the same.
/// On the other hand, in the case of `Function`, outermost `const` of return type and
/// parameters one is not an issue of concern.
pub fn is_compatible(&self, other: &Declaration) -> bool { pub fn is_compatible(&self, other: &Declaration) -> bool {
match (self, other) { match (self, other) {
(Self::Variable { dtype, .. }, Self::Variable { dtype: other, .. }) => dtype == other, (Self::Variable { dtype, .. }, Self::Variable { dtype: other, .. }) => dtype == other,
@@ -112,7 +110,7 @@ impl Declaration {
Self::Function { Self::Function {
signature: other, .. signature: other, ..
}, },
) => signature.dtype().is_compatible(&other.dtype()), ) => signature.dtype() == other.dtype(),
_ => false, _ => false,
} }
} }
@@ -127,19 +125,6 @@ impl HasDtype for Declaration {
} }
} }
#[derive(Debug, PartialEq, Clone)]
pub struct FunctionDefinition {
/// Memory allocations for local variables. The allocation is performed at the beginning of a
/// function invocation.
pub allocations: Vec<Dtype>,
/// Basic blocks.
pub blocks: HashMap<BlockId, Block>,
/// The initial block id.
pub bid_init: BlockId,
}
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct FunctionSignature { pub struct FunctionSignature {
pub ret: Dtype, pub ret: Dtype,
@@ -164,15 +149,229 @@ impl HasDtype for FunctionSignature {
} }
} }
#[derive(Debug, PartialEq, Clone)]
pub struct FunctionDefinition {
/// Memory allocations for local variables. The allocation is performed at the beginning of a
/// function invocation.
pub allocations: Vec<Named<Dtype>>,
/// Basic blocks.
pub blocks: HashMap<BlockId, Block>,
/// The initial block id.
pub bid_init: BlockId,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct BlockId(pub usize);
impl fmt::Display for BlockId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "b{}", self.0)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Block {
pub phinodes: Vec<Named<Dtype>>,
pub instructions: Vec<Named<Instruction>>,
pub exit: BlockExit,
}
#[derive(Debug, PartialEq, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum Instruction {
// TODO: the variants of Instruction will be added in the future
Nop,
BinOp {
op: ast::BinaryOperator,
lhs: Operand,
rhs: Operand,
dtype: Dtype,
},
UnaryOp {
op: ast::UnaryOperator,
operand: Operand,
dtype: Dtype,
},
Store {
ptr: Operand,
value: Operand,
},
Load {
ptr: Operand,
},
Call {
callee: Operand,
args: Vec<Operand>,
return_type: Dtype,
},
TypeCast {
value: Operand,
target_dtype: Dtype,
},
}
impl HasDtype for Instruction {
fn dtype(&self) -> Dtype {
match self {
Self::Nop => Dtype::unit(),
Self::BinOp { dtype, .. } => dtype.clone(),
Self::UnaryOp { dtype, .. } => dtype.clone(),
Self::Store { .. } => Dtype::unit(),
Self::Load { ptr } => ptr
.dtype()
.get_pointer_inner()
.expect("Load instruction must have pointer value as operand")
.deref()
.clone()
.set_const(false),
Self::Call { return_type, .. } => return_type.clone(),
Self::TypeCast { target_dtype, .. } => target_dtype.clone(),
}
}
}
impl Instruction {
pub fn is_pure(&self) -> bool {
match self {
Self::Store { .. } => false,
Self::Call { .. } => false,
_ => true,
}
}
}
// TODO
#[derive(Debug, PartialEq, Clone)]
pub enum BlockExit {
Jump {
arg: JumpArg,
},
ConditionalJump {
condition: Operand,
arg_then: JumpArg,
arg_else: JumpArg,
},
Switch {
value: Operand,
default: JumpArg,
cases: Vec<(Constant, JumpArg)>,
},
Return {
value: Operand,
},
Unreachable,
}
impl BlockExit {
pub fn walk_jump_args<F>(&mut self, mut f: F)
where
F: FnMut(&mut JumpArg),
{
match self {
Self::Jump { arg } => f(arg),
Self::ConditionalJump {
arg_then, arg_else, ..
} => {
f(arg_then);
f(arg_else);
}
Self::Switch { default, cases, .. } => {
f(default);
for (_, arg) in cases {
f(arg);
}
}
Self::Return { .. } | Self::Unreachable => {}
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct JumpArg {
pub bid: BlockId,
pub args: Vec<Operand>,
}
impl JumpArg {
pub fn new(bid: BlockId, args: Vec<Operand>) -> Self {
Self { bid, args }
}
}
impl fmt::Display for JumpArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({:?})", self.bid, self.args)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Operand {
Constant(Constant),
Register { rid: RegisterId, dtype: Dtype },
}
impl Operand {
pub fn constant(value: Constant) -> Self {
Self::Constant(value)
}
pub fn register(rid: RegisterId, dtype: Dtype) -> Self {
Self::Register { rid, dtype }
}
pub fn get_constant(&self) -> Option<&Constant> {
if let Self::Constant(constant) = self {
Some(constant)
} else {
None
}
}
pub fn get_register(&self) -> Option<(&RegisterId, &Dtype)> {
if let Self::Register { rid, dtype } = self {
Some((rid, dtype))
} else {
None
}
}
pub fn get_register_mut(&mut self) -> Option<(&mut RegisterId, &mut Dtype)> {
if let Self::Register { rid, dtype } = self {
Some((rid, dtype))
} else {
None
}
}
}
impl fmt::Display for Operand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Constant(value) => write!(f, "{}", value),
Self::Register { rid, .. } => write!(f, "{}", rid),
}
}
}
impl HasDtype for Operand {
fn dtype(&self) -> Dtype {
match self {
Self::Constant(value) => value.dtype(),
Self::Register { dtype, .. } => dtype.clone(),
}
}
}
#[derive(Debug, Eq, Clone)] #[derive(Debug, Eq, Clone)]
pub enum RegisterId { pub enum RegisterId {
/// Registers holding pointers to local allocations. /// Registers holding pointers to local allocations.
/// ///
/// # Fields /// # Fields
/// ///
/// - `name`: only for debugging purposes. /// - `aid`: local allocation id.
/// - `id`: local allocation id. Local { aid: usize },
Local { name: String, id: usize },
/// Registers holding block arguments. /// Registers holding block arguments.
/// ///
@@ -193,8 +392,8 @@ pub enum RegisterId {
} }
impl RegisterId { impl RegisterId {
pub fn local(name: String, id: usize) -> Self { pub fn local(aid: usize) -> Self {
Self::Local { name, id } Self::Local { aid }
} }
pub fn arg(bid: BlockId, aid: usize) -> Self { pub fn arg(bid: BlockId, aid: usize) -> Self {
@@ -209,9 +408,9 @@ impl RegisterId {
impl fmt::Display for RegisterId { impl fmt::Display for RegisterId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::Local { name, id } => write!(f, "%(local:{}:{})", name, id), Self::Local { aid } => write!(f, "%l{}", aid),
Self::Arg { bid, aid } => write!(f, "%(arg:{}:{})", bid, aid), Self::Arg { bid, aid } => write!(f, "%{}:p{}", bid, aid),
Self::Temp { bid, iid } => write!(f, "%({}:{})", bid, iid), Self::Temp { bid, iid } => write!(f, "%{}:i{}", bid, iid),
} }
} }
} }
@@ -219,7 +418,7 @@ impl fmt::Display for RegisterId {
impl PartialEq<RegisterId> for RegisterId { impl PartialEq<RegisterId> for RegisterId {
fn eq(&self, other: &RegisterId) -> bool { fn eq(&self, other: &RegisterId) -> bool {
match (self, other) { match (self, other) {
(Self::Local { id, .. }, Self::Local { id: other_id, .. }) => id == other_id, (Self::Local { aid }, Self::Local { aid: other_aid }) => aid == other_aid,
( (
Self::Arg { bid, aid }, Self::Arg { bid, aid },
Self::Arg { Self::Arg {
@@ -242,7 +441,7 @@ impl PartialEq<RegisterId> for RegisterId {
impl Hash for RegisterId { impl Hash for RegisterId {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
match self { match self {
Self::Local { id, .. } => id.hash(state), Self::Local { aid } => aid.hash(state),
Self::Arg { bid, aid } => { Self::Arg { bid, aid } => {
// TODO: needs to distinguish arg/temp? // TODO: needs to distinguish arg/temp?
bid.hash(state); bid.hash(state);
@@ -256,7 +455,7 @@ impl Hash for RegisterId {
} }
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Constant { pub enum Constant {
Undef { Undef {
dtype: Dtype, dtype: Dtype,
@@ -273,7 +472,7 @@ pub enum Constant {
/// * Casting from an f32 to an f64 is perfect and lossless (f32 -> f64) /// * Casting from an f32 to an f64 is perfect and lossless (f32 -> f64)
/// * Casting from an f64 to an f32 will produce the closest possible value (f64 -> f32) /// * Casting from an f64 to an f32 will produce the closest possible value (f64 -> f32)
/// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions /// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions
value: f64, value: OrderedFloat<f64>,
width: usize, width: usize,
}, },
GlobalVariable { GlobalVariable {
@@ -397,7 +596,10 @@ impl Constant {
.get_float_width() .get_float_width()
.expect("`dtype` must be `Dtype::Float`"); .expect("`dtype` must be `Dtype::Float`");
Self::Float { value, width } Self::Float {
value: value.into(),
width,
}
} }
#[inline] #[inline]
@@ -405,6 +607,20 @@ impl Constant {
Self::GlobalVariable { name, dtype } Self::GlobalVariable { name, dtype }
} }
#[inline]
pub fn get_int(&self) -> Option<(u128, usize, bool)> {
if let Self::Int {
value,
width,
is_signed,
} = self
{
Some((*value, *width, *is_signed))
} else {
None
}
}
pub fn is_undef(&self) -> bool { pub fn is_undef(&self) -> bool {
if let Self::Undef { .. } = self { if let Self::Undef { .. } = self {
true true
@@ -441,179 +657,30 @@ impl HasDtype for Constant {
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Operand { pub struct Named<T> {
Constant(Constant), name: Option<String>,
Register { rid: RegisterId, dtype: Dtype }, inner: T,
} }
impl Operand { impl<T> Deref for Named<T> {
pub fn constant(value: Constant) -> Self { type Target = T;
Self::Constant(value)
}
pub fn register(rid: RegisterId, dtype: Dtype) -> Self { fn deref(&self) -> &Self::Target {
Self::Register { rid, dtype } &self.inner
} }
}
pub fn get_constant(&self) -> Option<&Constant> { impl<T> DerefMut for Named<T> {
if let Self::Constant(constant) = self { fn deref_mut(&mut self) -> &mut Self::Target {
Some(constant) &mut self.inner
} else {
None
}
}
pub fn get_register(&self) -> Option<(&RegisterId, &Dtype)> {
if let Self::Register { rid, dtype } = self {
Some((rid, dtype))
} else {
None
}
}
pub fn get_register_mut(&mut self) -> Option<(&mut RegisterId, &mut Dtype)> {
if let Self::Register { rid, dtype } = self {
Some((rid, dtype))
} else {
None
}
} }
} }
impl fmt::Display for Operand { impl<T> Named<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { pub fn new(name: Option<String>, inner: T) -> Self {
match self { Self { name, inner }
Self::Constant(value) => write!(f, "{}", value), }
Self::Register { rid, .. } => write!(f, "{}", rid),
} pub fn name(&self) -> Option<&String> {
self.name.as_ref()
} }
} }
impl HasDtype for Operand {
fn dtype(&self) -> Dtype {
match self {
Self::Constant(value) => value.dtype(),
Self::Register { dtype, .. } => dtype.clone(),
}
}
}
#[derive(Debug, PartialEq, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum Instruction {
// TODO: the variants of Instruction will be added in the future
Nop,
BinOp {
op: ast::BinaryOperator,
lhs: Operand,
rhs: Operand,
dtype: Dtype,
},
UnaryOp {
op: ast::UnaryOperator,
operand: Operand,
dtype: Dtype,
},
Store {
ptr: Operand,
value: Operand,
},
Load {
ptr: Operand,
},
Call {
callee: Operand,
args: Vec<Operand>,
return_type: Dtype,
},
TypeCast {
value: Operand,
target_dtype: Dtype,
},
}
impl HasDtype for Instruction {
fn dtype(&self) -> Dtype {
match self {
Self::Nop => Dtype::unit(),
Self::BinOp { dtype, .. } => dtype.clone(),
Self::UnaryOp { dtype, .. } => dtype.clone(),
Self::Store { .. } => Dtype::unit(),
Self::Load { ptr } => ptr
.dtype()
.get_pointer_inner()
.expect("Load instruction must have pointer value as operand")
.deref()
.clone()
.set_const(false),
Self::Call { return_type, .. } => return_type.clone(),
Self::TypeCast { target_dtype, .. } => target_dtype.clone(),
}
}
}
impl Instruction {
pub fn is_pure(&self) -> bool {
match self {
Self::Store { .. } => false,
Self::Call { .. } => false,
_ => true,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct BlockId(pub usize);
impl fmt::Display for BlockId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "b{}", self.0)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct JumpArg {
pub bid: BlockId,
pub args: Vec<Operand>,
}
impl JumpArg {
pub fn new(bid: BlockId, args: Vec<Operand>) -> Self {
Self { bid, args }
}
}
impl fmt::Display for JumpArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({:?})", self.bid, self.args)
}
}
// TODO
#[derive(Debug, PartialEq, Clone)]
pub enum BlockExit {
Jump {
arg: JumpArg,
},
ConditionalJump {
condition: Operand,
arg_then: JumpArg,
arg_else: JumpArg,
},
Switch {
value: Operand,
default: JumpArg,
cases: Vec<(Constant, JumpArg)>,
},
Return {
value: Operand,
},
Unreachable,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Block {
pub phinodes: Vec<Dtype>,
pub instructions: Vec<Instruction>,
pub exit: BlockExit,
}

View File

@@ -58,25 +58,33 @@ impl WriteLine for (&String, &Declaration) {
match definition.as_ref() { match definition.as_ref() {
Some(defintion) => { Some(defintion) => {
// print function definition
writeln!(write, "define {} {{", declaration)?;
// print meta data for function // print meta data for function
writeln!( writeln!(
write, write,
"; function meta data:\n; bid_init: {}\n; allocations: {}", "init:\n bid: {}\n allocations: \n{}\n",
defintion.bid_init, defintion.bid_init,
defintion defintion
.allocations .allocations
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, a)| format!("{}:{}", i, a)) .map(|(i, a)| format!(
" %l{}:{}{}",
i,
a.deref(),
if let Some(name) = a.name() {
format!(":{}", name)
} else {
"".into()
}
))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join("\n")
)?; )?;
// print function definition
writeln!(write, "define {} {{", declaration)?;
for (id, block) in &defintion.blocks { for (id, block) in &defintion.blocks {
writeln!(write, "; <BoxId> {}", id)?; writeln!(write, "block {}", id)?;
(id, block).write_line(indent + 1, write)?; (id, block).write_line(indent + 1, write)?;
writeln!(write)?; writeln!(write)?;
} }
@@ -99,13 +107,33 @@ impl WriteLine for (&String, &Declaration) {
impl WriteLine for (&BlockId, &Block) { impl WriteLine for (&BlockId, &Block) {
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> { fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
for (i, phi) in self.1.phinodes.iter().enumerate() {
write_indent(indent, write)?;
writeln!(
write,
"{}:{}{}",
RegisterId::arg(*self.0, i),
phi.deref(),
if let Some(name) = phi.name() {
format!(":{}", name)
} else {
"".into()
}
)?;
}
for (i, instr) in self.1.instructions.iter().enumerate() { for (i, instr) in self.1.instructions.iter().enumerate() {
write_indent(indent, write)?; write_indent(indent, write)?;
writeln!( writeln!(
write, write,
"{}:{} = {}", "{}:{}{} = {}",
RegisterId::temp(*self.0, i), RegisterId::temp(*self.0, i),
instr.dtype(), instr.dtype(),
if let Some(name) = instr.name() {
format!(":{}", name)
} else {
"".into()
},
instr.write_string() instr.write_string()
)?; )?;
} }

View File

@@ -9,9 +9,6 @@ mod simplify_cfg;
pub use deadcode::Deadcode; pub use deadcode::Deadcode;
pub use gvn::Gvn; pub use gvn::Gvn;
pub use mem2reg::Mem2reg; pub use mem2reg::Mem2reg;
pub use opt_utils::{
make_cfg, make_domtree, replace_operand, replace_operands, reverse_cfg, Domtree, Walk,
};
pub use simplify_cfg::SimplifyCfg; pub use simplify_cfg::SimplifyCfg;
use crate::ir; use crate::ir;

View File

@@ -1,171 +0,0 @@
#![allow(dead_code)]
use std::collections::HashMap;
use crate::ir::*;
/// "Replace-all-uses-with".
pub trait Walk {
fn walk<F>(&mut self, f: F) -> bool
where
F: FnMut(&mut Operand) -> bool;
}
impl Walk for FunctionDefinition {
fn walk<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Operand) -> bool,
{
self.blocks.iter_mut().any(|(_, block)| block.walk(&mut f))
}
}
impl Walk for Block {
fn walk<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Operand) -> bool,
{
self.instructions.iter_mut().any(|i| i.walk(&mut f)) || self.exit.walk(&mut f)
}
}
impl Walk for Instruction {
fn walk<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Operand) -> bool,
{
match self {
Self::Nop => false,
Self::BinOp { lhs, rhs, .. } => lhs.walk(&mut f) || rhs.walk(&mut f),
Self::UnaryOp { operand, .. } => operand.walk(&mut f),
Self::Store { ptr, value } => ptr.walk(&mut f) || value.walk(&mut f),
Self::Load { ptr } => ptr.walk(&mut f),
Self::Call { callee, args, .. } => {
callee.walk(&mut f) || args.iter_mut().any(|a| a.walk(&mut f))
}
Self::TypeCast { value, .. } => value.walk(&mut f),
}
}
}
impl Walk for BlockExit {
fn walk<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Operand) -> bool,
{
match self {
Self::Jump { arg } => arg.walk(&mut f),
Self::ConditionalJump {
condition,
arg_then,
arg_else,
} => condition.walk(&mut f) || arg_then.walk(&mut f) || arg_else.walk(&mut f),
Self::Switch {
value,
default,
cases,
} => {
value.walk(&mut f)
|| default.walk(&mut f)
|| cases.iter_mut().any(|(_, a)| a.walk(&mut f))
}
Self::Return { value } => value.walk(&mut f),
Self::Unreachable => false,
}
}
}
impl Walk for JumpArg {
fn walk<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Operand) -> bool,
{
self.args.iter_mut().any(|a| a.walk(&mut f))
}
}
impl Walk for Operand {
fn walk<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Operand) -> bool,
{
f(self)
}
}
pub fn replace_operand(operand: &mut Operand, from: &Operand, to: &Operand) -> bool {
if operand == from {
*operand = to.clone();
true
} else {
false
}
}
pub fn replace_operands(operand: &mut Operand, dict: &HashMap<RegisterId, Operand>) -> bool {
if let Some((rid, dtype)) = operand.get_register_mut() {
if let Some(val) = dict.get(rid) {
assert_eq!(*dtype, val.dtype());
*operand = val.clone();
return true;
}
}
false
}
pub fn make_cfg(fdef: &FunctionDefinition) -> HashMap<BlockId, Vec<JumpArg>> {
let mut result = HashMap::new();
for (bid, block) in &fdef.blocks {
let mut args = Vec::new();
match &block.exit {
BlockExit::Jump { arg } => args.push(arg.clone()),
BlockExit::ConditionalJump {
arg_then, arg_else, ..
} => {
args.push(arg_then.clone());
args.push(arg_else.clone());
}
BlockExit::Switch { default, cases, .. } => {
args.push(default.clone());
for (_, arg) in cases {
args.push(arg.clone());
}
}
_ => {}
}
result.insert(*bid, args);
}
result
}
pub fn reverse_cfg(
cfg: &HashMap<BlockId, Vec<JumpArg>>,
) -> HashMap<BlockId, Vec<(BlockId, JumpArg)>> {
let mut result = HashMap::new();
for (bid, jumps) in cfg {
for jump in jumps {
result
.entry(jump.bid)
.or_insert_with(Vec::new)
.push((*bid, jump.clone()));
}
}
result
}
pub struct Domtree {}
impl Domtree {
pub fn walk<F>(&self, _f: F)
where
F: FnMut(BlockId, BlockId),
{
todo!()
}
}
pub fn make_domtree(_cfg: &HashMap<BlockId, Vec<JumpArg>>) -> Domtree {
todo!()
}

View File

@@ -1,5 +1,5 @@
use lang_c::ast::*; use lang_c::ast::*;
use std::fs::File; use std::fs::{self, File};
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use tempfile::tempdir; use tempfile::tempdir;
@@ -35,7 +35,7 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
.expect("failed to compile the given program"); .expect("failed to compile the given program");
// Execute compiled executable // Execute compiled executable
let status = Command::new(bin_path.clone()) let status = Command::new(fs::canonicalize(format!("./{}", bin_path.clone())).unwrap())
.status() .status()
.expect("failed to execute the compiled executable") .expect("failed to execute the compiled executable")
.code() .code()

View File

@@ -27,14 +27,15 @@ REPLACE_DICT = {
"union": "struct", "union": "struct",
r"enum[\w\s]*\{[^\}]*\};": "", r"enum[\w\s]*\{[^\}]*\};": "",
r"typedef enum[\w\s]*\{[^;]*;[\s_A-Z]*;": "", r"typedef enum[\w\s]*\{[^;]*;[\s_A-Z]*;": "",
"const char \*const sys_errlist\[\];": "", "const char \*const sys_errlist\[\];": "", # ArraySize::Unknown 삭제
r"[^\n]*printf[^;]*;": "", r"[^\n]*printf[^;]*;": "",
r"[^\n]*scanf[^;]*;": "", r"[^\n]*scanf[^;]*;": "",
" restrict": "", " restrict": "",
"inline ": "", "inline ": "",
"_Nullable": "", "_Nullable": "",
"\"g_\w*\", ": "", "\"g_\w*\", ": "", # transparent_crc에서 프린트 목적으로 받은 StringLiteral 삭제
"char\* vname, ": "", "char\* vname, ": "", # transparent_crc에서 사용하지 않는 파라미터 삭제
r"[^\n]*_IO_2_1_[^;]*;": "", # extern을 지우면서 생긴 size를 알 수 없는 struct 삭제
} }
CSMITH_DIR = "csmith-2.3.0" CSMITH_DIR = "csmith-2.3.0"
@@ -94,9 +95,8 @@ def generate(tests_dir, bin_path):
global CSMITH_DIR global CSMITH_DIR
options = [ options = [
"--no-argc", "--no-arrays", "--no-argc", "--no-arrays",
"--no-jumps", "--no-longlong", "--no-int8", "--no-jumps", "--no-pointers",
"--no-uint8", "--no-safe-math", "--no-pointers", "--no-structs", "--no-unions",
"--no-structs", "--no-unions", "--no-builtins",
] ]
args = [bin_path] + options args = [bin_path] + options