Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IRGen] Evaluate constant static variables referenced through member
expressions C++ allows us to reference static variables through member expressions. Prior to this commit, non-integer static variables that were referenced using a member expression were always emitted using lvalue loads. The old behaviour introduced an inconsistency between regular uses of static variables and member expressions uses. For example, the following program compiled and linked successfully: struct Foo { constexpr static const char *name = "foo"; }; int main() { return Foo::name[0] == 'f'; } but this program failed to link because "Foo::name" wasn't found: struct Foo { constexpr static const char *name = "foo"; }; int main() { Foo f; return f.name[0] == 'f'; } This commit ensures that constant static variables referenced through member expressions are emitted in the same way as ordinary static variable references. rdar://33942261 Differential Revision: https://reviews.llvm.org/D36876 llvm-svn: 311772
- Loading branch information
Showing
6 changed files
with
171 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
clang/test/CodeGenCXX/member-expr-references-variable.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s | ||
|
||
struct Agg { const char * x; const char * y; constexpr Agg() : x(0), y(0) {} }; | ||
|
||
struct Struct { | ||
constexpr static const char *name = "foo"; | ||
|
||
constexpr static __complex float complexValue = 42.0; | ||
|
||
static constexpr const Agg &agg = Agg(); | ||
|
||
Struct(); | ||
Struct(int x); | ||
}; | ||
|
||
void use(int n, const char *c); | ||
|
||
Struct *getPtr(); | ||
|
||
// CHECK: @[[STR:.*]] = private unnamed_addr constant [4 x i8] c"foo\00", align 1 | ||
|
||
void scalarStaticVariableInMemberExpr(Struct *ptr, Struct &ref) { | ||
use(1, Struct::name); | ||
// CHECK: call void @_Z3useiPKc(i32 1, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) | ||
Struct s; | ||
use(2, s.name); | ||
// CHECK: call void @_Z3useiPKc(i32 2, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) | ||
use(3, ptr->name); | ||
// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 | ||
// CHECK: call void @_Z3useiPKc(i32 3, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) | ||
use(4, ref.name); | ||
// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 | ||
// CHECK: call void @_Z3useiPKc(i32 4, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) | ||
use(5, Struct(2).name); | ||
// CHECK: call void @_ZN6StructC1Ei(%struct.Struct* %{{.*}}, i32 2) | ||
// CHECK: call void @_Z3useiPKc(i32 5, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) | ||
use(6, getPtr()->name); | ||
// CHECK: call %struct.Struct* @_Z6getPtrv() | ||
// CHECK: call void @_Z3useiPKc(i32 6, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0)) | ||
} | ||
|
||
void use(int n, __complex float v); | ||
|
||
void complexStaticVariableInMemberExpr(Struct *ptr, Struct &ref) { | ||
use(1, Struct::complexValue); | ||
// CHECK: store float 4.200000e+01, float* %[[coerce0:.*]].{{.*}}, align 4 | ||
// CHECK: store float 0.000000e+00, float* %[[coerce0]].{{.*}}, align 4 | ||
// CHECK: %[[cast0:.*]] = bitcast { float, float }* %[[coerce0]] to <2 x float>* | ||
// CHECK: %[[vector0:.*]] = load <2 x float>, <2 x float>* %[[cast0]], align 4 | ||
// CHECK: call void @_Z3useiCf(i32 1, <2 x float> %[[vector0]]) | ||
Struct s; | ||
use(2, s.complexValue); | ||
// CHECK: store float 4.200000e+01, float* %[[coerce1:.*]].{{.*}}, align 4 | ||
// CHECK: store float 0.000000e+00, float* %[[coerce1]].{{.*}}, align 4 | ||
// CHECK: %[[cast1:.*]] = bitcast { float, float }* %[[coerce1]] to <2 x float>* | ||
// CHECK: %[[vector1:.*]] = load <2 x float>, <2 x float>* %[[cast1]], align 4 | ||
// CHECK: call void @_Z3useiCf(i32 2, <2 x float> %[[vector1]]) | ||
use(3, ptr->complexValue); | ||
// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 | ||
// CHECK: store float 4.200000e+01, float* %[[coerce2:.*]].{{.*}}, align 4 | ||
// CHECK: store float 0.000000e+00, float* %[[coerce2]].{{.*}}, align 4 | ||
// CHECK: %[[cast2:.*]] = bitcast { float, float }* %[[coerce2]] to <2 x float>* | ||
// CHECK: %[[vector2:.*]] = load <2 x float>, <2 x float>* %[[cast2]], align 4 | ||
// CHECK: call void @_Z3useiCf(i32 3, <2 x float> %[[vector2]]) | ||
use(4, ref.complexValue); | ||
// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 | ||
// CHECK: store float 4.200000e+01, float* %[[coerce3:.*]].{{.*}}, align 4 | ||
// CHECK: store float 0.000000e+00, float* %[[coerce3]].{{.*}}, align 4 | ||
// CHECK: %[[cast3:.*]] = bitcast { float, float }* %[[coerce3]] to <2 x float>* | ||
// CHECK: %[[vector3:.*]] = load <2 x float>, <2 x float>* %[[cast3]], align 4 | ||
// CHECK: call void @_Z3useiCf(i32 4, <2 x float> %[[vector3]]) | ||
use(5, Struct(2).complexValue); | ||
// CHECK: call void @_ZN6StructC1Ei(%struct.Struct* %{{.*}}, i32 2) | ||
// CHECK: store float 4.200000e+01, float* %[[coerce4:.*]].{{.*}}, align 4 | ||
// CHECK: store float 0.000000e+00, float* %[[coerce4]].{{.*}}, align 4 | ||
// CHECK: %[[cast4:.*]] = bitcast { float, float }* %[[coerce4]] to <2 x float>* | ||
// CHECK: %[[vector4:.*]] = load <2 x float>, <2 x float>* %[[cast4]], align 4 | ||
// CHECK: call void @_Z3useiCf(i32 5, <2 x float> %[[vector4]]) | ||
use(6, getPtr()->complexValue); | ||
// CHECK: call %struct.Struct* @_Z6getPtrv() | ||
// CHECK: store float 4.200000e+01, float* %[[coerce5:.*]].{{.*}}, align 4 | ||
// CHECK: store float 0.000000e+00, float* %[[coerce5]].{{.*}}, align 4 | ||
// CHECK: %[[cast5:.*]] = bitcast { float, float }* %[[coerce5]] to <2 x float>* | ||
// CHECK: %[[vector5:.*]] = load <2 x float>, <2 x float>* %[[cast5]], align 4 | ||
// CHECK: call void @_Z3useiCf(i32 6, <2 x float> %[[vector5]]) | ||
} | ||
|
||
void aggregateRefInMemberExpr(Struct *ptr, Struct &ref) { | ||
use(1, Struct::agg.x); | ||
// CHECK: %[[value0:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8 | ||
// CHECK: call void @_Z3useiPKc(i32 1, i8* %[[value0]]) | ||
Struct s; | ||
use(2, s.agg.x); | ||
// CHECK: %[[value1:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8 | ||
// CHECK: call void @_Z3useiPKc(i32 2, i8* %[[value1]]) | ||
use(3, ptr->agg.x); | ||
// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 | ||
// CHECK: %[[value2:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8 | ||
// CHECK: call void @_Z3useiPKc(i32 3, i8* %[[value2]]) | ||
use(4, ref.agg.x); | ||
// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8 | ||
// CHECK: %[[value3:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8 | ||
// CHECK: call void @_Z3useiPKc(i32 4, i8* %[[value3]]) | ||
} |