|
| 1 | +//! We would like to try add `noundef` to small immediate arguments (the heuristic here is if the |
| 2 | +//! immediate argument fits within target pointer width) where possible and legal. Adding `noundef` |
| 3 | +//! attribute is legal iff the immediate argument do not have padding (indeterminate value |
| 4 | +//! otherwise). Only simple immediates are considered currently (trivially no padding), but could be |
| 5 | +//! potentially expanded to other small aggregate immediates that do not have padding (subject to |
| 6 | +//! being able to correctly calculate "no padding"). |
| 7 | +//! |
| 8 | +//! - We should recursively see through `#[repr(transparent)]` and `#[repr(Rust)]` layouts. |
| 9 | +//! - Unions cannot have `noundef` because all unions are currently allowed to be `undef`. This |
| 10 | +//! property is "infectious", anything that contains unions also may not have `noundef` applied. |
| 11 | +
|
| 12 | +// ignore-tidy-linelength |
| 13 | + |
| 14 | +#![crate_type = "lib"] |
| 15 | + |
| 16 | +//@ compile-flags: -C no-prepopulate-passes |
| 17 | + |
| 18 | +// We setup two revisions to check that `noundef` is only added when optimization is enabled. |
| 19 | +//@ revisions: NoOpt Opt |
| 20 | +//@ [NoOpt] compile-flags: -C opt-level=0 |
| 21 | +//@ [Opt] compile-flags: -O |
| 22 | + |
| 23 | +// Presence of `noundef` depends on target pointer width (it's only applied when the immediate fits |
| 24 | +// within target pointer width). |
| 25 | +//@ only-64bit |
| 26 | + |
| 27 | +// ------------------------------------------------------------------------------------------------- |
| 28 | + |
| 29 | +// # Positive test cases |
| 30 | +// |
| 31 | +// - Simple arrays of primitive types whose size fits within target pointer width (referred to as |
| 32 | +// "simple arrays" for the following positive test cases). |
| 33 | +// - `#[repr(transparent)]` ADTs which eventually contain simple arrays. |
| 34 | +// - `#[repr(Rust)]` ADTs which eventually contain simple arrays. This relies on rustc layout |
| 35 | +// behavior, and is not guaranteed by `#[repr(Rust)]`. |
| 36 | + |
| 37 | +// ## Simple arrays |
| 38 | + |
| 39 | +// NoOpt: define i64 @short_array_u64x1(i64 %{{.*}}) |
| 40 | +// Opt: define noundef i64 @short_array_u64x1(i64 noundef %{{.*}}) |
| 41 | +#[no_mangle] |
| 42 | +pub fn short_array_u64x1(v: [u64; 1]) -> [u64; 1] { |
| 43 | + v |
| 44 | +} |
| 45 | + |
| 46 | +// NoOpt: define i32 @short_array_u32x1(i32 %{{.*}}) |
| 47 | +// Opt: define noundef i32 @short_array_u32x1(i32 noundef %{{.*}}) |
| 48 | +#[no_mangle] |
| 49 | +pub fn short_array_u32x1(v: [u32; 1]) -> [u32; 1] { |
| 50 | + v |
| 51 | +} |
| 52 | + |
| 53 | +// NoOpt: define i64 @short_array_u32x2(i64 %{{.*}}) |
| 54 | +// Opt: define noundef i64 @short_array_u32x2(i64 noundef %{{.*}}) |
| 55 | +#[no_mangle] |
| 56 | +pub fn short_array_u32x2(v: [u32; 2]) -> [u32; 2] { |
| 57 | + v |
| 58 | +} |
| 59 | + |
| 60 | +// NoOpt: define i16 @short_array_u16x1(i16 %{{.*}}) |
| 61 | +// Opt: define noundef i16 @short_array_u16x1(i16 noundef %{{.*}}) |
| 62 | +#[no_mangle] |
| 63 | +pub fn short_array_u16x1(v: [u16; 1]) -> [u16; 1] { |
| 64 | + v |
| 65 | +} |
| 66 | + |
| 67 | +// NoOpt: define i32 @short_array_u16x2(i32 %{{.*}}) |
| 68 | +// Opt: define noundef i32 @short_array_u16x2(i32 noundef %{{.*}}) |
| 69 | +#[no_mangle] |
| 70 | +pub fn short_array_u16x2(v: [u16; 2]) -> [u16; 2] { |
| 71 | + v |
| 72 | +} |
| 73 | + |
| 74 | +// NoOpt: define i48 @short_array_u16x3(i48 %{{.*}}) |
| 75 | +// Opt: define noundef i48 @short_array_u16x3(i48 noundef %{{.*}}) |
| 76 | +#[no_mangle] |
| 77 | +pub fn short_array_u16x3(v: [u16; 3]) -> [u16; 3] { |
| 78 | + v |
| 79 | +} |
| 80 | + |
| 81 | +// NoOpt: define i64 @short_array_u16x4(i64 %{{.*}}) |
| 82 | +// Opt: define noundef i64 @short_array_u16x4(i64 noundef %{{.*}}) |
| 83 | +#[no_mangle] |
| 84 | +pub fn short_array_u16x4(v: [u16; 4]) -> [u16; 4] { |
| 85 | + v |
| 86 | +} |
| 87 | + |
| 88 | +// NoOpt: define i8 @short_array_u8x1(i8 %{{.*}}) |
| 89 | +// Opt: define noundef i8 @short_array_u8x1(i8 noundef %{{.*}}) |
| 90 | +#[no_mangle] |
| 91 | +pub fn short_array_u8x1(v: [u8; 1]) -> [u8; 1] { |
| 92 | + v |
| 93 | +} |
| 94 | + |
| 95 | +// NoOpt: define i16 @short_array_u8x2(i16 %{{.*}}) |
| 96 | +// Opt: define noundef i16 @short_array_u8x2(i16 noundef %{{.*}}) |
| 97 | +#[no_mangle] |
| 98 | +pub fn short_array_u8x2(v: [u8; 2]) -> [u8; 2] { |
| 99 | + v |
| 100 | +} |
| 101 | + |
| 102 | +// NoOpt: define i24 @short_array_u8x3(i24 %{{.*}}) |
| 103 | +// Opt: define noundef i24 @short_array_u8x3(i24 noundef %{{.*}}) |
| 104 | +#[no_mangle] |
| 105 | +pub fn short_array_u8x3(v: [u8; 3]) -> [u8; 3] { |
| 106 | + v |
| 107 | +} |
| 108 | + |
| 109 | +// NoOpt: define i64 @short_array_u8x8(i64 %{{.*}}) |
| 110 | +// Opt: define noundef i64 @short_array_u8x8(i64 noundef %{{.*}}) |
| 111 | +#[no_mangle] |
| 112 | +pub fn short_array_u8x8(v: [u8; 8]) -> [u8; 8] { |
| 113 | + v |
| 114 | +} |
| 115 | + |
| 116 | +// ## Small `#[repr(transparent)]` wrappers |
| 117 | + |
| 118 | +#[repr(transparent)] |
| 119 | +pub struct TransparentWrapper([u8; 4]); |
| 120 | + |
| 121 | +// NoOpt: define i32 @repr_transparent_wrapper(i32 %{{.*}}) |
| 122 | +// Opt: define noundef i32 @repr_transparent_wrapper(i32 noundef %{{.*}}) |
| 123 | +#[no_mangle] |
| 124 | +pub fn repr_transparent_wrapper(v: TransparentWrapper) -> TransparentWrapper { |
| 125 | + v |
| 126 | +} |
| 127 | + |
| 128 | +#[repr(transparent)] |
| 129 | +pub struct RecursiveTransparentWrapper(TransparentWrapper); |
| 130 | + |
| 131 | +// NoOpt: define i32 @recursive_repr_transparent_wrapper(i32 %{{.*}}) |
| 132 | +// Opt: define noundef i32 @recursive_repr_transparent_wrapper(i32 noundef %{{.*}}) |
| 133 | +#[no_mangle] |
| 134 | +pub fn recursive_repr_transparent_wrapper( |
| 135 | + v: RecursiveTransparentWrapper, |
| 136 | +) -> RecursiveTransparentWrapper { |
| 137 | + v |
| 138 | +} |
| 139 | + |
| 140 | +// ## Small `#[repr(Rust)]` wrappers |
| 141 | +// |
| 142 | +// Note that this relies on rustc self-consistency in handling simple `#[repr(Rust)]` wrappers, i.e. |
| 143 | +// that `struct Foo([u8; 4])` has the same layout as its sole inner member and that no additional |
| 144 | +// padding is introduced. |
| 145 | + |
| 146 | +pub struct ReprRustWrapper([u8; 4]); |
| 147 | + |
| 148 | +// NoOpt: define i32 @repr_rust_wrapper(i32 %{{.*}}) |
| 149 | +// Opt: define noundef i32 @repr_rust_wrapper(i32 noundef %{{.*}}) |
| 150 | +#[no_mangle] |
| 151 | +pub fn repr_rust_wrapper(v: ReprRustWrapper) -> ReprRustWrapper { |
| 152 | + v |
| 153 | +} |
| 154 | + |
| 155 | +// ## Cases not handled |
| 156 | +// |
| 157 | +// - Aggregates that have no padding and fits within target pointer width which are not simple |
| 158 | +// arrays. Potentially aggregates such as tuples `(u32, u32)`. This is left as an exercise to the |
| 159 | +// reader (follow-up welcomed) :) |
| 160 | + |
| 161 | +// No `noundef` annotation on return `{i32, i32}`, but argument does (when optimizations enabled). |
| 162 | +// NoOpt: define { i32, i32 } @unhandled_small_pair_ret(i32 %v.0, i32 %v.1) |
| 163 | +// Opt: define { i32, i32 } @unhandled_small_pair_ret(i32 noundef %v.0, i32 noundef %v.1) |
| 164 | +#[no_mangle] |
| 165 | +pub fn unhandled_small_pair_ret(v: (u32, u32)) -> (u32, u32) { |
| 166 | + v |
| 167 | +} |
| 168 | + |
| 169 | +// ------------------------------------------------------------------------------------------------- |
| 170 | + |
| 171 | +// # Negative test cases () |
| 172 | +// |
| 173 | +// - Other representations (not `transparent` or `Rust`) |
| 174 | +// - Unions cannot have `noundef` because they are allowed to be `undef`. |
| 175 | +// - Array of unions still contains unions, so they cannot have `noundef` |
| 176 | +// - Transparent unions are still unions, so they cannot have `noundef` |
| 177 | + |
| 178 | +// ## Other representations |
| 179 | + |
| 180 | +#[repr(C)] |
| 181 | +pub struct ReprCWrapper([u8; 4]); |
| 182 | + |
| 183 | +// NoOpt: define i32 @repr_c_immediate(i32 %0) |
| 184 | +// Opt: define i32 @repr_c_immediate(i32 %0) |
| 185 | +#[no_mangle] |
| 186 | +pub fn repr_c_immediate(v: ReprCWrapper) -> ReprCWrapper { |
| 187 | + v |
| 188 | +} |
| 189 | + |
| 190 | +// ## Unions |
| 191 | + |
| 192 | +union U { |
| 193 | + u1: u64, |
| 194 | + u2: [u8; 4], |
| 195 | +} |
| 196 | + |
| 197 | +// All unions can be `undef`, must not have `noundef` as immediate argument. |
| 198 | +// NoOpt: define i64 @union_immediate(i64 %0) |
| 199 | +// Opt: define i64 @union_immediate(i64 %0) |
| 200 | +#[no_mangle] |
| 201 | +pub fn union_immediate(v: U) -> U { |
| 202 | + v |
| 203 | +} |
| 204 | + |
| 205 | +// ## Array of unions |
| 206 | +// |
| 207 | +// Cannot have `noundef` because tainted by unions. |
| 208 | + |
| 209 | +union SmallButDangerous { |
| 210 | + u1: [u8; 2], |
| 211 | + u2: u16, |
| 212 | +} |
| 213 | + |
| 214 | +// NoOpt: define i16 @one_elem_array_of_unions(i16 %0) |
| 215 | +// Opt: define i16 @one_elem_array_of_unions(i16 %0) |
| 216 | +#[no_mangle] |
| 217 | +pub fn one_elem_array_of_unions(v: [SmallButDangerous; 1]) -> [SmallButDangerous; 1] { |
| 218 | + v |
| 219 | +} |
| 220 | + |
| 221 | +// NoOpt: define i32 @two_elem_array_of_unions(i32 %0) |
| 222 | +// Opt: define i32 @two_elem_array_of_unions(i32 %0) |
| 223 | +#[no_mangle] |
| 224 | +pub fn two_elem_array_of_unions(v: [SmallButDangerous; 2]) -> [SmallButDangerous; 2] { |
| 225 | + v |
| 226 | +} |
| 227 | + |
| 228 | +// # `#[repr(transparent)]` unions |
| 229 | + |
| 230 | +union Inner { |
| 231 | + i1: u8, |
| 232 | +} |
| 233 | + |
| 234 | +#[repr(transparent)] |
| 235 | +pub struct TransparentUnionWrapper(Inner); |
| 236 | + |
| 237 | +// NoOpt: define i8 @repr_transparent_union(i8 %v) |
| 238 | +// Opt: define i8 @repr_transparent_union(i8 %v) |
| 239 | +#[no_mangle] |
| 240 | +pub fn repr_transparent_union(v: TransparentUnionWrapper) -> TransparentUnionWrapper { |
| 241 | + v |
| 242 | +} |
0 commit comments