Skip to content

[aarch64] Fix Arm64EC libcall lowering after recent refactoring. #143977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions llvm/include/llvm/IR/RuntimeLibcalls.def
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,16 @@ HANDLE_LIBCALL(UREM_I16, "__umodhi3")
HANDLE_LIBCALL(UREM_I32, "__umodsi3")
HANDLE_LIBCALL(UREM_I64, "__umoddi3")
HANDLE_LIBCALL(UREM_I128, "__umodti3")
HANDLE_LIBCALL(SDIVREM_I8, nullptr)
HANDLE_LIBCALL(SDIVREM_I16, nullptr)
HANDLE_LIBCALL(SDIVREM_I32, nullptr)
HANDLE_LIBCALL(SDIVREM_I64, nullptr)
HANDLE_LIBCALL(SDIVREM_I128, nullptr)
HANDLE_LIBCALL(UDIVREM_I8, nullptr)
HANDLE_LIBCALL(UDIVREM_I16, nullptr)
HANDLE_LIBCALL(UDIVREM_I32, nullptr)
HANDLE_LIBCALL(UDIVREM_I64, nullptr)
HANDLE_LIBCALL(UDIVREM_I128, nullptr)
HANDLE_LIBCALL(SDIVREM_I8, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SDIVREM_I16, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SDIVREM_I32, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SDIVREM_I64, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SDIVREM_I128, LIBCALL_NO_NAME)
HANDLE_LIBCALL(UDIVREM_I8, LIBCALL_NO_NAME)
HANDLE_LIBCALL(UDIVREM_I16, LIBCALL_NO_NAME)
HANDLE_LIBCALL(UDIVREM_I32, LIBCALL_NO_NAME)
HANDLE_LIBCALL(UDIVREM_I64, LIBCALL_NO_NAME)
HANDLE_LIBCALL(UDIVREM_I128, LIBCALL_NO_NAME)
HANDLE_LIBCALL(NEG_I32, "__negsi2")
HANDLE_LIBCALL(NEG_I64, "__negdi2")
HANDLE_LIBCALL(CTLZ_I32, "__clzsi2")
Expand Down Expand Up @@ -240,13 +240,13 @@ HANDLE_LIBCALL(ATAN2_F64, "atan2")
HANDLE_LIBCALL(ATAN2_F80, "atan2l")
HANDLE_LIBCALL(ATAN2_F128,"atan2l")
HANDLE_LIBCALL(ATAN2_PPCF128, "atan2l")
HANDLE_LIBCALL(SINCOS_F32, nullptr)
HANDLE_LIBCALL(SINCOS_F64, nullptr)
HANDLE_LIBCALL(SINCOS_F80, nullptr)
HANDLE_LIBCALL(SINCOS_F128, nullptr)
HANDLE_LIBCALL(SINCOS_PPCF128, nullptr)
HANDLE_LIBCALL(SINCOS_STRET_F32, nullptr)
HANDLE_LIBCALL(SINCOS_STRET_F64, nullptr)
HANDLE_LIBCALL(SINCOS_F32, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SINCOS_F64, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SINCOS_F80, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SINCOS_F128, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SINCOS_PPCF128, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SINCOS_STRET_F32, LIBCALL_NO_NAME)
HANDLE_LIBCALL(SINCOS_STRET_F64, LIBCALL_NO_NAME)
HANDLE_LIBCALL(POW_F32, "powf")
HANDLE_LIBCALL(POW_F64, "pow")
HANDLE_LIBCALL(POW_F80, "powl")
Expand Down Expand Up @@ -518,7 +518,7 @@ HANDLE_LIBCALL(MEMMOVE, "memmove")
HANDLE_LIBCALL(MEMSET, "memset")
// DSEPass can emit calloc if it finds a pair of malloc/memset
HANDLE_LIBCALL(CALLOC, "calloc")
HANDLE_LIBCALL(BZERO, nullptr)
HANDLE_LIBCALL(BZERO, LIBCALL_NO_NAME)

// Element-wise unordered-atomic memory of different sizes
HANDLE_LIBCALL(MEMCPY_ELEMENT_UNORDERED_ATOMIC_1, "__llvm_memcpy_element_unordered_atomic_1")
Expand Down Expand Up @@ -669,10 +669,10 @@ HANDLE_LIBCALL(ATOMIC_FETCH_NAND_16, "__atomic_fetch_nand_16")

// Out-of-line atomics libcalls
#define HLCALLS(A, N) \
HANDLE_LIBCALL(A##N##_RELAX, nullptr) \
HANDLE_LIBCALL(A##N##_ACQ, nullptr) \
HANDLE_LIBCALL(A##N##_REL, nullptr) \
HANDLE_LIBCALL(A##N##_ACQ_REL, nullptr)
HANDLE_LIBCALL(A##N##_RELAX, LIBCALL_NO_NAME) \
HANDLE_LIBCALL(A##N##_ACQ, LIBCALL_NO_NAME) \
HANDLE_LIBCALL(A##N##_REL, LIBCALL_NO_NAME) \
HANDLE_LIBCALL(A##N##_ACQ_REL, LIBCALL_NO_NAME)
#define HLCALL5(A) \
HLCALLS(A, 1) HLCALLS(A, 2) HLCALLS(A, 4) HLCALLS(A, 8) HLCALLS(A, 16)
HLCALL5(OUTLINE_ATOMIC_CAS)
Expand All @@ -691,11 +691,11 @@ HANDLE_LIBCALL(STACKPROTECTOR_CHECK_FAIL, "__stack_chk_fail")
HANDLE_LIBCALL(DEOPTIMIZE, "__llvm_deoptimize")

// Return address
HANDLE_LIBCALL(RETURN_ADDRESS, nullptr)
HANDLE_LIBCALL(RETURN_ADDRESS, LIBCALL_NO_NAME)

// Clear cache
HANDLE_LIBCALL(CLEAR_CACHE, "__clear_cache")
HANDLE_LIBCALL(RISCV_FLUSH_ICACHE, "__riscv_flush_icache")

HANDLE_LIBCALL(UNKNOWN_LIBCALL, nullptr)
HANDLE_LIBCALL(UNKNOWN_LIBCALL, LIBCALL_NO_NAME)

15 changes: 11 additions & 4 deletions llvm/lib/IR/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ static void setAArch64LibcallNames(RuntimeLibcallsInfo &Info,
if (TT.isWindowsArm64EC()) {
// FIXME: are there calls we need to exclude from this?
#define HANDLE_LIBCALL(code, name) \
{ \
if (sizeof(name) != 1) { \
const char *libcallName = Info.getLibcallName(RTLIB::code); \
if (libcallName && libcallName[0] != '#') \
Info.setLibcallName(RTLIB::code, "#" #name); \
if (libcallName && libcallName[0] != '#') { \
assert(strcmp(libcallName, name) == 0 && "Unexpected name"); \
Info.setLibcallName(RTLIB::code, "#" name); \
} \
}
#define LIBCALL_NO_NAME ""
#include "llvm/IR/RuntimeLibcalls.def"
#undef HANDLE_LIBCALL
#undef LIBCALL_NO_NAME
}
}

Expand Down Expand Up @@ -223,8 +227,10 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT) {
nullptr);

#define HANDLE_LIBCALL(code, name) setLibcallName(RTLIB::code, name);
#define LIBCALL_NO_NAME nullptr
#include "llvm/IR/RuntimeLibcalls.def"
#undef HANDLE_LIBCALL
#undef LIBCALL_NO_NAME

// Initialize calling conventions to their default.
for (int LC = 0; LC < RTLIB::UNKNOWN_LIBCALL; ++LC)
Expand Down Expand Up @@ -462,7 +468,8 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT) {
}

// Setup Windows compiler runtime calls.
if (TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment()) {
if (TT.getArch() == Triple::x86 &&
(TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment())) {
static const struct {
const RTLIB::Libcall Op;
const char *const Name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,10 @@ struct StaticLibcallNameMap {
StaticLibcallNameMap() {
static const std::pair<const char *, RTLIB::Libcall> NameLibcalls[] = {
#define HANDLE_LIBCALL(code, name) {(const char *)name, RTLIB::code},
#define LIBCALL_NO_NAME nullptr
#include "llvm/IR/RuntimeLibcalls.def"
#undef HANDLE_LIBCALL
#undef LIBCALL_NO_NAME
};
for (const auto &NameLibcall : NameLibcalls) {
if (NameLibcall.first != nullptr &&
Expand Down
45 changes: 45 additions & 0 deletions llvm/test/CodeGen/AArch64/arm64ec-builtins.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
; RUN: llc -mtriple=arm64ec-pc-windows-msvc < %s | FileCheck %s

define void @f1(ptr %p, i64 %n) {
; CHECK-LABEL: "#f1":
; CHECK: bl "#memset"
call void @llvm.memset.p0.i64(ptr %p, i8 0, i64 %n, i1 false)
ret void
}

define void @f2(ptr %p1, ptr %p2, i64 %n) {
; CHECK-LABEL: "#f2":
; CHECK: bl "#memcpy"
call void @llvm.memcpy.p0.i64(ptr %p1, ptr %p2, i64 %n, i1 false)
ret void
}

define double @f3(double %x, double %y) {
; CHECK-LABEL: "#f3":
; CHECK: b "#fmod"
%r = frem double %x, %y
ret double %r
}

define i128 @f4(i128 %x, i128 %y) {
; CHECK-LABEL: "#f4":
; CHECK: bl "#__divti3"
%r = sdiv i128 %x, %y
ret i128 %r
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I assume this also hits these special cases:

if (TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment()) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And these maybe?

if (TT.isOSWindows() && !TT.isOSCygMing()) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like outlined atomics are broken; I'll add a testcase with the broken behavior. Not going to try to fix it right now (I'm not sure how to fix it given the way the code is currently structured, and it's not really a useful feature on Windows anyway.)

_alldiv etc. are, as far as I know, only a thing on 32-bit x86. 32-bit Arm has different libcalls, and 64-bit doesn't need libcalls for 64-bit operations. So I'm not sure sure there's anything to regression test. But I modified the code because it triggers the assertion otherwise.

llvm.ldexp.f32 correctly calls #ldexp (the 64-bit variant); I'll add a test. llvm.ldexp.f128 crashes for unrelated reasons (#144006).

; FIXME: This is wrong; should be "#__aarch64_cas1_relax"
define i8 @f5(i8 %expected, i8 %new, ptr %ptr) "target-features"="+outline-atomics" {
; CHECK-LABEL: "#f5":
; CHECK: bl __aarch64_cas1_relax
%pair = cmpxchg ptr %ptr, i8 %expected, i8 %new monotonic monotonic, align 1
%r = extractvalue { i8, i1 } %pair, 0
ret i8 %r
}

define float @f6(float %val, i32 %a) {
; CHECK-LABEL: "#f6":
; CHECK: bl "#ldexp"
%call = tail call fast float @llvm.ldexp.f32(float %val, i32 %a)
ret float %call
}
Loading