]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::builder::Builder; |
9fa01778 | 2 | use crate::context::CodegenCx; |
dfeec247 | 3 | use crate::llvm; |
9fa01778 | 4 | use crate::type_of::LayoutLlvmExt; |
9fa01778 | 5 | use crate::value::Value; |
54a0048b | 6 | |
a1dfa0c6 | 7 | use rustc_codegen_ssa::mir::operand::OperandValue; |
dfeec247 XL |
8 | use rustc_codegen_ssa::mir::place::PlaceRef; |
9 | use rustc_codegen_ssa::traits::*; | |
10 | use rustc_hir as hir; | |
11 | use rustc_span::Span; | |
32a655c1 | 12 | |
dfeec247 | 13 | use libc::{c_char, c_uint}; |
60c5eb7d | 14 | use log::debug; |
dfeec247 | 15 | use std::ffi::{CStr, CString}; |
a1dfa0c6 XL |
16 | |
17 | impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { | |
18 | fn codegen_inline_asm( | |
19 | &mut self, | |
60c5eb7d | 20 | ia: &hir::InlineAsmInner, |
a1dfa0c6 | 21 | outputs: Vec<PlaceRef<'tcx, &'ll Value>>, |
e1599b0c XL |
22 | mut inputs: Vec<&'ll Value>, |
23 | span: Span, | |
a1dfa0c6 XL |
24 | ) -> bool { |
25 | let mut ext_constraints = vec![]; | |
26 | let mut output_types = vec![]; | |
27 | ||
28 | // Prepare the output operands | |
29 | let mut indirect_outputs = vec![]; | |
30 | for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() { | |
31 | if out.is_rw { | |
32 | inputs.push(self.load_operand(place).immediate()); | |
33 | ext_constraints.push(i.to_string()); | |
34 | } | |
35 | if out.is_indirect { | |
36 | indirect_outputs.push(self.load_operand(place).immediate()); | |
37 | } else { | |
38 | output_types.push(place.layout.llvm_type(self.cx())); | |
39 | } | |
54a0048b | 40 | } |
a1dfa0c6 XL |
41 | if !indirect_outputs.is_empty() { |
42 | indirect_outputs.extend_from_slice(&inputs); | |
43 | inputs = indirect_outputs; | |
54a0048b | 44 | } |
54a0048b | 45 | |
dfeec247 | 46 | let clobbers = ia.clobbers.iter().map(|s| format!("~{{{}}}", &s)); |
a1dfa0c6 XL |
47 | |
48 | // Default per-arch clobbers | |
49 | // Basically what clang does | |
50 | let arch_clobbers = match &self.sess().target.target.arch[..] { | |
dfeec247 | 51 | "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], |
a1dfa0c6 | 52 | "mips" | "mips64" => vec!["~{$1}"], |
dfeec247 | 53 | _ => Vec::new(), |
a1dfa0c6 XL |
54 | }; |
55 | ||
dfeec247 XL |
56 | let all_constraints = ia |
57 | .outputs | |
58 | .iter() | |
59 | .map(|out| out.constraint.to_string()) | |
60 | .chain(ia.inputs.iter().map(|s| s.to_string())) | |
61 | .chain(ext_constraints) | |
62 | .chain(clobbers) | |
63 | .chain(arch_clobbers.iter().map(|s| s.to_string())) | |
64 | .collect::<Vec<String>>() | |
65 | .join(","); | |
a1dfa0c6 XL |
66 | |
67 | debug!("Asm Constraints: {}", &all_constraints); | |
68 | ||
69 | // Depending on how many outputs we have, the return type is different | |
70 | let num_outputs = output_types.len(); | |
71 | let output_type = match num_outputs { | |
72 | 0 => self.type_void(), | |
73 | 1 => output_types[0], | |
dfeec247 | 74 | _ => self.type_struct(&output_types, false), |
a1dfa0c6 XL |
75 | }; |
76 | ||
77 | let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap(); | |
78 | let constraint_cstr = CString::new(all_constraints).unwrap(); | |
532ac7d7 XL |
79 | let r = inline_asm_call( |
80 | self, | |
a1dfa0c6 XL |
81 | &asm, |
82 | &constraint_cstr, | |
83 | &inputs, | |
84 | output_type, | |
85 | ia.volatile, | |
86 | ia.alignstack, | |
dfeec247 | 87 | ia.dialect, |
a1dfa0c6 XL |
88 | ); |
89 | if r.is_none() { | |
90 | return false; | |
91 | } | |
92 | let r = r.unwrap(); | |
54a0048b | 93 | |
a1dfa0c6 XL |
94 | // Again, based on how many outputs we have |
95 | let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect); | |
96 | for (i, (_, &place)) in outputs.enumerate() { | |
97 | let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) }; | |
98 | OperandValue::Immediate(v).store(self, place); | |
99 | } | |
54a0048b | 100 | |
a1dfa0c6 XL |
101 | // Store mark in a metadata node so we can map LLVM errors |
102 | // back to source locations. See #17552. | |
103 | unsafe { | |
104 | let key = "srcloc"; | |
dfeec247 XL |
105 | let kind = llvm::LLVMGetMDKindIDInContext( |
106 | self.llcx, | |
107 | key.as_ptr() as *const c_char, | |
108 | key.len() as c_uint, | |
109 | ); | |
54a0048b | 110 | |
e1599b0c | 111 | let val: &'ll Value = self.const_i32(span.ctxt().outer_expn().as_u32() as i32); |
54a0048b | 112 | |
dfeec247 | 113 | llvm::LLVMSetMetadata(r, kind, llvm::LLVMMDNodeInContext(self.llcx, &val, 1)); |
a1dfa0c6 | 114 | } |
0bf4aa26 | 115 | |
a1dfa0c6 XL |
116 | true |
117 | } | |
54a0048b | 118 | } |
cc61c64b | 119 | |
dc9dc135 | 120 | impl AsmMethods for CodegenCx<'ll, 'tcx> { |
a1dfa0c6 XL |
121 | fn codegen_global_asm(&self, ga: &hir::GlobalAsm) { |
122 | let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); | |
123 | unsafe { | |
124 | llvm::LLVMRustAppendModuleInlineAsm(self.llmod, asm.as_ptr()); | |
125 | } | |
cc61c64b XL |
126 | } |
127 | } | |
532ac7d7 XL |
128 | |
129 | fn inline_asm_call( | |
130 | bx: &mut Builder<'a, 'll, 'tcx>, | |
131 | asm: &CStr, | |
132 | cons: &CStr, | |
133 | inputs: &[&'ll Value], | |
134 | output: &'ll llvm::Type, | |
135 | volatile: bool, | |
136 | alignstack: bool, | |
137 | dia: ::syntax::ast::AsmDialect, | |
138 | ) -> Option<&'ll Value> { | |
dfeec247 XL |
139 | let volatile = if volatile { llvm::True } else { llvm::False }; |
140 | let alignstack = if alignstack { llvm::True } else { llvm::False }; | |
141 | ||
142 | let argtys = inputs | |
143 | .iter() | |
144 | .map(|v| { | |
145 | debug!("Asm Input Type: {:?}", *v); | |
146 | bx.cx.val_ty(*v) | |
147 | }) | |
148 | .collect::<Vec<_>>(); | |
532ac7d7 XL |
149 | |
150 | debug!("Asm Output Type: {:?}", output); | |
151 | let fty = bx.cx.type_func(&argtys[..], output); | |
152 | unsafe { | |
153 | // Ask LLVM to verify that the constraints are well-formed. | |
154 | let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr()); | |
416331ca | 155 | debug!("constraint verification result: {:?}", constraints_ok); |
532ac7d7 XL |
156 | if constraints_ok { |
157 | let v = llvm::LLVMRustInlineAsm( | |
158 | fty, | |
159 | asm.as_ptr(), | |
160 | cons.as_ptr(), | |
161 | volatile, | |
162 | alignstack, | |
163 | llvm::AsmDialect::from_generic(dia), | |
164 | ); | |
165 | Some(bx.call(v, inputs, None)) | |
166 | } else { | |
167 | // LLVM has detected an issue with our constraints, bail out | |
168 | None | |
169 | } | |
170 | } | |
171 | } |