@@ -130,7 +130,9 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
130
130
for ( idx, op) in operands. iter ( ) . enumerate ( ) {
131
131
match * op {
132
132
InlineAsmOperandRef :: Out { reg, late, place } => {
133
- let ty = if let Some ( place) = place {
133
+ let mut layout = None ;
134
+ let ty = if let Some ( ref place) = place {
135
+ layout = Some ( & place. layout ) ;
134
136
llvm_fixup_output_type ( self . cx , reg. reg_class ( ) , & place. layout )
135
137
} else {
136
138
// If the output is discarded, we don't really care what
@@ -141,20 +143,21 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
141
143
output_types. push ( ty) ;
142
144
op_idx. insert ( idx, constraints. len ( ) ) ;
143
145
let prefix = if late { "=" } else { "=&" } ;
144
- constraints. push ( format ! ( "{}{}" , prefix, reg_to_llvm( reg) ) ) ;
146
+ constraints. push ( format ! ( "{}{}" , prefix, reg_to_llvm( reg, layout ) ) ) ;
145
147
}
146
148
InlineAsmOperandRef :: InOut { reg, late, in_value, out_place } => {
147
- let ty = if let Some ( ref out_place) = out_place {
148
- llvm_fixup_output_type ( self . cx , reg . reg_class ( ) , & out_place. layout )
149
+ let layout = if let Some ( ref out_place) = out_place {
150
+ & out_place. layout
149
151
} else {
150
152
// LLVM required tied operands to have the same type,
151
153
// so we just use the type of the input.
152
- llvm_fixup_output_type ( self . cx , reg . reg_class ( ) , & in_value. layout )
154
+ & in_value. layout
153
155
} ;
156
+ let ty = llvm_fixup_output_type ( self . cx , reg. reg_class ( ) , layout) ;
154
157
output_types. push ( ty) ;
155
158
op_idx. insert ( idx, constraints. len ( ) ) ;
156
159
let prefix = if late { "=" } else { "=&" } ;
157
- constraints. push ( format ! ( "{}{}" , prefix, reg_to_llvm( reg) ) ) ;
160
+ constraints. push ( format ! ( "{}{}" , prefix, reg_to_llvm( reg, Some ( layout ) ) ) ) ;
158
161
}
159
162
_ => { }
160
163
}
@@ -165,11 +168,11 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
165
168
for ( idx, op) in operands. iter ( ) . enumerate ( ) {
166
169
match * op {
167
170
InlineAsmOperandRef :: In { reg, value } => {
168
- let value =
171
+ let llval =
169
172
llvm_fixup_input ( self , value. immediate ( ) , reg. reg_class ( ) , & value. layout ) ;
170
- inputs. push ( value ) ;
173
+ inputs. push ( llval ) ;
171
174
op_idx. insert ( idx, constraints. len ( ) ) ;
172
- constraints. push ( reg_to_llvm ( reg) ) ;
175
+ constraints. push ( reg_to_llvm ( reg, Some ( & value . layout ) ) ) ;
173
176
}
174
177
InlineAsmOperandRef :: InOut { reg, late : _, in_value, out_place : _ } => {
175
178
let value = llvm_fixup_input (
@@ -410,10 +413,80 @@ fn inline_asm_call(
410
413
}
411
414
}
412
415
416
+ /// If the register is an xmm/ymm/zmm register then return its index.
417
+ fn xmm_reg_index ( reg : InlineAsmReg ) -> Option < u32 > {
418
+ match reg {
419
+ InlineAsmReg :: X86 ( reg)
420
+ if reg as u32 >= X86InlineAsmReg :: xmm0 as u32
421
+ && reg as u32 <= X86InlineAsmReg :: xmm15 as u32 =>
422
+ {
423
+ Some ( reg as u32 - X86InlineAsmReg :: xmm0 as u32 )
424
+ }
425
+ InlineAsmReg :: X86 ( reg)
426
+ if reg as u32 >= X86InlineAsmReg :: ymm0 as u32
427
+ && reg as u32 <= X86InlineAsmReg :: ymm15 as u32 =>
428
+ {
429
+ Some ( reg as u32 - X86InlineAsmReg :: ymm0 as u32 )
430
+ }
431
+ InlineAsmReg :: X86 ( reg)
432
+ if reg as u32 >= X86InlineAsmReg :: zmm0 as u32
433
+ && reg as u32 <= X86InlineAsmReg :: zmm31 as u32 =>
434
+ {
435
+ Some ( reg as u32 - X86InlineAsmReg :: zmm0 as u32 )
436
+ }
437
+ _ => None ,
438
+ }
439
+ }
440
+
441
+ /// If the register is an AArch64 vector register then return its index.
442
+ fn a64_vreg_index ( reg : InlineAsmReg ) -> Option < u32 > {
443
+ match reg {
444
+ InlineAsmReg :: AArch64 ( reg)
445
+ if reg as u32 >= AArch64InlineAsmReg :: v0 as u32
446
+ && reg as u32 <= AArch64InlineAsmReg :: v31 as u32 =>
447
+ {
448
+ Some ( reg as u32 - AArch64InlineAsmReg :: v0 as u32 )
449
+ }
450
+ _ => None ,
451
+ }
452
+ }
453
+
413
454
/// Converts a register class to an LLVM constraint code.
414
- fn reg_to_llvm ( reg : InlineAsmRegOrRegClass ) -> String {
455
+ fn reg_to_llvm ( reg : InlineAsmRegOrRegClass , layout : Option < & TyAndLayout < ' tcx > > ) -> String {
415
456
match reg {
416
- InlineAsmRegOrRegClass :: Reg ( reg) => format ! ( "{{{}}}" , reg. name( ) ) ,
457
+ // For vector registers LLVM wants the register name to match the type size.
458
+ InlineAsmRegOrRegClass :: Reg ( reg) => {
459
+ if let Some ( idx) = xmm_reg_index ( reg) {
460
+ let class = if let Some ( layout) = layout {
461
+ match layout. size . bytes ( ) {
462
+ 64 => 'z' ,
463
+ 32 => 'y' ,
464
+ _ => 'x' ,
465
+ }
466
+ } else {
467
+ // We use f32 as the type for discarded outputs
468
+ 'x'
469
+ } ;
470
+ format ! ( "{{{}mm{}}}" , class, idx)
471
+ } else if let Some ( idx) = a64_vreg_index ( reg) {
472
+ let class = if let Some ( layout) = layout {
473
+ match layout. size . bytes ( ) {
474
+ 16 => 'q' ,
475
+ 8 => 'd' ,
476
+ 4 => 's' ,
477
+ 2 => 'h' ,
478
+ 1 => 'd' , // We fixup i8 to i8x8
479
+ _ => unreachable ! ( ) ,
480
+ }
481
+ } else {
482
+ // We use i32 as the type for discarded outputs
483
+ 's'
484
+ } ;
485
+ format ! ( "{{{}{}}}" , class, idx)
486
+ } else {
487
+ format ! ( "{{{}}}" , reg. name( ) )
488
+ }
489
+ }
417
490
InlineAsmRegOrRegClass :: RegClass ( reg) => match reg {
418
491
InlineAsmRegClass :: AArch64 ( AArch64InlineAsmRegClass :: reg) => "r" ,
419
492
InlineAsmRegClass :: AArch64 ( AArch64InlineAsmRegClass :: vreg) => "w" ,
@@ -600,18 +673,26 @@ fn llvm_fixup_input(
600
673
InlineAsmRegClass :: X86 ( X86InlineAsmRegClass :: xmm_reg | X86InlineAsmRegClass :: zmm_reg) ,
601
674
Abi :: Vector { .. } ,
602
675
) if layout. size . bytes ( ) == 64 => bx. bitcast ( value, bx. cx . type_vector ( bx. cx . type_f64 ( ) , 8 ) ) ,
676
+ (
677
+ InlineAsmRegClass :: Arm ( ArmInlineAsmRegClass :: sreg | ArmInlineAsmRegClass :: sreg_low16) ,
678
+ Abi :: Scalar ( s) ,
679
+ ) => {
680
+ if let Primitive :: Int ( Integer :: I32 , _) = s. value {
681
+ bx. bitcast ( value, bx. cx . type_f32 ( ) )
682
+ } else {
683
+ value
684
+ }
685
+ }
603
686
(
604
687
InlineAsmRegClass :: Arm (
605
- ArmInlineAsmRegClass :: sreg_low16
688
+ ArmInlineAsmRegClass :: dreg
606
689
| ArmInlineAsmRegClass :: dreg_low8
607
- | ArmInlineAsmRegClass :: qreg_low4
608
- | ArmInlineAsmRegClass :: dreg
609
- | ArmInlineAsmRegClass :: qreg,
690
+ | ArmInlineAsmRegClass :: dreg_low16,
610
691
) ,
611
692
Abi :: Scalar ( s) ,
612
693
) => {
613
- if let Primitive :: Int ( Integer :: I32 , _) = s. value {
614
- bx. bitcast ( value, bx. cx . type_f32 ( ) )
694
+ if let Primitive :: Int ( Integer :: I64 , _) = s. value {
695
+ bx. bitcast ( value, bx. cx . type_f64 ( ) )
615
696
} else {
616
697
value
617
698
}
@@ -660,18 +741,26 @@ fn llvm_fixup_output(
660
741
InlineAsmRegClass :: X86 ( X86InlineAsmRegClass :: xmm_reg | X86InlineAsmRegClass :: zmm_reg) ,
661
742
Abi :: Vector { .. } ,
662
743
) if layout. size . bytes ( ) == 64 => bx. bitcast ( value, layout. llvm_type ( bx. cx ) ) ,
744
+ (
745
+ InlineAsmRegClass :: Arm ( ArmInlineAsmRegClass :: sreg | ArmInlineAsmRegClass :: sreg_low16) ,
746
+ Abi :: Scalar ( s) ,
747
+ ) => {
748
+ if let Primitive :: Int ( Integer :: I32 , _) = s. value {
749
+ bx. bitcast ( value, bx. cx . type_i32 ( ) )
750
+ } else {
751
+ value
752
+ }
753
+ }
663
754
(
664
755
InlineAsmRegClass :: Arm (
665
- ArmInlineAsmRegClass :: sreg_low16
756
+ ArmInlineAsmRegClass :: dreg
666
757
| ArmInlineAsmRegClass :: dreg_low8
667
- | ArmInlineAsmRegClass :: qreg_low4
668
- | ArmInlineAsmRegClass :: dreg
669
- | ArmInlineAsmRegClass :: qreg,
758
+ | ArmInlineAsmRegClass :: dreg_low16,
670
759
) ,
671
760
Abi :: Scalar ( s) ,
672
761
) => {
673
- if let Primitive :: Int ( Integer :: I32 , _) = s. value {
674
- bx. bitcast ( value, bx. cx . type_i32 ( ) )
762
+ if let Primitive :: Int ( Integer :: I64 , _) = s. value {
763
+ bx. bitcast ( value, bx. cx . type_i64 ( ) )
675
764
} else {
676
765
value
677
766
}
@@ -715,18 +804,26 @@ fn llvm_fixup_output_type(
715
804
InlineAsmRegClass :: X86 ( X86InlineAsmRegClass :: xmm_reg | X86InlineAsmRegClass :: zmm_reg) ,
716
805
Abi :: Vector { .. } ,
717
806
) if layout. size . bytes ( ) == 64 => cx. type_vector ( cx. type_f64 ( ) , 8 ) ,
807
+ (
808
+ InlineAsmRegClass :: Arm ( ArmInlineAsmRegClass :: sreg | ArmInlineAsmRegClass :: sreg_low16) ,
809
+ Abi :: Scalar ( s) ,
810
+ ) => {
811
+ if let Primitive :: Int ( Integer :: I32 , _) = s. value {
812
+ cx. type_f32 ( )
813
+ } else {
814
+ layout. llvm_type ( cx)
815
+ }
816
+ }
718
817
(
719
818
InlineAsmRegClass :: Arm (
720
- ArmInlineAsmRegClass :: sreg_low16
819
+ ArmInlineAsmRegClass :: dreg
721
820
| ArmInlineAsmRegClass :: dreg_low8
722
- | ArmInlineAsmRegClass :: qreg_low4
723
- | ArmInlineAsmRegClass :: dreg
724
- | ArmInlineAsmRegClass :: qreg,
821
+ | ArmInlineAsmRegClass :: dreg_low16,
725
822
) ,
726
823
Abi :: Scalar ( s) ,
727
824
) => {
728
- if let Primitive :: Int ( Integer :: I32 , _) = s. value {
729
- cx. type_f32 ( )
825
+ if let Primitive :: Int ( Integer :: I64 , _) = s. value {
826
+ cx. type_f64 ( )
730
827
} else {
731
828
layout. llvm_type ( cx)
732
829
}
0 commit comments