2018-11-28 12:38:10 +01:00
|
|
|
//===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2018-11-28 12:38:10 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements a target parser to recognise ARM hardware features
|
|
|
|
// such as FPU/CPU/ARCH/extensions and specific support such as HWDIV.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Support/ARMTargetParser.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2018-11-28 16:12:33 +01:00
|
|
|
#include <cctype>
|
2018-11-28 12:38:10 +01:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
static StringRef getHWDivSynonym(StringRef HWDiv) {
|
|
|
|
return StringSwitch<StringRef>(HWDiv)
|
|
|
|
.Case("thumb,arm", "arm,thumb")
|
|
|
|
.Default(HWDiv);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allows partial match, ex. "v7a" matches "armv7a".
|
|
|
|
ARM::ArchKind ARM::parseArch(StringRef Arch) {
|
|
|
|
Arch = getCanonicalArchName(Arch);
|
|
|
|
StringRef Syn = getArchSynonym(Arch);
|
|
|
|
for (const auto A : ARCHNames) {
|
|
|
|
if (A.getName().endswith(Syn))
|
|
|
|
return A.ID;
|
|
|
|
}
|
|
|
|
return ArchKind::INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Version number (ex. v7 = 7).
|
|
|
|
unsigned ARM::parseArchVersion(StringRef Arch) {
|
|
|
|
Arch = getCanonicalArchName(Arch);
|
|
|
|
switch (parseArch(Arch)) {
|
|
|
|
case ArchKind::ARMV2:
|
|
|
|
case ArchKind::ARMV2A:
|
|
|
|
return 2;
|
|
|
|
case ArchKind::ARMV3:
|
|
|
|
case ArchKind::ARMV3M:
|
|
|
|
return 3;
|
|
|
|
case ArchKind::ARMV4:
|
|
|
|
case ArchKind::ARMV4T:
|
|
|
|
return 4;
|
|
|
|
case ArchKind::ARMV5T:
|
|
|
|
case ArchKind::ARMV5TE:
|
|
|
|
case ArchKind::IWMMXT:
|
|
|
|
case ArchKind::IWMMXT2:
|
|
|
|
case ArchKind::XSCALE:
|
|
|
|
case ArchKind::ARMV5TEJ:
|
|
|
|
return 5;
|
|
|
|
case ArchKind::ARMV6:
|
|
|
|
case ArchKind::ARMV6K:
|
|
|
|
case ArchKind::ARMV6T2:
|
|
|
|
case ArchKind::ARMV6KZ:
|
|
|
|
case ArchKind::ARMV6M:
|
|
|
|
return 6;
|
|
|
|
case ArchKind::ARMV7A:
|
|
|
|
case ArchKind::ARMV7VE:
|
|
|
|
case ArchKind::ARMV7R:
|
|
|
|
case ArchKind::ARMV7M:
|
|
|
|
case ArchKind::ARMV7S:
|
|
|
|
case ArchKind::ARMV7EM:
|
|
|
|
case ArchKind::ARMV7K:
|
|
|
|
return 7;
|
|
|
|
case ArchKind::ARMV8A:
|
|
|
|
case ArchKind::ARMV8_1A:
|
|
|
|
case ArchKind::ARMV8_2A:
|
|
|
|
case ArchKind::ARMV8_3A:
|
|
|
|
case ArchKind::ARMV8_4A:
|
|
|
|
case ArchKind::ARMV8_5A:
|
|
|
|
case ArchKind::ARMV8R:
|
|
|
|
case ArchKind::ARMV8MBaseline:
|
|
|
|
case ArchKind::ARMV8MMainline:
|
2019-05-30 14:57:04 +02:00
|
|
|
case ArchKind::ARMV8_1MMainline:
|
2018-11-28 12:38:10 +01:00
|
|
|
return 8;
|
|
|
|
case ArchKind::INVALID:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unhandled architecture");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Profile A/R/M
|
|
|
|
ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
|
|
|
|
Arch = getCanonicalArchName(Arch);
|
|
|
|
switch (parseArch(Arch)) {
|
|
|
|
case ArchKind::ARMV6M:
|
|
|
|
case ArchKind::ARMV7M:
|
|
|
|
case ArchKind::ARMV7EM:
|
|
|
|
case ArchKind::ARMV8MMainline:
|
|
|
|
case ArchKind::ARMV8MBaseline:
|
2019-05-30 14:57:04 +02:00
|
|
|
case ArchKind::ARMV8_1MMainline:
|
2018-11-28 12:38:10 +01:00
|
|
|
return ProfileKind::M;
|
|
|
|
case ArchKind::ARMV7R:
|
|
|
|
case ArchKind::ARMV8R:
|
|
|
|
return ProfileKind::R;
|
|
|
|
case ArchKind::ARMV7A:
|
|
|
|
case ArchKind::ARMV7VE:
|
|
|
|
case ArchKind::ARMV7K:
|
|
|
|
case ArchKind::ARMV8A:
|
|
|
|
case ArchKind::ARMV8_1A:
|
|
|
|
case ArchKind::ARMV8_2A:
|
|
|
|
case ArchKind::ARMV8_3A:
|
|
|
|
case ArchKind::ARMV8_4A:
|
|
|
|
case ArchKind::ARMV8_5A:
|
|
|
|
return ProfileKind::A;
|
|
|
|
case ArchKind::ARMV2:
|
|
|
|
case ArchKind::ARMV2A:
|
|
|
|
case ArchKind::ARMV3:
|
|
|
|
case ArchKind::ARMV3M:
|
|
|
|
case ArchKind::ARMV4:
|
|
|
|
case ArchKind::ARMV4T:
|
|
|
|
case ArchKind::ARMV5T:
|
|
|
|
case ArchKind::ARMV5TE:
|
|
|
|
case ArchKind::ARMV5TEJ:
|
|
|
|
case ArchKind::ARMV6:
|
|
|
|
case ArchKind::ARMV6K:
|
|
|
|
case ArchKind::ARMV6T2:
|
|
|
|
case ArchKind::ARMV6KZ:
|
|
|
|
case ArchKind::ARMV7S:
|
|
|
|
case ArchKind::IWMMXT:
|
|
|
|
case ArchKind::IWMMXT2:
|
|
|
|
case ArchKind::XSCALE:
|
|
|
|
case ArchKind::INVALID:
|
|
|
|
return ProfileKind::INVALID;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unhandled architecture");
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getArchSynonym(StringRef Arch) {
|
|
|
|
return StringSwitch<StringRef>(Arch)
|
|
|
|
.Case("v5", "v5t")
|
|
|
|
.Case("v5e", "v5te")
|
|
|
|
.Case("v6j", "v6")
|
|
|
|
.Case("v6hl", "v6k")
|
|
|
|
.Cases("v6m", "v6sm", "v6s-m", "v6-m")
|
|
|
|
.Cases("v6z", "v6zk", "v6kz")
|
|
|
|
.Cases("v7", "v7a", "v7hl", "v7l", "v7-a")
|
|
|
|
.Case("v7r", "v7-r")
|
|
|
|
.Case("v7m", "v7-m")
|
|
|
|
.Case("v7em", "v7e-m")
|
|
|
|
.Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a")
|
|
|
|
.Case("v8.1a", "v8.1-a")
|
|
|
|
.Case("v8.2a", "v8.2-a")
|
|
|
|
.Case("v8.3a", "v8.3-a")
|
|
|
|
.Case("v8.4a", "v8.4-a")
|
|
|
|
.Case("v8.5a", "v8.5-a")
|
|
|
|
.Case("v8r", "v8-r")
|
|
|
|
.Case("v8m.base", "v8-m.base")
|
|
|
|
.Case("v8m.main", "v8-m.main")
|
2019-05-30 14:57:04 +02:00
|
|
|
.Case("v8.1m.main", "v8.1-m.main")
|
2018-11-28 12:38:10 +01:00
|
|
|
.Default(Arch);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) {
|
|
|
|
|
|
|
|
if (FPUKind >= FK_LAST || FPUKind == FK_INVALID)
|
|
|
|
return false;
|
|
|
|
|
[ARM] Fix bugs introduced by the fp64/d32 rework.
Change D60691 caused some knock-on failures that weren't caught by the
existing tests. Firstly, selecting a CPU that should have had a
restricted FPU (e.g. `-mcpu=cortex-m4`, which should have 16 d-regs
and no double precision) could give the unrestricted version, because
`ARM::getFPUFeatures` returned a list of features including subtracted
ones (here `-fp64`,`-d32`), but `ARMTargetInfo::initFeatureMap` threw
away all the ones that didn't start with `+`. Secondly, the
preprocessor macros didn't reliably match the actual compilation
settings: for example, `-mfpu=softvfp` could still set `__ARM_FP` as
if hardware FP was available, because the list of features on the cc1
command line would include things like `+vfp4`,`-vfp4d16` and clang
didn't realise that one of those cancelled out the other.
I've fixed both of these issues by rewriting `ARM::getFPUFeatures` so
that it returns a list that enables every FP-related feature
compatible with the selected FPU and disables every feature not
compatible, which is more verbose but means clang doesn't have to
understand the dependency relationships between the backend features.
Meanwhile, `ARMTargetInfo::handleTargetFeatures` is testing for all
the various forms of the FP feature names, so that it won't miss cases
where it should have set `HW_FP` to feed into feature test macros.
That in turn caused an ordering problem when handling `-mcpu=foo+bar`
together with `-mfpu=something_that_turns_off_bar`. To fix that, I've
arranged that the `+bar` suffixes on the end of `-mcpu` and `-march`
cause feature names to be put into a separate vector which is
concatenated after the output of `getFPUFeatures`.
Another side effect of all this is to fix a bug where `clang -target
armv8-eabi` by itself would fail to set `__ARM_FEATURE_FMA`, even
though `armv8` (aka Arm v8-A) implies FP-Armv8 which has FMA. That was
because `HW_FP` was being set to a value including only the `FPARMV8`
bit, but that feature test macro was testing only the `VFP4FPU` bit.
Now `HW_FP` ends up with all the bits set, so it gives the right
answer.
Changes to tests included in this patch:
* `arm-target-features.c`: I had to change basically all the expected
results. (The Cortex-M4 test in there should function as a
regression test for the accidental double-precision bug.)
* `arm-mfpu.c`, `armv8.1m.main.c`: switched to using `CHECK-DAG`
everywhere so that those tests are no longer sensitive to the order
of cc1 feature options on the command line.
* `arm-acle-6.5.c`: been updated to expect the right answer to that
FMA test.
* `Preprocessor/arm-target-features.c`: added a regression test for
the `mfpu=softvfp` issue.
Reviewers: SjoerdMeijer, dmgreen, ostannard, samparker, JamesNagurne
Reviewed By: ostannard
Subscribers: srhines, javed.absar, kristof.beyls, hiraditya, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62998
llvm-svn: 362791
2019-06-07 14:42:54 +02:00
|
|
|
static const struct FPUFeatureNameInfo {
|
|
|
|
const char *PlusName, *MinusName;
|
|
|
|
FPUVersion MinVersion;
|
|
|
|
FPURestriction MaxRestriction;
|
|
|
|
} FPUFeatureInfoList[] = {
|
|
|
|
// We have to specify the + and - versions of the name in full so
|
|
|
|
// that we can return them as static StringRefs.
|
|
|
|
//
|
|
|
|
// Also, the SubtargetFeatures ending in just "sp" are listed here
|
|
|
|
// under FPURestriction::None, which is the only FPURestriction in
|
|
|
|
// which they would be valid (since FPURestriction::SP doesn't
|
|
|
|
// exist).
|
|
|
|
|
|
|
|
{"+fpregs", "-fpregs", FPUVersion::VFPV2, FPURestriction::SP_D16},
|
|
|
|
{"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::None},
|
|
|
|
{"+vfp2d16", "-vfp2d16", FPUVersion::VFPV2, FPURestriction::D16},
|
|
|
|
{"+vfp2d16sp", "-vfp2d16sp", FPUVersion::VFPV2, FPURestriction::SP_D16},
|
|
|
|
{"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::None},
|
|
|
|
{"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None},
|
|
|
|
{"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16},
|
|
|
|
{"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16},
|
|
|
|
{"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None},
|
|
|
|
{"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16},
|
|
|
|
{"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None},
|
|
|
|
{"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16},
|
|
|
|
{"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16},
|
|
|
|
{"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None},
|
|
|
|
{"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None},
|
|
|
|
{"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16},
|
|
|
|
{"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16},
|
|
|
|
{"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None},
|
|
|
|
{"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16},
|
|
|
|
{"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16},
|
|
|
|
{"+d32", "-d32", FPUVersion::VFPV2, FPURestriction::None},
|
|
|
|
};
|
2018-11-28 12:38:10 +01:00
|
|
|
|
[ARM] Fix bugs introduced by the fp64/d32 rework.
Change D60691 caused some knock-on failures that weren't caught by the
existing tests. Firstly, selecting a CPU that should have had a
restricted FPU (e.g. `-mcpu=cortex-m4`, which should have 16 d-regs
and no double precision) could give the unrestricted version, because
`ARM::getFPUFeatures` returned a list of features including subtracted
ones (here `-fp64`,`-d32`), but `ARMTargetInfo::initFeatureMap` threw
away all the ones that didn't start with `+`. Secondly, the
preprocessor macros didn't reliably match the actual compilation
settings: for example, `-mfpu=softvfp` could still set `__ARM_FP` as
if hardware FP was available, because the list of features on the cc1
command line would include things like `+vfp4`,`-vfp4d16` and clang
didn't realise that one of those cancelled out the other.
I've fixed both of these issues by rewriting `ARM::getFPUFeatures` so
that it returns a list that enables every FP-related feature
compatible with the selected FPU and disables every feature not
compatible, which is more verbose but means clang doesn't have to
understand the dependency relationships between the backend features.
Meanwhile, `ARMTargetInfo::handleTargetFeatures` is testing for all
the various forms of the FP feature names, so that it won't miss cases
where it should have set `HW_FP` to feed into feature test macros.
That in turn caused an ordering problem when handling `-mcpu=foo+bar`
together with `-mfpu=something_that_turns_off_bar`. To fix that, I've
arranged that the `+bar` suffixes on the end of `-mcpu` and `-march`
cause feature names to be put into a separate vector which is
concatenated after the output of `getFPUFeatures`.
Another side effect of all this is to fix a bug where `clang -target
armv8-eabi` by itself would fail to set `__ARM_FEATURE_FMA`, even
though `armv8` (aka Arm v8-A) implies FP-Armv8 which has FMA. That was
because `HW_FP` was being set to a value including only the `FPARMV8`
bit, but that feature test macro was testing only the `VFP4FPU` bit.
Now `HW_FP` ends up with all the bits set, so it gives the right
answer.
Changes to tests included in this patch:
* `arm-target-features.c`: I had to change basically all the expected
results. (The Cortex-M4 test in there should function as a
regression test for the accidental double-precision bug.)
* `arm-mfpu.c`, `armv8.1m.main.c`: switched to using `CHECK-DAG`
everywhere so that those tests are no longer sensitive to the order
of cc1 feature options on the command line.
* `arm-acle-6.5.c`: been updated to expect the right answer to that
FMA test.
* `Preprocessor/arm-target-features.c`: added a regression test for
the `mfpu=softvfp` issue.
Reviewers: SjoerdMeijer, dmgreen, ostannard, samparker, JamesNagurne
Reviewed By: ostannard
Subscribers: srhines, javed.absar, kristof.beyls, hiraditya, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62998
llvm-svn: 362791
2019-06-07 14:42:54 +02:00
|
|
|
for (const auto &Info: FPUFeatureInfoList) {
|
|
|
|
if (FPUNames[FPUKind].FPUVer >= Info.MinVersion &&
|
|
|
|
FPUNames[FPUKind].Restriction <= Info.MaxRestriction)
|
|
|
|
Features.push_back(Info.PlusName);
|
|
|
|
else
|
|
|
|
Features.push_back(Info.MinusName);
|
[ARM] Replace fp-only-sp and d16 with fp64 and d32.
Those two subtarget features were awkward because their semantics are
reversed: each one indicates the _lack_ of support for something in
the architecture, rather than the presence. As a consequence, you
don't get the behavior you want if you combine two sets of feature
bits.
Each SubtargetFeature for an FP architecture version now comes in four
versions, one for each combination of those options. So you can still
say (for example) '+vfp2' in a feature string and it will mean what
it's always meant, but there's a new string '+vfp2d16sp' meaning the
version without those extra options.
A lot of this change is just mechanically replacing positive checks
for the old features with negative checks for the new ones. But one
more interesting change is that I've rearranged getFPUFeatures() so
that the main FPU feature is appended to the output list *before*
rather than after the features derived from the Restriction field, so
that -fp64 and -d32 can override defaults added by the main feature.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: srhines, javed.absar, eraman, kristof.beyls, hiraditya, zzheng, Petar.Avramovic, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D60691
llvm-svn: 361845
2019-05-28 18:13:20 +02:00
|
|
|
}
|
|
|
|
|
[ARM] Fix bugs introduced by the fp64/d32 rework.
Change D60691 caused some knock-on failures that weren't caught by the
existing tests. Firstly, selecting a CPU that should have had a
restricted FPU (e.g. `-mcpu=cortex-m4`, which should have 16 d-regs
and no double precision) could give the unrestricted version, because
`ARM::getFPUFeatures` returned a list of features including subtracted
ones (here `-fp64`,`-d32`), but `ARMTargetInfo::initFeatureMap` threw
away all the ones that didn't start with `+`. Secondly, the
preprocessor macros didn't reliably match the actual compilation
settings: for example, `-mfpu=softvfp` could still set `__ARM_FP` as
if hardware FP was available, because the list of features on the cc1
command line would include things like `+vfp4`,`-vfp4d16` and clang
didn't realise that one of those cancelled out the other.
I've fixed both of these issues by rewriting `ARM::getFPUFeatures` so
that it returns a list that enables every FP-related feature
compatible with the selected FPU and disables every feature not
compatible, which is more verbose but means clang doesn't have to
understand the dependency relationships between the backend features.
Meanwhile, `ARMTargetInfo::handleTargetFeatures` is testing for all
the various forms of the FP feature names, so that it won't miss cases
where it should have set `HW_FP` to feed into feature test macros.
That in turn caused an ordering problem when handling `-mcpu=foo+bar`
together with `-mfpu=something_that_turns_off_bar`. To fix that, I've
arranged that the `+bar` suffixes on the end of `-mcpu` and `-march`
cause feature names to be put into a separate vector which is
concatenated after the output of `getFPUFeatures`.
Another side effect of all this is to fix a bug where `clang -target
armv8-eabi` by itself would fail to set `__ARM_FEATURE_FMA`, even
though `armv8` (aka Arm v8-A) implies FP-Armv8 which has FMA. That was
because `HW_FP` was being set to a value including only the `FPARMV8`
bit, but that feature test macro was testing only the `VFP4FPU` bit.
Now `HW_FP` ends up with all the bits set, so it gives the right
answer.
Changes to tests included in this patch:
* `arm-target-features.c`: I had to change basically all the expected
results. (The Cortex-M4 test in there should function as a
regression test for the accidental double-precision bug.)
* `arm-mfpu.c`, `armv8.1m.main.c`: switched to using `CHECK-DAG`
everywhere so that those tests are no longer sensitive to the order
of cc1 feature options on the command line.
* `arm-acle-6.5.c`: been updated to expect the right answer to that
FMA test.
* `Preprocessor/arm-target-features.c`: added a regression test for
the `mfpu=softvfp` issue.
Reviewers: SjoerdMeijer, dmgreen, ostannard, samparker, JamesNagurne
Reviewed By: ostannard
Subscribers: srhines, javed.absar, kristof.beyls, hiraditya, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62998
llvm-svn: 362791
2019-06-07 14:42:54 +02:00
|
|
|
static const struct NeonFeatureNameInfo {
|
|
|
|
const char *PlusName, *MinusName;
|
|
|
|
NeonSupportLevel MinSupportLevel;
|
|
|
|
} NeonFeatureInfoList[] = {
|
|
|
|
{"+neon", "-neon", NeonSupportLevel::Neon},
|
|
|
|
{"+crypto", "-crypto", NeonSupportLevel::Crypto},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto &Info: NeonFeatureInfoList) {
|
|
|
|
if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel)
|
|
|
|
Features.push_back(Info.PlusName);
|
|
|
|
else
|
|
|
|
Features.push_back(Info.MinusName);
|
2018-11-28 12:38:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Little/Big endian
|
|
|
|
ARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
|
|
|
|
if (Arch.startswith("armeb") || Arch.startswith("thumbeb") ||
|
|
|
|
Arch.startswith("aarch64_be"))
|
|
|
|
return EndianKind::BIG;
|
|
|
|
|
|
|
|
if (Arch.startswith("arm") || Arch.startswith("thumb")) {
|
|
|
|
if (Arch.endswith("eb"))
|
|
|
|
return EndianKind::BIG;
|
|
|
|
else
|
|
|
|
return EndianKind::LITTLE;
|
|
|
|
}
|
|
|
|
|
2019-05-14 13:25:44 +02:00
|
|
|
if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32"))
|
2018-11-28 12:38:10 +01:00
|
|
|
return EndianKind::LITTLE;
|
|
|
|
|
|
|
|
return EndianKind::INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ARM, Thumb, AArch64
|
|
|
|
ARM::ISAKind ARM::parseArchISA(StringRef Arch) {
|
|
|
|
return StringSwitch<ISAKind>(Arch)
|
|
|
|
.StartsWith("aarch64", ISAKind::AARCH64)
|
|
|
|
.StartsWith("arm64", ISAKind::AARCH64)
|
|
|
|
.StartsWith("thumb", ISAKind::THUMB)
|
|
|
|
.StartsWith("arm", ISAKind::ARM)
|
|
|
|
.Default(ISAKind::INVALID);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ARM::parseFPU(StringRef FPU) {
|
|
|
|
StringRef Syn = getFPUSynonym(FPU);
|
|
|
|
for (const auto F : FPUNames) {
|
|
|
|
if (Syn == F.getName())
|
|
|
|
return F.ID;
|
|
|
|
}
|
|
|
|
return FK_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) {
|
|
|
|
if (FPUKind >= FK_LAST)
|
|
|
|
return NeonSupportLevel::None;
|
|
|
|
return FPUNames[FPUKind].NeonSupport;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but
|
|
|
|
// (iwmmxt|xscale)(eb)? is also permitted. If the former, return
|
|
|
|
// "v.+", if the latter, return unmodified string, minus 'eb'.
|
|
|
|
// If invalid, return empty string.
|
|
|
|
StringRef ARM::getCanonicalArchName(StringRef Arch) {
|
|
|
|
size_t offset = StringRef::npos;
|
|
|
|
StringRef A = Arch;
|
|
|
|
StringRef Error = "";
|
|
|
|
|
|
|
|
// Begins with "arm" / "thumb", move past it.
|
2019-05-14 13:25:44 +02:00
|
|
|
if (A.startswith("arm64_32"))
|
|
|
|
offset = 8;
|
|
|
|
else if (A.startswith("arm64"))
|
2018-11-28 12:38:10 +01:00
|
|
|
offset = 5;
|
2019-05-14 13:25:44 +02:00
|
|
|
else if (A.startswith("aarch64_32"))
|
|
|
|
offset = 10;
|
2018-11-28 12:38:10 +01:00
|
|
|
else if (A.startswith("arm"))
|
|
|
|
offset = 3;
|
|
|
|
else if (A.startswith("thumb"))
|
|
|
|
offset = 5;
|
|
|
|
else if (A.startswith("aarch64")) {
|
|
|
|
offset = 7;
|
|
|
|
// AArch64 uses "_be", not "eb" suffix.
|
|
|
|
if (A.find("eb") != StringRef::npos)
|
|
|
|
return Error;
|
|
|
|
if (A.substr(offset, 3) == "_be")
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ex. "armebv7", move past the "eb".
|
|
|
|
if (offset != StringRef::npos && A.substr(offset, 2) == "eb")
|
|
|
|
offset += 2;
|
|
|
|
// Or, if it ends with eb ("armv7eb"), chop it off.
|
|
|
|
else if (A.endswith("eb"))
|
|
|
|
A = A.substr(0, A.size() - 2);
|
|
|
|
// Trim the head
|
|
|
|
if (offset != StringRef::npos)
|
|
|
|
A = A.substr(offset);
|
|
|
|
|
|
|
|
// Empty string means offset reached the end, which means it's valid.
|
|
|
|
if (A.empty())
|
|
|
|
return Arch;
|
|
|
|
|
|
|
|
// Only match non-marketing names
|
|
|
|
if (offset != StringRef::npos) {
|
|
|
|
// Must start with 'vN'.
|
|
|
|
if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1])))
|
|
|
|
return Error;
|
|
|
|
// Can't have an extra 'eb'.
|
|
|
|
if (A.find("eb") != StringRef::npos)
|
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arch will either be a 'v' name (v7a) or a marketing name (xscale).
|
|
|
|
return A;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getFPUSynonym(StringRef FPU) {
|
|
|
|
return StringSwitch<StringRef>(FPU)
|
|
|
|
.Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported
|
|
|
|
.Case("vfp2", "vfpv2")
|
|
|
|
.Case("vfp3", "vfpv3")
|
|
|
|
.Case("vfp4", "vfpv4")
|
|
|
|
.Case("vfp3-d16", "vfpv3-d16")
|
|
|
|
.Case("vfp4-d16", "vfpv4-d16")
|
|
|
|
.Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16")
|
|
|
|
.Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16")
|
|
|
|
.Case("fp5-sp-d16", "fpv5-sp-d16")
|
|
|
|
.Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16")
|
|
|
|
// FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3.
|
|
|
|
.Case("neon-vfpv3", "neon")
|
|
|
|
.Default(FPU);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getFPUName(unsigned FPUKind) {
|
|
|
|
if (FPUKind >= FK_LAST)
|
|
|
|
return StringRef();
|
|
|
|
return FPUNames[FPUKind].getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
ARM::FPUVersion ARM::getFPUVersion(unsigned FPUKind) {
|
|
|
|
if (FPUKind >= FK_LAST)
|
|
|
|
return FPUVersion::NONE;
|
|
|
|
return FPUNames[FPUKind].FPUVer;
|
|
|
|
}
|
|
|
|
|
|
|
|
ARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) {
|
|
|
|
if (FPUKind >= FK_LAST)
|
|
|
|
return FPURestriction::None;
|
|
|
|
return FPUNames[FPUKind].Restriction;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) {
|
|
|
|
if (CPU == "generic")
|
|
|
|
return ARM::ARCHNames[static_cast<unsigned>(AK)].DefaultFPU;
|
|
|
|
|
|
|
|
return StringSwitch<unsigned>(CPU)
|
|
|
|
#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
|
|
|
|
.Case(NAME, DEFAULT_FPU)
|
|
|
|
#include "llvm/Support/ARMTargetParser.def"
|
|
|
|
.Default(ARM::FK_INVALID);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
|
|
|
|
if (CPU == "generic")
|
|
|
|
return ARM::ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
|
|
|
|
|
|
|
|
return StringSwitch<unsigned>(CPU)
|
|
|
|
#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
|
|
|
|
.Case(NAME, \
|
|
|
|
ARCHNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions | \
|
|
|
|
DEFAULT_EXT)
|
|
|
|
#include "llvm/Support/ARMTargetParser.def"
|
|
|
|
.Default(ARM::AEK_INVALID);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARM::getHWDivFeatures(unsigned HWDivKind,
|
|
|
|
std::vector<StringRef> &Features) {
|
|
|
|
|
|
|
|
if (HWDivKind == AEK_INVALID)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (HWDivKind & AEK_HWDIVARM)
|
|
|
|
Features.push_back("+hwdiv-arm");
|
|
|
|
else
|
|
|
|
Features.push_back("-hwdiv-arm");
|
|
|
|
|
|
|
|
if (HWDivKind & AEK_HWDIVTHUMB)
|
|
|
|
Features.push_back("+hwdiv");
|
|
|
|
else
|
|
|
|
Features.push_back("-hwdiv");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARM::getExtensionFeatures(unsigned Extensions,
|
|
|
|
std::vector<StringRef> &Features) {
|
|
|
|
|
|
|
|
if (Extensions == AEK_INVALID)
|
|
|
|
return false;
|
|
|
|
|
2019-07-14 20:32:42 +02:00
|
|
|
for (const auto AE : ARCHExtNames) {
|
|
|
|
if ((Extensions & AE.ID) == AE.ID && AE.Feature)
|
|
|
|
Features.push_back(AE.Feature);
|
|
|
|
else if (AE.NegFeature)
|
|
|
|
Features.push_back(AE.NegFeature);
|
|
|
|
}
|
2018-11-28 12:38:10 +01:00
|
|
|
|
|
|
|
return getHWDivFeatures(Extensions, Features);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getArchName(ARM::ArchKind AK) {
|
|
|
|
return ARCHNames[static_cast<unsigned>(AK)].getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getCPUAttr(ARM::ArchKind AK) {
|
|
|
|
return ARCHNames[static_cast<unsigned>(AK)].getCPUAttr();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getSubArch(ARM::ArchKind AK) {
|
|
|
|
return ARCHNames[static_cast<unsigned>(AK)].getSubArch();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ARM::getArchAttr(ARM::ArchKind AK) {
|
|
|
|
return ARCHNames[static_cast<unsigned>(AK)].ArchAttr;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getArchExtName(unsigned ArchExtKind) {
|
|
|
|
for (const auto AE : ARCHExtNames) {
|
|
|
|
if (ArchExtKind == AE.ID)
|
|
|
|
return AE.getName();
|
|
|
|
}
|
|
|
|
return StringRef();
|
|
|
|
}
|
|
|
|
|
2019-06-05 15:11:51 +02:00
|
|
|
static bool stripNegationPrefix(StringRef &Name) {
|
|
|
|
if (Name.startswith("no")) {
|
|
|
|
Name = Name.substr(2);
|
|
|
|
return true;
|
2018-11-28 12:38:10 +01:00
|
|
|
}
|
2019-06-05 15:11:51 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getArchExtFeature(StringRef ArchExt) {
|
|
|
|
bool Negated = stripNegationPrefix(ArchExt);
|
2018-11-28 12:38:10 +01:00
|
|
|
for (const auto AE : ARCHExtNames) {
|
|
|
|
if (AE.Feature && ArchExt == AE.getName())
|
2019-06-05 15:11:51 +02:00
|
|
|
return StringRef(Negated ? AE.NegFeature : AE.Feature);
|
2018-11-28 12:38:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return StringRef();
|
|
|
|
}
|
|
|
|
|
2019-06-05 15:11:51 +02:00
|
|
|
static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) {
|
|
|
|
const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];
|
|
|
|
|
|
|
|
// If the input FPU already supports double-precision, then there
|
|
|
|
// isn't any different FPU we can return here.
|
|
|
|
//
|
|
|
|
// The current available FPURestriction values are None (no
|
|
|
|
// restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs
|
|
|
|
// and single precision only); there's no value representing
|
|
|
|
// SP restriction without D16. So this test just means 'is it
|
|
|
|
// SP only?'.
|
|
|
|
if (InputFPU.Restriction != ARM::FPURestriction::SP_D16)
|
|
|
|
return ARM::FK_INVALID;
|
|
|
|
|
|
|
|
// Otherwise, look for an FPU entry with all the same fields, except
|
|
|
|
// that SP_D16 has been replaced with just D16, representing adding
|
|
|
|
// double precision and not changing anything else.
|
|
|
|
for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
|
|
|
|
if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
|
|
|
|
CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
|
|
|
|
CandidateFPU.Restriction == ARM::FPURestriction::D16) {
|
|
|
|
return CandidateFPU.ID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nothing found
|
|
|
|
return ARM::FK_INVALID;
|
|
|
|
}
|
|
|
|
|
2019-07-14 22:31:15 +02:00
|
|
|
static unsigned getAEKID(StringRef ArchExtName) {
|
|
|
|
for (const auto AE : ARM::ARCHExtNames)
|
|
|
|
if (AE.getName() == ArchExtName)
|
|
|
|
return AE.ID;
|
|
|
|
return ARM::AEK_INVALID;
|
|
|
|
}
|
|
|
|
|
2019-06-05 15:11:51 +02:00
|
|
|
bool ARM::appendArchExtFeatures(
|
|
|
|
StringRef CPU, ARM::ArchKind AK, StringRef ArchExt,
|
|
|
|
std::vector<StringRef> &Features) {
|
|
|
|
|
2019-07-14 22:31:15 +02:00
|
|
|
size_t StartingNumFeatures = Features.size();
|
2019-06-05 15:11:51 +02:00
|
|
|
const bool Negated = stripNegationPrefix(ArchExt);
|
2019-07-14 22:31:15 +02:00
|
|
|
unsigned ID = getAEKID(ArchExt);
|
|
|
|
|
|
|
|
if (ID == AEK_INVALID)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (const auto AE : ARCHExtNames) {
|
|
|
|
if (Negated && (AE.ID & ID) == ID && AE.NegFeature)
|
|
|
|
Features.push_back(AE.NegFeature);
|
|
|
|
else if (AE.ID == ID && AE.Feature)
|
|
|
|
Features.push_back(AE.Feature);
|
|
|
|
}
|
2019-06-05 15:11:51 +02:00
|
|
|
|
|
|
|
if (CPU == "")
|
|
|
|
CPU = "generic";
|
|
|
|
|
|
|
|
if (ArchExt == "fp" || ArchExt == "fp.dp") {
|
|
|
|
unsigned FPUKind;
|
|
|
|
if (ArchExt == "fp.dp") {
|
|
|
|
if (Negated) {
|
|
|
|
Features.push_back("-fp64");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK));
|
|
|
|
} else if (Negated) {
|
|
|
|
FPUKind = ARM::FK_NONE;
|
|
|
|
} else {
|
|
|
|
FPUKind = getDefaultFPU(CPU, AK);
|
|
|
|
}
|
|
|
|
return ARM::getFPUFeatures(FPUKind, Features);
|
|
|
|
}
|
2019-07-14 22:31:15 +02:00
|
|
|
return StartingNumFeatures != Features.size();
|
2019-06-05 15:11:51 +02:00
|
|
|
}
|
|
|
|
|
2018-11-28 12:38:10 +01:00
|
|
|
StringRef ARM::getHWDivName(unsigned HWDivKind) {
|
|
|
|
for (const auto D : HWDivNames) {
|
|
|
|
if (HWDivKind == D.ID)
|
|
|
|
return D.getName();
|
|
|
|
}
|
|
|
|
return StringRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::getDefaultCPU(StringRef Arch) {
|
|
|
|
ArchKind AK = parseArch(Arch);
|
|
|
|
if (AK == ArchKind::INVALID)
|
|
|
|
return StringRef();
|
|
|
|
|
|
|
|
// Look for multiple AKs to find the default for pair AK+Name.
|
|
|
|
for (const auto CPU : CPUNames) {
|
|
|
|
if (CPU.ArchID == AK && CPU.Default)
|
|
|
|
return CPU.getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we can't find a default then target the architecture instead
|
|
|
|
return "generic";
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ARM::parseHWDiv(StringRef HWDiv) {
|
|
|
|
StringRef Syn = getHWDivSynonym(HWDiv);
|
|
|
|
for (const auto D : HWDivNames) {
|
|
|
|
if (Syn == D.getName())
|
|
|
|
return D.ID;
|
|
|
|
}
|
|
|
|
return AEK_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ARM::parseArchExt(StringRef ArchExt) {
|
|
|
|
for (const auto A : ARCHExtNames) {
|
|
|
|
if (ArchExt == A.getName())
|
|
|
|
return A.ID;
|
|
|
|
}
|
|
|
|
return AEK_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
ARM::ArchKind ARM::parseCPUArch(StringRef CPU) {
|
|
|
|
for (const auto C : CPUNames) {
|
|
|
|
if (CPU == C.getName())
|
|
|
|
return C.ArchID;
|
|
|
|
}
|
|
|
|
return ArchKind::INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
|
|
|
|
for (const CpuNames<ArchKind> &Arch : CPUNames) {
|
|
|
|
if (Arch.ArchID != ArchKind::INVALID)
|
|
|
|
Values.push_back(Arch.getName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) {
|
|
|
|
StringRef ArchName =
|
|
|
|
CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU));
|
|
|
|
|
|
|
|
if (TT.isOSBinFormatMachO()) {
|
|
|
|
if (TT.getEnvironment() == Triple::EABI ||
|
|
|
|
TT.getOS() == Triple::UnknownOS ||
|
|
|
|
parseArchProfile(ArchName) == ProfileKind::M)
|
|
|
|
return "aapcs";
|
|
|
|
if (TT.isWatchABI())
|
|
|
|
return "aapcs16";
|
|
|
|
return "apcs-gnu";
|
|
|
|
} else if (TT.isOSWindows())
|
|
|
|
// FIXME: this is invalid for WindowsCE.
|
|
|
|
return "aapcs";
|
|
|
|
|
|
|
|
// Select the default based on the platform.
|
|
|
|
switch (TT.getEnvironment()) {
|
|
|
|
case Triple::Android:
|
|
|
|
case Triple::GNUEABI:
|
|
|
|
case Triple::GNUEABIHF:
|
|
|
|
case Triple::MuslEABI:
|
|
|
|
case Triple::MuslEABIHF:
|
|
|
|
return "aapcs-linux";
|
|
|
|
case Triple::EABIHF:
|
|
|
|
case Triple::EABI:
|
|
|
|
return "aapcs";
|
|
|
|
default:
|
|
|
|
if (TT.isOSNetBSD())
|
|
|
|
return "apcs-gnu";
|
|
|
|
if (TT.isOSOpenBSD())
|
|
|
|
return "aapcs-linux";
|
|
|
|
return "aapcs";
|
|
|
|
}
|
|
|
|
}
|