@@ -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. iter ( ) {
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,40 @@ 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- } ,
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+ assert ! (
206+ late,
207+ "input registers can only be used as lateout regisers"
199208 ) ;
200-
201- if is_target_supported && !clobbers. contains ( & reg_name) {
202- clobbers. push ( reg_name) ;
209+ ( "r" , dummy_output_type ( self . cx , reg. reg_class ( ) ) )
210+ } else {
211+ // `clobber_abi` can add lots of clobbers that are not supported by the target,
212+ // such as AVX-512 registers, so we just ignore unsupported registers
213+ let is_target_supported =
214+ reg. reg_class ( ) . supported_types ( asm_arch, true ) . iter ( ) . any (
215+ |& ( _, feature) | {
216+ if let Some ( feature) = feature {
217+ self . tcx
218+ . asm_target_features ( instance. def_id ( ) )
219+ . contains ( & feature)
220+ } else {
221+ true // Register class is unconditionally supported
222+ }
223+ } ,
224+ ) ;
225+
226+ if is_target_supported && !clobbers. contains ( & reg_name) {
227+ clobbers. push ( reg_name) ;
228+ }
229+ continue ;
203230 }
204- continue ;
205231 }
206232 } ;
207233
@@ -230,13 +256,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
230256 }
231257
232258 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- } ;
259+ let ConstraintOrRegister :: Constraint ( constraint) = reg_to_gcc ( reg) else {
260+ // left for the next pass
261+ continue ;
262+ } ;
240263
241264 // Rustc frontend guarantees that input and output types are "compatible",
242265 // so we can just use input var's type for the output variable.
0 commit comments