rvalue.rs 30.9 KB
Newer Older
1 2
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
M
Mark Rousskov 已提交
3
use super::{FunctionCx, LocalRef};
4 5

use crate::base;
C
Caleb Zulawski 已提交
6
use crate::common::{self, IntPredicate};
7
use crate::traits::*;
M
Mark Rousskov 已提交
8
use crate::MemFlags;
9

M
Mazdak Farrokhzad 已提交
10 11
use rustc_middle::mir;
use rustc_middle::ty::cast::{CastTy, IntTy};
12
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
M
Mazdak Farrokhzad 已提交
13
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
14
use rustc_span::source_map::{Span, DUMMY_SP};
15

16
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
17
    #[instrument(level = "trace", skip(self, bx))]
18 19
    pub fn codegen_rvalue(
        &mut self,
20
        mut bx: Bx,
21
        dest: PlaceRef<'tcx, Bx::Value>,
M
Mark Rousskov 已提交
22
        rvalue: &mir::Rvalue<'tcx>,
23
    ) -> Bx {
24
        match *rvalue {
M
Mark Rousskov 已提交
25 26 27 28 29 30 31
            mir::Rvalue::Use(ref operand) => {
                let cg_operand = self.codegen_operand(&mut bx, operand);
                // FIXME: consider not copying constants through stack. (Fixable by codegen'ing
                // constants into `OperandValue::Ref`; why don’t we do that yet if we don’t?)
                cg_operand.val.store(&mut bx, dest);
                bx
            }
32

33
            mir::Rvalue::Cast(mir::CastKind::Pointer(PointerCast::Unsize), ref source, _) => {
34 35
                // The destination necessarily contains a fat pointer, so if
                // it's a scalar pair, it's a fat pointer or newtype thereof.
36
                if bx.cx().is_backend_scalar_pair(dest.layout) {
37
                    // Into-coerce of a thin pointer to a fat pointer -- just
A
Ariel Ben-Yehuda 已提交
38
                    // use the operand path.
39
                    let (mut bx, temp) = self.codegen_rvalue_operand(bx, rvalue);
40
                    temp.val.store(&mut bx, dest);
41
                    return bx;
42 43
                }

A
Ariel Ben-Yehuda 已提交
44
                // Unsize of a nontrivial struct. I would prefer for
I
Irina Popa 已提交
45
                // this to be eliminated by MIR building, but
A
Ariel Ben-Yehuda 已提交
46 47
                // `CoerceUnsized` can be passed by a where-clause,
                // so the (generic) MIR may not be able to expand it.
48
                let operand = self.codegen_operand(&mut bx, source);
49
                match operand.val {
M
Mark Rousskov 已提交
50
                    OperandValue::Pair(..) | OperandValue::Immediate(_) => {
51
                        // Unsize from an immediate structure. We don't
52 53
                        // really need a temporary alloca here, but
                        // avoiding it would require us to have
54
                        // `coerce_unsized_into` use `extractvalue` to
55 56
                        // index into the struct, and this case isn't
                        // important enough for it.
I
Irina Popa 已提交
57
                        debug!("codegen_rvalue: creating ugly alloca");
58
                        let scratch = PlaceRef::alloca(&mut bx, operand.layout);
59 60 61 62
                        scratch.storage_live(&mut bx);
                        operand.val.store(&mut bx, scratch);
                        base::coerce_unsized_into(&mut bx, scratch, dest);
                        scratch.storage_dead(&mut bx);
63
                    }
64
                    OperandValue::Ref(llref, None, align) => {
65
                        let source = PlaceRef::new_sized_aligned(llref, operand.layout, align);
66
                        base::coerce_unsized_into(&mut bx, source, dest);
A
Ariel Ben-Yehuda 已提交
67
                    }
68
                    OperandValue::Ref(_, Some(_), _) => {
69
                        bug!("unsized coercion on an unsized rvalue");
70
                    }
71
                }
72
                bx
73 74
            }

75
            mir::Rvalue::Repeat(ref elem, count) => {
76
                let cg_elem = self.codegen_operand(&mut bx, elem);
77

78
                // Do not generate the loop for zero-sized elements or empty arrays.
79
                if dest.layout.is_zst() {
80
                    return bx;
81 82
                }

I
Irina Popa 已提交
83
                if let OperandValue::Immediate(v) = cg_elem.val {
84 85 86
                    let zero = bx.const_usize(0);
                    let start = dest.project_index(&mut bx, zero).llval;
                    let size = bx.const_usize(dest.layout.size.bytes());
87

88
                    // Use llvm.memset.p0i8.* to initialize all zero arrays
89
                    if bx.cx().const_to_opt_uint(v) == Some(0) {
90
                        let fill = bx.cx().const_u8(0);
91
                        bx.memset(start, fill, size, dest.align, MemFlags::empty());
92
                        return bx;
93 94
                    }

95
                    // Use llvm.memset.p0i8.* to initialize byte arrays
96
                    let v = bx.from_immediate(v);
97
                    if bx.cx().val_ty(v) == bx.cx().type_i8() {
98
                        bx.memset(start, v, size, dest.align, MemFlags::empty());
99
                        return bx;
100 101 102
                    }
                }

103
                let count =
B
Bastian Kauschke 已提交
104
                    self.monomorphize(count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
105

106
                bx.write_operand_repeatedly(cg_elem, count, dest)
107 108
            }

109
            mir::Rvalue::Aggregate(ref kind, ref operands) => {
110
                let (dest, active_field_index) = match **kind {
111
                    mir::AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
112
                        dest.codegen_set_discr(&mut bx, variant_index);
113
                        if bx.tcx().adt_def(adt_did).is_enum() {
114
                            (dest.project_downcast(&mut bx, variant_index), active_field_index)
115 116
                        } else {
                            (dest, active_field_index)
117 118
                        }
                    }
M
Mark Rousskov 已提交
119
                    _ => (dest, None),
120 121
                };
                for (i, operand) in operands.iter().enumerate() {
122
                    let op = self.codegen_operand(&mut bx, operand);
123
                    // Do not generate stores and GEPis for zero-sized fields.
124
                    if !op.layout.is_zst() {
125
                        let field_index = active_field_index.unwrap_or(i);
126 127
                        let field = dest.project_field(&mut bx, field_index);
                        op.val.store(&mut bx, field);
128
                    }
129
                }
130
                bx
131 132 133
            }

            _ => {
134 135
                assert!(self.rvalue_creates_operand(rvalue, DUMMY_SP));
                let (mut bx, temp) = self.codegen_rvalue_operand(bx, rvalue);
136
                temp.val.store(&mut bx, dest);
137
                bx
138 139 140 141
            }
        }
    }

142 143
    pub fn codegen_rvalue_unsized(
        &mut self,
144
        mut bx: Bx,
145 146 147
        indirect_dest: PlaceRef<'tcx, Bx::Value>,
        rvalue: &mir::Rvalue<'tcx>,
    ) -> Bx {
M
Mark Rousskov 已提交
148 149 150 151
        debug!(
            "codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})",
            indirect_dest.llval, rvalue
        );
152 153 154

        match *rvalue {
            mir::Rvalue::Use(ref operand) => {
155
                let cg_operand = self.codegen_operand(&mut bx, operand);
156
                cg_operand.val.store_unsized(&mut bx, indirect_dest);
157 158 159
                bx
            }

160
            _ => bug!("unsized assignment other than `Rvalue::Use`"),
161 162 163
        }
    }

164 165
    pub fn codegen_rvalue_operand(
        &mut self,
166
        mut bx: Bx,
M
Mark Rousskov 已提交
167
        rvalue: &mir::Rvalue<'tcx>,
168
    ) -> (Bx, OperandRef<'tcx, Bx::Value>) {
169
        assert!(
170
            self.rvalue_creates_operand(rvalue, DUMMY_SP),
171 172 173
            "cannot codegen {:?} to operand",
            rvalue,
        );
174 175

        match *rvalue {
176
            mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => {
177
                let operand = self.codegen_operand(&mut bx, source);
178
                debug!("cast operand is {:?}", operand);
B
Bastian Kauschke 已提交
179
                let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
A
Ariel Ben-Yehuda 已提交
180 181

                let val = match *kind {
182
                    mir::CastKind::PointerExposeAddress => {
183 184 185 186 187 188
                        assert!(bx.cx().is_backend_immediate(cast));
                        let llptr = operand.immediate();
                        let llcast_ty = bx.cx().immediate_backend_type(cast);
                        let lladdr = bx.ptrtoint(llptr, llcast_ty);
                        OperandValue::Immediate(lladdr)
                    }
189
                    mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
L
LeSeulArtichaut 已提交
190
                        match *operand.layout.ty.kind() {
V
varkor 已提交
191
                            ty::FnDef(def_id, substs) => {
D
David Wood 已提交
192 193 194 195 196
                                let instance = ty::Instance::resolve_for_fn_ptr(
                                    bx.tcx(),
                                    ty::ParamEnv::reveal_all(),
                                    def_id,
                                    substs,
197
                                )
D
David Wood 已提交
198 199 200
                                .unwrap()
                                .polymorphize(bx.cx().tcx());
                                OperandValue::Immediate(bx.get_fn_addr(instance))
201
                            }
M
Mark Rousskov 已提交
202
                            _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
203 204
                        }
                    }
205
                    mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => {
L
LeSeulArtichaut 已提交
206
                        match *operand.layout.ty.kind() {
V
varkor 已提交
207
                            ty::Closure(def_id, substs) => {
208
                                let instance = Instance::resolve_closure(
C
csmoe 已提交
209 210 211
                                    bx.cx().tcx(),
                                    def_id,
                                    substs,
M
Mark Rousskov 已提交
212
                                    ty::ClosureKind::FnOnce,
D
David Wood 已提交
213 214
                                )
                                .polymorphize(bx.cx().tcx());
B
bjorn3 已提交
215
                                OperandValue::Immediate(bx.cx().get_fn_addr(instance))
216
                            }
M
Mark Rousskov 已提交
217
                            _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
218 219
                        }
                    }
220
                    mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => {
221
                        // This is a no-op at the LLVM level.
A
Ariel Ben-Yehuda 已提交
222 223
                        operand.val
                    }
224
                    mir::CastKind::Pointer(PointerCast::Unsize) => {
225
                        assert!(bx.cx().is_backend_scalar_pair(cast));
crlf0710's avatar
crlf0710 已提交
226
                        let (lldata, llextra) = match operand.val {
227
                            OperandValue::Pair(lldata, llextra) => {
228
                                // unsize from a fat pointer -- this is a
crlf0710's avatar
crlf0710 已提交
229 230
                                // "trait-object-to-supertrait" coercion.
                                (lldata, Some(llextra))
A
Ariel Ben-Yehuda 已提交
231
                            }
A
Ariel Ben-Yehuda 已提交
232
                            OperandValue::Immediate(lldata) => {
A
Ariel Ben-Yehuda 已提交
233
                                // "standard" unsize
crlf0710's avatar
crlf0710 已提交
234
                                (lldata, None)
A
Ariel Ben-Yehuda 已提交
235
                            }
236
                            OperandValue::Ref(..) => {
M
Mark Rousskov 已提交
237
                                bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand);
A
Ariel Ben-Yehuda 已提交
238
                            }
crlf0710's avatar
crlf0710 已提交
239 240 241 242
                        };
                        let (lldata, llextra) =
                            base::unsize_ptr(&mut bx, lldata, operand.layout.ty, cast.ty, llextra);
                        OperandValue::Pair(lldata, llextra)
A
Ariel Ben-Yehuda 已提交
243
                    }
M
Mark Rousskov 已提交
244 245 246 247
                    mir::CastKind::Pointer(PointerCast::MutToConstPointer)
                    | mir::CastKind::Misc
                        if bx.cx().is_backend_scalar_pair(operand.layout) =>
                    {
248
                        if let OperandValue::Pair(data_ptr, meta) = operand.val {
249
                            if bx.cx().is_backend_scalar_pair(cast) {
M
Mark Rousskov 已提交
250 251 252 253
                                let data_cast = bx.pointercast(
                                    data_ptr,
                                    bx.cx().scalar_pair_element_backend_type(cast, 0, true),
                                );
254
                                OperandValue::Pair(data_cast, meta)
M
Mark Rousskov 已提交
255 256
                            } else {
                                // cast to thin-ptr
257 258
                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
                                // pointer-cast of that pointer to desired pointer type.
259
                                let llcast_ty = bx.cx().immediate_backend_type(cast);
260
                                let llval = bx.pointercast(data_ptr, llcast_ty);
261 262 263
                                OperandValue::Immediate(llval)
                            }
                        } else {
264
                            bug!("unexpected non-pair operand");
265 266
                        }
                    }
267 268 269
                    mir::CastKind::Pointer(
                        PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
                    )
270
                    | mir::CastKind::Misc
R
comment  
Ralf Jung 已提交
271 272 273
                    // Since int2ptr can have arbitrary integer types as input (so we have to do
                    // sign extension and all that), it is currently best handled in the same code
                    // path as the other integer-to-X casts.
274
                    | mir::CastKind::PointerFromExposedAddress => {
275
                        assert!(bx.cx().is_backend_immediate(cast));
276
                        let ll_t_out = bx.cx().immediate_backend_type(cast);
277
                        if operand.layout.abi.is_uninhabited() {
278
                            let val = OperandValue::Immediate(bx.cx().const_undef(ll_t_out));
M
Mark Rousskov 已提交
279
                            return (bx, OperandRef { val, layout: cast });
280
                        }
M
Mark Rousskov 已提交
281 282
                        let r_t_in =
                            CastTy::from_ty(operand.layout.ty).expect("bad input type for cast");
283
                        let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
284
                        let ll_t_in = bx.cx().immediate_backend_type(operand.layout);
285
                        let llval = operand.immediate();
286

287
                        let newval = match (r_t_in, r_t_out) {
288
                            (CastTy::Int(i), CastTy::Int(_)) => {
289
                                bx.intcast(llval, ll_t_out, i.is_signed())
290
                            }
291
                            (CastTy::Float, CastTy::Float) => {
D
Denis Merigoux 已提交
292 293
                                let srcsz = bx.cx().float_width(ll_t_in);
                                let dstsz = bx.cx().float_width(ll_t_out);
294
                                if dstsz > srcsz {
295
                                    bx.fpext(llval, ll_t_out)
296
                                } else if srcsz > dstsz {
297
                                    bx.fptrunc(llval, ll_t_out)
298 299 300 301
                                } else {
                                    llval
                                }
                            }
302
                            (CastTy::Int(i), CastTy::Float) => {
303
                                if i.is_signed() {
304 305 306 307 308
                                    bx.sitofp(llval, ll_t_out)
                                } else {
                                    bx.uitofp(llval, ll_t_out)
                                }
                            }
309
                            (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
M
Mark Rousskov 已提交
310 311
                                bx.pointercast(llval, ll_t_out)
                            }
312 313
                            (CastTy::Int(i), CastTy::Ptr(_)) => {
                                let usize_llval =
314
                                    bx.intcast(llval, bx.cx().type_isize(), i.is_signed());
315
                                bx.inttoptr(usize_llval, ll_t_out)
316
                            }
M
Mark Rousskov 已提交
317
                            (CastTy::Float, CastTy::Int(IntTy::I)) => {
C
Caleb Zulawski 已提交
318
                                bx.cast_float_to_int(true, llval, ll_t_out)
M
Mark Rousskov 已提交
319 320
                            }
                            (CastTy::Float, CastTy::Int(_)) => {
C
Caleb Zulawski 已提交
321
                                bx.cast_float_to_int(false, llval, ll_t_out)
M
Mark Rousskov 已提交
322 323
                            }
                            _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty),
324 325 326
                        };
                        OperandValue::Immediate(newval)
                    }
A
Ariel Ben-Yehuda 已提交
327
                };
M
Mark Rousskov 已提交
328
                (bx, OperandRef { val, layout: cast })
329 330
            }

331
            mir::Rvalue::Ref(_, bk, place) => {
M
Mark Rousskov 已提交
332 333 334 335 336 337
                let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
                    tcx.mk_ref(
                        tcx.lifetimes.re_erased,
                        ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() },
                    )
                };
M
Matthew Jasper 已提交
338 339
                self.codegen_place_to_pointer(bx, place, mk_ref)
            }
A
Ariel Ben-Yehuda 已提交
340

341
            mir::Rvalue::AddressOf(mutability, place) => {
M
Mark Rousskov 已提交
342
                let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
343
                    tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability })
M
Mark Rousskov 已提交
344
                };
M
Matthew Jasper 已提交
345
                self.codegen_place_to_pointer(bx, place, mk_ptr)
346 347
            }

348
            mir::Rvalue::Len(place) => {
349
                let size = self.evaluate_array_len(&mut bx, place);
350
                let operand = OperandRef {
351
                    val: OperandValue::Immediate(size),
352
                    layout: bx.cx().layout_of(bx.tcx().types.usize),
353
                };
354
                (bx, operand)
355 356
            }

357
            mir::Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
358 359
                let lhs = self.codegen_operand(&mut bx, lhs);
                let rhs = self.codegen_operand(&mut bx, rhs);
360
                let llresult = match (lhs.val, rhs.val) {
M
Mark Rousskov 已提交
361 362 363 364 365 366 367 368 369 370 371 372 373 374
                    (
                        OperandValue::Pair(lhs_addr, lhs_extra),
                        OperandValue::Pair(rhs_addr, rhs_extra),
                    ) => self.codegen_fat_ptr_binop(
                        &mut bx,
                        op,
                        lhs_addr,
                        lhs_extra,
                        rhs_addr,
                        rhs_extra,
                        lhs.layout.ty,
                    ),

                    (OperandValue::Immediate(lhs_val), OperandValue::Immediate(rhs_val)) => {
375
                        self.codegen_scalar_binop(&mut bx, op, lhs_val, rhs_val, lhs.layout.ty)
376 377
                    }

M
Mark Rousskov 已提交
378
                    _ => bug!(),
379
                };
380
                let operand = OperandRef {
A
Ariel Ben-Yehuda 已提交
381
                    val: OperandValue::Immediate(llresult),
M
Mark Rousskov 已提交
382
                    layout: bx.cx().layout_of(op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)),
383
                };
384
                (bx, operand)
385
            }
386
            mir::Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
387 388
                let lhs = self.codegen_operand(&mut bx, lhs);
                let rhs = self.codegen_operand(&mut bx, rhs);
M
Mark Rousskov 已提交
389 390 391 392 393 394 395
                let result = self.codegen_scalar_checked_binop(
                    &mut bx,
                    op,
                    lhs.immediate(),
                    rhs.immediate(),
                    lhs.layout.ty,
                );
396
                let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
A
Andrew Cann 已提交
397
                let operand_ty = bx.tcx().intern_tup(&[val_ty, bx.tcx().types.bool]);
M
Mark Rousskov 已提交
398
                let operand = OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) };
J
James Miller 已提交
399

400
                (bx, operand)
J
James Miller 已提交
401
            }
402 403

            mir::Rvalue::UnaryOp(op, ref operand) => {
404
                let operand = self.codegen_operand(&mut bx, operand);
405
                let lloperand = operand.immediate();
406
                let is_float = operand.layout.ty.is_floating_point();
407
                let llval = match op {
408
                    mir::UnOp::Not => bx.not(lloperand),
M
Mark Rousskov 已提交
409 410 411 412 413 414
                    mir::UnOp::Neg => {
                        if is_float {
                            bx.fneg(lloperand)
                        } else {
                            bx.neg(lloperand)
                        }
415 416
                    }
                };
M
Mark Rousskov 已提交
417
                (bx, OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout })
418 419
            }

420
            mir::Rvalue::Discriminant(ref place) => {
421
                let discr_ty = rvalue.ty(self.mir, bx.tcx());
422
                let discr_ty = self.monomorphize(discr_ty);
M
Mark Rousskov 已提交
423
                let discr = self
424
                    .codegen_place(&mut bx, place.as_ref())
425
                    .codegen_get_discr(&mut bx, discr_ty);
M
Mark Rousskov 已提交
426 427 428 429 430 431 432
                (
                    bx,
                    OperandRef {
                        val: OperandValue::Immediate(discr),
                        layout: self.cx.layout_of(discr_ty),
                    },
                )
433 434
            }

G
Gary Guo 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
            mir::Rvalue::NullaryOp(null_op, ty) => {
                let ty = self.monomorphize(ty);
                assert!(bx.cx().type_is_sized(ty));
                let layout = bx.cx().layout_of(ty);
                let val = match null_op {
                    mir::NullOp::SizeOf => layout.size.bytes(),
                    mir::NullOp::AlignOf => layout.align.abi.bytes(),
                };
                let val = bx.cx().const_usize(val);
                let tcx = self.cx.tcx();
                (
                    bx,
                    OperandRef {
                        val: OperandValue::Immediate(val),
                        layout: self.cx.layout_of(tcx.types.usize),
                    },
                )
            }

454 455 456 457 458 459 460
            mir::Rvalue::ThreadLocalRef(def_id) => {
                assert!(bx.cx().tcx().is_static(def_id));
                let static_ = bx.get_static(def_id);
                let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
                let operand = OperandRef::from_immediate_or_packed_pair(&mut bx, static_, layout);
                (bx, operand)
            }
461
            mir::Rvalue::Use(ref operand) => {
462
                let operand = self.codegen_operand(&mut bx, operand);
463
                (bx, operand)
464
            }
M
Mark Rousskov 已提交
465
            mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => {
466 467
                // According to `rvalue_creates_operand`, only ZST
                // aggregate rvalues are allowed to be operands.
468
                let ty = rvalue.ty(self.mir, self.cx.tcx());
M
Mark Rousskov 已提交
469
                let operand =
B
Bastian Kauschke 已提交
470
                    OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty)));
471
                (bx, operand)
472
            }
G
Gary Guo 已提交
473 474 475 476 477 478 479 480 481 482 483 484
            mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
                let operand = self.codegen_operand(&mut bx, operand);
                let lloperand = operand.immediate();

                let content_ty = self.monomorphize(content_ty);
                let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
                let llty_ptr = bx.cx().backend_type(box_layout);

                let val = bx.pointercast(lloperand, llty_ptr);
                let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
                (bx, operand)
            }
485 486
        }
    }
487

488
    fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
489
        // ZST are passed as operands and require special handling
I
Irina Popa 已提交
490
        // because codegen_place() panics if Local is operand.
491
        if let Some(index) = place.as_local() {
492
            if let LocalRef::Operand(Some(op)) = self.locals[index] {
L
LeSeulArtichaut 已提交
493
                if let ty::Array(_, n) = op.layout.ty.kind() {
494
                    let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
495
                    return bx.cx().const_usize(n);
496 497 498 499
                }
            }
        }
        // use common size calculation for non zero-sized types
500
        let cg_value = self.codegen_place(bx, place.as_ref());
501
        cg_value.len(bx.cx())
502 503
    }

M
Matthew Jasper 已提交
504 505 506 507
    /// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref`
    fn codegen_place_to_pointer(
        &mut self,
        mut bx: Bx,
508
        place: mir::Place<'tcx>,
M
Matthew Jasper 已提交
509 510
        mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
    ) -> (Bx, OperandRef<'tcx, Bx::Value>) {
511
        let cg_place = self.codegen_place(&mut bx, place.as_ref());
M
Matthew Jasper 已提交
512 513 514 515 516 517 518 519 520 521

        let ty = cg_place.layout.ty;

        // Note: places are indirect, so storing the `llval` into the
        // destination effectively creates a reference.
        let val = if !bx.cx().type_has_metadata(ty) {
            OperandValue::Immediate(cg_place.llval)
        } else {
            OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
        };
M
Mark Rousskov 已提交
522
        (bx, OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) })
M
Matthew Jasper 已提交
523 524
    }

525 526
    pub fn codegen_scalar_binop(
        &mut self,
527
        bx: &mut Bx,
528
        op: mir::BinOp,
529 530
        lhs: Bx::Value,
        rhs: Bx::Value,
531
        input_ty: Ty<'tcx>,
532
    ) -> Bx::Value {
533
        let is_float = input_ty.is_floating_point();
534 535
        let is_signed = input_ty.is_signed();
        match op {
M
Mark Rousskov 已提交
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
            mir::BinOp::Add => {
                if is_float {
                    bx.fadd(lhs, rhs)
                } else {
                    bx.add(lhs, rhs)
                }
            }
            mir::BinOp::Sub => {
                if is_float {
                    bx.fsub(lhs, rhs)
                } else {
                    bx.sub(lhs, rhs)
                }
            }
            mir::BinOp::Mul => {
                if is_float {
                    bx.fmul(lhs, rhs)
                } else {
                    bx.mul(lhs, rhs)
                }
            }
            mir::BinOp::Div => {
                if is_float {
                    bx.fdiv(lhs, rhs)
                } else if is_signed {
                    bx.sdiv(lhs, rhs)
                } else {
                    bx.udiv(lhs, rhs)
                }
            }
            mir::BinOp::Rem => {
                if is_float {
                    bx.frem(lhs, rhs)
                } else if is_signed {
                    bx.srem(lhs, rhs)
                } else {
                    bx.urem(lhs, rhs)
                }
            }
575 576 577
            mir::BinOp::BitOr => bx.or(lhs, rhs),
            mir::BinOp::BitAnd => bx.and(lhs, rhs),
            mir::BinOp::BitXor => bx.xor(lhs, rhs),
578 579 580 581 582 583 584 585
            mir::BinOp::Offset => {
                let pointee_type = input_ty
                    .builtin_deref(true)
                    .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty))
                    .ty;
                let llty = bx.cx().backend_type(bx.cx().layout_of(pointee_type));
                bx.inbounds_gep(llty, lhs, &[rhs])
            }
586 587
            mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs),
            mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs),
M
Mark Rousskov 已提交
588 589 590 591 592 593 594 595 596 597 598
            mir::BinOp::Ne
            | mir::BinOp::Lt
            | mir::BinOp::Gt
            | mir::BinOp::Eq
            | mir::BinOp::Le
            | mir::BinOp::Ge => {
                if is_float {
                    bx.fcmp(base::bin_op_to_fcmp_predicate(op.to_hir_binop()), lhs, rhs)
                } else {
                    bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs)
                }
599 600 601 602
            }
        }
    }

603 604
    pub fn codegen_fat_ptr_binop(
        &mut self,
605
        bx: &mut Bx,
606
        op: mir::BinOp,
607 608 609 610
        lhs_addr: Bx::Value,
        lhs_extra: Bx::Value,
        rhs_addr: Bx::Value,
        rhs_extra: Bx::Value,
611
        _input_ty: Ty<'tcx>,
612
    ) -> Bx::Value {
613 614
        match op {
            mir::BinOp::Eq => {
615 616 617
                let lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr);
                let rhs = bx.icmp(IntPredicate::IntEQ, lhs_extra, rhs_extra);
                bx.and(lhs, rhs)
618 619
            }
            mir::BinOp::Ne => {
620 621 622
                let lhs = bx.icmp(IntPredicate::IntNE, lhs_addr, rhs_addr);
                let rhs = bx.icmp(IntPredicate::IntNE, lhs_extra, rhs_extra);
                bx.or(lhs, rhs)
623
            }
M
Mark Rousskov 已提交
624
            mir::BinOp::Le | mir::BinOp::Lt | mir::BinOp::Ge | mir::BinOp::Gt => {
625 626
                // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
                let (op, strict_op) = match op {
627 628 629 630
                    mir::BinOp::Lt => (IntPredicate::IntULT, IntPredicate::IntULT),
                    mir::BinOp::Le => (IntPredicate::IntULE, IntPredicate::IntULT),
                    mir::BinOp::Gt => (IntPredicate::IntUGT, IntPredicate::IntUGT),
                    mir::BinOp::Ge => (IntPredicate::IntUGE, IntPredicate::IntUGT),
631 632
                    _ => bug!(),
                };
633 634 635 636 637
                let lhs = bx.icmp(strict_op, lhs_addr, rhs_addr);
                let and_lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr);
                let and_rhs = bx.icmp(op, lhs_extra, rhs_extra);
                let rhs = bx.and(and_lhs, and_rhs);
                bx.or(lhs, rhs)
638 639 640
            }
            _ => {
                bug!("unexpected fat ptr binop");
641 642 643
            }
        }
    }
J
James Miller 已提交
644

645 646
    pub fn codegen_scalar_checked_binop(
        &mut self,
647
        bx: &mut Bx,
648 649 650
        op: mir::BinOp,
        lhs: Bx::Value,
        rhs: Bx::Value,
M
Mark Rousskov 已提交
651
        input_ty: Ty<'tcx>,
652
    ) -> OperandValue<Bx::Value> {
653 654 655 656
        // This case can currently arise only from functions marked
        // with #[rustc_inherit_overflow_checks] and inlined from
        // another crate (mostly core::num generic/#[inline] fns),
        // while the current crate doesn't use overflow checks.
657
        if !bx.cx().check_overflow() {
I
Irina Popa 已提交
658
            let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty);
659
            return OperandValue::Pair(val, bx.cx().const_bool(false));
660 661
        }

J
James Miller 已提交
662 663 664 665 666 667 668
        let (val, of) = match op {
            // These are checked using intrinsics
            mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => {
                let oop = match op {
                    mir::BinOp::Add => OverflowOp::Add,
                    mir::BinOp::Sub => OverflowOp::Sub,
                    mir::BinOp::Mul => OverflowOp::Mul,
M
Mark Rousskov 已提交
669
                    _ => unreachable!(),
J
James Miller 已提交
670
                };
671
                bx.checked_binop(oop, input_ty, lhs, rhs)
J
James Miller 已提交
672 673
            }
            mir::BinOp::Shl | mir::BinOp::Shr => {
674 675
                let lhs_llty = bx.cx().val_ty(lhs);
                let rhs_llty = bx.cx().val_ty(rhs);
676
                let invert_mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, true);
677
                let outer_bits = bx.and(rhs, invert_mask);
J
James Miller 已提交
678

679
                let of = bx.icmp(IntPredicate::IntNE, outer_bits, bx.cx().const_null(rhs_llty));
I
Irina Popa 已提交
680
                let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty);
J
James Miller 已提交
681

682
                (val, of)
J
James Miller 已提交
683
            }
M
Mark Rousskov 已提交
684
            _ => bug!("Operator `{:?}` is not a checkable operator", op),
J
James Miller 已提交
685 686
        };

687
        OperandValue::Pair(val, of)
J
James Miller 已提交
688
    }
689
}
690

691
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
692
    pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
693 694
        match *rvalue {
            mir::Rvalue::Ref(..) |
M
Matthew Jasper 已提交
695
            mir::Rvalue::AddressOf(..) |
696 697
            mir::Rvalue::Len(..) |
            mir::Rvalue::Cast(..) | // (*)
G
Gary Guo 已提交
698
            mir::Rvalue::ShallowInitBox(..) | // (*)
699 700 701 702
            mir::Rvalue::BinaryOp(..) |
            mir::Rvalue::CheckedBinaryOp(..) |
            mir::Rvalue::UnaryOp(..) |
            mir::Rvalue::Discriminant(..) |
703
            mir::Rvalue::NullaryOp(..) |
704
            mir::Rvalue::ThreadLocalRef(_) |
705 706 707 708
            mir::Rvalue::Use(..) => // (*)
                true,
            mir::Rvalue::Repeat(..) |
            mir::Rvalue::Aggregate(..) => {
709
                let ty = rvalue.ty(self.mir, self.cx.tcx());
B
Bastian Kauschke 已提交
710
                let ty = self.monomorphize(ty);
711
                self.cx.spanned_layout_of(ty, span).is_zst()
712 713
            }
        }
714

715 716
        // (*) this is only true if the type is suitable
    }
717
}