Repository navigation
Commit 40aad02
authored
loops (#106)
* Core: Lower annotated assignment (x: c_int32 = 0)
The annotation types the slot, so `x: c_int32 = 0` is an i32 where the
literal alone would give an i64; the store goes through the same
handle_variable_assignment plain assignment uses. A bare `x: T` makes the
slot and binds nothing.
The already-bound and global-shadowing bookkeeping that Assign allocation did
inline moves into _bind_name, which both statements now call.
* Tests: Annotated assignment passes now
* Core: Lower if-branches in the function's return type
handle_if processed its branches without passing ret_type down, so a
return inside an if fell back to process_stmt's i64 default: a -> c_int32
function got `ret i64 7`, which llc rejects. The branches now go through
process_block, which threads ret_type and stops at a statement that ends
the block instead of emitting after its terminator.
* Core: Lower for-over-range and while loops, with break and continue
`for i in range(...)` steps a hidden induction counter, allocated in the
entry block next to the loop variable, and copies it into the variable each
iteration, so rebinding the variable in the body leaves the trip count alone
as in Python (and the loop stays visibly bounded for the verifier). The
counter is 64-bit, signed unless the bounds make C's arithmetic unsigned.
Bounds are evaluated once, before the loop; the step must be a nonzero
integer literal, because its sign picks the loop test.
`while` re-evaluates its test at the top of each iteration. `break` and
`continue` branch through a loop-target stack on the compilation context;
outside a loop they are a SyntaxError, as in Python. A loop's else-branch
runs on normal exit only. Anything but range() as the iterable is rejected
with NotImplementedError.
The allocation pass now descends into loop bodies and counts helper temps in
loop headers. Checked against clang -O2 on tests/c-form/loops.bpf.c: the
constant-bound cases fold to the same ret, and a helper-bounded loop gets the
same rotated loop.
* Tests: Loops pass now, plus the cases the lowering promises
- passing_tests/loops/: the seven range/while/break/continue/nested tests
move over from failing_tests/, joined by rebinding the loop variable, a
negative step, loop else-branches, and a helper-bounded loop over a
@bpfglobal that survives -O2 as a real loop for the verifier.
- failing_tests/loops/: break outside a loop, and a non-literal range step.
- for_map_items stays xfail: map iteration needs its own design.
- c-form/loops.bpf.c: the clang reference the lowering was checked against.
* Tests: Indent the loop C reference with spaces
The remove-tabs pre-commit hook rejects tab indentation outside docs/ and
Makefiles, which failed the Format job.
* Core: Fix loop edge cases the lowering got wrong
- `pass` is accepted as a statement, the natural body of a loop run for its
side effects.
- Falling off the end of a function returns 0 in the function's own return
type. After `while True` that block is unreachable, but a c_int32 function
still emitted `ret i64 0`, which llc rejected.
- A range() step other than 1 could wrap the counter past INT64_MAX or
UINT64_MAX back inside the range and loop forever. The step block now ends
the loop when the distance left to stop, exact as an unsigned number, is
no longer than the step. That is a normal exit, so the else-branch runs.
Steps of 1 cannot overshoot and keep the plain loop, so the helper-bounded
loop the verifier walks is unchanged.
- A step of 2**64 or more no longer truncates to 0: it is a compile error,
since it does not fit the counter. Steps from 2**63 up are emitted by
their bits.
- The counter's signedness folds each bound into a signed 64-bit type rather
than joining the bounds alone, so only a c_uint64 bound makes it unsigned:
range(-1, n) over a c_uint32 n runs 4 times, as in C with an __s64 counter.
* Tests: Run loop programs on the host, plus adversarial loop cases
Levels 1 and 2 only prove a loop compiles; one can still run the wrong
number of times, or forever. test_loops_run.py JIT-compiles each
helper-free passing_tests/loops case on the host (framework/host_jit.py,
in a subprocess with a timeout) and checks its return value against what
CPython returns for the same body.
- passing_tests/loops/: pass bodies, `while True` exited by a return in a
c_int32 function, step overflow past INT64_MAX, INT64_MIN and UINT64_MAX,
a c_uint32 stop with a negative start, and loop variables that must stay
one local (a nested same-name loop, a read after the loop).
- failing_tests/loops/range_step_too_wide.py: a 2**64 step is a compile error.
- reuse_loop_var_signedness.py is xfail in test_loops_run.py: every local
gets one slot typed by its first binding, so a second loop's `i` inherits
the first loop's unsigned type. `x = n_u64; x = -3` does the same, so the
fix is general, not loop-specific.1 parent 4662fe6 commit 40aad02
30 files changed
Lines changed: 1090 additions & 89 deletions
File tree
- pythonbpf
- functions
- tests
- c-form
- failing_tests/loops
- framework
- passing_tests
- assign
- loops
- return
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
53 | 62 | | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | 63 | | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
| 64 | + | |
| 65 | + | |
69 | 66 | | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
95 | 73 | | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
103 | 278 | | |
104 | 279 | | |
105 | 280 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
85 | 89 | | |
86 | 90 | | |
87 | 91 | | |
88 | 92 | | |
| 93 | + | |
0 commit comments