@@ -36,7 +36,8 @@ use crate::type_of::LayoutGccExt;
36
36
//
37
37
// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
38
38
// Contrary, Rust expresses clobbers through "out" operands that aren't tied to
39
- // a variable (`_`), and such "clobbers" do have index.
39
+ // a variable (`_`), and such "clobbers" do have index. Input operands cannot also
40
+ // be clobbered.
40
41
//
41
42
// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
42
43
// (like `out("eax")`) directly, offering so-called "local register variables"
@@ -161,6 +162,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
161
162
// Also, we don't emit any asm operands immediately; we save them to
162
163
// the one of the buffers to be emitted later.
163
164
165
+ let mut input_registers = vec ! [ ] ;
166
+
167
+ for op in rust_operands {
168
+ if let InlineAsmOperandRef :: In { reg, .. } = * op {
169
+ if let ConstraintOrRegister :: Register ( reg_name) = reg_to_gcc ( reg) {
170
+ input_registers. push ( reg_name) ;
171
+ }
172
+ }
173
+ }
174
+
164
175
// 1. Normal variables (and saving operands to buffers).
165
176
for ( rust_idx, op) in rust_operands. iter ( ) . enumerate ( ) {
166
177
match * op {
@@ -183,25 +194,39 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
183
194
continue ;
184
195
}
185
196
( Register ( reg_name) , None ) => {
186
- // `clobber_abi` can add lots of clobbers that are not supported by the target,
187
- // such as AVX-512 registers, so we just ignore unsupported registers
188
- let is_target_supported =
189
- reg. reg_class ( ) . supported_types ( asm_arch, true ) . iter ( ) . any (
190
- |& ( _, feature) | {
191
- if let Some ( feature) = feature {
192
- self . tcx
193
- . asm_target_features ( instance. def_id ( ) )
194
- . contains ( & feature)
195
- } else {
196
- true // Register class is unconditionally supported
197
- }
198
- } ,
199
- ) ;
200
-
201
- if is_target_supported && !clobbers. contains ( & reg_name) {
202
- clobbers. push ( reg_name) ;
197
+ if input_registers. contains ( & reg_name) {
198
+ // the `clobber_abi` operand is converted into a series of
199
+ // `lateout("reg") _` operands. Of course, a user could also
200
+ // explicitly define such an output operand.
201
+ //
202
+ // GCC does not allow input registers to be clobbered, so if this out register
203
+ // is also used as an in register, do not add it to the clobbers list.
204
+ // it will be treated as a lateout register with `out_place: None`
205
+ if !late {
206
+ bug ! ( "input registers can only be used as lateout regisers" ) ;
207
+ }
208
+ ( "r" , dummy_output_type ( self . cx , reg. reg_class ( ) ) )
209
+ } else {
210
+ // `clobber_abi` can add lots of clobbers that are not supported by the target,
211
+ // such as AVX-512 registers, so we just ignore unsupported registers
212
+ let is_target_supported =
213
+ reg. reg_class ( ) . supported_types ( asm_arch, true ) . iter ( ) . any (
214
+ |& ( _, feature) | {
215
+ if let Some ( feature) = feature {
216
+ self . tcx
217
+ . asm_target_features ( instance. def_id ( ) )
218
+ . contains ( & feature)
219
+ } else {
220
+ true // Register class is unconditionally supported
221
+ }
222
+ } ,
223
+ ) ;
224
+
225
+ if is_target_supported && !clobbers. contains ( & reg_name) {
226
+ clobbers. push ( reg_name) ;
227
+ }
228
+ continue ;
203
229
}
204
- continue ;
205
230
}
206
231
} ;
207
232
@@ -230,13 +255,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
230
255
}
231
256
232
257
InlineAsmOperandRef :: InOut { reg, late, in_value, out_place } => {
233
- let constraint =
234
- if let ConstraintOrRegister :: Constraint ( constraint) = reg_to_gcc ( reg) {
235
- constraint
236
- } else {
237
- // left for the next pass
238
- continue ;
239
- } ;
258
+ let ConstraintOrRegister :: Constraint ( constraint) = reg_to_gcc ( reg) else {
259
+ // left for the next pass
260
+ continue ;
261
+ } ;
240
262
241
263
// Rustc frontend guarantees that input and output types are "compatible",
242
264
// so we can just use input var's type for the output variable.
0 commit comments