mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Simplify the canonical enum clone branches to a copy statement
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
use rustc_abi::Integer;
|
||||
use rustc_const_eval::const_eval::mk_eval_cx_for_const_val;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
|
||||
use super::simplify::simplify_cfg;
|
||||
use crate::patch::MirPatch;
|
||||
|
||||
/// Merges all targets into one basic block if each statement can have the same statement.
|
||||
/// Unifies all targets into one basic block if each statement can have the same statement.
|
||||
pub(super) struct MatchBranchSimplification;
|
||||
|
||||
impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
|
||||
@@ -40,6 +42,7 @@ struct SimplifyMatch<'tcx, 'a> {
|
||||
patch: MirPatch<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
switch_bb: BasicBlock,
|
||||
discr: &'a Operand<'tcx>,
|
||||
discr_local: Option<Local>,
|
||||
discr_ty: Ty<'tcx>,
|
||||
}
|
||||
@@ -53,8 +56,8 @@ fn discr_local(&mut self) -> Local {
|
||||
})
|
||||
}
|
||||
|
||||
/// Merges the assignments if all rvalues are constants and equal.
|
||||
fn merge_if_equal_const(
|
||||
/// Unifies the assignments if all rvalues are constants and equal.
|
||||
fn unify_if_equal_const(
|
||||
&self,
|
||||
dest: Place<'tcx>,
|
||||
consts: &[(u128, &ConstOperand<'tcx>)],
|
||||
@@ -76,7 +79,7 @@ fn merge_if_equal_const(
|
||||
|
||||
/// If a source block is found that switches between two blocks that are exactly
|
||||
/// the same modulo const bool assignments (e.g., one assigns true another false
|
||||
/// to the same place), merge a target block statements into the source block,
|
||||
/// to the same place), unify a target block statements into the source block,
|
||||
/// using Eq / Ne comparison with switch value where const bools value differ.
|
||||
///
|
||||
/// For example:
|
||||
@@ -105,7 +108,7 @@ fn merge_if_equal_const(
|
||||
/// goto -> bb3;
|
||||
/// }
|
||||
/// ```
|
||||
fn merge_by_eq_op(
|
||||
fn unify_by_eq_op(
|
||||
&mut self,
|
||||
dest: Place<'tcx>,
|
||||
consts: &[(u128, &ConstOperand<'tcx>)],
|
||||
@@ -140,7 +143,7 @@ fn merge_by_eq_op(
|
||||
}
|
||||
}
|
||||
|
||||
/// Merges the assignments if all rvalues can be cast from the discriminant value by IntToInt.
|
||||
/// Unifies the assignments if all rvalues can be cast from the discriminant value by IntToInt.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
@@ -177,7 +180,7 @@ fn merge_by_eq_op(
|
||||
/// goto -> bb5;
|
||||
/// }
|
||||
/// ```
|
||||
fn merge_by_int_to_int(
|
||||
fn unify_by_int_to_int(
|
||||
&mut self,
|
||||
dest: Place<'tcx>,
|
||||
consts: &[(u128, &ConstOperand<'tcx>)],
|
||||
@@ -207,10 +210,91 @@ fn merge_by_int_to_int(
|
||||
}
|
||||
}
|
||||
|
||||
/// This is primarily used to unify these copy statements that simplified the canonical enum clone method by GVN.
|
||||
/// The GVN simplified
|
||||
/// ```ignore (syntax-highlighting-only)
|
||||
/// match a {
|
||||
/// Foo::A(x) => Foo::A(*x),
|
||||
/// Foo::B => Foo::B
|
||||
/// }
|
||||
/// ```
|
||||
/// to
|
||||
/// ```ignore (syntax-highlighting-only)
|
||||
/// match a {
|
||||
/// Foo::A(_x) => a, // copy a
|
||||
/// Foo::B => Foo::B
|
||||
/// }
|
||||
/// ```
|
||||
/// This will simplify into a copy statement.
|
||||
fn unify_by_copy(
|
||||
&self,
|
||||
dest: Place<'tcx>,
|
||||
rvals: &[(u128, &Rvalue<'tcx>)],
|
||||
) -> Option<StatementKind<'tcx>> {
|
||||
let bbs = &self.body.basic_blocks;
|
||||
// Check if the copy source matches the following pattern.
|
||||
// _2 = discriminant(*_1); // "*_1" is the expected the copy source.
|
||||
// switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
|
||||
let &Statement {
|
||||
kind: StatementKind::Assign(box (discr_place, Rvalue::Discriminant(copy_src_place))),
|
||||
..
|
||||
} = bbs[self.switch_bb].statements.last()?
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
if self.discr.place() != Some(discr_place) {
|
||||
return None;
|
||||
}
|
||||
let src_ty = copy_src_place.ty(self.body.local_decls(), self.tcx);
|
||||
if !src_ty.ty.is_enum() || src_ty.variant_index.is_some() {
|
||||
return None;
|
||||
}
|
||||
let dest_ty = dest.ty(self.body.local_decls(), self.tcx);
|
||||
if dest_ty.ty != src_ty.ty || dest_ty.variant_index.is_some() {
|
||||
return None;
|
||||
}
|
||||
let ty::Adt(def, _) = dest_ty.ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
for &(case, rvalue) in rvals.iter() {
|
||||
match rvalue {
|
||||
// Check if `_3 = const Foo::B` can be transformed to `_3 = copy *_1`.
|
||||
Rvalue::Use(Operand::Constant(box constant))
|
||||
if let Const::Val(const_, ty) = constant.const_ =>
|
||||
{
|
||||
let (ecx, op) = mk_eval_cx_for_const_val(
|
||||
self.tcx.at(constant.span),
|
||||
self.typing_env,
|
||||
const_,
|
||||
ty,
|
||||
)?;
|
||||
let variant = ecx.read_discriminant(&op).discard_err()?;
|
||||
if !def.variants()[variant].fields.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let Discr { val, .. } = ty.discriminant_for_variant(self.tcx, variant)?;
|
||||
if val != case {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Rvalue::Use(Operand::Copy(src_place)) if *src_place == copy_src_place => {}
|
||||
// Check if `_3 = Foo::B` can be transformed to `_3 = copy *_1`.
|
||||
Rvalue::Aggregate(box AggregateKind::Adt(_, variant_index, _, _, None), fields)
|
||||
if fields.is_empty()
|
||||
&& let Some(Discr { val, .. }) =
|
||||
src_ty.ty.discriminant_for_variant(self.tcx, *variant_index)
|
||||
&& val == case => {}
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
Some(StatementKind::Assign(Box::new((dest, Rvalue::Use(Operand::Copy(copy_src_place))))))
|
||||
}
|
||||
|
||||
/// Returns a new statement if we can use the statement replace all statements.
|
||||
fn try_merge_stmts(
|
||||
fn try_unify_stmts(
|
||||
&mut self,
|
||||
_index: usize,
|
||||
index: usize,
|
||||
stmts: &[(u128, &StatementKind<'tcx>)],
|
||||
otherwise: Option<&StatementKind<'tcx>>,
|
||||
) -> Option<StatementKind<'tcx>> {
|
||||
@@ -220,25 +304,37 @@ fn try_merge_stmts(
|
||||
|
||||
let (dest, rvals, otherwise) = candidate_assign(stmts, otherwise)?;
|
||||
if let Some((consts, otherwise)) = candidate_const(&rvals, otherwise) {
|
||||
if let Some(new_stmt) = self.merge_if_equal_const(dest, &consts, otherwise) {
|
||||
if let Some(new_stmt) = self.unify_if_equal_const(dest, &consts, otherwise) {
|
||||
return Some(new_stmt);
|
||||
}
|
||||
if let Some(new_stmt) = self.merge_by_eq_op(dest, &consts, otherwise) {
|
||||
if let Some(new_stmt) = self.unify_by_eq_op(dest, &consts, otherwise) {
|
||||
return Some(new_stmt);
|
||||
}
|
||||
// Requires the otherwise is unreachable.
|
||||
if otherwise.is_none()
|
||||
&& let Some(new_stmt) = self.merge_by_int_to_int(dest, &consts)
|
||||
&& let Some(new_stmt) = self.unify_by_int_to_int(dest, &consts)
|
||||
{
|
||||
return Some(new_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
// We only know the first statement is safe to introduce new dereferences.
|
||||
if index == 0
|
||||
// We cannot create overlapping assignments.
|
||||
&& dest.is_stable_offset()
|
||||
// Requires the otherwise is unreachable.
|
||||
&& otherwise.is_none()
|
||||
&& let Some(new_stmt) = self.unify_by_copy(dest, &rvals)
|
||||
{
|
||||
return Some(new_stmt);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the first case target if all targets have an equal number of statements and identical destination.
|
||||
fn candidate_match<'tcx>(body: &Body<'tcx>, switch_bb: BasicBlock) -> bool {
|
||||
use itertools::Itertools;
|
||||
let targets = match &body.basic_blocks[switch_bb].terminator().kind {
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(_) | Operand::Move(_), targets, ..
|
||||
@@ -254,21 +350,14 @@ fn candidate_match<'tcx>(body: &Body<'tcx>, switch_bb: BasicBlock) -> bool {
|
||||
if !targets.is_distinct() {
|
||||
return false;
|
||||
}
|
||||
let &[first, ref others @ .., otherwise] = targets.all_targets() else {
|
||||
return false;
|
||||
};
|
||||
let first_case_bb = &body.basic_blocks[first];
|
||||
let first_case_terminator_kind = &first_case_bb.terminator().kind;
|
||||
let first_case_stmts_len = first_case_bb.statements.len();
|
||||
|
||||
let otherwise =
|
||||
if body.basic_blocks[otherwise].is_empty_unreachable() { None } else { Some(&otherwise) };
|
||||
// Check that destinations are identical, and if not, then don't optimize this block
|
||||
others.iter().chain(otherwise).all(|&bb| {
|
||||
let bb = &body.basic_blocks[bb];
|
||||
first_case_stmts_len == bb.statements.len()
|
||||
&& first_case_terminator_kind == &bb.terminator().kind
|
||||
})
|
||||
targets
|
||||
.all_targets()
|
||||
.iter()
|
||||
.map(|&bb| &body.basic_blocks[bb])
|
||||
.filter(|bb| !bb.is_empty_unreachable())
|
||||
.map(|bb| (bb.statements.len(), &bb.terminator().kind))
|
||||
.all_equal()
|
||||
}
|
||||
|
||||
fn simplify_match<'tcx>(
|
||||
@@ -287,31 +376,41 @@ fn simplify_match<'tcx>(
|
||||
patch: MirPatch::new(body),
|
||||
body,
|
||||
switch_bb,
|
||||
discr,
|
||||
discr_local: None,
|
||||
discr_ty: discr.ty(body.local_decls(), tcx),
|
||||
};
|
||||
let stmts: Vec<_> = targets
|
||||
.iter()
|
||||
.map(|(case, bb)| (case, simplify_match.body.basic_blocks[bb].statements.as_slice()))
|
||||
.collect();
|
||||
let reachable_cases: Vec<_> =
|
||||
targets.iter().filter(|&(_, bb)| !body.basic_blocks[bb].is_empty_unreachable()).collect();
|
||||
let mut new_stmts = Vec::new();
|
||||
let otherwise_stmts = if body.basic_blocks[targets.otherwise()].is_empty_unreachable() {
|
||||
let otherwise = if body.basic_blocks[targets.otherwise()].is_empty_unreachable() {
|
||||
None
|
||||
} else {
|
||||
Some(body.basic_blocks[targets.otherwise()].statements.as_slice())
|
||||
Some(targets.otherwise())
|
||||
};
|
||||
// We can patch the terminator to goto because there is a single target.
|
||||
match (&reachable_cases[..], otherwise) {
|
||||
(&[(_, single_target)], None) | (&[], Some(single_target)) => {
|
||||
let mut patch = simplify_match.patch;
|
||||
patch.patch_terminator(switch_bb, TerminatorKind::Goto { target: single_target });
|
||||
patch.apply(body);
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let Some(&(_, first_case_bb)) = reachable_cases.first() else {
|
||||
return false;
|
||||
};
|
||||
let first_case_bb = targets.all_targets()[0];
|
||||
let stmt_len = body.basic_blocks[first_case_bb].statements.len();
|
||||
let mut cases = Vec::with_capacity(stmt_len);
|
||||
// Check at each position in the basic blocks whether these statements can be merged.
|
||||
// Check at each position in the basic blocks whether these statements can be unified.
|
||||
for index in 0..stmt_len {
|
||||
let otherwise = otherwise_stmts.map(|stmt| &stmt[index].kind);
|
||||
cases.clear();
|
||||
for &(case, stmts) in &stmts {
|
||||
cases.push((case, &stmts[index].kind));
|
||||
let otherwise = otherwise.map(|bb| &body.basic_blocks[bb].statements[index].kind);
|
||||
for &(case, bb) in &reachable_cases {
|
||||
cases.push((case, &body.basic_blocks[bb].statements[index].kind));
|
||||
}
|
||||
let Some(new_stmt) = simplify_match.try_merge_stmts(index, cases.as_slice(), otherwise)
|
||||
else {
|
||||
let Some(new_stmt) = simplify_match.try_unify_stmts(index, &cases, otherwise) else {
|
||||
return false;
|
||||
};
|
||||
new_stmts.push(new_stmt);
|
||||
|
||||
-12
@@ -4,7 +4,6 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
|
||||
debug slf => _1;
|
||||
let mut _0: T;
|
||||
scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
|
||||
let mut _2: isize;
|
||||
scope 2 {
|
||||
}
|
||||
scope 3 (inlined #[track_caller] unreachable_unchecked) {
|
||||
@@ -16,18 +15,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
_2 = discriminant(_1);
|
||||
switchInt(move _2) -> [0: bb2, 1: bb1, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = copy ((_1 as Some).0: T);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
-12
@@ -4,7 +4,6 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
|
||||
debug slf => _1;
|
||||
let mut _0: T;
|
||||
scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) {
|
||||
let mut _2: isize;
|
||||
scope 2 {
|
||||
}
|
||||
scope 3 (inlined #[track_caller] unreachable_unchecked) {
|
||||
@@ -16,18 +15,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
_2 = discriminant(_1);
|
||||
switchInt(move _2) -> [0: bb2, 1: bb1, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = copy ((_1 as Some).0: T);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
- // MIR for `match_option` before MatchBranchSimplification
|
||||
+ // MIR for `match_option` after MatchBranchSimplification
|
||||
|
||||
fn match_option(_1: &Option<i32>) -> Option<i32> {
|
||||
debug i => _1;
|
||||
let mut _0: std::option::Option<i32>;
|
||||
let mut _2: isize;
|
||||
|
||||
bb0: {
|
||||
_2 = discriminant((*_1));
|
||||
- switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
|
||||
- }
|
||||
-
|
||||
- bb1: {
|
||||
- unreachable;
|
||||
- }
|
||||
-
|
||||
- bb2: {
|
||||
- _0 = Option::<i32>::None;
|
||||
- goto -> bb4;
|
||||
- }
|
||||
-
|
||||
- bb3: {
|
||||
_0 = copy (*_1);
|
||||
- goto -> bb4;
|
||||
- }
|
||||
-
|
||||
- bb4: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
- // MIR for `match_option2_mut` before MatchBranchSimplification
|
||||
+ // MIR for `match_option2_mut` after MatchBranchSimplification
|
||||
|
||||
fn match_option2_mut(_1: &mut Option2<i32>) -> Option2<i32> {
|
||||
let mut _0: Option2<i32>;
|
||||
let mut _2: isize;
|
||||
|
||||
bb0: {
|
||||
_2 = discriminant((*_1));
|
||||
switchInt(copy _2) -> [0: bb1, 1: bb2, 2: bb3, otherwise: bb4];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
(*_1) = Option2::<i32>::None2;
|
||||
_0 = Option2::<i32>::None1;
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
(*_1) = Option2::<i32>::None2;
|
||||
_0 = Option2::<i32>::None2;
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
(*_1) = Option2::<i32>::None2;
|
||||
_0 = copy (*_1);
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,6 +675,23 @@ fn match_i128_u128(i: EnumAi128) -> u128 {
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR matches_reduce_branches.match_option.MatchBranchSimplification.diff
|
||||
fn match_option(i: &Option<i32>) -> Option<i32> {
|
||||
// CHECK-LABEL: fn match_option(
|
||||
// CHECK-NOT: switchInt
|
||||
// CHECK: _0 = copy (*_1);
|
||||
match i {
|
||||
Some(_) => *i,
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
enum Option2<T> {
|
||||
None1,
|
||||
None2,
|
||||
Some(T),
|
||||
}
|
||||
|
||||
// EMIT_MIR matches_reduce_branches.single_case.MatchBranchSimplification.diff
|
||||
#[custom_mir(dialect = "runtime")]
|
||||
fn single_case(i: Option<i32>) -> i32 {
|
||||
@@ -698,6 +715,47 @@ fn single_case(i: Option<i32>) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot dereference `i` after the value has been changed.
|
||||
// EMIT_MIR matches_reduce_branches.match_option2_mut.MatchBranchSimplification.diff
|
||||
#[custom_mir(dialect = "runtime")]
|
||||
fn match_option2_mut(i: &mut Option2<i32>) -> Option2<i32> {
|
||||
// CHECK-LABEL: fn match_option2_mut(
|
||||
// CHECK: switchInt
|
||||
// CHECK: return
|
||||
mir! {
|
||||
{
|
||||
let discr = Discriminant(*i);
|
||||
match discr {
|
||||
0 => none1_bb,
|
||||
1 => none2_bb,
|
||||
2 => some_bb,
|
||||
_ => unreachable_bb,
|
||||
}
|
||||
}
|
||||
none1_bb = {
|
||||
*i = Option2::None2;
|
||||
RET = Option2::None1;
|
||||
Goto(ret)
|
||||
}
|
||||
none2_bb = {
|
||||
*i = Option2::None2;
|
||||
RET = Option2::None2;
|
||||
Goto(ret)
|
||||
}
|
||||
some_bb = {
|
||||
*i = Option2::None2;
|
||||
RET = *i;
|
||||
Goto(ret)
|
||||
}
|
||||
unreachable_bb = {
|
||||
Unreachable()
|
||||
}
|
||||
ret = {
|
||||
Return()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff
|
||||
#[custom_mir(dialect = "runtime")]
|
||||
fn match_non_int_failed(i: char) -> u8 {
|
||||
@@ -767,4 +825,6 @@ fn main() {
|
||||
|
||||
let _ = my_is_some(None);
|
||||
let _ = match_non_int_failed('a');
|
||||
let _ = match_option(&None);
|
||||
let _ = match_option2_mut(&mut Option2::None1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
//@ [COPY] compile-flags: --cfg=copy
|
||||
//@ revisions: COPY CLONE
|
||||
|
||||
// Test case from https://github.com/rust-lang/rust/issues/128081.
|
||||
// Ensure both Copy and Clone get optimized copy.
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn intra_clone(intra: &Av1BlockIntra) -> Av1BlockIntraInter {
|
||||
// CHECK-LABEL: fn intra_clone(
|
||||
// CHECK: [[C:_.*]] = copy (*_1);
|
||||
// CHECK: _0 = Av1BlockIntraInter::Intra(move [[C]]);
|
||||
Av1BlockIntraInter::Intra(intra.clone())
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn inter_clone(inter: &Av1BlockInter) -> Av1BlockIntraInter {
|
||||
// CHECK-LABEL: fn inter_clone(
|
||||
// CHECK: [[C:_.*]] = copy (*_1);
|
||||
// CHECK: _0 = Av1BlockIntraInter::Inter(move [[C]]);
|
||||
Av1BlockIntraInter::Inter(inter.clone())
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn dav1dsequenceheader_copy(v: &Dav1dSequenceHeader) -> Dav1dSequenceHeader {
|
||||
// CHECK-LABEL: fn dav1dsequenceheader_copy(
|
||||
// CHECK: _0 = copy (*_1);
|
||||
v.clone()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct mv {
|
||||
pub y: i16,
|
||||
pub x: i16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct MaskedInterIntraPredMode(u8);
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(copy, derive(Copy))]
|
||||
#[repr(C)]
|
||||
pub struct Av1BlockInter1d {
|
||||
pub mv: [mv; 2],
|
||||
pub wedge_idx: u8,
|
||||
pub mask_sign: u8,
|
||||
pub interintra_mode: MaskedInterIntraPredMode,
|
||||
pub _padding: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(copy, derive(Copy))]
|
||||
#[repr(C)]
|
||||
pub struct Av1BlockInterNd {
|
||||
pub one_d: Av1BlockInter1d,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CompInterType {
|
||||
WeightedAvg = 1,
|
||||
Avg = 2,
|
||||
Seg = 3,
|
||||
Wedge = 4,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum MotionMode {
|
||||
Translation = 0,
|
||||
Obmc = 1,
|
||||
Warp = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DrlProximity {
|
||||
Nearest,
|
||||
Nearer,
|
||||
Near,
|
||||
Nearish,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum TxfmSize {
|
||||
S4x4 = 0,
|
||||
S8x8 = 1,
|
||||
S16x16 = 2,
|
||||
S32x32 = 3,
|
||||
S64x64 = 4,
|
||||
R4x8 = 5,
|
||||
R8x4 = 6,
|
||||
R8x16 = 7,
|
||||
R16x8 = 8,
|
||||
R16x32 = 9,
|
||||
R32x16 = 10,
|
||||
R32x64 = 11,
|
||||
R64x32 = 12,
|
||||
R4x16 = 13,
|
||||
R16x4 = 14,
|
||||
R8x32 = 15,
|
||||
R32x8 = 16,
|
||||
R16x64 = 17,
|
||||
R64x16 = 18,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Filter2d {
|
||||
Regular8Tap = 0,
|
||||
RegularSmooth8Tap = 1,
|
||||
RegularSharp8Tap = 2,
|
||||
SharpRegular8Tap = 3,
|
||||
SharpSmooth8Tap = 4,
|
||||
Sharp8Tap = 5,
|
||||
SmoothRegular8Tap = 6,
|
||||
Smooth8Tap = 7,
|
||||
SmoothSharp8Tap = 8,
|
||||
Bilinear = 9,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum InterIntraType {
|
||||
Blend,
|
||||
Wedge,
|
||||
}
|
||||
|
||||
#[cfg_attr(copy, derive(Copy))]
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Av1BlockInter {
|
||||
pub nd: Av1BlockInterNd,
|
||||
pub comp_type: Option<CompInterType>,
|
||||
pub inter_mode: u8,
|
||||
pub motion_mode: MotionMode,
|
||||
pub drl_idx: DrlProximity,
|
||||
pub r#ref: [i8; 2],
|
||||
pub max_ytx: TxfmSize,
|
||||
pub filter2d: Filter2d,
|
||||
pub interintra_type: Option<InterIntraType>,
|
||||
pub tx_split0: u8,
|
||||
pub tx_split1: u16,
|
||||
}
|
||||
|
||||
#[cfg_attr(copy, derive(Copy))]
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Av1BlockIntra {
|
||||
pub y_mode: u8,
|
||||
pub uv_mode: u8,
|
||||
pub tx: TxfmSize,
|
||||
pub pal_sz: [u8; 2],
|
||||
pub y_angle: i8,
|
||||
pub uv_angle: i8,
|
||||
pub cfl_alpha: [i8; 2],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum Av1BlockIntraInter {
|
||||
Intra(Av1BlockIntra),
|
||||
Inter(Av1BlockInter),
|
||||
}
|
||||
|
||||
use std::ffi::{c_int, c_uint};
|
||||
|
||||
pub type Dav1dPixelLayout = c_uint;
|
||||
pub type Dav1dColorPrimaries = c_uint;
|
||||
pub type Dav1dTransferCharacteristics = c_uint;
|
||||
pub type Dav1dMatrixCoefficients = c_uint;
|
||||
pub type Dav1dChromaSamplePosition = c_uint;
|
||||
pub type Dav1dAdaptiveBoolean = c_uint;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct Dav1dSequenceHeaderOperatingPoint {
|
||||
pub major_level: u8,
|
||||
pub minor_level: u8,
|
||||
pub initial_display_delay: u8,
|
||||
pub idc: u16,
|
||||
pub tier: u8,
|
||||
pub decoder_model_param_present: u8,
|
||||
pub display_model_param_present: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct Dav1dSequenceHeaderOperatingParameterInfo {
|
||||
pub decoder_buffer_delay: u32,
|
||||
pub encoder_buffer_delay: u32,
|
||||
pub low_delay_mode: u8,
|
||||
}
|
||||
|
||||
pub const DAV1D_MAX_OPERATING_POINTS: usize = 32;
|
||||
|
||||
#[cfg_attr(copy, derive(Copy))]
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Dav1dSequenceHeader {
|
||||
pub profile: u8,
|
||||
pub max_width: c_int,
|
||||
pub max_height: c_int,
|
||||
pub layout: Dav1dPixelLayout,
|
||||
pub pri: Dav1dColorPrimaries,
|
||||
pub trc: Dav1dTransferCharacteristics,
|
||||
pub mtrx: Dav1dMatrixCoefficients,
|
||||
pub chr: Dav1dChromaSamplePosition,
|
||||
pub hbd: u8,
|
||||
pub color_range: u8,
|
||||
pub num_operating_points: u8,
|
||||
pub operating_points: [Dav1dSequenceHeaderOperatingPoint; DAV1D_MAX_OPERATING_POINTS],
|
||||
pub still_picture: u8,
|
||||
pub reduced_still_picture_header: u8,
|
||||
pub timing_info_present: u8,
|
||||
pub num_units_in_tick: u32,
|
||||
pub time_scale: u32,
|
||||
pub equal_picture_interval: u8,
|
||||
pub num_ticks_per_picture: u32,
|
||||
pub decoder_model_info_present: u8,
|
||||
pub encoder_decoder_buffer_delay_length: u8,
|
||||
pub num_units_in_decoding_tick: u32,
|
||||
pub buffer_removal_delay_length: u8,
|
||||
pub frame_presentation_delay_length: u8,
|
||||
pub display_model_info_present: u8,
|
||||
pub width_n_bits: u8,
|
||||
pub height_n_bits: u8,
|
||||
pub frame_id_numbers_present: u8,
|
||||
pub delta_frame_id_n_bits: u8,
|
||||
pub frame_id_n_bits: u8,
|
||||
pub sb128: u8,
|
||||
pub filter_intra: u8,
|
||||
pub intra_edge_filter: u8,
|
||||
pub inter_intra: u8,
|
||||
pub masked_compound: u8,
|
||||
pub warped_motion: u8,
|
||||
pub dual_filter: u8,
|
||||
pub order_hint: u8,
|
||||
pub jnt_comp: u8,
|
||||
pub ref_frame_mvs: u8,
|
||||
pub screen_content_tools: Dav1dAdaptiveBoolean,
|
||||
pub force_integer_mv: Dav1dAdaptiveBoolean,
|
||||
pub order_hint_n_bits: u8,
|
||||
pub super_res: u8,
|
||||
pub cdef: u8,
|
||||
pub restoration: u8,
|
||||
pub ss_hor: u8,
|
||||
pub ss_ver: u8,
|
||||
pub monochrome: u8,
|
||||
pub color_description_present: u8,
|
||||
pub separate_uv_delta_q: u8,
|
||||
pub film_grain_present: u8,
|
||||
pub operating_parameter_info:
|
||||
[Dav1dSequenceHeaderOperatingParameterInfo; DAV1D_MAX_OPERATING_POINTS],
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
fn ub_if_b(_1: Thing) -> Thing {
|
||||
debug t => _1;
|
||||
let mut _0: Thing;
|
||||
let mut _2: isize;
|
||||
scope 1 (inlined #[track_caller] unreachable_unchecked) {
|
||||
scope 2 (inlined core::ub_checks::check_language_ub) {
|
||||
scope 3 (inlined core::ub_checks::check_language_ub::runtime) {
|
||||
@@ -12,16 +11,7 @@ fn ub_if_b(_1: Thing) -> Thing {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_2 = discriminant(_1);
|
||||
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = move _1;
|
||||
return;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-15
@@ -4,11 +4,11 @@ fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
|
||||
debug v => _1;
|
||||
let mut _0: i32;
|
||||
let mut _2: std::option::Option<i32>;
|
||||
let _4: i32;
|
||||
let _3: i32;
|
||||
scope 1 {
|
||||
debug v1 => _4;
|
||||
debug v1 => _3;
|
||||
scope 2 {
|
||||
debug v2 => _4;
|
||||
debug v2 => _3;
|
||||
}
|
||||
scope 8 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
|
||||
scope 9 {
|
||||
@@ -22,7 +22,6 @@ fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
|
||||
}
|
||||
}
|
||||
scope 3 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
|
||||
let mut _3: isize;
|
||||
scope 4 {
|
||||
}
|
||||
scope 5 (inlined #[track_caller] unreachable_unchecked) {
|
||||
@@ -35,17 +34,8 @@ fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
|
||||
|
||||
bb0: {
|
||||
_2 = copy (*_1);
|
||||
_3 = discriminant(_2);
|
||||
switchInt(copy _3) -> [0: bb2, 1: bb1, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_4 = copy ((_2 as Some).0: i32);
|
||||
_0 = Add(copy _4, copy _4);
|
||||
_3 = copy ((_2 as Some).0: i32);
|
||||
_0 = Add(copy _3, copy _3);
|
||||
return;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user