This is an archive of the discontinued LLVM Phabricator instance.

[RFC][SimplifyCFG] Allow target to control SpeculateOneExpensiveInst
AbandonedPublic

Authored by yonghong-song on Jun 15 2020, 11:20 AM.

Details

Summary

This RFC patch is part of effort to control code motion across
control flow boundaries in BPF. First, some use cases on why
we want to prevent speculative code motion. The patch is on
top of another patch https://reviews.llvm.org/D82112
("[RFC][BPF] Implement getUserCost() for BPFTargetTransformInfo").

Use case 1: bpf map value or some other data with a range.

data = bpf_map_lookup_elem(&map, &key);
if (!data) return 0;
payload = data->payload;
len = bpf_probe_read_kernel_str(payload, 16, &task->comm);
if (len <= 16) 
  payload += len;
...

The compiler may generate code like:

data = bpf_map_lookup_elem(&map, &key);
if (!data) return 0;
payload = data->payload;
len = bpf_probe_read_kernel_str(payload, 16, &task->comm);
new_payload = payload + len;
if (len > 16) 
  new_payload = payload
...

The "payload + len" may cause kernel verifier failure as
the "len" can be anything at this moment.

Use case 2: CO-RE relocatons

field_exist = ... 
if (field_exist) {
  offset = non-memory-access-builtin-expr1;
} else {
  offset = non-memory-access-builtin-expr2;
}   
use "offset" to read kernel memory

The compiler may generate code like:

field_exist = ... 
offset = non-memory-access-builtin-expr1;
if (!field_exist)
  offset = non-memory-access-builtin-expr2;
use "offset" to read kernel memory

This may cause failures since if field_exist is false and
libbpf is not able to perform relation
for "offset = non-memory-access-builtin-expr1".
The instruction itself will be rewritten as
an illegal instruction and this will cause
program load failures.

To address the above issues, people use

. inline assembly
. artificial complex control flow

to prevent the above optimizations.

Another BPF patch will have target specific
implementation of TTI.getUserCost() to control
the cost of code motion across control flows.

This patch mostly focused on SimplifyCFG commandline
option SpeculateOneExpensiveInst, which has default
true. We could like to disable it if a particular
BPF backend attribute is set. This patch implemented
a mechanism for backend can disallow SpeculateOneExpensiveInst.
Specifically, BPF target will disallow SpeculateOneExpensiveInst
if BPF attribute "adjustopt" is set.

Diff Detail

Event Timeline

yonghong-song created this revision.Jun 15 2020, 11:20 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 15 2020, 11:20 AM

more detailed implementation in BPF backend getUserCost() implementation to fix a few kernel bpf selftests issues.

yonghong-song retitled this revision from [RFC BPF] Prevent Speculative Code Motion to [RFC][SimplifyCFG] Allow target to control SpeculateOneExpensiveInst.
yonghong-song edited the summary of this revision. (Show Details)

separate BPF changes to another patch (https://reviews.llvm.org/D82112), so this patch can focus on solely the core change.

shawnl resigned from this revision.Jul 8 2020, 8:17 AM
yonghong-song abandoned this revision.Sep 9 2020, 3:34 PM

Abandon this one. The current approach is to introduce some kind of user barriers before instcombine to prevent such optimization in IR level.