diff options
author | Simon Tatham <simon.tatham@arm.com> | 2019-11-15 09:53:15 +0000 |
---|---|---|
committer | Simon Tatham <simon.tatham@arm.com> | 2019-11-15 09:53:58 +0000 |
commit | 9e37892773c0954a15f84b011223da1e707ab3bf (patch) | |
tree | d3aec012c1d6f5633cf81c408a5146b87903e59c /clang/utils/TableGen/MveEmitter.cpp | |
parent | 902e84556a51c70d95088aaa059ab9c494ab3516 (diff) | |
download | bcm5719-llvm-9e37892773c0954a15f84b011223da1e707ab3bf.tar.gz bcm5719-llvm-9e37892773c0954a15f84b011223da1e707ab3bf.zip |
[ARM,MVE] Add intrinsics for vector get/set lane.
This adds the `vgetq_lane` and `vsetq_lane` families, to copy between
a scalar and a specified lane of a vector.
One of the new `vgetq_lane` intrinsics returns a `float16_t`, which
causes a compile error if `%clang_cc1` doesn't get the option
`-fallow-half-arguments-and-returns`. The driver passes that option to
cc1 already, but I've had to edit all the explicit cc1 command lines
in the existing MVE intrinsics tests.
A couple of fixes are included for the code I wrote up front in
MveEmitter to support lane-index immediates (and which nothing has
tested until now): the type was wrong (`uint32_t` instead of `int`)
and the range was off by one.
I've also added a method of bypassing the default promotion to `i32`
that is done by the MveEmitter code generation: it's sensible to
promote short scalars like `i16` to `i32` if they're going to be
passed to custom IR intrinsics representing a machine instruction
operating on GPRs, but not if they're going to be passed to standard
IR operations like `insertelement` which expect the exact type.
Reviewers: ostannard, MarkMurrayARM, dmgreen
Reviewed By: dmgreen
Subscribers: kristof.beyls, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D70188
Diffstat (limited to 'clang/utils/TableGen/MveEmitter.cpp')
-rw-r--r-- | clang/utils/TableGen/MveEmitter.cpp | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp index 4258dd0a1f4..1ca3b5a3f22 100644 --- a/clang/utils/TableGen/MveEmitter.cpp +++ b/clang/utils/TableGen/MveEmitter.cpp @@ -980,7 +980,8 @@ public: const Type *Param); Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum, const Result::Scope &Scope, const Type *Param); - Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType); + Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, + bool Promote); // Constructor and top-level functions. @@ -1003,8 +1004,13 @@ const Type *MveEmitter::getType(Init *I, const Type *Param) { } const Type *MveEmitter::getType(Record *R, const Type *Param) { + // Pass to a subfield of any wrapper records. We don't expect more than one + // of these: immediate operands are used as plain numbers rather than as + // llvm::Value, so it's meaningless to promote their type anyway. if (R->isSubClassOf("Immediate")) - R = R->getValueAsDef("type"); // pass to subfield + R = R->getValueAsDef("type"); + else if (R->isSubClassOf("unpromoted")) + R = R->getValueAsDef("underlying_type"); if (R->getName() == "Void") return getVoidType(); @@ -1197,12 +1203,13 @@ Result::Ptr MveEmitter::getCodeForDagArg(DagInit *D, unsigned ArgNum, PrintFatalError("bad dag argument type for code generation"); } -Result::Ptr MveEmitter::getCodeForArg(unsigned ArgNum, const Type *ArgType) { +Result::Ptr MveEmitter::getCodeForArg(unsigned ArgNum, const Type *ArgType, + bool Promote) { Result::Ptr V = std::make_shared<BuiltinArgResult>(ArgNum, isa<PointerType>(ArgType)); if (const auto *ST = dyn_cast<ScalarType>(ArgType)) { - if (ST->isInteger() && ST->sizeInBits() < 32) + if (Promote && ST->isInteger() && ST->sizeInBits() < 32) V = std::make_shared<IntCastResult>(getScalarType("u32"), V); } else if (const auto *PT = dyn_cast<PredicateType>(ArgType)) { V = std::make_shared<IntCastResult>(getScalarType("u32"), V); @@ -1260,6 +1267,11 @@ ACLEIntrinsic::ACLEIntrinsic(MveEmitter &ME, Record *R, const Type *Param) for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) { Init *TypeInit = ArgsDag->getArg(i); + bool Promote = true; + if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) + if (TypeDI->getDef()->isSubClassOf("unpromoted")) + Promote = false; + // Work out the type of the argument, for use in the function prototype in // the header file. const Type *ArgType = ME.getType(TypeInit, Param); @@ -1269,7 +1281,7 @@ ACLEIntrinsic::ACLEIntrinsic(MveEmitter &ME, Record *R, const Type *Param) // into the variable-name scope that the code gen will refer to. StringRef ArgName = ArgsDag->getArgNameStr(i); if (!ArgName.empty()) - Scope[ArgName] = ME.getCodeForArg(i, ArgType); + Scope[ArgName] = ME.getCodeForArg(i, ArgType, Promote); // If the argument is a subclass of Immediate, record the details about // what values it can take, for Sema checking. @@ -1288,7 +1300,7 @@ ACLEIntrinsic::ACLEIntrinsic(MveEmitter &ME, Record *R, const Type *Param) } else if (Bounds->getName() == "IB_LaneIndex") { IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; IA.i1 = 0; - IA.i2 = 128 / Param->sizeInBits(); + IA.i2 = 128 / Param->sizeInBits() - 1; } else if (Bounds->getName() == "IB_EltBit") { IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; IA.i1 = Bounds->getValueAsInt("base"); |