[SystemZ] Support -msoft-float

This is needed when building the Linux kernel.

Review: Ulrich Weigand

Differential Revision: https://reviews.llvm.org/D72189
This commit is contained in:
Jonas Paulsson 2020-01-04 00:39:07 +01:00
parent 191a9a78b3
commit 563e84790f
28 changed files with 932 additions and 64 deletions

View File

@ -29,11 +29,12 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
int ISARevision;
bool HasTransactionalExecution;
bool HasVector;
bool SoftFloat;
public:
SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
: TargetInfo(Triple), CPU("z10"), ISARevision(8),
HasTransactionalExecution(false), HasVector(false) {
HasTransactionalExecution(false), HasVector(false), SoftFloat(false) {
IntMaxType = SignedLong;
Int64Type = SignedLong;
TLSSupported = true;
@ -109,12 +110,17 @@ public:
DiagnosticsEngine &Diags) override {
HasTransactionalExecution = false;
HasVector = false;
SoftFloat = false;
for (const auto &Feature : Features) {
if (Feature == "+transactional-execution")
HasTransactionalExecution = true;
else if (Feature == "+vector")
HasVector = true;
else if (Feature == "+soft-float")
SoftFloat = true;
}
HasVector &= !SoftFloat;
// If we use the vector ABI, vector types are 64-bit aligned.
if (HasVector) {
MaxVectorAlign = 64;

View File

@ -6565,10 +6565,11 @@ namespace {
class SystemZABIInfo : public SwiftABIInfo {
bool HasVector;
bool IsSoftFloatABI;
public:
SystemZABIInfo(CodeGenTypes &CGT, bool HV)
: SwiftABIInfo(CGT), HasVector(HV) {}
SystemZABIInfo(CodeGenTypes &CGT, bool HV, bool SF)
: SwiftABIInfo(CGT), HasVector(HV), IsSoftFloatABI(SF) {}
bool isPromotableIntegerType(QualType Ty) const;
bool isCompoundType(QualType Ty) const;
@ -6600,8 +6601,8 @@ public:
class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
public:
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector)
: TargetCodeGenInfo(new SystemZABIInfo(CGT, HasVector)) {}
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI)
: TargetCodeGenInfo(new SystemZABIInfo(CGT, HasVector, SoftFloatABI)) {}
};
}
@ -6640,6 +6641,9 @@ bool SystemZABIInfo::isVectorArgumentType(QualType Ty) const {
}
bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
if (IsSoftFloatABI)
return false;
if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
switch (BT->getKind()) {
case BuiltinType::Float:
@ -6725,7 +6729,7 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
} else {
if (AI.getCoerceToType())
ArgTy = AI.getCoerceToType();
InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy();
InFPRs = (!IsSoftFloatABI && (ArgTy->isFloatTy() || ArgTy->isDoubleTy()));
IsVector = ArgTy->isVectorTy();
UnpaddedSize = TyInfo.first;
DirectAlign = TyInfo.second;
@ -9900,8 +9904,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
}
case llvm::Triple::systemz: {
bool HasVector = getTarget().getABI() == "vector";
return SetCGInfo(new SystemZTargetCodeGenInfo(Types, HasVector));
bool SoftFloat = CodeGenOpts.FloatABI == "soft";
bool HasVector = !SoftFloat && getTarget().getABI() == "vector";
return SetCGInfo(new SystemZTargetCodeGenInfo(Types, HasVector, SoftFloat));
}
case llvm::Triple::tce:

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "SystemZ.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
@ -16,6 +17,22 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
systemz::FloatABI systemz::getSystemZFloatABI(const Driver &D,
const ArgList &Args) {
// Hard float is the default.
systemz::FloatABI ABI = systemz::FloatABI::Hard;
if (Args.hasArg(options::OPT_mfloat_abi_EQ))
D.Diag(diag::err_drv_unsupported_opt)
<< Args.getLastArg(options::OPT_mfloat_abi_EQ)->getAsString(Args);
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float,
options::OPT_mhard_float))
if (A->getOption().matches(clang::driver::options::OPT_msoft_float))
ABI = systemz::FloatABI::Soft;
return ABI;
}
std::string systemz::getSystemZTargetCPU(const ArgList &Args) {
if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
llvm::StringRef CPUName = A->getValue();
@ -33,7 +50,7 @@ std::string systemz::getSystemZTargetCPU(const ArgList &Args) {
return "z10";
}
void systemz::getSystemZTargetFeatures(const ArgList &Args,
void systemz::getSystemZTargetFeatures(const Driver &D, const ArgList &Args,
std::vector<llvm::StringRef> &Features) {
// -m(no-)htm overrides use of the transactional-execution facility.
if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) {
@ -49,4 +66,8 @@ void systemz::getSystemZTargetFeatures(const ArgList &Args,
else
Features.push_back("-vector");
}
systemz::FloatABI FloatABI = systemz::getSystemZFloatABI(D, Args);
if (FloatABI == systemz::FloatABI::Soft)
Features.push_back("+soft-float");
}

View File

@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H
#include "clang/Driver/Driver.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/Option.h"
#include <string>
@ -19,9 +20,16 @@ namespace driver {
namespace tools {
namespace systemz {
enum class FloatABI {
Soft,
Hard,
};
FloatABI getSystemZFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args);
void getSystemZTargetFeatures(const llvm::opt::ArgList &Args,
void getSystemZTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
} // end namespace systemz

View File

@ -339,7 +339,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
riscv::getRISCVTargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::systemz:
systemz::getSystemZTargetFeatures(Args, Features);
systemz::getSystemZTargetFeatures(D, Args, Features);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_32:
@ -2013,6 +2013,16 @@ void Clang::AddSystemZTargetArgs(const ArgList &Args,
CmdArgs.push_back("-mbackchain");
if (HasPackedStack)
CmdArgs.push_back("-mpacked-stack");
systemz::FloatABI FloatABI =
systemz::getSystemZFloatABI(getToolChain().getDriver(), Args);
if (FloatABI == systemz::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
}
}
static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args,

View File

@ -1,19 +1,22 @@
// RUN: %clang_cc1 -triple s390x-linux-gnu \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-feature +vector \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z13 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch11 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z14 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch12 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z15 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch13 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD-FLOAT
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch13 \
// RUN: -emit-llvm -o - %s -mfloat-abi soft | FileCheck %s \
// RUN: --check-prefixes=CHECK,SOFT-FLOAT
// Scalar types
@ -115,11 +118,13 @@ struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
struct agg_float { float a; };
struct agg_float pass_agg_float(struct agg_float arg) { return arg; }
// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, float %{{.*}})
// HARD-FLOAT-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, float %{{.*}})
// SOFT-FLOAT-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, i32 %{{.*}})
struct agg_double { double a; };
struct agg_double pass_agg_double(struct agg_double arg) { return arg; }
// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, double %{{.*}})
// HARD-FLOAT-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, double %{{.*}})
// SOFT-FLOAT-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, i64 %{{.*}})
struct agg_longdouble { long double a; };
struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return arg; }
@ -127,7 +132,8 @@ struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return ar
struct agg_float_a8 { float a __attribute__((aligned (8))); };
struct agg_float_a8 pass_agg_float_a8(struct agg_float_a8 arg) { return arg; }
// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, double %{{.*}})
// HARD-FLOAT-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, double %{{.*}})
// SOFT-FLOAT-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, i64 %{{.*}})
struct agg_float_a16 { float a __attribute__((aligned (16))); };
struct agg_float_a16 pass_agg_float_a16(struct agg_float_a16 arg) { return arg; }
@ -225,12 +231,15 @@ long long va_longlong(__builtin_va_list l) { return __builtin_va_arg(l, long lon
double va_double(__builtin_va_list l) { return __builtin_va_arg(l, double); }
// CHECK-LABEL: define double @va_double(%struct.__va_list_tag* %{{.*}})
// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// HARD-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// SOFT-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// HARD-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// SOFT-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
// CHECK: br i1 [[FITS_IN_REGS]],
// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// HARD-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// SOFT-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
@ -415,12 +424,15 @@ struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l,
struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float); }
// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// HARD-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// SOFT-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// HARD-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// SOFT-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
// CHECK: br i1 [[FITS_IN_REGS]],
// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// HARD-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// SOFT-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 20
// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
@ -438,12 +450,15 @@ struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l,
struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_double); }
// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// HARD-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// SOFT-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// HARD-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// SOFT-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
// CHECK: br i1 [[FITS_IN_REGS]],
// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// HARD-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// SOFT-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
@ -485,12 +500,15 @@ struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_
struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a8); }
// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// HARD-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
// SOFT-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// HARD-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// SOFT-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
// CHECK: br i1 [[FITS_IN_REGS]],
// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// HARD-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// SOFT-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]

View File

@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -x c++ -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -x c++ -o - %s -mfloat-abi soft \
// RUN: | FileCheck %s --check-prefix=SOFT-FLOAT
// For compatibility with GCC, this structure is passed in an FPR in C++,
// but passed in a GPR in C (checked in systemz-abi.c).
@ -6,4 +8,4 @@
struct agg_float_cpp { float a; int : 0; };
struct agg_float_cpp pass_agg_float_cpp(struct agg_float_cpp arg) { return arg; }
// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret %{{.*}}, float %{{.*}})
// SOFT-FLOAT: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret %{{.*}}, i32 %{{.*}})

View File

@ -193,6 +193,8 @@
// RUN: %clang_cc1 -triple s390x-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=SYSTEMZ
// RUN: %clang_cc1 -triple s390x-unknown -target-cpu z13 -target-feature +soft-float -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=SYSTEMZ
// SYSTEMZ: target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"
// RUN: %clang_cc1 -triple s390x-unknown -target-cpu z13 -o - -emit-llvm %s | \

View File

@ -0,0 +1,45 @@
// Check handling -mhard-float / -msoft-float options
// when build for SystemZ platforms.
//
// Default
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target s390x-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-DEF %s
// CHECK-DEF-NOT: "-msoft-float"
// CHECK-DEF-NOT: "-mfloat-abi" "soft"
//
// -mhard-float
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target s390x-linux-gnu -mhard-float \
// RUN: | FileCheck --check-prefix=CHECK-HARD %s
// CHECK-HARD-NOT: "-msoft-float"
// CHECK-HARD-NOT: "-mfloat-abi" "soft"
//
// -msoft-float
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target s390x-linux-gnu -msoft-float \
// RUN: | FileCheck --check-prefix=CHECK-SOFT %s
// CHECK-SOFT: "-msoft-float" "-mfloat-abi" "soft"
//
// -mfloat-abi=soft
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target s390x-linux-gnu -mfloat-abi=soft \
// RUN: | FileCheck --check-prefix=CHECK-FLOATABISOFT %s
// CHECK-FLOATABISOFT: error: unsupported option '-mfloat-abi=soft'
//
// -mfloat-abi=hard
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target s390x-linux-gnu -mfloat-abi=hard \
// RUN: | FileCheck --check-prefix=CHECK-FLOATABIHARD %s
// CHECK-FLOATABIHARD: error: unsupported option '-mfloat-abi=hard'
//
// check invalid -mfloat-abi
// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target s390x-linux-gnu -mfloat-abi=x \
// RUN: | FileCheck --check-prefix=CHECK-ERRMSG %s
// CHECK-ERRMSG: error: unsupported option '-mfloat-abi=x'
int foo(void) {
return 0;
}

View File

@ -0,0 +1,22 @@
// RUN: %clang -target s390x-linux-gnu -march=z13 -S %s -o - -msoft-float | FileCheck %s
//
// Check that -msoft-float works all the way to assembly output.
double fun0(double *A) {
// CHECK-LABEL: fun0
// CHECK-NOT: {{%f[0-9]}}
// CHECK: brasl %r14, __adddf3@PLT
return *A + 1.0;
}
typedef int v4si __attribute__ ((vector_size (16)));
v4si fun1(v4si *A) {
// CHECK-LABEL: fun1
// CHECK-NOT: {{%[v][0-9]}}
// CHECK: ark
// CHECK-NEXT: ark
// CHECK-NEXT: ark
// CHECK-NEXT: ark
v4si B = {1, 1, 1, 1};
return *A + B;
}

View File

@ -25,6 +25,13 @@ class SystemZFeatureList<list<SystemZFeature> x> {
class SystemZFeatureAdd<list<SystemZFeature> x, list<SystemZFeature> y>
: SystemZFeatureList<!listconcat(x, y)>;
// This feature is added as a subtarget feature whenever the function is
// compiled to use soft-float.
def FeatureSoftFloat : SystemZFeature<
"soft-float", "SoftFloat",
"Use software emulation for floating point"
>;
//===----------------------------------------------------------------------===//
//
// New features added in the Ninth Edition of the z/Architecture

View File

@ -88,6 +88,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
else
addRegisterClass(MVT::i32, &SystemZ::GR32BitRegClass);
addRegisterClass(MVT::i64, &SystemZ::GR64BitRegClass);
if (!useSoftFloat()) {
if (Subtarget.hasVector()) {
addRegisterClass(MVT::f32, &SystemZ::VR32BitRegClass);
addRegisterClass(MVT::f64, &SystemZ::VR64BitRegClass);
@ -108,6 +109,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::v4f32, &SystemZ::VR128BitRegClass);
addRegisterClass(MVT::v2f64, &SystemZ::VR128BitRegClass);
}
}
// Compute derived properties from the register classes
computeRegisterProperties(Subtarget.getRegisterInfo());
@ -666,6 +668,10 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
IsStrictFPEnabled = true;
}
bool SystemZTargetLowering::useSoftFloat() const {
return Subtarget.hasSoftFloat();
}
EVT SystemZTargetLowering::getSetCCResultType(const DataLayout &DL,
LLVMContext &, EVT VT) const {
if (!VT.isVector())
@ -1123,12 +1129,14 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
return std::make_pair(0U, &SystemZ::GRH32BitRegClass);
case 'f': // Floating-point register
if (!useSoftFloat()) {
if (VT == MVT::f64)
return std::make_pair(0U, &SystemZ::FP64BitRegClass);
else if (VT == MVT::f128)
return std::make_pair(0U, &SystemZ::FP128BitRegClass);
return std::make_pair(0U, &SystemZ::FP32BitRegClass);
}
break;
case 'v': // Vector register
if (Subtarget.hasVector()) {
if (VT == MVT::f32)
@ -1155,7 +1163,7 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
return parseRegisterNumber(Constraint, &SystemZ::GR64BitRegClass,
SystemZMC::GR64Regs, 16);
}
if (Constraint[1] == 'f') {
if (Constraint[1] == 'f' && !useSoftFloat()) {
if (VT == MVT::f32)
return parseRegisterNumber(Constraint, &SystemZ::FP32BitRegClass,
SystemZMC::FP32Regs, 16);
@ -1443,7 +1451,7 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
// Store the FPR varargs in the reserved frame slots. (We store the
// GPRs as part of the prologue.)
if (NumFixedFPRs < SystemZ::NumArgFPRs) {
if (NumFixedFPRs < SystemZ::NumArgFPRs && !useSoftFloat()) {
SDValue MemOps[SystemZ::NumArgFPRs];
for (unsigned I = NumFixedFPRs; I < SystemZ::NumArgFPRs; ++I) {
unsigned Offset = TFL->getRegSpillOffset(SystemZ::ArgFPRs[I]);

View File

@ -393,6 +393,8 @@ public:
explicit SystemZTargetLowering(const TargetMachine &TM,
const SystemZSubtarget &STI);
bool useSoftFloat() const override;
// Override TargetLowering.
MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override {
return MVT::i32;

View File

@ -33,6 +33,11 @@ SystemZSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
CPUName = "generic";
// Parse features string.
ParseSubtargetFeatures(CPUName, FS);
// -msoft-float implies -mno-vx.
if (HasSoftFloat)
HasVector = false;
return *this;
}
@ -57,7 +62,7 @@ SystemZSubtarget::SystemZSubtarget(const Triple &TT, const std::string &CPU,
HasInsertReferenceBitsMultiple(false),
HasMiscellaneousExtensions3(false), HasMessageSecurityAssist9(false),
HasVectorEnhancements2(false), HasVectorPackedDecimalEnhancement(false),
HasEnhancedSort(false), HasDeflateConversion(false),
HasEnhancedSort(false), HasDeflateConversion(false), HasSoftFloat(false),
TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)),
TLInfo(TM, *this), TSInfo(), FrameLowering() {}

View File

@ -68,6 +68,7 @@ protected:
bool HasVectorPackedDecimalEnhancement;
bool HasEnhancedSort;
bool HasDeflateConversion;
bool HasSoftFloat;
private:
Triple TargetTriple;
@ -239,6 +240,9 @@ public:
// Return true if the target has the deflate-conversion facility.
bool hasDeflateConversion() const { return HasDeflateConversion; }
// Return true if soft float should be used.
bool hasSoftFloat() const { return HasSoftFloat; }
// Return true if GV can be accessed using LARL for reloc model RM
// and code model CM.
bool isPC32DBLSymbol(const GlobalValue *GV, CodeModel::Model CM) const;

View File

@ -40,6 +40,7 @@ static bool UsesVectorABI(StringRef CPU, StringRef FS) {
// This is the case by default if CPU is z13 or later, and can be
// overridden via "[+-]vector" feature string elements.
bool VectorABI = true;
bool SoftFloat = false;
if (CPU.empty() || CPU == "generic" ||
CPU == "z10" || CPU == "z196" || CPU == "zEC12")
VectorABI = false;
@ -51,9 +52,13 @@ static bool UsesVectorABI(StringRef CPU, StringRef FS) {
VectorABI = true;
if (Feature == "-vector")
VectorABI = false;
if (Feature == "soft-float" || Feature == "+soft-float")
SoftFloat = true;
if (Feature == "-soft-float")
SoftFloat = false;
}
return VectorABI;
return VectorABI && !SoftFloat;
}
static std::string computeDataLayout(const Triple &TT, StringRef CPU,
@ -193,6 +198,7 @@ public:
void SystemZPassConfig::addIRPasses() {
if (getOptLevel() != CodeGenOpt::None) {
if (!getTM<SystemZTargetMachine>().getSubtargetImpl()->hasSoftFloat())
addPass(createSystemZTDCPass());
addPass(createLoopDataPrefetchPass());
}

View File

@ -1,6 +1,8 @@
; Test multiple return values (LLVM ABI extension)
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs| FileCheck %s
; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs \
; RUN: -mattr=soft-float | FileCheck %s --check-prefix=SOFT-FLOAT
; Up to four integer return values fit into GPRs.
define { i64, i64, i64, i64 } @f1() {
@ -37,6 +39,14 @@ define { double, double, double, double } @f3() {
; CHECK: larl [[TMP:%r[0-5]]], .LCPI
; CHECK: ldeb %f6, 0([[TMP]])
; CHECK: br %r14
; SOFT-FLOAT-LABEL: f3:
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: llihh %r2, 16368
; SOFT-FLOAT-NEXT: llihh %r3, 16384
; SOFT-FLOAT-NEXT: llihh %r4, 16392
; SOFT-FLOAT-NEXT: llihh %r5, 16400
; SOFT-FLOAT-NEXT: br %r14
ret { double, double, double, double }
{ double 1.0, double 2.0, double 3.0, double 4.0 }
}
@ -55,6 +65,21 @@ define { double, double, double, double, double } @f4() {
; CHECK: llihh [[TMP:%r[0-5]]], 16368
; CHECK: stg [[TMP]], 0(%r2)
; CHECK: br %r14
; SOFT-FLOAT-LABEL: f4:
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT-NOT: %r2
; SOFT-FLOAT: llihh %r0, 16404
; SOFT-FLOAT-NEXT: stg %r0, 32(%r2)
; SOFT-FLOAT-NEXT: llihh %r0, 16400
; SOFT-FLOAT-NEXT: stg %r0, 24(%r2)
; SOFT-FLOAT-NEXT: llihh %r0, 16392
; SOFT-FLOAT-NEXT: stg %r0, 16(%r2)
; SOFT-FLOAT-NEXT: llihh %r0, 16384
; SOFT-FLOAT-NEXT: stg %r0, 8(%r2)
; SOFT-FLOAT-NEXT: llihh %r0, 16368
; SOFT-FLOAT-NEXT: stg %r0, 0(%r2)
; SOFT-FLOAT-NEXT: br %r14
ret { double, double, double, double, double }
{ double 1.0, double 2.0, double 3.0, double 4.0, double 5.0 }
}

View File

@ -0,0 +1,235 @@
; RUN: llc -mcpu=z10 -mattr=soft-float -O0 < %s | FileCheck %s
; Arithmetic functions
define float @test_addsf3(float %a, float %b) {
; CHECK-LABEL: test_addsf3:
; CHECK: brasl %r14, __addsf3
%add = fadd float %a, %b
ret float %add
}
define double @test_adddf3(double %a, double %b) {
; CHECK-LABEL: test_adddf3:
; CHECK: brasl %r14, __adddf3
%add = fadd double %a, %b
ret double %add
}
define fp128 @test_addtf3(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_addtf3:
; CHECK: brasl %r14, __addtf3
%add = fadd fp128 %a, %b
ret fp128 %add
}
define float @test_mulsf3(float %a, float %b) {
; CHECK-LABEL: test_mulsf3:
; CHECK: brasl %r14, __mulsf3
%mul = fmul float %a, %b
ret float %mul
}
define double @test_muldf3(double %a, double %b) {
; CHECK-LABEL: test_muldf3:
; CHECK: brasl %r14, __muldf3
%mul = fmul double %a, %b
ret double %mul
}
define fp128 @test_multf3(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_multf3:
; CHECK: brasl %r14, __multf3
%mul = fmul fp128 %a, %b
ret fp128 %mul
}
define float @test_subsf3(float %a, float %b) {
; CHECK-LABEL: test_subsf3:
; CHECK: brasl %r14, __subsf3
%sub = fsub float %a, %b
ret float %sub
}
define double @test_subdf3(double %a, double %b) {
; CHECK-LABEL: test_subdf3:
; CHECK: brasl %r14, __subdf3
%sub = fsub double %a, %b
ret double %sub
}
define fp128 @test_subtf3(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_subtf3:
; CHECK: brasl %r14, __subtf3
%sub = fsub fp128 %a, %b
ret fp128 %sub
}
define float @test_divsf3(float %a, float %b) {
; CHECK-LABEL: test_divsf3:
; CHECK: brasl %r14, __divsf3
%div = fdiv float %a, %b
ret float %div
}
define double @test_divdf3(double %a, double %b) {
; CHECK-LABEL: test_divdf3:
; CHECK: brasl %r14, __divdf3
%div = fdiv double %a, %b
ret double %div
}
define fp128 @test_divtf3(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_divtf3:
; CHECK: brasl %r14, __divtf3
%div = fdiv fp128 %a, %b
ret fp128 %div
}
; Comparison functions
define i1 @test_unordsf2(float %a, float %b) {
; CHECK-LABEL: test_unordsf2:
; CHECK: brasl %r14, __unordsf2
%cmp = fcmp uno float %a, %b
ret i1 %cmp
}
define i1 @test_unorddf2(double %a, double %b) {
; CHECK-LABEL: test_unorddf2:
; CHECK: brasl %r14, __unorddf2
%cmp = fcmp uno double %a, %b
ret i1 %cmp
}
define i1 @test_unordtf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_unordtf2:
; CHECK: brasl %r14, __unordtf2
%cmp = fcmp uno fp128 %a, %b
ret i1 %cmp
}
define i1 @test_eqsf2(float %a, float %b) {
; CHECK-LABEL: test_eqsf2:
; CHECK: brasl %r14, __eqsf2
%cmp = fcmp oeq float %a, %b
ret i1 %cmp
}
define i1 @test_eqdf2(double %a, double %b) {
; CHECK-LABEL: test_eqdf2:
; CHECK: brasl %r14, __eqdf2
%cmp = fcmp oeq double %a, %b
ret i1 %cmp
}
define i1 @test_eqtf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_eqtf2:
; CHECK: brasl %r14, __eqtf2
%cmp = fcmp oeq fp128 %a, %b
ret i1 %cmp
}
define i1 @test_nesf2(float %a, float %b) {
; CHECK-LABEL: test_nesf2:
; CHECK: brasl %r14, __nesf2
%cmp = fcmp une float %a, %b
ret i1 %cmp
}
define i1 @test_nedf2(double %a, double %b) {
; CHECK-LABEL: test_nedf2:
; CHECK: brasl %r14, __nedf2
%cmp = fcmp une double %a, %b
ret i1 %cmp
}
define i1 @test_netf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_netf2:
; CHECK: brasl %r14, __netf2
%cmp = fcmp une fp128 %a, %b
ret i1 %cmp
}
define i1 @test_gesf2(float %a, float %b) {
; CHECK-LABEL: test_gesf2:
; CHECK: brasl %r14, __gesf2
%cmp = fcmp oge float %a, %b
ret i1 %cmp
}
define i1 @test_gedf2(double %a, double %b) {
; CHECK-LABEL: test_gedf2:
; CHECK: brasl %r14, __gedf2
%cmp = fcmp oge double %a, %b
ret i1 %cmp
}
define i1 @test_getf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_getf2:
; CHECK: brasl %r14, __getf2
%cmp = fcmp oge fp128 %a, %b
ret i1 %cmp
}
define i1 @test_ltsf2(float %a, float %b) {
; CHECK-LABEL: test_ltsf2:
; CHECK: brasl %r14, __ltsf2
%cmp = fcmp olt float %a, %b
ret i1 %cmp
}
define i1 @test_ltdf2(double %a, double %b) {
; CHECK-LABEL: test_ltdf2:
; CHECK: brasl %r14, __ltdf2
%cmp = fcmp olt double %a, %b
ret i1 %cmp
}
define i1 @test_lttf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_lttf2:
; CHECK: brasl %r14, __lttf2
%cmp = fcmp olt fp128 %a, %b
ret i1 %cmp
}
define i1 @test_lesf2(float %a, float %b) {
; CHECK-LABEL: test_lesf2:
; CHECK: brasl %r14, __lesf2
%cmp = fcmp ole float %a, %b
ret i1 %cmp
}
define i1 @test_ledf2(double %a, double %b) {
; CHECK-LABEL: test_ledf2:
; CHECK: brasl %r14, __ledf2
%cmp = fcmp ole double %a, %b
ret i1 %cmp
}
define i1 @test_letf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_letf2:
; CHECK: brasl %r14, __letf2
%cmp = fcmp ole fp128 %a, %b
ret i1 %cmp
}
define i1 @test_gtsf2(float %a, float %b) {
; CHECK-LABEL: test_gtsf2:
; CHECK: brasl %r14, __gtsf2
%cmp = fcmp ogt float %a, %b
ret i1 %cmp
}
define i1 @test_gtdf2(double %a, double %b) {
; CHECK-LABEL: test_gtdf2:
; CHECK: brasl %r14, __gtdf2
%cmp = fcmp ogt double %a, %b
ret i1 %cmp
}
define i1 @test_gttf2(fp128 %a, fp128 %b) {
; CHECK-LABEL: test_gttf2:
; CHECK: brasl %r14, __gttf2
%cmp = fcmp ogt fp128 %a, %b
ret i1 %cmp
}

View File

@ -0,0 +1,15 @@
; RUN: llc < %s -mtriple=s390x-linux-gnu -mattr=soft-float | FileCheck %s
;
; Check that FP registers are not saved in a vararg function if soft-float is
; used.
define void @fun0(...) {
; CHECK-LABEL: fun0
; CHECK-NOT: std %f0
; CHECK-NOT: std %f2
; CHECK-NOT: std %f4
; CHECK-NOT: std %f6
ret void
}

View File

@ -0,0 +1,11 @@
; RUN: llc -mcpu=z13 -mattr=soft-float -O3 < %s | FileCheck %s
;
; Check that soft-float implies "-vector".
define <2 x i64> @f0(<2 x i64> %dummy, <2 x i64> %val1, <2 x i64> %val2) {
; CHECK-LABEL: f0:
; CHECK-NOT: vag
; CHECK-NOT: %v
%res = add <2 x i64> %val1, %val2
ret <2 x i64> %res
}

View File

@ -0,0 +1,22 @@
; RUN: llc -mcpu=z14 -O3 -mattr=soft-float < %s | FileCheck %s
;
; Check that this function with soft-float does not result in a s390.tdc
; intrinsic (which cannot be handled by SoftenFloatOperand).
define void @fun(float %arg) {
; CHECK-LABEL: fun:
; CHECK: cijl
bb:
%tmp = bitcast float %arg to i32
br label %bb1
bb1: ; preds = %bb
%tmp2 = icmp sgt i32 %tmp, -1
br i1 %tmp2, label %bb3, label %bb4
bb3: ; preds = %bb1
unreachable
bb4: ; preds = %bb1
unreachable
}

View File

@ -0,0 +1,308 @@
; RUN: llc -mcpu=z13 -mattr=soft-float -O3 < %s | FileCheck %s
;
; Test that arguments and return values of fp/vector types are always handled
; with gprs with soft-float.
define double @f1(double %arg) {
; CHECK-LABEL: f1:
; CHECK-NOT: %r2
; CHECK-NOT: %{{[fv]}}
; CHECK: llihh %r3, 16368
; CHECK-NEXT: brasl %r14, __adddf3@PLT
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = fadd double %arg, 1.0
ret double %res
}
define float @f2(float %arg) {
; CHECK-LABEL: f2:
; CHECK-NOT: %r2
; CHECK-NOT: %{{[fv]}}
; CHECK: llgfr %r2, %r2
; CHECK-NEXT: llilh %r3, 16256
; CHECK-NEXT: brasl %r14, __addsf3@PLT
; CHECK-NEXT: # kill: def $r2l killed $r2l killed $r2d
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = fadd float %arg, 1.0
ret float %res
}
define fp128 @f2_fp128(fp128 %arg) {
; CHECK-LABEL: f2_fp128:
; CHECK-NOT: %{{[fv]}}
; CHECK: aghi %r15, -208
; CHECK-NEXT: .cfi_def_cfa_offset 368
; CHECK-NEXT: lg %r0, 0(%r2)
; CHECK-NEXT: lg %r1, 8(%r2)
; CHECK-NEXT: llihf %r2, 1073823744
; CHECK-NEXT: stg %r2, 160(%r15)
; CHECK-NEXT: la %r2, 192(%r15)
; CHECK-NEXT: la %r3, 176(%r15)
; CHECK-NEXT: la %r4, 160(%r15)
; CHECK-NEXT: stg %r1, 184(%r15)
; CHECK-NEXT: stg %r0, 176(%r15)
; CHECK-NEXT: mvghi 168(%r15), 0
; CHECK-NEXT: brasl %r14, __addtf3@PLT
; CHECK-NEXT: lg %r2, 192(%r15)
; CHECK-NEXT: lg %r3, 200(%r15)
; CHECK-NEXT: lmg %r14, %r15, 320(%r15)
; CHECK-NEXT: br %r14
%res = fadd fp128 %arg, 0xL00000000000000004001400000000000
ret fp128 %res
}
define <2 x double> @f3(<2 x double> %arg) {
; CHECK-LABEL: f3:
; CHECK-NOT: %{{[fv]}}
; CHECK: lg %r13, 8(%r2)
; CHECK-NEXT: lg %r2, 0(%r2)
; CHECK-NEXT: llihh %r3, 16368
; CHECK-NEXT: brasl %r14, __adddf3@PLT
; CHECK-NEXT: lgr %r12, %r2
; CHECK-NEXT: lgr %r2, %r13
; CHECK-NEXT: llihh %r3, 16368
; CHECK-NEXT: brasl %r14, __adddf3@PLT
; CHECK-NEXT: lgr %r3, %r2
; CHECK-NEXT: lgr %r2, %r12
; CHECK-NEXT: lmg %r12, %r15, 256(%r15)
; CHECK-NEXT: br %r14
%res = fadd <2 x double> %arg, <double 1.000000e+00, double 1.000000e+00>
ret <2 x double> %res
}
define <2 x float> @f4(<2 x float> %arg) {
; CHECK-LABEL: f4:
; CHECK-NOT: %{{[fv]}}
; CHECK: lr %r13, %r3
; CHECK-NEXT: llgfr %r2, %r2
; CHECK-NEXT: llilh %r3, 16256
; CHECK-NEXT: brasl %r14, __addsf3@PLT
; CHECK-NEXT: lgr %r12, %r2
; CHECK-NEXT: llgfr %r2, %r13
; CHECK-NEXT: llilh %r3, 16256
; CHECK-NEXT: brasl %r14, __addsf3@PLT
; CHECK-NEXT: lgr %r3, %r2
; CHECK-NEXT: lr %r2, %r12
; CHECK-NEXT: # kill: def $r3l killed $r3l killed $r3d
; CHECK-NEXT: lmg %r12, %r15, 256(%r15)
; CHECK-NEXT: br %r14
%res = fadd <2 x float> %arg, <float 1.000000e+00, float 1.000000e+00>
ret <2 x float> %res
}
define <2 x i64> @f5(<2 x i64> %arg) {
; CHECK-LABEL: f5:
; CHECK-NOT: %{{[fv]}}
; CHECK: lghi %r0, 1
; CHECK-NEXT: ag %r0, 0(%r2)
; CHECK-NEXT: lghi %r3, 1
; CHECK-NEXT: ag %r3, 8(%r2)
; CHECK-NEXT: lgr %r2, %r0
; CHECK-NEXT: br %r14
%res = add <2 x i64> %arg, <i64 1, i64 1>
ret <2 x i64> %res
}
define <2 x i32> @f6(<2 x i32> %arg) {
; CHECK-LABEL: f6:
; CHECK-NOT: %{{[fv]}}
; CHECK: ahi %r2, 1
; CHECK-NEXT: ahi %r3, 1
; CHECK-NEXT: br %r14
%res = add <2 x i32> %arg, <i32 1, i32 1>
ret <2 x i32> %res
}
;; Stack arguments
define double @f7(double %A, double %B, double %C, double %D, double %E,
double %F) {
; CHECK-LABEL: f7:
; CHECK-NOT: %{{[fv]}}
; CHECK: aghi %r15, -160
; CHECK-NEXT: .cfi_def_cfa_offset 320
; CHECK-NEXT: lg %r3, 320(%r15)
; CHECK-NEXT: brasl %r14, __adddf3@PLT
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = fadd double %A, %F
ret double %res
}
define float @f8(float %A, float %B, float %C, float %D, float %E,
float %F) {
; CHECK-LABEL: f8:
; CHECK-NOT: %{{[fv]}}
; CHECK: aghi %r15, -160
; CHECK-NEXT: .cfi_def_cfa_offset 320
; CHECK-NEXT: llgf %r3, 324(%r15)
; CHECK-NEXT: llgfr %r2, %r2
; CHECK-NEXT: brasl %r14, __addsf3@PLT
; CHECK-NEXT: # kill: def $r2l killed $r2l killed $r2d
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = fadd float %A, %F
ret float %res
}
define <2 x double> @f9(<2 x double> %A, <2 x double> %B, <2 x double> %C,
<2 x double> %D, <2 x double> %E, <2 x double> %F,
<2 x double> %G, <2 x double> %H, <2 x double> %I) {
; CHECK-LABEL: f9:
; CHECK-NOT: %{{[fv]}}
; CHECK: aghi %r15, -160
; CHECK-NEXT: .cfi_def_cfa_offset 320
; CHECK-NEXT: lg %r1, 344(%r15)
; CHECK-NEXT: lg %r13, 8(%r2)
; CHECK-NEXT: lg %r2, 0(%r2)
; CHECK-NEXT: lg %r3, 0(%r1)
; CHECK-NEXT: lg %r12, 8(%r1)
; CHECK-NEXT: brasl %r14, __adddf3@PLT
; CHECK-NEXT: lgr %r11, %r2
; CHECK-NEXT: lgr %r2, %r13
; CHECK-NEXT: lgr %r3, %r12
; CHECK-NEXT: brasl %r14, __adddf3@PLT
; CHECK-NEXT: lgr %r3, %r2
; CHECK-NEXT: lgr %r2, %r11
; CHECK-NEXT: lmg %r11, %r15, 248(%r15)
; CHECK-NEXT: br %r14
%res = fadd <2 x double> %A, %I
ret <2 x double> %res
}
define <2 x float> @f10(<2 x float> %A, <2 x float> %B, <2 x float> %C,
<2 x float> %D, <2 x float> %E, <2 x float> %F,
<2 x float> %G, <2 x float> %H, <2 x float> %I) {
; CHECK-LABEL: f10:
; CHECK-NOT: %{{[fv]}}
; CHECK: aghi %r15, -160
; CHECK-NEXT: .cfi_def_cfa_offset 320
; CHECK-NEXT: lr %r13, %r3
; CHECK-NEXT: llgf %r3, 412(%r15)
; CHECK-NEXT: llgf %r12, 420(%r15)
; CHECK-NEXT: llgfr %r2, %r2
; CHECK-NEXT: brasl %r14, __addsf3@PLT
; CHECK-NEXT: lgr %r11, %r2
; CHECK-NEXT: llgfr %r2, %r13
; CHECK-NEXT: lgr %r3, %r12
; CHECK-NEXT: brasl %r14, __addsf3@PLT
; CHECK-NEXT: lgr %r3, %r2
; CHECK-NEXT: lr %r2, %r11
; CHECK-NEXT: # kill: def $r3l killed $r3l killed $r3d
; CHECK-NEXT: lmg %r11, %r15, 248(%r15)
; CHECK-NEXT: br %r14
%res = fadd <2 x float> %A, %I
ret <2 x float> %res
}
define <2 x i64> @f11(<2 x i64> %A, <2 x i64> %B, <2 x i64> %C,
<2 x i64> %D, <2 x i64> %E, <2 x i64> %F,
<2 x i64> %G, <2 x i64> %H, <2 x i64> %I) {
; CHECK-LABEL: f11:
; CHECK-NOT: %{{[fv]}}
; CHECK: lg %r1, 184(%r15)
; CHECK-NEXT: lg %r3, 8(%r2)
; CHECK-NEXT: lg %r2, 0(%r2)
; CHECK-NEXT: ag %r2, 0(%r1)
; CHECK-NEXT: ag %r3, 8(%r1)
; CHECK-NEXT: br %r14
%res = add <2 x i64> %A, %I
ret <2 x i64> %res
}
;; calls
declare double @bar_double(double %arg);
define double @f12(double %arg, double %arg2) {
; CHECK-LABEL: f12:
; CHECK-NOT: %{{[fv]}}
; CHECK-NOT: %r{{[23]}}
; CHECK: lgr %r2, %r3
; CHECK-NEXT: brasl %r14, bar_double@PLT
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = call double @bar_double(double %arg2)
ret double %res
}
declare float @bar_float(float %arg);
define float @f13(float %arg, float %arg2) {
; CHECK-LABEL: f13:
; CHECK-NOT: %{{[fv]}}
; CHECK-NOT: %r{{[23]}}
; CHECK: lr %r2, %r3
; CHECK-NEXT: brasl %r14, bar_float@PLT
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = call float @bar_float(float %arg2)
ret float %res
}
declare fp128 @bar_fp128(fp128 %arg);
define fp128 @f14(fp128 %arg, fp128 %arg2) {
; CHECK-LABEL: f14:
; CHECK-NOT: %{{[fv]}}
; CHECK-NOT: %r3
; CHECK: lg %r0, 0(%r3)
; CHECK-NEXT: lg %r1, 8(%r3)
; CHECK-NEXT: la %r2, 160(%r15)
; CHECK-NEXT: stg %r1, 168(%r15)
; CHECK-NEXT: stg %r0, 160(%r15)
; CHECK-NEXT: brasl %r14, bar_fp128@PLT
; CHECK-NEXT: lmg %r14, %r15, 288(%r15)
; CHECK-NEXT: br %r14
%res = call fp128 @bar_fp128(fp128 %arg2)
ret fp128 %res
}
declare <2 x double> @bar_v2f64(<2 x double> %arg);
define <2 x double> @f15(<2 x double> %arg, <2 x double> %arg2) {
; CHECK-LABEL: f15:
; CHECK-NOT: %{{[fv]}}
; CHECK-NOT: %r3
; CHECK: lg %r0, 0(%r3)
; CHECK-NEXT: lg %r1, 8(%r3)
; CHECK-NEXT: la %r2, 160(%r15)
; CHECK-NEXT: stg %r1, 168(%r15)
; CHECK-NEXT: stg %r0, 160(%r15)
; CHECK-NEXT: brasl %r14, bar_v2f64@PLT
; CHECK-NEXT: lmg %r14, %r15, 288(%r15)
; CHECK-NEXT: br %r14
%res = call <2 x double> @bar_v2f64(<2 x double> %arg2)
ret <2 x double> %res
}
declare <2 x float> @bar_v2f32(<2 x float> %arg);
define <2 x float> @f16(<2 x float> %arg, <2 x float> %arg2) {
; CHECK-LABEL: f16:
; CHECK-NOT: %{{[fv]}}
; CHECK-NOT: %r{{[2345]}}
; CHECK: lr %r3, %r5
; CHECK-NEXT: lr %r2, %r4
; CHECK-NEXT: brasl %r14, bar_v2f32@PLT
; CHECK-NEXT: lmg %r14, %r15, 272(%r15)
; CHECK-NEXT: br %r14
%res = call <2 x float> @bar_v2f32(<2 x float> %arg2)
ret <2 x float> %res
}
declare <2 x i64> @bar_v2i64(<2 x i64> %arg);
define <2 x i64> @f17(<2 x i64> %arg, <2 x i64> %arg2) {
; CHECK-LABEL: f17:
; CHECK-NOT: %{{[fv]}}
; CHECK-NOT: %r3
; CHECK: lg %r0, 0(%r3)
; CHECK-NEXT: lg %r1, 8(%r3)
; CHECK-NEXT: la %r2, 160(%r15)
; CHECK-NEXT: stg %r1, 168(%r15)
; CHECK-NEXT: stg %r0, 160(%r15)
; CHECK-NEXT: brasl %r14, bar_v2i64@PLT
; CHECK-NEXT: lmg %r14, %r15, 288(%r15)
; CHECK-NEXT: br %r14
%res = call <2 x i64> @bar_v2i64(<2 x i64> %arg2)
ret <2 x i64> %res
}

View File

@ -0,0 +1,10 @@
; RUN: not llc < %s -mcpu=z13 -mattr=soft-float -O3 2>&1 | FileCheck %s
;
; Verify that inline asms cannot use fp/vector registers with soft-float.
define float @f1() {
%ret = call float asm "", "=f" ()
ret float %ret
}
; CHECK: error: couldn't allocate output register for constraint 'f'

View File

@ -0,0 +1,10 @@
; RUN: not llc < %s -mcpu=z13 -mattr=soft-float -O3 2>&1 | FileCheck %s
;
; Verify that inline asms cannot use fp/vector registers with soft-float.
define float @f1() {
%ret = call float asm "", "={f0}" ()
ret float %ret
}
; CHECK: error: couldn't allocate output register for constraint '{f0}'

View File

@ -0,0 +1,10 @@
; RUN: not llc < %s -mcpu=z13 -mattr=soft-float -O3 2>&1 | FileCheck %s
;
; Verify that inline asms cannot use fp/vector registers with soft-float.
define <2 x i64> @f1() {
%ret = call <2 x i64> asm "", "=v" ()
ret <2 x i64> %ret
}
; CHECK: error: couldn't allocate output register for constraint 'v'

View File

@ -32,6 +32,15 @@
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -mattr=-vector | \
; RUN: FileCheck -check-prefix=CHECK-NOVECTOR %s
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -mattr=+soft-float | \
; RUN: FileCheck -check-prefix=CHECK-NOVECTOR %s
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 \
; RUN: -mattr=soft-float,-soft-float | \
; RUN: FileCheck -check-prefix=CHECK-VECTOR %s
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 \
; RUN: -mattr=-soft-float,soft-float | \
; RUN: FileCheck -check-prefix=CHECK-NOVECTOR %s
%struct.S = type { i8, <2 x i64> }
define void @test(%struct.S* %s) nounwind {

View File

@ -1,6 +1,8 @@
; Test multiple return values (LLVM ABI extension)
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -mattr=soft-float \
; RUN: | FileCheck %s --check-prefix=SOFT-FLOAT
; Up to eight vector return values fit into VRs.
define { <2 x double>, <2 x double>, <2 x double>, <2 x double>,
@ -23,6 +25,17 @@ define { <2 x double>, <2 x double>, <2 x double>, <2 x double>,
; CHECK: larl [[TMP:%r[0-5]]], .LCPI
; CHECK: vl %v31, 0([[TMP]])
; CHECK: br %r14
; SOFT-FLOAT-LABEL: f1:
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: llihf
; SOFT-FLOAT-NEXT: oilf
; SOFT-FLOAT-NEXT: stg
; SOFT-FLOAT-NEXT: llihh
; SOFT-FLOAT-NEXT: stg
; SOFT-FLOAT-NEXT: llihf
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: br %r14
ret { <2 x double>, <2 x double>, <2 x double>, <2 x double>,
<2 x double>, <2 x double>, <2 x double>, <2 x double> }
{ <2 x double> <double 1.0, double 1.1>,
@ -68,6 +81,17 @@ define { <2 x double>, <2 x double>, <2 x double>, <2 x double>,
; CHECK: vl [[VTMP:%v[0-9]+]], 0([[TMP]])
; CHECK: vst [[VTMP]], 0(%r2)
; CHECK: br %r14
; SOFT-FLOAT-LABEL: f2:
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: llihf
; SOFT-FLOAT-NEXT: oilf
; SOFT-FLOAT-NEXT: stg
; SOFT-FLOAT-NEXT: llihh
; SOFT-FLOAT-NEXT: stg
; SOFT-FLOAT-NEXT: llihf
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: br %r14
ret { <2 x double>, <2 x double>, <2 x double>, <2 x double>,
<2 x double>, <2 x double>, <2 x double>, <2 x double>,
<2 x double> }

View File

@ -1,6 +1,8 @@
; Test calling functions with multiple return values (LLVM ABI extension)
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -mattr=soft-float \
; RUN: | FileCheck %s --check-prefix=SOFT-FLOAT
; Up to eight vector return values fit into VRs.
declare { <2 x double>, <2 x double>, <2 x double>, <2 x double>,
@ -11,6 +13,14 @@ define <2 x double> @f1() {
; CHECK: brasl %r14, bar1
; CHECK: vlr %v24, %v31
; CHECK: br %r14
; SOFT-FLOAT-LABEL: f1:
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: brasl %r14, bar1
; SOFT-FLOAT-NEXT: lg %r3, 280(%r15)
; SOFT-FLOAT-NEXT: lg %r2, 272(%r15)
; SOFT-FLOAT-NEXT: lmg %r14, %r15, 400(%r15)
; SOFT-FLOAT-NEXT: br %r14
%mret = call { <2 x double>, <2 x double>,
<2 x double>, <2 x double>,
<2 x double>, <2 x double>,
@ -33,6 +43,14 @@ define <2 x double> @f2() {
; CHECK: brasl %r14, bar2
; CHECK: vl %v24, 288(%r15)
; CHECK: br %r14
; SOFT-FLOAT-LABEL: f2:
; SOFT-FLOAT-NOT: %{{[fv]}}
; SOFT-FLOAT: brasl %r14, bar2
; SOFT-FLOAT-NEXT: lg %r3, 296(%r15)
; SOFT-FLOAT-NEXT: lg %r2, 288(%r15)
; SOFT-FLOAT-NEXT: lmg %r14, %r15, 416(%r15)
; SOFT-FLOAT-NEXT: br %r14
%mret = call { <2 x double>, <2 x double>,
<2 x double>, <2 x double>,
<2 x double>, <2 x double>,