diff options
Diffstat (limited to 'clang/lib/Basic/Targets/LoongArch.cpp')
-rw-r--r-- | clang/lib/Basic/Targets/LoongArch.cpp | 217 |
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; +} |