Yep. Actually we have a C helper per instruction and generate IR blocks full of CALLs to such helpers. Then the inliner and other optimizations take care of doing their work.
Anyway, if you never used LLVM, be ready to spend some time getting familiar with its IR and its C++ magic (though as a user I never had too much trouble... and I'm not a C++ guy). The documentation is also not very helpful, but the examples are good enough to get you started. The ORCv1 vs ORCv2 thing is kind of confusing sometimes.
IR = Intermediate Representation, named as such because whereas machine code is extremely carefully designed holistically with the hardware it executes on, an intermediate representation can much less "efficient" in the name of maintaining invariants to ease analysis throughout it's use in the compiler.
Anyway, if you never used LLVM, be ready to spend some time getting familiar with its IR and its C++ magic (though as a user I never had too much trouble... and I'm not a C++ guy). The documentation is also not very helpful, but the examples are good enough to get you started. The ORCv1 vs ORCv2 thing is kind of confusing sometimes.