summaryrefslogtreecommitdiffstats
path: root/clang/utils/TableGen/MveEmitter.cpp
diff options
context:
space:
mode:
authorSimon Tatham <simon.tatham@arm.com>2019-11-15 09:53:15 +0000
committerSimon Tatham <simon.tatham@arm.com>2019-11-15 09:53:58 +0000
commit9e37892773c0954a15f84b011223da1e707ab3bf (patch)
treed3aec012c1d6f5633cf81c408a5146b87903e59c /clang/utils/TableGen/MveEmitter.cpp
parent902e84556a51c70d95088aaa059ab9c494ab3516 (diff)
downloadbcm5719-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.cpp24
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");
OpenPOWER on IntegriCloud