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.
|
|
|
|
|
2014-04-01 14:28:08 +00:00
|
|
|
#![allow(dead_code)] // FFI wrappers
|
|
|
|
|
2014-07-08 00:58:01 +00:00
|
|
|
use llvm;
|
2016-08-02 20:10:10 +00:00
|
|
|
use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
|
2015-10-24 01:18:44 +00:00
|
|
|
use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef};
|
2018-07-20 16:42:45 +00:00
|
|
|
use llvm::{ValueRef, BasicBlockRef, BuilderRef};
|
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};
|
2014-11-25 21:28:35 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
use std::borrow::Cow;
|
2014-11-25 21:28:35 +00:00
|
|
|
use std::ffi::CString;
|
2017-09-23 12:04:37 +00:00
|
|
|
use std::ops::Range;
|
2015-02-02 18:03:23 +00:00
|
|
|
use std::ptr;
|
2016-06-21 22:08:13 +00:00
|
|
|
use syntax_pos::Span;
|
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]
|
2014-04-22 12:56:37 +00:00
|
|
|
pub struct Builder<'a, 'tcx: 'a> {
|
2014-03-28 17:05:27 +00:00
|
|
|
pub llbuilder: BuilderRef,
|
2018-01-05 05:04:08 +00:00
|
|
|
pub cx: &'a CodegenCx<'a, 'tcx>,
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
|
2016-12-18 02:54:32 +00:00
|
|
|
impl<'a, 'tcx> Drop for Builder<'a, 'tcx> {
|
2016-12-17 00:39:35 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMDisposeBuilder(self.llbuilder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 12:56:37 +00:00
|
|
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
2018-01-05 05:04:08 +00:00
|
|
|
pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, 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 {
|
|
|
|
let name = CString::new(name).unwrap();
|
|
|
|
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-01-05 05:04:08 +00:00
|
|
|
pub fn with_cx(cx: &'a CodegenCx<'a, '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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-02 20:18:38 +00:00
|
|
|
pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, '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
|
|
|
}
|
|
|
|
|
2016-12-31 23:00:24 +00:00
|
|
|
pub fn llfn(&self) -> ValueRef {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMGetBasicBlockParent(self.llbb())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn llbb(&self) -> BasicBlockRef {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
pub fn set_value_name(&self, value: ValueRef, name: &str) {
|
|
|
|
let cname = CString::new(name.as_bytes()).unwrap();
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetValueName(value, cname.as_ptr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn position_before(&self, insn: ValueRef) {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMPositionBuilderBefore(self.llbuilder, insn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn position_at_end(&self, llbb: BasicBlockRef) {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-04 17:40:28 +00:00
|
|
|
pub fn position_at_start(&self, llbb: BasicBlockRef) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ret(&self, v: ValueRef) {
|
|
|
|
self.count_insn("ret");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildRet(self.llbuilder, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAggregateRet(self.llbuilder,
|
2013-12-15 12:35:12 +00:00
|
|
|
ret_vals.as_ptr(),
|
2013-07-21 13:33:40 +00:00
|
|
|
ret_vals.len() as c_uint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn br(&self, dest: BasicBlockRef) {
|
|
|
|
self.count_insn("br");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildBr(self.llbuilder, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) {
|
|
|
|
self.count_insn("condbr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: usize) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
pub fn indirect_br(&self, addr: ValueRef, num_dests: usize) {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("indirectbr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn invoke(&self,
|
|
|
|
llfn: ValueRef,
|
|
|
|
args: &[ValueRef],
|
|
|
|
then: BasicBlockRef,
|
2013-09-16 22:30:59 +00:00
|
|
|
catch: BasicBlockRef,
|
2016-04-20 06:10:40 +00:00
|
|
|
bundle: Option<&OperandBundleDef>) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("invoke");
|
2014-06-28 19:55:17 +00:00
|
|
|
|
2016-02-18 17:49:45 +00:00
|
|
|
debug!("Invoke {:?} with args ({})",
|
|
|
|
Value(llfn),
|
2014-06-28 19:55:17 +00:00
|
|
|
args.iter()
|
2016-02-18 17:49:45 +00:00
|
|
|
.map(|&v| format!("{:?}", Value(v)))
|
2014-06-28 19:55:17 +00:00
|
|
|
.collect::<Vec<String>>()
|
2015-07-10 12:19:21 +00:00
|
|
|
.join(", "));
|
2014-06-28 19:55:17 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
let args = self.check_call("invoke", llfn, args);
|
2016-06-24 18:54:52 +00:00
|
|
|
let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
|
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 */
|
|
|
|
pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("add");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("nswadd");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("nuwadd");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fadd");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 23:01:12 +00:00
|
|
|
pub fn fadd_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fadd");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("sub");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
2018-07-09 07:24:42 +00:00
|
|
|
self.count_insn("nswsub");
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("nuwsub");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 23:01:12 +00:00
|
|
|
pub fn fsub_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("mul");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("nswmul");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("nuwmul");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fmul");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 23:01:12 +00:00
|
|
|
pub fn fmul_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fmul");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("udiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
pub fn exactudiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("exactudiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("sdiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("exactsdiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fdiv");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 23:01:12 +00:00
|
|
|
pub fn fdiv_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fdiv");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("urem");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("srem");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("frem");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 23:01:12 +00:00
|
|
|
pub fn frem_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("frem");
|
|
|
|
unsafe {
|
|
|
|
let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname());
|
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("shl");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("lshr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("ashr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("and");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("or");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("xor");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef)
|
|
|
|
-> ValueRef {
|
|
|
|
self.count_insn("binop");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 21:15:03 +00:00
|
|
|
pub fn neg(&self, v: ValueRef) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 21:15:03 +00:00
|
|
|
pub fn nswneg(&self, v: ValueRef) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("nswneg");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildNSWNeg(self.llbuilder, v, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 21:15:03 +00:00
|
|
|
pub fn nuwneg(&self, v: ValueRef) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("nuwneg");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildNUWNeg(self.llbuilder, v, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-15 21:15:03 +00:00
|
|
|
pub fn fneg(&self, v: ValueRef) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 21:15:03 +00:00
|
|
|
pub fn not(&self, v: ValueRef) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-19 18:28:52 +00:00
|
|
|
pub fn alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
|
2017-11-19 18:28:52 +00:00
|
|
|
pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef {
|
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() {
|
2013-07-21 13:33:40 +00:00
|
|
|
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
|
|
|
|
} else {
|
2015-02-18 06:47:40 +00:00
|
|
|
let name = CString::new(name).unwrap();
|
2014-11-25 21:28:35 +00:00
|
|
|
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn free(&self, ptr: ValueRef) {
|
|
|
|
self.count_insn("free");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFree(self.llbuilder, ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 22:28:43 +00:00
|
|
|
pub fn load(&self, ptr: ValueRef, align: Align) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-28 14:01:53 +00:00
|
|
|
pub fn volatile_load(&self, ptr: ValueRef) -> ValueRef {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-01 18:50:53 +00:00
|
|
|
pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering, align: Align) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-23 12:04:37 +00:00
|
|
|
pub fn range_metadata(&self, load: ValueRef, range: Range<u128>) {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 12:04:37 +00:00
|
|
|
pub fn nonnull_metadata(&self, load: ValueRef) {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 22:28:43 +00:00
|
|
|
pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef {
|
2018-05-11 10:26:32 +00:00
|
|
|
self.store_with_flags(val, ptr, align, MemFlags::empty())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store_with_flags(
|
|
|
|
&self,
|
|
|
|
val: ValueRef,
|
|
|
|
ptr: ValueRef,
|
|
|
|
align: Align,
|
|
|
|
flags: MemFlags,
|
|
|
|
) -> ValueRef {
|
|
|
|
debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags);
|
2014-12-19 16:57:12 +00:00
|
|
|
assert!(!self.llbuilder.is_null());
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-01 18:50:53 +00:00
|
|
|
pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
|
|
|
|
order: AtomicOrdering, align: Align) {
|
2016-02-18 17:49:45 +00:00
|
|
|
debug!("Store {:?} -> {:?}", Value(val), Value(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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-25 09:41:24 +00:00
|
|
|
pub fn struct_gep(&self, ptr: ValueRef, idx: u64) -> ValueRef {
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:47:34 +00:00
|
|
|
pub fn global_string(&self, _str: *const c_char) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("globalstring");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildGlobalString(self.llbuilder, _str, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:47:34 +00:00
|
|
|
pub fn global_string_ptr(&self, _str: *const c_char) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("globalstringptr");
|
|
|
|
unsafe {
|
2014-02-15 21:15:03 +00:00
|
|
|
llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _str, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Casts */
|
|
|
|
pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("trunc");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("zext");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("sext");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("fptoui");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("fptosi");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("uitofp");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("sitofp");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("fptrunc");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("fpext");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("ptrtoint");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("inttoptr");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("bitcast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("zextorbitcast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("sextorbitcast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("truncorbitcast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("cast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("pointercast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 17:29:39 +00:00
|
|
|
pub fn intcast(&self, val: ValueRef, dest_ty: Type, is_signed: bool) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("intcast");
|
|
|
|
unsafe {
|
2017-02-10 17:29:39 +00:00
|
|
|
llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed)
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("fpcast");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Comparisons */
|
|
|
|
pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("icmp");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("fcmp");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Miscellaneous instructions */
|
|
|
|
pub fn empty_phi(&self, ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("emptyphi");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 16:13:04 +00:00
|
|
|
pub fn add_span_comment(&self, sp: Span, text: &str) {
|
2018-01-05 05:04:08 +00:00
|
|
|
if self.cx.sess().asm_comments() {
|
2014-05-16 17:45:16 +00:00
|
|
|
let s = format!("{} ({})",
|
|
|
|
text,
|
2018-01-05 05:04:08 +00:00
|
|
|
self.cx.sess().codemap().span_to_string(sp));
|
2017-03-24 08:31:26 +00:00
|
|
|
debug!("{}", s);
|
|
|
|
self.add_comment(&s);
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_comment(&self, text: &str) {
|
2018-01-05 05:04:08 +00:00
|
|
|
if self.cx.sess().asm_comments() {
|
2013-07-21 13:33:40 +00:00
|
|
|
let sanitized = text.replace("$", "");
|
2014-05-28 16:24:28 +00:00
|
|
|
let comment_text = format!("{} {}", "#",
|
|
|
|
sanitized.replace("\n", "\n\t# "));
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("inlineasm");
|
2015-02-18 06:47:40 +00:00
|
|
|
let comment_text = CString::new(comment_text).unwrap();
|
2014-11-25 21:28:35 +00:00
|
|
|
let asm = unsafe {
|
2018-01-05 05:04:08 +00:00
|
|
|
llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.cx)).to_ref(),
|
2014-11-25 21:28:35 +00:00
|
|
|
comment_text.as_ptr(), noname(), False,
|
|
|
|
False)
|
|
|
|
};
|
2016-02-25 23:10:40 +00:00
|
|
|
self.call(asm, &[], None);
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 19:47:34 +00:00
|
|
|
pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
|
2013-07-21 13:33:40 +00:00
|
|
|
inputs: &[ValueRef], output: Type,
|
|
|
|
volatile: bool, alignstack: bool,
|
|
|
|
dia: AsmDialect) -> ValueRef {
|
|
|
|
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| {
|
2016-02-18 17:49:45 +00:00
|
|
|
debug!("Asm Input Type: {:?}", Value(*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);
|
2015-02-18 19:48:57 +00:00
|
|
|
let fty = Type::func(&argtys[..], &output);
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
2016-08-01 23:35:09 +00:00
|
|
|
let v = llvm::LLVMRustInlineAsm(
|
2016-08-02 21:25:19 +00:00
|
|
|
fty.to_ref(), asm, cons, volatile, alignstack, dia);
|
2016-02-25 23:10:40 +00:00
|
|
|
self.call(v, inputs, None)
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-13 04:14:17 +00:00
|
|
|
pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
|
2016-02-25 23:10:40 +00:00
|
|
|
bundle: Option<&OperandBundleDef>) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("call");
|
2014-01-27 12:18:36 +00:00
|
|
|
|
2016-02-18 17:49:45 +00:00
|
|
|
debug!("Call {:?} with args ({})",
|
|
|
|
Value(llfn),
|
2014-03-28 19:42:34 +00:00
|
|
|
args.iter()
|
2016-02-18 17:49:45 +00:00
|
|
|
.map(|&v| format!("{:?}", Value(v)))
|
2014-05-22 23:57:53 +00:00
|
|
|
.collect::<Vec<String>>()
|
2015-07-10 12:19:21 +00:00
|
|
|
.join(", "));
|
2014-01-27 12:18:36 +00:00
|
|
|
|
2016-10-12 15:36:04 +00:00
|
|
|
let args = self.check_call("call", llfn, args);
|
2016-06-24 18:54:52 +00:00
|
|
|
let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
|
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-03-21 20:49:22 +00:00
|
|
|
pub fn minnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("minnum");
|
|
|
|
unsafe {
|
2018-03-22 13:48:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs);
|
2018-03-22 15:28:11 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0");
|
|
|
|
}
|
2018-03-22 13:48:58 +00:00
|
|
|
instr
|
2018-03-21 20:49:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn maxnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("maxnum");
|
|
|
|
unsafe {
|
2018-03-22 13:48:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs);
|
2018-03-22 15:28:11 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0");
|
|
|
|
}
|
2018-03-22 13:48:58 +00:00
|
|
|
instr
|
2018-03-21 20:49:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("select");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef {
|
|
|
|
self.count_insn("vaarg");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("extractelement");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("insertelement");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("shufflevector");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
pub fn vector_splat(&self, num_elts: usize, elt: ValueRef) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
unsafe {
|
|
|
|
let elt_ty = val_ty(elt);
|
2014-02-15 21:15:03 +00:00
|
|
|
let undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref());
|
2018-01-05 05:04:08 +00:00
|
|
|
let vec = self.insert_element(undef, elt, C_i32(self.cx, 0));
|
|
|
|
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-03-13 15:46:55 +00:00
|
|
|
pub fn vector_reduce_fadd_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef {
|
|
|
|
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-03-13 15:46:55 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src);
|
2018-03-15 15:51:58 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0");
|
|
|
|
}
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_fmul_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef {
|
|
|
|
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-03-13 15:46:55 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src);
|
2018-03-15 15:51:58 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0");
|
|
|
|
}
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_add(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.add");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_mul(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.mul");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_and(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.and");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_or(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.or");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_xor(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.xor");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-14 16:22:40 +00:00
|
|
|
pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef {
|
|
|
|
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-03-15 15:51:58 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-14 16:22:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef {
|
|
|
|
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-03-15 15:51:58 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-14 16:22:40 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-13 15:46:55 +00:00
|
|
|
pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.fmin_fast");
|
|
|
|
unsafe {
|
2018-03-21 09:32:53 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true);
|
2018-03-15 15:51:58 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
|
|
|
|
}
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_fmax_fast(&self, src: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.fmax_fast");
|
|
|
|
unsafe {
|
2018-03-21 09:32:53 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true);
|
2018-03-15 15:51:58 +00:00
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
|
|
|
|
}
|
2018-03-13 15:46:55 +00:00
|
|
|
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
|
|
|
instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_min(&self, src: ValueRef, is_signed: bool) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.min");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vector_reduce_max(&self, src: ValueRef, is_signed: bool) -> ValueRef {
|
|
|
|
self.count_insn("vector.reduce.max");
|
|
|
|
unsafe {
|
2018-03-15 15:51:58 +00:00
|
|
|
let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed);
|
|
|
|
if instr.is_null() {
|
|
|
|
bug!("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0");
|
|
|
|
}
|
|
|
|
instr
|
2018-03-13 15:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-25 09:41:24 +00:00
|
|
|
pub fn extract_value(&self, agg_val: ValueRef, idx: u64) -> ValueRef {
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
|
2017-06-25 09:41:24 +00:00
|
|
|
idx: u64) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_null(&self, val: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("isnull");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildIsNull(self.llbuilder, val, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_not_null(&self, val: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("isnotnull");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("ptrdiff");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-30 15:56:56 +00:00
|
|
|
pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef,
|
2017-12-08 09:53:46 +00:00
|
|
|
num_clauses: usize) -> ValueRef {
|
2013-07-21 13:33:40 +00:00
|
|
|
self.count_insn("landingpad");
|
|
|
|
unsafe {
|
2017-12-08 09:53:46 +00:00
|
|
|
llvm::LLVMBuildLandingPad(self.llbuilder, ty.to_ref(), pers_fn,
|
|
|
|
num_clauses as c_uint, noname())
|
2013-07-21 13:33:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-20 20:27:38 +00:00
|
|
|
pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMAddClause(landing_pad, clause);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 13:33:40 +00:00
|
|
|
pub fn set_cleanup(&self, landing_pad: ValueRef) {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn resume(&self, exn: ValueRef) -> ValueRef {
|
|
|
|
self.count_insn("resume");
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMBuildResume(self.llbuilder, exn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-24 01:18:44 +00:00
|
|
|
pub fn cleanup_pad(&self,
|
|
|
|
parent: Option<ValueRef>,
|
|
|
|
args: &[ValueRef]) -> ValueRef {
|
|
|
|
self.count_insn("cleanuppad");
|
2016-06-24 18:54:52 +00:00
|
|
|
let parent = parent.unwrap_or(ptr::null_mut());
|
2015-10-24 01:18:44 +00:00
|
|
|
let name = CString::new("cleanuppad").unwrap();
|
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCleanupPad(self.llbuilder,
|
|
|
|
parent,
|
|
|
|
args.len() as c_uint,
|
|
|
|
args.as_ptr(),
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
|
|
|
assert!(!ret.is_null(), "LLVM does not have support for cleanuppad");
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cleanup_ret(&self, cleanup: ValueRef,
|
|
|
|
unwind: Option<BasicBlockRef>) -> ValueRef {
|
|
|
|
self.count_insn("cleanupret");
|
2016-06-24 18:54:52 +00:00
|
|
|
let unwind = unwind.unwrap_or(ptr::null_mut());
|
2015-10-24 01:18:44 +00:00
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCleanupRet(self.llbuilder, cleanup, unwind)
|
|
|
|
};
|
|
|
|
assert!(!ret.is_null(), "LLVM does not have support for cleanupret");
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn catch_pad(&self,
|
|
|
|
parent: ValueRef,
|
|
|
|
args: &[ValueRef]) -> ValueRef {
|
|
|
|
self.count_insn("catchpad");
|
|
|
|
let name = CString::new("catchpad").unwrap();
|
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCatchPad(self.llbuilder, parent,
|
|
|
|
args.len() as c_uint, args.as_ptr(),
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
|
|
|
assert!(!ret.is_null(), "LLVM does not have support for catchpad");
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn catch_ret(&self, pad: ValueRef, unwind: BasicBlockRef) -> ValueRef {
|
|
|
|
self.count_insn("catchret");
|
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCatchRet(self.llbuilder, pad, unwind)
|
|
|
|
};
|
|
|
|
assert!(!ret.is_null(), "LLVM does not have support for catchret");
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn catch_switch(&self,
|
|
|
|
parent: Option<ValueRef>,
|
|
|
|
unwind: Option<BasicBlockRef>,
|
|
|
|
num_handlers: usize) -> ValueRef {
|
|
|
|
self.count_insn("catchswitch");
|
2016-06-24 18:54:52 +00:00
|
|
|
let parent = parent.unwrap_or(ptr::null_mut());
|
|
|
|
let unwind = unwind.unwrap_or(ptr::null_mut());
|
2015-10-24 01:18:44 +00:00
|
|
|
let name = CString::new("catchswitch").unwrap();
|
|
|
|
let ret = unsafe {
|
|
|
|
llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind,
|
|
|
|
num_handlers as c_uint,
|
|
|
|
name.as_ptr())
|
|
|
|
};
|
|
|
|
assert!(!ret.is_null(), "LLVM does not have support for catchswitch");
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_handler(&self, catch_switch: ValueRef, handler: BasicBlockRef) {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustAddHandler(catch_switch, handler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_personality_fn(&self, personality: ValueRef) {
|
|
|
|
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
|
|
|
|
pub fn atomic_cmpxchg(&self, dst: ValueRef,
|
|
|
|
cmp: ValueRef, src: ValueRef,
|
2014-03-31 21:43:19 +00:00
|
|
|
order: AtomicOrdering,
|
2016-01-16 23:40:11 +00:00
|
|
|
failure_order: AtomicOrdering,
|
|
|
|
weak: llvm::Bool) -> ValueRef {
|
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
|
|
|
}
|
|
|
|
}
|
2016-08-02 20:10:10 +00:00
|
|
|
pub fn atomic_rmw(&self, op: AtomicRmwBinOp,
|
2013-07-21 13:33:40 +00:00
|
|
|
dst: ValueRef, src: ValueRef,
|
|
|
|
order: AtomicOrdering) -> ValueRef {
|
|
|
|
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
|
|
|
|
2016-12-11 22:03:52 +00:00
|
|
|
pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
|
2016-12-11 15:59:20 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMAddCase(s, on_val, dest)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 22:03:52 +00:00
|
|
|
pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-21 08:08:06 +00:00
|
|
|
pub fn set_invariant_load(&self, load: ValueRef) {
|
|
|
|
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,
|
|
|
|
val: ValueRef,
|
|
|
|
ptr: ValueRef) -> ValueRef {
|
|
|
|
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,
|
|
|
|
llfn: ValueRef,
|
|
|
|
args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> {
|
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",
|
|
|
|
Value(llfn),
|
|
|
|
expected_ty, i, actual_ty);
|
|
|
|
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
|
|
|
|
|
|
|
pub fn lifetime_start(&self, ptr: ValueRef, size: Size) {
|
|
|
|
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lifetime_end(&self, ptr: ValueRef, size: Size) {
|
|
|
|
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`).
|
|
|
|
fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: ValueRef, 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
|
|
|
}
|