@@ -16,13 +16,15 @@ pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
1616use rustc_middle:: ty:: Ty ;
1717use rustc_session:: config;
1818pub use rustc_target:: abi:: call:: * ;
19- use rustc_target:: abi:: { self , HasDataLayout , Int } ;
19+ use rustc_target:: abi:: { self , HasDataLayout , Int , Size } ;
2020pub use rustc_target:: spec:: abi:: Abi ;
2121use rustc_target:: spec:: SanitizerSet ;
2222
2323use libc:: c_uint;
2424use smallvec:: SmallVec ;
2525
26+ use std:: cmp;
27+
2628pub trait ArgAttributesExt {
2729 fn apply_attrs_to_llfn ( & self , idx : AttributePlace , cx : & CodegenCx < ' _ , ' _ > , llfn : & Value ) ;
2830 fn apply_attrs_to_callsite (
@@ -130,42 +132,36 @@ impl LlvmType for Reg {
130132impl LlvmType for CastTarget {
131133 fn llvm_type < ' ll > ( & self , cx : & CodegenCx < ' ll , ' _ > ) -> & ' ll Type {
132134 let rest_ll_unit = self . rest . unit . llvm_type ( cx) ;
133- let ( rest_count, rem_bytes ) = if self . rest . unit . size . bytes ( ) == 0 {
134- ( 0 , 0 )
135+ let rest_count = if self . rest . total == Size :: ZERO {
136+ 0
135137 } else {
136- (
137- self . rest . total . bytes ( ) / self . rest . unit . size . bytes ( ) ,
138- self . rest . total . bytes ( ) % self . rest . unit . size . bytes ( ) ,
139- )
138+ assert_ne ! (
139+ self . rest. unit. size,
140+ Size :: ZERO ,
141+ "total size {:?} cannot be divided into units of zero size" ,
142+ self . rest. total
143+ ) ;
144+ if self . rest . total . bytes ( ) % self . rest . unit . size . bytes ( ) != 0 {
145+ assert_eq ! ( self . rest. unit. kind, RegKind :: Integer , "only int regs can be split" ) ;
146+ }
147+ self . rest . total . bytes ( ) . div_ceil ( self . rest . unit . size . bytes ( ) )
140148 } ;
141149
150+ // Simplify to a single unit or an array if there's no prefix.
151+ // This produces the same layout, but using a simpler type.
142152 if self . prefix . iter ( ) . all ( |x| x. is_none ( ) ) {
143- // Simplify to a single unit when there is no prefix and size <= unit size
144- if self . rest . total <= self . rest . unit . size {
153+ if rest_count == 1 {
145154 return rest_ll_unit;
146155 }
147156
148- // Simplify to array when all chunks are the same size and type
149- if rem_bytes == 0 {
150- return cx. type_array ( rest_ll_unit, rest_count) ;
151- }
152- }
153-
154- // Create list of fields in the main structure
155- let mut args: Vec < _ > = self
156- . prefix
157- . iter ( )
158- . flat_map ( |option_reg| option_reg. map ( |reg| reg. llvm_type ( cx) ) )
159- . chain ( ( 0 ..rest_count) . map ( |_| rest_ll_unit) )
160- . collect ( ) ;
161-
162- // Append final integer
163- if rem_bytes != 0 {
164- // Only integers can be really split further.
165- assert_eq ! ( self . rest. unit. kind, RegKind :: Integer ) ;
166- args. push ( cx. type_ix ( rem_bytes * 8 ) ) ;
157+ return cx. type_array ( rest_ll_unit, rest_count) ;
167158 }
168159
160+ // Generate a struct type with the prefix and the "rest" arguments.
161+ let prefix_args =
162+ self . prefix . iter ( ) . flat_map ( |option_reg| option_reg. map ( |reg| reg. llvm_type ( cx) ) ) ;
163+ let rest_args = ( 0 ..rest_count) . map ( |_| rest_ll_unit) ;
164+ let args: Vec < _ > = prefix_args. chain ( rest_args) . collect ( ) ;
169165 cx. type_struct ( & args, false )
170166 }
171167}
0 commit comments