245 lines · c
1// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 62// RUN: %clang_cc1 -triple=x86_64 -std=c99 -Wno-dangling -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK3// RUN: %clang_cc1 -triple=x86_64 -std=c11 -Wno-dangling -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK4// RUN: %clang_cc1 -triple=x86_64 -std=c11 -O2 -disable-llvm-passes -Wno-dangling -emit-llvm -o - %s | FileCheck %s --check-prefix=C11-O25 6// Ensure that codegen for temporary lifetimes makes sense.7 8struct X { int a[5]; };9struct X f(void);10 11// CHECK-LABEL: define dso_local i32 @func_return(12// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {13// CHECK-NEXT: [[ENTRY:.*:]]14// CHECK-NEXT: [[P:%.*]] = alloca ptr, align 815// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X:%.*]], align 416// CHECK-NEXT: call void @f(ptr dead_on_unwind writable sret([[STRUCT_X]]) align 4 [[REF_TMP]])17// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 018// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 019// CHECK-NEXT: store ptr [[ARRAYDECAY]], ptr [[P]], align 820// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 821// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 422// CHECK-NEXT: ret i32 [[TMP1]]23//24// C11-O2-LABEL: define dso_local i32 @func_return(25// C11-O2-SAME: ) #[[ATTR0:[0-9]+]] {26// C11-O2-NEXT: [[ENTRY:.*:]]27// C11-O2-NEXT: [[P:%.*]] = alloca ptr, align 828// C11-O2-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X:%.*]], align 429// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[P]]) #[[ATTR5:[0-9]+]]30// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[REF_TMP]]) #[[ATTR5]]31// C11-O2-NEXT: call void @f(ptr dead_on_unwind writable sret([[STRUCT_X]]) align 4 [[REF_TMP]])32// C11-O2-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 033// C11-O2-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 034// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[REF_TMP]]) #[[ATTR5]]35// C11-O2-NEXT: store ptr [[ARRAYDECAY]], ptr [[P]], align 8, !tbaa [[INTPTR_TBAA6:![0-9]+]]36// C11-O2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[INTPTR_TBAA6]]37// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[INT_TBAA2:![0-9]+]]38// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[P]]) #[[ATTR5]]39// C11-O2-NEXT: ret i32 [[TMP1]]40//41int func_return(void) {42 int *p = f().a;43 return *p;44}45 46// CHECK-LABEL: define dso_local i32 @ternary(47// CHECK-SAME: ) #[[ATTR0]] {48// CHECK-NEXT: [[ENTRY:.*:]]49// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X:%.*]], align 450// CHECK-NEXT: [[Q:%.*]] = alloca ptr, align 851// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_X]], align 452// CHECK-NEXT: br i1 true, label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]53// CHECK: [[COND_TRUE]]:54// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[REF_TMP]], i8 0, i64 20, i1 false)55// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 056// CHECK-NEXT: br label %[[COND_END:.*]]57// CHECK: [[COND_FALSE]]:58// CHECK-NEXT: call void @f(ptr dead_on_unwind writable sret([[STRUCT_X]]) align 4 [[REF_TMP]])59// CHECK-NEXT: br label %[[COND_END]]60// CHECK: [[COND_END]]:61// CHECK-NEXT: [[A1:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 062// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A1]], i64 0, i64 063// CHECK-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 864// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[DOTCOMPOUNDLITERAL]], i8 0, i64 20, i1 false)65// CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 066// CHECK-NEXT: [[A3:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 067// CHECK-NEXT: [[ARRAYDECAY4:%.*]] = getelementptr inbounds [5 x i32], ptr [[A3]], i64 0, i64 068// CHECK-NEXT: store ptr [[ARRAYDECAY4]], ptr [[Q]], align 869// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 870// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 471// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[Q]], align 872// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 473// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP3]]74// CHECK-NEXT: ret i32 [[ADD]]75//76// C11-O2-LABEL: define dso_local i32 @ternary(77// C11-O2-SAME: ) #[[ATTR0]] {78// C11-O2-NEXT: [[ENTRY:.*:]]79// C11-O2-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X:%.*]], align 480// C11-O2-NEXT: [[Q:%.*]] = alloca ptr, align 881// C11-O2-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_X]], align 482// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[REF_TMP]]) #[[ATTR5]]83// C11-O2-NEXT: br i1 true, label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]84// C11-O2: [[COND_TRUE]]:85// C11-O2-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[REF_TMP]], i8 0, i64 20, i1 false)86// C11-O2-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 087// C11-O2-NEXT: br label %[[COND_END:.*]]88// C11-O2: [[COND_FALSE]]:89// C11-O2-NEXT: call void @f(ptr dead_on_unwind writable sret([[STRUCT_X]]) align 4 [[REF_TMP]])90// C11-O2-NEXT: br label %[[COND_END]]91// C11-O2: [[COND_END]]:92// C11-O2-NEXT: [[A1:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 093// C11-O2-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A1]], i64 0, i64 094// C11-O2-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]95// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[REF_TMP]]) #[[ATTR5]]96// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[Q]]) #[[ATTR5]]97// C11-O2-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[DOTCOMPOUNDLITERAL]], i8 0, i64 20, i1 false)98// C11-O2-NEXT: [[A2:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 099// C11-O2-NEXT: [[A3:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 0100// C11-O2-NEXT: [[ARRAYDECAY4:%.*]] = getelementptr inbounds [5 x i32], ptr [[A3]], i64 0, i64 0101// C11-O2-NEXT: store ptr [[ARRAYDECAY4]], ptr [[Q]], align 8, !tbaa [[INTPTR_TBAA6]]102// C11-O2-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]103// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[INT_TBAA2]]104// C11-O2-NEXT: [[TMP2:%.*]] = load ptr, ptr [[Q]], align 8, !tbaa [[INTPTR_TBAA6]]105// C11-O2-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4, !tbaa [[INT_TBAA2]]106// C11-O2-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP3]]107// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[Q]]) #[[ATTR5]]108// C11-O2-NEXT: ret i32 [[ADD]]109//110int ternary(void) {111 extern int *p;112 p = (1 ? (struct X){ 0 } : f()).a;113 int *q = 1 ? (struct X){ 0 }.a : f().a;114 115 return *p + *q;116}117 118// CHECK-LABEL: define dso_local i32 @comma(119// CHECK-SAME: ) #[[ATTR0]] {120// CHECK-NEXT: [[ENTRY:.*:]]121// CHECK-NEXT: [[X:%.*]] = alloca [[STRUCT_X:%.*]], align 4122// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X]], align 4123// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[REF_TMP]], ptr align 4 [[X]], i64 20, i1 false)124// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 0125// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 0126// CHECK-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8127// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8128// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4129// CHECK-NEXT: ret i32 [[TMP1]]130//131// C11-O2-LABEL: define dso_local i32 @comma(132// C11-O2-SAME: ) #[[ATTR0]] {133// C11-O2-NEXT: [[ENTRY:.*:]]134// C11-O2-NEXT: [[X:%.*]] = alloca [[STRUCT_X:%.*]], align 4135// C11-O2-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X]], align 4136// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[X]]) #[[ATTR5]]137// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[REF_TMP]]) #[[ATTR5]]138// C11-O2-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[REF_TMP]], ptr align 4 [[X]], i64 20, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]139// C11-O2-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 0140// C11-O2-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 0141// C11-O2-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]142// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[REF_TMP]]) #[[ATTR5]]143// C11-O2-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]144// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[INT_TBAA2]]145// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[X]]) #[[ATTR5]]146// C11-O2-NEXT: ret i32 [[TMP1]]147//148int comma(void) {149 struct X x;150 extern int *p;151 p = ((void)0, x).a;152 return *p;153}154 155// CHECK-LABEL: define dso_local i32 @cast(156// CHECK-SAME: ) #[[ATTR0]] {157// CHECK-NEXT: [[ENTRY:.*:]]158// CHECK-NEXT: [[X:%.*]] = alloca [[STRUCT_X:%.*]], align 4159// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X]], align 4160// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[REF_TMP]], ptr align 4 [[X]], i64 20, i1 false)161// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 0162// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 0163// CHECK-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8164// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8165// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4166// CHECK-NEXT: ret i32 [[TMP1]]167//168// C11-O2-LABEL: define dso_local i32 @cast(169// C11-O2-SAME: ) #[[ATTR0]] {170// C11-O2-NEXT: [[ENTRY:.*:]]171// C11-O2-NEXT: [[X:%.*]] = alloca [[STRUCT_X:%.*]], align 4172// C11-O2-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X]], align 4173// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[X]]) #[[ATTR5]]174// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[REF_TMP]]) #[[ATTR5]]175// C11-O2-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[REF_TMP]], ptr align 4 [[X]], i64 20, i1 false), !tbaa.struct [[TBAA_STRUCT9]]176// C11-O2-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 0177// C11-O2-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 0178// C11-O2-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]179// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[REF_TMP]]) #[[ATTR5]]180// C11-O2-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]181// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[INT_TBAA2]]182// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[X]]) #[[ATTR5]]183// C11-O2-NEXT: ret i32 [[TMP1]]184//185int cast(void) {186 struct X x;187 extern int *p;188 p = ((struct X)x).a;189 return *p;190}191 192// CHECK-LABEL: define dso_local i32 @assign(193// CHECK-SAME: ) #[[ATTR0]] {194// CHECK-NEXT: [[ENTRY:.*:]]195// CHECK-NEXT: [[X:%.*]] = alloca [[STRUCT_X:%.*]], align 4196// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_X]], align 4197// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X]], align 4198// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr align 4 [[S]], i64 20, i1 false)199// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[REF_TMP]], ptr align 4 [[X]], i64 20, i1 false)200// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 0201// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 0202// CHECK-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8203// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8204// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4205// CHECK-NEXT: ret i32 [[TMP1]]206//207// C11-O2-LABEL: define dso_local i32 @assign(208// C11-O2-SAME: ) #[[ATTR0]] {209// C11-O2-NEXT: [[ENTRY:.*:]]210// C11-O2-NEXT: [[X:%.*]] = alloca [[STRUCT_X:%.*]], align 4211// C11-O2-NEXT: [[S:%.*]] = alloca [[STRUCT_X]], align 4212// C11-O2-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_X]], align 4213// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[X]]) #[[ATTR5]]214// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[S]]) #[[ATTR5]]215// C11-O2-NEXT: call void @llvm.lifetime.start.p0(ptr [[REF_TMP]]) #[[ATTR5]]216// C11-O2-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr align 4 [[S]], i64 20, i1 false), !tbaa.struct [[TBAA_STRUCT9]]217// C11-O2-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[REF_TMP]], ptr align 4 [[X]], i64 20, i1 false), !tbaa.struct [[TBAA_STRUCT9]]218// C11-O2-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr [[REF_TMP]], i32 0, i32 0219// C11-O2-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [5 x i32], ptr [[A]], i64 0, i64 0220// C11-O2-NEXT: store ptr [[ARRAYDECAY]], ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]221// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[REF_TMP]]) #[[ATTR5]]222// C11-O2-NEXT: [[TMP0:%.*]] = load ptr, ptr @p, align 8, !tbaa [[INTPTR_TBAA6]]223// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[INT_TBAA2]]224// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[S]]) #[[ATTR5]]225// C11-O2-NEXT: call void @llvm.lifetime.end.p0(ptr [[X]]) #[[ATTR5]]226// C11-O2-NEXT: ret i32 [[TMP1]]227//228int assign(void) {229 struct X x, s;230 extern int *p;231 p = (x = s).a;232 return *p;233}234//.235// C11-O2: [[INT_TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}236// C11-O2: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}237// C11-O2: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}238// C11-O2: [[META5]] = !{!"Simple C/C++ TBAA"}239// C11-O2: [[INTPTR_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}240// C11-O2: [[META7]] = !{!"p1 int", [[META8:![0-9]+]], i64 0}241// C11-O2: [[META8]] = !{!"any pointer", [[META4]], i64 0}242// C11-O2: [[TBAA_STRUCT9]] = !{i64 0, i64 20, [[META10:![0-9]+]]}243// C11-O2: [[META10]] = !{[[META4]], [[META4]], i64 0}244//.245