about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src/allocator.rs
diff options
context:
space:
mode:
authormark <markm@cs.wisc.edu>2020-08-27 22:58:48 -0500
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2020-08-30 18:45:07 +0300
commit9e5f7d5631b8f4009ac1c693e585d4b7108d4275 (patch)
tree158a05eb3f204a8e72939b58427d0c2787a4eade /compiler/rustc_codegen_llvm/src/allocator.rs
parentdb534b3ac286cf45688c3bbae6aa6e77439e52d2 (diff)
downloadrust-9e5f7d5631b8f4009ac1c693e585d4b7108d4275.tar.gz
rust-9e5f7d5631b8f4009ac1c693e585d4b7108d4275.zip
mv compiler to compiler/
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/allocator.rs')
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
new file mode 100644
index 00000000000..bc1d9e1818c
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -0,0 +1,85 @@
+use crate::attributes;
+use libc::c_uint;
+use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_middle::bug;
+use rustc_middle::ty::TyCtxt;
+
+use crate::llvm::{self, False, True};
+use crate::ModuleLlvm;
+
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: AllocatorKind) {
+    let llcx = &*mods.llcx;
+    let llmod = mods.llmod();
+    let usize = match &tcx.sess.target.target.target_pointer_width[..] {
+        "16" => llvm::LLVMInt16TypeInContext(llcx),
+        "32" => llvm::LLVMInt32TypeInContext(llcx),
+        "64" => llvm::LLVMInt64TypeInContext(llcx),
+        tws => bug!("Unsupported target word size for int: {}", tws),
+    };
+    let i8 = llvm::LLVMInt8TypeInContext(llcx);
+    let i8p = llvm::LLVMPointerType(i8, 0);
+    let void = llvm::LLVMVoidTypeInContext(llcx);
+
+    for method in ALLOCATOR_METHODS {
+        let mut args = Vec::with_capacity(method.inputs.len());
+        for ty in method.inputs.iter() {
+            match *ty {
+                AllocatorTy::Layout => {
+                    args.push(usize); // size
+                    args.push(usize); // align
+                }
+                AllocatorTy::Ptr => args.push(i8p),
+                AllocatorTy::Usize => args.push(usize),
+
+                AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
+            }
+        }
+        let output = match method.output {
+            AllocatorTy::ResultPtr => Some(i8p),
+            AllocatorTy::Unit => None,
+
+            AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+                panic!("invalid allocator output")
+            }
+        };
+        let ty = llvm::LLVMFunctionType(
+            output.unwrap_or(void),
+            args.as_ptr(),
+            args.len() as c_uint,
+            False,
+        );
+        let name = format!("__rust_{}", method.name);
+        let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
+
+        if tcx.sess.target.target.options.default_hidden_visibility {
+            llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+        }
+        if tcx.sess.must_emit_unwind_tables() {
+            attributes::emit_uwtable(llfn, true);
+        }
+
+        let callee = kind.fn_name(method.name);
+        let callee =
+            llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
+        llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+        let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
+
+        let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
+        llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
+        let args = args
+            .iter()
+            .enumerate()
+            .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
+            .collect::<Vec<_>>();
+        let ret =
+            llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
+        llvm::LLVMSetTailCall(ret, True);
+        if output.is_some() {
+            llvm::LLVMBuildRet(llbuilder, ret);
+        } else {
+            llvm::LLVMBuildRetVoid(llbuilder);
+        }
+        llvm::LLVMDisposeBuilder(llbuilder);
+    }
+}