@@ -39,7 +39,7 @@ const bpffunction_cache = Dict{UInt,Any}()
3939
4040# actual compilation
4141function bpffunction_compile (source:: FunctionSpec ; format= :obj , license= " " ,
42- prog_section= " prog" , btf= true , kwargs... )
42+ prog_section= " prog" , btf= false , kwargs... )
4343 # compile to BPF
4444 target = BPFCompilerTarget (; license, prog_section)
4545 params = BPFCompilerParams ()
@@ -49,3 +49,96 @@ function bpffunction_compile(source::FunctionSpec; format=:obj, license="",
4949 return collect (codeunits (args[1 ]))
5050end
5151bpffunction_link (@nospecialize (source:: FunctionSpec ), exe; kwargs... ) = exe
52+
53+ function GPUCompiler. finish_module! (job:: BPFCompilerJob , mod:: LLVM.Module )
54+ #= TODO : Fix upstream and re-enable if needed
55+ invoke(GPUCompiler.finish_module!,
56+ Tuple{CompilerJob{BPFCompilerTarget}, LLVM.Module},
57+ job, mod)
58+ =#
59+
60+ for func in LLVM. functions (mod)
61+ if LLVM. name (func) == " gpu_signal_exception"
62+ throw (GPUCompiler. KernelError (job, " eBPF does not support exceptions" ))
63+ end
64+ # Set entry section for loaders like libbpf
65+ LLVM. section! (func, job. target. prog_section)
66+ end
67+
68+ # Set license
69+ license = job. target. license
70+ if license != " "
71+ ctx = LLVM. context (mod)
72+ i8 = LLVM. Int8Type (ctx)
73+ glob = GlobalVariable (mod, LLVM. ArrayType (i8, length (license)+ 1 ), " _license" )
74+ linkage! (glob, LLVM. API. LLVMExternalLinkage)
75+ constant! (glob, true )
76+ section! (glob, " license" )
77+ str = ConstantArray (Vector {UInt8} (license* ' \0 ' ), ctx)
78+ @assert context (glob) == context (str) == ctx
79+ initializer! (glob, str)
80+ end
81+
82+ # Set all map definitions as external linkage
83+ for gv in filter (x-> (section (x)== " maps" )|| (section (x)== " .maps" ), collect (LLVM. globals (mod)))
84+ linkage! (gv, LLVM. API. LLVMExternalLinkage)
85+ end
86+
87+ ModulePassManager () do pm
88+ if Base. JLOptions (). debug_level > 1
89+ # Validate contexts, for my sanity
90+ add! (pm, ModulePass (" BPFValidateContexts" , validate_contexts!))
91+ end
92+ # Promote `@malloc` intrinsics
93+ add! (pm, FunctionPass (" BPFHeapToStack" , heap_to_stack!))
94+ run! (pm, mod)
95+ end
96+ end
97+
98+ " Validates LLVM contexts of all the things."
99+ function validate_contexts! (mod:: LLVM.Module )
100+ ctx = LLVM. context (mod)
101+ for fn in LLVM. functions (mod)
102+ @assert context (fn) == ctx " Failed validation: $fn "
103+ for bb in LLVM. blocks (fn)
104+ for insn in LLVM. instructions (bb)
105+ @assert context (insn) == ctx " Failed validation: $insn "
106+ for op in LLVM. operands (insn)
107+ @assert context (op) == ctx " Failed validation: $op "
108+ end
109+ end
110+ end
111+ end
112+ for gv in LLVM. globals (mod)
113+ @assert context (gv) == ctx " Failed validation: $gv "
114+ end
115+ false
116+ end
117+
118+ " Promotes `@malloc` intrinsics to allocas."
119+ function heap_to_stack! (fn:: LLVM.Function )
120+ changed = false
121+ ctx = LLVM. context (fn)
122+ for bb in LLVM. blocks (fn)
123+ for insn in LLVM. instructions (bb)
124+ if insn isa LLVM. CallInst && LLVM. name (LLVM. called_value (insn)) == " malloc"
125+ sz = convert (Int64, LLVM. operands (insn)[1 ])
126+ T_i8 = LLVM. Int8Type (ctx)
127+ T_pi8 = LLVM. PointerType (T_i8)
128+ T_buf = LLVM. ArrayType (T_i8, sz)
129+ Builder (ctx) do builder
130+ # Place alloca at beginning of entry
131+ position! (builder, first (LLVM. instructions (first (LLVM. blocks (fn)))))
132+ buf = alloca! (builder, T_buf)
133+ # Replace malloc with bitcast'd alloca
134+ position! (builder, insn)
135+ new_insn = bitcast! (builder, buf, T_pi8)
136+ replace_uses! (insn, new_insn)
137+ unsafe_delete! (LLVM. parent (insn), insn)
138+ end
139+ changed = true
140+ end
141+ end
142+ end
143+ changed
144+ end
0 commit comments