Take a list of bitcode module bytes and their names and codegen it into ptx bytes. The final PTX *should* be utf8, but just to be on the safe side it returns a vector of bytes. Note that this will implicitly try to find libdevice and add it, so don't do that step before this. It will fatal error if it cannot find it.
(
opts: &[NvvmOption],
sess: &Session,
modules: Vec<Vec<u8>>,
llcx: &Context,
)
| 50 | /// Note that this will implicitly try to find libdevice and add it, so don't do that |
| 51 | /// step before this. It will fatal error if it cannot find it. |
| 52 | pub fn codegen_bitcode_modules( |
| 53 | opts: &[NvvmOption], |
| 54 | sess: &Session, |
| 55 | modules: Vec<Vec<u8>>, |
| 56 | llcx: &Context, |
| 57 | ) -> Result<Vec<u8>, CodegenErr> { |
| 58 | debug!("Codegenning bitcode to PTX"); |
| 59 | |
| 60 | // make sure the nvvm version is high enough so users don't get confusing compilation errors. |
| 61 | let (major, minor) = nvvm::ir_version(); |
| 62 | |
| 63 | if minor < 6 || major < 1 { |
| 64 | sess.fatal("rustc_codegen_nvvm requires at least libnvvm 1.6 (CUDA 11.2)"); |
| 65 | } |
| 66 | |
| 67 | // first, create the nvvm program we will add modules to. |
| 68 | let prog = NvvmProgram::new()?; |
| 69 | |
| 70 | let module = merge_llvm_modules(modules, llcx); |
| 71 | unsafe { |
| 72 | internalize_pass(module, llcx); |
| 73 | dce_pass(module); |
| 74 | |
| 75 | if sess.opts.debuginfo != DebugInfo::None { |
| 76 | cleanup_dicompileunit(module); |
| 77 | } |
| 78 | |
| 79 | let (dbg_major, dbg_minor) = nvvm::dbg_version(); |
| 80 | |
| 81 | // needed for debug info or else nvvm complains about ir version mismatch for some |
| 82 | // reason. It works if you don't use debug info though... |
| 83 | let ty_i32 = LLVMInt32TypeInContext(llcx); |
| 84 | let major = LLVMConstInt(ty_i32, major as u64, False); |
| 85 | let minor = LLVMConstInt(ty_i32, minor as u64, False); |
| 86 | let dbg_major = LLVMConstInt(ty_i32, dbg_major as u64, False); |
| 87 | let dbg_minor = LLVMConstInt(ty_i32, dbg_minor as u64, False); |
| 88 | let vals = vec![major, minor, dbg_major, dbg_minor]; |
| 89 | let node = LLVMMDNodeInContext(llcx, vals.as_ptr(), vals.len() as u32); |
| 90 | |
| 91 | LLVMAddNamedMetadataOperand(module, "nvvmir.version\0".as_ptr().cast(), node); |
| 92 | } |
| 93 | let buf = ThinBuffer::new(module); |
| 94 | |
| 95 | prog.add_module(buf.data(), "merged".to_string())?; |
| 96 | |
| 97 | let libdevice = if let Some(bc) = find_libdevice() { |
| 98 | bc |
| 99 | } else { |
| 100 | // i would put a more helpful error here, but to actually use the codegen |
| 101 | // it needs to find libnvvm before this, and libdevice is in the nvvm directory |
| 102 | // so if it can find libnvvm there is almost no way it can't find libdevice. |
| 103 | sess.fatal("Could not find the libdevice library (libdevice.10.bc) in the CUDA directory") |
| 104 | }; |
| 105 | |
| 106 | prog.add_lazy_module(&libdevice, "libdevice".to_string())?; |
| 107 | prog.add_lazy_module(LIBINTRINSICS, "libintrinsics".to_string())?; |
| 108 | |
| 109 | // for now, while the codegen is young, we always run verification on the program. |
no test coverage detected