@@ -36,7 +36,8 @@ use crate::type_of::LayoutGccExt;
3636//
3737// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
3838// 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.
4041//
4142// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
4243// (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> {
161162 // Also, we don't emit any asm operands immediately; we save them to
162163 // the one of the buffers to be emitted later.
163164
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+
164175 // 1. Normal variables (and saving operands to buffers).
165176 for ( rust_idx, op) in rust_operands. iter ( ) . enumerate ( ) {
166177 match * op {
@@ -183,25 +194,39 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
183194 continue ;
184195 }
185196 ( 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 ;
203229 }
204- continue ;
205230 }
206231 } ;
207232
@@ -230,13 +255,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
230255 }
231256
232257 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+ } ;
240262
241263 // Rustc frontend guarantees that input and output types are "compatible",
242264 // so we can just use input var's type for the output variable.
0 commit comments