1515)
1616from .debuginfo import DW_LANG_C11 , DwarfBehaviorEnum , DebugInfoGenerator
1717import os
18+ import shutil
1819import subprocess
1920import inspect
2021from pathlib import Path
@@ -175,8 +176,66 @@ def compile_to_ir(filename: str, output: str, loglevel=logging.INFO):
175176 return output , structs_sym_tab , maps_sym_tab
176177
177178
179+ MIN_OPT_VERSION = 15
180+ _OPT_VERSIONED_RE = re .compile (r"opt-(\d+)" )
181+
182+
183+ def _find_opt ():
184+ """Locate an LLVM opt binary.
185+
186+ Prefers a plain ``opt`` on PATH. Otherwise falls back to the newest
187+ versioned ``opt-N`` (N >= MIN_OPT_VERSION) that distros such as
188+ Debian/Ubuntu install, e.g. ``opt-18``. Returns None if none is found.
189+ """
190+ opt = shutil .which ("opt" )
191+ if opt :
192+ return opt
193+
194+ best_version , best_path = - 1 , None
195+ for directory in os .environ .get ("PATH" , "" ).split (os .pathsep ):
196+ try :
197+ entries = os .listdir (directory or "." )
198+ except OSError :
199+ continue
200+ for entry in entries :
201+ match = _OPT_VERSIONED_RE .fullmatch (entry )
202+ if not match :
203+ continue
204+ version = int (match .group (1 ))
205+ if version < MIN_OPT_VERSION or version <= best_version :
206+ continue
207+ path = shutil .which (entry , path = directory or "." )
208+ if path :
209+ best_version , best_path = version , path
210+ return best_path
211+
212+
213+ def _run_opt (ll_file ):
214+ """Run the O2 pipeline over the IR and return it as bitcode, or None if
215+ no opt binary is available."""
216+
217+ opt = _find_opt ()
218+ if opt is None :
219+ logger .warning (
220+ f"No LLVM 'opt' (or 'opt-N', N >= { MIN_OPT_VERSION } ) found on PATH; "
221+ "skipping IR optimization."
222+ )
223+ return None
224+
225+ logger .info (f"Optimizing IR with { opt } -O2: { ll_file } " )
226+ result = subprocess .run (
227+ [opt , "-O2" , str (ll_file ), "-o" , "-" ],
228+ check = True ,
229+ capture_output = True ,
230+ )
231+ return result .stdout
232+
233+
178234def _run_llc (ll_file , obj_file ):
179- """Compile LLVM IR to BPF object file using llc."""
235+ """Optimize LLVM IR with opt (when available) and compile it to a BPF
236+ object file using llc."""
237+
238+ bitcode = _run_opt (ll_file )
180239
181240 logger .info (f"Compiling IR to object: { ll_file } -> { obj_file } " )
182241 result = subprocess .run (
@@ -185,20 +244,20 @@ def _run_llc(ll_file, obj_file):
185244 "-march=bpf" ,
186245 "-filetype=obj" ,
187246 "-O2" ,
188- str (ll_file ),
247+ "-" if bitcode is not None else str (ll_file ),
189248 "-o" ,
190249 str (obj_file ),
191250 ],
251+ input = bitcode ,
192252 check = True ,
193253 capture_output = True ,
194- text = True ,
195254 )
196255
197256 if result .returncode == 0 :
198257 logger .info (f"Object file written to { obj_file } " )
199258 return True
200259 else :
201- logger .error (f"llc compilation failed: { result .stderr } " )
260+ logger .error (f"llc compilation failed: { result .stderr . decode () } " )
202261 return False
203262
204263
0 commit comments