1fe6060f1SDimitry Andric //===--- M68k.cpp - Implement M68k targets feature support-------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file implements M68k TargetInfo objects. 10fe6060f1SDimitry Andric // 11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include "M68k.h" 14fe6060f1SDimitry Andric #include "clang/Basic/Builtins.h" 15fe6060f1SDimitry Andric #include "clang/Basic/Diagnostic.h" 16fe6060f1SDimitry Andric #include "clang/Basic/TargetBuiltins.h" 17fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h" 18fe6060f1SDimitry Andric #include "llvm/ADT/StringRef.h" 19fe6060f1SDimitry Andric #include "llvm/ADT/StringSwitch.h" 2006c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.h" 21fe6060f1SDimitry Andric #include <cstdint> 22fe6060f1SDimitry Andric #include <cstring> 23fe6060f1SDimitry Andric #include <limits> 24bdd1243dSDimitry Andric #include <optional> 25fe6060f1SDimitry Andric 26fe6060f1SDimitry Andric namespace clang { 27fe6060f1SDimitry Andric namespace targets { 28fe6060f1SDimitry Andric 29fe6060f1SDimitry Andric M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, 3006c3fb27SDimitry Andric const TargetOptions &Opts) 3106c3fb27SDimitry Andric : TargetInfo(Triple), TargetOpts(Opts) { 32fe6060f1SDimitry Andric 3304eeddc0SDimitry Andric std::string Layout; 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric // M68k is Big Endian 36fe6060f1SDimitry Andric Layout += "E"; 37fe6060f1SDimitry Andric 38fe6060f1SDimitry Andric // FIXME how to wire it with the used object format? 39fe6060f1SDimitry Andric Layout += "-m:e"; 40fe6060f1SDimitry Andric 4169ade1e0SDimitry Andric // M68k pointers are always 32 bit wide even for 16-bit CPUs 4269ade1e0SDimitry Andric Layout += "-p:32:16:32"; 43fe6060f1SDimitry Andric 44fe6060f1SDimitry Andric // M68k integer data types 45fe6060f1SDimitry Andric Layout += "-i8:8:8-i16:16:16-i32:16:32"; 46fe6060f1SDimitry Andric 47fe6060f1SDimitry Andric // FIXME no floats at the moment 48fe6060f1SDimitry Andric 49fe6060f1SDimitry Andric // The registers can hold 8, 16, 32 bits 50fe6060f1SDimitry Andric Layout += "-n8:16:32"; 51fe6060f1SDimitry Andric 52fe6060f1SDimitry Andric // 16 bit alignment for both stack and aggregate 53fe6060f1SDimitry Andric // in order to conform to ABI used by GCC 54fe6060f1SDimitry Andric Layout += "-a:0:16-S16"; 55fe6060f1SDimitry Andric 56fe6060f1SDimitry Andric resetDataLayout(Layout); 57fe6060f1SDimitry Andric 58fe6060f1SDimitry Andric SizeType = UnsignedInt; 59fe6060f1SDimitry Andric PtrDiffType = SignedInt; 60fe6060f1SDimitry Andric IntPtrType = SignedInt; 61fe6060f1SDimitry Andric } 62fe6060f1SDimitry Andric 63fe6060f1SDimitry Andric bool M68kTargetInfo::setCPU(const std::string &Name) { 64fe6060f1SDimitry Andric StringRef N = Name; 65fe6060f1SDimitry Andric CPU = llvm::StringSwitch<CPUKind>(N) 66fe6060f1SDimitry Andric .Case("generic", CK_68000) 67fe6060f1SDimitry Andric .Case("M68000", CK_68000) 68fe6060f1SDimitry Andric .Case("M68010", CK_68010) 69fe6060f1SDimitry Andric .Case("M68020", CK_68020) 70fe6060f1SDimitry Andric .Case("M68030", CK_68030) 71fe6060f1SDimitry Andric .Case("M68040", CK_68040) 72fe6060f1SDimitry Andric .Case("M68060", CK_68060) 73fe6060f1SDimitry Andric .Default(CK_Unknown); 74fe6060f1SDimitry Andric return CPU != CK_Unknown; 75fe6060f1SDimitry Andric } 76fe6060f1SDimitry Andric 77fe6060f1SDimitry Andric void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, 78fe6060f1SDimitry Andric MacroBuilder &Builder) const { 79fe6060f1SDimitry Andric using llvm::Twine; 80fe6060f1SDimitry Andric 81fe6060f1SDimitry Andric Builder.defineMacro("__m68k__"); 82fe6060f1SDimitry Andric 835f757f3fSDimitry Andric DefineStd(Builder, "mc68000", Opts); 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric // For sub-architecture 86fe6060f1SDimitry Andric switch (CPU) { 87fe6060f1SDimitry Andric case CK_68010: 885f757f3fSDimitry Andric DefineStd(Builder, "mc68010", Opts); 89fe6060f1SDimitry Andric break; 90fe6060f1SDimitry Andric case CK_68020: 915f757f3fSDimitry Andric DefineStd(Builder, "mc68020", Opts); 92fe6060f1SDimitry Andric break; 93fe6060f1SDimitry Andric case CK_68030: 945f757f3fSDimitry Andric DefineStd(Builder, "mc68030", Opts); 95fe6060f1SDimitry Andric break; 96fe6060f1SDimitry Andric case CK_68040: 975f757f3fSDimitry Andric DefineStd(Builder, "mc68040", Opts); 98fe6060f1SDimitry Andric break; 99fe6060f1SDimitry Andric case CK_68060: 1005f757f3fSDimitry Andric DefineStd(Builder, "mc68060", Opts); 101fe6060f1SDimitry Andric break; 102fe6060f1SDimitry Andric default: 103fe6060f1SDimitry Andric break; 104fe6060f1SDimitry Andric } 105bdd1243dSDimitry Andric 106bdd1243dSDimitry Andric if (CPU >= CK_68020) { 107bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 108bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 109bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 110bdd1243dSDimitry Andric } 11106c3fb27SDimitry Andric 11206c3fb27SDimitry Andric // Floating point 11306c3fb27SDimitry Andric if (TargetOpts.FeatureMap.lookup("isa-68881") || 11406c3fb27SDimitry Andric TargetOpts.FeatureMap.lookup("isa-68882")) 11506c3fb27SDimitry Andric Builder.defineMacro("__HAVE_68881__"); 116fe6060f1SDimitry Andric } 117fe6060f1SDimitry Andric 118fe6060f1SDimitry Andric ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const { 119fe6060f1SDimitry Andric // FIXME: Implement. 120bdd1243dSDimitry Andric return std::nullopt; 121fe6060f1SDimitry Andric } 122fe6060f1SDimitry Andric 123fe6060f1SDimitry Andric bool M68kTargetInfo::hasFeature(StringRef Feature) const { 124fe6060f1SDimitry Andric // FIXME elaborate moar 125fe6060f1SDimitry Andric return Feature == "M68000"; 126fe6060f1SDimitry Andric } 127fe6060f1SDimitry Andric 128fe6060f1SDimitry Andric const char *const M68kTargetInfo::GCCRegNames[] = { 129fe6060f1SDimitry Andric "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 130*0fca6ea1SDimitry Andric "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", 131fe6060f1SDimitry Andric "pc"}; 132fe6060f1SDimitry Andric 133fe6060f1SDimitry Andric ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const { 134bdd1243dSDimitry Andric return llvm::ArrayRef(GCCRegNames); 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric 137*0fca6ea1SDimitry Andric const TargetInfo::GCCRegAlias M68kTargetInfo::GCCRegAliases[] = { 138*0fca6ea1SDimitry Andric {{"bp"}, "a5"}, 139*0fca6ea1SDimitry Andric {{"fp"}, "a6"}, 140*0fca6ea1SDimitry Andric {{"usp", "ssp", "isp", "a7"}, "sp"}, 141*0fca6ea1SDimitry Andric }; 142*0fca6ea1SDimitry Andric 143fe6060f1SDimitry Andric ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const { 144*0fca6ea1SDimitry Andric return llvm::ArrayRef(GCCRegAliases); 145fe6060f1SDimitry Andric } 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric bool M68kTargetInfo::validateAsmConstraint( 148fe6060f1SDimitry Andric const char *&Name, TargetInfo::ConstraintInfo &info) const { 149fe6060f1SDimitry Andric switch (*Name) { 150fe6060f1SDimitry Andric case 'a': // address register 151fe6060f1SDimitry Andric case 'd': // data register 152fe6060f1SDimitry Andric info.setAllowsRegister(); 153fe6060f1SDimitry Andric return true; 154fe6060f1SDimitry Andric case 'I': // constant integer in the range [1,8] 155fe6060f1SDimitry Andric info.setRequiresImmediate(1, 8); 156fe6060f1SDimitry Andric return true; 157fe6060f1SDimitry Andric case 'J': // constant signed 16-bit integer 158fe6060f1SDimitry Andric info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), 159fe6060f1SDimitry Andric std::numeric_limits<int16_t>::max()); 160fe6060f1SDimitry Andric return true; 161fe6060f1SDimitry Andric case 'K': // constant that is NOT in the range of [-0x80, 0x80) 162fe6060f1SDimitry Andric info.setRequiresImmediate(); 163fe6060f1SDimitry Andric return true; 164fe6060f1SDimitry Andric case 'L': // constant integer in the range [-8,-1] 165fe6060f1SDimitry Andric info.setRequiresImmediate(-8, -1); 166fe6060f1SDimitry Andric return true; 167fe6060f1SDimitry Andric case 'M': // constant that is NOT in the range of [-0x100, 0x100] 168fe6060f1SDimitry Andric info.setRequiresImmediate(); 169fe6060f1SDimitry Andric return true; 170fe6060f1SDimitry Andric case 'N': // constant integer in the range [24,31] 171fe6060f1SDimitry Andric info.setRequiresImmediate(24, 31); 172fe6060f1SDimitry Andric return true; 173fe6060f1SDimitry Andric case 'O': // constant integer 16 174fe6060f1SDimitry Andric info.setRequiresImmediate(16); 175fe6060f1SDimitry Andric return true; 176fe6060f1SDimitry Andric case 'P': // constant integer in the range [8,15] 177fe6060f1SDimitry Andric info.setRequiresImmediate(8, 15); 178fe6060f1SDimitry Andric return true; 179fe6060f1SDimitry Andric case 'C': 180fe6060f1SDimitry Andric ++Name; 181fe6060f1SDimitry Andric switch (*Name) { 182fe6060f1SDimitry Andric case '0': // constant integer 0 183fe6060f1SDimitry Andric info.setRequiresImmediate(0); 184fe6060f1SDimitry Andric return true; 185fe6060f1SDimitry Andric case 'i': // constant integer 186fe6060f1SDimitry Andric case 'j': // integer constant that doesn't fit in 16 bits 187fe6060f1SDimitry Andric info.setRequiresImmediate(); 188fe6060f1SDimitry Andric return true; 189fe6060f1SDimitry Andric default: 190fe6060f1SDimitry Andric break; 191fe6060f1SDimitry Andric } 192fe6060f1SDimitry Andric break; 19306c3fb27SDimitry Andric case 'Q': // address register indirect addressing 19406c3fb27SDimitry Andric case 'U': // address register indirect w/ constant offset addressing 19506c3fb27SDimitry Andric // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when 19606c3fb27SDimitry Andric // '-mpcrel' flag is properly handled by the driver. 19706c3fb27SDimitry Andric info.setAllowsMemory(); 19806c3fb27SDimitry Andric return true; 199fe6060f1SDimitry Andric default: 200fe6060f1SDimitry Andric break; 201fe6060f1SDimitry Andric } 202fe6060f1SDimitry Andric return false; 203fe6060f1SDimitry Andric } 204fe6060f1SDimitry Andric 205bdd1243dSDimitry Andric std::optional<std::string> 206fe6060f1SDimitry Andric M68kTargetInfo::handleAsmEscapedChar(char EscChar) const { 207fe6060f1SDimitry Andric char C; 208fe6060f1SDimitry Andric switch (EscChar) { 209fe6060f1SDimitry Andric case '.': 210fe6060f1SDimitry Andric case '#': 211fe6060f1SDimitry Andric C = EscChar; 212fe6060f1SDimitry Andric break; 213fe6060f1SDimitry Andric case '/': 214fe6060f1SDimitry Andric C = '%'; 215fe6060f1SDimitry Andric break; 216fe6060f1SDimitry Andric case '$': 217fe6060f1SDimitry Andric C = 's'; 218fe6060f1SDimitry Andric break; 219fe6060f1SDimitry Andric case '&': 220fe6060f1SDimitry Andric C = 'd'; 221fe6060f1SDimitry Andric break; 222fe6060f1SDimitry Andric default: 223bdd1243dSDimitry Andric return std::nullopt; 224fe6060f1SDimitry Andric } 225fe6060f1SDimitry Andric 226fe6060f1SDimitry Andric return std::string(1, C); 227fe6060f1SDimitry Andric } 228fe6060f1SDimitry Andric 229fe6060f1SDimitry Andric std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const { 230fe6060f1SDimitry Andric if (*Constraint == 'C') 231fe6060f1SDimitry Andric // Two-character constraint; add "^" hint for later parsing 232fe6060f1SDimitry Andric return std::string("^") + std::string(Constraint++, 2); 233fe6060f1SDimitry Andric 234fe6060f1SDimitry Andric return std::string(1, *Constraint); 235fe6060f1SDimitry Andric } 236fe6060f1SDimitry Andric 23706c3fb27SDimitry Andric std::string_view M68kTargetInfo::getClobbers() const { 238fe6060f1SDimitry Andric // FIXME: Is this really right? 239fe6060f1SDimitry Andric return ""; 240fe6060f1SDimitry Andric } 241fe6060f1SDimitry Andric 242fe6060f1SDimitry Andric TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const { 243fe6060f1SDimitry Andric return TargetInfo::VoidPtrBuiltinVaList; 244fe6060f1SDimitry Andric } 245fe6060f1SDimitry Andric 2465f757f3fSDimitry Andric TargetInfo::CallingConvCheckResult 2475f757f3fSDimitry Andric M68kTargetInfo::checkCallingConvention(CallingConv CC) const { 2485f757f3fSDimitry Andric switch (CC) { 2495f757f3fSDimitry Andric case CC_C: 2505f757f3fSDimitry Andric case CC_M68kRTD: 2515f757f3fSDimitry Andric return CCCR_OK; 2525f757f3fSDimitry Andric default: 2535f757f3fSDimitry Andric return TargetInfo::checkCallingConvention(CC); 2545f757f3fSDimitry Andric } 2555f757f3fSDimitry Andric } 256fe6060f1SDimitry Andric } // namespace targets 257fe6060f1SDimitry Andric } // namespace clang 258