2013-07-21 13:33:40 +00:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2016-08-02 20:10:10 +00:00
|
|
|
use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
|
2018-07-10 15:00:02 +00:00
|
|
|
use llvm::{IntPredicate, RealPredicate, False, OperandBundleDef};
|
2018-07-10 11:34:34 +00:00
|
|
|
use llvm::{self, BasicBlock};
|
2016-03-22 17:23:36 +00:00
|
|
|
use common::*;
|
|
|
|
use type_::Type;
|
|
|
|
use value::Value;
|
2014-10-14 20:36:11 +00:00
|
|
|
use libc::{c_uint, c_char};
|
2017-02-06 16:27:09 +00:00
|
|
|
use rustc::ty::TyCtxt;
|
2017-06-01 18:50:53 +00:00
|
|
|
use rustc::ty::layout::{Align, Size};
|
|
|
|
use rustc::session::{config, Session};
|
2018-08-07 14:04:34 +00:00
|
|
|
use rustc_data_structures::small_c_str::SmallCStr;
|
2014-11-25 21:28:35 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
use std::borrow::Cow;
|
2017-09-23 12:04:37 +00:00
|
|
|
use std::ops::Range;
|
2015-02-02 18:03:23 +00:00
|
|
|
use std::ptr;
|
2013-07-21 13:33:40 +00:00
|
|
|
|
2016-12-31 23:00:24 +00:00
|
|
|
// All Builders must have an llfn associated with them
|
|
|
|
#[must_use]
|
2018-07-02 14:52:53 +00:00
|
|
|
pub struct Builder<'a, 'll: 'a, 'tcx: 'll> {
|
2018-07-17 15:33:09 +00:00
|
|
|
pub llbuilder: &'ll mut llvm::Builder<'ll>,
|
2018-07-02 14:52:53 +00:00
|
|
|
pub cx: &'a CodegenCx<'ll, 'tcx>,
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
impl Drop for Builder<'a, 'll, 'tcx> {
|
2016-12-17 00:39:35 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
2018-07-17 15:33:09 +00:00
|
|
|
llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
|
2016-12-17 00:39:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
// This is a really awful way to get a zero-length c-string, but better (and a
|
|
|
|
// lot more efficient) than doing str::as_c_str("", ...) every time.
|
2016-12-17 17:21:15 +00:00
|
|
|
fn noname() -> *const c_char {
|
2014-09-13 01:55:37 +00:00
|
|
|
static CNULL: c_char = 0;
|
2015-01-17 04:34:10 +00:00
|
|
|
&CNULL
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 10:26:32 +00:00
|
|
|
bitflags! {
|
|
|
|
pub struct MemFlags: u8 {
|
|
|
|
const VOLATILE = 1 << 0;
|
|
|
|
const NONTEMPORAL = 1 << 1;
|
2018-07-14 22:28:39 +00:00
|
|
|
const UNALIGNED = 1 << 2;
|
2018-05-11 10:26:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
impl Builder<'a, 'll, 'tcx> {
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn new_block<'b>(cx: &'a CodegenCx<'ll, 'tcx>, llfn: &'ll Value, name: &'b str) -> Self {
|
2018-01-05 05:12:32 +00:00
|
|
|
let bx = Builder::with_cx(cx);
|
2016-12-31 23:00:24 +00:00
|
|
|
let llbb = unsafe {
|
2018-08-07 14:04:34 +00:00
|
|
|
let name = SmallCStr::new(name);
|
2016-12-31 23:00:24 +00:00
|
|
|
llvm::LLVMAppendBasicBlockInContext(
|
2018-01-05 05:04:08 +00:00
|
|
|
cx.llcx,
|
2016-12-31 23:00:24 +00:00
|
|
|
llfn,
|
|
|
|
name.as_ptr()
|
|
|
|
)
|
|
|
|
};
|
2018-01-05 05:12:32 +00:00
|
|
|
bx.position_at_end(llbb);
|
|
|
|
bx
|
2016-12-31 23:00:24 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
|
2016-12-17 00:39:35 +00:00
|
|
|
// Create a fresh builder from the crate context.
|
|
|
|
let llbuilder = unsafe {
|
2018-01-05 05:04:08 +00:00
|
|
|
llvm::LLVMCreateBuilderInContext(cx.llcx)
|
2016-12-17 00:39:35 +00:00
|
|
|
};
|
2013-07-21 13:33:40 +00:00
|
|
|
Builder {
|
2017-08-07 05:54:09 +00:00
|
|
|
llbuilder,
|
2018-01-05 05:04:08 +00:00
|
|
|
cx,
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, 'll, 'tcx> {
|
2018-01-05 05:04:08 +00:00
|
|
|
Builder::new_block(self.cx, self.llfn(), name)
|
2016-12-31 23:00:24 +00:00
|
|
|
}
|
|
|
|
|
2017-01-01 15:46:34 +00:00
|
|
|
pub fn sess(&self) -> &Session {
|
2018-01-05 05:04:08 +00:00
|
|
|
self.cx.sess()
|
2017-01-01 15:46:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
|
2018-01-05 05:04:08 +00:00
|
|
|
self.cx.tcx
|
2017-01-01 15:46:34 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn llfn(&self) -> &'ll Value {
|
2016-12-31 23:00:24 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMGetBasicBlockParent(self.llbb())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn llbb(&self) -> &'ll BasicBlock {
|
2016-12-31 23:00:24 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMGetInsertBlock(self.llbuilder)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-17 17:21:15 +00:00
|
|
|
fn count_insn(&self, category: &str) {
|
2018-05-08 13:10:16 +00:00
|
|
|
if self.cx.sess().codegen_stats() {
|
2018-01-05 05:04:08 +00:00
|
|
|
self.cx.stats.borrow_mut().n_llvm_insns += 1;
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
2018-01-05 05:04:08 +00:00
|
|
|
if self.cx.sess().count_llvm_insns() {
|
|
|
|
*self.cx.stats
|
2017-09-14 03:26:39 +00:00
|
|
|
.borrow_mut()
|
|
|
|
.llvm_insns
|
|
|
|
.entry(category.to_string())
|
|
|
|
.or_insert(0) += 1;
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn set_value_name(&self, value: &'ll Value, name: &str) {
|
2018-08-07 14:04:34 +00:00
|
|
|
let cname = SmallCStr::new(name);
|
Avoid unnecessary copies of arguments that are simple bindings
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
2017-10-11 18:49:36 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetValueName(value, cname.as_ptr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn position_at_end(&self, llbb: &'ll BasicBlock) {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn position_at_start(&self, llbb: &'ll BasicBlock) {
|
2016-02-04 17:40:28 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn ret_void(&self) {
|
|
|
|
self.count_insn("retvoid");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildRetVoid(self.llbuilder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn ret(&self, v: &'ll Value) {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("ret");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildRet(self.llbuilder, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn br(&self, dest: &'ll BasicBlock) {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("br");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildBr(self.llbuilder, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-17 15:26:58 +00:00
|
|
|
pub fn cond_br(
|
|
|
|
&self,
|
|
|
|
cond: &'ll Value,
|
|
|
|
then_llbb: &'ll BasicBlock,
|
|
|
|
else_llbb: &'ll BasicBlock,
|
|
|
|
) {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("condbr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-17 15:26:58 +00:00
|
|
|
pub fn switch(
|
|
|
|
&self,
|
|
|
|
v: &'ll Value,
|
|
|
|
else_llbb: &'ll BasicBlock,
|
|
|
|
num_cases: usize,
|
|
|
|
) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn invoke(&self,
|
2018-07-10 10:28:39 +00:00
|
|
|
llfn: &'ll Value,
|
|
|
|
args: &[&'ll Value],
|
2018-07-10 11:34:34 +00:00
|
|
|
then: &'ll BasicBlock,
|
|
|
|
catch: &'ll BasicBlock,
|
2018-07-16 13:02:31 +00:00
|
|
|
bundle: Option<&OperandBundleDef<'ll>>) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("invoke");
|
2014-06-28 19:55:17 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
debug!("Invoke {:?} with args ({:?})",
|
|
|
|
llfn,
|
|
|
|
args);
|
2014-06-28 19:55:17 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
let args = self.check_call("invoke", llfn, args);
|
2018-07-16 13:02:31 +00:00
|
|
|
let bundle = bundle.map(|b| &*b.raw);
|
2015-10-24 01:18:44 +00:00
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2016-02-25 23:10:40 +00:00
|
|
|
llvm::LLVMRustBuildInvoke(self.llbuilder,
|
|
|
|
llfn,
|
|
|
|
args.as_ptr(),
|
|
|
|
args.len() as c_uint,
|
|
|
|
then,
|
|
|
|
catch,
|
|
|
|
bundle,
|
|
|
|
noname())
|
2013-09-16 22:30:59 +00:00
|
|
|
}
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unreachable(&self) {
|
|
|
|
self.count_insn("unreachable");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildUnreachable(self.llbuilder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Arithmetic */
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn add(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("add");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fadd(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fadd");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fadd_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2016-03-14 23:01:12 +00:00
|
|
|
self.count_insn("fadd");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn sub(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("sub");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fsub(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2018-07-09 07:24:42 +00:00
|
|
|
self.count_insn("fsub");
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fsub_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2018-07-09 07:24:42 +00:00
|
|
|
self.count_insn("fsub");
|
2016-03-14 23:01:12 +00:00
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn mul(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("mul");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fmul(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fmul");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fmul_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2016-03-14 23:01:12 +00:00
|
|
|
self.count_insn("fmul");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn udiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("udiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn exactudiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
Introduce unsafe offset_from on pointers
Adds intrinsics::exact_div to take advantage of the unsafe, which reduces the implementation from
```asm
sub rcx, rdx
mov rax, rcx
sar rax, 63
shr rax, 62
lea rax, [rax + rcx]
sar rax, 2
ret
```
down to
```asm
sub rcx, rdx
sar rcx, 2
mov rax, rcx
ret
```
(for `*const i32`)
2018-03-23 08:30:23 +00:00
|
|
|
self.count_insn("exactudiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn sdiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("sdiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn exactsdiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("exactsdiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fdiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fdiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fdiv_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2016-03-14 23:01:12 +00:00
|
|
|
self.count_insn("fdiv");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn urem(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("urem");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn srem(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("srem");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn frem(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("frem");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn frem_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2016-03-14 23:01:12 +00:00
|
|
|
self.count_insn("frem");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn shl(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("shl");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn lshr(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("lshr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn ashr(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("ashr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn and(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("and");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn or(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("or");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn xor(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("xor");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn neg(&self, v: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("neg");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildNeg(self.llbuilder, v, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fneg(&self, v: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fneg");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildFNeg(self.llbuilder, v, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn not(&self, v: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("not");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildNot(self.llbuilder, v, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn alloca(&self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
|
2018-01-05 05:12:32 +00:00
|
|
|
let bx = Builder::with_cx(self.cx);
|
|
|
|
bx.position_at_start(unsafe {
|
2016-12-31 23:00:24 +00:00
|
|
|
llvm::LLVMGetFirstBasicBlock(self.llfn())
|
|
|
|
});
|
2018-01-05 05:12:32 +00:00
|
|
|
bx.dynamic_alloca(ty, name, align)
|
2016-12-31 23:00:24 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn dynamic_alloca(&self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("alloca");
|
|
|
|
unsafe {
|
2017-01-14 22:49:29 +00:00
|
|
|
let alloca = if name.is_empty() {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildAlloca(self.llbuilder, ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
} else {
|
2018-08-07 14:04:34 +00:00
|
|
|
let name = SmallCStr::new(name);
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildAlloca(self.llbuilder, ty,
|
2014-11-25 21:28:35 +00:00
|
|
|
name.as_ptr())
|
2017-01-14 22:49:29 +00:00
|
|
|
};
|
2017-11-19 18:28:52 +00:00
|
|
|
llvm::LLVMSetAlignment(alloca, align.abi() as c_uint);
|
2017-01-14 22:49:29 +00:00
|
|
|
alloca
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-28 15:07:23 +00:00
|
|
|
pub fn array_alloca(&self,
|
|
|
|
ty: &'ll Type,
|
|
|
|
len: &'ll Value,
|
|
|
|
name: &str,
|
|
|
|
align: Align) -> &'ll Value {
|
|
|
|
self.count_insn("alloca");
|
|
|
|
unsafe {
|
|
|
|
let alloca = if name.is_empty() {
|
|
|
|
llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, noname())
|
|
|
|
} else {
|
|
|
|
let name = SmallCStr::new(name);
|
|
|
|
llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len,
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
|
|
|
llvm::LLVMSetAlignment(alloca, align.abi() as c_uint);
|
|
|
|
alloca
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn load(&self, ptr: &'ll Value, align: Align) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("load");
|
|
|
|
unsafe {
|
2017-02-06 16:27:09 +00:00
|
|
|
let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
|
2017-12-01 22:28:43 +00:00
|
|
|
llvm::LLVMSetAlignment(load, align.abi() as c_uint);
|
2017-02-06 16:27:09 +00:00
|
|
|
load
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn volatile_load(&self, ptr: &'ll Value) -> &'ll Value {
|
2013-12-28 14:01:53 +00:00
|
|
|
self.count_insn("load.volatile");
|
|
|
|
unsafe {
|
|
|
|
let insn = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
|
2014-07-08 00:58:01 +00:00
|
|
|
llvm::LLVMSetVolatile(insn, llvm::True);
|
2013-12-28 14:01:53 +00:00
|
|
|
insn
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn atomic_load(&self, ptr: &'ll Value, order: AtomicOrdering, align: Align) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("load.atomic");
|
|
|
|
unsafe {
|
2017-06-01 18:50:53 +00:00
|
|
|
let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order);
|
2017-11-19 01:56:37 +00:00
|
|
|
// FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here?
|
|
|
|
// However, 64-bit atomic loads on `i686-apple-darwin` appear to
|
|
|
|
// require `___atomic_load` with ABI-alignment, so it's staying.
|
|
|
|
llvm::LLVMSetAlignment(load, align.pref() as c_uint);
|
2017-06-01 18:50:53 +00:00
|
|
|
load
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn range_metadata(&self, load: &'ll Value, range: Range<u128>) {
|
2018-07-19 03:05:08 +00:00
|
|
|
if self.sess().target.target.arch == "amdgpu" {
|
|
|
|
// amdgpu/LLVM does something weird and thinks a i64 value is
|
|
|
|
// split into a v2i32, halving the bitwidth LLVM expects,
|
|
|
|
// tripping an assertion. So, for now, just disable this
|
|
|
|
// optimization.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2017-09-23 12:04:37 +00:00
|
|
|
let llty = val_ty(load);
|
|
|
|
let v = [
|
|
|
|
C_uint_big(llty, range.start),
|
|
|
|
C_uint_big(llty, range.end)
|
|
|
|
];
|
2013-12-17 14:49:31 +00:00
|
|
|
|
2017-09-23 12:04:37 +00:00
|
|
|
llvm::LLVMSetMetadata(load, llvm::MD_range as c_uint,
|
2018-01-05 05:04:08 +00:00
|
|
|
llvm::LLVMMDNodeInContext(self.cx.llcx,
|
2014-10-14 20:36:11 +00:00
|
|
|
v.as_ptr(),
|
|
|
|
v.len() as c_uint));
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn nonnull_metadata(&self, load: &'ll Value) {
|
2015-02-02 18:03:23 +00:00
|
|
|
unsafe {
|
2017-09-23 12:04:37 +00:00
|
|
|
llvm::LLVMSetMetadata(load, llvm::MD_nonnull as c_uint,
|
2018-01-05 05:04:08 +00:00
|
|
|
llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0));
|
2015-02-02 18:03:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn store(&self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
|
2018-05-11 10:26:32 +00:00
|
|
|
self.store_with_flags(val, ptr, align, MemFlags::empty())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store_with_flags(
|
|
|
|
&self,
|
2018-07-10 10:28:39 +00:00
|
|
|
val: &'ll Value,
|
|
|
|
ptr: &'ll Value,
|
2018-05-11 10:26:32 +00:00
|
|
|
align: Align,
|
|
|
|
flags: MemFlags,
|
2018-07-10 10:28:39 +00:00
|
|
|
) -> &'ll Value {
|
|
|
|
debug!("Store {:?} -> {:?} ({:?})", val, ptr, flags);
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("store");
|
2016-10-12 17:26:06 +00:00
|
|
|
let ptr = self.check_store(val, ptr);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2016-12-29 01:20:26 +00:00
|
|
|
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
|
2018-07-14 22:28:39 +00:00
|
|
|
let align = if flags.contains(MemFlags::UNALIGNED) {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
align.abi() as c_uint
|
|
|
|
};
|
|
|
|
llvm::LLVMSetAlignment(store, align);
|
2018-05-11 10:26:32 +00:00
|
|
|
if flags.contains(MemFlags::VOLATILE) {
|
|
|
|
llvm::LLVMSetVolatile(store, llvm::True);
|
|
|
|
}
|
|
|
|
if flags.contains(MemFlags::NONTEMPORAL) {
|
|
|
|
// According to LLVM [1] building a nontemporal store must
|
|
|
|
// *always* point to a metadata value of the integer 1.
|
|
|
|
//
|
|
|
|
// [1]: http://llvm.org/docs/LangRef.html#store-instruction
|
|
|
|
let one = C_i32(self.cx, 1);
|
|
|
|
let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
|
|
|
|
llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
|
|
|
|
}
|
2016-12-29 01:20:26 +00:00
|
|
|
store
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn atomic_store(&self, val: &'ll Value, ptr: &'ll Value,
|
2017-06-01 18:50:53 +00:00
|
|
|
order: AtomicOrdering, align: Align) {
|
2018-07-10 10:28:39 +00:00
|
|
|
debug!("Store {:?} -> {:?}", val, ptr);
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("store.atomic");
|
2016-10-12 17:26:06 +00:00
|
|
|
let ptr = self.check_store(val, ptr);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2017-06-01 18:50:53 +00:00
|
|
|
let store = llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order);
|
2017-11-19 01:56:37 +00:00
|
|
|
// FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here?
|
|
|
|
// Also see `atomic_load` for more context.
|
|
|
|
llvm::LLVMSetAlignment(store, align.pref() as c_uint);
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn gep(&self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("gep");
|
|
|
|
unsafe {
|
2013-12-15 12:35:12 +00:00
|
|
|
llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(),
|
2013-07-21 13:33:40 +00:00
|
|
|
indices.len() as c_uint, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn inbounds_gep(&self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("inboundsgep");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildInBoundsGEP(
|
2013-12-15 12:35:12 +00:00
|
|
|
self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn struct_gep(&self, ptr: &'ll Value, idx: u64) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("structgep");
|
2017-06-25 09:41:24 +00:00
|
|
|
assert_eq!(idx as c_uint as u64, idx);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Casts */
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn trunc(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("trunc");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn zext(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("zext");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn sext(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("sext");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fptoui(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fptoui");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fptosi(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fptosi");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty,noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn uitofp(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("uitofp");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn sitofp(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("sitofp");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fptrunc(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fptrunc");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fpext(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fpext");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn ptrtoint(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("ptrtoint");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn inttoptr(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("inttoptr");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn bitcast(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("bitcast");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn pointercast(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("pointercast");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn intcast(&self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("intcast");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty, is_signed)
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Comparisons */
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn icmp(&self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("icmp");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn fcmp(&self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("fcmp");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Miscellaneous instructions */
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn empty_phi(&self, ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("emptyphi");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildPhi(self.llbuilder, ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn phi(&self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
assert_eq!(vals.len(), bbs.len());
|
|
|
|
let phi = self.empty_phi(ty);
|
|
|
|
self.count_insn("addincoming");
|
|
|
|
unsafe {
|
2013-12-15 12:35:12 +00:00
|
|
|
llvm::LLVMAddIncoming(phi, vals.as_ptr(),
|
|
|
|
bbs.as_ptr(),
|
2013-07-21 13:33:40 +00:00
|
|
|
vals.len() as c_uint);
|
|
|
|
phi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:47:34 +00:00
|
|
|
pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
|
2018-07-10 10:28:39 +00:00
|
|
|
inputs: &[&'ll Value], output: &'ll Type,
|
2013-07-21 13:33:40 +00:00
|
|
|
volatile: bool, alignstack: bool,
|
2018-09-25 18:35:19 +00:00
|
|
|
dia: AsmDialect) -> Option<&'ll Value> {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("inlineasm");
|
|
|
|
|
2014-07-08 00:58:01 +00:00
|
|
|
let volatile = if volatile { llvm::True }
|
|
|
|
else { llvm::False };
|
|
|
|
let alignstack = if alignstack { llvm::True }
|
|
|
|
else { llvm::False };
|
2013-07-21 13:33:40 +00:00
|
|
|
|
2014-03-28 19:42:34 +00:00
|
|
|
let argtys = inputs.iter().map(|v| {
|
2018-07-10 10:28:39 +00:00
|
|
|
debug!("Asm Input Type: {:?}", *v);
|
2013-07-21 13:33:40 +00:00
|
|
|
val_ty(*v)
|
2014-03-28 19:42:34 +00:00
|
|
|
}).collect::<Vec<_>>();
|
2013-07-21 13:33:40 +00:00
|
|
|
|
2016-02-18 17:49:45 +00:00
|
|
|
debug!("Asm Output Type: {:?}", output);
|
2018-07-02 14:52:53 +00:00
|
|
|
let fty = Type::func(&argtys[..], output);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2018-09-25 18:35:19 +00:00
|
|
|
// Ask LLVM to verify that the constraints are well-formed.
|
|
|
|
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons);
|
|
|
|
debug!("Constraint verification result: {:?}", constraints_ok);
|
2018-09-26 04:43:19 +00:00
|
|
|
if constraints_ok == llvm::True {
|
2018-09-25 18:35:19 +00:00
|
|
|
let v = llvm::LLVMRustInlineAsm(
|
|
|
|
fty, asm, cons, volatile, alignstack, dia);
|
|
|
|
Some(self.call(v, inputs, None))
|
|
|
|
} else {
|
|
|
|
// LLVM has detected an issue with our constaints, bail out
|
|
|
|
None
|
|
|
|
}
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn call(&self, llfn: &'ll Value, args: &[&'ll Value],
|
2018-07-16 13:02:31 +00:00
|
|
|
bundle: Option<&OperandBundleDef<'ll>>) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("call");
|
2014-01-27 12:18:36 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
debug!("Call {:?} with args ({:?})",
|
|
|
|
llfn,
|
|
|
|
args);
|
2014-01-27 12:18:36 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
let args = self.check_call("call", llfn, args);
|
2018-07-16 13:02:31 +00:00
|
|
|
let bundle = bundle.map(|b| &*b.raw);
|
2015-10-24 01:18:44 +00:00
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2016-02-25 23:10:40 +00:00
|
|
|
llvm::LLVMRustBuildCall(self.llbuilder, llfn, args.as_ptr(),
|
|
|
|
args.len() as c_uint, bundle, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn minnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2018-03-21 20:49:22 +00:00
|
|
|
self.count_insn("minnum");
|
|
|
|
unsafe {
|
2018-03-22 13:48:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildMinNum is not available in LLVM version < 6.0")
|
2018-03-21 20:49:22 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn maxnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
|
2018-03-21 20:49:22 +00:00
|
|
|
self.count_insn("maxnum");
|
|
|
|
unsafe {
|
2018-03-22 13:48:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildMaxNum is not available in LLVM version < 6.0")
|
2018-03-21 20:49:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn select(
|
|
|
|
&self, cond: &'ll Value,
|
|
|
|
then_val: &'ll Value,
|
|
|
|
else_val: &'ll Value,
|
|
|
|
) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("select");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 15:00:02 +00:00
|
|
|
#[allow(dead_code)]
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn va_arg(&self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("vaarg");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildVAArg(self.llbuilder, list, ty, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn extract_element(&self, vec: &'ll Value, idx: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("extractelement");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn insert_element(
|
|
|
|
&self, vec: &'ll Value,
|
|
|
|
elt: &'ll Value,
|
|
|
|
idx: &'ll Value,
|
|
|
|
) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("insertelement");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn shuffle_vector(&self, v1: &'ll Value, v2: &'ll Value, mask: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("shufflevector");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_splat(&self, num_elts: usize, elt: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
let elt_ty = val_ty(elt);
|
2018-07-02 14:52:53 +00:00
|
|
|
let undef = llvm::LLVMGetUndef(Type::vector(elt_ty, num_elts as u64));
|
2018-01-05 05:04:08 +00:00
|
|
|
let vec = self.insert_element(undef, elt, C_i32(self.cx, 0));
|
2018-07-02 14:52:53 +00:00
|
|
|
let vec_i32_ty = Type::vector(Type::i32(self.cx), num_elts as u64);
|
2014-03-15 20:29:34 +00:00
|
|
|
self.shuffle_vector(vec, undef, C_null(vec_i32_ty))
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_fadd_fast(&self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.fadd_fast");
|
|
|
|
unsafe {
|
2018-03-14 16:22:40 +00:00
|
|
|
// FIXME: add a non-fast math version once
|
|
|
|
// https://bugs.llvm.org/show_bug.cgi?id=36732
|
|
|
|
// is fixed.
|
2018-07-17 15:26:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src)
|
|
|
|
.expect("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0");
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_fmul_fast(&self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.fmul_fast");
|
|
|
|
unsafe {
|
2018-03-14 16:22:40 +00:00
|
|
|
// FIXME: add a non-fast math version once
|
|
|
|
// https://bugs.llvm.org/show_bug.cgi?id=36732
|
|
|
|
// is fixed.
|
2018-07-17 15:26:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src)
|
|
|
|
.expect("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0");
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_add(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.add");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_mul(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.mul");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_and(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.and");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_or(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.or");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_xor(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.xor");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_fmin(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-14 16:22:40 +00:00
|
|
|
self.count_insn("vector.reduce.fmin");
|
|
|
|
unsafe {
|
2018-03-21 09:32:53 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0")
|
2018-03-14 16:22:40 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_fmax(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-14 16:22:40 +00:00
|
|
|
self.count_insn("vector.reduce.fmax");
|
|
|
|
unsafe {
|
2018-03-21 09:32:53 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0")
|
2018-03-14 16:22:40 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_fmin_fast(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.fmin_fast");
|
|
|
|
unsafe {
|
2018-07-17 15:26:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true)
|
|
|
|
.expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_fmax_fast(&self, src: &'ll Value) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.fmax_fast");
|
|
|
|
unsafe {
|
2018-07-17 15:26:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true)
|
|
|
|
.expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_min(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.min");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn vector_reduce_max(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
|
2018-03-13 15:46:55 +00:00
|
|
|
self.count_insn("vector.reduce.max");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed);
|
2018-07-10 10:28:39 +00:00
|
|
|
instr.expect("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0")
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn extract_value(&self, agg_val: &'ll Value, idx: u64) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("extractvalue");
|
2017-06-25 09:41:24 +00:00
|
|
|
assert_eq!(idx as c_uint as u64, idx);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn insert_value(&self, agg_val: &'ll Value, elt: &'ll Value,
|
|
|
|
idx: u64) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("insertvalue");
|
2017-06-25 09:41:24 +00:00
|
|
|
assert_eq!(idx as c_uint as u64, idx);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
|
2013-08-07 19:40:09 +00:00
|
|
|
noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn landing_pad(&self, ty: &'ll Type, pers_fn: &'ll Value,
|
|
|
|
num_clauses: usize) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("landingpad");
|
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn,
|
2017-12-08 09:53:46 +00:00
|
|
|
num_clauses as c_uint, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn add_clause(&self, landing_pad: &'ll Value, clause: &'ll Value) {
|
2015-07-20 20:27:38 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMAddClause(landing_pad, clause);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn set_cleanup(&self, landing_pad: &'ll Value) {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("setcleanup");
|
|
|
|
unsafe {
|
2014-07-08 00:58:01 +00:00
|
|
|
llvm::LLVMSetCleanup(landing_pad, llvm::True);
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn resume(&self, exn: &'ll Value) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("resume");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildResume(self.llbuilder, exn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-24 01:18:44 +00:00
|
|
|
pub fn cleanup_pad(&self,
|
2018-07-10 10:28:39 +00:00
|
|
|
parent: Option<&'ll Value>,
|
|
|
|
args: &[&'ll Value]) -> &'ll Value {
|
2015-10-24 01:18:44 +00:00
|
|
|
self.count_insn("cleanuppad");
|
2018-08-07 14:03:57 +00:00
|
|
|
let name = const_cstr!("cleanuppad");
|
2015-10-24 01:18:44 +00:00
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCleanupPad(self.llbuilder,
|
|
|
|
parent,
|
|
|
|
args.len() as c_uint,
|
|
|
|
args.as_ptr(),
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
2018-07-10 10:28:39 +00:00
|
|
|
ret.expect("LLVM does not have support for cleanuppad")
|
2015-10-24 01:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn cleanup_ret(
|
|
|
|
&self, cleanup: &'ll Value,
|
|
|
|
unwind: Option<&'ll BasicBlock>,
|
|
|
|
) -> &'ll Value {
|
2015-10-24 01:18:44 +00:00
|
|
|
self.count_insn("cleanupret");
|
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCleanupRet(self.llbuilder, cleanup, unwind)
|
|
|
|
};
|
2018-07-10 10:28:39 +00:00
|
|
|
ret.expect("LLVM does not have support for cleanupret")
|
2015-10-24 01:18:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn catch_pad(&self,
|
2018-07-10 10:28:39 +00:00
|
|
|
parent: &'ll Value,
|
|
|
|
args: &[&'ll Value]) -> &'ll Value {
|
2015-10-24 01:18:44 +00:00
|
|
|
self.count_insn("catchpad");
|
2018-08-07 14:03:57 +00:00
|
|
|
let name = const_cstr!("catchpad");
|
2015-10-24 01:18:44 +00:00
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCatchPad(self.llbuilder, parent,
|
|
|
|
args.len() as c_uint, args.as_ptr(),
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
2018-07-10 10:28:39 +00:00
|
|
|
ret.expect("LLVM does not have support for catchpad")
|
2015-10-24 01:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn catch_ret(&self, pad: &'ll Value, unwind: &'ll BasicBlock) -> &'ll Value {
|
2015-10-24 01:18:44 +00:00
|
|
|
self.count_insn("catchret");
|
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCatchRet(self.llbuilder, pad, unwind)
|
|
|
|
};
|
2018-07-10 10:28:39 +00:00
|
|
|
ret.expect("LLVM does not have support for catchret")
|
2015-10-24 01:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn catch_switch(
|
|
|
|
&self,
|
|
|
|
parent: Option<&'ll Value>,
|
2018-07-10 11:34:34 +00:00
|
|
|
unwind: Option<&'ll BasicBlock>,
|
2018-07-10 10:28:39 +00:00
|
|
|
num_handlers: usize,
|
|
|
|
) -> &'ll Value {
|
2015-10-24 01:18:44 +00:00
|
|
|
self.count_insn("catchswitch");
|
2018-08-07 14:03:57 +00:00
|
|
|
let name = const_cstr!("catchswitch");
|
2015-10-24 01:18:44 +00:00
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind,
|
|
|
|
num_handlers as c_uint,
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
2018-07-10 10:28:39 +00:00
|
|
|
ret.expect("LLVM does not have support for catchswitch")
|
2015-10-24 01:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn add_handler(&self, catch_switch: &'ll Value, handler: &'ll BasicBlock) {
|
2015-10-24 01:18:44 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustAddHandler(catch_switch, handler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn set_personality_fn(&self, personality: &'ll Value) {
|
2015-10-24 01:18:44 +00:00
|
|
|
unsafe {
|
2017-01-26 15:51:10 +00:00
|
|
|
llvm::LLVMSetPersonalityFn(self.llfn(), personality);
|
2015-10-24 01:18:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
// Atomic Operations
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn atomic_cmpxchg(
|
|
|
|
&self,
|
|
|
|
dst: &'ll Value,
|
|
|
|
cmp: &'ll Value,
|
|
|
|
src: &'ll Value,
|
|
|
|
order: AtomicOrdering,
|
|
|
|
failure_order: AtomicOrdering,
|
|
|
|
weak: llvm::Bool,
|
|
|
|
) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2016-07-12 22:38:30 +00:00
|
|
|
llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src,
|
2016-01-16 23:40:11 +00:00
|
|
|
order, failure_order, weak)
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn atomic_rmw(
|
|
|
|
&self,
|
|
|
|
op: AtomicRmwBinOp,
|
|
|
|
dst: &'ll Value,
|
|
|
|
src: &'ll Value,
|
|
|
|
order: AtomicOrdering,
|
|
|
|
) -> &'ll Value {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2013-05-25 22:23:12 +00:00
|
|
|
llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order, False)
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
2013-07-28 07:48:16 +00:00
|
|
|
|
2015-02-15 06:48:10 +00:00
|
|
|
pub fn atomic_fence(&self, order: AtomicOrdering, scope: SynchronizationScope) {
|
2013-07-28 07:48:16 +00:00
|
|
|
unsafe {
|
2016-08-01 23:35:09 +00:00
|
|
|
llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope);
|
2013-07-28 07:48:16 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-20 23:43:01 +00:00
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn add_case(&self, s: &'ll Value, on_val: &'ll Value, dest: &'ll BasicBlock) {
|
2016-12-11 15:59:20 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMAddCase(s, on_val, dest)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 11:34:34 +00:00
|
|
|
pub fn add_incoming_to_phi(&self, phi: &'ll Value, val: &'ll Value, bb: &'ll BasicBlock) {
|
2018-07-09 07:24:42 +00:00
|
|
|
self.count_insn("addincoming");
|
2016-12-11 15:59:20 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn set_invariant_load(&self, load: &'ll Value) {
|
2017-02-21 08:08:06 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint,
|
2018-01-05 05:04:08 +00:00
|
|
|
llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0));
|
2017-02-21 08:08:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-12 17:26:06 +00:00
|
|
|
/// Returns the ptr value that should be used for storing `val`.
|
|
|
|
fn check_store<'b>(&self,
|
2018-07-10 10:28:39 +00:00
|
|
|
val: &'ll Value,
|
|
|
|
ptr: &'ll Value) -> &'ll Value {
|
2016-10-12 17:26:06 +00:00
|
|
|
let dest_ptr_ty = val_ty(ptr);
|
|
|
|
let stored_ty = val_ty(val);
|
|
|
|
let stored_ptr_ty = stored_ty.ptr_to();
|
|
|
|
|
|
|
|
assert_eq!(dest_ptr_ty.kind(), llvm::TypeKind::Pointer);
|
|
|
|
|
|
|
|
if dest_ptr_ty == stored_ptr_ty {
|
|
|
|
ptr
|
|
|
|
} else {
|
|
|
|
debug!("Type mismatch in store. \
|
|
|
|
Expected {:?}, got {:?}; inserting bitcast",
|
|
|
|
dest_ptr_ty, stored_ptr_ty);
|
|
|
|
self.bitcast(ptr, stored_ptr_ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the args that should be used for a call to `llfn`.
|
2016-10-12 15:36:04 +00:00
|
|
|
fn check_call<'b>(&self,
|
|
|
|
typ: &str,
|
2018-07-10 10:28:39 +00:00
|
|
|
llfn: &'ll Value,
|
|
|
|
args: &'b [&'ll Value]) -> Cow<'b, [&'ll Value]> {
|
2016-04-20 23:43:01 +00:00
|
|
|
let mut fn_ty = val_ty(llfn);
|
|
|
|
// Strip off pointers
|
|
|
|
while fn_ty.kind() == llvm::TypeKind::Pointer {
|
|
|
|
fn_ty = fn_ty.element_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
assert!(fn_ty.kind() == llvm::TypeKind::Function,
|
2017-02-22 00:24:16 +00:00
|
|
|
"builder::{} not passed a function, but {:?}", typ, fn_ty);
|
2016-04-20 23:43:01 +00:00
|
|
|
|
|
|
|
let param_tys = fn_ty.func_params();
|
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
let all_args_match = param_tys.iter()
|
|
|
|
.zip(args.iter().map(|&v| val_ty(v)))
|
|
|
|
.all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
|
|
|
|
|
|
|
|
if all_args_match {
|
|
|
|
return Cow::Borrowed(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
let casted_args: Vec<_> = param_tys.into_iter()
|
|
|
|
.zip(args.iter())
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, (expected_ty, &actual_val))| {
|
|
|
|
let actual_ty = val_ty(actual_val);
|
|
|
|
if expected_ty != actual_ty {
|
|
|
|
debug!("Type mismatch in function call of {:?}. \
|
|
|
|
Expected {:?} for param {}, got {:?}; injecting bitcast",
|
2018-07-10 10:28:39 +00:00
|
|
|
llfn, expected_ty, i, actual_ty);
|
2016-10-12 15:36:04 +00:00
|
|
|
self.bitcast(actual_val, expected_ty)
|
|
|
|
} else {
|
|
|
|
actual_val
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2016-04-20 23:43:01 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
return Cow::Owned(casted_args);
|
2016-04-20 23:43:01 +00:00
|
|
|
}
|
2017-06-01 18:50:53 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn lifetime_start(&self, ptr: &'ll Value, size: Size) {
|
2017-06-01 18:50:53 +00:00
|
|
|
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
|
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn lifetime_end(&self, ptr: &'ll Value, size: Size) {
|
2017-06-01 18:50:53 +00:00
|
|
|
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If LLVM lifetime intrinsic support is enabled (i.e. optimizations
|
|
|
|
/// on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
|
|
|
|
/// and the intrinsic for `lt` and passes them to `emit`, which is in
|
|
|
|
/// charge of generating code to call the passed intrinsic on whatever
|
2018-02-16 14:56:50 +00:00
|
|
|
/// block of generated code is targeted for the intrinsic.
|
2017-06-01 18:50:53 +00:00
|
|
|
///
|
|
|
|
/// If LLVM lifetime intrinsic support is disabled (i.e. optimizations
|
|
|
|
/// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
|
2018-07-10 10:28:39 +00:00
|
|
|
fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: &'ll Value, size: Size) {
|
2018-01-05 05:04:08 +00:00
|
|
|
if self.cx.sess().opts.optimize == config::OptLevel::No {
|
2017-06-01 18:50:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let size = size.bytes();
|
|
|
|
if size == 0 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic);
|
2017-06-01 18:50:53 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let ptr = self.pointercast(ptr, Type::i8p(self.cx));
|
|
|
|
self.call(lifetime_intrinsic, &[C_u64(self.cx, size), ptr], None);
|
2017-06-01 18:50:53 +00:00
|
|
|
}
|
2016-04-20 23:43:01 +00:00
|
|
|
}
|