| // RUN: %clang_cc1 -triple x86_64-linux-gnu -gkey-instructions -gno-column-info -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \ | |
| // RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-CXX | |
| // RUN: %clang_cc1 -triple x86_64-linux-gnu -gkey-instructions -gno-column-info -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \ | |
| // RUN: | FileCheck %s | |
| // Check the stores to `retval` allocas and branches to `return` block are in | |
| // the same atom group. They are both rank 1, which could in theory introduce | |
| // an extra step in some optimized code. This low risk currently feels an | |
| // acceptable for keeping the code a bit simpler (as opposed to adding | |
| // scaffolding to make the store rank 2). | |
| // Also check that in the case of a single return (no control flow) the | |
| // return instruction inherits the atom group of the branch to the return | |
| // block when the blocks get folded togather. | |
| #ifdef __cplusplus | |
| #define nomangle extern "C" | |
| #else | |
| #define nomangle | |
| #endif | |
| int g; | |
| nomangle float a() { | |
| // CHECK: float @a() | |
| if (g) | |
| // CHECK: if.then: | |
| // CHECK-NEXT: %1 = load i32, ptr @g{{.*}}, !dbg [[G2R3:!.*]] | |
| // CHECK-NEXT: %conv = sitofp i32 %1 to float{{.*}}, !dbg [[G2R2:!.*]] | |
| // CHECK-NEXT: store float %conv, ptr %retval{{.*}}, !dbg [[G2R1:!.*]] | |
| // CHECK-NEXT: br label %return{{.*}}, !dbg [[G2R1]] | |
| return g; | |
| // CHECK: if.end: | |
| // CHECK-NEXT: store float 1.000000e+00, ptr %retval{{.*}}, !dbg [[G3R1:!.*]] | |
| // CHECK-NEXT: br label %return, !dbg [[G3R1]] | |
| // CHECK: return: | |
| // CHECK-NEXT: %2 = load float, ptr %retval{{.*}}, !dbg [[G4R2:!.*]] | |
| // CHECK-NEXT: ret float %2{{.*}}, !dbg [[G4R1:!.*]] | |
| return 1; | |
| } | |
| // CHECK: void @b() | |
| // CHECK: ret void{{.*}}, !dbg [[B_G1R1:!.*]] | |
| nomangle void b() { return; } | |
| // CHECK: i32 @c() | |
| // CHECK: %add = add{{.*}}, !dbg [[C_G1R2:!.*]] | |
| // CHECK: ret i32 %add{{.*}}, !dbg [[C_G1R1:!.*]] | |
| nomangle int c() { return g + 1; } | |
| // NOTE: (return) (g = 1) are two separate atoms. | |
| // CHECK: i32 @d() | |
| // CHECK: store{{.*}}, !dbg [[D_G2R1:!.*]] | |
| // CHECK: ret i32 1{{.*}}, !dbg [[D_G1R1:!.*]] | |
| nomangle int d() { return g = 1; } | |
| // The implicit return here get the line number of the closing brace; make it | |
| // key to match existing behaviour. | |
| // CHECK: void @e() | |
| // CHECK: ret void, !dbg [[E_G1R1:!.*]] | |
| nomangle void e() {} | |
| #ifdef __cplusplus | |
| // CHECK-CXX: ptr @_Z1fRi | |
| int &f(int &r) { | |
| // Include ctrl-flow to stop ret value store being elided. | |
| if (r) | |
| // CHECK-CXX: if.then: | |
| // CHECK-CXX-NEXT: %2 = load ptr, ptr %r.addr{{.*}}, !dbg [[F_G2R2:!.*]], !nonnull | |
| // CHECK-CXX-NEXT: store ptr %2, ptr %retval{{.*}}, !dbg [[F_G2R1:!.*]] | |
| // CHECK-CXX-NEXT: br label %return, !dbg [[F_G2R1:!.*]] | |
| return r; | |
| // CHECK-CXX: if.end: | |
| // CHECK-CXX-NEXT: store ptr @g, ptr %retval{{.*}}, !dbg [[F_G3R1:!.*]] | |
| // CHECK-CXX-NEXT: br label %return, !dbg [[F_G3R1:!.*]] | |
| // CHECK-CXX: return: | |
| // CHECK-CXX-NEXT: %3 = load ptr, ptr %retval{{.*}}, !dbg [[F_G4R2:!.*]] | |
| // CHECK-CXX-NEXT: ret ptr %3, !dbg [[F_G4R1:!.*]] | |
| return g; | |
| } | |
| #endif | |
| // CHECK: [[G2R3]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 3) | |
| // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) | |
| // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) | |
| // CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) | |
| // CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2) | |
| // CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1) | |
| // CHECK: [[B_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) | |
| // CHECK: [[C_G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2) | |
| // CHECK: [[C_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) | |
| // CHECK: [[D_G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) | |
| // CHECK: [[D_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) | |
| // CHECK: [[E_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1) | |
| // CHECK-CXX: [[F_G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2) | |
| // CHECK-CXX: [[F_G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1) | |
| // CHECK-CXX: [[F_G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1) | |
| // CHECK-CXX: [[F_G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2) | |
| // CHECK-CXX: [[F_G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1) |