1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals 2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC 4; PR36485 5; musttail call result can't be replaced with a constant, unless the call can be removed 6 7declare i32 @external() 8 9define ptr @start(i8 %v) { 10; 11; TUNIT-LABEL: define {{[^@]+}}@start 12; TUNIT-SAME: (i8 [[V:%.*]]) { 13; TUNIT-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0 14; TUNIT-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]] 15; TUNIT: true: 16; TUNIT-NEXT: [[CA:%.*]] = musttail call noalias noundef align 4294967296 ptr @side_effects(i8 [[V]]) 17; TUNIT-NEXT: ret ptr [[CA]] 18; TUNIT: false: 19; TUNIT-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1 20; TUNIT-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]] 21; TUNIT: c2_true: 22; TUNIT-NEXT: ret ptr null 23; TUNIT: c2_false: 24; TUNIT-NEXT: [[CA2:%.*]] = musttail call noalias noundef align 4294967296 ptr @dont_zap_me(i8 undef) 25; TUNIT-NEXT: ret ptr [[CA2]] 26; 27; CGSCC-LABEL: define {{[^@]+}}@start 28; CGSCC-SAME: (i8 [[V:%.*]]) { 29; CGSCC-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0 30; CGSCC-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]] 31; CGSCC: true: 32; CGSCC-NEXT: [[CA:%.*]] = musttail call noalias noundef align 4294967296 ptr @side_effects(i8 [[V]]) 33; CGSCC-NEXT: ret ptr [[CA]] 34; CGSCC: false: 35; CGSCC-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1 36; CGSCC-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]] 37; CGSCC: c2_true: 38; CGSCC-NEXT: [[CA1:%.*]] = musttail call noalias noundef align 4294967296 ptr @no_side_effects(i8 [[V]]) 39; CGSCC-NEXT: ret ptr [[CA1]] 40; CGSCC: c2_false: 41; CGSCC-NEXT: [[CA2:%.*]] = musttail call noalias noundef align 4294967296 ptr @dont_zap_me(i8 [[V]]) 42; CGSCC-NEXT: ret ptr [[CA2]] 43; 44 %c1 = icmp eq i8 %v, 0 45 br i1 %c1, label %true, label %false 46true: 47 ; FIXME: propagate the value information for %v 48 %ca = musttail call ptr @side_effects(i8 %v) 49 ret ptr %ca 50false: 51 %c2 = icmp eq i8 %v, 1 52 br i1 %c2, label %c2_true, label %c2_false 53c2_true: 54 %ca1 = musttail call ptr @no_side_effects(i8 %v) 55 ret ptr %ca1 56c2_false: 57 %ca2 = musttail call ptr @dont_zap_me(i8 %v) 58 ret ptr %ca2 59} 60 61define internal ptr @side_effects(i8 %v) { 62; CHECK-LABEL: define {{[^@]+}}@side_effects 63; CHECK-SAME: (i8 [[V:%.*]]) { 64; CHECK-NEXT: [[I1:%.*]] = call i32 @external() 65; CHECK-NEXT: [[CA:%.*]] = musttail call noalias noundef align 4294967296 ptr @start(i8 0) 66; CHECK-NEXT: ret ptr [[CA]] 67; 68 %i1 = call i32 @external() 69 70 ; since this goes back to `start` the SCPP should be see that the return value 71 ; is always `null`. 72 ; The call can't be removed due to `external` call above, though. 73 74 %ca = musttail call ptr @start(i8 %v) 75 76 ; Thus the result must be returned anyway 77 ret ptr %ca 78} 79 80define internal ptr @no_side_effects(i8 %v) readonly nounwind { 81; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 82; CGSCC-LABEL: define {{[^@]+}}@no_side_effects 83; CGSCC-SAME: (i8 [[V:%.*]]) #[[ATTR0:[0-9]+]] { 84; CGSCC-NEXT: ret ptr null 85; 86 ret ptr null 87} 88 89define internal ptr @dont_zap_me(i8 %v) { 90; CHECK-LABEL: define {{[^@]+}}@dont_zap_me 91; CHECK-SAME: (i8 [[V:%.*]]) { 92; CHECK-NEXT: [[I1:%.*]] = call i32 @external() 93; CHECK-NEXT: ret ptr null 94; 95 %i1 = call i32 @external() 96 ret ptr null 97} 98;. 99; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 100;. 101