[Clang] Verify data layout consistency (#144720)

Verify that the alignments specified by clang TargetInfo match the
alignments specified by LLVM data layout, which will hopefully prevent
accidental mismatches in the future.

This currently contains opt-outs for a number of of existing mismatches.

I'm also skipping the verification if options like `-malign-double` are
used, or a language that mandates sizes/alignments that differ from C.

The verification happens in CodeGen, as we can't have an IR dependency
in Basic.
This commit is contained in:
Nikita Popov
2025-07-01 10:43:40 +02:00
committed by GitHub
parent cb80651091
commit 5fa4eb1dfd

View File

@@ -332,6 +332,72 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *TheTargetCodeGenInfo;
}
static void checkDataLayoutConsistency(const TargetInfo &Target,
llvm::LLVMContext &Context,
const LangOptions &Opts) {
#ifndef NDEBUG
// Don't verify non-standard ABI configurations.
if (Opts.AlignDouble || Opts.OpenCL || Opts.HLSL)
return;
llvm::Triple Triple = Target.getTriple();
llvm::DataLayout DL(Target.getDataLayoutString());
auto Check = [&](const char *Name, llvm::Type *Ty, unsigned Alignment) {
llvm::Align DLAlign = DL.getABITypeAlign(Ty);
llvm::Align ClangAlign(Alignment / 8);
if (DLAlign != ClangAlign) {
llvm::errs() << "For target " << Triple.str() << " type " << Name
<< " mapping to " << *Ty << " has data layout alignment "
<< DLAlign.value() << " while clang specifies "
<< ClangAlign.value() << "\n";
abort();
}
};
Check("bool", llvm::Type::getIntNTy(Context, Target.BoolWidth),
Target.BoolAlign);
Check("short", llvm::Type::getIntNTy(Context, Target.ShortWidth),
Target.ShortAlign);
Check("int", llvm::Type::getIntNTy(Context, Target.IntWidth),
Target.IntAlign);
Check("long", llvm::Type::getIntNTy(Context, Target.LongWidth),
Target.LongAlign);
// FIXME: M68k specifies incorrect long long alignment in both LLVM and Clang.
if (Triple.getArch() != llvm::Triple::m68k)
Check("long long", llvm::Type::getIntNTy(Context, Target.LongLongWidth),
Target.LongLongAlign);
// FIXME: There are int128 alignment mismatches on multiple targets.
if (Target.hasInt128Type() && !Target.getTargetOpts().ForceEnableInt128 &&
!Triple.isAMDGPU() && !Triple.isSPIRV() &&
Triple.getArch() != llvm::Triple::ve)
Check("__int128", llvm::Type::getIntNTy(Context, 128), Target.Int128Align);
if (Target.hasFloat16Type())
Check("half", llvm::Type::getFloatingPointTy(Context, *Target.HalfFormat),
Target.HalfAlign);
if (Target.hasBFloat16Type())
Check("bfloat", llvm::Type::getBFloatTy(Context), Target.BFloat16Align);
Check("float", llvm::Type::getFloatingPointTy(Context, *Target.FloatFormat),
Target.FloatAlign);
// FIXME: AIX specifies wrong double alignment in DataLayout
if (!Triple.isOSAIX()) {
Check("double",
llvm::Type::getFloatingPointTy(Context, *Target.DoubleFormat),
Target.DoubleAlign);
Check("long double",
llvm::Type::getFloatingPointTy(Context, *Target.LongDoubleFormat),
Target.LongDoubleAlign);
}
// FIXME: Wasm has a mismatch in f128 alignment between Clang and LLVM.
if (Target.hasFloat128Type() && !Triple.isWasm())
Check("__float128", llvm::Type::getFP128Ty(Context), Target.Float128Align);
if (Target.hasIbm128Type())
Check("__ibm128", llvm::Type::getPPC_FP128Ty(Context), Target.Ibm128Align);
Check("void*", llvm::PointerType::getUnqual(Context), Target.PointerAlign);
#endif
}
CodeGenModule::CodeGenModule(ASTContext &C,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HSO,
@@ -487,6 +553,9 @@ CodeGenModule::CodeGenModule(ASTContext &C,
llvm::sort(this->MSHotPatchFunctions);
}
if (!Context.getAuxTargetInfo())
checkDataLayoutConsistency(Context.getTargetInfo(), LLVMContext, LangOpts);
}
CodeGenModule::~CodeGenModule() {}