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