Auto merge of #127731 - veluca93:abi_checks, r= · rust-lang/rust@7587ff3 (original) (raw)

``

1

`+

use rustc_abi::Abi;

`

``

2

`+

use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};

`

``

3

`+

use rustc_span::{def_id::DefId, Span, Symbol};

`

``

4

`+

use rustc_target::abi:🤙:{FnAbi, PassMode};

`

``

5

+

``

6

`+

use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef};

`

``

7

+

``

8

`+

const SSE_FEATURES: &'static [&'static str] = &["sse", "sse2", "ssse3", "sse3", "sse4.1", "sse4.2"];

`

``

9

`+

const AVX_FEATURES: &'static [&'static str] = &["avx", "avx2", "f16c", "fma"];

`

``

10

`+

const AVX512_FEATURES: &'static [&'static str] = &[

`

``

11

`+

"avx512f",

`

``

12

`+

"avx512bw",

`

``

13

`+

"avx512cd",

`

``

14

`+

"avx512er",

`

``

15

`+

"avx512pf",

`

``

16

`+

"avx512vl",

`

``

17

`+

"avx512dq",

`

``

18

`+

"avx512ifma",

`

``

19

`+

"avx512vbmi",

`

``

20

`+

"avx512vnni",

`

``

21

`+

"avx512bitalg",

`

``

22

`+

"avx512vpopcntdq",

`

``

23

`+

"avx512bf16",

`

``

24

`+

"avx512vbmi2",

`

``

25

`+

];

`

``

26

+

``

27

`+

fn do_check_abi<'tcx>(

`

``

28

`+

tcx: TyCtxt<'tcx>,

`

``

29

`+

abi: &FnAbi<'tcx, Ty<'tcx>>,

`

``

30

`+

target_feature_def: DefId,

`

``

31

`+

emit_err: impl Fn(&'static str),

`

``

32

`+

) {

`

``

33

`+

// FIXME: add support for other architectures

`

``

34

`+

if tcx.sess.target.arch != "x86" && tcx.sess.target.arch != "x86_64" {

`

``

35

`+

return;

`

``

36

`+

}

`

``

37

`+

let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);

`

``

38

`+

for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {

`

``

39

`+

let size = arg_abi.layout.size;

`

``

40

`+

if matches!(arg_abi.layout.abi, Abi::Vector { .. })

`

``

41

`+

&& matches!(arg_abi.mode, PassMode::Direct(_))

`

``

42

`+

{

`

``

43

`+

let features: &[_] = match size.bits() {

`

``

44

`+

x if x <= 128 => &[SSE_FEATURES, AVX_FEATURES, AVX512_FEATURES],

`

``

45

`+

x if x <= 256 => &[AVX_FEATURES, AVX512_FEATURES],

`

``

46

`+

x if x <= 512 => &[AVX512_FEATURES],

`

``

47

`+

_ => {

`

``

48

`+

panic!("Unknown vector size for x86: {}; arg = {:?}", size.bits(), arg_abi)

`

``

49

`+

}

`

``

50

`+

};

`

``

51

`+

let required_feature = features.iter().map(|x| x.iter()).flatten().next().unwrap();

`

``

52

`+

if !features.iter().map(|x| x.iter()).flatten().any(|feature| {

`

``

53

`+

let required_feature_sym = Symbol::intern(feature);

`

``

54

`+

tcx.sess.unstable_target_features.contains(&required_feature_sym)

`

``

55

`+

|| codegen_attrs.target_features.contains(&required_feature_sym)

`

``

56

`+

}) {

`

``

57

`+

emit_err(required_feature);

`

``

58

`+

}

`

``

59

`+

}

`

``

60

`+

}

`

``

61

`+

}

`

``

62

+

``

63

`+

/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments

`

``

64

`+

/// or return values for which the corresponding target feature is not enabled.

`

``

65

`+

pub fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {

`

``

66

`+

let param_env = ParamEnv::reveal_all();

`

``

67

`+

let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else {

`

``

68

`+

// An error will be reported during codegen if we cannot determine the ABI of this

`

``

69

`+

// function.

`

``

70

`+

return;

`

``

71

`+

};

`

``

72

`+

do_check_abi(tcx, abi, instance.def_id(), |required_feature| {

`

``

73

`+

tcx.dcx().emit_err(AbiErrorDisabledVectorTypeDef {

`

``

74

`+

span: tcx.def_span(instance.def_id()),

`

``

75

`+

required_feature,

`

``

76

`+

});

`

``

77

`+

})

`

``

78

`+

}

`

``

79

+

``

80

`+

/// Checks that a call expression does not try to pass a vector-passed argument which requires a

`

``

81

`+

/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch.

`

``

82

`+

pub fn check_call_site_abi<'tcx>(

`

``

83

`+

tcx: TyCtxt<'tcx>,

`

``

84

`+

ty: Ty<'tcx>,

`

``

85

`+

span: Span,

`

``

86

`+

caller: InstanceKind<'tcx>,

`

``

87

`+

) {

`

``

88

`+

let param_env = ParamEnv::reveal_all();

`

``

89

`+

let callee_abi = match *ty.kind() {

`

``

90

`+

ty::FnPtr(sig) => tcx.fn_abi_of_fn_ptr(param_env.and((sig, ty::List::empty()))),

`

``

91

`+

ty::FnDef(def_id, args) => {

`

``

92

`+

// Intrinsics are handled separately by the compiler.

`

``

93

`+

if tcx.intrinsic(def_id).is_some() {

`

``

94

`+

return;

`

``

95

`+

}

`

``

96

`+

let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, span);

`

``

97

`+

tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty())))

`

``

98

`+

}

`

``

99

`+

_ => {

`

``

100

`+

panic!("Invalid function call");

`

``

101

`+

}

`

``

102

`+

};

`

``

103

+

``

104

`+

let Ok(callee_abi) = callee_abi else {

`

``

105

`+

// ABI failed to compute; this will not get through codegen.

`

``

106

`+

return;

`

``

107

`+

};

`

``

108

`+

do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| {

`

``

109

`+

tcx.dcx().emit_err(AbiErrorDisabledVectorTypeCall { span, required_feature });

`

``

110

`+

})

`

``

111

`+

}

`