| //===--- M68k.cpp - Implement M68k targets 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 M68k TargetInfo objects. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "M68k.h" |
| #include "clang/Basic/Builtins.h" |
| #include "clang/Basic/Diagnostic.h" |
| #include "clang/Basic/TargetBuiltins.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Support/TargetParser.h" |
| #include <cstdint> |
| #include <cstring> |
| #include <limits> |
| |
| namespace clang { |
| namespace targets { |
| |
| M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, |
| const TargetOptions &) |
| : TargetInfo(Triple) { |
| |
| std::string Layout = ""; |
| |
| // M68k is Big Endian |
| Layout += "E"; |
| |
| // FIXME how to wire it with the used object format? |
| Layout += "-m:e"; |
| |
| // M68k pointers are always 32 bit wide even for 16-bit CPUs |
| Layout += "-p:32:16:32"; |
| |
| // M68k integer data types |
| Layout += "-i8:8:8-i16:16:16-i32:16:32"; |
| |
| // FIXME no floats at the moment |
| |
| // The registers can hold 8, 16, 32 bits |
| Layout += "-n8:16:32"; |
| |
| // 16 bit alignment for both stack and aggregate |
| // in order to conform to ABI used by GCC |
| Layout += "-a:0:16-S16"; |
| |
| resetDataLayout(Layout); |
| |
| SizeType = UnsignedInt; |
| PtrDiffType = SignedInt; |
| IntPtrType = SignedInt; |
| } |
| |
| bool M68kTargetInfo::setCPU(const std::string &Name) { |
| StringRef N = Name; |
| CPU = llvm::StringSwitch<CPUKind>(N) |
| .Case("generic", CK_68000) |
| .Case("M68000", CK_68000) |
| .Case("M68010", CK_68010) |
| .Case("M68020", CK_68020) |
| .Case("M68030", CK_68030) |
| .Case("M68040", CK_68040) |
| .Case("M68060", CK_68060) |
| .Default(CK_Unknown); |
| return CPU != CK_Unknown; |
| } |
| |
| void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, |
| MacroBuilder &Builder) const { |
| using llvm::Twine; |
| |
| Builder.defineMacro("__m68k__"); |
| |
| Builder.defineMacro("mc68000"); |
| Builder.defineMacro("__mc68000"); |
| Builder.defineMacro("__mc68000__"); |
| |
| // For sub-architecture |
| switch (CPU) { |
| case CK_68010: |
| Builder.defineMacro("mc68010"); |
| Builder.defineMacro("__mc68010"); |
| Builder.defineMacro("__mc68010__"); |
| break; |
| case CK_68020: |
| Builder.defineMacro("mc68020"); |
| Builder.defineMacro("__mc68020"); |
| Builder.defineMacro("__mc68020__"); |
| break; |
| case CK_68030: |
| Builder.defineMacro("mc68030"); |
| Builder.defineMacro("__mc68030"); |
| Builder.defineMacro("__mc68030__"); |
| break; |
| case CK_68040: |
| Builder.defineMacro("mc68040"); |
| Builder.defineMacro("__mc68040"); |
| Builder.defineMacro("__mc68040__"); |
| break; |
| case CK_68060: |
| Builder.defineMacro("mc68060"); |
| Builder.defineMacro("__mc68060"); |
| Builder.defineMacro("__mc68060__"); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const { |
| // FIXME: Implement. |
| return None; |
| } |
| |
| bool M68kTargetInfo::hasFeature(StringRef Feature) const { |
| // FIXME elaborate moar |
| return Feature == "M68000"; |
| } |
| |
| const char *const M68kTargetInfo::GCCRegNames[] = { |
| "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", |
| "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", |
| "pc"}; |
| |
| ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const { |
| return llvm::makeArrayRef(GCCRegNames); |
| } |
| |
| ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const { |
| // No aliases. |
| return None; |
| } |
| |
| bool M68kTargetInfo::validateAsmConstraint( |
| const char *&Name, TargetInfo::ConstraintInfo &info) const { |
| switch (*Name) { |
| case 'a': // address register |
| case 'd': // data register |
| info.setAllowsRegister(); |
| return true; |
| case 'I': // constant integer in the range [1,8] |
| info.setRequiresImmediate(1, 8); |
| return true; |
| case 'J': // constant signed 16-bit integer |
| info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), |
| std::numeric_limits<int16_t>::max()); |
| return true; |
| case 'K': // constant that is NOT in the range of [-0x80, 0x80) |
| info.setRequiresImmediate(); |
| return true; |
| case 'L': // constant integer in the range [-8,-1] |
| info.setRequiresImmediate(-8, -1); |
| return true; |
| case 'M': // constant that is NOT in the range of [-0x100, 0x100] |
| info.setRequiresImmediate(); |
| return true; |
| case 'N': // constant integer in the range [24,31] |
| info.setRequiresImmediate(24, 31); |
| return true; |
| case 'O': // constant integer 16 |
| info.setRequiresImmediate(16); |
| return true; |
| case 'P': // constant integer in the range [8,15] |
| info.setRequiresImmediate(8, 15); |
| return true; |
| case 'C': |
| ++Name; |
| switch (*Name) { |
| case '0': // constant integer 0 |
| info.setRequiresImmediate(0); |
| return true; |
| case 'i': // constant integer |
| case 'j': // integer constant that doesn't fit in 16 bits |
| info.setRequiresImmediate(); |
| return true; |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| llvm::Optional<std::string> |
| M68kTargetInfo::handleAsmEscapedChar(char EscChar) const { |
| char C; |
| switch (EscChar) { |
| case '.': |
| case '#': |
| C = EscChar; |
| break; |
| case '/': |
| C = '%'; |
| break; |
| case '$': |
| C = 's'; |
| break; |
| case '&': |
| C = 'd'; |
| break; |
| default: |
| return llvm::None; |
| } |
| |
| return std::string(1, C); |
| } |
| |
| std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const { |
| if (*Constraint == 'C') |
| // Two-character constraint; add "^" hint for later parsing |
| return std::string("^") + std::string(Constraint++, 2); |
| |
| return std::string(1, *Constraint); |
| } |
| |
| const char *M68kTargetInfo::getClobbers() const { |
| // FIXME: Is this really right? |
| return ""; |
| } |
| |
| TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const { |
| return TargetInfo::VoidPtrBuiltinVaList; |
| } |
| |
| } // namespace targets |
| } // namespace clang |