#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/TargetParser/TargetParser.h"
#include <cstdint>
#include <cstring>
#include <limits>
#include <optional>
namespace clang {
namespace targets {
M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple,
const TargetOptions &Opts)
: TargetInfo(Triple), TargetOpts(Opts) {
std::string Layout;
Layout += "E";
Layout += "-m:e";
Layout += "-p:32:16:32";
Layout += "-i8:8:8-i16:16:16-i32:16:32";
Layout += "-n8:16:32";
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__");
DefineStd(Builder, "mc68000", Opts);
switch (CPU) {
case CK_68010:
DefineStd(Builder, "mc68010", Opts);
break;
case CK_68020:
DefineStd(Builder, "mc68020", Opts);
break;
case CK_68030:
DefineStd(Builder, "mc68030", Opts);
break;
case CK_68040:
DefineStd(Builder, "mc68040", Opts);
break;
case CK_68060:
DefineStd(Builder, "mc68060", Opts);
break;
default:
break;
}
if (CPU >= CK_68020) {
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 (TargetOpts.FeatureMap.lookup("isa-68881") ||
TargetOpts.FeatureMap.lookup("isa-68882"))
Builder.defineMacro("__HAVE_68881__");
}
ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const {
return std::nullopt;
}
bool M68kTargetInfo::hasFeature(StringRef Feature) const {
return Feature == "M68000";
}
const char *const M68kTargetInfo::GCCRegNames[] = {
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
"pc"};
ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const {
return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias M68kTargetInfo::GCCRegAliases[] = {
{{"bp"}, "a5"},
{{"fp"}, "a6"},
{{"usp", "ssp", "isp", "a7"}, "sp"},
};
ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const {
return llvm::ArrayRef(GCCRegAliases);
}
bool M68kTargetInfo::validateAsmConstraint(
const char *&Name, TargetInfo::ConstraintInfo &info) const {
switch (*Name) {
case 'a':
case 'd':
info.setAllowsRegister();
return true;
case 'I':
info.setRequiresImmediate(1, 8);
return true;
case 'J':
info.setRequiresImmediate(std::numeric_limits<int16_t>::min(),
std::numeric_limits<int16_t>::max());
return true;
case 'K':
info.setRequiresImmediate();
return true;
case 'L':
info.setRequiresImmediate(-8, -1);
return true;
case 'M':
info.setRequiresImmediate();
return true;
case 'N':
info.setRequiresImmediate(24, 31);
return true;
case 'O':
info.setRequiresImmediate(16);
return true;
case 'P':
info.setRequiresImmediate(8, 15);
return true;
case 'C':
++Name;
switch (*Name) {
case '0':
info.setRequiresImmediate(0);
return true;
case 'i':
case 'j':
info.setRequiresImmediate();
return true;
default:
break;
}
break;
case 'Q':
case 'U':
info.setAllowsMemory();
return true;
default:
break;
}
return false;
}
std::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 std::nullopt;
}
return std::string(1, C);
}
std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const {
if (*Constraint == 'C')
return std::string("^") + std::string(Constraint++, 2);
return std::string(1, *Constraint);
}
std::string_view M68kTargetInfo::getClobbers() const {
return "";
}
TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const {
return TargetInfo::VoidPtrBuiltinVaList;
}
TargetInfo::CallingConvCheckResult
M68kTargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
case CC_C:
case CC_M68kRTD:
return CCCR_OK;
default:
return TargetInfo::checkCallingConvention(CC);
}
}
}
}