@@ -67,9 +67,14 @@ pub enum OperandValue<V> {
6767 /// `is_zst` on its `Layout` returns `true`. Note however that
6868 /// these values can still require alignment.
6969 ZeroSized ,
70+ Uninit ,
7071}
7172
7273impl < V : CodegenObject > OperandValue < V > {
74+ pub ( crate ) fn is_uninit ( & self ) -> bool {
75+ matches ! ( self , OperandValue :: Uninit )
76+ }
77+
7378 /// Treat this value as a pointer and return the data pointer and
7479 /// optional metadata as backend values.
7580 ///
@@ -100,6 +105,7 @@ impl<V: CodegenObject> OperandValue<V> {
100105 ty : TyAndLayout < ' tcx > ,
101106 ) -> bool {
102107 match self {
108+ OperandValue :: Uninit => true ,
103109 OperandValue :: ZeroSized => ty. is_zst ( ) ,
104110 OperandValue :: Immediate ( _) => cx. is_backend_immediate ( ty) ,
105111 OperandValue :: Pair ( _, _) => cx. is_backend_scalar_pair ( ty) ,
@@ -144,6 +150,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
144150 ) -> Self {
145151 let layout = bx. layout_of ( ty) ;
146152
153+ if val. all_bytes_uninit ( bx. tcx ( ) ) {
154+ return OperandRef { val : OperandValue :: Uninit , layout } ;
155+ }
156+
147157 let val = match val {
148158 ConstValue :: Scalar ( x) => {
149159 let BackendRepr :: Scalar ( scalar) = layout. backend_repr else {
@@ -442,6 +452,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
442452
443453 // Read the tag/niche-encoded discriminant from memory.
444454 let tag_op = match self . val {
455+ OperandValue :: Uninit => bug ! ( "shouldn't load from uninit" ) ,
445456 OperandValue :: ZeroSized => bug ! ( ) ,
446457 OperandValue :: Immediate ( _) | OperandValue :: Pair ( _, _) => {
447458 self . extract_field ( fx, bx, tag_field. as_usize ( ) )
@@ -591,6 +602,28 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
591602}
592603
593604impl < ' a , ' tcx , V : CodegenObject > OperandRef < ' tcx , Result < V , abi:: Scalar > > {
605+ fn update_uninit < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
606+ bx : & mut Bx ,
607+ tgt : & mut Result < V , abi:: Scalar > ,
608+ ) {
609+ let to_scalar = tgt. unwrap_err ( ) ;
610+ let bty = bx. cx ( ) . type_from_scalar ( to_scalar) ;
611+ * tgt = Ok ( bx. const_undef ( bty) ) ;
612+ }
613+
614+ fn update < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
615+ bx : & mut Bx ,
616+ tgt : & mut Result < V , abi:: Scalar > ,
617+ src : V ,
618+ from_scalar : rustc_abi:: Scalar ,
619+ ) {
620+ let from_bty = bx. cx ( ) . type_from_scalar ( from_scalar) ;
621+ let to_scalar = tgt. unwrap_err ( ) ;
622+ let to_bty = bx. cx ( ) . type_from_scalar ( to_scalar) ;
623+ let imm = transmute_immediate ( bx, src, from_scalar, from_bty, to_scalar, to_bty) ;
624+ * tgt = Ok ( imm) ;
625+ }
626+
594627 pub ( crate ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
595628 & mut self ,
596629 bx : & mut Bx ,
@@ -614,37 +647,48 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result<V, abi::Scalar>> {
614647 ( field_layout. is_zst ( ) , field_offset == Size :: ZERO )
615648 } ;
616649
617- let mut update = |tgt : & mut Result < V , abi:: Scalar > , src, from_scalar| {
618- let from_bty = bx. cx ( ) . type_from_scalar ( from_scalar) ;
619- let to_scalar = tgt. unwrap_err ( ) ;
620- let to_bty = bx. cx ( ) . type_from_scalar ( to_scalar) ;
621- let imm = transmute_immediate ( bx, src, from_scalar, from_bty, to_scalar, to_bty) ;
622- * tgt = Ok ( imm) ;
623- } ;
624-
625650 match ( operand. val , operand. layout . backend_repr ) {
626651 ( OperandValue :: ZeroSized , _) if expect_zst => { }
627652 ( OperandValue :: Immediate ( v) , BackendRepr :: Scalar ( from_scalar) ) => match & mut self . val {
628653 OperandValue :: Immediate ( val @ Err ( _) ) if is_zero_offset => {
629- update ( val, v, from_scalar) ;
654+ Self :: update ( bx , val, v, from_scalar) ;
630655 }
631656 OperandValue :: Pair ( fst @ Err ( _) , _) if is_zero_offset => {
632- update ( fst, v, from_scalar) ;
657+ Self :: update ( bx , fst, v, from_scalar) ;
633658 }
634659 OperandValue :: Pair ( _, snd @ Err ( _) ) if !is_zero_offset => {
635- update ( snd, v, from_scalar) ;
660+ Self :: update ( bx, snd, v, from_scalar) ;
661+ }
662+ _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
663+ } ,
664+ ( OperandValue :: Uninit , BackendRepr :: Scalar ( _) ) => match & mut self . val {
665+ OperandValue :: Immediate ( val @ Err ( _) ) if is_zero_offset => {
666+ Self :: update_uninit ( bx, val) ;
667+ }
668+ OperandValue :: Pair ( fst @ Err ( _) , _) if is_zero_offset => {
669+ Self :: update_uninit ( bx, fst) ;
670+ }
671+ OperandValue :: Pair ( _, snd @ Err ( _) ) if !is_zero_offset => {
672+ Self :: update_uninit ( bx, snd) ;
636673 }
637674 _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
638675 } ,
639676 ( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( from_sa, from_sb) ) => {
640677 match & mut self . val {
641678 OperandValue :: Pair ( fst @ Err ( _) , snd @ Err ( _) ) => {
642- update ( fst, a, from_sa) ;
643- update ( snd, b, from_sb) ;
679+ Self :: update ( bx , fst, a, from_sa) ;
680+ Self :: update ( bx , snd, b, from_sb) ;
644681 }
645682 _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
646683 }
647684 }
685+ ( OperandValue :: Uninit , BackendRepr :: ScalarPair ( ..) ) => match & mut self . val {
686+ OperandValue :: Pair ( fst @ Err ( _) , snd @ Err ( _) ) => {
687+ Self :: update_uninit ( bx, fst) ;
688+ Self :: update_uninit ( bx, snd) ;
689+ }
690+ _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
691+ } ,
648692 _ => bug ! ( "Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}" ) ,
649693 }
650694 }
@@ -663,6 +707,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result<V, abi::Scalar>> {
663707 } ;
664708
665709 let val = match val {
710+ OperandValue :: Uninit => OperandValue :: Uninit ,
666711 OperandValue :: ZeroSized => OperandValue :: ZeroSized ,
667712 OperandValue :: Immediate ( v) => OperandValue :: Immediate ( unwrap ( v) ) ,
668713 OperandValue :: Pair ( a, b) => OperandValue :: Pair ( unwrap ( a) , unwrap ( b) ) ,
@@ -739,6 +784,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
739784 ) {
740785 debug ! ( "OperandRef::store: operand={:?}, dest={:?}" , self , dest) ;
741786 match self {
787+ OperandValue :: Uninit => {
788+ // Ideally we'd hint to the backend that the destination is deinitialized by the
789+ // store. But in practice the destination is almost always uninit already because
790+ // OperandValue::Uninit is pretty much only produced by MaybeUninit::uninit.
791+ // Attempting to generate a hint by calling memset with undef mostly seems to
792+ // confuse LLVM.
793+ }
742794 OperandValue :: ZeroSized => {
743795 // Avoid generating stores of zero-sized values, because the only way to have a
744796 // zero-sized value is through `undef`/`poison`, and the store itself is useless.
0 commit comments