Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use trivial data-dependencies to ignore non-rt functions with trivial conditionals #35

Open
falkTX opened this issue Jan 17, 2018 · 3 comments

Comments

@falkTX
Copy link
Contributor

falkTX commented Jan 17, 2018

Note sure how to title this.

Take the following code:
https://github.com/falkTX/Carla/blob/01b50d2f0ba44f4e98e2ae75082a0a465116d9ef/source/backend/plugin/CarlaPlugin.cpp#L1306
There's 2 boolean arguments - sendOsc and sendCallback.
This function is called from RT side, but with those arguments as false.
For example here: https://github.com/falkTX/Carla/blob/01b50d2f0ba44f4e98e2ae75082a0a465116d9ef/source/backend/plugin/CarlaPluginLADSPA.cpp#L968

Hopefully it's possible to detect the cases where the code obviously is not being run, like calling a function with 'false' directly, as in the examples.
Carla's stoat output is 75% filled with stuff like this.

@fundamental fundamental changed the title Ignore non-rt-safe blocks with clear false statements Use trivial data-dependencies to ignore non-rt functions with trivial conditionals Jan 17, 2018
@fundamental
Copy link
Owner

One of the issues with stoat (documented at LAC) is that it does not use any data dependent information to determine if a function will be called.

For example if you have the function:

void a(void) {
  if(0)
    b();
}

Then stoat will (to the best of my knowledge) report that a can possibly call b as clang is called with -O0.

The above case is fairly easy to handle with a few of LLVM's optimization passes, though optimization operations make it a fair bit harder to reason about the original code. The case that you're interested in is a harder one however as you want to be able to propagate a constant through a function call. As to why this is difficult let's look at the minimum test example:

void a(void) { }

void b(int c)
{
    if(c)
        a();
}

void d(void) { b(1); }

void e(void) { b(0); }

Translated to LLVM IR this looks like:

; ModuleID = '<stdin>'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

; Function Attrs: nounwind uwtable
define void @a() #0 {
  ret void
}

; Function Attrs: nounwind uwtable
define void @b(i32 %c) #0 {
  %1 = alloca i32, align 4
  store i32 %c, i32* %1, align 4
  %2 = load i32, i32* %1, align 4
  %3 = icmp ne i32 %2, 0
  br i1 %3, label %4, label %5

; <label>:4                                       ; preds = %0
  call void @a()
  br label %5

; <label>:5                                       ; preds = %4, %0
  ret void
}

; Function Attrs: nounwind uwtable
define void @d() #0 {
  call void @b(i32 1)
  ret void
}

; Function Attrs: nounwind uwtable
define void @e() #0 {
  call void @b(i32 0)
  ret void
}

attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)"}

To use the data dependency within function b(), we must look at the branch above <label>:4 . From there we need to establish if %3 is true/false. Next we need to invert the logic about %2 to say that 0== no branch, then a few more steps have to trace the value back to being an argument.

Expanding this to across functions, then there needs to be a new node in the stoat graph which is a specialization of b() whenever there's a 0 argument. With that established then there likely needs to be another pass over all calls of b() to determine if they're b(special-case) or b(unknown-case). Then it's possible to say that e calls b_specialization0 rather than just b().

So the feature request is certainly doable, but a non-trivial bit of work. My current suggestion is to have separate functions for realtime and non-realtime operations, though I realize that this may not always be a possibility. In those cases a suppression would be useful.

@falkTX
Copy link
Contributor Author

falkTX commented Jan 17, 2018

hmm I see.
would it be possible to add a decorator/attribute for functions that can be called like this?
that would mean only selected functions will need to go through the special argument verification

@fundamental
Copy link
Owner

An attribute doesn't save that much time/effort IMO. Most of the work is in the complexity of implementing the feature, not the time spent executing the feature after it's implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants