diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b86fab8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.vscode +ocelot/AtomicRegionInference/build +benchmarks/tests/*.out +benchmarks/tests/*.bc + +.DS_Store \ No newline at end of file diff --git a/readme.md b/README.md similarity index 100% rename from readme.md rename to README.md diff --git a/benchmarks/intermittent.rs b/benchmarks/intermittent.rs index 6a14b83..de3631d 100644 --- a/benchmarks/intermittent.rs +++ b/benchmarks/intermittent.rs @@ -1,14 +1,14 @@ //#![no_std] //#![feature(core_panic)] //#![feature(const_in_array_repeat_expressions)] -extern crate panic_msp430; -extern { +// extern crate panic_msp430; +extern "C" { fn start_atomic(); fn end_atomic(); - //add any externs, as from drivers, here + //add any externs, as from drivers, here fn printf(format: *const u8, ...); //necessary to import as the intrumentation pass needs to see this - static mut atomic_depth:u16; + static mut atomic_depth: u16; } /* @@ -19,62 +19,60 @@ pub extern "C" fn _entry() { */ #[allow(dead_code)] #[allow(non_snake_case)] -fn Fresh(_var:T) -> (){} +#[no_mangle] +fn Fresh(_var: T) -> () {} #[allow(dead_code)] #[allow(non_snake_case)] -fn Consistent(_var:T, _id:u16) -> (){} +#[no_mangle] +fn Consistent(_var: T, _id: u16) -> () {} #[allow(dead_code)] #[allow(non_snake_case)] -fn FreshConsistent(_var:T, _id:u16) -> (){} +#[no_mangle] +fn FreshConsistent(_var: T, _id: u16) -> () {} //#[inline(always)] #[no_mangle] -fn atomic_start() -> (){ +fn atomic_start() -> () { unsafe { - // variable must be visible to the omega pass - let local = atomic_depth; - start_atomic(); + // variable must be visible to the omega pass + let local = atomic_depth; + start_atomic(); } } #[no_mangle] -fn atomic_end() -> (){ +fn atomic_end() -> () { unsafe { - end_atomic(); - + end_atomic(); } } #[macro_export] macro_rules! nv { ($name:ident : $ty:ty = $expr:expr) => { - unsafe { - #[link_section = ".nv_vars"] - static mut $name: Option<$ty> = None; - - let used = $name.is_some(); - if used { - None - } else { - $name = Some($expr); - $name.as_mut() + unsafe { + #[link_section = ".nv_vars"] + static mut $name: Option<$ty> = None; - } - } + let used = $name.is_some(); + if used { + None + } else { + $name = Some($expr); + $name.as_mut() + } + } }; } - #[macro_export] macro_rules! big_nv { ($name:ident : $ty:ty = $expr:expr) => { - unsafe { - #[link_section = ".nv_vars"] - static mut $name:$ty = $expr; - & mut $name - - } + unsafe { + #[link_section = ".nv_vars"] + static mut $name: $ty = $expr; + &mut $name + } }; } - diff --git a/benchmarks/tests/example.ll b/benchmarks/tests/example.ll new file mode 100644 index 0000000..40607b5 --- /dev/null +++ b/benchmarks/tests/example.ll @@ -0,0 +1,178 @@ +; ModuleID = '../../benchmarks/tests/example.bc' +source_filename = "example.a08634fc28d17a86-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hd44a932dcf55a427E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h06fb5f22a45b1729E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @tmp }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h11952cf61e1518ebE(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17h2e8e8fa7347da120E(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17ha3b54fab1f2518b9E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h11952cf61e1518ebE(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h026d1b3fd579707fE"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h06fb5f22a45b1729E"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17h631194d6dbd64289E(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17h2e8e8fa7347da120E(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17h631194d6dbd64289E(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hd44a932dcf55a427E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h026d1b3fd579707fE"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: uwtable +define dso_local i32 @tmp() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + call void @atomic_start() + %x = call i32 @tmp() + call void @log(i32 %x) + call void @atomic_end() + ret void +} + +; Function Attrs: uwtable +define internal void @_ZN7example4main17ha3370acdcff48c7aE() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17ha3b54fab1f2518b9E(ptr @_ZN7example4main17ha3370acdcff48c7aE, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1115290} +!4 = !{} diff --git a/benchmarks/tests/example.orig.ll b/benchmarks/tests/example.orig.ll new file mode 100644 index 0000000..7118a00 --- /dev/null +++ b/benchmarks/tests/example.orig.ll @@ -0,0 +1,183 @@ +; ModuleID = '../../benchmarks/tests/example.bc' +source_filename = "example.a08634fc28d17a86-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hd44a932dcf55a427E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h06fb5f22a45b1729E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @tmp }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h11952cf61e1518ebE(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17h2e8e8fa7347da120E(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17ha3b54fab1f2518b9E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h11952cf61e1518ebE(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h026d1b3fd579707fE"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h06fb5f22a45b1729E"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17h631194d6dbd64289E(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17h2e8e8fa7347da120E(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17h631194d6dbd64289E(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he4a3bb6af4f8bfafE"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hd44a932dcf55a427E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h026d1b3fd579707fE"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: uwtable +define dso_local i32 @tmp() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + %x = call i32 @tmp() + call void @Fresh(i32 %x) + call void @log(i32 %x) + ret void +} + +; Function Attrs: uwtable +define internal void @_ZN7example4main17ha3370acdcff48c7aE() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define internal void @Fresh(i32 %_var) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17ha3b54fab1f2518b9E(ptr @_ZN7example4main17ha3370acdcff48c7aE, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1115290} +!4 = !{} diff --git a/benchmarks/tests/example.rs b/benchmarks/tests/example.rs new file mode 100644 index 0000000..bb6f8a1 --- /dev/null +++ b/benchmarks/tests/example.rs @@ -0,0 +1,23 @@ +include!("../intermittent.rs"); + +#[no_mangle] +fn tmp() -> i32 { + 0 +} + +#[no_mangle] +pub static IO_NAME: fn() -> i32 = tmp; + +#[no_mangle] +fn log(i: i32) -> () {} + +#[no_mangle] +fn app() -> () { + let x = tmp(); + Fresh(x); + log(x) +} + +fn main() -> () { + app() +} diff --git a/benchmarks/tests/example01.c b/benchmarks/tests/example01.c new file mode 100644 index 0000000..3bad3e9 --- /dev/null +++ b/benchmarks/tests/example01.c @@ -0,0 +1,25 @@ +#include + +void Fresh(int x) { printf("Fresh\n"); } +void Consistent(int x, int id) { printf("Consistent\n"); } + +void atomic_start() {} +void atomic_end() {} + +int tmp() { return 0; } +int (*IO_NAME1)() = tmp; + +void log(int x) { + printf("%d\n", x); +} + +int app() { + int x = tmp(); + Fresh(x); + log(x); + return 0; +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example01.ll b/benchmarks/tests/example01.ll new file mode 100644 index 0000000..1c44e5f --- /dev/null +++ b/benchmarks/tests/example01.ll @@ -0,0 +1,71 @@ +; ModuleID = '../../benchmarks/tests/example01.c' +source_filename = "../../benchmarks/tests/example01.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@.str = private unnamed_addr constant [7 x i8] c"Fresh\0A\00", align 1 +@.str.1 = private unnamed_addr constant [12 x i8] c"Consistent\0A\00", align 1 +@IO_NAME1 = global ptr @tmp, align 8 +@.str.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +declare i32 @printf(ptr noundef, ...) #0 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #1 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #1 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @tmp() #1 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #1 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef %0) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @app() #1 { +entry: + %x = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @tmp() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + call void @log(i32 noundef %0) + call void @atomic_end() + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #1 { +entry: + %call = call i32 @app() + ret i32 0 +} + +attributes #0 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example01.orig.ll b/benchmarks/tests/example01.orig.ll new file mode 100644 index 0000000..9692ddb --- /dev/null +++ b/benchmarks/tests/example01.orig.ll @@ -0,0 +1,91 @@ +; ModuleID = '../../benchmarks/tests/example01.c' +source_filename = "../../benchmarks/tests/example01.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@.str = private unnamed_addr constant [7 x i8] c"Fresh\0A\00", align 1 +@.str.1 = private unnamed_addr constant [12 x i8] c"Consistent\0A\00", align 1 +@IO_NAME1 = global ptr @tmp, align 8 +@.str.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Consistent(i32 noundef %x, i32 noundef %id) #0 { +entry: + %x.addr = alloca i32, align 4 + %id.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + store i32 %id, ptr %id.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str.1) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @tmp() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef %0) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @app() #0 { +entry: + %x = alloca i32, align 4 + %call = call i32 @tmp() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %0) + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + %call = call i32 @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example02.c b/benchmarks/tests/example02.c new file mode 100644 index 0000000..75bced9 --- /dev/null +++ b/benchmarks/tests/example02.c @@ -0,0 +1,32 @@ +#include + +void Fresh(int x) {} +void Consistent(int x, int id) {} + +void atomic_start() {} +void atomic_end() {} + +int sense() { return 0; } +int (*IO_NAME)() = sense; + +int norm(int t) { return t; } + +void log(int x) { + printf("%d\n", x); +} + +int tmp() { + int t = sense(); + int t_norm = norm(t); + return t_norm; +} + +void app() { + int x = tmp(); + Fresh(x); + log(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example02.ll b/benchmarks/tests/example02.ll new file mode 100644 index 0000000..c6886ac --- /dev/null +++ b/benchmarks/tests/example02.ll @@ -0,0 +1,92 @@ +; ModuleID = '../../benchmarks/tests/example02.c' +source_filename = "../../benchmarks/tests/example02.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @sense, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @sense() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @norm(i32 noundef %t) #0 { +entry: + %t.addr = alloca i32, align 4 + store i32 %t, ptr %t.addr, align 4 + %0 = load i32, ptr %t.addr, align 4 + ret i32 %0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @tmp() #0 { +entry: + %t = alloca i32, align 4 + %t_norm = alloca i32, align 4 + %call = call i32 @sense() + store i32 %call, ptr %t, align 4 + %0 = load i32, ptr %t, align 4 + %call1 = call i32 @norm(i32 noundef %0) + store i32 %call1, ptr %t_norm, align 4 + %1 = load i32, ptr %t_norm, align 4 + ret i32 %1 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @tmp() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + call void @log(i32 noundef %0) + call void @atomic_end() + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example02.orig.ll b/benchmarks/tests/example02.orig.ll new file mode 100644 index 0000000..9ec0125 --- /dev/null +++ b/benchmarks/tests/example02.orig.ll @@ -0,0 +1,110 @@ +; ModuleID = '../../benchmarks/tests/example02.c' +source_filename = "../../benchmarks/tests/example02.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @sense, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Consistent(i32 noundef %x, i32 noundef %id) #0 { +entry: + %x.addr = alloca i32, align 4 + %id.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + store i32 %id, ptr %id.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @sense() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @norm(i32 noundef %t) #0 { +entry: + %t.addr = alloca i32, align 4 + store i32 %t, ptr %t.addr, align 4 + %0 = load i32, ptr %t.addr, align 4 + ret i32 %0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @tmp() #0 { +entry: + %t = alloca i32, align 4 + %t_norm = alloca i32, align 4 + %call = call i32 @sense() + store i32 %call, ptr %t, align 4 + %0 = load i32, ptr %t, align 4 + %call1 = call i32 @norm(i32 noundef %0) + store i32 %call1, ptr %t_norm, align 4 + %1 = load i32, ptr %t_norm, align 4 + ret i32 %1 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %call = call i32 @tmp() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %0) + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example03.c b/benchmarks/tests/example03.c new file mode 100644 index 0000000..06d59f8 --- /dev/null +++ b/benchmarks/tests/example03.c @@ -0,0 +1,27 @@ +#include + +void Fresh(int x) {} +void Consistent(int x, int id) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + int y = 1; + int z = y + 1; + log(z); + log(x); + Fresh(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example03.ll b/benchmarks/tests/example03.ll new file mode 100644 index 0000000..a156f6a --- /dev/null +++ b/benchmarks/tests/example03.ll @@ -0,0 +1,77 @@ +; ModuleID = '../../benchmarks/tests/example03.c' +source_filename = "../../benchmarks/tests/example03.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + call void @log(i32 noundef %0) + call void @atomic_end() + store i32 1, ptr %y, align 4 + %1 = load i32, ptr %y, align 4 + %2 = add nsw i32 %1, 1 + store i32 %2, ptr %z, align 4 + %3 = load i32, ptr %z, align 4 + call void @log(i32 noundef %3) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example03.orig.ll b/benchmarks/tests/example03.orig.ll new file mode 100644 index 0000000..5a4464d --- /dev/null +++ b/benchmarks/tests/example03.orig.ll @@ -0,0 +1,95 @@ +; ModuleID = '../../benchmarks/tests/example03.c' +source_filename = "../../benchmarks/tests/example03.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Consistent(i32 noundef %x, i32 noundef %id) #0 { +entry: + %x.addr = alloca i32, align 4 + %id.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + store i32 %id, ptr %id.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 1, ptr %y, align 4 + %0 = load i32, ptr %y, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, ptr %z, align 4 + %1 = load i32, ptr %z, align 4 + call void @log(i32 noundef %1) + %2 = load i32, ptr %x, align 4 + call void @log(i32 noundef %2) + %3 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %3) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example04.c b/benchmarks/tests/example04.c new file mode 100644 index 0000000..a4463c3 --- /dev/null +++ b/benchmarks/tests/example04.c @@ -0,0 +1,28 @@ +#include + +void Fresh(int x) {} +void Consistent(int x, int id) {} +void FreshConsistent(int x, int id) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + int y = input(); + log(x); + log(y); + Consistent(x, 1); + FreshConsistent(y, 1); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example04.ll b/benchmarks/tests/example04.ll new file mode 100644 index 0000000..1185b60 --- /dev/null +++ b/benchmarks/tests/example04.ll @@ -0,0 +1,76 @@ +; ModuleID = '../../benchmarks/tests/example04.c' +source_filename = "../../benchmarks/tests/example04.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + call void @atomic_start() + %call1 = call i32 @input() + call void @atomic_end() + store i32 %call1, ptr %y, align 4 + %0 = load i32, ptr %y, align 4 + call void @log(i32 noundef %0) + call void @atomic_end() + store i32 %call, ptr %x, align 4 + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example04.orig.ll b/benchmarks/tests/example04.orig.ll new file mode 100644 index 0000000..c177c2f --- /dev/null +++ b/benchmarks/tests/example04.orig.ll @@ -0,0 +1,104 @@ +; ModuleID = '../../benchmarks/tests/example04.c' +source_filename = "../../benchmarks/tests/example04.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Consistent(i32 noundef %x, i32 noundef %id) #0 { +entry: + %x.addr = alloca i32, align 4 + %id.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + store i32 %id, ptr %id.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @FreshConsistent(i32 noundef %x, i32 noundef %id) #0 { +entry: + %x.addr = alloca i32, align 4 + %id.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + store i32 %id, ptr %id.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + %call1 = call i32 @input() + store i32 %call1, ptr %y, align 4 + %0 = load i32, ptr %x, align 4 + call void @log(i32 noundef %0) + %1 = load i32, ptr %y, align 4 + call void @log(i32 noundef %1) + %2 = load i32, ptr %x, align 4 + call void @Consistent(i32 noundef %2, i32 noundef 1) + %3 = load i32, ptr %y, align 4 + call void @FreshConsistent(i32 noundef %3, i32 noundef 1) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example05.c b/benchmarks/tests/example05.c new file mode 100644 index 0000000..e46b4fb --- /dev/null +++ b/benchmarks/tests/example05.c @@ -0,0 +1,29 @@ +#include + +void Fresh(int x) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + for (int i = 0; i < 10; i++) { + log(1); + log(x); + } + // for (int i = 0; i < 10; i++) { + // log(1); + // } + Fresh(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example05.ll b/benchmarks/tests/example05.ll new file mode 100644 index 0000000..2902ef0 --- /dev/null +++ b/benchmarks/tests/example05.ll @@ -0,0 +1,110 @@ +; ModuleID = '../../benchmarks/tests/example05.c' +source_filename = "../../benchmarks/tests/example05.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %0 = alloca i32, align 4 + %i = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %entry, %for.inc, + %1 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %1, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %2 = load i32, ptr %x, align 4 + call void @log(i32 noundef %2) + br label %for.inc + +for.inc: ; preds = %for.body, + %3 = load i32, ptr %i, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + call void @atomic_end() + store i32 0, ptr %0, align 4 + br label %for.cond1 + +for.cond1: ; preds = %for.inc3, %for.end + %4 = load i32, ptr %0, align 4 + %5 = icmp slt i32 %4, 10 + br i1 %5, label %for.body2, label %for.end4 + +for.body2: ; preds = %for.cond1 + call void @log(i32 noundef 1) + br label %for.inc3 + +for.inc3: ; preds = %for.body2 + %6 = load i32, ptr %0, align 4 + %7 = add nsw i32 %6, 1 + store i32 %7, ptr %0, align 4 + br label %for.cond1, !llvm.loop !5 + +for.end4: ; preds = %for.cond1 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example05.orig.ll b/benchmarks/tests/example05.orig.ll new file mode 100644 index 0000000..ccf8289 --- /dev/null +++ b/benchmarks/tests/example05.orig.ll @@ -0,0 +1,99 @@ +; ModuleID = '../../benchmarks/tests/example05.c' +source_filename = "../../benchmarks/tests/example05.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %0, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + call void @log(i32 noundef 1) + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + br label %for.inc + +for.inc: ; preds = %for.body + %2 = load i32, ptr %i, align 4 + %inc = add nsw i32 %2, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + %3 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %3) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example06.c b/benchmarks/tests/example06.c new file mode 100644 index 0000000..d192581 --- /dev/null +++ b/benchmarks/tests/example06.c @@ -0,0 +1,25 @@ +#include + +void Fresh(int x) {} +void Consistent(int x, int id) {} + +void atomic_start() {} +void atomic_end() {} + +int input(int i) { return i; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int i = 1; + int x = input(i); + Fresh(x); + log(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example06.ll b/benchmarks/tests/example06.ll new file mode 100644 index 0000000..3cf6d2b --- /dev/null +++ b/benchmarks/tests/example06.ll @@ -0,0 +1,75 @@ +; ModuleID = '../../benchmarks/tests/example06.c' +source_filename = "../../benchmarks/tests/example06.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input(i32 noundef %i) #0 { +entry: + %i.addr = alloca i32, align 4 + store i32 %i, ptr %i.addr, align 4 + %0 = load i32, ptr %i.addr, align 4 + ret i32 %0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %i = alloca i32, align 4 + %x = alloca i32, align 4 + call void @atomic_start() + store i32 1, ptr %i, align 4 + %0 = load i32, ptr %i, align 4 + %call = call i32 @input(i32 noundef %0) + store i32 %call, ptr %x, align 4 + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + call void @atomic_end() + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example06.orig.ll b/benchmarks/tests/example06.orig.ll new file mode 100644 index 0000000..e2cc907 --- /dev/null +++ b/benchmarks/tests/example06.orig.ll @@ -0,0 +1,93 @@ +; ModuleID = '../../benchmarks/tests/example06.c' +source_filename = "../../benchmarks/tests/example06.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Consistent(i32 noundef %x, i32 noundef %id) #0 { +entry: + %x.addr = alloca i32, align 4 + %id.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + store i32 %id, ptr %id.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input(i32 noundef %i) #0 { +entry: + %i.addr = alloca i32, align 4 + store i32 %i, ptr %i.addr, align 4 + %0 = load i32, ptr %i.addr, align 4 + ret i32 %0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %i = alloca i32, align 4 + %x = alloca i32, align 4 + store i32 1, ptr %i, align 4 + %0 = load i32, ptr %i, align 4 + %call = call i32 @input(i32 noundef %0) + store i32 %call, ptr %x, align 4 + %1 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %1) + %2 = load i32, ptr %x, align 4 + call void @log(i32 noundef %2) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} diff --git a/benchmarks/tests/example07.c b/benchmarks/tests/example07.c new file mode 100644 index 0000000..19fe98d --- /dev/null +++ b/benchmarks/tests/example07.c @@ -0,0 +1,27 @@ +#include + +void Fresh(int x) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + for (int i = 0; i < 10; i++) { + int y = 1; + log(x); + log(y + 2); + } + Fresh(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example07.ll b/benchmarks/tests/example07.ll new file mode 100644 index 0000000..ef3a2c6 --- /dev/null +++ b/benchmarks/tests/example07.ll @@ -0,0 +1,114 @@ +; ModuleID = '../../benchmarks/tests/example07.c' +source_filename = "../../benchmarks/tests/example07.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %0 = alloca i32, align 4 + %i = alloca i32, align 4 + %y = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %entry, %for.inc, + %1 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %1, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %2 = load i32, ptr %x, align 4 + call void @log(i32 noundef %2) + br label %for.inc + +for.inc: ; preds = %for.body, + %3 = load i32, ptr %i, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + call void @atomic_end() + store i32 0, ptr %0, align 4 + br label %for.cond1 + +for.cond1: ; preds = %for.inc3, %for.end + %4 = load i32, ptr %0, align 4 + %5 = icmp slt i32 %4, 10 + br i1 %5, label %for.body2, label %for.end4 + +for.body2: ; preds = %for.cond1 + store i32 1, ptr %y, align 4 + %6 = load i32, ptr %y, align 4 + %7 = add nsw i32 %6, 2 + call void @log(i32 noundef %7) + br label %for.inc3 + +for.inc3: ; preds = %for.body2 + %8 = load i32, ptr %0, align 4 + %9 = add nsw i32 %8, 1 + store i32 %9, ptr %0, align 4 + br label %for.cond1, !llvm.loop !5 + +for.end4: ; preds = %for.cond1 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example07.orig.ll b/benchmarks/tests/example07.orig.ll new file mode 100644 index 0000000..8b10b06 --- /dev/null +++ b/benchmarks/tests/example07.orig.ll @@ -0,0 +1,103 @@ +; ModuleID = '../../benchmarks/tests/example07.c' +source_filename = "../../benchmarks/tests/example07.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + %y = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %0, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + store i32 1, ptr %y, align 4 + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + %2 = load i32, ptr %y, align 4 + %add = add nsw i32 %2, 2 + call void @log(i32 noundef %add) + br label %for.inc + +for.inc: ; preds = %for.body + %3 = load i32, ptr %i, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + %4 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %4) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example08.c b/benchmarks/tests/example08.c new file mode 100644 index 0000000..77a3580 --- /dev/null +++ b/benchmarks/tests/example08.c @@ -0,0 +1,27 @@ +#include + +void Fresh(int x) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + for (int i = x; i < 10; i++) { + int y = 1; + log(y + 2); + log(x); + } + Fresh(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example08.ll b/benchmarks/tests/example08.ll new file mode 100644 index 0000000..315670d --- /dev/null +++ b/benchmarks/tests/example08.ll @@ -0,0 +1,96 @@ +; ModuleID = '../../benchmarks/tests/example08.c' +source_filename = "../../benchmarks/tests/example08.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + %y = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + store i32 %0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry, , + %1 = load i32, ptr %i, align 4 + %2 = icmp slt i32 %1, 10 + br i1 %2, label %for.body, label %for.end + +for.body: ; preds = %for.cond, + %3 = load i32, ptr %x, align 4 + call void @log(i32 noundef %3) + store i32 1, ptr %y, align 4 + %4 = load i32, ptr %y, align 4 + %5 = add nsw i32 %4, 2 + call void @log(i32 noundef %5) + br label %for.inc + +for.inc: ; preds = %for.body, + %6 = load i32, ptr %i, align 4 + %7 = add nsw i32 %6, 1 + store i32 %7, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond, + call void @atomic_end() + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example08.orig.ll b/benchmarks/tests/example08.orig.ll new file mode 100644 index 0000000..39e141a --- /dev/null +++ b/benchmarks/tests/example08.orig.ll @@ -0,0 +1,104 @@ +; ModuleID = '../../benchmarks/tests/example08.c' +source_filename = "../../benchmarks/tests/example08.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + %y = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + store i32 %0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %1 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %1, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + store i32 1, ptr %y, align 4 + %2 = load i32, ptr %y, align 4 + %add = add nsw i32 %2, 2 + call void @log(i32 noundef %add) + %3 = load i32, ptr %x, align 4 + call void @log(i32 noundef %3) + br label %for.inc + +for.inc: ; preds = %for.body + %4 = load i32, ptr %i, align 4 + %inc = add nsw i32 %4, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + %5 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %5) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example09.c b/benchmarks/tests/example09.c new file mode 100644 index 0000000..ace57fa --- /dev/null +++ b/benchmarks/tests/example09.c @@ -0,0 +1,26 @@ +#include + +void Fresh(int x) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + for (int i = 0; i < 10; i++) { + log(x); + log(i); + } + Fresh(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example09.ll b/benchmarks/tests/example09.ll new file mode 100644 index 0000000..02f1d07 --- /dev/null +++ b/benchmarks/tests/example09.ll @@ -0,0 +1,111 @@ +; ModuleID = '../../benchmarks/tests/example09.c' +source_filename = "../../benchmarks/tests/example09.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %0 = alloca i32, align 4 + %i = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %entry, %for.inc, + %1 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %1, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %2 = load i32, ptr %x, align 4 + call void @log(i32 noundef %2) + br label %for.inc + +for.inc: ; preds = %for.body, + %3 = load i32, ptr %i, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + call void @atomic_end() + store i32 0, ptr %0, align 4 + br label %for.cond1 + +for.cond1: ; preds = %for.inc3, %for.end + %4 = load i32, ptr %0, align 4 + %5 = icmp slt i32 %4, 10 + br i1 %5, label %for.body2, label %for.end4 + +for.body2: ; preds = %for.cond1 + %6 = load i32, ptr %i, align 4 + call void @log(i32 noundef %6) + br label %for.inc3 + +for.inc3: ; preds = %for.body2 + %7 = load i32, ptr %0, align 4 + %8 = add nsw i32 %7, 1 + store i32 %8, ptr %0, align 4 + br label %for.cond1, !llvm.loop !5 + +for.end4: ; preds = %for.cond1 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example09.orig.ll b/benchmarks/tests/example09.orig.ll new file mode 100644 index 0000000..9694cbd --- /dev/null +++ b/benchmarks/tests/example09.orig.ll @@ -0,0 +1,100 @@ +; ModuleID = '../../benchmarks/tests/example09.c' +source_filename = "../../benchmarks/tests/example09.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %0, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %1 = load i32, ptr %x, align 4 + call void @log(i32 noundef %1) + %2 = load i32, ptr %i, align 4 + call void @log(i32 noundef %2) + br label %for.inc + +for.inc: ; preds = %for.body + %3 = load i32, ptr %i, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + %4 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %4) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example10.c b/benchmarks/tests/example10.c new file mode 100644 index 0000000..4e57ff7 --- /dev/null +++ b/benchmarks/tests/example10.c @@ -0,0 +1,25 @@ +#include + +void Fresh(int x) {} + +void atomic_start() {} +void atomic_end() {} + +int input() { return 0; } +int (*IO_NAME)() = input; + +void log(int x) { + printf("%d\n", x); +} + +void app() { + int x = input(); + for (int i = x; i < 10; i++) { + log(i + 2); + } + Fresh(x); +} + +int main() { + app(); +} \ No newline at end of file diff --git a/benchmarks/tests/example10.ll b/benchmarks/tests/example10.ll new file mode 100644 index 0000000..6741975 --- /dev/null +++ b/benchmarks/tests/example10.ll @@ -0,0 +1,92 @@ +; ModuleID = '../../benchmarks/tests/example10.c' +source_filename = "../../benchmarks/tests/example10.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + call void @atomic_start() + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + store i32 %0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry, , + %1 = load i32, ptr %i, align 4 + %2 = icmp slt i32 %1, 10 + br i1 %2, label %for.body, label %for.end + +for.body: ; preds = %for.cond, + %3 = load i32, ptr %i, align 4 + %4 = add nsw i32 %3, 2 + call void @log(i32 noundef %4) + br label %for.inc + +for.inc: ; preds = %for.body, + %5 = load i32, ptr %i, align 4 + %6 = add nsw i32 %5, 1 + store i32 %6, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond, + call void @atomic_end() + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example10.orig.ll b/benchmarks/tests/example10.orig.ll new file mode 100644 index 0000000..7f3c08e --- /dev/null +++ b/benchmarks/tests/example10.orig.ll @@ -0,0 +1,100 @@ +; ModuleID = '../../benchmarks/tests/example10.c' +source_filename = "../../benchmarks/tests/example10.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@IO_NAME = global ptr @input, align 8 +@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @Fresh(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_start() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @atomic_end() #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @input() #0 { +entry: + ret i32 0 +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @log(i32 noundef %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, ptr %x.addr, align 4 + %0 = load i32, ptr %x.addr, align 4 + %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0) + ret void +} + +declare i32 @printf(ptr noundef, ...) #1 + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @app() #0 { +entry: + %x = alloca i32, align 4 + %i = alloca i32, align 4 + %call = call i32 @input() + store i32 %call, ptr %x, align 4 + %0 = load i32, ptr %x, align 4 + store i32 %0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %1 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %1, 10 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %2 = load i32, ptr %i, align 4 + %add = add nsw i32 %2, 2 + call void @log(i32 noundef %add) + br label %for.inc + +for.inc: ; preds = %for.body + %3 = load i32, ptr %i, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond, !llvm.loop !5 + +for.end: ; preds = %for.cond + %4 = load i32, ptr %x, align 4 + call void @Fresh(i32 noundef %4) + ret void +} + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define i32 @main() #0 { +entry: + call void @app() + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } +attributes #1 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"Homebrew clang version 17.0.2"} +!5 = distinct !{!5, !6} +!6 = !{!"llvm.loop.mustprogress"} diff --git a/benchmarks/tests/example11.ll b/benchmarks/tests/example11.ll new file mode 100644 index 0000000..05a924d --- /dev/null +++ b/benchmarks/tests/example11.ll @@ -0,0 +1,179 @@ +; ModuleID = '../../benchmarks/tests/example11.bc' +source_filename = "example11.808d53e03ac95af8-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hbf6a0eaa1969aba0E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h1b5be734946d3eb7E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @input }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h7035381af5c34fd9E(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17h3bf07a824888a276E(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17h9a96c5bd5005f31bE(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h7035381af5c34fd9E(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h22ca6c304b09fb94E"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h1b5be734946d3eb7E"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17h32b22b06cefb658aE(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17h32b22b06cefb658aE(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17h3bf07a824888a276E(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hbf6a0eaa1969aba0E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h22ca6c304b09fb94E"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: uwtable +define dso_local i32 @input() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + call void @atomic_start() + %x = call i32 @input() + call void @log(i32 %x) + call void @atomic_end() + call void @log(i32 1) + ret void +} + +; Function Attrs: uwtable +define internal void @_ZN9example114main17h0b701389294a589fE() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17h9a96c5bd5005f31bE(ptr @_ZN9example114main17h0b701389294a589fE, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1115339} +!4 = !{} diff --git a/benchmarks/tests/example11.orig.ll b/benchmarks/tests/example11.orig.ll new file mode 100644 index 0000000..fff931a --- /dev/null +++ b/benchmarks/tests/example11.orig.ll @@ -0,0 +1,184 @@ +; ModuleID = '../../benchmarks/tests/example11.bc' +source_filename = "example11.808d53e03ac95af8-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hbf6a0eaa1969aba0E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h1b5be734946d3eb7E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @input }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h7035381af5c34fd9E(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17h3bf07a824888a276E(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17h9a96c5bd5005f31bE(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h7035381af5c34fd9E(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h22ca6c304b09fb94E"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h1b5be734946d3eb7E"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17h32b22b06cefb658aE(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17h32b22b06cefb658aE(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17he176d602148ddb94E"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17h3bf07a824888a276E(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hbf6a0eaa1969aba0E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h22ca6c304b09fb94E"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: uwtable +define dso_local i32 @input() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + %x = call i32 @input() + call void @log(i32 1) + call void @log(i32 %x) + call void @Fresh(i32 %x) + ret void +} + +; Function Attrs: uwtable +define internal void @_ZN9example114main17h0b701389294a589fE() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define internal void @Fresh(i32 %_var) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17h9a96c5bd5005f31bE(ptr @_ZN9example114main17h0b701389294a589fE, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1115339} +!4 = !{} diff --git a/benchmarks/tests/example11.rs b/benchmarks/tests/example11.rs new file mode 100644 index 0000000..8f355c3 --- /dev/null +++ b/benchmarks/tests/example11.rs @@ -0,0 +1,26 @@ +include!("../intermittent.rs"); + +#[no_mangle] +fn input() -> i32 { + 0 +} + +#[no_mangle] +pub static IO_NAME: fn() -> i32 = input; + +#[no_mangle] +fn log(i: i32) -> () {} + +#[no_mangle] +fn app() -> () { + let x = input(); + let y = 1; + let z = y; + log(z); + log(x); + Fresh(x); +} + +fn main() -> () { + app() +} diff --git a/benchmarks/tests/example12.ll b/benchmarks/tests/example12.ll new file mode 100644 index 0000000..8ad00f3 --- /dev/null +++ b/benchmarks/tests/example12.ll @@ -0,0 +1,290 @@ +; ModuleID = '../../benchmarks/tests/example12.bc' +source_filename = "example12.2ec73fdcc3bed253-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17h47ea1b16ba3e87a4E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h2a2856448793d4cbE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @input }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h9c77676ca687ad52E(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17hc6a9dc29a00ac63eE(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17h04742dcfd5f87c29E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h9c77676ca687ad52E(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hc6cb452c4729c1f5E"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h3be66287c3fcbba4E"(i32 %start1, i64 %n) unnamed_addr #2 { +start: + %rhs = trunc i64 %n to i32 + %_0 = add nsw i32 %start1, %rhs + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h2a2856448793d4cbE"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17had97088f55991c2cE(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17had97088f55991c2cE(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17hc6a9dc29a00ac63eE(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17h47ea1b16ba3e87a4E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h3186fffc13203a36E"(ptr align 4 %self) unnamed_addr #2 { +start: + %0 = call { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h1b9638ceb504bcf5E"(ptr align 4 %self) + %_0.0 = extractvalue { i32, i32 } %0, 0 + %_0.1 = extractvalue { i32, i32 } %0, 1 + %1 = insertvalue { i32, i32 } poison, i32 %_0.0, 0 + %2 = insertvalue { i32, i32 } %1, i32 %_0.1, 1 + ret { i32, i32 } %2 +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hc6cb452c4729c1f5E"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h9c831713eeb3e5efE"(i32 %self.0, i32 %self.1) unnamed_addr #2 { +start: + %0 = insertvalue { i32, i32 } poison, i32 %self.0, 0 + %1 = insertvalue { i32, i32 } %0, i32 %self.1, 1 + ret { i32, i32 } %1 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h1b9638ceb504bcf5E"(ptr align 4 %self) unnamed_addr #2 { +start: + %_0 = alloca { i32, i32 }, align 4 + %_4 = getelementptr inbounds { i32, i32 }, ptr %self, i32 0, i32 1 + %_3.i = load i32, ptr %self, align 4, !noundef !4 + %_4.i = load i32, ptr %_4, align 4, !noundef !4 + %_0.i = icmp slt i32 %_3.i, %_4.i + br i1 %_0.i, label %bb2, label %bb4 + +bb4: ; preds = %start + store i32 0, ptr %_0, align 4 + br label %bb5 + +bb2: ; preds = %start + %old = load i32, ptr %self, align 4, !noundef !4 + %_6 = call i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h3be66287c3fcbba4E"(i32 %old, i64 1) + store i32 %_6, ptr %self, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + store i32 %old, ptr %0, align 4 + store i32 1, ptr %_0, align 4 + br label %bb5 + +bb5: ; preds = %bb2, %bb4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !range !5, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + %4 = load i32, ptr %3, align 4 + %5 = insertvalue { i32, i32 } poison, i32 %2, 0 + %6 = insertvalue { i32, i32 } %5, i32 %4, 1 + ret { i32, i32 } %6 +} + +; Function Attrs: uwtable +define dso_local i32 @input() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + %0 = alloca { i32, i32 }, align 8 + %_5 = alloca { i32, i32 }, align 4 + %iter = alloca { i32, i32 }, align 4 + %_3 = alloca { i32, i32 }, align 4 + call void @atomic_start() + %x = call i32 @input() + store i32 0, ptr %_3, align 4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + store i32 10, ptr %1, align 4 + %2 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 0 + %3 = load i32, ptr %2, align 4, !noundef !4 + %4 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + %5 = load i32, ptr %4, align 4, !noundef !4 + %6 = call { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h9c831713eeb3e5efE"(i32 %3, i32 %5) + %7 = extractvalue { i32, i32 } %6, 0 + %8 = extractvalue { i32, i32 } %6, 1 + %9 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 0 + store i32 %7, ptr %9, align 4 + %10 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 1 + store i32 %8, ptr %10, align 4 + br label %bb3 + +bb3: ; preds = %bb5, %start, , + %11 = call { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h3186fffc13203a36E"(ptr align 4 %iter) + store { i32, i32 } %11, ptr %_5, align 4 + %12 = load i32, ptr %_5, align 4, !range !5, !noundef !4 + %_7 = zext i32 %12 to i64 + %13 = icmp eq i64 %_7, 0 + br i1 %13, label %bb7, label %bb5 + +bb7: ; preds = %bb3 + call void @atomic_end() + store { i32, i32 } %11, ptr %0, align 4 + br label %bb31 + +bb5: ; preds = %bb3 + call void @log(i32 %x) + br label %bb3 + +bb6: ; No predecessors! + unreachable + +bb31: ; preds = %bb52, %bb7 + %14 = call { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h3186fffc13203a36E"(ptr align 4 %iter) + store { i32, i32 } %11, ptr %_5, align 4 + %15 = load i32, ptr %0, align 4, !range !5, !noundef !4 + %16 = zext i32 %12 to i64 + %17 = icmp eq i64 %_7, 0 + br i1 %17, label %bb52, label %bb73 + +bb52: ; preds = %bb31 + call void @log(i32 1) + br label %bb31 + +bb73: ; preds = %bb31 + ret void +} + +; Function Attrs: uwtable +define internal void @_ZN9example124main17h35539225bd174e48E() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17h04742dcfd5f87c29E(ptr @_ZN9example124main17h35539225bd174e48E, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1453225} +!4 = !{} +!5 = !{i32 0, i32 2} diff --git a/benchmarks/tests/example12.orig.ll b/benchmarks/tests/example12.orig.ll new file mode 100644 index 0000000..3ccefe2 --- /dev/null +++ b/benchmarks/tests/example12.orig.ll @@ -0,0 +1,279 @@ +; ModuleID = '../../benchmarks/tests/example12.bc' +source_filename = "example12.2ec73fdcc3bed253-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17h47ea1b16ba3e87a4E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h2a2856448793d4cbE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @input }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h9c77676ca687ad52E(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17hc6a9dc29a00ac63eE(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17h04742dcfd5f87c29E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h9c77676ca687ad52E(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hc6cb452c4729c1f5E"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h3be66287c3fcbba4E"(i32 %start1, i64 %n) unnamed_addr #2 { +start: + %rhs = trunc i64 %n to i32 + %_0 = add nsw i32 %start1, %rhs + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h2a2856448793d4cbE"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17had97088f55991c2cE(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17had97088f55991c2cE(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h339710bdc8eea187E"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17hc6a9dc29a00ac63eE(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17h47ea1b16ba3e87a4E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h3186fffc13203a36E"(ptr align 4 %self) unnamed_addr #2 { +start: + %0 = call { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h1b9638ceb504bcf5E"(ptr align 4 %self) + %_0.0 = extractvalue { i32, i32 } %0, 0 + %_0.1 = extractvalue { i32, i32 } %0, 1 + %1 = insertvalue { i32, i32 } poison, i32 %_0.0, 0 + %2 = insertvalue { i32, i32 } %1, i32 %_0.1, 1 + ret { i32, i32 } %2 +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hc6cb452c4729c1f5E"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h9c831713eeb3e5efE"(i32 %self.0, i32 %self.1) unnamed_addr #2 { +start: + %0 = insertvalue { i32, i32 } poison, i32 %self.0, 0 + %1 = insertvalue { i32, i32 } %0, i32 %self.1, 1 + ret { i32, i32 } %1 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h1b9638ceb504bcf5E"(ptr align 4 %self) unnamed_addr #2 { +start: + %_0 = alloca { i32, i32 }, align 4 + %_4 = getelementptr inbounds { i32, i32 }, ptr %self, i32 0, i32 1 + %_3.i = load i32, ptr %self, align 4, !noundef !4 + %_4.i = load i32, ptr %_4, align 4, !noundef !4 + %_0.i = icmp slt i32 %_3.i, %_4.i + br i1 %_0.i, label %bb2, label %bb4 + +bb4: ; preds = %start + store i32 0, ptr %_0, align 4 + br label %bb5 + +bb2: ; preds = %start + %old = load i32, ptr %self, align 4, !noundef !4 + %_6 = call i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h3be66287c3fcbba4E"(i32 %old, i64 1) + store i32 %_6, ptr %self, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + store i32 %old, ptr %0, align 4 + store i32 1, ptr %_0, align 4 + br label %bb5 + +bb5: ; preds = %bb2, %bb4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !range !5, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + %4 = load i32, ptr %3, align 4 + %5 = insertvalue { i32, i32 } poison, i32 %2, 0 + %6 = insertvalue { i32, i32 } %5, i32 %4, 1 + ret { i32, i32 } %6 +} + +; Function Attrs: uwtable +define dso_local i32 @input() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + %_5 = alloca { i32, i32 }, align 4 + %iter = alloca { i32, i32 }, align 4 + %_3 = alloca { i32, i32 }, align 4 + %x = call i32 @input() + store i32 0, ptr %_3, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + store i32 10, ptr %0, align 4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + %4 = load i32, ptr %3, align 4, !noundef !4 + %5 = call { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h9c831713eeb3e5efE"(i32 %2, i32 %4) + %_2.0 = extractvalue { i32, i32 } %5, 0 + %_2.1 = extractvalue { i32, i32 } %5, 1 + %6 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 0 + store i32 %_2.0, ptr %6, align 4 + %7 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 1 + store i32 %_2.1, ptr %7, align 4 + br label %bb3 + +bb3: ; preds = %bb5, %start + %8 = call { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h3186fffc13203a36E"(ptr align 4 %iter) + store { i32, i32 } %8, ptr %_5, align 4 + %9 = load i32, ptr %_5, align 4, !range !5, !noundef !4 + %_7 = zext i32 %9 to i64 + %10 = icmp eq i64 %_7, 0 + br i1 %10, label %bb7, label %bb5 + +bb7: ; preds = %bb3 + call void @Fresh(i32 %x) + ret void + +bb5: ; preds = %bb3 + call void @log(i32 1) + call void @log(i32 %x) + br label %bb3 + +bb6: ; No predecessors! + unreachable +} + +; Function Attrs: uwtable +define internal void @_ZN9example124main17h35539225bd174e48E() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define internal void @Fresh(i32 %_var) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17h04742dcfd5f87c29E(ptr @_ZN9example124main17h35539225bd174e48E, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1453225} +!4 = !{} +!5 = !{i32 0, i32 2} diff --git a/benchmarks/tests/example12.rs b/benchmarks/tests/example12.rs new file mode 100644 index 0000000..05d20c3 --- /dev/null +++ b/benchmarks/tests/example12.rs @@ -0,0 +1,26 @@ +include!("../intermittent.rs"); + +#[no_mangle] +fn input() -> i32 { + 0 +} + +#[no_mangle] +pub static IO_NAME: fn() -> i32 = input; + +#[no_mangle] +fn log(i: i32) -> () {} + +#[no_mangle] +fn app() -> () { + let x = input(); + for _ in 0..10 { + log(1); + log(x); + } + Fresh(x); +} + +fn main() -> () { + app() +} diff --git a/benchmarks/tests/example13.ll b/benchmarks/tests/example13.ll new file mode 100644 index 0000000..1a22fb2 --- /dev/null +++ b/benchmarks/tests/example13.ll @@ -0,0 +1,275 @@ +; ModuleID = '../../benchmarks/tests/example13.bc' +source_filename = "example13.a75a82856bfae51d-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hf0f1c0343a3d5304E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h4dfc989e8a89cebeE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @input }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hf4f9b68dd936cd73E(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17h6b12a0453d0fac53E(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17h431fe12d2c8c1de6E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hf4f9b68dd936cd73E(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h2db0f42e6485e7e4E"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h4944c1e1e44c8861E"(i32 %start1, i64 %n) unnamed_addr #2 { +start: + %rhs = trunc i64 %n to i32 + %_0 = add nsw i32 %start1, %rhs + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h4dfc989e8a89cebeE"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17hde4d0e94a62ddc18E(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17h6b12a0453d0fac53E(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17hde4d0e94a62ddc18E(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hf0f1c0343a3d5304E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h81d1ae0fa0da4546E"(ptr align 4 %self) unnamed_addr #2 { +start: + %0 = call { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h3a2fc0cbb86bcd54E"(ptr align 4 %self) + %_0.0 = extractvalue { i32, i32 } %0, 0 + %_0.1 = extractvalue { i32, i32 } %0, 1 + %1 = insertvalue { i32, i32 } poison, i32 %_0.0, 0 + %2 = insertvalue { i32, i32 } %1, i32 %_0.1, 1 + ret { i32, i32 } %2 +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h2db0f42e6485e7e4E"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h80dc70a24d0c93edE"(i32 %self.0, i32 %self.1) unnamed_addr #2 { +start: + %0 = insertvalue { i32, i32 } poison, i32 %self.0, 0 + %1 = insertvalue { i32, i32 } %0, i32 %self.1, 1 + ret { i32, i32 } %1 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h3a2fc0cbb86bcd54E"(ptr align 4 %self) unnamed_addr #2 { +start: + %_0 = alloca { i32, i32 }, align 4 + %_4 = getelementptr inbounds { i32, i32 }, ptr %self, i32 0, i32 1 + %_3.i = load i32, ptr %self, align 4, !noundef !4 + %_4.i = load i32, ptr %_4, align 4, !noundef !4 + %_0.i = icmp slt i32 %_3.i, %_4.i + br i1 %_0.i, label %bb2, label %bb4 + +bb4: ; preds = %start + store i32 0, ptr %_0, align 4 + br label %bb5 + +bb2: ; preds = %start + %old = load i32, ptr %self, align 4, !noundef !4 + %_6 = call i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h4944c1e1e44c8861E"(i32 %old, i64 1) + store i32 %_6, ptr %self, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + store i32 %old, ptr %0, align 4 + store i32 1, ptr %_0, align 4 + br label %bb5 + +bb5: ; preds = %bb2, %bb4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !range !5, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + %4 = load i32, ptr %3, align 4 + %5 = insertvalue { i32, i32 } poison, i32 %2, 0 + %6 = insertvalue { i32, i32 } %5, i32 %4, 1 + ret { i32, i32 } %6 +} + +; Function Attrs: uwtable +define dso_local i32 @input() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + %_6 = alloca { i32, i32 }, align 4 + %iter = alloca { i32, i32 }, align 4 + %_3 = alloca { i32, i32 }, align 4 + call void @atomic_start() + %x = call i32 @input() + store i32 %x, ptr %_3, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + store i32 10, ptr %0, align 4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + %4 = load i32, ptr %3, align 4, !noundef !4 + %5 = call { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h80dc70a24d0c93edE"(i32 %2, i32 %4) + %6 = extractvalue { i32, i32 } %5, 0 + %7 = extractvalue { i32, i32 } %5, 1 + %8 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 0 + store i32 %6, ptr %8, align 4 + %9 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 1 + store i32 %7, ptr %9, align 4 + br label %bb3 + +bb3: ; preds = %start, %bb5, + %10 = call { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h81d1ae0fa0da4546E"(ptr align 4 %iter) + store { i32, i32 } %10, ptr %_6, align 4 + %11 = load i32, ptr %_6, align 4, !range !5, !noundef !4 + %_8 = zext i32 %11 to i64 + %12 = icmp eq i64 %_8, 0 + br i1 %12, label %bb7, label %bb5 + +bb7: ; preds = %bb3 + call void @atomic_end() + ret void + +bb5: ; preds = %bb3 + %13 = getelementptr inbounds { i32, i32 }, ptr %_6, i32 0, i32 1 + %i = load i32, ptr %13, align 4, !noundef !4 + call void @log(i32 %i) + br label %bb3 + +bb6: ; No predecessors! + unreachable +} + +; Function Attrs: uwtable +define internal void @_ZN9example134main17haba30008cc3025a3E() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17h431fe12d2c8c1de6E(ptr @_ZN9example134main17haba30008cc3025a3E, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1453209} +!4 = !{} +!5 = !{i32 0, i32 2} diff --git a/benchmarks/tests/example13.orig.ll b/benchmarks/tests/example13.orig.ll new file mode 100644 index 0000000..564dab2 --- /dev/null +++ b/benchmarks/tests/example13.orig.ll @@ -0,0 +1,280 @@ +; ModuleID = '../../benchmarks/tests/example13.bc' +source_filename = "example13.a75a82856bfae51d-cgu.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hf0f1c0343a3d5304E", [16 x i8] c"\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h4dfc989e8a89cebeE", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E", ptr @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E" }>, align 8 +@IO_NAME = constant <{ ptr }> <{ ptr @input }>, align 8 +@atomic_depth = external global i16 + +; Function Attrs: noinline uwtable +define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hf4f9b68dd936cd73E(ptr %f) unnamed_addr #0 { +start: + call void @_ZN4core3ops8function6FnOnce9call_once17h6b12a0453d0fac53E(ptr %f) + call void asm sideeffect "", "~{memory}"(), !srcloc !3 + ret void +} + +; Function Attrs: uwtable +define hidden i64 @_ZN3std2rt10lang_start17h431fe12d2c8c1de6E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 { +start: + %_8 = alloca ptr, align 8 + %_5 = alloca i64, align 8 + store ptr %main, ptr %_8, align 8 + %0 = call i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv, i8 %sigpipe) + store i64 %0, ptr %_5, align 8 + %v = load i64, ptr %_5, align 8, !noundef !4 + ret i64 %v +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E"(ptr align 8 %_1) unnamed_addr #2 { +start: + %_4 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hf4f9b68dd936cd73E(ptr %_4) + %self = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h2db0f42e6485e7e4E"() + %_0 = zext i8 %self to i32 + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h4944c1e1e44c8861E"(i32 %start1, i64 %n) unnamed_addr #2 { +start: + %rhs = trunc i64 %n to i32 + %_0 = add nsw i32 %start1, %rhs + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h4dfc989e8a89cebeE"(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + %0 = load ptr, ptr %_1, align 8, !nonnull !4, !noundef !4 + %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17hde4d0e94a62ddc18E(ptr %0) + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3ops8function6FnOnce9call_once17h6b12a0453d0fac53E(ptr %_1) unnamed_addr #2 { +start: + %_2 = alloca {}, align 1 + call void %_1() + ret void +} + +; Function Attrs: inlinehint uwtable +define internal i32 @_ZN4core3ops8function6FnOnce9call_once17hde4d0e94a62ddc18E(ptr %0) unnamed_addr #2 personality ptr @rust_eh_personality { +start: + %1 = alloca { ptr, i32 }, align 8 + %_2 = alloca {}, align 1 + %_1 = alloca ptr, align 8 + store ptr %0, ptr %_1, align 8 + %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h51a796a89a29b131E"(ptr align 8 %_1) + to label %bb1 unwind label %cleanup + +bb3: ; preds = %cleanup + %2 = load ptr, ptr %1, align 8, !noundef !4 + %3 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + %4 = load i32, ptr %3, align 8, !noundef !4 + %5 = insertvalue { ptr, i32 } poison, ptr %2, 0 + %6 = insertvalue { ptr, i32 } %5, i32 %4, 1 + resume { ptr, i32 } %6 + +cleanup: ; preds = %start + %7 = landingpad { ptr, i32 } + cleanup + %8 = extractvalue { ptr, i32 } %7, 0 + %9 = extractvalue { ptr, i32 } %7, 1 + %10 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 0 + store ptr %8, ptr %10, align 8 + %11 = getelementptr inbounds { ptr, i32 }, ptr %1, i32 0, i32 1 + store i32 %9, ptr %11, align 8 + br label %bb3 + +bb1: ; preds = %start + ret i32 %_0 +} + +; Function Attrs: inlinehint uwtable +define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hf0f1c0343a3d5304E"(ptr align 8 %_1) unnamed_addr #2 { +start: + ret void +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h81d1ae0fa0da4546E"(ptr align 4 %self) unnamed_addr #2 { +start: + %0 = call { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h3a2fc0cbb86bcd54E"(ptr align 4 %self) + %_0.0 = extractvalue { i32, i32 } %0, 0 + %_0.1 = extractvalue { i32, i32 } %0, 1 + %1 = insertvalue { i32, i32 } poison, i32 %_0.0, 0 + %2 = insertvalue { i32, i32 } %1, i32 %_0.1, 1 + ret { i32, i32 } %2 +} + +; Function Attrs: inlinehint uwtable +define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h2db0f42e6485e7e4E"() unnamed_addr #2 { +start: + ret i8 0 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h80dc70a24d0c93edE"(i32 %self.0, i32 %self.1) unnamed_addr #2 { +start: + %0 = insertvalue { i32, i32 } poison, i32 %self.0, 0 + %1 = insertvalue { i32, i32 } %0, i32 %self.1, 1 + ret { i32, i32 } %1 +} + +; Function Attrs: inlinehint uwtable +define internal { i32, i32 } @"_ZN89_$LT$core..ops..range..Range$LT$T$GT$$u20$as$u20$core..iter..range..RangeIteratorImpl$GT$9spec_next17h3a2fc0cbb86bcd54E"(ptr align 4 %self) unnamed_addr #2 { +start: + %_0 = alloca { i32, i32 }, align 4 + %_4 = getelementptr inbounds { i32, i32 }, ptr %self, i32 0, i32 1 + %_3.i = load i32, ptr %self, align 4, !noundef !4 + %_4.i = load i32, ptr %_4, align 4, !noundef !4 + %_0.i = icmp slt i32 %_3.i, %_4.i + br i1 %_0.i, label %bb2, label %bb4 + +bb4: ; preds = %start + store i32 0, ptr %_0, align 4 + br label %bb5 + +bb2: ; preds = %start + %old = load i32, ptr %self, align 4, !noundef !4 + %_6 = call i32 @"_ZN47_$LT$i32$u20$as$u20$core..iter..range..Step$GT$17forward_unchecked17h4944c1e1e44c8861E"(i32 %old, i64 1) + store i32 %_6, ptr %self, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + store i32 %old, ptr %0, align 4 + store i32 1, ptr %_0, align 4 + br label %bb5 + +bb5: ; preds = %bb2, %bb4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !range !5, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_0, i32 0, i32 1 + %4 = load i32, ptr %3, align 4 + %5 = insertvalue { i32, i32 } poison, i32 %2, 0 + %6 = insertvalue { i32, i32 } %5, i32 %4, 1 + ret { i32, i32 } %6 +} + +; Function Attrs: uwtable +define dso_local i32 @input() unnamed_addr #1 { +start: + ret i32 0 +} + +; Function Attrs: uwtable +define dso_local void @log(i32 %i) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @app() unnamed_addr #1 { +start: + %_6 = alloca { i32, i32 }, align 4 + %iter = alloca { i32, i32 }, align 4 + %_3 = alloca { i32, i32 }, align 4 + %x = call i32 @input() + store i32 %x, ptr %_3, align 4 + %0 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + store i32 10, ptr %0, align 4 + %1 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 0 + %2 = load i32, ptr %1, align 4, !noundef !4 + %3 = getelementptr inbounds { i32, i32 }, ptr %_3, i32 0, i32 1 + %4 = load i32, ptr %3, align 4, !noundef !4 + %5 = call { i32, i32 } @"_ZN63_$LT$I$u20$as$u20$core..iter..traits..collect..IntoIterator$GT$9into_iter17h80dc70a24d0c93edE"(i32 %2, i32 %4) + %_2.0 = extractvalue { i32, i32 } %5, 0 + %_2.1 = extractvalue { i32, i32 } %5, 1 + %6 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 0 + store i32 %_2.0, ptr %6, align 4 + %7 = getelementptr inbounds { i32, i32 }, ptr %iter, i32 0, i32 1 + store i32 %_2.1, ptr %7, align 4 + br label %bb3 + +bb3: ; preds = %bb5, %start + %8 = call { i32, i32 } @"_ZN4core4iter5range101_$LT$impl$u20$core..iter..traits..iterator..Iterator$u20$for$u20$core..ops..range..Range$LT$A$GT$$GT$4next17h81d1ae0fa0da4546E"(ptr align 4 %iter) + store { i32, i32 } %8, ptr %_6, align 4 + %9 = load i32, ptr %_6, align 4, !range !5, !noundef !4 + %_8 = zext i32 %9 to i64 + %10 = icmp eq i64 %_8, 0 + br i1 %10, label %bb7, label %bb5 + +bb7: ; preds = %bb3 + call void @Fresh(i32 %x) + ret void + +bb5: ; preds = %bb3 + %11 = getelementptr inbounds { i32, i32 }, ptr %_6, i32 0, i32 1 + %i = load i32, ptr %11, align 4, !noundef !4 + call void @log(i32 %i) + br label %bb3 + +bb6: ; No predecessors! + unreachable +} + +; Function Attrs: uwtable +define internal void @_ZN9example134main17haba30008cc3025a3E() unnamed_addr #1 { +start: + call void @app() + ret void +} + +; Function Attrs: uwtable +define internal void @Fresh(i32 %_var) unnamed_addr #1 { +start: + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_start() unnamed_addr #1 { +start: + %local = load i16, ptr @atomic_depth, align 2, !noundef !4 + call void @start_atomic() + ret void +} + +; Function Attrs: uwtable +define dso_local void @atomic_end() unnamed_addr #1 { +start: + call void @end_atomic() + ret void +} + +; Function Attrs: uwtable +declare i64 @_ZN3std2rt19lang_start_internal17hadaf077a6dd0140bE(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1 + +; Function Attrs: uwtable +declare i32 @rust_eh_personality(i32, i32, i64, ptr, ptr) unnamed_addr #1 + +; Function Attrs: uwtable +declare void @start_atomic() unnamed_addr #1 + +; Function Attrs: uwtable +declare void @end_atomic() unnamed_addr #1 + +define i32 @main(i32 %0, ptr %1) unnamed_addr #3 { +top: + %2 = sext i32 %0 to i64 + %3 = call i64 @_ZN3std2rt10lang_start17h431fe12d2c8c1de6E(ptr @_ZN9example134main17haba30008cc3025a3E, i64 %2, ptr %1, i8 0) + %4 = trunc i64 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #1 = { uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #2 = { inlinehint uwtable "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } +attributes #3 = { "frame-pointer"="non-leaf" "target-cpu"="apple-m1" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 8, !"PIC Level", i32 2} +!1 = !{i32 7, !"PIE Level", i32 2} +!2 = !{!"rustc version 1.73.0 (cc66ad468 2023-10-03)"} +!3 = !{i32 1453209} +!4 = !{} +!5 = !{i32 0, i32 2} diff --git a/benchmarks/tests/example13.rs b/benchmarks/tests/example13.rs new file mode 100644 index 0000000..3748f61 --- /dev/null +++ b/benchmarks/tests/example13.rs @@ -0,0 +1,25 @@ +include!("../intermittent.rs"); + +#[no_mangle] +fn input() -> i32 { + 0 +} + +#[no_mangle] +pub static IO_NAME: fn() -> i32 = input; + +#[no_mangle] +fn log(i: i32) -> () {} + +#[no_mangle] +fn app() -> () { + let x = input(); + for i in x..10 { + log(i); + } + Fresh(x); +} + +fn main() -> () { + app() +} diff --git a/ocelot/AtomicRegionInference/CMakeLists.txt b/ocelot/AtomicRegionInference/CMakeLists.txt index 24e2883..81d46f5 100644 --- a/ocelot/AtomicRegionInference/CMakeLists.txt +++ b/ocelot/AtomicRegionInference/CMakeLists.txt @@ -1,8 +1,22 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.6) +project(InferAtoms) +# LLVM uses C++17. +set(CMAKE_CXX_STANDARD 17) + +# Load LLVMConfig.cmake. If this fails, consider setting `LLVM_DIR` to point +# to your LLVM installation's `lib/cmake/llvm` directory. find_package(LLVM REQUIRED CONFIG) + +# Include the part of LLVM's CMake libraries that defines +# `add_llvm_pass_plugin`. +include(AddLLVM) + +# Use LLVM's preprocessor definitions, include directories, and library search +# paths. add_definitions(${LLVM_DEFINITIONS}) include_directories(${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) -add_subdirectory(src) # Use your pass name here. +# Our pass lives in this subdirectory. +add_subdirectory(src) diff --git a/ocelot/AtomicRegionInference/Makefile b/ocelot/AtomicRegionInference/Makefile new file mode 100644 index 0000000..4dbe6ea --- /dev/null +++ b/ocelot/AtomicRegionInference/Makefile @@ -0,0 +1,102 @@ +.PHONY: clean_tests clean eg1 eg2 eg3 eg4 eg5 eg6 eg7 eg8 eg9 eg10 egr run_eg1 run_eg2 run_eg3 run_eg4 run_eg5 run_eg6 run_eg7 run_eg8 run_eg9 run_eg10 + +all: + make eg1 + make eg2 + make eg3 + make eg4 + make eg5 + make eg6 + make eg7 + make eg8 + make eg9 + make eg10 + make egr + make eg11 + +eg1: + TEST=example01 make test +eg2: + TEST=example02 make test +eg3: + TEST=example03 make test +eg4: + TEST=example04 make test +eg5: + TEST=example05 make test +eg6: + TEST=example06 make test +eg7: + TEST=example07 make test +eg8: + TEST=example08 make test +eg9: + TEST=example09 make test +eg10: + TEST=example10 make test +egr: + TEST=example make testr +eg11: + TEST=example11 make testr +eg12: + TEST=example12 make testr +eg13: + TEST=example13 make testr + +run_eg1: + TEST=example01 make run && ../../benchmarks/tests/example01.out +run_eg2: + TEST=example02 make run && ../../benchmarks/tests/example02.out +run_eg3: + TEST=example03 make run && ../../benchmarks/tests/example03.out +run_eg4: + TEST=example04 make run && ../../benchmarks/tests/example04.out +run_eg5: + TEST=example05 make run && ../../benchmarks/tests/example05.out +run_eg6: + TEST=example06 make run && ../../benchmarks/tests/example06.out +run_eg7: + TEST=example07 make run && ../../benchmarks/tests/example07.out +run_eg8: + TEST=example08 make run && ../../benchmarks/tests/example08.out +run_eg9: + TEST=example09 make run && ../../benchmarks/tests/example09.out +run_eg10: + TEST=example10 make run && ../../benchmarks/tests/example10.out + +test: + $(MAKE) -C build + clang -S -emit-llvm\ + -fno-discard-value-names\ + ../../benchmarks/tests/$(TEST).c\ + -o ../../benchmarks/tests/$(TEST).orig.ll + clang -S -emit-llvm\ + -fpass-plugin=build/src/InferAtomsPass.dylib\ + -fno-discard-value-names\ + ../../benchmarks/tests/$(TEST).c\ + -o ../../benchmarks/tests/$(TEST).ll + +testr: + $(MAKE) -C build + rustc ../../benchmarks/tests/$(TEST).rs --emit llvm-bc -o ../../benchmarks/tests/$(TEST).bc + clang -S -emit-llvm\ + -fno-discard-value-names\ + ../../benchmarks/tests/$(TEST).bc\ + -o ../../benchmarks/tests/$(TEST).orig.ll + clang -S -emit-llvm\ + -fpass-plugin=build/src/InferAtomsPass.dylib\ + -fno-discard-value-names\ + ../../benchmarks/tests/$(TEST).bc\ + -o ../../benchmarks/tests/$(TEST).ll + +run: + $(MAKE) -C build + clang -fpass-plugin=build/src/InferAtomsPass.dylib\ + ../../benchmarks/tests/$(TEST).c\ + -o ../../benchmarks/tests/$(TEST).out + +clean_tests: + find ../../benchmarks/tests -name "*.ll" -exec rm -rf {} \; + +clean: + rm -rf build diff --git a/ocelot/AtomicRegionInference/README.md b/ocelot/AtomicRegionInference/README.md index d9a1c3a..2f9aed8 100644 --- a/ocelot/AtomicRegionInference/README.md +++ b/ocelot/AtomicRegionInference/README.md @@ -1,14 +1,32 @@ -# region-inference-pass +# Atomic Region Inference -LLVM Pass for inferring atomic regions +LLVM Pass for inferring atomic regions. Tested to work with LLVM 17. -Build: +To build the pass: - $ mkdir build - $ cd build - $ cmake .. - $ make +```sh +mkdir build +cd build +cmake .. +make +``` -Run: +You may bootstrap Clang to use the pass to compile a C file like so (run in the +same directory as this README): - $ opt -load build/src/libInferAtomicPass.so -atomize something.bc +```sh +clang -S -emit-llvm -fpass-plugin=build/src/InferAtomsPass.dylib -fno-discard-value-names ../../benchmarks/ctests/example03.c +``` + +Or, use the shortcuts provided in the Makefile (e.g., `make eg3`), which produce +two LLVM IRs with and without the pass enabled. + +Actually link and produce executable by running: + +```sh +clang -fpass-plugin=build/src/InferAtomsPass.dylib ../../benchmarks/ctests/example03.c -o ../../benchmarks/ctests/example03.out + +../../benchmarks/ctests/example03.out +``` + +Or, use the equivalent shortcut `make run_eg3 && ../../benchmarks/ctests/example03.out`. diff --git a/ocelot/AtomicRegionInference/src/CMakeLists.txt b/ocelot/AtomicRegionInference/src/CMakeLists.txt index 03033ee..e44f56e 100644 --- a/ocelot/AtomicRegionInference/src/CMakeLists.txt +++ b/ocelot/AtomicRegionInference/src/CMakeLists.txt @@ -1,23 +1,7 @@ -add_library(InferAtomicPass MODULE +add_llvm_pass_plugin(InferAtomsPass # List your source files here. - InferAtomicPass.cpp - ConsistentInference.cpp + InferAtoms.cpp TaintTracker.cpp + InferFreshCons.cpp + Helpers.cpp ) - -# Use C++11 to compile our pass (i.e., supply -std=c++11). -target_compile_features(InferAtomicPass PRIVATE cxx_range_for cxx_auto_type) - -# LLVM is (typically) built with no C++ RTTI. We need to match that; -# otherwise, we'll get linker errors about missing RTTI data. -set_target_properties(InferAtomicPass PROPERTIES - COMPILE_FLAGS "-fno-rtti" -) - -# Get proper shared-library behavior (where symbols are not necessarily -# resolved when the shared library is linked) on OS X. -if(APPLE) - set_target_properties(InferAtomicPass PROPERTIES - LINK_FLAGS "-undefined dynamic_lookup" - ) -endif(APPLE) diff --git a/ocelot/AtomicRegionInference/src/ConsistentInference.cpp b/ocelot/AtomicRegionInference/src/ConsistentInference.cpp deleted file mode 100644 index f59be4b..0000000 --- a/ocelot/AtomicRegionInference/src/ConsistentInference.cpp +++ /dev/null @@ -1,505 +0,0 @@ -#include "include/ConsistentInference.h" - -#define DEBUGINFER 0 -//Come back to this. it can crash and if pass not run with debug, shouldn't be needed -#if 0 -namespace { - - // Find closest debug info. Note that LLVM throws fatal error if we don't add debug info -// to call instructions that we insert (if the parent function has debug info). -DebugLoc findClosestDebugLoc(Instruction *instr) -{ - - DIScope *scope = instr->getFunction()->getSubprogram(); - Instruction *instrWithDebugLoc = instr; - while (!instrWithDebugLoc->getDebugLoc() && instrWithDebugLoc->getPrevNode() != NULL) - instrWithDebugLoc = instrWithDebugLoc->getPrevNode(); - if (instrWithDebugLoc->getDebugLoc()) // if found an instruction with info, use that info - return DebugLoc(instrWithDebugLoc->getDebugLoc()); - else // use the parent function's info (can't see any better source) - return DebugLoc::get(instr->getFunction()->getSubprogram()->getLine(), /* col */ 0, scope); -} - -} // namespace anon -#endif -using namespace std; -using namespace llvm; -Instruction* ConsistentInference::insertRegionInst(int toInsertType, Instruction* insertBefore) { - - Instruction* call; - IRBuilder<> builder(insertBefore); - //build and insert a region start inst - if (toInsertType == 0) { - //Constant* c = M->getOrInsertFunction(""); - call = builder.CreateCall(atomStart); - #if DEBUGINFER - errs() << "create start\n"; - #endif - } else { - //build and insert a region start inst - #if DEBUGINFER - errs() << "Inserting end at: "<< *insertBefore<<"\n"; - #endif - call = builder.CreateCall(atomEnd); - #if DEBUGINFER - errs() << "create end\n"; - #endif - } - return call; -} - -//if a direct pred is also a successor, then it's a for loop block -bool ConsistentInference::loopCheck(BasicBlock* bb) { - StringRef bbname = bb->getName().drop_front(2); - if (!bb->hasNPredecessors(1)) { - for (auto it = pred_begin(bb), et = pred_end(bb); it != et; ++it) { - BasicBlock* predecessor = *it; - StringRef pname = predecessor->getName().drop_front(2); - // errs() << "comparing " << pname<< " and " < 0) { - // errs() << "comparison is true\n"; - return true; - } - } - } - return false; -} - - -//find the first block after a for loop -BasicBlock* ConsistentInference::getLoopEnd(BasicBlock* bb) { - Instruction* ti = bb->getTerminator(); - BasicBlock* end = ti->getSuccessor(0); - ti = end->getTerminator(); - // errs() << "end is " << end->getName() << "\n"; - //for switch inst, succ 0 is the fall through - end = ti->getSuccessor(1); - // errs() << "end is " << end->getName() << "\n"; - return end; -} - -/*Top level region inference function -- could flatten later*/ -void ConsistentInference::inferConsistent(std::map allSets) -{ - //TODO: start with pseudo code structure from design doc - for( auto map : allSets ) { - #if DEBUGINFER - errs() << "DEBUGINFER: starting set " << map.first << "\n"; - #endif - addRegion(map.second, 0); - } - -} - -/*The only difference is outer map vs outer vec*/ -void ConsistentInference::inferFresh(inst_vec_vec allSets) -{ - //TODO: start with pseudo code structure from design doc - for( auto singleVec : allSets ) { - addRegion(singleVec, 1); - } - -} - -//Region type: 0 for Con, 1 for fresh -void ConsistentInference::addRegion(inst_vec conSet, int regionType) -{ - //construct a map of set item to bb - map blocks; - //a queue for regions that still need to be processed - queue> regionsNeeded; - - for(Instruction* item : conSet) { - blocks[item] = item->getParent(); - } - - regionsNeeded.push(blocks); - - Function* root; - for (Function& f : *m) { - if (f.getName().equals("app")) { - root = &f; - } - } - - //iterate until no more possible regions - //THEN pick the best one - vector> regionsFound; - while (!regionsNeeded.empty()) { - //need to raise all blocks in the map until - //they are the same - map blockMap = regionsNeeded.front(); - regionsNeeded.pop(); - //record which functions have been travelled through - set nested; - - while (!sameFunction(blockMap)) { - //to think on: does this change? - Function* goal = commonPredecessor(blockMap, root); - for (Instruction* item : conSet) { - //not all blocks need to be moved up - Function* currFunc = blockMap[item]->getParent(); - nested.insert(currFunc); - if(currFunc!=goal) { - - //if more than one call: - //callChain info is already in the starting set - //so only explore a caller if it's in conSet - bool first = true; - for(User* use : currFunc->users()) { - //if (regionType == 1) { - if(! (find(conSet.begin(), conSet.end(), use)!=conSet.end())) { - continue; - } - //errs() << "Use: "<< *use << " is in call chain\n"; - //} - Instruction* inst = dyn_cast(use); - #if DEBUGINFER - errs() << "DEBUGINFER: examining use: "<< *inst<<"\n"; - #endif - if (inst == NULL) { - //errs () <<"ERROR: use " << *use << "not an instruction\n"; - break; - } - //update the original map - if (first) { - blockMap[item] = inst->getParent(); - first = false; - } else { - //copy the blockmap, update, add to queue - Instruction* inst = dyn_cast(use); - map copy; - for(auto map : blockMap) { - copy[map.first] = map.second; - } - copy[item] = inst->getParent(); - regionsNeeded.push(copy); - } - }//end forall uses - }//end currFunc check - }//end forall items - }//end same function check - - - - /**Now, all bb in the map are in the same function, so we can run - * dom or post-dom analysis on that function**/ - #if DEBUGINFER - errs() << "DEBUGINFER: start dom tree analysis\n"; - #endif - Function* home = blockMap.begin()->second->getParent(); - if(home == nullptr) { - #if DEBUGINFER - errs() << "DEBUGINFER: no function found\n"; - #endif - continue; - } - DominatorTree& domTree = pass->getAnalysis(*home).getDomTree(); - //Find the closest point that dominates - BasicBlock* startDom = blockMap.begin()->second; - for (auto map : blockMap) { - startDom = domTree.findNearestCommonDominator(map.second, startDom); - } - //TODO: if an inst in the set is in the bb, we can truncate? - #if DEBUGINFER - errs() << "DEBUGINFER: start post dom tree analysis\n"; - #endif - //Flip directions for the region end - PostDominatorTree& postDomTree = pass->getAnalysis(*home).getPostDomTree(); - //Find the closest point that dominates - BasicBlock* endDom = blockMap.begin()->second; - for (auto map : blockMap) { - #if DEBUGINFER - if (endDom!=nullptr) { - errs() << "finding post dom of:" << map.second->getName()<< " and " << endDom->getName()<< "\n"; - } else { - errs() << "endDom is null\n"; - } - #endif - endDom = postDomTree.findNearestCommonDominator(map.second, endDom); - } - if (startDom==nullptr) { - errs() << "ERROR: null start\n"; - } else if (endDom==nullptr) { - errs() << "ERROR: null end\n"; - } - #if DEBUGINFER - errs() << "DEBUGINFER: match scope\n"; - #endif - //need to make the start and end dominate each other as well. - startDom = domTree.findNearestCommonDominator(startDom, endDom); - endDom = postDomTree.findNearestCommonDominator(startDom, endDom); - - //extra check to disallow loop conditional block as the end - if(loopCheck(endDom)) { - endDom = getLoopEnd(endDom); - } - - - - if (startDom==nullptr) { - errs() << "ERROR: null start after scope merge\n"; - } else if (endDom==nullptr) { - errs() << "ERROR: null end after scope merge\n"; - } -#if DEBUGINFER - errs() << "DEBUGINFER: insert insts\n"; -#endif - //TODO: fallback if endDom is null? Need hyper-blocks, I think - //possibly can do a truncation check, to lessen the size a little, but could that interfere with compiler optimizations? - Instruction* regionStart = truncate(startDom, true, conSet, nested); - Instruction* regionEnd = truncate(endDom, false, conSet, nested); - if (regionStart==nullptr) { - errs() << "ERROR: null start after truncation\n"; - } else if (regionEnd==nullptr) { - errs() << "ERROR: null end after truncation\n"; - } else { - //errs() << "Region start is before " << *regionStart<<" and region end is before " << *regionEnd<<"\n"; - } - - //insert into regions found - regionsFound.push_back(make_pair(regionStart, regionEnd)); - }//end while regions needed - - //now see which region is smallest -- instruction count? they must dominate - //each other, so there's no possibility of not running into the start from - //the end - pair smallestReg = findSmallest(regionsFound); - //errs() << "Smallest Region was " << *smallestReg.first<< " and " << *smallestReg.second <<"\n"; - Instruction* regionStart = smallestReg.first; - Instruction* regionEnd = smallestReg.second; - insertRegionInst(0, regionStart); - insertRegionInst(1, regionEnd); - //}//end while regions needed -} - -/*Function to truncate a bb if the instruction is in the bb */ -Instruction* ConsistentInference::truncate(BasicBlock* bb, bool forwards, inst_vec conSet, set nested) -{ - //truncate the front - if(forwards) { - for (Instruction& inst : *bb) { - //stop at first inst in the basic block that is in the set. - if (find(conSet.begin(), conSet.end(), &inst)!=conSet.end()){ - return &inst; - } - //need to stop at relevant callIsnsts as well - else if (CallInst* ci = dyn_cast(&inst)){ - if (nested.find(ci->getCalledFunction())!=nested.end()) { - return &inst; - } - } - - } - //otherwise just return the last inst - return &bb->back(); - } - //reverse directions if not forwards - Instruction* prev = NULL; - for(BasicBlock::reverse_iterator i = bb->rbegin(), e = bb->rend(); i!=e;++i) { - Instruction* inst = &*i; - if (find(conSet.begin(), conSet.end(), inst)!=conSet.end()){ - //need to return the previous inst (next in fowards), as it should be inserted before the returned inst - - if (prev == NULL) { - //only happens if use is a ret inst, which is a scope use to make the branching - //work, not an actual one, so this is safe - return inst; - } - return prev; - } - else if (CallInst* ci = dyn_cast(inst)){ - if (nested.find(ci->getCalledFunction())!=nested.end()) { - return prev; - } - } - prev = inst; - } - //otherwise just return first inst of the block - //errs() << "truncate returning " << bb->front() << "\n"; - return &bb->front(); -} - - -Function* ConsistentInference::commonPredecessor(map blockMap, Function* root) -{ - vector funcList; - //add the parents, without duplicates - for (auto map : blockMap) { - if(!(find(funcList.begin(), funcList.end(), map.second->getParent())!=funcList.end())) { - funcList.push_back(map.second->getParent()); - #if DEBUGINFER - errs() << "DEBUGINFER: adding: " << map.second->getParent()->getName()<<"\n"; - #endif - } - } - //easy case: everything is already in the same function - if(funcList.size()==1) { - return funcList.at(0); - } - /* Algo Goal: get the deepest function that still calls (or is) all funcs in funcList. - * Consider: multiple calls? Should be dealt with in the add region function -- eventually each caller - * gets its own region - */ - Function* goal = nullptr; - //Function* root = m->getFunction("app"); - #if DEBUGINFER - errs() << "DEBUGINFER: starting from " << root->getName() << "\n"; - #endif - deepCaller(root, funcList, &goal); - if(goal == nullptr) { - errs() << "ERROR: deepCaller failed\n"; - } - return goal; -} - -/*Recursive: from a root, returns list of called funcs. */ -vector ConsistentInference::deepCaller(Function* root, vector funcList, Function** goal) -{ - vector calledFuncs; - bool mustIncludeSelf = false; - - for (inst_iterator inst = inst_begin(root), E = inst_end(root); inst != E; ++inst) { - if(CallInst* ci = dyn_cast(&(*inst))) { - calledFuncs.push_back(ci->getCalledFunction()); - } - } - vector explorationList; - for (Function* item : funcList) { - - //skip over root or called funcs - if ((find(calledFuncs.begin(), calledFuncs.end(), item)!=calledFuncs.end()) || item == root) { - if (item == root) { - mustIncludeSelf = true; - } - continue; - } - explorationList.push_back(item); - #if DEBUGINFER - errs() << "need to find " << item->getName() <<"\n"; - #endif - } - //this function is a root of a call tree that calls everything in the func List - if (explorationList.empty()) { - #if DEBUGINFER - errs() << "empty list\n"; - #endif - *goal = root; - return calledFuncs; - } - //otherwise recurse - Function* candidate = nullptr; - for (Function* called : calledFuncs) { - vector partial = deepCaller(called, explorationList, &candidate); - //if candidate is set, it means called is a root for everything in the explorationList - if (candidate!=nullptr) { - *goal = candidate; - #if DEBUGINFER - errs() << "New candidate: " << (*goal)->getName() << "\n"; - #endif - } - //remove from explorationList, but add to calledFuncs - for (Function* item : partial) { - func_vec::iterator place = find(explorationList.begin(), explorationList.end(), item); - if(place!=explorationList.end()) { - explorationList.erase(place); - } - calledFuncs.push_back(item); - } - - } - //current point is a root - if(explorationList.empty()) { - //not the deepest - if (candidate!=nullptr && !mustIncludeSelf) { - *goal = candidate; - } else { - //is the deepest - *goal = root; - } - } - return calledFuncs; -} - - - - -/*Recursive: get the min of the maximum length of each regions*/ -inst_inst_pair ConsistentInference::findSmallest(vectorregionsFound) -{ - inst_inst_pair best; - int best_count = 2147483647; - - for (inst_inst_pair candidate : regionsFound) { - Function* root = candidate.first->getFunction(); - int pre = 0 ; - int found = 0; - for (Instruction& inst : *candidate.first->getParent()) { - pre++; - if (&inst==candidate.first) { - break; - - } - } - //get the max length from the bb to the end instruction - vector v; - int length = getSubLength(candidate.first->getParent(), candidate.second, v); - //substract the prefix before the start inst - length -= pre; - if (length < best_count) { - best_count = length; - best = candidate; - //errs() << "best candidate is " << *candidate.first << " and " << - // *candidate.second << " with length " << length << "\n"; - } - - } - return best; -} -//helper func, recursive -int ConsistentInference::getSubLength(BasicBlock* bb, Instruction* end, vector visited){ - int count = 0; - int max_ret = 0; - visited.push_back(bb); - for (Instruction& inst : *bb) { - count++; - if (&inst == end){ - return count; - } - if(CallInst* ci = dyn_cast(&inst)){ - Function* cf = ci->getCalledFunction(); - if (!cf->empty() && cf!=NULL) { - //errs() <<"attempting function " << cf->getName() << "\n"; - count+= cf->getInstructionCount(); - } - } - if (inst.isTerminator()) { - int numS = inst.getNumSuccessors(); - for (int i = 0; i < numS; i++) { - BasicBlock* next = inst.getSuccessor(i); - //already counted -- do something more fancy for loops? - if (find(visited.begin(), visited.end(), next)!=visited.end()) { - continue; - } - int intermed = getSubLength(inst.getSuccessor(i), end, visited); - if (intermed > max_ret) { - max_ret = intermed; - } - } - } - } - return count + max_ret; -} - -bool ConsistentInference::sameFunction(map blockMap) -{ - Function* comp = blockMap.begin()->second->getParent(); - for (auto map : blockMap) { - if (map.second->getParent()!= comp) { - return false; - } - } - return true; -} - - diff --git a/ocelot/AtomicRegionInference/src/Helpers.cpp b/ocelot/AtomicRegionInference/src/Helpers.cpp new file mode 100644 index 0000000..d71bf11 --- /dev/null +++ b/ocelot/AtomicRegionInference/src/Helpers.cpp @@ -0,0 +1,89 @@ +#include "include/Helpers.h" + +std::string getSimpleNodeLabel(const Value* node) { + if (node->hasName()) { + return node->getName().str(); + } + + std::string str; + raw_string_ostream OS(str); + + node->printAsOperand(OS, false); + return str; +} + +bool isAnnot(const StringRef annotName) { + return annotName.equals("Fresh") || annotName.equals("Consistent") || annotName.equals("FreshConsistent"); +} + +void printInstInsts(const inst_insts_map& iim, bool onlyCalls) { + for (auto& [inst, inputs] : iim) { + if (!onlyCalls || isa(inst)) { + errs() << *inst << " ->\n"; + for (auto* input : inputs) errs() << *input << "\n"; + errs() << "\n"; + } + } +} + +void printInsts(const inst_vec& iv) { + for (auto& inst : iv) { + errs() << *inst << "\n"; + } +} + +void printIntInsts(const std::map& iim) { + for (auto& [id, insts] : iim) { + errs() << id << " ->\n"; + printInsts(insts); + errs() << "\n"; + } +} + +/** + * Given a freshly cloned basic block, repair references among its + * instructions based on a mapping from the original instructions + * to their clones. + * + * @param block The cloned basic block + * @param clonedInsts The mapping from original to cloned instructions + */ +void patchClonedBlock(BasicBlock* block, inst_inst_map clonedInsts) { + for (auto& I : *block) { + if (isa(I) || isa(I)) { + auto* inst = dyn_cast(&I); + for (int i = 0; i < inst->getNumOperands(); i++) { + auto* operand = dyn_cast(inst->getOperand(i)); + if (operand != nullptr) { + inst_inst_map::iterator it = clonedInsts.find(operand); + if (it != clonedInsts.end()) inst->setOperand(i, it->second); + } + } + } else if (auto* li = dyn_cast(&I)) { + auto* ptr = dyn_cast(li->getPointerOperand()); + inst_inst_map::iterator it = clonedInsts.find(ptr); + if (it != clonedInsts.end()) li->setOperand(0, it->second); + } else if (auto* bi = dyn_cast(&I)) { + for (unsigned i = 0; i < bi->getNumOperands(); i++) { + auto* operand = dyn_cast(bi->getOperand(i)); + inst_inst_map::iterator it = clonedInsts.find(operand); + if (it != clonedInsts.end()) bi->setOperand(i, it->second); + } + } else if (auto* ci = dyn_cast(&I)) { + // The last operand is the called function + for (unsigned i = 0; i < ci->getNumOperands() - 1; i++) { + auto* arg = dyn_cast(ci->getOperand(i)); + inst_inst_map::iterator it = clonedInsts.find(arg); + if (it != clonedInsts.end()) ci->setOperand(i, it->second); + } + } else if (auto* ci = dyn_cast(&I)) { + auto* cond = dyn_cast(ci->getOperand(0)); + inst_inst_map::iterator it = clonedInsts.find(cond); + if (it != clonedInsts.end()) ci->setOperand(0, it->second); + } else if (auto* ei = dyn_cast(&I)) { + auto* operand = dyn_cast(ei->getOperand(0)); + inst_inst_map::iterator it = clonedInsts.find(operand); + if (it != clonedInsts.end()) ei->setOperand(0, it->second); + } + } +} diff --git a/ocelot/AtomicRegionInference/src/InferAtomicPass.cpp b/ocelot/AtomicRegionInference/src/InferAtomicPass.cpp deleted file mode 100644 index a105841..0000000 --- a/ocelot/AtomicRegionInference/src/InferAtomicPass.cpp +++ /dev/null @@ -1,516 +0,0 @@ -#include "include/InferAtomicPass.h" -#include "include/TaintTracker.h" - -#define CAPSIZE 1000 -#define PRINTMAPS 1 -#define FRESHDEBUG 1 - -void InferAtomicModulePass::removeAnnotations(inst_vec* toDelete) -{ - //delete all the annotation function calls - bool instsLeftToDelete = true; - Instruction* candidate; - while (instsLeftToDelete) { - instsLeftToDelete = false; - //can't delete while directly iterating through the module - for (Function& f : *this->m) { - for (BasicBlock& bb : f) { - for (Instruction& inst : bb) { - - //for now, let's just delete unused core or compiler builtin functions - if(isa(&inst)) { - if (find(toDelete->begin(), toDelete->end(), &inst)!=toDelete->end()) { - candidate = &inst; - instsLeftToDelete = true; - break; - } - } - } - } - } - //recheck, as this could be the last iteration - if(instsLeftToDelete) { - #if DEBUG - errs() << "DEBUG: deleting: " << candidate->getName() <<"\n"; - #endif - candidate->replaceAllUsesWith(UndefValue::get(candidate->getType())); - candidate->eraseFromParent(); - } - - } - //now delete all the annotation functions - //vector toDeleteF; - bool functionsLeftToDelete = true; - Function* candidatef; - while (functionsLeftToDelete) { - functionsLeftToDelete = false; - //can't delete while directly iterating through the module - for (Function& f : *this->m) { - if (f.hasName()) { - //for now, let's just delete unused core or compiler builtin functions - if(f.getName().contains("Fresh")||f.getName().contains("Consistent")) { - candidatef = &f; - functionsLeftToDelete = true; - break; - - } - } - - } - - //recheck, as this could be the last iteration - if(functionsLeftToDelete) { -#if DEBUG - errs() << "DEBUG: deleting: " << candidatef->getName() <<"\n"; -#endif - - candidatef->replaceAllUsesWith(UndefValue::get(candidatef->getType())); - candidatef->eraseFromParent(); - } - } -} - -/* - * Top-level pass for atomic region inference - */ -bool InferAtomicModulePass::runOnModule(Module &M) { - m = &M; - capacitorSize = CAPSIZE; - - //TODO: init atomStart/End with the proper functions - for (Function& F : M) { - if (F.getName().contains("atomic_start")) { - #if DEBUG - errs() << "DEBUG: found atom start\n"; - #endif - atomStart = &F; - } - if (F.getName().contains("atomic_end")) { - #if DEBUG - errs() << "DEBUG: found atom end\n"; - #endif - atomEnd = &F; - } - } - - //Build the consistent set and fresh lists here, to only - //go through all the declarations once. - std::map conVars; - inst_vec_vec freshVars; - inst_insts_map inputInfo = buildInputs(m); - inst_vec toDelete; - getAnnotations(&conVars, &freshVars, inputInfo, &toDelete); - //TODO: need to add unique point of call chain prefix to con set - #if PRINTMAPS - errs () << "Initial fresh is: \n"; - for (inst_vec item : freshVars) { - for (Instruction* item2 : item) { - errs() << *item2 << "\n"; - } - } - errs() << "End init fresh\n"; - #endif - - #if PRINTMAPS - errs () << "Initial consistent is: \n"; - for (auto map : conVars) { - errs() << "Begin set\n"; - for (Instruction* item2 : map.second) { - errs() << *item2 << "\n"; - } - } - errs() << "End init Consistent\n"; - #endif - - #if PRINTMAPS - errs() << "Printing map:\n"; - for (auto map : inputInfo) { - if (isa(map.first)) { - errs() << *(map.first) << "in map\n"; - for (Value* l : map.second) { - errs() << *l << "\n"; - } - } - } - #endif - map allConSets = collectCon(conVars, inputInfo); - inst_vec_vec allFresh = collectFresh(freshVars, inputInfo); - - - - #if PRINTMAPS - errs () << "Fresh is: \n"; - for (inst_vec item : allFresh) { - for (Instruction* item2 : item) { - errs() << *item2 << "\n"; - } - } - errs() << "End fresh\n"; - #endif - - #if PRINTMAPS - errs () << "Consistent is: \n"; - for (auto map : allConSets) { - for (Instruction* item2 : map.second) { - errs() << *item2 << "\n"; - } - } - errs() << "End Consistent\n"; - #endif - - - - //will do consistency first - ConsistentInference* ci = new ConsistentInference(this, &M, atomStart, atomEnd); - - ci->inferConsistent(allConSets); - ci->inferFresh(allFresh); - - //delete annotations - removeAnnotations(&toDelete); - - return true; -} - - -/**This function finds annotated variables)**/ -void InferAtomicModulePass::getAnnotations(std::map* conSets, inst_vec_vec* freshVars, - inst_insts_map inputMap, inst_vec* toDelete) -{ - //note: delete the annotation functions afterwards - map recallSet; - - for (Function& f : *m) { - for (BasicBlock& bb : f) { - for (Instruction& inst : bb) { - if(CallInst* ci = dyn_cast(&inst)) { - Function* called = ci->getCalledFunction(); - //various empty or null checks - if (called==NULL) { - continue; - } - if (called->empty()||!called->hasName()) { - continue; - } - //covers both Consistent and FreshConsistent - if (called->getName().contains("Consistent")) { - //first para is var, second is id - toDelete->push_back(ci); - int setID; - //v.push_back(ai); <<-- don't actually need this? - //bit cast use of x, then value operand of store - Instruction* var = dyn_cast(ci->getOperand(0)); - - if (var==NULL) { - //errs() << "error casting with " << *ci <<"\n"; - continue; - } - // errs() << "New consistent annot. with " << *var<<"\n"; - Value* id = ci->getOperand(1); - if(ConstantInt* cint = dyn_cast(id)) { - setID = cint->getSExtValue(); - } - queue customUsers; - set v; - //v.emplace(ci); - //in case var itself is iOp - for (Instruction* iOp : inputMap[var]) { - v.emplace(iOp); - } - - //customUsers.push(var); - for (Value* use : var->users()) { - //don't push the annotation - if (use == ci) { - continue; - } - //errs() << "DEBUG: pushing use of var: " << *use << "\n"; - customUsers.push(use); - } - while(!customUsers.empty()) { - Value* use = customUsers.front(); - customUsers.pop(); - //errs() << "DEBUG: use is " << *use << " of var " << *var<<"\n"; - if (Instruction* instUse = dyn_cast(use)) { - for (Instruction* iOp : inputMap[instUse]) { - v.emplace(iOp); - // errs() << "DEBUG: adding to v " << *iOp << "\n"; - } - } - if(isa(use)||isa(use)) { - for (Value* use2 : use->users()) { - // errs() << "DEBUG: use2 is " << *use2 << "\n"; - if(StoreInst* si = dyn_cast(use2)){ - for (Instruction* iOp : inputMap[si]) { - v.emplace(iOp); - // errs() << "DEBUG: adding to v " << *iOp << "\n"; - } - } - // errs() << "DEBUG: pushing use2 of var: " << *use2 << "\n"; - customUsers.push(use2); - } - } - - if(isa(use)) { - for (Value* use2 : use->users()) { - // errs() << "DEBUG: use2 is " << *use2 << "\n"; - if(StoreInst* si = dyn_cast(use2)){ - //v.push_back(si); - for (Instruction* iOp : inputMap[si]) { - v.emplace(iOp); - // errs() << "DEBUG: adding to v " << *iOp << "\n"; - } - } - // errs() << "DEBUG: pushing use2 of var: " << *use2 << "\n"; - customUsers.push(use2); - } - } - } - //last case - if (v.empty()) { - //some entries have a first link with ci, not var - - for (Instruction* iOp : inputMap[ci]) { - if (inputMap[ci].size() == 1) { - for (Instruction* origLink : inputMap[iOp]) { - v.emplace(origLink); - } - } else { - v.emplace(iOp); - } - - } - - - } - //for later deletion purposes - inputMap.erase(ci); - - - if (!v.empty()) { - inst_vec temp; - for (Instruction* item : v) { - temp.push_back(item); - } - //add the collected list to the map - if(conSets->find(setID)!=conSets->end()) { - conSets->at(setID).insert(conSets->at(setID).end(), temp.begin(), temp.end()); - } else { - conSets->emplace(setID, temp); - } - } - - } - if (called->getName().contains("Fresh")) { - set v; - toDelete->push_back(ci); - inputMap.erase(ci); - Value* var = ci->getOperand(0); - if (Instruction* inst = dyn_cast(var)) { - v.emplace(inst); - } else { - //errs() << "error casting\n"; - } - //errs() << "New Fresh annot. with " << *var<<"\n"; - // v.push_back(ci); - - for(Value* use : var->users()) { - if(StoreInst* si = dyn_cast(use)){ - // errs() << "DEBUG: pushing " << *use << "\n"; - v.emplace(si); - } - if(isa(use)) { - for (Value* use2 : use->users()) { - // errs() << "DEBUG: pushing " << *use2 << "\n"; - if(StoreInst* si = dyn_cast(use2)){ - v.emplace(si); - } - } - } - } - if (!v.empty()) { - inst_vec temp; - for (Instruction* item : v) { - temp.push_back(item); - } - freshVars->push_back(temp); - } - } - - } - - } - } - } - -} - - - - -/*Given the starting point annotations of conSets, find the -deepest unique point of the call chain*/ -map InferAtomicModulePass::collectCon(map startingPoints, inst_insts_map inputMap) -{ - map toReturn; - for (pair iv : startingPoints ) { - set unique; - map> callChains; - //each item should be the starting point from a different annot - for(Instruction* item : iv.second) { - #if FRESHDEBUG - errs() << "Starting point: " << *item << "\n"; - #endif - //add self to call chain - callChains[item].insert(item); - - for (Instruction* iOp : inputMap[item]) { - // unique.insert(iOp); - callChains[item].insert(iOp); - queue toExplore; - toExplore.push(iOp); - while (!toExplore.empty()) { - Instruction* curr = toExplore.front(); - toExplore.pop(); - for (Instruction* intermed : inputMap[curr]) { - if (! (find(callChains[item].begin(), callChains[item].end(), intermed) - !=callChains[item].end())) { - callChains[item].insert(intermed); - toExplore.push(intermed); - } - } - } - - }// finish constructing call chain for one annot. in the set - - }//constructed call chains for ALL annot. in the set. - //now check the call chain - - //int index = 0; - //map foundUniquePoint; - //clean up the call chains - - for(auto ccmap : callChains) { - for (Instruction* possibility : ccmap.second) { - //if the link is in the same function, then continue - //errs() << "examining possibility: " << *possibility << "\n"; - bool sf = false; - for (Instruction* link : inputMap[possibility]) { - //errs() << "next link is" << *link << "\n"; - if ((link!=possibility) && link->getFunction() == possibility->getFunction()) { - sf = true; - - } - } - if (sf) { - continue; - } - bool isUnique = true; - for (auto ccmapNest : callChains) { - //if self then skip - if (ccmapNest == ccmap) { - continue; - } - //otherwise check if this map also contains the possibility - if (find(ccmapNest.second.begin(), ccmapNest.second.end(), possibility) - != ccmapNest.second.end()) - { - isUnique = false; - break; - } - } - if (isUnique){ - unique.insert(possibility); - // errs() << "Found unique!" << *possibility << "\n"; - } else { - //try another poss. - continue; - } - } - } - - - inst_vec v; - for (Instruction* item2 : unique) { - if (!isa(item2)) { - v.push_back(item2); - } - } - toReturn[iv.first] = v; - }//end starting point check - - return toReturn; -} - -/*This function collects the input srcs and uses off of the fresh annotated vars*/ -inst_vec_vec InferAtomicModulePass::collectFresh(inst_vec_vec startingPoints, inst_insts_map inputMap) -{ - inst_vec_vec toReturn; - - for (inst_vec iv : startingPoints ) { - set unique; - set callChain; - for(Instruction* item : iv) { - #if FRESHDEBUG - errs() << "Starting point: " << *item << "\n"; - #endif - //uses (forwards) are direct only (might need a little chaining for direct in rs to be direct in IR) - inst_vec uses = traverseDirectUses(item); - - for (Instruction* use : uses) { - #if FRESHDEBUG - errs() << "Starting point use: " << *use << "\n"; - #endif - // if (isa(use)||isa(use)) { - unique.insert(use); - //} - for (Instruction* iOp : inputMap[use]) { - unique.insert(iOp); - } - } - - for (Instruction* iOp : inputMap[item]) { - unique.insert(iOp); - callChain.insert(iOp); - queue toExplore; - toExplore.push(iOp); - while (!toExplore.empty()) { - Instruction* curr = toExplore.front(); - toExplore.pop(); - for (Instruction* intermed : inputMap[curr]) { - if (! (find(callChain.begin(), callChain.end(), intermed)!=callChain.end())) { - callChain.insert(intermed); - toExplore.push(intermed); - } - } - } - - } - //don't forget the item itself - if (isa(item)||isa(item)) { - unique.insert(item); - } - - - } - //now construct the call chain - for (Instruction* vv : callChain) { - // errs() << "call chain val: " << *vv <<"\n"; - unique.insert(vv); - } - inst_vec v; - for (Instruction* item2 : unique) { - if (!isa(item2)) { - v.push_back(item2); - } - } - toReturn.push_back(v); - } - - - return toReturn; -} - -char InferAtomicModulePass::ID = 0; - -RegisterPass X("atomize", "Infer Atomic Pass"); diff --git a/ocelot/AtomicRegionInference/src/InferAtoms.cpp b/ocelot/AtomicRegionInference/src/InferAtoms.cpp new file mode 100644 index 0000000..445b578 --- /dev/null +++ b/ocelot/AtomicRegionInference/src/InferAtoms.cpp @@ -0,0 +1,674 @@ +#include "include/InferAtoms.h" + +#define CAPSIZE 1000 + +// Top-level pass for atomic region inference +PreservedAnalyses InferAtomsPass::run(Module& M, ModuleAnalysisManager& AM) { + PassBuilder PB; + FunctionAnalysisManager FAM; + PB.registerFunctionAnalyses(FAM); + + setModule(&M); + + for (auto& F : M) { + auto FName = F.getName(); + if (FName.equals("atomic_start")) { +#if DEBUG + errs() << "Found atomic_start\n"; +#endif + atomStart = &F; + } else if (FName.equals("atomic_end")) { +#if DEBUG + errs() << "Found atomic_end\n"; +#endif + atomEnd = &F; + } + } + + // Build the consistent set and fresh lists here, + // to only go through all the declarations once. + std::map consVars; + inst_vec_vec freshVars; + auto [inputMap, inputInsts] = buildInputs(this->M); + errs() << "inputMap:\n"; + printInstInsts(inputMap); + inst_vec toDeleteAnnots; + getAnnotations(&consVars, &freshVars, inputMap, &toDeleteAnnots); + // TODO: Need to add unique point of call chain prefix to cons set + +#if DEBUG + errs() << "Initial Consistent:\n"; + for (auto& [_, insts] : consVars) { + for (auto* inst : insts) errs() << *inst << "\n"; + } +#endif + +#if DEBUG + errs() << "Initial Fresh:\n"; + for (auto& insts : freshVars) + for (auto* inst : insts) errs() << *inst << "\n"; +#endif + + // #if DEBUG + // errs() << "Print inputMap CallInst entries:\n"; + // printInstInsts(inputMap, true); + // #endif + + auto allConsSets = collectCons(consVars, inputMap); + auto allFresh = collectFresh(freshVars, inputMap); + +#if DEBUG + errs() << "Fresh sets after collect: \n"; + for (auto& freshSet : allFresh) + for (auto* inst : freshSet) errs() << *inst << "\n"; +#endif + +#if DEBUG + errs() << "Cons. sets after collect: \n"; + for (auto& [_, insts] : allConsSets) + for (auto* inst : insts) errs() << *inst << "\n"; +#endif + + // Consistent first + InferFreshCons* ci = new InferFreshCons(&FAM, &M, atomStart, atomEnd); + + ci->inferCons(allConsSets, &allFresh, &toDeleteAnnots, &inputInsts); + ci->inferFresh(allFresh, &allConsSets, &toDeleteAnnots, &inputInsts); + + // Delete annotations + removeAnnotations(toDeleteAnnots); + + return PreservedAnalyses::none(); +} + +// Finds *all* variables affected by annotation +void InferAtomsPass::getAnnotations(std::map* consVars, inst_vec_vec* freshVars, + inst_insts_map inputMap, inst_vec* toDelete) { +#if DEBUG + errs() << "=== getAnnotations ===\n"; +#endif + for (auto& F : *this->M) { + for (auto& B : F) { + for (auto& I : B) { + if (auto* ci = dyn_cast(&I)) { +#if DEBUG + errs() << "[Loop I] Found call: " << *ci << "\n"; +#endif + auto* fun = ci->getCalledFunction(); + // Various empty or null checks + if (fun == NULL || fun->empty() || !fun->hasName()) continue; + auto funName = fun->getName(); + // Consistent & FreshConsistent + if (isAnnot(funName) && !funName.equals("Fresh")) { + toDelete->push_back(ci); + int setID; + // Bit cast use of x, then value operand of store + auto* var = dyn_cast(ci->getOperand(0)); + if (var == NULL) continue; +#if DEBUG + errs() << "Cons. annot. for: " << *var << "\n"; +#endif + + auto* id = ci->getOperand(1); + if (auto* cint = dyn_cast(id)) { + setID = cint->getSExtValue(); +#if DEBUG + errs() << "In set with label: " << setID << "\n"; +#endif + } + + std::queue customUsers; + std::set v; + // v.emplace(ci); + // in case var itself is iOp +#if DEBUG + errs() << "Add to v inputs assoc. w/ Cons. var:\n"; +#endif + for (auto* input : inputMap[var]) { +#if DEBUG + errs() << "Input: " << *input << "\n"; +#endif + v.emplace(input); + } + + // customUsers.push(var); +#if DEBUG + errs() << "Collect uses of Cons. var:\n"; +#endif + for (auto* use : var->users()) { + // Don't push the annotation + if (use == ci) continue; +#if DEBUG + errs() << "Use: " << *use << "\n"; +#endif + customUsers.push(use); + } + + while (!customUsers.empty()) { + auto* use = customUsers.front(); + customUsers.pop(); + // errs() << "DEBUG: use is " << *use << " of var " << *var<<"\n"; + if (Instruction* instUse = dyn_cast(use)) { + for (Instruction* iOp : inputMap[instUse]) { + v.emplace(iOp); + // errs() << "DEBUG: adding to v " << *iOp << "\n"; + } + } + if (isa(use) || isa(use)) { + for (Value* use2 : use->users()) { + // errs() << "DEBUG: use2 is " << *use2 << "\n"; + if (StoreInst* si = dyn_cast(use2)) { + for (Instruction* iOp : inputMap[si]) { + v.emplace(iOp); + // errs() << "DEBUG: adding to v " << *iOp << "\n"; + } + } + // errs() << "DEBUG: pushing use2 of var: " << *use2 << "\n"; + customUsers.push(use2); + } + } + + if (isa(use)) { + for (Value* use2 : use->users()) { + // errs() << "DEBUG: use2 is " << *use2 << "\n"; + if (StoreInst* si = dyn_cast(use2)) { + // v.push_back(si); + for (Instruction* iOp : inputMap[si]) { + v.emplace(iOp); + // errs() << "DEBUG: adding to v " << *iOp << "\n"; + } + } + // errs() << "DEBUG: pushing use2 of var: " << *use2 << "\n"; + customUsers.push(use2); + } + } + } + + // Last case + if (v.empty()) { +#if DEBUG + errs() << "v empty, go over inputs assoc. w/ Cons. annot.:\n"; +#endif + // Some entries have a first link with ci, not var + for (auto* input : inputMap[ci]) { +#if DEBUG + errs() << "Input: " << *input << "\n"; +#endif + if (inputMap[ci].size() == 1) { +#if DEBUG + errs() << "Set of assoc. inputs is a singleton\n"; +#endif + for (auto* origLink : inputMap[input]) { +#if DEBUG + errs() << "Add to v the original input: " << *origLink << "\n"; +#endif + v.emplace(origLink); + } + } else { +#if DEBUG + errs() << "Set of assoc. input isn't a singleton, add to v the input\n"; +#endif + v.emplace(input); + } + } + } + + // For later deletion purposes +#if DEBUG + errs() << "Remove inputs assoc. w/ Cons. annot.\n"; +#endif + inputMap.erase(ci); + + if (!v.empty()) { +#if DEBUG + errs() << "v not empty\n"; +#endif + inst_vec tmp; +#if DEBUG + errs() << "Add each item in v to tmp:\n"; +#endif + for (auto* item : v) { +#if DEBUG + errs() << "Item: " << *item << "\n"; +#endif + tmp.push_back(item); + } + + // Add the collected list to the map + if (consVars->find(setID) != consVars->end()) { + consVars->at(setID).insert(consVars->at(setID).end(), tmp.begin(), tmp.end()); + } else { + consVars->emplace(setID, tmp); + } +#if DEBUG + errs() << "Add tmp items to consVars: \n"; + printIntInsts(*consVars); +#endif + } + } + + // Fresh & FreshConsistent + if (isAnnot(funName) && !funName.equals("Consistent")) { +#if DEBUG + errs() << "[Loop I] Calls Fresh\n"; +#endif + std::set v; + if (find(toDelete->begin(), toDelete->end(), ci) == toDelete->end()) { + // errs() << "getAnnot: " << ci << "\n"; + toDelete->push_back(ci); + } + + // #if DEBUG + // errs() << "[Loop I] Print inputMap entries:\n"; + // printInstInsts(inputMap); + // #endif + + //* Can't actually remove, otherwise wrong result + // #if DEBUG + // errs() << "[Loop I] Remove Fresh call from inputMap\n"; + // #endif + // inputMap.erase(ci); + + auto* freshArg = ci->getOperand(0); +#if DEBUG + errs() << "[Loop I] freshArg: " << *freshArg << "\n"; +#endif + + if (auto* inst = dyn_cast(freshArg)) { +#if DEBUG + errs() << "[Loop I] Add freshVar to v\n"; +#endif + v.emplace(inst); + + //* Actually collect all uses (e.g., log(x)) + if (auto* li = dyn_cast(inst)) { +#if DEBUG + errs() << "[Loop I] Further arg = LoadInst\n"; +#endif + auto* ptr = li->getPointerOperand(); +#if DEBUG + errs() << "[Loop I] Ptr operand: " << *ptr << "\n"; +#endif + for (auto* ptrUse : ptr->users()) { +#if DEBUG + errs() << "[Loop ptr users] ptrUse: " << *ptrUse << "\n"; +#endif + if (ptrUse != inst) { + if (auto* liUse = dyn_cast(ptrUse)) { + errs() << "[Loop ptr users] ptrUse = LoadInst & diff from freshArg, add to v\n"; + v.emplace(liUse); + } + } + } + } + } + // v.push_back(ci); + +#if DEBUG + errs() << "[Loop I] Go over arg users\n"; +#endif + for (auto* use : freshArg->users()) { + if (auto* si = dyn_cast(use)) { +#if DEBUG + errs() << "[Loop Users] use = StoreInst, add to v: " << *si << "\n"; +#endif + v.emplace(si); + } else if (isa(use)) { + for (auto* use2 : use->users()) { + if (auto* si = dyn_cast(use2)) { + v.emplace(si); + } + } + } + } + + if (!v.empty()) { +#if DEBUG + errs() << "[Loop I] Add v's insts to a set in freshVars:\n"; +#endif + inst_vec tmp; + for (auto* inst : v) { +#if DEBUG + errs() << "[Loop v] " << *inst << "\n"; +#endif + tmp.push_back(inst); + } + freshVars->push_back(tmp); + } + } + } + } + } + } + +#if DEBUG + errs() << "*** getAnnotations ***\n"; +#endif +} + +void InferAtomsPass::removeAnnotations(inst_vec& toDelete) { + std::vector toDeleteF; + + // Delete all annotation function calls + for (auto& F : *this->M) { + if (F.hasName() && isAnnot(F.getName())) + toDeleteF.push_back(&F); + else + for (auto& B : F) { + auto I = B.begin(); + for (; I != B.end(); I++) { + if (auto* ci = dyn_cast(I)) { + // TODO: No need to confirm in toDelete? + if (find(toDelete.begin(), toDelete.end(), &*I) != toDelete.end()) { +#if DEBUG + errs() << "Remove call: " << *I << "\n"; +#endif + I->replaceAllUsesWith(UndefValue::get(I->getType())); + I = I->eraseFromParent(); + + //* Remove args and their uses as well + for (auto& arg : ci->args()) { + if (auto* argInst = dyn_cast(arg)) { + auto argUsers = argInst->users(); + if (std::distance(argUsers.begin(), argUsers.end()) == 0) { +#if DEBUG + errs() << "No other users, remove call arg: " << *argInst << "\n"; +#endif + argInst->eraseFromParent(); + argInst->replaceAllUsesWith(UndefValue::get(argInst->getType())); + } + } + } + } + } + } + } + } + + // Delete all annotation function defs + for (auto* F : toDeleteF) { +#if DEBUG + errs() << "Remove function " << F->getName() << "\n"; +#endif + F->replaceAllUsesWith(UndefValue::get(F->getType())); + F->eraseFromParent(); + } +} + +// Given the starting point annotations of conSets, find the +// deepest unique point of the call chain +std::map InferAtomsPass::collectCons(std::map startingPoints, inst_insts_map inputMap) { +#if DEBUG + errs() << "=== collectCons ===\n"; +#endif + std::map toReturn; + +#if DEBUG + errs() << "Go over all cons. sets\n"; +#endif + for (auto& [id, starts] : startingPoints) { +#if DEBUG + errs() << "Go over cons. set " << id << "\n"; +#endif + std::set unique; + std::map> callChains; + + // Each item should be the starting point from a different annot + for (auto* start : starts) { +#if DEBUG + errs() << "Starting point: " << *start << "\n"; +#endif + // Add self to call chain +#if DEBUG + errs() << "Add starting point to call chain\n"; +#endif + callChains[start].insert(start); + +#if DEBUG + errs() << "Go over inputs assoc. w/ starting point:\n"; +#endif + for (auto* input : inputMap[start]) { + // unique.insert(iOp); +#if DEBUG + errs() << "Input: " << *input << "\n"; + errs() << "Add input to call chain\n"; +#endif + callChains[start].insert(input); + + std::queue toExplore; +#if DEBUG + errs() << "Add input to toExplore, go over toExplore\n"; +#endif + toExplore.push(input); + + while (!toExplore.empty()) { + auto* cur = toExplore.front(); + toExplore.pop(); +#if DEBUG + errs() << "Exploring cur: " << *cur << "\n"; + errs() << "Go over inputs assoc. w/ cur: " << *cur << "\n"; +#endif + + for (auto* intermed : inputMap[cur]) { +#if DEBUG + errs() << "intermed: " << *intermed << "\n"; +#endif + if (find(callChains[start].begin(), callChains[start].end(), intermed) == callChains[start].end()) { + callChains[start].insert(intermed); + toExplore.push(intermed); + } else { +#if DEBUG + errs() << "intermed already in call chain\n"; +#endif + } + } + } + + } // finish constructing call chain for one annot. in the set + + } // constructed call chains for ALL annot. in the set. + // now check the call chain + + // int index = 0; + // map foundUniquePoint; + // clean up the call chains + +#if DEBUG + errs() << "Finished building call chains, go over them\n"; +#endif + for (auto callChain : callChains) { +#if DEBUG + errs() << "Next chain\n"; +#endif + auto& [id, chain] = callChain; + for (auto* inst : chain) { +#if DEBUG + errs() << "Cur point along chain: " << *inst << "\n"; +#endif + bool isSameFun = false; + for (auto* link : inputMap[inst]) + isSameFun = ((link != inst) && link->getFunction() == inst->getFunction()); + if (isSameFun) { +#if DEBUG + errs() << "Continue if the link is in the same function\n"; +#endif + continue; + } + + bool isUnique = true; + for (auto otherCallChain : callChains) { + // Skip if self + if (otherCallChain == callChain) continue; + auto& [_, otherChain] = otherCallChain; + // Otherwise check if this map also contains inst + if (find(otherChain.begin(), otherChain.end(), inst) != otherChain.end()) { + isUnique = false; + break; + } + } + + if (isUnique) { + unique.insert(inst); +#if DEBUG + errs() << "Found unique point along chain: " << *inst << "\n"; +#endif + } + } + } + + inst_vec v; +#if DEBUG + errs() << "Go over unique insts\n"; +#endif + for (auto* inst : unique) { + if (!isa(inst)) { +#if DEBUG + errs() << "Unique inst != AllocaInst, add to v: " << *inst << "\n"; +#endif + v.push_back(inst); + } + } + +#if DEBUG + errs() << "Add v to toReturn at ID " << id << ": \n"; + printInsts(v); +#endif + toReturn[id] = v; + } // end starting point check + +#if DEBUG + errs() << "*** collectCons ***\n"; +#endif + return toReturn; +} + +// Collects the source inputs and uses of Fresh-annotated vars +inst_vec_vec InferAtomsPass::collectFresh(inst_vec_vec freshVars, inst_insts_map inputMap) { +#if DEBUG + errs() << "=== collectFresh ===\n"; +#endif + inst_vec_vec toReturn; + +#if DEBUG + errs() << "Go over freshSets\n"; +#endif + for (auto varSet : freshVars) { +#if DEBUG + errs() << "[Loop freshVars] Go over varSet:\n"; + printInsts(varSet); +#endif + + inst_set unique, callChain; + for (auto* var : varSet) { +#if DEBUG + errs() << "[Loop varSet] Cur var: " << *var << "\n"; +#endif + // Uses (forwards) are direct only (might need a little chaining for direct in rs to be direct in IR) + inst_vec uses = traverseUses(var); + +#if DEBUG + errs() << "[Loop varSet] Go over uses of var\n"; +#endif + for (auto* use : uses) { +#if DEBUG + errs() << "[Loop uses] Add use: " << *use << "\n"; +#endif + unique.insert(use); + +#if DEBUG + errs() << "[Loop uses] Go over each src input of use\n"; +#endif + for (auto* input : inputMap[use]) { +#if DEBUG + errs() << "Src input: " << *input << "\n"; + errs() << "Add insts tainted by it to unique\n"; +#endif + + if (unique.count(input) == 0) { + unique.insert(input); + + auto* ci = dyn_cast(input); + std::queue toExplore; + toExplore.push(ci); + + while (!toExplore.empty()) { + auto* I = toExplore.front(); + toExplore.pop(); + + // TODO: If there's no tainted inst in the chain, + // then don't need to include in unique + errs() << "[Loop inputInst] Found inst tainted by src input: " << *I << "\n"; + if (isa(I) || isa(I) || isa(I)) { + unique.insert(I); + for (auto& operand : I->operands()) + if (auto* operandI = dyn_cast(operand)) + toExplore.push(operandI); + } else if (auto* ai = dyn_cast(I)) { + for (auto* user : ai->users()) + if (auto* userI = dyn_cast(user)) + if (unique.count(userI) == 0) toExplore.push(userI); + } + } + } + } + } + +#if DEBUG + errs() << "[Loop varSet] Go over src inputs of var\n"; +#endif + for (auto* input : inputMap[var]) { +#if DEBUG + errs() << "[Loop inputMap[var]] Cur src input: " << *input << "\n"; +#endif + unique.insert(input); + callChain.insert(input); + std::queue toExplore; + toExplore.push(input); + while (!toExplore.empty()) { + Instruction* curr = toExplore.front(); + toExplore.pop(); + for (Instruction* intermed : inputMap[curr]) { + if (!(find(callChain.begin(), callChain.end(), intermed) != callChain.end())) { + callChain.insert(intermed); + toExplore.push(intermed); + } + } + } + } + + // Add the var itself + if (isa(var) || isa(var)) { +#if DEBUG + errs() << "[Loop varSet] Cur var = StoreInst/CallInst, add to unique\n"; +#endif + unique.insert(var); + } + } + // Now construct the call chain + for (auto* vv : callChain) { + unique.insert(vv); + } + inst_vec v; +#if DEBUG + errs() << "[Loop freshVars] Go over unique\n"; +#endif + for (auto* inst : unique) { + if (!isa(inst)) { +#if DEBUG + errs() << "[Loop unique] Cur inst != AllocaInst, add to v: " << *inst << "\n"; +#endif + v.push_back(inst); + } + } + +#if DEBUG + errs() << "[Loop FreshVars] Add v to toReturn\n"; +#endif + toReturn.push_back(v); + } + +#if DEBUG + errs() << "*** collectFresh ***\n"; +#endif + return toReturn; +} diff --git a/ocelot/AtomicRegionInference/src/InferFreshCons.cpp b/ocelot/AtomicRegionInference/src/InferFreshCons.cpp new file mode 100644 index 0000000..eb53e0f --- /dev/null +++ b/ocelot/AtomicRegionInference/src/InferFreshCons.cpp @@ -0,0 +1,855 @@ +#include "include/InferFreshCons.h" + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/PostDominators.h" + +Instruction* InferFreshCons::insertRegionInst(InsertKind insertKind, Instruction* insertBefore) { +#if DEBUG + errs() << "=== insertRegionInst ===\n"; +#endif + Instruction* call; + IRBuilder<> builder(insertBefore); + + if (insertKind == Start) { +#if DEBUG + errs() << "Insert start before: " << *insertBefore << "\n"; +#endif + call = builder.CreateCall(this->atomStart); + } else { +#if DEBUG + errs() << "Insert end before: " << *insertBefore << "\n"; +#endif + call = builder.CreateCall(this->atomEnd); + } + +#if DEBUG + errs() << "*** insertRegionInst ***\n"; +#endif + return call; +} + +// If a direct pred is also a successor, then it's a for loop block +bool InferFreshCons::loopCheck(BasicBlock* B) { + auto BName = getSimpleNodeLabel(B); + + if (!B->hasNPredecessors(1)) { + for (auto it = pred_begin(B), et = pred_end(B); it != et; ++it) { + auto* predecessor = *it; + auto pname = predecessor->getName().drop_front(2); + // errs() << "comparing " << pname<< " and " < 0) { + // errs() << "comparison is true\n"; + return true; + } + } + } + + return false; +} + +// Find the first block after a for loop +BasicBlock* InferFreshCons::getLoopEnd(BasicBlock* bb) { + auto* ti = bb->getTerminator(); + if (ti->getNumSuccessors() == 0) { + return bb; + } else { + auto* end = ti->getSuccessor(0); + ti = end->getTerminator(); + // errs() << "end is " << end->getName() << "\n"; + // for switch inst, succ 0 is the fall through + end = ti->getSuccessor(1); + // errs() << "end is " << end->getName() << "\n"; + return end; + } +} + +// Top level region inference function -- could flatten later +void InferFreshCons::inferCons(std::map consSets, inst_vec_vec* freshSets, inst_vec* toDeleteAnnots, std::set* inputInsts) { +#if DEBUG + errs() << "=== inferCons ===\n"; +#endif + for (auto& [id, set] : consSets) { +#if DEBUG + errs() << "[inferCons] Adding region for set " << id << "\n"; +#endif + addRegion(set, freshSets, toDeleteAnnots, nullptr); + } +#if DEBUG + errs() << "*** inferCons ***\n"; +#endif +} + +// The only difference is outer map vs outer vec +void InferFreshCons::inferFresh(inst_vec_vec freshSets, std::map* consSets, inst_vec* toDeleteAnnots, std::set* inputInsts) { +#if DEBUG + errs() << "=== inferFresh ===\n"; +#endif + + std::vector consVec; + for (auto& [_, consSet] : *consSets) consVec.push_back(consSet); + + for (auto freshSet : freshSets) { + addRegion(freshSet, &consVec, toDeleteAnnots, inputInsts); + } +#if DEBUG + errs() << "*** inferFresh ***\n"; +#endif +} + +void InferFreshCons::addRegion(inst_vec targetInsts, inst_vec_vec* other, inst_vec* toDeleteAnnots, std::set* inputInsts) { +#if DEBUG + errs() << "=== addRegion ===\n"; +#endif + // A map from set item to bb + std::map targetBlocks; + // A queue of regions that still need to be processed + std::queue> regionsNeeded; + +#if DEBUG + errs() << "Build map from inst to bb\n"; +#endif + for (auto* targetInst : targetInsts) { + // errs() << "Check: " << *targetInst << "\n"; + targetBlocks[targetInst] = targetInst->getParent(); + } + +#if DEBUG + errs() << "Add map to regionsNeeded\n"; +#endif + regionsNeeded.push(targetBlocks); + + auto* root = m->getFunction("app"); + + // Iterate until no more possible regions, then pick the best one + inst_inst_vec regionsFound; + while (!regionsNeeded.empty()) { + // Need to raise all blocks in the map until they are the same + auto taintedBlocks = regionsNeeded.front(); + regionsNeeded.pop(); + + // Record which functions have been traveled through + std::set seenFuns; + +#if DEBUG + errs() << "[Loop regionsNeeded] While blocks are in diff functions\n"; +#endif + while (!sameFunction(taintedBlocks)) { + // To think on: does this change? + auto* goal = findCandidate(taintedBlocks, root); +#if DEBUG + errs() << "[Loop !sameFunction] Go over each targetInst\n"; +#endif + for (auto* targetInst : targetInsts) { + // not all blocks need to be moved up + auto* curFun = taintedBlocks[targetInst]->getParent(); + seenFuns.insert(curFun); + if (curFun != goal) { + // if more than one call: + // callChain info is already in the starting set + // so only explore a caller if it's in conSet + bool first = true; + for (auto* use : curFun->users()) { + if (!(find(targetInsts.begin(), targetInsts.end(), use) != targetInsts.end())) + continue; + auto* inst = dyn_cast(use); +#if DEBUGINFER + errs() << "DEBUGINFER: examining use: " << *inst << "\n"; +#endif + if (inst == NULL) { + // errs () << "ERROR: use " << *use << "not an instruction\n"; + break; + } + // update the original map + if (first) { + taintedBlocks[targetInst] = inst->getParent(); + first = false; + } else { + // copy the blockmap, update, add to queue + auto* inst = dyn_cast(use); + std::map copy; + for (auto map : taintedBlocks) copy[map.first] = map.second; + copy[targetInst] = inst->getParent(); + regionsNeeded.push(copy); + } + } // end forall uses + } // end currFunc check + } // end forall items + } // end same function check + +// Now, all bbs in the map are in the same function, so we can run +// dom or post-dom analysis on that function +#if DEBUG + errs() << "[Loop regionsNeeded] Start dom tree analysis\n"; +#endif + + auto* homeFun = taintedBlocks.begin()->second->getParent(); + if (homeFun == nullptr) { +#if DEBUG + errs() << "[Loop regionsNeeded] No function found\n"; +#endif + continue; + } +#if DEBUG + errs() << "[Loop regionsNeeded] Found home fun: " << homeFun->getName() << "\n"; +#endif + +#if OPT + std::set seenBlocks; + + LoopInfo& LI = FAM->getResult(*homeFun); + std::map> untaintedLoopClones; + bool loopCondTainted = false; + +#if DEBUG + errs() << "[Loop regionsNeeded] Go over all blocks\n"; +#endif + for (auto& B : *homeFun) { + bool isTainted = false; + for (auto& [_, tB] : taintedBlocks) { + if (&B == tB) { + isTainted = true; + break; + } + } + + if (isTainted && seenBlocks.find(&B) == seenBlocks.end()) { +#if DEBUG + errs() << "Tainted block " << B.getName() << ":\n"; +#endif + seenBlocks.emplace(&B); + + inst_vec toDelete, toDelay; + inst_inst_map instClones; + + for (auto& I : B) { +#if DEBUG + errs() << I << "\n"; +#endif + + bool inExistingSet = false; + for (auto insts : *other) { + if (find(insts.begin(), insts.end(), &I) != insts.end()) { + inExistingSet = true; + break; + } + } + + bool isAtomicBoundary = false; + if (auto* ci = dyn_cast(&I)) { + auto* calledFun = ci->getCalledFunction(); + if (calledFun == this->atomStart || calledFun == this->atomEnd) + isAtomicBoundary = true; + } + + if (find(targetInsts.begin(), targetInsts.end(), &I) == targetInsts.end() && !isa(&I) && !inExistingSet && !isAtomicBoundary) { +#if DEBUG + errs() << "__Should be delayed__\n"; +#endif + auto* clone = I.clone(); + instClones.emplace(&I, clone); + toDelete.push_back(&I); + toDelay.push_back(clone); + + auto* loop = LI.getLoopFor(&B); + if (loop != nullptr) { + if (&B != loop->getBlocks()[1]) loopCondTainted = true; + + if (untaintedLoopClones.count(loop) == 0) + untaintedLoopClones[loop] = {clone}; + else + untaintedLoopClones[loop].push_back(clone); + } + } + } + + for (auto* I : toDelete) I->removeFromParent(); + + IRBuilder BBuilder(&B); + for (auto* I : toDelay) BBuilder.Insert(I); + + patchClonedBlock(&B, instClones); + + // Sync freshSets + if (other != nullptr) { + for (auto& set : *other) { + for (size_t i = 0; i < set.size(); i++) { + auto it = find(toDelete.begin(), toDelete.end(), set[i]); + if (it != toDelete.end()) { + auto idx = std::distance(toDelete.begin(), it); + auto* newInst = toDelay[idx]; + set[i] = newInst; + } + } + } + } + + // Sync toDelete + if (toDeleteAnnots != nullptr) { + for (size_t i = 0; i < toDeleteAnnots->size(); i++) { + auto* annot = toDeleteAnnots->at(i); + auto it = find(toDelete.begin(), toDelete.end(), annot); + if (it != toDelete.end()) { + auto idx = std::distance(toDelete.begin(), it); + auto* newAnnot = toDelay[idx]; + toDeleteAnnots->at(i) = newAnnot; + } + } + } + +#if DEBUG + errs() << "After: " << B << "\n"; +#endif + } + } + + if (!loopCondTainted) { + for (auto& [taintedLoop, untaintedClones] : untaintedLoopClones) { +#if DEBUG + errs() << "Clone taintedLoop\n"; +#endif + std::vector clonedLoop; + BasicBlock* forEnd; + Instruction* clonedAlloca; + Value* initVal; + inst_inst_map instClones; + + auto loopBlocks = taintedLoop->getBlocks(); + // assert(loopBlocks.size() == 3); + + for (int i = 0; i < loopBlocks.size(); i++) { + auto* block = loopBlocks[i]; + auto* clonedBlock = BasicBlock::Create(block->getContext(), block->getName(), homeFun); + IRBuilder builder(clonedBlock); + +#if DEBUG + errs() << "Clone block " << block->getName() << "\n"; +#endif + + Instruction* prev; + for (auto& I : *block) { +#if DEBUG + errs() << "Clone inst: " << I << "\n"; +#endif + auto* clonedI = I.clone(); + + // Only extract if untainted + // Covers the cond and inc blocks; they are processed on the fly due to + // their special role in keeping the loop going + if (find(targetInsts.begin(), targetInsts.end(), &I) == targetInsts.end()) { + // for.cond + if (i == 0) { + if (auto* li = dyn_cast(clonedI)) { + auto* ptr = li->getPointerOperand(); + + if (auto* ai = dyn_cast(*ptr->uses().begin())) { + IRBuilder builder(ai); + clonedAlloca = builder.CreateAlloca(ai->getAllocatedType()); + } + + for (auto* ptrUser : ptr->users()) { + if (auto* si = dyn_cast(ptrUser)) { + if (!isa(si->getOperand(0))) { + initVal = si->getOperand(0); + } + } + } + + li->setOperand(0, clonedAlloca); + prev = li; + } else if (auto* ci = dyn_cast(clonedI)) { + // TODO: Check if operand originates from the current loop + if (isa(ci->getOperand(0))) { + ci->setOperand(0, prev); + } + prev = ci; + } else if (auto* bi = dyn_cast(clonedI)) { + assert(bi->isConditional()); + bi->setCondition(prev); + + if (auto* B = dyn_cast(bi->getOperand(2))) { + // errs() << "ayo: " << *B << "\n"; + forEnd = B; + } + } + } + + // for.inc + else if (i == 2) { + if (auto* li = dyn_cast(clonedI)) { + li->setOperand(0, clonedAlloca); + prev = li; + } else if (auto* bi = dyn_cast(clonedI)) { + auto* lhs = bi->getOperand(0); + if (isa(lhs)) bi->setOperand(0, prev); + auto* rhs = bi->getOperand(1); + if (isa(rhs)) bi->setOperand(1, prev); + prev = bi; + } else if (auto* si = dyn_cast(clonedI)) { + si->setOperand(0, prev); + si->setOperand(1, clonedAlloca); + } + } + + instClones.emplace(&I, clonedI); + builder.Insert(clonedI); + } + } + + // for.body + // Performs a standard sound cloning procedure (on each operand); + // the instructions in the body are unrelated to the loop except the final + // branch instruction + if (i == 1) patchClonedBlock(clonedBlock, instClones); + + clonedLoop.push_back(clonedBlock); + } + + auto* forEndClone = BasicBlock::Create(forEnd->getContext(), forEnd->getName(), homeFun); + IRBuilder builder(forEndClone); + for (auto& I : *forEnd) { + if (!isa(I) && !isa(I)) { + auto* clone = I.clone(); + builder.Insert(clone); + } + + if (isa(I)) { + IRBuilder builder(&I); + builder.CreateBr(clonedLoop[0]); + I.removeFromParent(); + break; + } + } + + for (auto& I : *forEnd) { + if (auto* bi = dyn_cast(&I)) { + IRBuilder builder(bi); + builder.CreateStore(initVal, clonedAlloca); + } + } + + // Connect the blocks of the new loop + for (int i = 0; i < clonedLoop.size(); i++) { + auto* block = clonedLoop[i]; + for (auto& I : *block) { + if (auto* bi = dyn_cast(&I)) { + // for.cond + if (i == 0) { + bi->setSuccessor(0, clonedLoop[1]); + bi->setSuccessor(1, forEndClone); + } + // for.body + else if (i == 1) { + // bi->setSuccessor(0, clonedLoop[2]); + bi->setSuccessor(0, clonedLoop[0]); + } + // for.inc + else if (i == 2) { + bi->setSuccessor(0, clonedLoop[0]); + } + } + } + } + + for (auto* untaintedClone : untaintedClones) { + if (!isa(untaintedClone)) untaintedClone->removeFromParent(); + } + } + } +#endif + + auto& domTree = FAM->getResult(*homeFun); + // Find the closest point that dominates + auto* startDom = taintedBlocks.begin()->second; + for (auto& [_, B] : taintedBlocks) + startDom = domTree.findNearestCommonDominator(B, startDom); + // #if DEBUG + // errs() << "[Loop regionsNeeded] startDom: " << *startDom << "\n"; + // #endif + + // TODO: if an inst in the set is in the bb, we can truncate? + +#if DEBUG + errs() << "Start post dom tree analysis\n"; +#endif + + // Flip directions for the region end + auto& postDomTree = FAM->getResult(*homeFun); + // Find the closest point that dominates + auto* endDom = taintedBlocks.begin()->second; + for (auto& [_, taintedBlock] : taintedBlocks) { +#if DEBUGINFER + if (endDom != nullptr) { + errs() << "Finding post dom of: " << getSimpleNodeLabel(map.second) << " and " << getSimpleNodeLabel(endDom) << "\n"; + } else { + errs() << "endDom is null\n"; + } +#endif + endDom = postDomTree.findNearestCommonDominator(taintedBlock, endDom); + } + + // #if DEBUG + // errs() << "[Loop regionsNeeded] endDom: " << *endDom << "\n"; + // #endif + + if (startDom == nullptr) { + errs() << "[Error] Null startDom\n"; + } else if (endDom == nullptr) { + errs() << "[Error] Null endDom\n"; + } + + // Need to make the start and end dominate each other as well. + startDom = domTree.findNearestCommonDominator(startDom, endDom); + endDom = postDomTree.findNearestCommonDominator(startDom, endDom); + + // #if DEBUG + // errs() << "[Loop regionsNeeded] After matching scope\n"; + // errs() << "[Loop regionsNeeded] startDom: " << *startDom << "\n"; + // errs() << "[Loop regionsNeeded] endDom: " << *endDom << "\n"; + // #endif + + // Extra check to disallow loop conditional block as the end + if (loopCheck(endDom)) { +#if DEBUG + errs() << "[Loop regionsNeeded] Loop check passed\n"; +#endif + endDom = getLoopEnd(endDom); + } + + if (startDom == nullptr) { + errs() << "[Error] Null startDom after scope merge\n"; + } else if (endDom == nullptr) { + errs() << "[Error] Null endDom after scope merge\n"; + } + + // TODO: fallback if endDom is null? Need hyper-blocks, I think + // pOssibly can do a truncation check, to lessen the size a little, but could that interfere with compiler optimizations? + auto* regionStart = truncate(startDom, true, targetInsts, seenFuns); + auto* regionEnd = truncate(endDom, false, targetInsts, seenFuns); + if (regionStart == nullptr) { + errs() << "[Error] Null startDom after truncation\n"; + } else if (regionEnd == nullptr) { + errs() << "[Error] Null endDom after truncation\n"; + } else { + // errs() << "Region start is before " << *regionStart<<" and region end is before " << *regionEnd<<"\n"; + } + +#if DEBUG + errs() << "[Loop regionsNeeded] Add to regionsFound: (" << *regionStart << ", " << *regionEnd << ")\n"; +#endif + // Insert into regionsFound + regionsFound.emplace_back(regionStart, regionEnd); + } // end while regions needed + + // Now see which region is smallest -- instruction count? they must dominate + // each other, so there's no possibility of not running into the start from + // the end + auto [regionStart, regionEnd] = findShortest(regionsFound); + insertRegionInst(Start, regionStart); + insertRegionInst(End, regionEnd); + //}//end while regions needed + +#if DEBUG + errs() << "Final:\n" + << *root << "\n"; + errs() << "*** addRegion ***\n"; +#endif +} + +// Truncate a bb if the instruction is in the bb +Instruction* InferFreshCons::truncate(BasicBlock* B, bool forwards, inst_vec set, std::set nested) { +#if DEBUG + errs() << "=== truncate ===\n"; +#endif + + // #if DEBUG + // errs() << "Set:\n"; + // printInsts(set); + // #endif + + // Truncate the front + if (forwards) { +#if DEBUG + errs() << "Truncate startDom, go over each inst\n"; +#endif + for (auto& I : *B) { + // Stop at first inst in bb that is in the set. + if (find(set.begin(), set.end(), &I) != set.end()) { +#if DEBUG + errs() << "[Loop B] Found first inst also in set: " << I << "\n"; +#endif + return &I; + } + // Need to stop at relevant CallInsts as well + else if (auto* ci = dyn_cast(&I)) { + if (nested.find(ci->getCalledFunction()) != nested.end()) + return &I; + } + } + +#if DEBUG + errs() << "Found no inst, return last inst\n"; +#endif + // Otherwise just return the last inst + return &B->back(); + } + +#if DEBUG + errs() << "Truncate endDom, go over each inst in reverse\n"; +#endif + // Reverse directions if not forwards + Instruction* prev; + for (auto I = B->rbegin(), rend = B->rend(); I != rend; I++) { + auto* inst = &*I; + if (find(set.begin(), set.end(), inst) != set.end()) { +#if DEBUG + errs() << "[Loop B] Found last inst also in set: " << *I << "\n"; +#endif + // Need to return the previous inst (next in forwards), + // as it should be inserted before the returned inst + if (prev == nullptr) { + // Only happens if use is a ret inst, which is a scope use to make the branching + // work, not an actual one, so this is safe + return inst; + } + +#if DEBUG + errs() << "[Loop B] Return prev inst: " << *prev << "\n"; +#endif + return prev; + } else if (auto* ci = dyn_cast(inst)) { + if (nested.find(ci->getCalledFunction()) != nested.end()) { + return prev; + } + } + prev = inst; + } + +#if DEBUG + errs() << "*** truncate ***\n"; +#endif + +#if DEBUG + errs() << "Found no inst, return first inst\n"; +#endif + // Otherwise just return first inst of the block + // errs() << "truncate returning " << bb->front() << "\n"; + return &B->front(); +} + +Function* InferFreshCons::findCandidate(std::map blockMap, Function* root) { +#if DEBUG + errs() << "== findCandidate ===\n"; +#endif + std::vector funList; + // Add the parents, without duplicates + for (auto& [_, B] : blockMap) { + if (!(find(funList.begin(), funList.end(), B->getParent()) != funList.end())) { +#if DEBUG + errs() << "Add: " << B->getParent()->getName() << "\n"; +#endif + funList.push_back(B->getParent()); + } + } + + // Easy case: everything is already in the same function + if (funList.size() == 1) return funList.at(0); + + /* Algo goal: get the deepest function that still calls (or is) all funcs in funcList. + * Consider: multiple calls? Should be dealt with in the addRegion -- eventually each caller gets its own region + */ + Function* goal = nullptr; +#if DEBUG + errs() << "starting from " << root->getName() << "\n"; +#endif + deepCaller(root, funList, &goal); + if (goal == nullptr) { + errs() << "ERROR: deepCaller failed\n"; + } + +#if DEBUG + errs() << "*** findCandidate ***\n"; +#endif + return goal; +} + +// From a root, returns list of called functions. +std::vector InferFreshCons::deepCaller(Function* root, std::vector& funList, Function** goal) { + std::vector calledFuncs; + bool mustIncludeSelf = false; + + for (inst_iterator inst = inst_begin(root), E = inst_end(root); inst != E; ++inst) { + if (CallInst* ci = dyn_cast(&(*inst))) { + calledFuncs.push_back(ci->getCalledFunction()); + } + } + std::vector explorationList; + for (auto* item : funList) { + // skip over root or called funcs + if ((find(calledFuncs.begin(), calledFuncs.end(), item) != calledFuncs.end()) || item == root) { + if (item == root) { + mustIncludeSelf = true; + } + continue; + } + explorationList.push_back(item); +#if DEBUGINFER + errs() << "need to find " << item->getName() << "\n"; +#endif + } + // this function is a root of a call tree that calls everything in the func List + if (explorationList.empty()) { +#if DEBUGINFER + errs() << "empty list\n"; +#endif + *goal = root; + return calledFuncs; + } + // otherwise recurse + Function* candidate = nullptr; + for (Function* called : calledFuncs) { + std::vector partial = deepCaller(called, explorationList, &candidate); + // if candidate is set, it means called is a root for everything in the explorationList + if (candidate != nullptr) { + *goal = candidate; +#if DEBUGINFER + errs() << "New candidate: " << (*goal)->getName() << "\n"; +#endif + } + // remove from explorationList, but add to calledFuncs + for (Function* item : partial) { + func_vec::iterator place = find(explorationList.begin(), explorationList.end(), item); + if (place != explorationList.end()) { + explorationList.erase(place); + } + calledFuncs.push_back(item); + } + } + // current point is a root + if (explorationList.empty()) { + // not the deepest + if (candidate != nullptr && !mustIncludeSelf) { + *goal = candidate; + } else { + // is the deepest + *goal = root; + } + } + return calledFuncs; +} + +// Get the min of the max length of each region +inst_inst_pair InferFreshCons::findShortest(inst_inst_vec regionsFound) { +#if DEBUG + errs() << "=== findShortest ===\n"; +#endif + inst_inst_pair best; + int shortest = INT32_MAX; + +#if DEBUG + errs() << "Go over regionsFound\n"; +#endif + for (auto& [start, end] : regionsFound) { + int prefixLength = 0, found = 0; + auto* startParent = start->getParent(); +#if DEBUG + errs() << "[Loop regionsFound] startParent: " << *startParent << "\n"; + errs() << "Go over startParent insts\n"; +#endif + for (auto& I : *startParent) { + prefixLength++; + if (&I == start) break; + } + + // Get the max length from the bb to the end instruction + std::vector v; + int endLength = getSubLength(startParent, end, v); + // Subtract the prefix before the start inst + endLength -= prefixLength; +#if DEBUG + errs() << "[Loop regionsFound] Region length " << endLength << "\n"; +#endif + if (endLength < shortest) { +#if DEBUG + errs() << "[Loop regionsFound] Shortest region: (" << *start << ", " << *end + << ") at length " << endLength << "\n"; +#endif + shortest = endLength; + best = std::make_pair(start, end); + } + } + +#if DEBUG + errs() << "*** findShortest ***\n"; +#endif + return best; +} + +int InferFreshCons::getSubLength(BasicBlock* B, Instruction* end, std::vector visited) { +#if DEBUG + errs() << "=== getSubLength ===\n"; +#endif + + int count = 0, max_ret = 0; + visited.push_back(B); +#if DEBUG + errs() << "Go over B insts\n"; +#endif + for (auto& I : *B) { + count++; + + if (&I == end) { +#if DEBUG + errs() << "[Loop I] I = end, stop: " << *end << "\n"; +#endif + return count; + } + + if (auto* ci = dyn_cast(&I)) { + auto* cf = ci->getCalledFunction(); + if (!cf->empty() && cf != NULL) { +#if DEBUG + errs() << "[Loop I] I = CallInst, calling: " << cf->getName() << "\n"; +#endif + count += cf->getInstructionCount(); + } + } + + if (I.isTerminator()) { +#if DEBUG + errs() << "[Loop I] I = terminator: " << I << "\n"; +#endif + for (int i = 0; i < I.getNumSuccessors(); i++) { + auto* next = I.getSuccessor(i); + // Already counted -- do something more fancy for loops? + if (find(visited.begin(), visited.end(), next) != visited.end()) continue; + int intermed = getSubLength(next, end, visited); + if (intermed > max_ret) { + max_ret = intermed; + } + } + } + } + +#if DEBUG + errs() << "*** getSubLength ***\n"; +#endif + return count + max_ret; +} + +bool InferFreshCons::sameFunction(std::map blockMap) { + auto* BComp = blockMap.begin()->second->getParent(); + + for (auto& [I, B] : blockMap) { + if (B->getParent() != BComp) { +#if DEBUG + errs() << "Blocks are NOT in same fun\n"; +#endif + return false; + } + } + +#if DEBUG + errs() << "Blocks are in same fun\n"; +#endif + return true; +} diff --git a/ocelot/AtomicRegionInference/src/TaintTracker.cpp b/ocelot/AtomicRegionInference/src/TaintTracker.cpp index 0033a78..1ffffee 100644 --- a/ocelot/AtomicRegionInference/src/TaintTracker.cpp +++ b/ocelot/AtomicRegionInference/src/TaintTracker.cpp @@ -1,857 +1,1040 @@ #include "include/TaintTracker.h" +// Main dataflow function to construct map of store (TODO: not just stores) insts to vars (inputs?) they depend on +std::pair> buildInputs(Module* M) { +#if DEBUG + errs() << "=== buildInputs ===\n"; +#endif -/*Main DataFlow function to construct map of store insts to vars they depend on*/ -inst_insts_map buildInputs(Module* m) -{ - inst_vec inputs = findInputInsts(m); - inst_insts_map taintedDecl; - inst_vec promoted_inputs; - - for (Instruction* iOp : inputs) { - #if DEBUG - errs() << "Starting input: " << *iOp <<"\n"; - #endif - //don't forget to add self to map - taintedDecl[iOp].insert(iOp); - queue toExplore; - toExplore.push(iOp); - - //iterate until no more interproc flows found - while(!toExplore.empty()) { - - Value* currVal = toExplore.front(); - if (currVal == NULL) { - continue; - } + std::set inputInsts = findInputInsts(M); + inst_insts_map taintedInsts; + inst_vec promotedInputs; - val_vec interProcFlows; + for (auto* inputInst : inputInsts) { +#if DEBUG + errs() << "[Loop inputInst] inputInst: " << *inputInst << "\n"; +#endif + + // Add self to map + taintedInsts[inputInst].insert(inputInst); + std::queue toExplore; +#if DEBUG + errs() << "[Loop inputInst] Add orig input to toExplore\n"; +#endif + toExplore.push(inputInst); + +#if DEBUG + errs() << "[Loop inputInst] Explore flows from orig input\n"; +#endif + + // Iterate until no more inter-proc flows found + while (!toExplore.empty()) { +#if DEBUG + errs() << "=== Loop toExplore ===\n"; +#endif + auto* curInst = toExplore.front(); toExplore.pop(); - if (currVal == iOp) { - interProcFlows = traverseLocal(currVal, iOp, &taintedDecl, nullptr); - for (Value* vipf : interProcFlows) { - if(Instruction* iipf = dyn_cast(vipf)) { - if (CallInst* anno_check = dyn_cast(iipf)){ - //we delete these later... creates problems - if (anno_check->getName().contains("Fresh") || - anno_check->getName().contains("Consistent") ) { - continue; - } - } - taintedDecl[iipf].insert(iOp); + + if (curInst == NULL) continue; + +#if DEBUG + errs() << "[Loop toExplore] curInst: " << *curInst << "\n"; +#endif + + val_vec interProcFlows; + if (curInst == inputInst) { +#if DEBUG + errs() << "[Loop toExplore] curInst = inputInst\n"; + errs() << "[Loop toExplore] Call traverseLocal with curInst (tainted), origInput (srcInput), caller (none)\n"; +#endif + interProcFlows = traverseLocal(curInst, inputInst, &taintedInsts, nullptr); +#if DEBUG + errs() << "[Loop toExplore][curInst = inputInst] Inspect interProcFlows:\n"; +#endif + for (auto* vipf : interProcFlows) { + if (auto* iipf = dyn_cast(vipf)) { + if (auto* anno_check = dyn_cast(iipf)) { + // We delete these later... creates problems + if (isAnnot(anno_check->getName())) continue; + } + +#if DEBUG + errs() << "Add inputInst (" << *inputInst << ") to set at " << *iipf << "\n"; +#endif + taintedInsts[iipf].insert(inputInst); } } - } else if (isa(currVal)) { - //note it will not be iop, even though iop is a call - //this case handles both returns and pbref - - promoted_inputs.push_back(dyn_cast(currVal)); - Value* next = toExplore.front(); + } else if (isa(curInst)) { +#if DEBUG + errs() << "[Loop toExplore] cur inst = CallInst\n"; +#endif + // Note it will not be iop, even though iop is a call + // This case handles both returns and pbref + + promotedInputs.push_back(dyn_cast(curInst)); + auto* next = toExplore.front(); toExplore.pop(); - //if the next is a return, this was a return flow - //otherwise, if it's an arg, this was pbref + // If the next is a return, this was a return flow + // Otherwise, if it's an arg, this was pbref + //? pbref - pass by reference? if (isa(next)) { - interProcFlows = traverseLocal(currVal, dyn_cast(currVal), &taintedDecl, nullptr); +#if DEBUG + errs() << "[Loop toExplore] cur inst next = Return inst (return flow)\n"; +#endif + interProcFlows = traverseLocal(curInst, dyn_cast(curInst), &taintedInsts, nullptr); for (Value* vipf : interProcFlows) { - if(Instruction* iipf = dyn_cast(vipf)) { - - //don't add self - if (currVal == vipf) { + if (Instruction* iipf = dyn_cast(vipf)) { + // don't add self + if (curInst == vipf) { continue; } - if (CallInst* anno_check = dyn_cast(iipf)){ - //we delete these later... creates problems - if (anno_check->getName().contains("Fresh") || - anno_check->getName().contains("Consistent") ) { - continue; - } - } - taintedDecl[iipf].insert(dyn_cast(currVal)); + if (CallInst* anno_check = dyn_cast(iipf)) { + // we delete these later... creates problems + if (anno_check->getName().contains("Fresh") || + anno_check->getName().contains("Consistent")) { + continue; + } + } + taintedInsts[iipf].insert(dyn_cast(curInst)); } - } + } } else if (isa(next)) { - //grab the para corresponding to the argument +#if DEBUG + errs() << "[Loop toExplore] cur inst next = Argument (pbref)\n"; +#endif + // Grab the para corresponding to the argument int index = -1; int i = 0; - CallInst* ci = dyn_cast(currVal); - + CallInst* ci = dyn_cast(curInst); - if (ci->getCalledFunction() == NULL) { - continue; + if (ci->getCalledFunction() == NULL) continue; + if (ci->getCalledFunction()->empty()) continue; + +#if DEBUG + errs() << "exploring function " << ci->getCalledFunction()->getName() << "\n"; +#endif + + for (auto& arg : ci->getCalledFunction()->args()) { + // errs() <<"arg is "<(&arg) != next) { + i++; + } else { + index = i; + } } - if (ci->getCalledFunction()->empty()) { + if (index == -1) { +#if DEBUG + errs() << "couldn't find pass by ref " << *next << "\n"; +#endif continue; } - #if DEBUG - errs() << "exploring function " << ci->getCalledFunction()->getName() << "\n"; - #endif - - for (auto& arg : ci->getCalledFunction()->args()){ - //errs() <<"arg is "<(&arg)!=next) { - i++; - } else { - index = i; - } - - } - if(index == -1){ - #if DEBUG - errs() << "couldn't find pass by ref " << *next << "\n"; - #endif - continue; + Value* tArg = ci->getArgOperand(index); + // errs() << "arg_op: "<< *arg_op<<"\n"; + // check if reference is part of an array + if (GEPOperator* gep = dyn_cast(tArg)) { + tArg = gep->getPointerOperand(); } - - Value* tArg = ci->getArgOperand(index); - //errs() << "arg_op: "<< *arg_op<<"\n"; - //check if reference is part of an array - if (GEPOperator* gep = dyn_cast(tArg)) { - tArg = gep->getPointerOperand(); - } - //if bitcast inst, - else if (BitCastInst* bci = dyn_cast(tArg)){ + // if bitcast inst, + else if (BitCastInst* bci = dyn_cast(tArg)) { tArg = bci->getOperand(0); } - //need to actually find the first use *after* the callInst - Instruction* fstUse = ptrAfterCall(tArg,ci); - if (fstUse!=nullptr && fstUse!=tArg) { - #if DEBUG + // need to actually find the first use *after* the callInst + Instruction* fstUse = ptrAfterCall(tArg, ci); + if (fstUse != nullptr && fstUse != tArg) { +#if DEBUG errs() << "First use after call: " << *fstUse << "\n"; - #endif - //if the first use is itself a callinst, then treat as a tainted para case, +#endif + // if the first use is itself a callinst, then treat as a tainted para case, val_vec visited_fstuse; visited_fstuse.push_back(ci); - - while (CallInst* ci_fstuse = dyn_cast(fstUse) ) { - //already visited, as in loop - if (find(visited_fstuse.begin(),visited_fstuse.end(), ci_fstuse) - !=visited_fstuse.end()) { - //no non-call uses + + while (CallInst* ci_fstuse = dyn_cast(fstUse)) { + // already visited, as in loop + if (find(visited_fstuse.begin(), visited_fstuse.end(), ci_fstuse) != visited_fstuse.end()) { + // no non-call uses fstUse = nullptr; break; } - if (CallInst* anno_check = dyn_cast(ci_fstuse)){ - //we delete these later... creates problems - if (anno_check->getName().contains("Fresh") || - anno_check->getName().contains("Consistent") ) { - continue; - } - } + if (CallInst* anno_check = dyn_cast(ci_fstuse)) { + // we delete these later... creates problems + if (anno_check->getName().contains("Fresh") || + anno_check->getName().contains("Consistent")) { + continue; + } + } visited_fstuse.push_back(ci_fstuse); - unsigned int arg_num = ci_fstuse->getNumArgOperands(); - + unsigned int arg_num = ci_fstuse->arg_size(); + +#if DEBUG + errs() << "[Loop customUsers] Find index of tainted arg:\n"; +#endif // Find the index of the tainted argument - for (unsigned int i = 0; i < arg_num; i++){ - #if DEBUG - errs() << "DEBUG: comparing "<< *tArg <<" and " << *(ci_fstuse->getArgOperand(i))<<"\n"; - #endif - if(ci_fstuse->getArgOperand(i)==tArg) { - #if DEBUG - // errs() << "DEBUG: pushing arg of "<< calledFunc->getName() <<"\n"; - #endif + for (unsigned int i = 0; i < arg_num; i++) { + // TODO +#if DEBUG + errs() << "comparing " << *tArg << " and " << *(ci_fstuse->getArgOperand(i)) << "\n"; +#endif + if (ci_fstuse->getArgOperand(i) == tArg) { +#if DEBUG + // errs() << "pushing arg of "<< calledFunc->getName() <<"\n"; +#endif interProcFlows.push_back((ci_fstuse->getCalledFunction()->arg_begin() + i)); - //MUST also push back the call inst. + // MUST also push back the call inst. interProcFlows.push_back(ci_fstuse); - //and the srcOp + // and the srcOp interProcFlows.push_back(ci); - + break; } } - //find next local use - //promoted_inputs.push_back(ci); - taintedDecl[ci_fstuse].insert(ci); - fstUse = ptrAfterCall(tArg,ci_fstuse); + // find next local use + // promoted_inputs.push_back(ci); + taintedInsts[ci_fstuse].insert(ci); + fstUse = ptrAfterCall(tArg, ci_fstuse); if (fstUse == nullptr) { break; } - } - //re nullptr check - if (fstUse!=nullptr) { - interProcFlows = traverseLocal(fstUse, dyn_cast(currVal), &taintedDecl, nullptr); + } + // re nullptr check + if (fstUse != nullptr) { + interProcFlows = traverseLocal(fstUse, dyn_cast(curInst), &taintedInsts, nullptr); for (Value* vipf : interProcFlows) { - if(Instruction* iipf = dyn_cast(vipf)) { - if (CallInst* anno_check = dyn_cast(iipf)){ - //we delete these later... creates problems - if (anno_check->getName().contains("Fresh") || - anno_check->getName().contains("Consistent") ) { + if (Instruction* iipf = dyn_cast(vipf)) { + if (CallInst* anno_check = dyn_cast(iipf)) { + // we delete these later... creates problems + if (anno_check->getName().contains("Fresh") || + anno_check->getName().contains("Consistent")) { continue; } } - taintedDecl[iipf].insert(dyn_cast(currVal)); + taintedInsts[iipf].insert(dyn_cast(curInst)); } } } - } + } } - } else if (isa(currVal)) { - #if DEBUG - errs() << "exploring tainted arg " << *currVal << "\n"; - #endif - Instruction* caller = dyn_cast(toExplore.front()); - - //promoted_inputs.push_back(caller); + } else if (isa(curInst)) { +#if DEBUG + errs() << "[Loop toExplore] curInst = Argument (tainted arg)\n"; +#endif + + auto* caller = dyn_cast(toExplore.front()); toExplore.pop(); - Instruction* innerSrcOp = dyn_cast(toExplore.front()); +#if DEBUG + errs() << "[Loop toExplore] Caller: " << *caller << "\n"; +#endif + // promoted_inputs.push_back(caller); + + auto* innerInputInst = dyn_cast(toExplore.front()); toExplore.pop(); - interProcFlows = traverseLocal(currVal, innerSrcOp, &taintedDecl, caller); - - for (Value* vipf : interProcFlows) { - if(Instruction* iipf = dyn_cast(vipf)) { - if (CallInst* anno_check = dyn_cast(iipf)){ - //we delete these later... creates problems - if (anno_check->getName().contains("Fresh") || - anno_check->getName().contains("Consistent") ) { - continue; - } - } - taintedDecl[iipf].insert(innerSrcOp); - } - } - }//end elsif chain - #if DEBUG - errs() << "Finished iteration\n"; - #endif - for (Value* item : interProcFlows) { - if(item != NULL) { - //errs() <<"pushing item " << *item <<"\n"; +#if DEBUG + errs() << "[Loop toExplore] inputInst: " << *innerInputInst << "\n"; + errs() << "[Loop toExplore] Call traverseLocal with curInst (tainted), inputInst, caller\n"; +#endif + + interProcFlows = traverseLocal(curInst, innerInputInst, &taintedInsts, caller); + +#if DEBUG + errs() << "[Loop toExplore] Inspect interProcFlows:\n"; +#endif + for (auto* vipf : interProcFlows) { + if (auto* iipf = dyn_cast(vipf)) { + if (auto* anno_check = dyn_cast(iipf)) { + // We delete these later... creates problems + if (isAnnot(anno_check->getName())) continue; + } + taintedInsts[iipf].insert(innerInputInst); +#if DEBUG + errs() << "Adding innerInputInst (" << *innerInputInst << ") to set at " << *iipf << "\n"; +#endif + } + } + } // end elsif chain + + for (auto* item : interProcFlows) { + if (item != NULL) { +#if DEBUG + errs() << "Add to toExplore: " << *item << "\n"; +#endif toExplore.push(item); } else { errs() << "ERROR: encountered null interproc item\n"; } } - }//end while queue not empty - }//end for all iOp - - return taintedDecl; + +#if DEBUG + errs() << "*** Loop toExplore ***\n"; +#endif + } // end while queue not empty + } // end for all inputInsts + +#if DEBUG + errs() << "*** buildInputs ***\n"; +#endif + return make_pair(taintedInsts, inputInsts); } -val_vec traverseLocal(Value* tainted, Instruction* srcOp, inst_insts_map* iInfo, Instruction* caller) -{ - val_vec interProcSinks; - queue localDeps; +val_vec traverseLocal(Value* tainted, Instruction* srcInput, inst_insts_map* taintedInsts, Instruction* caller) { +#if DEBUG + errs() << "=== traverseLocal ===\n"; +#endif + + val_vec interProcFlows; + std::queue localDeps; +#if DEBUG + errs() << "Add tainted inst to localDeps\n"; +#endif localDeps.push(tainted); - while(!localDeps.empty()) { - Value* currVal = localDeps.front(); + while (!localDeps.empty()) { +#if DEBUG + errs() << "=== Loop localDeps ===\n"; +#endif + auto* curInst = localDeps.front(); localDeps.pop(); - val_vec customUsers; - if (StoreInst* si = dyn_cast(currVal)) { - //add the pointer to deps, as stores have no uses - //Add info on the store to the map - if(iInfo->find(si)!=iInfo->end()) { - if (find(iInfo->at(si).begin(), iInfo->at(si).end(), srcOp)!=iInfo->at(si).end()) { - continue; - } else { - iInfo->at(si).insert(srcOp); - } +#if DEBUG + errs() << "[Loop localDeps] curInst: " << *curInst << "\n"; +#endif + val_vec customUsers; + if (auto* si = dyn_cast(curInst)) { +#if DEBUG + errs() << "[Loop localDeps] curInst = StoreInst\n"; +#endif + // Add the pointer to deps, as stores have no uses + // Add info on the store to the map + if (taintedInsts->find(si) != taintedInsts->end()) { + auto insts = taintedInsts->at(si); + if (std::find(insts.begin(), insts.end(), srcInput) != insts.end()) continue; + taintedInsts->at(si).insert(srcInput); } else { - set seti; - seti.insert(srcOp); - iInfo->emplace(si, seti); + std::set seti; + seti.insert(srcInput); + taintedInsts->emplace(si, seti); } - #if DEBUG - errs() << " adding to map " << *srcOp << " for " << *si << "\n"; - #endif - //See if it is (or aliases?) one of the function arguments - for (Argument& arg : si->getFunction()->args()) { - Value* to_comp = si->getPointerOperand()->stripPointerCasts(); - #if DEBUG - errs() << " PBRef comp: " << *to_comp << " and " << arg << "\n"; - #endif - if (to_comp== &arg) { - //if taint came from inside any callsite is potentially tainted + + // See if it is (or aliases?) one of the function arguments (PBRef comp) + auto* storePtr = si->getPointerOperand()->stripPointerCasts(); + errs() << "[Loop args] storePtr: " << *storePtr << "\n"; +#if DEBUG + errs() << "[Loop localDeps] Go over fun args\n"; +#endif + for (auto& arg : si->getFunction()->args()) { +#if DEBUG + errs() << "[Loop args] arg: " << arg << "\n"; + // errs() << "[Loop localDeps] Is ptr being stored to (" << *storePtr << ") = fun arg (" << arg << ")\n"; +#endif + if (storePtr == &arg) { + // storePtr: _x_ = input(); + // arg: Consistent(_x_, 1); +#if DEBUG + errs() << "[Loop args] storePtr = arg\n"; +#endif + // If taint came from inside any callsite is potentially tainted if (caller == nullptr) { - for(Value* calls : si->getFunction()->users()) { - interProcSinks.push_back(calls); - interProcSinks.push_back(dyn_cast(&arg)); - if (Instruction* key = dyn_cast(calls)) { - //check to make sure not already visited - // iInfo->at(key).insert(srcOp); - +#if DEBUG + errs() << "[Loop args] Caller = nullptr"; +#endif + for (auto calls : si->getFunction()->users()) { + interProcFlows.push_back(calls); + interProcFlows.push_back(dyn_cast(&arg)); + if (auto key = dyn_cast(calls)) { + // Check to make sure not already visited + // taintedInsts->at(key).insert(srcOp); } } } else { - //otherwise, just the caller's - interProcSinks.push_back(caller); - interProcSinks.push_back(dyn_cast(&arg)); - if (Instruction* key = dyn_cast(caller)) { - - - //check to make sure not already visited - // iInfo->at(key).insert(srcOp); - +#if DEBUG + errs() << "[Loop args] Caller: " << *caller << "\n"; +#endif + // Otherwise, just the caller's + interProcFlows.push_back(caller); + interProcFlows.push_back(dyn_cast(&arg)); + if (auto key = dyn_cast(caller)) { + // Check to make sure not already visited + // taintedInsts->at(key).insert(srcOp); } } } } - //construct "users" of the store - #if DEBUG - errs() << "DEBUG: Store users\n"; - #endif - //add in loads that are reachable from the tainted store. - Value* ptr = si->getPointerOperand(); - //if bci, get the operand, as that's the useful ptr - if (BitCastInst* bciptr = dyn_cast(ptr) ){ - ptr = bciptr->getOperand(0); - } - for(Value* use : ptr->users()){ - if (Instruction* useOfStore = dyn_cast(use)) { - #if DEBUG - errs() << "DEBUG: checking use " << *useOfStore << "\n"; - #endif + // Construct "users" of the store +#if DEBUG + errs() << "[Loop localDeps] Add users (loads) of store to customUsers:\n"; +#endif + // Add in loads that are reachable from the tainted store. + auto* ptr = si->getPointerOperand(); + // If bci, get the operand, as that's the useful ptr + if (auto bciptr = dyn_cast(ptr)) ptr = bciptr->getOperand(0); + for (auto* use : ptr->users()) { + if (auto* useOfStore = dyn_cast(use)) { if (storePrecedesUse(useOfStore, si)) { +#if DEBUG + errs() << "[Loop Store Users] Store precedes this use, add:" << *useOfStore << "to customUsers\n"; +#endif customUsers.push_back(useOfStore); } } } - //update currVal to be the pointer - currVal = si->getPointerOperand(); + // Update curVal to be the pointer + curInst = si->getPointerOperand(); - //if it's a gepi, see if there are others that occur afterwards + // If it's a gepi, see if there are others that occur afterwards if (isa(si->getPointerOperand())) { inst_vec matching = couldMatchGEPI(dyn_cast(si->getPointerOperand())); - for (Instruction* item : matching) { + for (auto item : matching) { localDeps.push(item); } - //check pbref, need to compare op of the gepi, not gepi itself - for (Argument& arg : si->getFunction()->args()) { - #if DEBUG - errs() << " PBRef comp: " << *dyn_cast(currVal)->getOperand(0) << " and " << arg << "\n"; - #endif - if (dyn_cast(currVal)->getOperand(0) == &arg) { - //if taint came from inside any callsite is potentially tainted + // check pbref, need to compare op of the gepi, not gepi itself + for (auto& arg : si->getFunction()->args()) { +#if DEBUG + errs() << " PBRef comp: " << *dyn_cast(curInst)->getOperand(0) << " and " << arg << "\n"; +#endif + if (dyn_cast(curInst)->getOperand(0) == &arg) { + // if taint came from inside any callsite is potentially tainted if (caller == nullptr) { - for(Value* calls : si->getFunction()->users()) { - interProcSinks.push_back(calls); - interProcSinks.push_back(dyn_cast(&arg)); + for (Value* calls : si->getFunction()->users()) { + interProcFlows.push_back(calls); + interProcFlows.push_back(dyn_cast(&arg)); if (Instruction* key = dyn_cast(calls)) { - - // iInfo->at(key).insert(srcOp); + // taintedInsts->at(key).insert(srcOp); } } } else { - //otherwise, just the caller's - interProcSinks.push_back(caller); - interProcSinks.push_back(dyn_cast(&arg)); + // otherwise, just the caller's + interProcFlows.push_back(caller); + interProcFlows.push_back(dyn_cast(&arg)); if (Instruction* key = dyn_cast(caller)) { - - // iInfo->at(key).insert(srcOp); + // taintedInsts->at(key).insert(srcOp); } } } - } + } } - + } else { - //if not a store, do normal users of currval - customUsers.insert(customUsers.end(), currVal->user_begin(), currVal->user_end()); +#if DEBUG + errs() << "[Loop localDeps] curInst != StoreInst\n"; + errs() << "[Loop localDeps] Add users of curInst to customUsers:\n"; + for (auto* use : curInst->users()) errs() << *use << "\n"; +#endif + // If not a store, do normal users of curVal + customUsers.insert(customUsers.end(), curInst->user_begin(), curInst->user_end()); } - - - - for (Value* use : customUsers) { - - //check that the use of a tainted pointer is really tainted - - //this is checking if the use is a tainted store - - if (ReturnInst* ri = dyn_cast(use)) { - #if DEBUG - errs() << "DEBUG: in return case\n"; - #endif +#if DEBUG + errs() << "[Loop localDeps] Go over uses\n"; +#endif + //* Here we may cross over to another procedure + for (auto* use : customUsers) { + // Check that the use of a tainted pointer is really tainted + + // This is checking if the use is a tainted store + + if (auto ri = dyn_cast(use)) { +#if DEBUG + errs() << "[Loop customUsers] use = ReturnInst\n"; +#endif if (caller == nullptr) { - for(Value* calls : ri->getFunction()->users()) { - if(CallInst* ci = dyn_cast(calls)) { - interProcSinks.push_back(calls); - //extra for bookkeeping - interProcSinks.push_back(use); +#if DEBUG + errs() << "[Loop customUsers] No caller\n"; +#endif + for (auto calls : ri->getFunction()->users()) { + if (auto ci = dyn_cast(calls)) { + interProcFlows.push_back(calls); + // extra for bookkeeping + interProcFlows.push_back(use); } } } else { - //otherwise, just the caller's - interProcSinks.push_back(caller); - //extra for bookkeeping - interProcSinks.push_back(use); +#if DEBUG + errs() << "[Loop customUsers] Some caller\n"; +#endif + // otherwise, just the caller's + interProcFlows.push_back(caller); + // extra for bookkeeping + interProcFlows.push_back(use); } - - } else if (isa(use)) { - #if DEBUG - errs() << "DEBUG: in call case\n"; - #endif - //Add the right argument to the list - CallInst* ci = dyn_cast(use); - Function* calledFunc = ci ->getCalledFunction(); - if (calledFunc == NULL || calledFunc->empty()) { - //special case for llvm.memcpy - //See if it is (or aliases?) one of the function arguments - if (calledFunc!=NULL && calledFunc->hasName() && - calledFunc->getName().contains("llvm.memcpy")) { - //errs() << "DEBUG: memcpy " << *ci << "\n"; + } else if (auto* ci = dyn_cast(use)) { +#if DEBUG + errs() << "[Loop customUsers] use = CallInst\n"; +#endif + // Add the right argument to the list + auto* calledFun = ci->getCalledFunction(); + if (calledFun == NULL || calledFun->empty()) { + // special case for llvm.memcpy + // See if it is (or aliases?) one of the function arguments + if (calledFun != NULL && calledFun->hasName() && + calledFun->getName().contains("llvm.memcpy")) { + // errs() << "memcpy " << *ci << "\n"; Value* src = ci->getOperand(1)->stripPointerCasts(); Value* dest = ci->getOperand(0); - // errs() << "DEBUG: with dest " << *dest << "\n"; + // errs() << "with dest " << *dest << "\n"; if (BitCastInst* bci = dyn_cast(dest)) { dest = bci->getOperand(0); - } + } if (GetElementPtrInst* gepi = dyn_cast(dest)) { dest = gepi->getOperand(0); - // errs() << "DEBUG: and gepi dest " << *dest << "\n"; + // errs() << "and gepi dest " << *dest << "\n"; } bool found = false; for (Argument& arg : ci->getFunction()->args()) { - //Value* to_comp = - #if DEBUG +// Value* to_comp = +#if DEBUG errs() << " PBRef comp: " << *dest << " and " << arg << "\n"; - #endif - if (dest== &arg) { +#endif + if (dest == &arg) { found = true; - //if taint came from inside any callsite is potentially tainted + // if taint came from inside any callsite is potentially tainted if (caller == nullptr) { - for(Value* calls : ci->getFunction()->users()) { - interProcSinks.push_back(calls); - interProcSinks.push_back(dyn_cast(&arg)); + for (Value* calls : ci->getFunction()->users()) { + interProcFlows.push_back(calls); + interProcFlows.push_back(dyn_cast(&arg)); if (Instruction* key = dyn_cast(calls)) { - - // iInfo->at(key).insert(srcOp); + // taintedInsts->at(key).insert(srcOp); } } } else { - //otherwise, just the caller's - interProcSinks.push_back(caller); - interProcSinks.push_back(dyn_cast(&arg)); + // otherwise, just the caller's + interProcFlows.push_back(caller); + interProcFlows.push_back(dyn_cast(&arg)); if (Instruction* key = dyn_cast(caller)) { - // iInfo->at(key).insert(srcOp); + // taintedInsts->at(key).insert(srcOp); } } } } - //it wasn't pbref, just "store", so find fst ptr after call - //and also put in iInfo + // it wasn't pbref, just "store", so find fst ptr after call + // and also put in taintedInsts if (!found) { - Value* destFst = ptrAfterCall(dest,ci); - - - //in case of loop - if (destFst !=ci->getOperand(0)) { - // errs () << "found a memcpy store " << *destFst <<"\n"; - if(iInfo->find(ci)!=iInfo->end()) { - if (find(iInfo->at(ci).begin(), iInfo->at(ci).end(), srcOp)!=iInfo->at(ci).end()) { + Value* destFst = ptrAfterCall(dest, ci); + + // in case of loop + if (destFst != ci->getOperand(0)) { + // errs () << "found a memcpy store " << *destFst <<"\n"; + if (taintedInsts->find(ci) != taintedInsts->end()) { + if (find(taintedInsts->at(ci).begin(), taintedInsts->at(ci).end(), srcInput) != taintedInsts->at(ci).end()) { continue; } else { - iInfo->at(ci).insert(srcOp); + taintedInsts->at(ci).insert(srcInput); } } else { - set seti; - seti.insert(srcOp); - iInfo->emplace(ci, seti); + std::set seti; + seti.insert(srcInput); + taintedInsts->emplace(ci, seti); } localDeps.push(destFst); } - } - } //end memcpy check - - //conservative tainting decision - if (calledFunc->empty()) { - - //if it's empty but declared in our mod (one of the passed in C ones) - //and it returns a value, then consider the taint passed to the - //return - if (!calledFunc->getName().contains("llvm") && - !calledFunc->getName().contains("core")) { - #if DEBUG - errs() << "DEBUG: pushing presumed c lib func " << calledFunc->getName() << "\n"; - #endif - localDeps.push(ci); - } - + } + } // end memcpy check + + // conservative tainting decision + if (calledFun->empty()) { + // if it's empty but declared in our mod (one of the passed in C ones) + // and it returns a value, then consider the taint passed to the + // return + if (!calledFun->getName().contains("llvm") && + !calledFun->getName().contains("core")) { +#if DEBUG + errs() << "pushing presumed c lib func " << calledFun->getName() << "\n"; +#endif + localDeps.push(ci); + } } continue; - } - unsigned int arg_num = ci->getNumArgOperands(); - - // Find the index of the tainted argument - for (unsigned int i = 0; i < arg_num; i++){ - #if DEBUG - errs() << "DEBUG: comparing "<< *currVal <<" and " << *(ci->getArgOperand(i))<<"\n"; - #endif - if(ci->getArgOperand(i)==currVal) { - #if DEBUG - errs() << "DEBUG: pushing arg of "<< calledFunc->getName() <<"\n"; - #endif - interProcSinks.push_back((calledFunc->arg_begin() + i)); - //MUST also push back the call inst. - interProcSinks.push_back(ci); - //MUST also push back the current srcOp - interProcSinks.push_back(srcOp); - if (Instruction* key = dyn_cast(ci)) { - // iInfo->at(key).insert(srcOp); + + unsigned int arg_num = ci->arg_size(); + auto funName = calledFun->getName(); +#if DEBUG + errs() << "[Loop customUsers] Find tainted arg of " << funName << "\n"; +#endif + // Find the param index of the tainted argument + for (unsigned int i = 0; i < arg_num; i++) { + auto* arg = ci->getArgOperand(i); + if (arg == curInst) { + auto param = calledFun->arg_begin() + i; +#if DEBUG + errs() << "[Loop customUsers] Found tainted arg of " << funName << ": " << *arg << "\n"; + errs() << "[Loop customUsers] Add to interProcFlows the corresp. param " << *param << ", the call " << *ci << ", and srcInput " << *srcInput << "\n"; +#endif + interProcFlows.push_back(param); + // MUST also push back the call inst. + interProcFlows.push_back(ci); + // MUST also push back the current srcInput + interProcFlows.push_back(srcInput); + if (auto* key = dyn_cast(ci)) { + // taintedInsts->at(key).insert(srcOp); } - break; - } - } + break; + } + } + } else if (auto* iUse = dyn_cast(use)) { +#if DEBUG + errs() << "[Loop customUsers] use != ReturnInst & use != CallInst:\n"; + errs() << *iUse << "\n"; +#endif - } else if (Instruction* iUse = dyn_cast(use)) { if (iUse->isTerminator()) { if (iUse->getNumSuccessors() > 1) { - //Add control deps off of a branch. - #if DEBUG - errs() << "DEBUG: adding condeps case\n"; - #endif +// Add control deps off of a branch. +#if DEBUG + errs() << "adding condeps case\n"; +#endif val_vec controlDeps = getControlDeps(iUse); - //for all condep, add any reached loads, and add the store to the map - for (Value* item : controlDeps) { - if (StoreInst* siCon = dyn_cast(item)) { + // for all condep, add any reached loads, and add the store to the map + for (auto* item : controlDeps) { + if (auto* siCon = dyn_cast(item)) { localDeps.push(siCon); } - }//end for vals in condep + } } - }//end terminator check - #if DEBUG - //errs() << "DEBUG: pushing "<< *iUse<<"\n"; - #endif + } + +#if DEBUG + errs() << "[Loop customUsers] Add use to localDeps\n"; +#endif + //* Here we may push inst from another procedure, crossing boundaries localDeps.push(iUse); } } +#if DEBUG + errs() << "*** Loop localDeps ***\n"; +#endif } - return interProcSinks; +#if DEBUG + errs() << "*** traverseLocal ***\n"; +#endif + return interProcFlows; } +std::set findInputInsts(Module* M) { +#if DEBUG + errs() << "=== findInputInsts ===\n"; +#endif + std::set inputInsts; + // Find IO_NAME annotations + for (auto& gv : M->globals()) { + if (gv.getName().starts_with("IO_NAME")) { + Function* ioFun; -inst_vec findInputInsts(Module* M) -{ - inst_vec sources; - func_vec io_name; - //Find io name annotations - for(GlobalVariable& gv : M->globals()) { - if(gv.getName().contains("IO_NAME")) { - - if( Function* fp = dyn_cast(gv.getInitializer()->getOperand(0)->stripPointerCasts())) { - #if DEBUG - errs() << "Found io inst "<< fp->getName() <<"\n"; - #endif - io_name.push_back(fp); + auto* init = gv.getInitializer(); + if (isa(init)) { + ioFun = dyn_cast(init); } else { - errs() << "ERROR: could not unwrap function pointer from annotation\n"; + ioFun = dyn_cast(init->getOperand(0)); } - } - } - - //now, search for calls to those functions - for (Function& func : * M) { - for (BasicBlock& bb : func) { - for(Instruction& inst : bb) { - if(CallInst* ci = dyn_cast(&inst)) { - if(find(io_name.begin(), io_name.end(),ci->getCalledFunction())!=io_name.end()) { - sources.push_back(&inst); - } + + if (ioFun != nullptr) { +#if DEBUG + errs() << "Found IO fun: " << ioFun->getName() << "\n"; +#endif + + // Now, search for calls to those functions + for (auto& F : *M) { + for (auto& B : F) { + for (auto& I : B) { + if (auto* ci = dyn_cast(&I)) { + if (ioFun == ci->getCalledFunction()) { +#if DEBUG + errs() << "Found IO call: " << I << "\n"; +#endif + inputInsts.insert(ci); + } + } + } + } } + } else { + errs() << "[ERROR] Could not unwrap function pointer from annotation\n"; } - - } + } } - return sources; -} + errs() << "*** findInputInsts ***\n"; + return inputInsts; +} -/*See if a particular store is exposed to a use -- possibly replace couldLoadTainted*/ +// See if a particular store is exposed to a use -- possibly replace couldLoadTainted bool storePrecedesUse(Instruction* use, StoreInst* toMatch) { - queue to_visit; - vector visited; + std::queue to_visit; + std::vector visited; BasicBlock* current; - vector possible; + std::vector possible; int found = 0; int skip = 1; - + to_visit.push(use->getParent()); - while(!to_visit.empty()) { + while (!to_visit.empty()) { current = to_visit.front(); to_visit.pop(); - - for(BasicBlock::reverse_iterator i = current->rbegin(), e = current->rend(); i!=e;++i) { + + for (BasicBlock::reverse_iterator i = current->rbegin(), e = current->rend(); i != e; ++i) { Instruction* inst = &*i; - //don't look at li block before li - if((current == use->getParent())&&(skip)) { - //errs() << "skipping" << *inst <<"\n"; - if(use==inst){ - skip = 0; - } - continue; + // don't look at li block before li + if ((current == use->getParent()) && (skip)) { + // errs() << "skipping" << *inst <<"\n"; + if (use == inst) { + skip = 0; + } + continue; + } + // if(BI!=nullptr) { + // errs() << "looking at" << *BI <<"\n"; + if (StoreInst* si = dyn_cast(inst)) { + // errs() << "found a store" << *si <<"\n"; + if (si->getPointerOperand() == toMatch->getPointerOperand()) { + possible.push_back(si); + found = 1; + break; + } } - //if(BI!=nullptr) { - //errs() << "looking at" << *BI <<"\n"; - if (StoreInst* si = dyn_cast(inst)) { - //errs() << "found a store" << *si <<"\n"; - if (si->getPointerOperand() == toMatch->getPointerOperand()) { - possible.push_back(si); - found = 1; - break; - } - } } - //we found a store in this node - if(found) { + // we found a store in this node + if (found) { found = 0; continue; } /*add pred. blocks to our queue*/ for (auto PI = pred_begin(current); PI != pred_end(current); ++PI) { - //if it's new - if(!(find(visited.begin(), visited.end(), *PI) != visited.end())){ - visited.push_back(*PI); - to_visit.push(*PI); + // if it's new + if (!(find(visited.begin(), visited.end(), *PI) != visited.end())) { + visited.push_back(*PI); + to_visit.push(*PI); } } } /*Was one of the preceding writes the store in question?*/ - for(Value* poss : possible) { - if(poss == toMatch) { - return true; + for (Value* poss : possible) { + if (poss == toMatch) { + return true; } - } - //this use does not consume the tainted store + // this use does not consume the tainted store return false; } - /*See if the same EP is used in multiple GEPI, check if exposed*/ inst_vec couldMatchGEPI(GetElementPtrInst* tGEPI) { - queue to_visit; - vector visited; + std::queue to_visit; + std::vector visited; BasicBlock* current; - vector possible; + std::vector possible; inst_vec matching; int found = 0; int skip = 1; - + to_visit.push(tGEPI->getParent()); - while(!to_visit.empty()) { + while (!to_visit.empty()) { current = to_visit.front(); to_visit.pop(); - - //forwards exploration - for(Instruction& i : *current) { + + // forwards exploration + for (Instruction& i : *current) { Instruction* inst = &i; - //don't look at gepi block before gepi - if((current == tGEPI->getParent())&&(skip)) { - //errs() << "skipping" << *inst <<"\n"; - if(tGEPI==inst){ - skip = 0; - } - continue; + // don't look at gepi block before gepi + if ((current == tGEPI->getParent()) && (skip)) { + // errs() << "skipping" << *inst <<"\n"; + if (tGEPI == inst) { + skip = 0; + } + continue; } - //if(BI!=nullptr) { - //errs() << "looking at" << *BI <<"\n"; - if (GetElementPtrInst* another = dyn_cast(inst)) { - //errs() << "found a store" << *si <<"\n"; - //check if the ops match - if (another->getPointerOperand() == tGEPI->getPointerOperand()) { - //check if used in load or store - for (Value* pUse : another->users()) { + // if(BI!=nullptr) { + // errs() << "looking at" << *BI <<"\n"; + if (GetElementPtrInst* another = dyn_cast(inst)) { + // errs() << "found a store" << *si <<"\n"; + // check if the ops match + if (another->getPointerOperand() == tGEPI->getPointerOperand()) { + // check if used in load or store + for (Value* pUse : another->users()) { if (isa(pUse)) { found = 1; break; } } - //no store + // no store if (!found) { - #if DEBUG - errs() << "matching GEPS: " << *another<<" and " << *tGEPI <<"\n"; - #endif +#if DEBUG + errs() << "matching GEPS: " << *another << " and " << *tGEPI << "\n"; +#endif matching.push_back(another); } - } - } + } + } } - //we found a store in this node - if(found) { + // we found a store in this node + if (found) { found = 0; continue; } /*add succ. blocks to our queue*/ for (auto SI = succ_begin(current); SI != succ_end(current); ++SI) { - //if it's new - if(!(find(visited.begin(), visited.end(), *SI) != visited.end())){ - visited.push_back(*SI); - to_visit.push(*SI); + // if it's new + if (!(find(visited.begin(), visited.end(), *SI) != visited.end())) { + visited.push_back(*SI); + to_visit.push(*SI); } } } - + return matching; } /*Find first use of a pointer after a callInst, for pass-by-ref*/ Instruction* ptrAfterCall(Value* ptr, CallInst* ci) { - queue to_visit; - vector visited; + std::queue to_visit; + std::vector visited; BasicBlock* current; - + int found = 0; int skip = 1; - + to_visit.push(ci->getParent()); - while(!to_visit.empty()) { + while (!to_visit.empty()) { current = to_visit.front(); to_visit.pop(); - - //forwards exploration - for(Instruction& i : *current) { + + // forwards exploration + for (Instruction& i : *current) { Instruction* inst = &i; - //don't look at gepi block before gepi - if((current == ci->getParent())&&(skip)) { - //errs() << "skipping" << *inst <<"\n"; - if(ci==inst){ - skip = 0; - } - continue; + // don't look at gepi block before gepi + if ((current == ci->getParent()) && (skip)) { + // errs() << "skipping" << *inst <<"\n"; + if (ci == inst) { + skip = 0; + } + continue; } - //if the inst is a use of the pointer - if (find(ptr->user_begin(),ptr->user_end(), inst)!=ptr->user_end()) { + // if the inst is a use of the pointer + if (std::find(ptr->user_begin(), ptr->user_end(), inst) != ptr->user_end()) { return inst; } - } /*add succ. blocks to our queue*/ for (auto SI = succ_begin(current); SI != succ_end(current); ++SI) { - //if it's new - if(!(find(visited.begin(), visited.end(), *SI) != visited.end())){ - visited.push_back(*SI); - to_visit.push(*SI); + // if it's new + if (!(find(visited.begin(), visited.end(), *SI) != visited.end())) { + visited.push_back(*SI); + to_visit.push(*SI); } } } return nullptr; } - -/*This is a function to return all the control dependent stores off of a control inst -Input -- ti, the (formerly) terminator inst +/*This is a function to return all the control dependent stores off of a control inst +Input -- ti, the (formerly) terminator inst Output -- list of deps */ -val_vec getControlDeps(Instruction* ti) -{ +val_vec getControlDeps(Instruction* ti) { val_vec deps; int succ_i = 0; while (succ_i < ti->getNumSuccessors()) { BasicBlock* bb = ti->getSuccessor(succ_i); succ_i++; - for(Instruction& inst : *bb) { - //if we encounter a store, add to deps - if(isa(&inst)) { - deps.push_back(&inst); - } //if we encounter a multi succ branch, recursive call, if we encouter a join, continue to next succ - else if(inst.isTerminator()) { - - if(ti->getNumSuccessors() > 1) { - vector intermed = getControlDeps(&inst); - for(Value* item : intermed) { - deps.push_back(item); - } - } else { - break; - } + for (Instruction& inst : *bb) { + // if we encounter a store, add to deps + if (isa(&inst)) { + deps.push_back(&inst); + } // if we encounter a multi succ branch, recursive call, if we encouter a join, continue to next succ + else if (inst.isTerminator()) { + if (ti->getNumSuccessors() > 1) { + std::vector intermed = getControlDeps(&inst); + for (Value* item : intermed) { + deps.push_back(item); + } + } else { + break; + } } } } return deps; } - -/*Get direct uses (at src level, not IR) of a fresh var*/ -inst_vec traverseDirectUses(Instruction* root) -{ +// Get direct uses (at src level, not IR) of a fresh var +inst_vec traverseDirectUses(Instruction* root) { +#if DEBUG + errs() << "=== traverseDirectUses ===\n"; +#endif inst_vec uses; - queue localDeps; + std::queue localDeps; +#if DEBUG + errs() << "Add root to localDeps: " << *root << "\n"; +#endif localDeps.push(root); - - //Edge case: check if return is an internally allocated stack var + + // Edge case: check if return is an internally allocated stack var Value* retPtr; - Instruction* last = &(root->getFunction()->back().back()); - if (ReturnInst* ri = dyn_cast(last)) { - for (Use& op : ri->operands()) { - if(LoadInst* li = dyn_cast(op.get())) { + auto* last = &(root->getFunction()->back().back()); + if (auto* ri = dyn_cast(last)) { + for (auto& op : ri->operands()) { + if (auto* li = dyn_cast(op.get())) { retPtr = li->getPointerOperand(); +#if DEBUG + errs() << "retPtr: " << *retPtr << "\n"; +#endif } } - } - while(!localDeps.empty()) { - Instruction* currVal = localDeps.front(); - uses.push_back(currVal); + while (!localDeps.empty()) { + auto* curVal = localDeps.front(); +#if DEBUG + errs() << "[Loop localDeps] Add curVal to uses: " << *curVal << "\n"; +#endif + uses.push_back(curVal); localDeps.pop(); - for (Value* use : currVal->users()) { - //if it's a gepi, see if there are others that occur afterwards - // errs() << *use <<" is a direct use of " << *currVal<<"\n"; + +#if DEBUG + errs() << "[Loop localDeps] Go over curVal users\n"; +#endif + for (auto* use : curVal->users()) { +#if DEBUG + errs() << "[Loop users] use: " << *use << "\n"; +#endif + // If it's a gepi, see if there are others that occur afterwards + // errs() << *use <<" is a direct use of " << *currVal<<"\n"; if (isa(use)) { - inst_vec matching = couldMatchGEPI(dyn_cast(use)); - for (Instruction* item : matching) { - // errs() << "pushing to local deps " << *item <<"\n"; + auto matching = couldMatchGEPI(dyn_cast(use)); + for (auto* item : matching) { + // errs() << "pushing to local deps " << *item <<"\n"; localDeps.push(item); } - } - else if (ReturnInst* ri = dyn_cast(use)) { - for(Value* calls : ri->getFunction()->users()) { - if(isa(calls)) { + } else if (ReturnInst* ri = dyn_cast(use)) { + for (Value* calls : ri->getFunction()->users()) { + if (isa(calls)) { uses.push_back(dyn_cast(calls)); - } } } else if (StoreInst* si = dyn_cast(use)) { - //if stores into ret pointer, treat as above +#if DEBUG + errs() << "[Loop users] use = StoreInst\n"; +#endif + // If stores into ret pointer, treat as above if (si->getPointerOperand() == retPtr) { - for(Value* calls : si->getFunction()->users()) { - if(isa(calls)) { - uses.push_back(dyn_cast(calls)); - +#if DEBUG + errs() << "[Loop users] ptr operand = retPtr\n"; +#endif + for (Value* calls : si->getFunction()->users()) { + if (isa(calls)) { + uses.push_back(dyn_cast(calls)); } - } + } } } else if (BranchInst* bi = dyn_cast(use)) { - //if a use is a branch inst the atomic region needs to - //dominate the successors + // If a use is a branch inst the atomic region needs to + // dominate the successors for (BasicBlock* bbInterior : bi->successors()) { - //skip panic blocks, otherwise there will be no post dom + // Skip panic blocks, otherwise there will be no post dom if (bbInterior->getName().equals("panic")) { continue; } uses.push_back(&(bbInterior->front())); } } else if (CallInst* ci = dyn_cast(use)) { - if(ci->hasName() && ci->getName().startswith("_")) { - //fall through +#if DEBUG + errs() << "[Loop users] use = CallInst\n"; +#endif + if (ci->hasName() && ci->getName().startswith("_")) { + // Fall through } else { +#if DEBUG + errs() << "[Loop users] Add CallInst to uses\n"; +#endif uses.push_back(ci); continue; } } - if (Instruction* iUse = dyn_cast(use)) { - //see if load is to another var or just internal ssa - if (LoadInst* li = dyn_cast(iUse)) { - if(li->hasName()) { - //Hacky --verify that this is always true - if(!li->getName().startswith("_")) { + + if (auto* iUse = dyn_cast(use)) { + // See if load is to another var or just internal ssa + if (auto* li = dyn_cast(iUse)) { + if (li->hasName()) { + // Hacky -- verify that this is always true + if (!li->getName().startswith("_")) continue; - } } } + +#if DEBUG + errs() << "[Loop users] Add use to localDeps\n"; +#endif localDeps.push(iUse); } } } +#if DEBUG + errs() << "*** traverseDirectUses ***\n"; +#endif return uses; } +inst_vec traverseUses(Instruction* root) { +#if DEBUG + errs() << "=== traverseUses ===\n"; +#endif + auto directUses = traverseDirectUses(root); + inst_set uses(directUses.begin(), directUses.end()); + + for (auto* directUse : directUses) { +#if DEBUG + errs() << "[directUses] directUse: " << *directUse << "\n"; +#endif + + if (auto* si = dyn_cast(directUse)) { +#if DEBUG + errs() << "[directUses] directUse = StoreInst\n"; +#endif + auto* ptr = si->getPointerOperand(); +#if DEBUG + errs() << "[directUses] ptr operand: " << *ptr << "\n"; +#endif + + for (auto* ptrUse : ptr->users()) { + if (auto* li = dyn_cast(ptrUse)) { +#if DEBUG + errs() << "[ptrUsers] Add ptrUse (LoadInst) to uses: " << *ptrUse << "\n"; +#endif + uses.emplace(li); + + for (auto* liUse : li->users()) { + if (auto* ci = dyn_cast(liUse)) { +#if DEBUG + errs() << "[liUsers] Add liUse (CallInst) to uses: " << *liUse << "\n"; +#endif + uses.emplace(ci); + } + } + } + } + } else if (auto* li = dyn_cast(directUse)) { +#if DEBUG + errs() << "[directUses] directUse = LoadInst\n"; +#endif + auto* ptr = li->getPointerOperand(); + for (auto* ptrUse : ptr->users()) { + if (auto* si = dyn_cast(ptrUse)) { +#if DEBUG + errs() << "[ptrUses] Add ptrUse (StoreInst) to uses: " << *si << "\n"; +#endif + uses.emplace(si); + } + } + } + } + +#if DEBUG + errs() << "*** traverseUses ***\n"; +#endif + inst_vec uses_vec(uses.begin(), uses.end()); + return uses_vec; +} diff --git a/ocelot/AtomicRegionInference/src/include/ConsistentInference.h b/ocelot/AtomicRegionInference/src/include/ConsistentInference.h deleted file mode 100644 index 1f7a429..0000000 --- a/ocelot/AtomicRegionInference/src/include/ConsistentInference.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __CONSISTENTINFERENCE__ -#define __CONSISTENTINFERENCE__ - -#include "HelperTypes.h" -using namespace llvm; -using namespace std; - -class ConsistentInference { -public: - ConsistentInference(Pass* _pass, Module* _m, Function* _as, Function* _ae) { - pass = _pass; - m = _m; - atomStart = _as; - atomEnd = _ae; - } - void inferConsistent(map allSets); - void inferFresh(inst_vec_vec allSets); - void addRegion(inst_vec conSet, int regType); - Function* commonPredecessor(map blocks, Function* root); - Instruction* insertRegionInst(int regInst, Instruction* insertBefore); - bool sameFunction(map blockMap); - Instruction* truncate(BasicBlock* bb, bool forwards, inst_vec conSet, set nested); - vector deepCaller(Function* root, vector funcList, Function** goal); - inst_inst_pair findSmallest(vectorregionsFound); - BasicBlock* getLoopEnd(BasicBlock* bb); - bool loopCheck(BasicBlock* bb); - int getSubLength(BasicBlock* bb, Instruction* end, vector visited); - - - -private: - Pass* pass; - Module* m; - Function* atomStart; - Function* atomEnd; -}; - -#endif diff --git a/ocelot/AtomicRegionInference/src/include/HelperTypes.h b/ocelot/AtomicRegionInference/src/include/HelperTypes.h index 843c498..4a9414e 100644 --- a/ocelot/AtomicRegionInference/src/include/HelperTypes.h +++ b/ocelot/AtomicRegionInference/src/include/HelperTypes.h @@ -1,52 +1,41 @@ -#ifndef __HELPERTYPES__ -#define __HELPERTYPES__ - -#include "llvm/Pass.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Function.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/ADT/ilist.h" -#include "llvm/IR/DebugInfoMetadata.h" -#include "llvm/IR/SymbolTableListTraits.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/BasicAliasAnalysis.h" -#include "llvm/Analysis/CallGraph.h" -#include -#include -#include -#include -//#include - -#define DEBUG 0 - -using namespace llvm; - -typedef std::vector val_vec; -typedef std::vector bb_vec; -typedef std::vector inst_vec; -typedef std::map val_insts_map; -typedef std::vector gv_vec; -typedef std::vector> val_inst_vec; -typedef std::vector> inst_inst_vec; -typedef std::map inst_vals_map; -typedef std::map> inst_insts_map; -typedef std::vector func_vec; -typedef std::vector inst_vec_vec; -typedef std::pair inst_inst_pair; - -extern gv_vec gv_list; - -/*bool isArray(Value* v); -bool isTask(Function* F); -bool isMemcpy(Instruction* I); -uint64_t getSize(Value* val); -int is_atomic_boundary(Instruction* ci); -#define OVERHEAD 0 -*/ -#endif +#ifndef __HELPERTYPES__ +#define __HELPERTYPES__ + +#include +#include +#include +#include + +#include "llvm/ADT/ilist.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/SymbolTableListTraits.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +using namespace llvm; + +typedef std::vector val_vec; +typedef std::vector bb_vec; +typedef std::vector inst_vec; +typedef std::set inst_set; +typedef std::map val_insts_map; +typedef std::vector gv_vec; +typedef std::vector> val_inst_vec; +typedef std::pair inst_inst_pair; +typedef std::vector inst_inst_vec; +typedef std::map inst_vals_map; +typedef std::map inst_insts_map; +typedef std::vector func_vec; +typedef std::vector inst_vec_vec; +typedef std::map inst_inst_map; + +extern gv_vec gv_list; + +#endif diff --git a/ocelot/AtomicRegionInference/src/include/Helpers.h b/ocelot/AtomicRegionInference/src/include/Helpers.h new file mode 100644 index 0000000..bde9ca9 --- /dev/null +++ b/ocelot/AtomicRegionInference/src/include/Helpers.h @@ -0,0 +1,20 @@ +#ifndef __HELPERS__ +#define __HELPERS__ + +#include + +#include "HelperTypes.h" + +using namespace llvm; + +#define DEBUG 1 +#define OPT 1 + +std::string getSimpleNodeLabel(const Value* Node); +bool isAnnot(const StringRef annotName); +void printInstInsts(const inst_insts_map& iim, bool onlyCalls = false); +void printInsts(const inst_vec& iv); +void printIntInsts(const std::map& iim); +void patchClonedBlock(BasicBlock* block, inst_inst_map clonedInsts); + +#endif \ No newline at end of file diff --git a/ocelot/AtomicRegionInference/src/include/InferAtomicPass.h b/ocelot/AtomicRegionInference/src/include/InferAtomicPass.h deleted file mode 100644 index bd0036a..0000000 --- a/ocelot/AtomicRegionInference/src/include/InferAtomicPass.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef __INFERPASS__ -#define __INFERPASS__ - -#include "HelperTypes.h" -#include "ConsistentInference.h" -#include "llvm/ADT/APInt.h" -#include "llvm/IR/Verifier.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/IR/Argument.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include - -using namespace llvm; - -class InferAtomicModulePass : public ModulePass { - public: - static char ID; - InferAtomicModulePass() : ModulePass(ID) {} - - virtual bool runOnModule(Module &M); - int getMaxCost(Function* f); - void mergeRegions(Function* f); - void getAnnotations(map* conSets, inst_vec_vec* freshVars, inst_insts_map inputs, inst_vec* toDelete); - inst_vec_vec collectFresh(inst_vec_vec startingPoints, inst_insts_map info); - map collectCon(map startingPointa, inst_insts_map inputMap); - void removeAnnotations(inst_vec* toDelete); - - - virtual void getAnalysisUsage(AnalysisUsage& AU) const { - AU.setPreservesAll(); - //AU.addRequired(); - //AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - } - Module* getModule() { - return m; - } - Module* setModule(Module* _m) { - return m = _m; - } - private: - Module* m; - int capacitorSize; - Function* atomStart; - Function* atomEnd; - - -}; - -#endif diff --git a/ocelot/AtomicRegionInference/src/include/InferAtoms.h b/ocelot/AtomicRegionInference/src/include/InferAtoms.h new file mode 100644 index 0000000..1da8c5a --- /dev/null +++ b/ocelot/AtomicRegionInference/src/include/InferAtoms.h @@ -0,0 +1,60 @@ +#ifndef __INFERATOMS__ +#define __INFERATOMS__ + +#include +#include +#include +#include +#include +#include + +#include "Helpers.h" +#include "InferFreshCons.h" +#include "TaintTracker.h" +#include "llvm/ADT/APInt.h" +#include "llvm/Analysis/PostDominators.h" +#include "llvm/Pass.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/InstructionNamer.h" + +using namespace llvm; + +struct InferAtomsPass : public PassInfoMixin { + public: + InferAtomsPass() {} + PreservedAnalyses run(Module& M, ModuleAnalysisManager& AM); + + void getAnnotations(std::map* consVars, inst_vec_vec* freshVars, inst_insts_map inputMap, inst_vec* toDelete); + inst_vec_vec collectFresh(inst_vec_vec startingPoints, inst_insts_map info); + std::map collectCons(std::map startingPointa, inst_insts_map inputMap); + void removeAnnotations(inst_vec& toDelete); + void setModule(Module* _M) { M = _M; } + + private: + Module* M; + Function* atomStart; + Function* atomEnd; +}; + +extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo +llvmGetPassPluginInfo() { + return { + .APIVersion = LLVM_PLUGIN_API_VERSION, + .PluginName = "Atomic Region Inference Pass", + .PluginVersion = "v0.1", + .RegisterPassBuilderCallbacks = [](PassBuilder& PB) { + // PB.registerPipelineParsingCallback( + // [](StringRef PassName, FunctionPassManager& FPM, ...) { + // FPM.addPass(InstructionNamerPass()); + // return true; + // }); + PB.registerPipelineStartEPCallback( + [](ModulePassManager& MPM, OptimizationLevel Level) { + MPM.addPass(InferAtomsPass()); + }); + }}; +} + +#endif diff --git a/ocelot/AtomicRegionInference/src/include/InferFreshCons.h b/ocelot/AtomicRegionInference/src/include/InferFreshCons.h new file mode 100644 index 0000000..f26adbf --- /dev/null +++ b/ocelot/AtomicRegionInference/src/include/InferFreshCons.h @@ -0,0 +1,43 @@ +#ifndef __INFERFRESHCONS__ +#define __INFERFRESHCONS__ + +#include "Helpers.h" + +using namespace llvm; + +struct InferFreshCons { + public: + InferFreshCons(FunctionAnalysisManager* _FAM, Module* _m, Function* _as, Function* _ae) { + FAM = _FAM; + m = _m; + atomStart = _as; + atomEnd = _ae; + } + + enum RegionKind { Fresh, + Consistent }; + + enum InsertKind { Start, + End }; + + void inferCons(std::map consSets, inst_vec_vec* freshSets, inst_vec* toDeleteAnnots, std::set* inputInsts); + void inferFresh(inst_vec_vec freshSets, std::map* consSets, inst_vec* toDeleteAnnots, std::set* inputInsts); + void addRegion(inst_vec conSet, inst_vec_vec* other, inst_vec* toDeleteAnnots, std::set* inputInsts); + Function* findCandidate(std::map blocks, Function* root); + Instruction* insertRegionInst(InsertKind insertKind, Instruction* insertBefore); + bool sameFunction(std::map blockMap); + Instruction* truncate(BasicBlock* bb, bool forwards, inst_vec conSet, std::set nested); + std::vector deepCaller(Function* root, std::vector& funcList, Function** goal); + inst_inst_pair findShortest(inst_inst_vec regionsFound); + BasicBlock* getLoopEnd(BasicBlock* bb); + bool loopCheck(BasicBlock* bb); + int getSubLength(BasicBlock* bb, Instruction* end, std::vector visited); + + private: + FunctionAnalysisManager* FAM; + Module* m; + Function* atomStart; + Function* atomEnd; +}; + +#endif diff --git a/ocelot/AtomicRegionInference/src/include/TaintTracker.h b/ocelot/AtomicRegionInference/src/include/TaintTracker.h index ffd90ef..1b06e48 100644 --- a/ocelot/AtomicRegionInference/src/include/TaintTracker.h +++ b/ocelot/AtomicRegionInference/src/include/TaintTracker.h @@ -1,40 +1,18 @@ -#include "llvm/Pass.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/AliasSetTracker.h" -#include "llvm/Analysis/CFLSteensAliasAnalysis.h" -#include "llvm/Analysis/MemoryLocation.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/CFG.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Operator.h" -#include "llvm/IR/Metadata.h" -#include "llvm/IR/DebugInfoMetadata.h" -#include -#include -#include -#include -#include -#include -#include -#include "HelperTypes.h" +#ifndef __TAINTTRACKER__ +#define __TAINTTRACKER__ -using namespace llvm; -using namespace std; +#include "Helpers.h" +using namespace llvm; -inst_insts_map buildInputs(Module* m); +std::pair> buildInputs(Module* m); val_vec traverseLocal(Value* tainted, Instruction* srcOp, inst_insts_map* buildMap, Instruction* caller); - -inst_vec findInputInsts(Module* M); -Instruction* ptrAfterCall(Value* ptr, CallInst* ci); +std::set findInputInsts(Module* M); +Instruction* ptrAfterCall(Value* ptr, CallInst* ci); bool storePrecedesUse(Instruction* use, StoreInst* toMatch); inst_vec couldMatchGEPI(GetElementPtrInst* tGEPI); val_vec getControlDeps(Instruction* ti); inst_vec traverseDirectUses(Instruction* root); +inst_vec traverseUses(Instruction* root); + +#endif