Make CodegenCx and Builder generic

Co-authored-by: Oli Scherer <github35764891676564198441@oli-obk.de>
This commit is contained in:
Manuel Drehwald 2025-01-24 16:05:26 -05:00
parent a48e7b0057
commit 386c233858
10 changed files with 239 additions and 56 deletions

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::borrow::{Borrow, Cow};
use std::ops::Deref;
use std::{iter, ptr};
@ -31,20 +31,22 @@ use tracing::{debug, instrument};
use crate::abi::FnAbiLlvmExt;
use crate::attributes;
use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, SimpleCx};
use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True};
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
// All Builders must have an llfn associated with them
#[must_use]
pub(crate) struct Builder<'a, 'll, 'tcx> {
pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> {
pub llbuilder: &'ll mut llvm::Builder<'ll>,
pub cx: &'a CodegenCx<'ll, 'tcx>,
pub cx: &'a CX,
}
impl Drop for Builder<'_, '_, '_> {
pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>;
pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>;
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
@ -52,6 +54,112 @@ impl Drop for Builder<'_, '_, '_> {
}
}
impl<'a, 'll> SBuilder<'a, 'll> {
fn call(
&mut self,
llty: &'ll Type,
llfn: &'ll Value,
args: &[&'ll Value],
funclet: Option<&Funclet<'ll>>,
) -> &'ll Value {
debug!("call {:?} with args ({:?})", llfn, args);
let args = self.check_call("call", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
let call = unsafe {
llvm::LLVMBuildCallWithOperandBundles(
self.llbuilder,
llty,
llfn,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
bundles.as_ptr(),
bundles.len() as c_uint,
c"".as_ptr(),
)
};
call
}
fn with_scx(scx: &'a SimpleCx<'ll>) -> Self {
// Create a fresh builder from the simple context.
let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) };
SBuilder { llbuilder, cx: scx }
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
}
fn ret_void(&mut self) {
unsafe {
llvm::LLVMBuildRetVoid(self.llbuilder);
}
}
fn ret(&mut self, v: &'ll Value) {
unsafe {
llvm::LLVMBuildRet(self.llbuilder, v);
}
}
}
impl<'a, 'll> SBuilder<'a, 'll> {
fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> {
let bx = SBuilder::with_scx(cx);
unsafe {
llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
}
bx
}
fn check_call<'b>(
&mut self,
typ: &str,
fn_ty: &'ll Type,
llfn: &'ll Value,
args: &'b [&'ll Value],
) -> Cow<'b, [&'ll Value]> {
assert!(
self.cx.type_kind(fn_ty) == TypeKind::Function,
"builder::{typ} not passed a function, but {fn_ty:?}"
);
let param_tys = self.cx.func_params_types(fn_ty);
let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
.all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
if all_args_match {
return Cow::Borrowed(args);
}
let casted_args: Vec<_> = iter::zip(param_tys, args)
.enumerate()
.map(|(i, (expected_ty, &actual_val))| {
let actual_ty = self.cx.val_ty(actual_val);
if expected_ty != actual_ty {
debug!(
"type mismatch in function call of {:?}. \
Expected {:?} for param {}, got {:?}; injecting bitcast",
llfn, expected_ty, i, actual_ty
);
self.bitcast(actual_val, expected_ty)
} else {
actual_val
}
})
.collect();
Cow::Owned(casted_args)
}
}
/// Empty string, to be used where LLVM expects an instruction name, indicating
/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
@ -1222,6 +1330,14 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> {
let bx = Builder::with_cx(cx);
unsafe {
llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
}
bx
}
fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
// Create a fresh builder from the crate context.
let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) };
@ -1231,13 +1347,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
pub(crate) fn llfn(&self) -> &'ll Value {
unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) }
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
fn position_at_start(&mut self, llbb: &'ll BasicBlock) {
unsafe {
llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
}
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn align_metadata(&mut self, load: &'ll Value, align: Align) {
unsafe {
let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
@ -1259,7 +1378,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
self.set_metadata(inst, llvm::MD_unpredictable, md);
}
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
}
@ -1360,7 +1480,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
ret.expect("LLVM does not have support for catchret")
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn check_call<'b>(
&mut self,
typ: &str,
@ -1401,11 +1523,13 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
Cow::Owned(casted_args)
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
let (ty, f) = self.cx.get_intrinsic(intrinsic);
self.call(ty, None, None, f, args, None, None)
@ -1423,7 +1547,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn phi(
&mut self,
ty: &'ll Type,
@ -1443,7 +1568,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
}
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
let src_ty = self.cx.val_ty(val);
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {

View file

@ -3,20 +3,19 @@ use std::ptr;
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::back::write::ModuleConfig;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
use rustc_errors::FatalError;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::Lto;
use tracing::{debug, trace};
use crate::back::write::{llvm_err, llvm_optimize};
use crate::builder::Builder;
use crate::declare::declare_raw_fn;
use crate::builder::SBuilder;
use crate::context::SimpleCx;
use crate::declare::declare_simple_fn;
use crate::errors::LlvmError;
use crate::llvm::AttributePlace::Function;
use crate::llvm::{Metadata, True};
use crate::value::Value;
use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, context, llvm};
use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, llvm};
fn get_params(fnc: &Value) -> Vec<&Value> {
unsafe {
@ -38,8 +37,8 @@ fn get_params(fnc: &Value) -> Vec<&Value> {
/// [^1]: <https://enzyme.mit.edu/getting_started/CallingConvention/>
// FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to
// cover some assumptions of enzyme/autodiff, which could lead to UB otherwise.
fn generate_enzyme_call<'ll, 'tcx>(
cx: &context::CodegenCx<'ll, 'tcx>,
fn generate_enzyme_call<'ll>(
cx: &SimpleCx<'ll>,
fn_to_diff: &'ll Value,
outer_fn: &'ll Value,
attrs: AutoDiffAttrs,
@ -112,7 +111,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
//FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and
// think a bit more about what should go here.
let cc = llvm::LLVMGetFunctionCallConv(outer_fn);
let ad_fn = declare_raw_fn(
let ad_fn = declare_simple_fn(
cx,
&ad_name,
llvm::CallConv::try_from(cc).expect("invalid callconv"),
@ -132,7 +131,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
llvm::LLVMRustEraseInstFromParent(br);
let last_inst = llvm::LLVMRustGetLastInstruction(entry).unwrap();
let mut builder = Builder::build(cx, entry);
let mut builder = SBuilder::build(cx, entry);
let num_args = llvm::LLVMCountParams(&fn_to_diff);
let mut args = Vec::with_capacity(num_args as usize + 1);
@ -236,7 +235,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
}
}
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
let call = builder.call(enzyme_ty, ad_fn, &args, None);
// This part is a bit iffy. LLVM requires that a call to an inlineable function has some
// metadata attachted to it, but we just created this code oota. Given that the
@ -274,10 +273,9 @@ fn generate_enzyme_call<'ll, 'tcx>(
}
}
pub(crate) fn differentiate<'ll, 'tcx>(
pub(crate) fn differentiate<'ll>(
module: &'ll ModuleCodegen<ModuleLlvm>,
cgcx: &CodegenContext<LlvmCodegenBackend>,
tcx: TyCtxt<'tcx>,
diff_items: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
@ -286,8 +284,7 @@ pub(crate) fn differentiate<'ll, 'tcx>(
}
let diag_handler = cgcx.create_dcx();
let (_, cgus) = tcx.collect_and_partition_mono_items(());
let cx = context::CodegenCx::new(tcx, &cgus.first().unwrap(), &module.module_llvm);
let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx };
// Before dumping the module, we want all the TypeTrees to become part of the module.
for item in diff_items.iter() {

View file

@ -1,11 +1,13 @@
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::ffi::{CStr, c_char, c_uint};
use std::ops::Deref;
use std::str;
use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
use rustc_codegen_ssa::back::versioned_llvm_target;
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
@ -30,23 +32,46 @@ use smallvec::SmallVec;
use crate::back::write::to_llvm_code_model;
use crate::callee::get_fn;
use crate::common::AsCCharPtr;
use crate::common::{self, AsCCharPtr};
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
use crate::llvm::{Metadata, MetadataType};
use crate::type_::Type;
use crate::value::Value;
use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
/// `TyCtxt` (and related cache datastructures) can't be move between threads.
/// However, there are various cx related functions which we want to be available to the builder and
/// other compiler pieces. Here we define a small subset which has enough information and can be
/// moved around more freely.
pub(crate) struct SimpleCx<'ll> {
pub llmod: &'ll llvm::Module,
pub llcx: &'ll llvm::Context,
}
impl<'ll> Borrow<SimpleCx<'ll>> for CodegenCx<'ll, '_> {
fn borrow(&self) -> &SimpleCx<'ll> {
&self.scx
}
}
impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
type Target = SimpleCx<'ll>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.scx
}
}
/// There is one `CodegenCx` per codegen unit. Each one has its own LLVM
/// `llvm::Context` so that several codegen units may be processed in parallel.
/// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
pub(crate) struct CodegenCx<'ll, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub scx: SimpleCx<'ll>,
pub use_dll_storage_attrs: bool,
pub tls_model: llvm::ThreadLocalMode,
pub llmod: &'ll llvm::Module,
pub llcx: &'ll llvm::Context,
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
/// Cache instances of monomorphic and polymorphic items
@ -553,10 +578,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
CodegenCx {
tcx,
scx: SimpleCx { llcx, llmod },
use_dll_storage_attrs,
tls_model,
llmod,
llcx,
codegen_unit,
instances: Default::default(),
vtables: Default::default(),
@ -600,6 +624,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::set_section(g, c"llvm.metadata");
}
}
}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
common::val_ty(v)
}
pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
@ -625,6 +654,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
})
}
pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind {
unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
}
}
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@ -1176,6 +1209,20 @@ impl CodegenCx<'_, '_> {
}
}
// This is a duplication of the set_metadata function above. However, so far it's the only one
// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it
// for the Builder.
impl SimpleCx<'_> {
#[allow(unused)]
/// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
unsafe {
let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
}
}
}
impl HasDataLayout for CodegenCx<'_, '_> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {

View file

@ -21,26 +21,26 @@ use tracing::debug;
use crate::abi::{FnAbi, FnAbiLlvmExt};
use crate::common::AsCCharPtr;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, SimpleCx};
use crate::llvm::AttributePlace::Function;
use crate::llvm::Visibility;
use crate::type_::Type;
use crate::value::Value;
use crate::{attributes, llvm};
/// Declare a function.
/// Declare a function with a SimpleCx.
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
pub(crate) fn declare_raw_fn<'ll>(
cx: &CodegenCx<'ll, '_>,
pub(crate) fn declare_simple_fn<'ll>(
cx: &SimpleCx<'ll>,
name: &str,
callconv: llvm::CallConv,
unnamed: llvm::UnnamedAddr,
visibility: llvm::Visibility,
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty);
let llfn = unsafe {
llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
};
@ -49,6 +49,24 @@ pub(crate) fn declare_raw_fn<'ll>(
llvm::SetUnnamedAddress(llfn, unnamed);
llvm::set_visibility(llfn, visibility);
llfn
}
/// Declare a function.
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
pub(crate) fn declare_raw_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
name: &str,
callconv: llvm::CallConv,
unnamed: llvm::UnnamedAddr,
visibility: llvm::Visibility,
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
let llfn = declare_simple_fn(cx, name, callconv, unnamed, visibility, ty);
let mut attrs = SmallVec::<[_; 4]>::new();
if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {

View file

@ -1081,11 +1081,11 @@ fn codegen_emcc_try<'ll>(
// Helper function to give a Block to a closure to codegen a shim function.
// This is currently primarily used for the `try` intrinsic functions above.
fn gen_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
fn gen_fn<'a, 'll, 'tcx>(
cx: &'a CodegenCx<'ll, 'tcx>,
name: &str,
rust_fn_sig: ty::PolyFnSig<'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
) -> (&'ll Type, &'ll Value) {
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
let llty = fn_abi.llvm_type(cx);
@ -1104,9 +1104,9 @@ fn gen_fn<'ll, 'tcx>(
// catch exceptions.
//
// This function is only generated once and is then cached.
fn get_rust_try_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
fn get_rust_try_fn<'a, 'll, 'tcx>(
cx: &'a CodegenCx<'ll, 'tcx>,
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
) -> (&'ll Type, &'ll Value) {
if let Some(llfn) = cx.rust_try_fn.get() {
return llfn;

View file

@ -237,7 +237,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
/// Generate autodiff rules
fn autodiff(
cgcx: &CodegenContext<Self>,
tcx: TyCtxt<'_>,
module: &ModuleCodegen<Self::Module>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,
@ -246,7 +245,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
let dcx = cgcx.create_dcx();
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));
}
builder::autodiff::differentiate(module, cgcx, tcx, diff_fncs, config)
builder::autodiff::differentiate(module, cgcx, diff_fncs, config)
}
}

View file

@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Ty};
use rustc_target::callconv::{CastTarget, FnAbi, Reg};
use crate::abi::{FnAbiLlvmExt, LlvmType};
use crate::context::CodegenCx;
use crate::context::{CodegenCx, SimpleCx};
pub(crate) use crate::llvm::Type;
use crate::llvm::{Bool, False, Metadata, True};
use crate::type_of::LayoutLlvmExt;
@ -35,7 +35,8 @@ impl fmt::Debug for Type {
}
}
impl<'ll> CodegenCx<'ll, '_> {
impl<'ll> CodegenCx<'ll, '_> {}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
let name = SmallCStr::new(name);
unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
@ -44,11 +45,9 @@ impl<'ll> CodegenCx<'ll, '_> {
pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
}
pub(crate) fn type_void(&self) -> &'ll Type {
unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
}
pub(crate) fn type_token(&self) -> &'ll Type {
unsafe { llvm::LLVMTokenTypeInContext(self.llcx) }
}
@ -75,7 +74,8 @@ impl<'ll> CodegenCx<'ll, '_> {
args
}
}
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
pub(crate) fn type_bool(&self) -> &'ll Type {
self.type_i8()
}
@ -120,7 +120,8 @@ impl<'ll> CodegenCx<'ll, '_> {
assert_eq!(size % unit_size, 0);
self.type_array(self.type_from_integer(unit), size / unit_size)
}
}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
}