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