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 "llvm/ADT/StringRef.h" 17 #include "llvm/ADT/StringSwitch.h" 18 #include "llvm/TargetParser/TargetParser.h" 19 #include <cstdint> 20 #include <cstring> 21 #include <limits> 22 #include <optional> 23 24 namespace clang { 25 namespace targets { 26 27 M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, 28 const TargetOptions &Opts) 29 : TargetInfo(Triple), TargetOpts(Opts) { 30 31 std::string Layout; 32 33 // M68k is Big Endian 34 Layout += "E"; 35 36 // FIXME how to wire it with the used object format? 37 Layout += "-m:e"; 38 39 // M68k pointers are always 32 bit wide even for 16-bit CPUs 40 Layout += "-p:32:16:32"; 41 42 // M68k integer data types 43 Layout += "-i8:8:8-i16:16:16-i32:16:32"; 44 45 // FIXME no floats at the moment 46 47 // The registers can hold 8, 16, 32 bits 48 Layout += "-n8:16:32"; 49 50 // 16 bit alignment for both stack and aggregate 51 // in order to conform to ABI used by GCC 52 Layout += "-a:0:16-S16"; 53 54 resetDataLayout(Layout); 55 56 SizeType = UnsignedInt; 57 PtrDiffType = SignedInt; 58 IntPtrType = SignedInt; 59 IntAlign = LongAlign = PointerAlign = 16; 60 } 61 62 bool M68kTargetInfo::setCPU(const std::string &Name) { 63 StringRef N = Name; 64 CPU = llvm::StringSwitch<CPUKind>(N) 65 .Case("generic", CK_68000) 66 .Case("M68000", CK_68000) 67 .Case("M68010", CK_68010) 68 .Case("M68020", CK_68020) 69 .Case("M68030", CK_68030) 70 .Case("M68040", CK_68040) 71 .Case("M68060", CK_68060) 72 .Default(CK_Unknown); 73 return CPU != CK_Unknown; 74 } 75 76 void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, 77 MacroBuilder &Builder) const { 78 using llvm::Twine; 79 80 Builder.defineMacro("__m68k__"); 81 82 DefineStd(Builder, "mc68000", Opts); 83 84 // For sub-architecture 85 switch (CPU) { 86 case CK_68010: 87 DefineStd(Builder, "mc68010", Opts); 88 break; 89 case CK_68020: 90 DefineStd(Builder, "mc68020", Opts); 91 break; 92 case CK_68030: 93 DefineStd(Builder, "mc68030", Opts); 94 break; 95 case CK_68040: 96 DefineStd(Builder, "mc68040", Opts); 97 break; 98 case CK_68060: 99 DefineStd(Builder, "mc68060", Opts); 100 break; 101 default: 102 break; 103 } 104 105 if (CPU >= CK_68020) { 106 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 107 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 108 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 109 } 110 111 // Floating point 112 if (TargetOpts.FeatureMap.lookup("isa-68881") || 113 TargetOpts.FeatureMap.lookup("isa-68882")) 114 Builder.defineMacro("__HAVE_68881__"); 115 } 116 117 llvm::SmallVector<Builtin::InfosShard> 118 M68kTargetInfo::getTargetBuiltins() const { 119 // FIXME: Implement. 120 return {}; 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