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 Builder.defineMacro("mc68000"); 84 Builder.defineMacro("__mc68000"); 85 Builder.defineMacro("__mc68000__"); 86 87 // For sub-architecture 88 switch (CPU) { 89 case CK_68010: 90 Builder.defineMacro("mc68010"); 91 Builder.defineMacro("__mc68010"); 92 Builder.defineMacro("__mc68010__"); 93 break; 94 case CK_68020: 95 Builder.defineMacro("mc68020"); 96 Builder.defineMacro("__mc68020"); 97 Builder.defineMacro("__mc68020__"); 98 break; 99 case CK_68030: 100 Builder.defineMacro("mc68030"); 101 Builder.defineMacro("__mc68030"); 102 Builder.defineMacro("__mc68030__"); 103 break; 104 case CK_68040: 105 Builder.defineMacro("mc68040"); 106 Builder.defineMacro("__mc68040"); 107 Builder.defineMacro("__mc68040__"); 108 break; 109 case CK_68060: 110 Builder.defineMacro("mc68060"); 111 Builder.defineMacro("__mc68060"); 112 Builder.defineMacro("__mc68060__"); 113 break; 114 default: 115 break; 116 } 117 118 if (CPU >= CK_68020) { 119 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 120 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 121 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 122 } 123 124 // Floating point 125 if (TargetOpts.FeatureMap.lookup("isa-68881") || 126 TargetOpts.FeatureMap.lookup("isa-68882")) 127 Builder.defineMacro("__HAVE_68881__"); 128 } 129 130 ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const { 131 // FIXME: Implement. 132 return std::nullopt; 133 } 134 135 bool M68kTargetInfo::hasFeature(StringRef Feature) const { 136 // FIXME elaborate moar 137 return Feature == "M68000"; 138 } 139 140 const char *const M68kTargetInfo::GCCRegNames[] = { 141 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 142 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", 143 "pc"}; 144 145 ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const { 146 return llvm::ArrayRef(GCCRegNames); 147 } 148 149 ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const { 150 // No aliases. 151 return std::nullopt; 152 } 153 154 bool M68kTargetInfo::validateAsmConstraint( 155 const char *&Name, TargetInfo::ConstraintInfo &info) const { 156 switch (*Name) { 157 case 'a': // address register 158 case 'd': // data register 159 info.setAllowsRegister(); 160 return true; 161 case 'I': // constant integer in the range [1,8] 162 info.setRequiresImmediate(1, 8); 163 return true; 164 case 'J': // constant signed 16-bit integer 165 info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), 166 std::numeric_limits<int16_t>::max()); 167 return true; 168 case 'K': // constant that is NOT in the range of [-0x80, 0x80) 169 info.setRequiresImmediate(); 170 return true; 171 case 'L': // constant integer in the range [-8,-1] 172 info.setRequiresImmediate(-8, -1); 173 return true; 174 case 'M': // constant that is NOT in the range of [-0x100, 0x100] 175 info.setRequiresImmediate(); 176 return true; 177 case 'N': // constant integer in the range [24,31] 178 info.setRequiresImmediate(24, 31); 179 return true; 180 case 'O': // constant integer 16 181 info.setRequiresImmediate(16); 182 return true; 183 case 'P': // constant integer in the range [8,15] 184 info.setRequiresImmediate(8, 15); 185 return true; 186 case 'C': 187 ++Name; 188 switch (*Name) { 189 case '0': // constant integer 0 190 info.setRequiresImmediate(0); 191 return true; 192 case 'i': // constant integer 193 case 'j': // integer constant that doesn't fit in 16 bits 194 info.setRequiresImmediate(); 195 return true; 196 default: 197 break; 198 } 199 break; 200 case 'Q': // address register indirect addressing 201 case 'U': // address register indirect w/ constant offset addressing 202 // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when 203 // '-mpcrel' flag is properly handled by the driver. 204 info.setAllowsMemory(); 205 return true; 206 default: 207 break; 208 } 209 return false; 210 } 211 212 std::optional<std::string> 213 M68kTargetInfo::handleAsmEscapedChar(char EscChar) const { 214 char C; 215 switch (EscChar) { 216 case '.': 217 case '#': 218 C = EscChar; 219 break; 220 case '/': 221 C = '%'; 222 break; 223 case '$': 224 C = 's'; 225 break; 226 case '&': 227 C = 'd'; 228 break; 229 default: 230 return std::nullopt; 231 } 232 233 return std::string(1, C); 234 } 235 236 std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const { 237 if (*Constraint == 'C') 238 // Two-character constraint; add "^" hint for later parsing 239 return std::string("^") + std::string(Constraint++, 2); 240 241 return std::string(1, *Constraint); 242 } 243 244 std::string_view M68kTargetInfo::getClobbers() const { 245 // FIXME: Is this really right? 246 return ""; 247 } 248 249 TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const { 250 return TargetInfo::VoidPtrBuiltinVaList; 251 } 252 253 } // namespace targets 254 } // namespace clang 255