Skip to content

Commit

Permalink
Add support for AArch64 target.
Browse files Browse the repository at this point in the history
In cooperation with the LLVM patch, this should implement all scalar front-end
parts of the C and C++ ABIs for AArch64.

This patch excludes the NEON support also reviewed due to an outbreak of
batshit insanity in our legal department. That will be committed soon bringing
the changes to precisely what has been approved.

Further reviews would be gratefully received.

llvm-svn: 174055
  • Loading branch information
Tim Northover authored and Tim Northover committed Jan 31, 2013
1 parent e0e3aef commit 9bb857a
Show file tree
Hide file tree
Showing 19 changed files with 1,467 additions and 6 deletions.
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/TargetCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ class TargetCXXABI {
/// - constructor/destructor signatures.
iOS,

/// The generic AArch64 ABI is also a modified version of the Itanium ABI,
/// but it has fewer divergences than the 32-bit ARM ABI.
///
/// The relevant changes from the generic ABI in this case are:
/// - representation of member function pointers adjusted as in ARM.
/// - guard variables are smaller.
GenericAArch64,

/// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and
/// compatible compilers).
///
Expand Down Expand Up @@ -93,6 +101,7 @@ class TargetCXXABI {
/// \brief Does this ABI generally fall into the Itanium family of ABIs?
bool isItaniumFamily() const {
switch (getKind()) {
case GenericAArch64:
case GenericItanium:
case GenericARM:
case iOS:
Expand All @@ -107,6 +116,7 @@ class TargetCXXABI {
/// \brief Is this ABI an MSVC-compatible ABI?
bool isMicrosoft() const {
switch (getKind()) {
case GenericAArch64:
case GenericItanium:
case GenericARM:
case iOS:
Expand Down Expand Up @@ -175,6 +185,7 @@ class TargetCXXABI {
case GenericARM:
return false;

case GenericAArch64:
case GenericItanium:
case iOS: // old iOS compilers did not follow this rule
case Microsoft:
Expand Down Expand Up @@ -220,6 +231,7 @@ class TargetCXXABI {
// permanently locked the definition of POD to the rules of C++ TR1,
// and that trickles down to all the derived ABIs.
case GenericItanium:
case GenericAArch64:
case GenericARM:
case iOS:
return UseTailPaddingUnlessPOD03;
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
/// typedef void* __builtin_va_list;
VoidPtrBuiltinVaList,

/// __builtin_va_list as defind by the AArch64 ABI
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf
AArch64ABIBuiltinVaList,

/// __builtin_va_list as defined by the PNaCl ABI:
/// http://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Machine-Types
PNaClABIBuiltinVaList,
Expand Down
83 changes: 83 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
return CreateARMCXXABI(*this);
case TargetCXXABI::GenericAArch64: // Same as Itanium at this level
case TargetCXXABI::GenericItanium:
return CreateItaniumCXXABI(*this);
case TargetCXXABI::Microsoft:
Expand Down Expand Up @@ -5563,6 +5564,85 @@ static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) {
return VaListTypeDecl;
}

static TypedefDecl *
CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
RecordDecl *VaListTagDecl;
if (Context->getLangOpts().CPlusPlus) {
// namespace std { struct __va_list {
NamespaceDecl *NS;
NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
Context->getTranslationUnitDecl(),
/*Inline*/false, SourceLocation(),
SourceLocation(), &Context->Idents.get("std"),
/*PrevDecl*/0);

VaListTagDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
Context->getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Context->Idents.get("__va_list"));
VaListTagDecl->setDeclContext(NS);
} else {
// struct __va_list
VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
Context->getTranslationUnitDecl(),
&Context->Idents.get("__va_list"));
}

VaListTagDecl->startDefinition();

const size_t NumFields = 5;
QualType FieldTypes[NumFields];
const char *FieldNames[NumFields];

// void *__stack;
FieldTypes[0] = Context->getPointerType(Context->VoidTy);
FieldNames[0] = "__stack";

// void *__gr_top;
FieldTypes[1] = Context->getPointerType(Context->VoidTy);
FieldNames[1] = "__gr_top";

// void *__vr_top;
FieldTypes[2] = Context->getPointerType(Context->VoidTy);
FieldNames[2] = "__vr_top";

// int __gr_offs;
FieldTypes[3] = Context->IntTy;
FieldNames[3] = "__gr_offs";

// int __vr_offs;
FieldTypes[4] = Context->IntTy;
FieldNames[4] = "__vr_offs";

// Create fields
for (unsigned i = 0; i < NumFields; ++i) {
FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
VaListTagDecl,
SourceLocation(),
SourceLocation(),
&Context->Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
VaListTagDecl->addDecl(Field);
}
VaListTagDecl->completeDefinition();
QualType VaListTagType = Context->getRecordType(VaListTagDecl);
Context->VaListTagTy = VaListTagType;

// } __builtin_va_list;
TypedefDecl *VaListTypedefDecl
= TypedefDecl::Create(const_cast<ASTContext &>(*Context),
Context->getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Context->Idents.get("__builtin_va_list"),
Context->getTrivialTypeSourceInfo(VaListTagType));

return VaListTypedefDecl;
}

static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
Expand Down Expand Up @@ -5796,6 +5876,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
return CreateCharPtrBuiltinVaListDecl(Context);
case TargetInfo::VoidPtrBuiltinVaList:
return CreateVoidPtrBuiltinVaListDecl(Context);
case TargetInfo::AArch64ABIBuiltinVaList:
return CreateAArch64ABIBuiltinVaListDecl(Context);
case TargetInfo::PowerABIBuiltinVaList:
return CreatePowerABIBuiltinVaListDecl(Context);
case TargetInfo::X86_64ABIBuiltinVaList:
Expand Down Expand Up @@ -7642,6 +7724,7 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {

MangleContext *ASTContext::createMangleContext() {
switch (Target->getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
Expand Down
188 changes: 188 additions & 0 deletions clang/lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3020,6 +3020,186 @@ class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> {
Int64Type = SignedLongLong;
}
};
}

namespace {
class AArch64TargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
public:
AArch64TargetInfo(const std::string& triple) : TargetInfo(triple) {
BigEndian = false;
LongWidth = LongAlign = 64;
LongDoubleWidth = LongDoubleAlign = 128;
PointerWidth = PointerAlign = 64;
SuitableAlign = 128;
DescriptionString = "e-p:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-i128:128:128-f32:32:32-f64:64:64-"
"f128:128:128-n32:64-S128";

WCharType = UnsignedInt;
LongDoubleFormat = &llvm::APFloat::IEEEquad;

TheCXXABI.set(TargetCXXABI::GenericAArch64);
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// GCC defines theses currently
Builder.defineMacro("__aarch64__");
Builder.defineMacro("__AARCH64EL__");

// ACLE predefines. Many can only have one possible value on v8 AArch64.

// FIXME: these were written based on an unreleased version of a 32-bit ACLE
// which was intended to be compatible with a 64-bit implementation. They
// will need updating when a real 64-bit ACLE exists. Particularly pressing
// instances are: __AARCH_ISA_A32, __AARCH_ISA_T32, __ARCH_PCS.
Builder.defineMacro("__AARCH_ACLE", "101");
Builder.defineMacro("__AARCH", "8");
Builder.defineMacro("__AARCH_PROFILE", "'A'");

Builder.defineMacro("__AARCH_FEATURE_UNALIGNED");
Builder.defineMacro("__AARCH_FEATURE_CLZ");
Builder.defineMacro("__AARCH_FEATURE_FMA");

// FIXME: ACLE 1.1 reserves bit 4. Will almost certainly come to mean
// 128-bit LDXP present, at which point this becomes 0x1f.
Builder.defineMacro("__AARCH_FEATURE_LDREX", "0xf");

// 0xe implies support for half, single and double precision operations.
Builder.defineMacro("__AARCH_FP", "0xe");

// PCS specifies this for SysV variants, which is all we support. Other ABIs
// may choose __AARCH_FP16_FORMAT_ALTERNATIVE.
Builder.defineMacro("__AARCH_FP16_FORMAT_IEEE");

if (Opts.FastMath || Opts.FiniteMathOnly)
Builder.defineMacro("__AARCH_FP_FAST");

if ((Opts.C99 || Opts.C11) && !Opts.Freestanding)
Builder.defineMacro("__AARCH_FP_FENV_ROUNDING");

Builder.defineMacro("__AARCH_SIZEOF_WCHAR_T",
Opts.ShortWChar ? "2" : "4");

Builder.defineMacro("__AARCH_SIZEOF_MINIMAL_ENUM",
Opts.ShortEnums ? "1" : "4");

if (BigEndian)
Builder.defineMacro("__AARCH_BIG_ENDIAN");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
Records = 0;
NumRecords = 0;
}
virtual bool hasFeature(StringRef Feature) const {
return Feature == "aarch64";
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const;

virtual bool isCLZForZeroUndef() const { return false; }

virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default: return false;
case 'w': // An FP/SIMD vector register
Info.setAllowsRegister();
return true;
case 'I': // Constant that can be used with an ADD instruction
case 'J': // Constant that can be used with a SUB instruction
case 'K': // Constant that can be used with a 32-bit logical instruction
case 'L': // Constant that can be used with a 64-bit logical instruction
case 'M': // Constant that can be used as a 32-bit MOV immediate
case 'N': // Constant that can be used as a 64-bit MOV immediate
case 'Y': // Floating point constant zero
case 'Z': // Integer constant zero
return true;
case 'Q': // A memory reference with base register and no offset
Info.setAllowsMemory();
return true;
case 'S': // A symbolic address
Info.setAllowsRegister();
return true;
case 'U':
// Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes, whatever they may be
// Utf: A memory address suitable for ldp/stp in TF mode, whatever it may be
// Usa: An absolute symbolic address
// Ush: The high part (bits 32:12) of a pc-relative symbolic address
llvm_unreachable("FIXME: Unimplemented support for bizarre constraints");
}
}

virtual const char *getClobbers() const {
// There are no AArch64 clobbers shared by all asm statements.
return "";
}

virtual BuiltinVaListKind getBuiltinVaListKind() const {
return TargetInfo::AArch64ABIBuiltinVaList;
}
};

const char * const AArch64TargetInfo::GCCRegNames[] = {
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
"w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", "wzr",

"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", "xzr",

"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
"b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15",
"b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
"b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31",

"h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7",
"h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15",
"h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
"h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31",

"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",

"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",

"q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
"q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
"q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"
};

void AArch64TargetInfo::getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const {
Names = GCCRegNames;
NumNames = llvm::array_lengthof(GCCRegNames);
}

const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
{ { "x16" }, "ip0"},
{ { "x17" }, "ip1"},
{ { "x29" }, "fp" },
{ { "x30" }, "lr" }
};

void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const {
Aliases = GCCRegAliases;
NumAliases = llvm::array_lengthof(GCCRegAliases);

}
} // end anonymous namespace

namespace {
Expand Down Expand Up @@ -4540,6 +4720,14 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::hexagon:
return new HexagonTargetInfo(T);

case llvm::Triple::aarch64:
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<AArch64TargetInfo>(T);
default:
return new AArch64TargetInfo(T);
}

case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Triple.isOSDarwin())
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/ABIInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,10 @@ namespace clang {
return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0);
, bool Realign = false
, llvm::Type *Padding = 0) {
return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
Padding);
}
static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static const char AnnotationSection[] = "llvm.metadata";

static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
case TargetCXXABI::GenericItanium:
Expand Down

0 comments on commit 9bb857a

Please sign in to comment.