Skip to content

Commit

Permalink
Implement IRGen for the x86 vectorcall convention
Browse files Browse the repository at this point in the history
The most complex aspect of the convention is the handling of homogeneous
vector and floating point aggregates.  Reuse the homogeneous aggregate
classification code that we use on PPC64 and ARM for this.

This convention also has a C mangling, and we apparently implement that
in both Clang and LLVM.

Reviewed By: majnemer

Differential Revision: http://reviews.llvm.org/D6063

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221006 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
rnk committed Oct 31, 2014
1 parent 6feb239 commit 3568925
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 62 deletions.
53 changes: 31 additions & 22 deletions lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ static void mangleFunctionBlock(MangleContext &Context,

void MangleContext::anchor() { }

enum StdOrFastCC {
SOF_OTHER,
SOF_FAST,
SOF_STD
enum CCMangling {
CCM_Other,
CCM_Fast,
CCM_Vector,
CCM_Std
};

static bool isExternC(const NamedDecl *ND) {
Expand All @@ -61,40 +62,44 @@ static bool isExternC(const NamedDecl *ND) {
return cast<VarDecl>(ND)->isExternC();
}

static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
const NamedDecl *ND) {
static CCMangling getCallingConvMangling(const ASTContext &Context,
const NamedDecl *ND) {
const TargetInfo &TI = Context.getTargetInfo();
const llvm::Triple &Triple = TI.getTriple();
if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86)
return SOF_OTHER;
if (!Triple.isOSWindows() ||
!(Triple.getArch() == llvm::Triple::x86 ||
Triple.getArch() == llvm::Triple::x86_64))
return CCM_Other;

if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
TI.getCXXABI() == TargetCXXABI::Microsoft)
return SOF_OTHER;
return CCM_Other;

const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
if (!FD)
return SOF_OTHER;
return CCM_Other;
QualType T = FD->getType();

const FunctionType *FT = T->castAs<FunctionType>();

CallingConv CC = FT->getCallConv();
switch (CC) {
default:
return SOF_OTHER;
return CCM_Other;
case CC_X86FastCall:
return SOF_FAST;
return CCM_Fast;
case CC_X86StdCall:
return SOF_STD;
return CCM_Std;
case CC_X86VectorCall:
return CCM_Vector;
}
}

bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
const ASTContext &ASTContext = getASTContext();

StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
if (CC != SOF_OTHER)
CCMangling CC = getCallingConvMangling(ASTContext, D);
if (CC != CCM_Other)
return true;

// In C, functions with no attributes never need to be mangled. Fastpath them.
Expand Down Expand Up @@ -131,10 +136,10 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
}

const ASTContext &ASTContext = getASTContext();
StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
CCMangling CC = getCallingConvMangling(ASTContext, D);
bool MCXX = shouldMangleCXXName(D);
const TargetInfo &TI = Context.getTargetInfo();
if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
mangleObjCMethodName(OMD, Out);
else
Expand All @@ -143,9 +148,9 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
}

Out << '\01';
if (CC == SOF_STD)
if (CC == CCM_Std)
Out << '_';
else
else if (CC == CCM_Fast)
Out << '@';

if (!MCXX)
Expand All @@ -158,6 +163,8 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
const FunctionDecl *FD = cast<FunctionDecl>(D);
const FunctionType *FT = FD->getType()->castAs<FunctionType>();
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT);
if (CC == CCM_Vector)
Out << '@';
Out << '@';
if (!Proto) {
Out << '0';
Expand All @@ -169,9 +176,11 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
if (!MD->isStatic())
++ArgWords;
for (const auto &AT : Proto->param_types())
// Size should be aligned to DWORD boundary
ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32;
Out << 4 * ArgWords;
// Size should be aligned to pointer size.
ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT),
TI.getPointerWidth(0)) /
TI.getPointerWidth(0);
Out << ((TI.getPointerWidth(0) / 8) * ArgWords);
}

void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
Expand Down
2 changes: 2 additions & 0 deletions lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3503,6 +3503,7 @@ class X86_64TargetInfo : public X86TargetInfo {

CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C ||
CC == CC_X86VectorCall ||
CC == CC_IntelOclBicc ||
CC == CC_X86_64Win64) ? CCCR_OK : CCCR_Warning;
}
Expand Down Expand Up @@ -3542,6 +3543,7 @@ class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
}
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C ||
CC == CC_X86VectorCall ||
CC == CC_IntelOclBicc ||
CC == CC_X86_64SysV) ? CCCR_OK : CCCR_Warning;
}
Expand Down
8 changes: 7 additions & 1 deletion lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
// TODO: Add support for __pascal to LLVM.
case CC_X86Pascal: return llvm::CallingConv::C;
// TODO: Add support for __vectorcall to LLVM.
case CC_X86VectorCall: return llvm::CallingConv::C;
case CC_X86VectorCall: return llvm::CallingConv::X86_VectorCall;
}
}

Expand Down Expand Up @@ -603,6 +603,9 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) {
CharUnits UnionSize = CharUnits::Zero();

for (const auto *FD : RD->fields()) {
// Skip zero length bitfields.
if (FD->isBitField() && FD->getBitWidthValue(Context) == 0)
continue;
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
CharUnits FieldSize = Context.getTypeSizeInChars(FD->getType());
Expand All @@ -622,6 +625,9 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) {
}

for (const auto *FD : RD->fields()) {
// Skip zero length bitfields.
if (FD->isBitField() && FD->getBitWidthValue(Context) == 0)
continue;
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
Fields.push_back(FD);
Expand Down
11 changes: 9 additions & 2 deletions lib/CodeGen/MicrosoftCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,15 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
if (RD->hasNonTrivialCopyConstructor())
return RAA_Indirect;

// Win64 passes objects larger than 8 bytes indirectly.
if (getContext().getTypeSize(RD->getTypeForDecl()) > 64)
// If an object has a destructor, we'd really like to pass it indirectly
// because it allows us to elide copies. Unfortunately, MSVC makes that
// impossible for small types, which it will pass in a single register or
// stack slot. Most objects with dtors are large-ish, so handle that early.
// We can't call out all large objects as being indirect because there are
// multiple x64 calling conventions and the C++ ABI code shouldn't dictate
// how we pass large POD types.
if (RD->hasNonTrivialDestructor() &&
getContext().getTypeSize(RD->getTypeForDecl()) > 64)
return RAA_Indirect;

// We have a trivial copy constructor or no copy constructors, but we have
Expand Down
Loading

0 comments on commit 3568925

Please sign in to comment.