aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Basic/Targets/LoongArch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Basic/Targets/LoongArch.cpp')
-rw-r--r--clang/lib/Basic/Targets/LoongArch.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
new file mode 100644
index 000000000000..2079c89e3e15
--- /dev/null
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -0,0 +1,217 @@
+//===--- LoongArch.cpp - Implement LoongArch target feature support -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements LoongArch TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LoongArch.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const {
+ static const char *const GCCRegNames[] = {
+ // General purpose registers.
+ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9",
+ "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18",
+ "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27",
+ "$r28", "$r29", "$r30", "$r31",
+ // Floating point registers.
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9",
+ "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18",
+ "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27",
+ "$f28", "$f29", "$f30", "$f31"};
+ return llvm::ArrayRef(GCCRegNames);
+}
+
+ArrayRef<TargetInfo::GCCRegAlias>
+LoongArchTargetInfo::getGCCRegAliases() const {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
+ {{"$zero"}, "$r0"}, {{"$ra"}, "$r1"}, {{"$tp"}, "$r2"},
+ {{"$sp"}, "$r3"}, {{"$a0"}, "$r4"}, {{"$a1"}, "$r5"},
+ {{"$a2"}, "$r6"}, {{"$a3"}, "$r7"}, {{"$a4"}, "$r8"},
+ {{"$a5"}, "$r9"}, {{"$a6"}, "$r10"}, {{"$a7"}, "$r11"},
+ {{"$t0"}, "$r12"}, {{"$t1"}, "$r13"}, {{"$t2"}, "$r14"},
+ {{"$t3"}, "$r15"}, {{"$t4"}, "$r16"}, {{"$t5"}, "$r17"},
+ {{"$t6"}, "$r18"}, {{"$t7"}, "$r19"}, {{"$t8"}, "$r20"},
+ {{"$fp", "$s9"}, "$r22"}, {{"$s0"}, "$r23"}, {{"$s1"}, "$r24"},
+ {{"$s2"}, "$r25"}, {{"$s3"}, "$r26"}, {{"$s4"}, "$r27"},
+ {{"$s5"}, "$r28"}, {{"$s6"}, "$r29"}, {{"$s7"}, "$r30"},
+ {{"$s8"}, "$r31"}, {{"$fa0"}, "$f0"}, {{"$fa1"}, "$f1"},
+ {{"$fa2"}, "$f2"}, {{"$fa3"}, "$f3"}, {{"$fa4"}, "$f4"},
+ {{"$fa5"}, "$f5"}, {{"$fa6"}, "$f6"}, {{"$fa7"}, "$f7"},
+ {{"$ft0"}, "$f8"}, {{"$ft1"}, "$f9"}, {{"$ft2"}, "$f10"},
+ {{"$ft3"}, "$f11"}, {{"$ft4"}, "$f12"}, {{"$ft5"}, "$f13"},
+ {{"$ft6"}, "$f14"}, {{"$ft7"}, "$f15"}, {{"$ft8"}, "$f16"},
+ {{"$ft9"}, "$f17"}, {{"$ft10"}, "$f18"}, {{"$ft11"}, "$f19"},
+ {{"$ft12"}, "$f20"}, {{"$ft13"}, "$f21"}, {{"$ft14"}, "$f22"},
+ {{"$ft15"}, "$f23"}, {{"$fs0"}, "$f24"}, {{"$fs1"}, "$f25"},
+ {{"$fs2"}, "$f26"}, {{"$fs3"}, "$f27"}, {{"$fs4"}, "$f28"},
+ {{"$fs5"}, "$f29"}, {{"$fs6"}, "$f30"}, {{"$fs7"}, "$f31"},
+ };
+ return llvm::ArrayRef(GCCRegAliases);
+}
+
+bool LoongArchTargetInfo::validateAsmConstraint(
+ const char *&Name, TargetInfo::ConstraintInfo &Info) const {
+ // See the GCC definitions here:
+ // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html
+ // Note that the 'm' constraint is handled in TargetInfo.
+ switch (*Name) {
+ default:
+ return false;
+ case 'f':
+ // A floating-point register (if available).
+ Info.setAllowsRegister();
+ return true;
+ case 'k':
+ // A memory operand whose address is formed by a base register and
+ // (optionally scaled) index register.
+ Info.setAllowsMemory();
+ return true;
+ case 'l':
+ // A signed 16-bit constant.
+ Info.setRequiresImmediate(-32768, 32767);
+ return true;
+ case 'I':
+ // A signed 12-bit constant (for arithmetic instructions).
+ Info.setRequiresImmediate(-2048, 2047);
+ return true;
+ case 'J':
+ // Integer zero.
+ Info.setRequiresImmediate(0);
+ return true;
+ case 'K':
+ // An unsigned 12-bit constant (for logic instructions).
+ Info.setRequiresImmediate(0, 4095);
+ return true;
+ case 'Z':
+ // ZB: An address that is held in a general-purpose register. The offset is
+ // zero.
+ // ZC: A memory operand whose address is formed by a base register
+ // and offset that is suitable for use in instructions with the same
+ // addressing mode as ll.w and sc.w.
+ if (Name[1] == 'C' || Name[1] == 'B') {
+ Info.setAllowsMemory();
+ ++Name; // Skip over 'Z'.
+ return true;
+ }
+ return false;
+ }
+}
+
+std::string
+LoongArchTargetInfo::convertConstraint(const char *&Constraint) const {
+ std::string R;
+ switch (*Constraint) {
+ case 'Z':
+ // "ZC"/"ZB" are two-character constraints; add "^" hint for later
+ // parsing.
+ R = "^" + std::string(Constraint, 2);
+ ++Constraint;
+ break;
+ default:
+ R = TargetInfo::convertConstraint(Constraint);
+ break;
+ }
+ return R;
+}
+
+void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__loongarch__");
+ unsigned GRLen = getRegisterWidth();
+ Builder.defineMacro("__loongarch_grlen", Twine(GRLen));
+ if (GRLen == 64)
+ Builder.defineMacro("__loongarch64");
+
+ if (HasFeatureD)
+ Builder.defineMacro("__loongarch_frlen", "64");
+ else if (HasFeatureF)
+ Builder.defineMacro("__loongarch_frlen", "32");
+ else
+ Builder.defineMacro("__loongarch_frlen", "0");
+
+ // TODO: define __loongarch_arch and __loongarch_tune.
+
+ StringRef ABI = getABI();
+ if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
+ Builder.defineMacro("__loongarch_lp64");
+
+ if (ABI == "lp64d" || ABI == "ilp32d") {
+ Builder.defineMacro("__loongarch_hard_float");
+ Builder.defineMacro("__loongarch_double_float");
+ } else if (ABI == "lp64f" || ABI == "ilp32f") {
+ Builder.defineMacro("__loongarch_hard_float");
+ Builder.defineMacro("__loongarch_single_float");
+ } else if (ABI == "lp64s" || ABI == "ilp32s") {
+ Builder.defineMacro("__loongarch_soft_float");
+ }
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ if (GRLen == 64)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+}
+
+static constexpr Builtin::Info BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#include "clang/Basic/BuiltinsLoongArch.def"
+};
+
+bool LoongArchTargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ if (getTriple().getArch() == llvm::Triple::loongarch64)
+ Features["64bit"] = true;
+ if (getTriple().getArch() == llvm::Triple::loongarch32)
+ Features["32bit"] = true;
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+}
+
+/// Return true if has this feature.
+bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {
+ bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;
+ // TODO: Handle more features.
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("loongarch32", !Is64Bit)
+ .Case("loongarch64", Is64Bit)
+ .Case("32bit", !Is64Bit)
+ .Case("64bit", Is64Bit)
+ .Default(false);
+}
+
+ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const {
+ return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+bool LoongArchTargetInfo::handleTargetFeatures(
+ std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
+ for (const auto &Feature : Features) {
+ if (Feature == "+d" || Feature == "+f") {
+ // "d" implies "f".
+ HasFeatureF = true;
+ if (Feature == "+d") {
+ HasFeatureD = true;
+ }
+ }
+ }
+ return true;
+}