From 2f72e1596764e9fd052705ced0bf4800a86f9081 Mon Sep 17 00:00:00 2001 From: Bart Coppens Date: Mon, 15 Jan 2024 18:18:25 +0100 Subject: [PATCH] Respect the alignment attribute of functions (#186) Respect the alignment attribute of functions. This is necessary to support calls to function pointer calls to member functions (which need to be aligned to 2, and the generated code crashes if this happens to be not the case) MSVC doesn't support adding alignment to functions, so create a separate #define for this, which is a no-op on MSVC Given that this occurs in several tests, and the MSVC tests have error-on-warning, this is a comment rather than a #warning --- lib/Target/CBackend/CBackend.cpp | 18 +++++++++++ lib/Target/CBackend/CBackend.h | 2 ++ .../cpp_tests/test_virtual_function_calls.cpp | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 test/cpp_tests/test_virtual_function_calls.cpp diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index e9f5b6e6..a1b0620b 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -2051,6 +2051,15 @@ static void defineAligns(raw_ostream &Out) { Out << "#endif\n\n"; } +static void defineFunctionAlign(raw_ostream &Out) { + Out << "#ifdef _MSC_VER\n"; + Out << "#define __FUNCTIONALIGN__(X) /* WARNING: THIS FEATURE IS NOT " + "SUPPORTED BY MSVC! */ \n"; + Out << "#else\n"; + Out << "#define __FUNCTIONALIGN__(X) __attribute__((aligned(X)))\n"; + Out << "#endif\n\n"; +} + static void defineUnreachable(raw_ostream &Out) { Out << "#ifdef _MSC_VER\n"; Out << "#define __builtin_unreachable() __assume(0)\n"; @@ -2355,6 +2364,8 @@ void CWriter::generateCompilerSpecificCode(raw_ostream &Out, defineUnalignedLoad(Out); if (headerIncAligns()) defineAligns(Out); + if (headerIncFunctionAlign()) + defineFunctionAlign(Out); if (headerIncNanInf()) defineNanInf(Out); if (headerIncInt128()) @@ -2632,6 +2643,7 @@ void CWriter::generateHeader(Module &M) { headerUseAttributeWeak(); Out << "__MSVC_INLINE__ "; } + printFunctionProto(Out, &*I, GetValueName(&*I)); printFunctionAttributes(Out, I->getAttributes()); if (I->hasWeakLinkage() || I->hasLinkOnceLinkage()) { @@ -2655,6 +2667,12 @@ void CWriter::generateHeader(Module &M) { Out << " __HIDDEN__"; } + unsigned Alignment = I->getAlignment(); + if (Alignment != 0) { + headerUseFunctionAlign(); + Out << " __FUNCTIONALIGN__(" << Alignment << ") "; + } + if (I->hasName() && I->getName()[0] == 1) Out << " __asm__ (\"" << I->getName().substr(1) << "\")"; diff --git a/lib/Target/CBackend/CBackend.h b/lib/Target/CBackend/CBackend.h index e45bae54..64b0a076 100644 --- a/lib/Target/CBackend/CBackend.h +++ b/lib/Target/CBackend/CBackend.h @@ -112,6 +112,7 @@ class CWriter : public FunctionPass, public InstVisitor { bool AttributeList : 1; bool UnalignedLoad : 1; bool Aligns : 1; + bool FunctionAlign : 1; bool NanInf : 1; bool Int128 : 1; bool ThreadFence : 1; @@ -148,6 +149,7 @@ class CWriter : public FunctionPass, public InstVisitor { USED_HEADERS_FLAG(AttributeList) USED_HEADERS_FLAG(UnalignedLoad) USED_HEADERS_FLAG(Aligns) + USED_HEADERS_FLAG(FunctionAlign) USED_HEADERS_FLAG(NanInf) USED_HEADERS_FLAG(Int128) USED_HEADERS_FLAG(ThreadFence) diff --git a/test/cpp_tests/test_virtual_function_calls.cpp b/test/cpp_tests/test_virtual_function_calls.cpp new file mode 100644 index 00000000..2860a71c --- /dev/null +++ b/test/cpp_tests/test_virtual_function_calls.cpp @@ -0,0 +1,31 @@ +#ifndef _MSC_VER +// Suppress "dereferencing type-punned pointer will break strict-aliasing rules" +// gcc_extra_args: -Wno-strict-aliasing +struct A { + int a; + int b; + int f1(int i) { return 1 + i; } + int f2(int i) { return 1 + i; } + typedef int (A::*Function)(int); + int function_wrapper(Function f, int i) __attribute__((noinline)) { + return (this->*f)(i); + } +}; + +int main() { + A a{}; + if (a.function_wrapper(&A::f1, 1) != 2) + return 0; + if (a.function_wrapper(&A::f2, 1) != 2) + return 0; + return 6; +} + +#else + +/* MSVC doesn't support adding alignment to functions, treat it as an expected + * failure */ + +int main() { return 25; } + +#endif