Generate nuw GEPs for struct member accesses, as inbounds + non-negative implies nuw. Regression tests are updated using update scripts where possible, and by find + replace where not.
191 lines
8.3 KiB
Plaintext
191 lines
8.3 KiB
Plaintext
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
|
|
// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
|
|
|
template <typename T>
|
|
struct Foo {
|
|
private:
|
|
T x;
|
|
|
|
public:
|
|
Foo(T x) : x(x) {}
|
|
~Foo() {}
|
|
|
|
T get() { return x; }
|
|
void set(T _x) { x = _x; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct Bar {
|
|
private:
|
|
struct Foo<T> foo;
|
|
|
|
public:
|
|
Bar(T x) : foo(x) {}
|
|
~Bar() {}
|
|
|
|
T get() { return foo.get(); }
|
|
void set(T _x) { foo.set(_x); }
|
|
};
|
|
|
|
template <typename T>
|
|
struct Baz : Foo<T> {
|
|
public:
|
|
Baz(T x) : Foo<T>(x) {}
|
|
~Baz() {}
|
|
};
|
|
|
|
// These two specializations should generate lines for all of Foo's methods.
|
|
|
|
// CHECK-LABEL: @_ZN3FooIcEC1Ec(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i8 [[X:%.*]], ptr [[X_ADDR]], align 1
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1
|
|
// CHECK-NEXT: call void @_ZN3FooIcEC2Ec(ptr noundef nonnull align 1 dereferenceable(1) [[THIS1]], i8 noundef signext [[TMP0]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3FooIcED1Ev(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: call void @_ZN3FooIcED2Ev(ptr noundef nonnull align 1 dereferenceable(1) [[THIS1]]) #[[ATTR1:[0-9]+]]
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3FooIcE3getEv(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_FOO:%.*]], ptr [[THIS1]], i32 0, i32 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X]], align 1
|
|
// CHECK-NEXT: ret i8 [[TMP0]]
|
|
//
|
|
// CHECK-LABEL: @_ZN3FooIcE3setEc(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[_X_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i8 [[_X:%.*]], ptr [[_X_ADDR]], align 1
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[_X_ADDR]], align 1
|
|
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_FOO:%.*]], ptr [[THIS1]], i32 0, i32 0
|
|
// CHECK-NEXT: store i8 [[TMP0]], ptr [[X]], align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
template struct Foo<char>;
|
|
|
|
// CHECK-LABEL: @_ZN3FooIsEC1Es(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i16 [[X:%.*]], ptr [[X_ADDR]], align 2
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2
|
|
// CHECK-NEXT: call void @_ZN3FooIsEC2Es(ptr noundef nonnull align 2 dereferenceable(2) [[THIS1]], i16 noundef signext [[TMP0]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3FooIsED1Ev(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: call void @_ZN3FooIsED2Ev(ptr noundef nonnull align 2 dereferenceable(2) [[THIS1]]) #[[ATTR1]]
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3FooIsE3getEv(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_FOO_0:%.*]], ptr [[THIS1]], i32 0, i32 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X]], align 2
|
|
// CHECK-NEXT: ret i16 [[TMP0]]
|
|
//
|
|
// CHECK-LABEL: @_ZN3FooIsE3setEs(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[_X_ADDR:%.*]] = alloca i16, align 2
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i16 [[_X:%.*]], ptr [[_X_ADDR]], align 2
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[_X_ADDR]], align 2
|
|
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_FOO_0:%.*]], ptr [[THIS1]], i32 0, i32 0
|
|
// CHECK-NEXT: store i16 [[TMP0]], ptr [[X]], align 2
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
template struct Foo<short>;
|
|
|
|
// This should not generate lines for the implicit specialization of Foo, but
|
|
// should generate lines for the explicit specialization of Bar.
|
|
|
|
// CHECK-LABEL: @_ZN3BarIiEC1Ei(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i32 [[X:%.*]], ptr [[X_ADDR]], align 4
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
|
|
// CHECK-NEXT: call void @_ZN3BarIiEC2Ei(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3BarIiED1Ev(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: call void @_ZN3BarIiED2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR1]]
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3BarIiE3getEv(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds nuw [[STRUCT_BAR:%.*]], ptr [[THIS1]], i32 0, i32 0
|
|
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN3FooIiE3getEv(ptr noundef nonnull align 4 dereferenceable(4) [[FOO]])
|
|
// CHECK-NEXT: ret i32 [[CALL]]
|
|
//
|
|
// CHECK-LABEL: @_ZN3BarIiE3setEi(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[_X_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i32 [[_X:%.*]], ptr [[_X_ADDR]], align 4
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[FOO:%.*]] = getelementptr inbounds nuw [[STRUCT_BAR:%.*]], ptr [[THIS1]], i32 0, i32 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[_X_ADDR]], align 4
|
|
// CHECK-NEXT: call void @_ZN3FooIiE3setEi(ptr noundef nonnull align 4 dereferenceable(4) [[FOO]], i32 noundef [[TMP0]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
template struct Bar<int>;
|
|
|
|
// This should not generate lines for the implicit specialization of Foo, but
|
|
// should generate lines for the explicit specialization of Baz.
|
|
|
|
// CHECK-LABEL: @_ZN3BazIlEC1El(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i64, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: store i64 [[X:%.*]], ptr [[X_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8
|
|
// CHECK-NEXT: call void @_ZN3BazIlEC2El(ptr noundef nonnull align 8 dereferenceable(8) [[THIS1]], i64 noundef [[TMP0]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-LABEL: @_ZN3BazIlED1Ev(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
|
|
// CHECK-NEXT: call void @_ZN3BazIlED2Ev(ptr noundef nonnull align 8 dereferenceable(8) [[THIS1]]) #[[ATTR1]]
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
template struct Baz<long>;
|