xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/M68k.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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