Skip to content

Commit 5f96d58

Browse files
committed
Fix Arm64EC name mangling algorithm
1 parent cb98366 commit 5f96d58

File tree

3 files changed

+78
-7
lines changed

3 files changed

+78
-7
lines changed

llvm/include/llvm/IR/Mangler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ std::optional<std::string> getArm64ECDemangledFunctionName(StringRef Name);
6464
/// Check if an ARM64EC function name is mangled.
6565
bool inline isArm64ECMangledFunctionName(StringRef Name) {
6666
return Name[0] == '#' ||
67-
(Name[0] == '?' && Name.find("$$h") != StringRef::npos);
67+
(Name[0] == '?' && Name.find("@$$h") != StringRef::npos);
6868
}
6969

7070
} // End llvm namespace

llvm/lib/IR/Mangler.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,14 +302,23 @@ std::optional<std::string> llvm::getArm64ECMangledFunctionName(StringRef Name) {
302302
// Insert the ARM64EC "$$h" tag after the mangled function name.
303303
if (Name.contains("$$h"))
304304
return std::nullopt;
305-
size_t InsertIdx = Name.find("@@");
306-
size_t ThreeAtSignsIdx = Name.find("@@@");
307-
if (InsertIdx != std::string::npos && InsertIdx != ThreeAtSignsIdx) {
305+
306+
// The last 4 characters of the symbol type may contain a `@@` if the symbol
307+
// is returning a qualified type. We don't want to insert `$$h` at that point.
308+
auto TrimmedName = Name.drop_back(4);
309+
310+
// The last `@@` is the separation between the qualified name of the symbol
311+
// and its type, which is where we want to insert `$$h`.
312+
auto InsertIdx = TrimmedName.rfind("@@");
313+
if (InsertIdx != StringRef::npos) {
308314
InsertIdx += 2;
309315
} else {
310-
InsertIdx = Name.find("@");
311-
if (InsertIdx != std::string::npos)
312-
InsertIdx++;
316+
// If there is no `@@`, then this is a global symbol (e.g., `operator new`)
317+
// so look for a `@` instead (since we assume that it will not return a
318+
// qualified type).
319+
InsertIdx = TrimmedName.find_last_of('@');
320+
assert(InsertIdx != StringRef::npos && "Invalid mangled name");
321+
InsertIdx += 1;
313322
}
314323

315324
return std::optional<std::string>(

llvm/unittests/IR/ManglerTest.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,66 @@ TEST(ManglerTest, GOFF) {
172172
"L#foo");
173173
}
174174

175+
TEST(ManglerTest, Arm64EC) {
176+
constexpr std::string_view Arm64ECNames[] = {
177+
// Basic C name.
178+
"#Foo",
179+
180+
// Basic C++ name.
181+
"?foo@@$$hYAHXZ",
182+
183+
// Regression test: https://github.com/llvm/llvm-project/issues/115231
184+
"?GetValue@?$Wrapper@UA@@@@$$hQEBAHXZ",
185+
186+
// Symbols from:
187+
// ```
188+
// namespace A::B::C::D {
189+
// struct Base {
190+
// virtual int f() { return 0; }
191+
// };
192+
// }
193+
// struct Derived : public A::B::C::D::Base {
194+
// virtual int f() override { return 1; }
195+
// };
196+
// A::B::C::D::Base* MakeObj() { return new Derived(); }
197+
// ```
198+
// void * __cdecl operator new(unsigned __int64)
199+
"??2@$$hYAPEAX_K@Z",
200+
// public: virtual int __cdecl A::B::C::D::Base::f(void)
201+
"?f@Base@D@C@B@A@@$$hUEAAHXZ",
202+
// public: __cdecl A::B::C::D::Base::Base(void)
203+
"??0Base@D@C@B@A@@$$hQEAA@XZ",
204+
// public: virtual int __cdecl Derived::f(void)
205+
"?f@Derived@@$$hUEAAHXZ",
206+
// public: __cdecl Derived::Derived(void)
207+
"??0Derived@@$$hQEAA@XZ",
208+
// struct A::B::C::D::Base * __cdecl MakeObj(void)
209+
"?MakeObj@@$$hYAPEAUBase@D@C@B@A@@XZ",
210+
};
211+
212+
for (const auto &Arm64ECName : Arm64ECNames) {
213+
// Check that this is a mangled name.
214+
EXPECT_TRUE(isArm64ECMangledFunctionName(Arm64ECName))
215+
<< "Test case: " << Arm64ECName;
216+
// Refuse to mangle it again.
217+
EXPECT_FALSE(getArm64ECMangledFunctionName(Arm64ECName).has_value())
218+
<< "Test case: " << Arm64ECName;
219+
220+
// Demangle.
221+
auto Arm64Name = getArm64ECDemangledFunctionName(Arm64ECName);
222+
EXPECT_TRUE(Arm64Name.has_value()) << "Test case: " << Arm64ECName;
223+
// Check that it is not mangled.
224+
EXPECT_FALSE(isArm64ECMangledFunctionName(Arm64Name.value()))
225+
<< "Test case: " << Arm64ECName;
226+
// Refuse to demangle it again.
227+
EXPECT_FALSE(getArm64ECDemangledFunctionName(Arm64Name.value()).has_value())
228+
<< "Test case: " << Arm64ECName;
229+
230+
// Round-trip.
231+
auto RoundTripArm64ECName =
232+
getArm64ECMangledFunctionName(Arm64Name.value());
233+
EXPECT_EQ(RoundTripArm64ECName, Arm64ECName);
234+
}
235+
}
236+
175237
} // end anonymous namespace

0 commit comments

Comments
 (0)