Use the DataLayout-aware TargetFolder instead of ConstantFolder in Clang's CGBuilder. The primary impact of this change is that GEP constant expressions are now emitted in canonical `getelementptr i8` form. This is in preparation for the migration to ptradd, which requires this form. Part of the test updates were performed by Claude Code and reviewed by me.
62 lines
2.4 KiB
C++
62 lines
2.4 KiB
C++
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
|
|
|
extern "C" void* memcpy(void*, const void*, decltype(sizeof(int)));
|
|
void func();
|
|
|
|
namespace std {
|
|
template <class T>
|
|
class reference_wrapper {
|
|
T* ptr;
|
|
|
|
public:
|
|
T& get() { return *ptr; }
|
|
};
|
|
} // namespace std
|
|
|
|
struct Callable {
|
|
void operator()() {}
|
|
|
|
void func();
|
|
};
|
|
|
|
extern "C" void call1() {
|
|
__builtin_invoke(func);
|
|
__builtin_invoke(Callable{});
|
|
__builtin_invoke(memcpy, nullptr, nullptr, 0);
|
|
|
|
// CHECK: define dso_local void @call1
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: %ref.tmp = alloca %struct.Callable, align 1
|
|
// CHECK-NEXT: call void @_Z4funcv()
|
|
// CHECK-NEXT: call void @_ZN8CallableclEv(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp)
|
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 null, ptr align 1 null, i64 0, i1 false)
|
|
// CHECK-NEXT: ret void
|
|
}
|
|
|
|
extern "C" void call_memptr(std::reference_wrapper<Callable> wrapper) {
|
|
__builtin_invoke(&Callable::func, wrapper);
|
|
|
|
// CHECK: define dso_local void @call_memptr
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: %wrapper = alloca %"class.std::reference_wrapper", align 8
|
|
// CHECK-NEXT: %coerce.dive = getelementptr inbounds nuw %"class.std::reference_wrapper", ptr %wrapper, i32 0, i32 0
|
|
// CHECK-NEXT: store ptr %wrapper.coerce, ptr %coerce.dive, align 8
|
|
// CHECK-NEXT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_ZNSt17reference_wrapperI8CallableE3getEv(ptr noundef nonnull align 8 dereferenceable(8) %wrapper)
|
|
// CHECK-NEXT: %0 = getelementptr inbounds i8, ptr %call, i64 0
|
|
// CHECK-NEXT: br i1 false, label %memptr.virtual, label %memptr.nonvirtual
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: memptr.virtual:
|
|
// CHECK-NEXT: %vtable = load ptr, ptr %0, align 8
|
|
// CHECK-NEXT: %1 = getelementptr i8, ptr %vtable, i64 sub (i64 ptrtoint (ptr @_ZN8Callable4funcEv to i64), i64 1), !nosanitize !1
|
|
// CHECK-NEXT: %memptr.virtualfn = load ptr, ptr %1, align 8, !nosanitize !1
|
|
// CHECK-NEXT: br label %memptr.end
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: memptr.nonvirtual:
|
|
// CHECK-NEXT: br label %memptr.end
|
|
// CHECK-EMPTY:
|
|
// CHECK-NEXT: memptr.end:
|
|
// CHECK-NEXT: %2 = phi ptr [ %memptr.virtualfn, %memptr.virtual ], [ @_ZN8Callable4funcEv, %memptr.nonvirtual ]
|
|
// CHECK-NEXT: call void %2(ptr noundef nonnull align 1 dereferenceable(1) %0)
|
|
// CHECK-NEXT: ret void
|
|
}
|