1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3 2; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s 3; RUN: llc < %s -mtriple=x86_64-win64 | FileCheck %s 4; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' < %s -mtriple=x86_64-apple-macosx -S | FileCheck %s --check-prefix=OPTALL --check-prefix=OPT --check-prefix=NONSTRESS 5; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' < %s -mtriple=x86_64-apple-macosx -S -stress-cgp-ext-ld-promotion | FileCheck %s --check-prefix=OPTALL --check-prefix=OPT --check-prefix=STRESS 6; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' < %s -mtriple=x86_64-apple-macosx -S -disable-cgp-ext-ld-promotion | FileCheck %s --check-prefix=OPTALL --check-prefix=DISABLE 7 8; rdar://7304838 9; CodeGenPrepare should move the zext into the block with the load 10; so that SelectionDAG can select it with the load. 11; 12; CHECK-LABEL: foo: 13; CHECK: movsbl ({{%rdi|%rcx}}), %eax 14define void @foo(ptr %p, ptr %q) { 15; OPTALL-LABEL: define void @foo( 16; OPTALL-SAME: ptr [[P:%.*]], ptr [[Q:%.*]]) { 17; OPTALL-NEXT: entry: 18; OPTALL-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 19; OPTALL-NEXT: [[S:%.*]] = zext i8 [[T]] to i32 20; OPTALL-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 21; OPTALL-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 22; OPTALL: true: 23; OPTALL-NEXT: store i32 [[S]], ptr [[Q]], align 4 24; OPTALL-NEXT: ret void 25; OPTALL: false: 26; OPTALL-NEXT: ret void 27; 28entry: 29 %t = load i8, ptr %p 30 %a = icmp slt i8 %t, 20 31 br i1 %a, label %true, label %false 32true: 33 %s = zext i8 %t to i32 34 store i32 %s, ptr %q 35 ret void 36false: 37 ret void 38} 39 40; Check that we manage to form a zextload is an operation with only one 41; argument to explicitly extend is in the way. 42; Make sure the operation is not promoted when the promotion pass is disabled. 43define void @promoteOneArg(ptr %p, ptr %q) { 44; OPT-LABEL: define void @promoteOneArg( 45; OPT-SAME: ptr [[P:%.*]], ptr [[Q:%.*]]) { 46; OPT-NEXT: entry: 47; OPT-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 48; OPT-NEXT: [[S:%.*]] = zext i8 [[T]] to i32 49; OPT-NEXT: [[ADD:%.*]] = add nuw i32 [[S]], 2 50; OPT-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 51; OPT-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 52; OPT: true: 53; OPT-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 54; OPT-NEXT: ret void 55; OPT: false: 56; OPT-NEXT: ret void 57; 58; DISABLE-LABEL: define void @promoteOneArg( 59; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]]) { 60; DISABLE-NEXT: entry: 61; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 62; DISABLE-NEXT: [[ADD:%.*]] = add nuw i8 [[T]], 2 63; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 64; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 65; DISABLE: true: 66; DISABLE-NEXT: [[S:%.*]] = zext i8 [[ADD]] to i32 67; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 68; DISABLE-NEXT: ret void 69; DISABLE: false: 70; DISABLE-NEXT: ret void 71; 72entry: 73 %t = load i8, ptr %p 74 %add = add nuw i8 %t, 2 75 %a = icmp slt i8 %t, 20 76 br i1 %a, label %true, label %false 77true: 78 %s = zext i8 %add to i32 79 store i32 %s, ptr %q 80 ret void 81false: 82 ret void 83} 84 85; Check that we manage to form a sextload is an operation with only one 86; argument to explicitly extend is in the way. 87; Version with sext. 88define void @promoteOneArgSExt(ptr %p, ptr %q) { 89; OPT-LABEL: define void @promoteOneArgSExt( 90; OPT-SAME: ptr [[P:%.*]], ptr [[Q:%.*]]) { 91; OPT-NEXT: entry: 92; OPT-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 93; OPT-NEXT: [[S:%.*]] = sext i8 [[T]] to i32 94; OPT-NEXT: [[ADD:%.*]] = add nsw i32 [[S]], 2 95; OPT-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 96; OPT-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 97; OPT: true: 98; OPT-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 99; OPT-NEXT: ret void 100; OPT: false: 101; OPT-NEXT: ret void 102; 103; DISABLE-LABEL: define void @promoteOneArgSExt( 104; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]]) { 105; DISABLE-NEXT: entry: 106; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 107; DISABLE-NEXT: [[ADD:%.*]] = add nsw i8 [[T]], 2 108; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 109; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 110; DISABLE: true: 111; DISABLE-NEXT: [[S:%.*]] = sext i8 [[ADD]] to i32 112; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 113; DISABLE-NEXT: ret void 114; DISABLE: false: 115; DISABLE-NEXT: ret void 116; 117entry: 118 %t = load i8, ptr %p 119 %add = add nsw i8 %t, 2 120 %a = icmp slt i8 %t, 20 121 br i1 %a, label %true, label %false 122true: 123 %s = sext i8 %add to i32 124 store i32 %s, ptr %q 125 ret void 126false: 127 ret void 128} 129 130; Check that we manage to form a zextload is an operation with two 131; arguments to explicitly extend is in the way. 132; Extending %add will create two extensions: 133; 1. One for %b. 134; 2. One for %t. 135; #1 will not be removed as we do not know anything about %b. 136; #2 may not be merged with the load because %t is used in a comparison. 137; Since two extensions may be emitted in the end instead of one before the 138; transformation, the regular heuristic does not apply the optimization. 139define void @promoteTwoArgZext(ptr %p, ptr %q, i8 %b) { 140; NONSTRESS-LABEL: define void @promoteTwoArgZext( 141; NONSTRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]]) { 142; NONSTRESS-NEXT: entry: 143; NONSTRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 144; NONSTRESS-NEXT: [[ADD:%.*]] = add nuw i8 [[T]], [[B]] 145; NONSTRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 146; NONSTRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 147; NONSTRESS: true: 148; NONSTRESS-NEXT: [[S:%.*]] = zext i8 [[ADD]] to i32 149; NONSTRESS-NEXT: store i32 [[S]], ptr [[Q]], align 4 150; NONSTRESS-NEXT: ret void 151; NONSTRESS: false: 152; NONSTRESS-NEXT: ret void 153; 154; STRESS-LABEL: define void @promoteTwoArgZext( 155; STRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]]) { 156; STRESS-NEXT: entry: 157; STRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 158; STRESS-NEXT: [[S:%.*]] = zext i8 [[T]] to i32 159; STRESS-NEXT: [[PROMOTED:%.*]] = zext i8 [[B]] to i32 160; STRESS-NEXT: [[ADD:%.*]] = add nuw i32 [[S]], [[PROMOTED]] 161; STRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 162; STRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 163; STRESS: true: 164; STRESS-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 165; STRESS-NEXT: ret void 166; STRESS: false: 167; STRESS-NEXT: ret void 168; 169; DISABLE-LABEL: define void @promoteTwoArgZext( 170; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]]) { 171; DISABLE-NEXT: entry: 172; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 173; DISABLE-NEXT: [[ADD:%.*]] = add nuw i8 [[T]], [[B]] 174; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 175; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 176; DISABLE: true: 177; DISABLE-NEXT: [[S:%.*]] = zext i8 [[ADD]] to i32 178; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 179; DISABLE-NEXT: ret void 180; DISABLE: false: 181; DISABLE-NEXT: ret void 182; 183entry: 184 %t = load i8, ptr %p 185 %add = add nuw i8 %t, %b 186 %a = icmp slt i8 %t, 20 187 br i1 %a, label %true, label %false 188true: 189 %s = zext i8 %add to i32 190 store i32 %s, ptr %q 191 ret void 192false: 193 ret void 194} 195 196; Check that we manage to form a sextload is an operation with two 197; arguments to explicitly extend is in the way. 198; Version with sext. 199define void @promoteTwoArgSExt(ptr %p, ptr %q, i8 %b) { 200; NONSTRESS-LABEL: define void @promoteTwoArgSExt( 201; NONSTRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]]) { 202; NONSTRESS-NEXT: entry: 203; NONSTRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 204; NONSTRESS-NEXT: [[ADD:%.*]] = add nsw i8 [[T]], [[B]] 205; NONSTRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 206; NONSTRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 207; NONSTRESS: true: 208; NONSTRESS-NEXT: [[S:%.*]] = sext i8 [[ADD]] to i32 209; NONSTRESS-NEXT: store i32 [[S]], ptr [[Q]], align 4 210; NONSTRESS-NEXT: ret void 211; NONSTRESS: false: 212; NONSTRESS-NEXT: ret void 213; 214; STRESS-LABEL: define void @promoteTwoArgSExt( 215; STRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]]) { 216; STRESS-NEXT: entry: 217; STRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 218; STRESS-NEXT: [[S:%.*]] = sext i8 [[T]] to i32 219; STRESS-NEXT: [[PROMOTED:%.*]] = sext i8 [[B]] to i32 220; STRESS-NEXT: [[ADD:%.*]] = add nsw i32 [[S]], [[PROMOTED]] 221; STRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 222; STRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 223; STRESS: true: 224; STRESS-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 225; STRESS-NEXT: ret void 226; STRESS: false: 227; STRESS-NEXT: ret void 228; 229; DISABLE-LABEL: define void @promoteTwoArgSExt( 230; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]]) { 231; DISABLE-NEXT: entry: 232; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 233; DISABLE-NEXT: [[ADD:%.*]] = add nsw i8 [[T]], [[B]] 234; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 235; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 236; DISABLE: true: 237; DISABLE-NEXT: [[S:%.*]] = sext i8 [[ADD]] to i32 238; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 239; DISABLE-NEXT: ret void 240; DISABLE: false: 241; DISABLE-NEXT: ret void 242; 243entry: 244 %t = load i8, ptr %p 245 %add = add nsw i8 %t, %b 246 %a = icmp slt i8 %t, 20 247 br i1 %a, label %true, label %false 248true: 249 %s = sext i8 %add to i32 250 store i32 %s, ptr %q 251 ret void 252false: 253 ret void 254} 255 256; Check that we do not a zextload if we need to introduce more than 257; one additional extension. 258define void @promoteThreeArgZext(ptr %p, ptr %q, i8 %b, i8 %c) { 259; NONSTRESS-LABEL: define void @promoteThreeArgZext( 260; NONSTRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { 261; NONSTRESS-NEXT: entry: 262; NONSTRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 263; NONSTRESS-NEXT: [[TMP:%.*]] = add nuw i8 [[T]], [[B]] 264; NONSTRESS-NEXT: [[ADD:%.*]] = add nuw i8 [[TMP]], [[C]] 265; NONSTRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 266; NONSTRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 267; NONSTRESS: true: 268; NONSTRESS-NEXT: [[S:%.*]] = zext i8 [[ADD]] to i32 269; NONSTRESS-NEXT: store i32 [[S]], ptr [[Q]], align 4 270; NONSTRESS-NEXT: ret void 271; NONSTRESS: false: 272; NONSTRESS-NEXT: ret void 273; 274; STRESS-LABEL: define void @promoteThreeArgZext( 275; STRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { 276; STRESS-NEXT: entry: 277; STRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 278; STRESS-NEXT: [[S:%.*]] = zext i8 [[T]] to i32 279; STRESS-NEXT: [[PROMOTED1:%.*]] = zext i8 [[B]] to i32 280; STRESS-NEXT: [[TMP:%.*]] = add nuw i32 [[S]], [[PROMOTED1]] 281; STRESS-NEXT: [[PROMOTED:%.*]] = zext i8 [[C]] to i32 282; STRESS-NEXT: [[ADD:%.*]] = add nuw i32 [[TMP]], [[PROMOTED]] 283; STRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 284; STRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 285; STRESS: true: 286; STRESS-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 287; STRESS-NEXT: ret void 288; STRESS: false: 289; STRESS-NEXT: ret void 290; 291; DISABLE-LABEL: define void @promoteThreeArgZext( 292; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { 293; DISABLE-NEXT: entry: 294; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 295; DISABLE-NEXT: [[TMP:%.*]] = add nuw i8 [[T]], [[B]] 296; DISABLE-NEXT: [[ADD:%.*]] = add nuw i8 [[TMP]], [[C]] 297; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 298; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 299; DISABLE: true: 300; DISABLE-NEXT: [[S:%.*]] = zext i8 [[ADD]] to i32 301; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 302; DISABLE-NEXT: ret void 303; DISABLE: false: 304; DISABLE-NEXT: ret void 305; 306entry: 307 %t = load i8, ptr %p 308 %tmp = add nuw i8 %t, %b 309 %add = add nuw i8 %tmp, %c 310 %a = icmp slt i8 %t, 20 311 br i1 %a, label %true, label %false 312true: 313 %s = zext i8 %add to i32 314 store i32 %s, ptr %q 315 ret void 316false: 317 ret void 318} 319 320; Check that we manage to form a zextload after promoting and merging 321; two extensions. 322define void @promoteMergeExtArgZExt(ptr %p, ptr %q, i16 %b) { 323; NONSTRESS-LABEL: define void @promoteMergeExtArgZExt( 324; NONSTRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i16 [[B:%.*]]) { 325; NONSTRESS-NEXT: entry: 326; NONSTRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 327; NONSTRESS-NEXT: [[EXT:%.*]] = zext i8 [[T]] to i16 328; NONSTRESS-NEXT: [[ADD:%.*]] = add nuw i16 [[EXT]], [[B]] 329; NONSTRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 330; NONSTRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 331; NONSTRESS: true: 332; NONSTRESS-NEXT: [[S:%.*]] = zext i16 [[ADD]] to i32 333; NONSTRESS-NEXT: store i32 [[S]], ptr [[Q]], align 4 334; NONSTRESS-NEXT: ret void 335; NONSTRESS: false: 336; NONSTRESS-NEXT: ret void 337; 338; STRESS-LABEL: define void @promoteMergeExtArgZExt( 339; STRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i16 [[B:%.*]]) { 340; STRESS-NEXT: entry: 341; STRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 342; STRESS-NEXT: [[PROMOTED1:%.*]] = zext i8 [[T]] to i32 343; STRESS-NEXT: [[PROMOTED:%.*]] = zext i16 [[B]] to i32 344; STRESS-NEXT: [[ADD:%.*]] = add nuw i32 [[PROMOTED1]], [[PROMOTED]] 345; STRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 346; STRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 347; STRESS: true: 348; STRESS-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 349; STRESS-NEXT: ret void 350; STRESS: false: 351; STRESS-NEXT: ret void 352; 353; DISABLE-LABEL: define void @promoteMergeExtArgZExt( 354; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i16 [[B:%.*]]) { 355; DISABLE-NEXT: entry: 356; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 357; DISABLE-NEXT: [[EXT:%.*]] = zext i8 [[T]] to i16 358; DISABLE-NEXT: [[ADD:%.*]] = add nuw i16 [[EXT]], [[B]] 359; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 360; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 361; DISABLE: true: 362; DISABLE-NEXT: [[S:%.*]] = zext i16 [[ADD]] to i32 363; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 364; DISABLE-NEXT: ret void 365; DISABLE: false: 366; DISABLE-NEXT: ret void 367; 368entry: 369 %t = load i8, ptr %p 370 %ext = zext i8 %t to i16 371 %add = add nuw i16 %ext, %b 372 %a = icmp slt i8 %t, 20 373 br i1 %a, label %true, label %false 374true: 375 %s = zext i16 %add to i32 376 store i32 %s, ptr %q 377 ret void 378false: 379 ret void 380} 381 382; Check that we manage to form a sextload after promoting and merging 383; two extensions. 384; Version with sext. 385define void @promoteMergeExtArgSExt(ptr %p, ptr %q, i16 %b) { 386; NONSTRESS-LABEL: define void @promoteMergeExtArgSExt( 387; NONSTRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i16 [[B:%.*]]) { 388; NONSTRESS-NEXT: entry: 389; NONSTRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 390; NONSTRESS-NEXT: [[EXT:%.*]] = zext i8 [[T]] to i16 391; NONSTRESS-NEXT: [[ADD:%.*]] = add nsw i16 [[EXT]], [[B]] 392; NONSTRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 393; NONSTRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 394; NONSTRESS: true: 395; NONSTRESS-NEXT: [[S:%.*]] = sext i16 [[ADD]] to i32 396; NONSTRESS-NEXT: store i32 [[S]], ptr [[Q]], align 4 397; NONSTRESS-NEXT: ret void 398; NONSTRESS: false: 399; NONSTRESS-NEXT: ret void 400; 401; STRESS-LABEL: define void @promoteMergeExtArgSExt( 402; STRESS-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i16 [[B:%.*]]) { 403; STRESS-NEXT: entry: 404; STRESS-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 405; STRESS-NEXT: [[PROMOTED1:%.*]] = zext i8 [[T]] to i32 406; STRESS-NEXT: [[PROMOTED:%.*]] = sext i16 [[B]] to i32 407; STRESS-NEXT: [[ADD:%.*]] = add nsw i32 [[PROMOTED1]], [[PROMOTED]] 408; STRESS-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 409; STRESS-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 410; STRESS: true: 411; STRESS-NEXT: store i32 [[ADD]], ptr [[Q]], align 4 412; STRESS-NEXT: ret void 413; STRESS: false: 414; STRESS-NEXT: ret void 415; 416; DISABLE-LABEL: define void @promoteMergeExtArgSExt( 417; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i16 [[B:%.*]]) { 418; DISABLE-NEXT: entry: 419; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 420; DISABLE-NEXT: [[EXT:%.*]] = zext i8 [[T]] to i16 421; DISABLE-NEXT: [[ADD:%.*]] = add nsw i16 [[EXT]], [[B]] 422; DISABLE-NEXT: [[A:%.*]] = icmp slt i8 [[T]], 20 423; DISABLE-NEXT: br i1 [[A]], label [[TRUE:%.*]], label [[FALSE:%.*]] 424; DISABLE: true: 425; DISABLE-NEXT: [[S:%.*]] = sext i16 [[ADD]] to i32 426; DISABLE-NEXT: store i32 [[S]], ptr [[Q]], align 4 427; DISABLE-NEXT: ret void 428; DISABLE: false: 429; DISABLE-NEXT: ret void 430; 431entry: 432 %t = load i8, ptr %p 433 %ext = zext i8 %t to i16 434 %add = add nsw i16 %ext, %b 435 %a = icmp slt i8 %t, 20 436 br i1 %a, label %true, label %false 437true: 438 %s = sext i16 %add to i32 439 store i32 %s, ptr %q 440 ret void 441false: 442 ret void 443} 444 445; Check that we manage to catch all the extload opportunities that are exposed 446; by the different iterations of codegen prepare. 447; Moreover, check that we do not promote more than we need to. 448; Here is what is happening in this test (not necessarly in this order): 449; 1. We try to promote the operand of %sextadd. 450; a. This creates one sext of %ld2 and one of %zextld 451; b. The sext of %ld2 can be combine with %ld2, so we remove one sext but 452; introduced one. This is fine with the current heuristic: neutral. 453; => We have one zext of %zextld left and we created one sext of %ld2. 454; 2. We try to promote the operand of %sextaddza. 455; a. This creates one sext of %zexta and one of %zextld 456; b. The sext of %zexta can be combined with the zext of %a. 457; c. The sext of %zextld leads to %ld and can be combined with it. This is 458; done by promoting %zextld. This is fine with the current heuristic: 459; neutral. 460; => We have created a new zext of %ld and we created one sext of %zexta. 461; 3. We try to promote the operand of %sextaddb. 462; a. This creates one sext of %b and one of %zextld 463; b. The sext of %b is a dead-end, nothing to be done. 464; c. Same thing as 2.c. happens. 465; => We have created a new zext of %ld and we created one sext of %b. 466; 4. We try to promote the operand of the zext of %zextld introduced in #1. 467; a. Same thing as 2.c. happens. 468; b. %zextld does not have any other uses. It is dead coded. 469; => We have created a new zext of %ld and we removed a zext of %zextld and 470; a zext of %ld. 471; Currently we do not try to reuse existing extensions, so in the end we have 472; 3 identical zext of %ld. The extensions will be CSE'ed by SDag. 473define void @severalPromotions(ptr %addr1, ptr %addr2, i8 %a, i32 %b) { 474; OPT-LABEL: define void @severalPromotions( 475; OPT-SAME: ptr [[ADDR1:%.*]], ptr [[ADDR2:%.*]], i8 [[A:%.*]], i32 [[B:%.*]]) { 476; OPT-NEXT: [[LD:%.*]] = load i8, ptr [[ADDR1]], align 1 477; OPT-NEXT: [[PROMOTED4:%.*]] = zext i8 [[LD]] to i64 478; OPT-NEXT: [[PROMOTED3:%.*]] = zext i8 [[LD]] to i64 479; OPT-NEXT: [[LD2:%.*]] = load i32, ptr [[ADDR2]], align 4 480; OPT-NEXT: [[SEXTADD:%.*]] = sext i32 [[LD2]] to i64 481; OPT-NEXT: [[PROMOTED1:%.*]] = zext i8 [[LD]] to i64 482; OPT-NEXT: [[ADD:%.*]] = add nsw i64 [[SEXTADD]], [[PROMOTED1]] 483; OPT-NEXT: [[PROMOTED2:%.*]] = zext i8 [[A]] to i64 484; OPT-NEXT: [[ADDZA:%.*]] = add nsw i64 [[PROMOTED2]], [[PROMOTED3]] 485; OPT-NEXT: [[SEXTADDB:%.*]] = sext i32 [[B]] to i64 486; OPT-NEXT: [[ADDB:%.*]] = add nsw i64 [[SEXTADDB]], [[PROMOTED4]] 487; OPT-NEXT: call void @dummy(i64 [[ADD]], i64 [[ADDZA]], i64 [[ADDB]]) 488; OPT-NEXT: ret void 489; 490; DISABLE-LABEL: define void @severalPromotions( 491; DISABLE-SAME: ptr [[ADDR1:%.*]], ptr [[ADDR2:%.*]], i8 [[A:%.*]], i32 [[B:%.*]]) { 492; DISABLE-NEXT: [[LD:%.*]] = load i8, ptr [[ADDR1]], align 1 493; DISABLE-NEXT: [[ZEXTLD:%.*]] = zext i8 [[LD]] to i32 494; DISABLE-NEXT: [[LD2:%.*]] = load i32, ptr [[ADDR2]], align 4 495; DISABLE-NEXT: [[ADD:%.*]] = add nsw i32 [[LD2]], [[ZEXTLD]] 496; DISABLE-NEXT: [[SEXTADD:%.*]] = sext i32 [[ADD]] to i64 497; DISABLE-NEXT: [[ZEXTA:%.*]] = zext i8 [[A]] to i32 498; DISABLE-NEXT: [[ADDZA:%.*]] = add nsw i32 [[ZEXTA]], [[ZEXTLD]] 499; DISABLE-NEXT: [[SEXTADDZA:%.*]] = sext i32 [[ADDZA]] to i64 500; DISABLE-NEXT: [[ADDB:%.*]] = add nsw i32 [[B]], [[ZEXTLD]] 501; DISABLE-NEXT: [[SEXTADDB:%.*]] = sext i32 [[ADDB]] to i64 502; DISABLE-NEXT: call void @dummy(i64 [[SEXTADD]], i64 [[SEXTADDZA]], i64 [[SEXTADDB]]) 503; DISABLE-NEXT: ret void 504; 505 %ld = load i8, ptr %addr1 506 %zextld = zext i8 %ld to i32 507 %ld2 = load i32, ptr %addr2 508 %add = add nsw i32 %ld2, %zextld 509 %sextadd = sext i32 %add to i64 510 %zexta = zext i8 %a to i32 511 %addza = add nsw i32 %zexta, %zextld 512 %sextaddza = sext i32 %addza to i64 513 %addb = add nsw i32 %b, %zextld 514 %sextaddb = sext i32 %addb to i64 515 call void @dummy(i64 %sextadd, i64 %sextaddza, i64 %sextaddb) 516 ret void 517} 518 519declare void @dummy(i64, i64, i64) 520 521; Make sure we do not try to promote vector types since the type promotion 522; helper does not support them for now. 523define void @vectorPromotion() { 524; OPTALL-LABEL: define void @vectorPromotion() { 525; OPTALL-NEXT: entry: 526; OPTALL-NEXT: [[A:%.*]] = shl nuw nsw <2 x i32> zeroinitializer, splat (i32 8) 527; OPTALL-NEXT: [[B:%.*]] = zext <2 x i32> [[A]] to <2 x i64> 528; OPTALL-NEXT: ret void 529; 530entry: 531 %a = shl nuw nsw <2 x i32> zeroinitializer, <i32 8, i32 8> 532 %b = zext <2 x i32> %a to <2 x i64> 533 ret void 534} 535 536@a = common global i32 0, align 4 537@c = common global [2 x i32] zeroinitializer, align 4 538 539; PR21978. 540; Make sure we support promotion of operands that produces a Value as opposed 541; to an instruction. 542; This used to cause a crash. 543define i32 @promotionOfArgEndsUpInValue(ptr %addr) { 544; OPT-LABEL: define i32 @promotionOfArgEndsUpInValue( 545; OPT-SAME: ptr [[ADDR:%.*]]) { 546; OPT-NEXT: entry: 547; OPT-NEXT: [[VAL:%.*]] = load i16, ptr [[ADDR]], align 2 548; OPT-NEXT: [[CONV3:%.*]] = sext i16 [[VAL]] to i32 549; OPT-NEXT: [[CMP:%.*]] = icmp ne ptr getelementptr inbounds ([2 x i32], ptr @c, i64 0, i64 1), @a 550; OPT-NEXT: [[PROMOTED1:%.*]] = zext i1 [[CMP]] to i32 551; OPT-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[CONV3]], [[PROMOTED1]] 552; OPT-NEXT: ret i32 [[ADD]] 553; 554; DISABLE-LABEL: define i32 @promotionOfArgEndsUpInValue( 555; DISABLE-SAME: ptr [[ADDR:%.*]]) { 556; DISABLE-NEXT: entry: 557; DISABLE-NEXT: [[VAL:%.*]] = load i16, ptr [[ADDR]], align 2 558; DISABLE-NEXT: [[CMP:%.*]] = icmp ne ptr getelementptr inbounds ([2 x i32], ptr @c, i64 0, i64 1), @a 559; DISABLE-NEXT: [[EXT:%.*]] = zext i1 [[CMP]] to i16 560; DISABLE-NEXT: [[ADD:%.*]] = add nuw nsw i16 [[VAL]], [[EXT]] 561; DISABLE-NEXT: [[CONV3:%.*]] = sext i16 [[ADD]] to i32 562; DISABLE-NEXT: ret i32 [[CONV3]] 563; 564entry: 565 %val = load i16, ptr %addr 566 %cmp = icmp ne ptr getelementptr inbounds ([2 x i32], ptr @c, i64 0, i64 1), @a 567 %ext = zext i1 %cmp to i16 568 %add = add nuw nsw i16 %val, %ext 569 %conv3 = sext i16 %add to i32 570 ret i32 %conv3 571} 572 573; Check that we see that one zext can be derived from the other for free. 574define void @promoteTwoArgZextWithSourceExtendedTwice(ptr %p, ptr %q, i32 %b, ptr %addr) { 575; OPT-LABEL: define void @promoteTwoArgZextWithSourceExtendedTwice( 576; OPT-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i32 [[B:%.*]], ptr [[ADDR:%.*]]) { 577; OPT-NEXT: entry: 578; OPT-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 579; OPT-NEXT: [[PROMOTED:%.*]] = zext i8 [[T]] to i64 580; OPT-NEXT: [[ZEXTT:%.*]] = zext i8 [[T]] to i32 581; OPT-NEXT: [[ADD:%.*]] = add nuw i32 [[ZEXTT]], [[B]] 582; OPT-NEXT: [[ADD2:%.*]] = add nuw i64 [[PROMOTED]], 12 583; OPT-NEXT: store i32 [[ADD]], ptr [[ADDR]], align 4 584; OPT-NEXT: store i64 [[ADD2]], ptr [[Q]], align 8 585; OPT-NEXT: ret void 586; 587; DISABLE-LABEL: define void @promoteTwoArgZextWithSourceExtendedTwice( 588; DISABLE-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i32 [[B:%.*]], ptr [[ADDR:%.*]]) { 589; DISABLE-NEXT: entry: 590; DISABLE-NEXT: [[T:%.*]] = load i8, ptr [[P]], align 1 591; DISABLE-NEXT: [[ZEXTT:%.*]] = zext i8 [[T]] to i32 592; DISABLE-NEXT: [[ADD:%.*]] = add nuw i32 [[ZEXTT]], [[B]] 593; DISABLE-NEXT: [[ADD2:%.*]] = add nuw i32 [[ZEXTT]], 12 594; DISABLE-NEXT: store i32 [[ADD]], ptr [[ADDR]], align 4 595; DISABLE-NEXT: [[S:%.*]] = zext i32 [[ADD2]] to i64 596; DISABLE-NEXT: store i64 [[S]], ptr [[Q]], align 8 597; DISABLE-NEXT: ret void 598; 599entry: 600 %t = load i8, ptr %p 601 %zextt = zext i8 %t to i32 602 %add = add nuw i32 %zextt, %b 603 %add2 = add nuw i32 %zextt, 12 604 store i32 %add, ptr%addr 605 %s = zext i32 %add2 to i64 606 store i64 %s, ptr %q 607 ret void 608} 609