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