Make SSA aggregates without needing an alloca · rust-lang/rust@c38f75c (original) (raw)

`@@ -8,14 +8,16 @@ use crate::traits::*;

`

8

8

`use crate::MemFlags;

`

9

9

``

10

10

`use rustc_hir as hir;

`

11

``

`-

use rustc_middle::mir::{self, AggregateKind, Operand};

`

``

11

`+

use rustc_middle::mir;

`

12

12

`use rustc_middle::ty::cast::{CastTy, IntTy};

`

13

13

`use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};

`

14

14

`use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt};

`

15

15

`use rustc_middle::{bug, span_bug};

`

16

16

`use rustc_session::config::OptLevel;

`

17

17

`use rustc_span::{Span, DUMMY_SP};

`

18

``

`-

use rustc_target::abi::{self, FIRST_VARIANT};

`

``

18

`+

use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT};

`

``

19

+

``

20

`+

use arrayvec::ArrayVec;

`

19

21

``

20

22

`impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

`

21

23

`#[instrument(level = "trace", skip(self, bx))]

`

`@@ -581,7 +583,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

`

581

583

`self.codegen_place_to_pointer(bx, place, mk_ref)

`

582

584

`}

`

583

585

``

584

``

`-

mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)),

`

``

586

`+

mir::Rvalue::CopyForDeref(place) => {

`

``

587

`+

self.codegen_operand(bx, &mir::Operand::Copy(place))

`

``

588

`+

}

`

585

589

` mir::Rvalue::AddressOf(mutability, place) => {

`

586

590

`let mk_ptr =

`

587

591

`move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability);

`

`@@ -739,11 +743,40 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

`

739

743

`}

`

740

744

`}

`

741

745

` mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"),

`

742

``

`-

mir::Rvalue::Aggregate(..) => {

`

743

``

`` -

// According to rvalue_creates_operand, only ZST

``

744

``

`-

// aggregate rvalues are allowed to be operands.

`

``

746

`+

mir::Rvalue::Aggregate(_, ref fields) => {

`

745

747

`let ty = rvalue.ty(self.mir, self.cx.tcx());

`

746

``

`-

OperandRef::zero_sized(self.cx.layout_of(self.monomorphize(ty)))

`

``

748

`+

let ty = self.monomorphize(ty);

`

``

749

`+

let layout = self.cx.layout_of(ty);

`

``

750

+

``

751

`` +

// rvalue_creates_operand has arranged that we only get here if

``

``

752

`+

// we can build the aggregate immediate from the field immediates.

`

``

753

`+

let mut inputs = ArrayVec::<Bx::Value, 2>::new();

`

``

754

`+

let mut input_scalars = ArrayVec::<abi::Scalar, 2>::new();

`

``

755

`+

for field_idx in layout.fields.index_by_increasing_offset() {

`

``

756

`+

let field_idx = FieldIdx::from_usize(field_idx);

`

``

757

`+

let op = self.codegen_operand(bx, &fields[field_idx]);

`

``

758

`+

let values = op.val.immediates_or_place().left_or_else(|p| {

`

``

759

`+

bug!("Field {field_idx:?} is {p:?} making {layout:?}");

`

``

760

`+

});

`

``

761

`+

inputs.extend(values);

`

``

762

`+

let scalars = self.value_kind(op.layout).scalars().unwrap();

`

``

763

`+

input_scalars.extend(scalars);

`

``

764

`+

}

`

``

765

+

``

766

`+

let output_scalars = self.value_kind(layout).scalars().unwrap();

`

``

767

`+

itertools::izip!(&mut inputs, input_scalars, output_scalars).for_each(

`

``

768

`+

|(v, in_s, out_s)| {

`

``

769

`+

if in_s != out_s {

`

``

770

`+

// We have to be really careful about bool here, because

`

``

771

`` +

// (bool,) stays i1 but Cell<bool> becomes i8.

``

``

772

`+

*v = bx.from_immediate(*v);

`

``

773

`+

*v = bx.to_immediate_scalar(*v, out_s);

`

``

774

`+

}

`

``

775

`+

},

`

``

776

`+

);

`

``

777

+

``

778

`+

let val = OperandValue::from_immediates(inputs);

`

``

779

`+

OperandRef { val, layout }

`

747

780

`}

`

748

781

` mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {

`

749

782

`let operand = self.codegen_operand(bx, operand);

`

`@@ -1051,16 +1084,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

`

1051

1084

` mir::Rvalue::ThreadLocalRef(_) |

`

1052

1085

` mir::Rvalue::Use(..) => // (*)

`

1053

1086

`true,

`

1054

``

`` -

// This always produces a ty::RawPtr, so will be Immediate or Pair

``

1055

``

`-

mir::Rvalue::Aggregate(box AggregateKind::RawPtr(..), ..) => true,

`

1056

1087

`// Arrays are always aggregates, so it's not worth checking anything here.

`

1057

1088

`` // (If it's really [(); N] or [T; 0] and we use the place path, fine.)

``

1058

1089

` mir::Rvalue::Repeat(..) => false,

`

1059

``

`-

mir::Rvalue::Aggregate(..) => {

`

``

1090

`+

mir::Rvalue::Aggregate(ref kind, _) => {

`

``

1091

`+

let allowed_kind = match **kind {

`

``

1092

`` +

// This always produces a ty::RawPtr, so will be Immediate or Pair

``

``

1093

`+

mir::AggregateKind::RawPtr(..) => true,

`

``

1094

`+

mir::AggregateKind::Array(..) => false,

`

``

1095

`+

mir::AggregateKind::Tuple => true,

`

``

1096

`+

mir::AggregateKind::Adt(def_id, ..) => {

`

``

1097

`+

let adt_def = self.cx.tcx().adt_def(def_id);

`

``

1098

`+

adt_def.is_struct() && !adt_def.repr().simd()

`

``

1099

`+

}

`

``

1100

`+

mir::AggregateKind::Closure(..) => true,

`

``

1101

`+

// FIXME: Can we do this for simple coroutines too?

`

``

1102

`+

mir::AggregateKind::Coroutine(..) | mir::AggregateKind::CoroutineClosure(..) => false,

`

``

1103

`+

};

`

``

1104

`+

allowed_kind && {

`

1060

1105

`let ty = rvalue.ty(self.mir, self.cx.tcx());

`

1061

1106

`let ty = self.monomorphize(ty);

`

1062

``

`` -

// For ZST this can be OperandValueKind::ZeroSized.

``

1063

``

`-

self.cx.spanned_layout_of(ty, span).is_zst()

`

``

1107

`+

let layout = self.cx.spanned_layout_of(ty, span);

`

``

1108

`+

!self.cx.is_backend_ref(layout)

`

``

1109

`+

}

`

1064

1110

`}

`

1065

1111

`}

`

1066

1112

``

`@@ -1102,3 +1148,14 @@ enum OperandValueKind {

`

1102

1148

`Pair(abi::Scalar, abi::Scalar),

`

1103

1149

`ZeroSized,

`

1104

1150

`}

`

``

1151

+

``

1152

`+

impl OperandValueKind {

`

``

1153

`+

fn scalars(self) -> Option<ArrayVec<abi::Scalar, 2>> {

`

``

1154

`+

Some(match self {

`

``

1155

`+

OperandValueKind::ZeroSized => ArrayVec::new(),

`

``

1156

`+

OperandValueKind::Immediate(a) => ArrayVec::from_iter([a]),

`

``

1157

`+

OperandValueKind::Pair(a, b) => [a, b].into(),

`

``

1158

`+

OperandValueKind::Ref => return None,

`

``

1159

`+

})

`

``

1160

`+

}

`

``

1161

`+

}

`