1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use llvm;
use common::*;
use type_::Type;
use type_of::LayoutLlvmExt;
use builder::Builder;
use value::Value;
use rustc::hir;
use mir::place::PlaceRef;
use mir::operand::OperandValue;
use std::ffi::CString;
use syntax::ast::AsmDialect;
use libc::{c_uint, c_char};
pub fn codegen_inline_asm(
bx: &Builder<'a, 'll, 'tcx>,
ia: &hir::InlineAsm,
outputs: Vec<PlaceRef<'ll, 'tcx>>,
mut inputs: Vec<&'ll Value>
) {
let mut ext_constraints = vec![];
let mut output_types = vec![];
let mut indirect_outputs = vec![];
for (i, (out, place)) in ia.outputs.iter().zip(&outputs).enumerate() {
if out.is_rw {
inputs.push(place.load(bx).immediate());
ext_constraints.push(i.to_string());
}
if out.is_indirect {
indirect_outputs.push(place.load(bx).immediate());
} else {
output_types.push(place.layout.llvm_type(bx.cx));
}
}
if !indirect_outputs.is_empty() {
indirect_outputs.extend_from_slice(&inputs);
inputs = indirect_outputs;
}
let clobbers = ia.clobbers.iter()
.map(|s| format!("~{{{}}}", &s));
let arch_clobbers = match &bx.sess().target.target.arch[..] {
"x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
"mips" | "mips64" => vec!["~{$1}"],
_ => Vec::new()
};
let all_constraints =
ia.outputs.iter().map(|out| out.constraint.to_string())
.chain(ia.inputs.iter().map(|s| s.to_string()))
.chain(ext_constraints)
.chain(clobbers)
.chain(arch_clobbers.iter().map(|s| s.to_string()))
.collect::<Vec<String>>().join(",");
debug!("Asm Constraints: {}", &all_constraints);
let num_outputs = output_types.len();
let output_type = match num_outputs {
0 => Type::void(bx.cx),
1 => output_types[0],
_ => Type::struct_(bx.cx, &output_types, false)
};
let dialect = match ia.dialect {
AsmDialect::Att => llvm::AsmDialect::Att,
AsmDialect::Intel => llvm::AsmDialect::Intel,
};
let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap();
let constraint_cstr = CString::new(all_constraints).unwrap();
let r = bx.inline_asm_call(
asm.as_ptr(),
constraint_cstr.as_ptr(),
&inputs,
output_type,
ia.volatile,
ia.alignstack,
dialect
);
let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
for (i, (_, &place)) in outputs.enumerate() {
let v = if num_outputs == 1 { r } else { bx.extract_value(r, i as u64) };
OperandValue::Immediate(v).store(bx, place);
}
unsafe {
let key = "srcloc";
let kind = llvm::LLVMGetMDKindIDInContext(bx.cx.llcx,
key.as_ptr() as *const c_char, key.len() as c_uint);
let val: &'ll Value = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32);
llvm::LLVMSetMetadata(r, kind,
llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
}
}
pub fn codegen_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
ga: &hir::GlobalAsm) {
let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap();
unsafe {
llvm::LLVMRustAppendModuleInlineAsm(cx.llmod, asm.as_ptr());
}
}