Skip to content

Commit

Permalink
[SystemZ] Add support for z13 and its vector facility
Browse files Browse the repository at this point in the history
This patch adds support for the z13 architecture type.  For compatibility
with GCC, a pair of options -mvx / -mno-vx can be used to selectively
enable/disable use of the vector facility.

When the vector facility is present, we default to the new vector ABI.
This is characterized by two major differences:
- Vector types are passed/returned in vector registers
  (except for unnamed arguments of a variable-argument list function).
- Vector types are at most 8-byte aligned.

The reason for the choice of 8-byte vector alignment is that the hardware
is able to efficiently load vectors at 8-byte alignment, and the ABI only
guarantees 8-byte alignment of the stack pointer, so requiring any higher
alignment for vectors would require dynamic stack re-alignment code.

However, for compatibility with old code that may use vector types, when
*not* using the vector facility, the old alignment rules (vector types
are naturally aligned) remain in use.

These alignment rules are not only implemented at the C language level,
but also at the LLVM IR level.  This is done by selecting a different
DataLayout string depending on whether the vector ABI is in effect or not.

Based on a patch by Richard Sandiford.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236531 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
uweigand committed May 5, 2015
1 parent b9af15e commit a731c44
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 30 deletions.
3 changes: 3 additions & 0 deletions include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,9 @@ def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[CC1Option]>
def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>;
def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>;

def mvx : Flag<["-"], "mvx">, Group<m_Group>;
def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>;

def mno_warn_nonportable_cfstrings : Flag<["-"], "mno-warn-nonportable-cfstrings">, Group<m_Group>;
def mno_omit_leaf_frame_pointer : Flag<["-"], "mno-omit-leaf-frame-pointer">, Group<m_Group>;
def momit_leaf_frame_pointer : Flag<["-"], "momit-leaf-frame-pointer">, Group<m_Group>,
Expand Down
23 changes: 22 additions & 1 deletion lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5531,10 +5531,11 @@ class SystemZTargetInfo : public TargetInfo {
static const char *const GCCRegNames[];
std::string CPU;
bool HasTransactionalExecution;
bool HasVector;

public:
SystemZTargetInfo(const llvm::Triple &Triple)
: TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false) {
: TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), HasVector(false) {
IntMaxType = SignedLong;
Int64Type = SignedLong;
TLSSupported = true;
Expand Down Expand Up @@ -5587,13 +5588,18 @@ class SystemZTargetInfo : public TargetInfo {
.Case("z10", true)
.Case("z196", true)
.Case("zEC12", true)
.Case("z13", true)
.Default(false);

return CPUKnown;
}
void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
if (CPU == "zEC12")
Features["transactional-execution"] = true;
if (CPU == "z13") {
Features["transactional-execution"] = true;
Features["vector"] = true;
}
}

bool handleTargetFeatures(std::vector<std::string> &Features,
Expand All @@ -5602,6 +5608,14 @@ class SystemZTargetInfo : public TargetInfo {
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
if (Features[i] == "+transactional-execution")
HasTransactionalExecution = true;
if (Features[i] == "+vector")
HasVector = true;
}
// If we use the vector ABI, vector types are 64-bit aligned.
if (HasVector) {
MaxVectorAlign = 64;
DescriptionString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64"
"-v128:64-a:8:16-n32:64";
}
return true;
}
Expand All @@ -5610,8 +5624,15 @@ class SystemZTargetInfo : public TargetInfo {
return llvm::StringSwitch<bool>(Feature)
.Case("systemz", true)
.Case("htm", HasTransactionalExecution)
.Case("vx", HasVector)
.Default(false);
}

StringRef getABI() const override {
if (HasVector)
return "vector";
return "";
}
};

const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = {
Expand Down
101 changes: 75 additions & 26 deletions lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5146,12 +5146,17 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name,
namespace {

class SystemZABIInfo : public ABIInfo {
bool HasVector;

public:
SystemZABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
SystemZABIInfo(CodeGenTypes &CGT, bool HV)
: ABIInfo(CGT), HasVector(HV) {}

bool isPromotableIntegerType(QualType Ty) const;
bool isCompoundType(QualType Ty) const;
bool isVectorArgumentType(QualType Ty) const;
bool isFPArgumentType(QualType Ty) const;
QualType GetSingleElementType(QualType Ty) const;

ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType ArgTy) const;
Expand All @@ -5169,8 +5174,8 @@ class SystemZABIInfo : public ABIInfo {

class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
public:
SystemZTargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new SystemZABIInfo(CGT)) {}
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector)
: TargetCodeGenInfo(new SystemZABIInfo(CGT, HasVector)) {}
};

}
Expand Down Expand Up @@ -5202,6 +5207,12 @@ bool SystemZABIInfo::isCompoundType(QualType Ty) const {
isAggregateTypeForABI(Ty));
}

bool SystemZABIInfo::isVectorArgumentType(QualType Ty) const {
return (HasVector &&
Ty->isVectorType() &&
getContext().getTypeSize(Ty) <= 128);
}

bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
switch (BT->getKind()) {
Expand All @@ -5212,9 +5223,13 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
return false;
}

return false;
}

QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const {
if (const RecordType *RT = Ty->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl();
bool Found = false;
QualType Found;

// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
Expand All @@ -5225,11 +5240,9 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
if (isEmptyRecord(getContext(), Base, true))
continue;

if (Found)
return false;
Found = isFPArgumentType(Base);
if (!Found)
return false;
if (!Found.isNull())
return Ty;
Found = GetSingleElementType(Base);
}

// Check the fields.
Expand All @@ -5242,20 +5255,19 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
continue;

// Unlike isSingleElementStruct(), arrays do not count.
// Nested isFPArgumentType structures still do though.
if (Found)
return false;
Found = isFPArgumentType(FD->getType());
if (!Found)
return false;
// Nested structures still do though.
if (!Found.isNull())
return Ty;
Found = GetSingleElementType(FD->getType());
}

// Unlike isSingleElementStruct(), trailing padding is allowed.
// An 8-byte aligned struct s { float f; } is passed as a double.
return Found;
if (!Found.isNull())
return Found;
}

return false;
return Ty;
}

llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
Expand All @@ -5268,14 +5280,16 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// i8 *__reg_save_area;
// };

// Every argument occupies 8 bytes and is passed by preference in either
// GPRs or FPRs.
// Every non-vector argument occupies 8 bytes and is passed by preference
// in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are
// always passed on the stack.
Ty = CGF.getContext().getCanonicalType(Ty);
llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty);
llvm::Type *APTy = llvm::PointerType::getUnqual(ArgTy);
ABIArgInfo AI = classifyArgumentType(Ty);
bool IsIndirect = AI.isIndirect();
bool InFPRs = false;
bool IsVector = false;
unsigned UnpaddedBitSize;
if (IsIndirect) {
APTy = llvm::PointerType::getUnqual(APTy);
Expand All @@ -5284,14 +5298,38 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
if (AI.getCoerceToType())
ArgTy = AI.getCoerceToType();
InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy();
IsVector = ArgTy->isVectorTy();
UnpaddedBitSize = getContext().getTypeSize(Ty);
}
unsigned PaddedBitSize = 64;
unsigned PaddedBitSize = (IsVector && UnpaddedBitSize > 64) ? 128 : 64;
assert((UnpaddedBitSize <= PaddedBitSize) && "Invalid argument size.");

unsigned PaddedSize = PaddedBitSize / 8;
unsigned Padding = (PaddedBitSize - UnpaddedBitSize) / 8;

llvm::Type *IndexTy = CGF.Int64Ty;
llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize);

if (IsVector) {
// Work out the address of a vector argument on the stack.
// Vector arguments are always passed in the high bits of a
// single (8 byte) or double (16 byte) stack slot.
llvm::Value *OverflowArgAreaPtr =
CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 2,
"overflow_arg_area_ptr");
llvm::Value *OverflowArgArea =
CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area");
llvm::Value *MemAddr =
CGF.Builder.CreateBitCast(OverflowArgArea, APTy, "mem_addr");

// Update overflow_arg_area_ptr pointer
llvm::Value *NewOverflowArgArea =
CGF.Builder.CreateGEP(OverflowArgArea, PaddedSizeV, "overflow_arg_area");
CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr);

return MemAddr;
}

unsigned MaxRegs, RegCountField, RegSaveIndex, RegPadding;
if (InFPRs) {
MaxRegs = 4; // Maximum of 4 FPR arguments
Expand All @@ -5308,7 +5346,6 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Value *RegCountPtr = CGF.Builder.CreateStructGEP(
nullptr, VAListAddr, RegCountField, "reg_count_ptr");
llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count");
llvm::Type *IndexTy = RegCount->getType();
llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs);
llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV,
"fits_in_regs");
Expand All @@ -5322,7 +5359,6 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CGF.EmitBlock(InRegBlock);

// Work out the address of an argument register.
llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize);
llvm::Value *ScaledRegCount =
CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count");
llvm::Value *RegBase =
Expand Down Expand Up @@ -5380,6 +5416,8 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
if (isVectorArgumentType(RetTy))
return ABIArgInfo::getDirect();
if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64)
return ABIArgInfo::getIndirect(0);
return (isPromotableIntegerType(RetTy) ?
Expand All @@ -5395,8 +5433,16 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
if (isPromotableIntegerType(Ty))
return ABIArgInfo::getExtend();

// Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly.
// Handle vector types and vector-like structure types. Note that
// as opposed to float-like structure types, we do not allow any
// padding for vector-like structures, so verify the sizes match.
uint64_t Size = getContext().getTypeSize(Ty);
QualType SingleElementTy = GetSingleElementType(Ty);
if (isVectorArgumentType(SingleElementTy) &&
getContext().getTypeSize(SingleElementTy) == Size)
return ABIArgInfo::getDirect(CGT.ConvertType(SingleElementTy));

// Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly.
if (Size != 8 && Size != 16 && Size != 32 && Size != 64)
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);

Expand All @@ -5410,7 +5456,7 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {

// The structure is passed as an unextended integer, a float, or a double.
llvm::Type *PassTy;
if (isFPArgumentType(Ty)) {
if (isFPArgumentType(SingleElementTy)) {
assert(Size == 32 || Size == 64);
if (Size == 32)
PassTy = llvm::Type::getFloatTy(getVMContext());
Expand Down Expand Up @@ -7067,8 +7113,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::msp430:
return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types));

case llvm::Triple::systemz:
return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types));
case llvm::Triple::systemz: {
bool HasVector = getTarget().getABI() == "vector";
return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types,
HasVector));
}

case llvm::Triple::tce:
return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types));
Expand Down
8 changes: 8 additions & 0 deletions lib/Driver/Tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,14 @@ static void getSystemZTargetFeatures(const ArgList &Args,
else
Features.push_back("-transactional-execution");
}
// -m(no-)vx overrides use of the vector facility.
if (Arg *A = Args.getLastArg(options::OPT_mvx,
options::OPT_mno_vx)) {
if (A->getOption().matches(options::OPT_mvx))
Features.push_back("+vector");
else
Features.push_back("-vector");
}
}

static const char *getX86TargetCPU(const ArgList &Args,
Expand Down
Loading

0 comments on commit a731c44

Please sign in to comment.