Skip to content

Commit e7664e0

Browse files
committed
offload wrapper generation
1 parent 2e53675 commit e7664e0

File tree

6 files changed

+162
-3
lines changed

6 files changed

+162
-3
lines changed

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{iter, ptr};
44

55
pub(crate) mod autodiff;
66
pub(crate) mod gpu_offload;
7+
pub(crate) mod gpu_wrapper;
78

89
use libc::{c_char, c_uint, size_t};
910
use rustc_abi as abi;

compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::llvm::{self, Linkage, Type, Value};
1212
use crate::{LlvmCodegenBackend, SimpleCx, attributes};
1313

1414
pub(crate) fn handle_gpu_code<'ll>(
15-
_cgcx: &CodegenContext<LlvmCodegenBackend>,
15+
cgcx: &CodegenContext<LlvmCodegenBackend>,
1616
cx: &'ll SimpleCx<'_>,
1717
) {
1818
// The offload memory transfer type for each kernel
@@ -26,8 +26,8 @@ pub(crate) fn handle_gpu_code<'ll>(
2626
kernels.push(kernel);
2727
}
2828
}
29-
3029
gen_call_handling(&cx, &kernels, &o_types);
30+
crate::builder::gpu_wrapper::gen_image_wrapper_module(&cgcx);
3131
}
3232

3333
// What is our @1 here? A magic global, used in our data_{begin/update/end}_mapper:
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use std::ffi::CString;
2+
3+
use llvm::Linkage::*;
4+
use rustc_abi::Align;
5+
use rustc_codegen_ssa::back::write::CodegenContext;
6+
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
7+
8+
use crate::builder::gpu_offload::*;
9+
use crate::llvm::{self, Visibility};
10+
use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx};
11+
12+
pub(crate) fn create_struct_ty<'ll>(
13+
cx: &'ll SimpleCx<'_>,
14+
name: &str,
15+
tys: &[&'ll llvm::Type],
16+
) -> &'ll llvm::Type {
17+
let entry_struct_name = CString::new(name).unwrap();
18+
unsafe {
19+
let entry_struct = llvm::LLVMStructCreateNamed(cx.llcx, entry_struct_name.as_ptr());
20+
llvm::LLVMStructSetBody(entry_struct, tys.as_ptr(), tys.len() as u32, 0);
21+
entry_struct
22+
}
23+
}
24+
25+
// We don't copy types from other functions because we generate a new module and context.
26+
// Bringing in types from other contexts would likely cause issues.
27+
pub(crate) fn gen_image_wrapper_module(cgcx: &CodegenContext<LlvmCodegenBackend>) {
28+
let dl_cstr = CString::new("e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9").unwrap();
29+
let target_cstr = CString::new("amdgcn-amd-amdhsa").unwrap();
30+
let name = "offload.wrapper.module";
31+
let m: crate::ModuleLlvm =
32+
ModuleLlvm::new_simple(name, dl_cstr.into_raw(), target_cstr.into_raw(), &cgcx).unwrap();
33+
let cx = SimpleCx::new(m.llmod(), m.llcx, cgcx.pointer_size);
34+
let tptr = cx.type_ptr();
35+
let ti64 = cx.type_i64();
36+
let ti32 = cx.type_i32();
37+
let ti16 = cx.type_i16();
38+
39+
let entry_fields = [ti64, ti16, ti16, ti32, tptr, tptr, ti64, ti64, tptr];
40+
create_struct_ty(&cx, "__tgt_offload_entry", &entry_fields);
41+
create_struct_ty(&cx, "__tgt_device_image", &[tptr, tptr, tptr, tptr]);
42+
create_struct_ty(&cx, "__tgt_bin_desc", &[ti32, tptr, tptr, tptr]);
43+
44+
let offload_entry_ty = add_tgt_offload_entry(&cx);
45+
let offload_entry_arr = cx.type_array(offload_entry_ty, 0);
46+
47+
let c_name = CString::new("__start_omp_offloading_entries").unwrap();
48+
let llglobal = llvm::add_global(cx.llmod, offload_entry_arr, &c_name);
49+
llvm::set_global_constant(llglobal, true);
50+
llvm::set_linkage(llglobal, ExternalLinkage);
51+
llvm::set_visibility(llglobal, Visibility::Hidden);
52+
let c_name = CString::new("__stop_omp_offloading_entries").unwrap();
53+
let llglobal = llvm::add_global(cx.llmod, offload_entry_arr, &c_name);
54+
llvm::set_global_constant(llglobal, true);
55+
llvm::set_linkage(llglobal, ExternalLinkage);
56+
llvm::set_visibility(llglobal, Visibility::Hidden);
57+
58+
let c_name = CString::new("__dummy.omp_offloading_entries").unwrap();
59+
let llglobal = llvm::add_global(cx.llmod, offload_entry_arr, &c_name);
60+
llvm::set_global_constant(llglobal, true);
61+
llvm::set_linkage(llglobal, InternalLinkage);
62+
let c_section_name = CString::new("omp_offloading_entries").unwrap();
63+
llvm::set_section(llglobal, &c_section_name);
64+
let zeroinit = cx.const_null(offload_entry_arr);
65+
llvm::set_initializer(llglobal, zeroinit);
66+
67+
CString::new("llvm.compiler.used").unwrap();
68+
let arr_val = cx.const_array(tptr, &[llglobal]);
69+
let c_section_name = CString::new("llvm.metadata").unwrap();
70+
let llglobal = add_global(&cx, "llvm.compiler.used", arr_val, AppendingLinkage);
71+
llvm::set_section(llglobal, &c_section_name);
72+
llvm::set_global_constant(llglobal, false);
73+
74+
//@llvm.compiler.used = appending global [1 x ptr] [ptr @__dummy.omp_offloading_entries], section "llvm.metadata"
75+
76+
let mapper_fn_ty = cx.type_func(&[tptr], cx.type_void());
77+
crate::declare::declare_simple_fn(
78+
&cx,
79+
&"__tgt_unregister_lib",
80+
llvm::CallConv::CCallConv,
81+
llvm::UnnamedAddr::No,
82+
llvm::Visibility::Default,
83+
mapper_fn_ty,
84+
);
85+
crate::declare::declare_simple_fn(
86+
&cx,
87+
&"__tgt_register_lib",
88+
llvm::CallConv::CCallConv,
89+
llvm::UnnamedAddr::No,
90+
llvm::Visibility::Default,
91+
mapper_fn_ty,
92+
);
93+
crate::declare::declare_simple_fn(
94+
&cx,
95+
&"atexit",
96+
llvm::CallConv::CCallConv,
97+
llvm::UnnamedAddr::No,
98+
llvm::Visibility::Default,
99+
cx.type_func(&[tptr], ti32),
100+
);
101+
102+
let unknown_txt = "11111111111111";
103+
let c_entry_name = CString::new(unknown_txt).unwrap();
104+
let c_val = c_entry_name.as_bytes_with_nul();
105+
let initializer = crate::common::bytes_in_context(cx.llcx, c_val);
106+
let llglobal =
107+
add_unnamed_global(&cx, &".omp_offloading.device_image", initializer, InternalLinkage);
108+
let c_section_name = CString::new(".llvm.offloading").unwrap();
109+
llvm::set_section(llglobal, &c_section_name);
110+
llvm::set_alignment(llglobal, Align::EIGHT);
111+
112+
unsafe {
113+
llvm::LLVMPrintModuleToFile(
114+
cx.llmod,
115+
CString::new("rustmagic.openmp.image.wrapper.ll").unwrap().as_ptr(),
116+
std::ptr::null_mut(),
117+
);
118+
}
119+
}

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,23 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
159159
}
160160
}
161161

162+
// FIXME(offload): This method is not relying on a tcx. We might still want to try to share some of
163+
// the logic with create_module, e.g. the target_data_layout handling.
164+
pub(crate) unsafe fn create_simple_module<'ll>(
165+
llcx: &'ll llvm::Context,
166+
target_data_layout: *const i8,
167+
target_triple: *const i8,
168+
mod_name: &str,
169+
) -> &'ll llvm::Module {
170+
let mod_name = SmallCStr::new(mod_name);
171+
let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };
172+
unsafe {
173+
llvm::LLVMSetDataLayout(llmod, target_data_layout);
174+
llvm::LLVMSetTarget(llmod, target_triple);
175+
}
176+
llmod
177+
}
178+
162179
pub(crate) unsafe fn create_module<'ll>(
163180
tcx: TyCtxt<'_>,
164181
llcx: &'ll llvm::Context,

compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,21 @@ unsafe impl Send for ModuleLlvm {}
388388
unsafe impl Sync for ModuleLlvm {}
389389

390390
impl ModuleLlvm {
391+
fn new_simple(
392+
name: &str,
393+
dl_cstr: *const i8,
394+
target_cstr: *const i8,
395+
cgcx: &CodegenContext<LlvmCodegenBackend>,
396+
) -> Result<Self, FatalError> {
397+
unsafe {
398+
let llcx = llvm::LLVMRustContextCreate(false);
399+
let llmod_raw = context::create_simple_module(llcx, dl_cstr, target_cstr, name);
400+
let dcx = cgcx.create_dcx();
401+
let tm = ModuleLlvm::tm_from_cgcx(cgcx, name, dcx.handle())?;
402+
Ok(ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) })
403+
}
404+
}
405+
391406
fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
392407
unsafe {
393408
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,16 +1005,23 @@ unsafe extern "C" {
10051005
) -> MetadataKindId;
10061006

10071007
// Create modules.
1008+
pub(crate) fn LLVMCloneModule(M: &Module) -> &Module;
10081009
pub(crate) fn LLVMModuleCreateWithNameInContext(
10091010
ModuleID: *const c_char,
10101011
C: &Context,
10111012
) -> &Module;
1012-
pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module;
1013+
pub(crate) fn LLVMPrintModuleToFile(
1014+
M: &Module,
1015+
Name: *const c_char,
1016+
Error_message: *mut c_char,
1017+
);
10131018

10141019
/// Data layout. See Module::getDataLayout.
10151020
pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char;
10161021
pub(crate) fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
10171022

1023+
pub(crate) fn LLVMSetTarget(M: &Module, Name: *const c_char);
1024+
10181025
/// Append inline assembly to a module. See `Module::appendModuleInlineAsm`.
10191026
pub(crate) fn LLVMAppendModuleInlineAsm(
10201027
M: &Module,

0 commit comments

Comments
 (0)