Skip to content

Commit beea2a9

Browse files
authored
[Clang] Respect MS layout attributes during CUDA/HIP device compilation (#146620)
This patch fixes an issue where Microsoft-specific layout attributes, such as __declspec(empty_bases), were ignored during CUDA/HIP device compilation on a Windows host. This caused a critical memory layout mismatch between host and device objects, breaking libraries that rely on these attributes for ABI compatibility. The fix introduces a centralized hasMicrosoftRecordLayout() check within the TargetInfo class. This check is aware of the auxiliary (host) target and is set during TargetInfo::adjust if the host uses a Microsoft ABI. The empty_bases, layout_version, and msvc::no_unique_address attributes now use this centralized flag, ensuring device code respects them and maintains layout consistency with the host. Fixes: #146047
1 parent ab187bb commit beea2a9

File tree

19 files changed

+95
-45
lines changed

19 files changed

+95
-45
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,22 @@ def TargetHasDLLImportExport : TargetSpec {
492492
def TargetItaniumCXXABI : TargetSpec {
493493
let CustomCode = [{ Target.getCXXABI().isItaniumFamily() }];
494494
}
495+
495496
def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> {
496497
let CustomCode = [{ Target.getCXXABI().isMicrosoft() }];
497498
}
499+
500+
// The target follows Microsoft record layout. Usually this happens in two
501+
// cases: 1. the target itself has Microsoft C++ ABI, e.g. x86_64 in MSVC
502+
// environment on Windows 2. an offloading target e.g. amdgcn or nvptx with
503+
// a host target in MSVC environment on Windows.
504+
def TargetMicrosoftRecordLayout : TargetArch<["x86", "x86_64", "arm", "thumb",
505+
"aarch64", "amdgcn", "nvptx",
506+
"nvptx64", "spirv", "spirv32",
507+
"spirv64"]> {
508+
let CustomCode = [{ Target.hasMicrosoftRecordLayout() }];
509+
}
510+
498511
def TargetELF : TargetSpec {
499512
let ObjectFormats = ["ELF"];
500513
}
@@ -1789,7 +1802,7 @@ def Destructor : InheritableAttr {
17891802
let Documentation = [CtorDtorDocs];
17901803
}
17911804

1792-
def EmptyBases : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
1805+
def EmptyBases : InheritableAttr, TargetSpecificAttr<TargetMicrosoftRecordLayout> {
17931806
let Spellings = [Declspec<"empty_bases">];
17941807
let Subjects = SubjectList<[CXXRecord]>;
17951808
let Documentation = [EmptyBasesDocs];
@@ -2021,7 +2034,7 @@ def Restrict : InheritableAttr {
20212034
let Documentation = [RestrictDocs];
20222035
}
20232036

2024-
def LayoutVersion : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
2037+
def LayoutVersion : InheritableAttr, TargetSpecificAttr<TargetMicrosoftRecordLayout> {
20252038
let Spellings = [Declspec<"layout_version">];
20262039
let Args = [UnsignedArgument<"Version">];
20272040
let Subjects = SubjectList<[CXXRecord]>;
@@ -2239,7 +2252,7 @@ def NoUniqueAddress : InheritableAttr {
22392252
let Spellings = [CXX11<"", "no_unique_address", 201803>, CXX11<"msvc", "no_unique_address", 201803>];
22402253
let TargetSpecificSpellings = [
22412254
TargetSpecificSpelling<TargetItaniumCXXABI, [CXX11<"", "no_unique_address", 201803>]>,
2242-
TargetSpecificSpelling<TargetMicrosoftCXXABI, [CXX11<"msvc", "no_unique_address", 201803>]>,
2255+
TargetSpecificSpelling<TargetMicrosoftRecordLayout, [CXX11<"msvc", "no_unique_address", 201803>]>,
22432256
];
22442257
let Documentation = [NoUniqueAddressDocs];
22452258
}

clang/include/clang/Basic/TargetInfo.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ class TargetInfo : public TransferrableTargetInfo,
289289

290290
std::optional<llvm::Triple> DarwinTargetVariantTriple;
291291

292+
bool HasMicrosoftRecordLayout = false;
293+
292294
// TargetInfo Constructor. Default initializes all fields.
293295
TargetInfo(const llvm::Triple &T);
294296

@@ -1331,7 +1333,8 @@ class TargetInfo : public TransferrableTargetInfo,
13311333
/// Apply changes to the target information with respect to certain
13321334
/// language options which change the target configuration and adjust
13331335
/// the language based on the target options where applicable.
1334-
virtual void adjust(DiagnosticsEngine &Diags, LangOptions &Opts);
1336+
virtual void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
1337+
const TargetInfo *Aux);
13351338

13361339
/// Initialize the map with the default set of target features for the
13371340
/// CPU this should include all legal feature strings on the target.
@@ -1846,6 +1849,8 @@ class TargetInfo : public TransferrableTargetInfo,
18461849

18471850
virtual void setAuxTarget(const TargetInfo *Aux) {}
18481851

1852+
bool hasMicrosoftRecordLayout() const { return HasMicrosoftRecordLayout; }
1853+
18491854
/// Whether target allows debuginfo types for decl only variables/functions.
18501855
virtual bool allowDebugInfoForExternalRef() const { return false; }
18511856

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,15 +2458,6 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
24582458
llvm_unreachable("bad tail-padding use kind");
24592459
}
24602460

2461-
static bool isMsLayout(const ASTContext &Context) {
2462-
// Check if it's CUDA device compilation; ensure layout consistency with host.
2463-
if (Context.getLangOpts().CUDA && Context.getLangOpts().CUDAIsDevice &&
2464-
Context.getAuxTargetInfo())
2465-
return Context.getAuxTargetInfo()->getCXXABI().isMicrosoft();
2466-
2467-
return Context.getTargetInfo().getCXXABI().isMicrosoft();
2468-
}
2469-
24702461
// This section contains an implementation of struct layout that is, up to the
24712462
// included tests, compatible with cl.exe (2013). The layout produced is
24722463
// significantly different than those produced by the Itanium ABI. Here we note
@@ -3399,7 +3390,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
33993390

34003391
const ASTRecordLayout *NewEntry = nullptr;
34013392

3402-
if (isMsLayout(*this)) {
3393+
if (getTargetInfo().hasMicrosoftRecordLayout()) {
34033394
if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
34043395
EmptySubobjectMap EmptySubobjects(*this, RD);
34053396
MicrosoftRecordLayoutBuilder Builder(*this, &EmptySubobjects);
@@ -3656,7 +3647,8 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
36563647
bool HasOwnVBPtr = Layout.hasOwnVBPtr();
36573648

36583649
// Vtable pointer.
3659-
if (CXXRD->isDynamicClass() && !PrimaryBase && !isMsLayout(C)) {
3650+
if (CXXRD->isDynamicClass() && !PrimaryBase &&
3651+
!C.getTargetInfo().hasMicrosoftRecordLayout()) {
36603652
PrintOffset(OS, Offset, IndentLevel);
36613653
OS << '(' << *RD << " vtable pointer)\n";
36623654
} else if (HasOwnVFPtr) {
@@ -3754,7 +3746,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
37543746

37553747
PrintIndentNoOffset(OS, IndentLevel - 1);
37563748
OS << "[sizeof=" << Layout.getSize().getQuantity();
3757-
if (CXXRD && !isMsLayout(C))
3749+
if (CXXRD && !C.getTargetInfo().hasMicrosoftRecordLayout())
37583750
OS << ", dsize=" << Layout.getDataSize().getQuantity();
37593751
OS << ", align=" << Layout.getAlignment().getQuantity();
37603752
if (C.getTargetInfo().defaultsToAIXPowerAlignment())
@@ -3793,7 +3785,7 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
37933785
OS << "\nLayout: ";
37943786
OS << "<ASTRecordLayout\n";
37953787
OS << " Size:" << toBits(Info.getSize()) << "\n";
3796-
if (!isMsLayout(*this))
3788+
if (!getTargetInfo().hasMicrosoftRecordLayout())
37973789
OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
37983790
OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
37993791
if (Target->defaultsToAIXPowerAlignment())

clang/lib/Basic/TargetInfo.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
176176
? TargetCXXABI::Microsoft
177177
: TargetCXXABI::GenericItanium);
178178

179+
HasMicrosoftRecordLayout = TheCXXABI.isMicrosoft();
180+
179181
// Default to an empty address space map.
180182
AddrSpaceMap = &DefaultAddrSpaceMap;
181183
UseAddrSpaceMapMangling = false;
@@ -410,7 +412,8 @@ bool TargetInfo::isTypeSigned(IntType T) {
410412
/// Apply changes to the target information with respect to certain
411413
/// language options which change the target configuration and adjust
412414
/// the language based on the target options where applicable.
413-
void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
415+
void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
416+
const TargetInfo *Aux) {
414417
if (Opts.NoBitFieldTypeAlign)
415418
UseBitFieldTypeAlignment = false;
416419

@@ -550,6 +553,10 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
550553

551554
if (Opts.FakeAddressSpaceMap)
552555
AddrSpaceMap = &FakeAddrSpaceMap;
556+
557+
// Check if it's CUDA device compilation; ensure layout consistency with host.
558+
if (Opts.CUDA && Opts.CUDAIsDevice && Aux && !HasMicrosoftRecordLayout)
559+
HasMicrosoftRecordLayout = Aux->getCXXABI().isMicrosoft();
553560
}
554561

555562
bool TargetInfo::initFeatureMap(

clang/lib/Basic/Targets/AMDGPU.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,9 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple,
271271
HalfArgsAndReturns = true;
272272
}
273273

274-
void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
275-
TargetInfo::adjust(Diags, Opts);
274+
void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
275+
const TargetInfo *Aux) {
276+
TargetInfo::adjust(Diags, Opts, Aux);
276277
// ToDo: There are still a few places using default address space as private
277278
// address space in OpenCL, which needs to be cleaned up, then the references
278279
// to OpenCL can be removed from the following line.

clang/lib/Basic/Targets/AMDGPU.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
8989

9090
void setAddressSpaceMap(bool DefaultIsPrivate);
9191

92-
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override;
92+
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
93+
const TargetInfo *Aux) override;
9394

9495
uint64_t getPointerWidthV(LangAS AS) const override {
9596
if (isR600(getTriple()))

clang/lib/Basic/Targets/DirectX.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
9595
return TargetInfo::VoidPtrBuiltinVaList;
9696
}
9797

98-
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
99-
TargetInfo::adjust(Diags, Opts);
98+
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
99+
const TargetInfo *Aux) override {
100+
TargetInfo::adjust(Diags, Opts, Aux);
100101
// The static values this addresses do not apply outside of the same thread
101102
// This protection is neither available nor needed
102103
Opts.ThreadsafeStatics = false;

clang/lib/Basic/Targets/PPC.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,10 +758,11 @@ void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
758758
llvm::PPC::fillValidCPUList(Values);
759759
}
760760

761-
void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
761+
void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
762+
const TargetInfo *Aux) {
762763
if (HasAltivec)
763764
Opts.AltiVec = 1;
764-
TargetInfo::adjust(Diags, Opts);
765+
TargetInfo::adjust(Diags, Opts, Aux);
765766
if (LongDoubleFormat != &llvm::APFloat::IEEEdouble())
766767
LongDoubleFormat = Opts.PPCIEEELongDouble
767768
? &llvm::APFloat::IEEEquad()

clang/lib/Basic/Targets/PPC.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
8888
}
8989

9090
// Set the language option for altivec based on our value.
91-
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override;
91+
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
92+
const TargetInfo *Aux) override;
9293

9394
// Note: GCC recognizes the following additional cpus:
9495
// 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801,

clang/lib/Basic/Targets/SPIR.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,9 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
205205
AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap;
206206
}
207207

208-
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
209-
TargetInfo::adjust(Diags, Opts);
208+
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
209+
const TargetInfo *Aux) override {
210+
TargetInfo::adjust(Diags, Opts, Aux);
210211
// FIXME: SYCL specification considers unannotated pointers and references
211212
// to be pointing to the generic address space. See section 5.9.3 of
212213
// SYCL 2020 specification.
@@ -383,8 +384,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
383384
std::optional<LangAS> getConstantAddressSpace() const override {
384385
return ConstantAS;
385386
}
386-
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
387-
BaseSPIRVTargetInfo::adjust(Diags, Opts);
387+
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
388+
const TargetInfo *Aux) override {
389+
BaseSPIRVTargetInfo::adjust(Diags, Opts, Aux);
388390
// opencl_constant will map to UniformConstant in SPIR-V
389391
if (Opts.OpenCL)
390392
ConstantAS = LangAS::opencl_constant;
@@ -446,8 +448,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final
446448

447449
void setAuxTarget(const TargetInfo *Aux) override;
448450

449-
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
450-
TargetInfo::adjust(Diags, Opts);
451+
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,
452+
const TargetInfo *Aux) override {
453+
TargetInfo::adjust(Diags, Opts, Aux);
451454
}
452455

453456
bool hasInt128Type() const override { return TargetInfo::hasInt128Type(); }

0 commit comments

Comments
 (0)