Avoid setting always-inline for functions that contain DMD-style inline assembly. (#4631)

As the presence of DMD-style inline assembly in a function causes
never-inline to be set for that function.
This commit is contained in:
Harry Gillanders 2024-04-28 00:11:22 +01:00 committed by GitHub
parent 696a18b70b
commit 48db5d5621
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 66 additions and 7 deletions

View file

@ -654,7 +654,22 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {
irFunc->setNeverInline();
} else {
if (fdecl->inlining == PINLINE::always) {
// If the function contains DMD-style inline assembly.
if (fdecl->hasReturnExp & 32) {
// The presence of DMD-style inline assembly in a function causes that
// function to become never-inline. So, if this function contains DMD-style
// inline assembly we'll emit an error as it can't be made always-inline.
// However, we'll make an exception for C functions, as the C standard doesn't
// actually require that `inline` functions be inlined. So, for C functions we just
// ignore the attempt to make it always-inline.
if (!fdecl->isCsymbol()) {
error(fdecl->loc,
"`%s` cannot be `pragma(inline, true)` as it contains DMD-style inline assembly",
fdecl->toPrettyChars());
}
} else {
irFunc->setAlwaysInline();
}
} else if (fdecl->inlining == PINLINE::never) {
irFunc->setNeverInline();
}

View file

@ -0,0 +1,15 @@
// ImportC treats `inline` C functions as though `pragma(inline, true)` was applied to them.
// The presence of DMD-style inline assembly inhibits inlining,
// so if `pragma(inline, true)` is also present, an error should occur; but C doesn't
// require that an `inline` function is actually inlined, so we permit `inline` C functions
// to contain DMD-style inline assembly,
// REQUIRES: Windows && target_X86
// RUN: %ldc -mtriple=i686-pc-windows-msvc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
// CHECK-NOT: alwaysinline
inline unsigned int hasDMDStyleAsm(unsigned int a) {
asm {
mov EAX, dword ptr [a];
}
}

View file

@ -1,14 +1,11 @@
module inputs.inlinables_asm;
import ldc.attributes;
import ldc.llvmasm;
extern (C): // simplify mangling for easier function name matching
pragma(inline, true) extern (C) void naked_asm_func()
pragma(inline, true) extern (C) @naked void naked_asm_func()
{
asm pure nothrow @nogc
{
naked;
nop;
}
return __asm("nop", "");
}

View file

@ -0,0 +1,15 @@
// The presence of non-DMD-style inline assembly does not inhibit inlining,
// so `pragma(inline, true)` should work for functions containing non-DMD-style inline assembly.
// REQUIRES: target_X86
// RUN: %ldc -mtriple=i686-pc-windows-msvc -output-ll -of=%t.ll -c %s && FileCheck %s < %t.ll
import ldc.llvmasm;
// CHECK: alwaysinline
// CHECK-NEXT: {{define.+hasLDCStyleAsm}}
pragma(inline, true)
uint hasLDCStyleAsm(uint a)
{
return __asm!uint("add 7, $0", "=r,0,~{flags}", a);
}

View file

@ -0,0 +1,17 @@
// The presence of DMD-style inline assembly inhibits inlining,
// so if `pragma(inline, true)` is also present, some kind of error should occur.
// REQUIRES: target_X86
// RUN: not %ldc -mtriple=i686-pc-windows-msvc -c %s 2>&1 | FileCheck %s
module dmd_style_asm_in_inline_d_function;
// CHECK: `dmd_style_asm_in_inline_d_function.hasDMDStyleAsm` cannot be `pragma(inline, true)` as it contains DMD-style inline assembly
pragma(inline, true)
uint hasDMDStyleAsm(uint a)
{
asm
{
mov EAX, dword ptr [a];
}
}