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
26namespace clang {
27namespace targets {
28
29M68kTargetInfo::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(DL: Layout);
57
58 SizeType = UnsignedInt;
59 PtrDiffType = SignedInt;
60 IntPtrType = SignedInt;
61}
62
63bool M68kTargetInfo::setCPU(const std::string &Name) {
64 StringRef N = Name;
65 CPU = llvm::StringSwitch<CPUKind>(N)
66 .Case(S: "generic", Value: CK_68000)
67 .Case(S: "M68000", Value: CK_68000)
68 .Case(S: "M68010", Value: CK_68010)
69 .Case(S: "M68020", Value: CK_68020)
70 .Case(S: "M68030", Value: CK_68030)
71 .Case(S: "M68040", Value: CK_68040)
72 .Case(S: "M68060", Value: CK_68060)
73 .Default(Value: CK_Unknown);
74 return CPU != CK_Unknown;
75}
76
77void M68kTargetInfo::getTargetDefines(const LangOptions &Opts,
78 MacroBuilder &Builder) const {
79 using llvm::Twine;
80
81 Builder.defineMacro(Name: "__m68k__");
82
83 DefineStd(Builder, MacroName: "mc68000", Opts);
84
85 // For sub-architecture
86 switch (CPU) {
87 case CK_68010:
88 DefineStd(Builder, MacroName: "mc68010", Opts);
89 break;
90 case CK_68020:
91 DefineStd(Builder, MacroName: "mc68020", Opts);
92 break;
93 case CK_68030:
94 DefineStd(Builder, MacroName: "mc68030", Opts);
95 break;
96 case CK_68040:
97 DefineStd(Builder, MacroName: "mc68040", Opts);
98 break;
99 case CK_68060:
100 DefineStd(Builder, MacroName: "mc68060", Opts);
101 break;
102 default:
103 break;
104 }
105
106 if (CPU >= CK_68020) {
107 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
108 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
109 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
110 }
111
112 // Floating point
113 if (TargetOpts.FeatureMap.lookup(Key: "isa-68881") ||
114 TargetOpts.FeatureMap.lookup(Key: "isa-68882"))
115 Builder.defineMacro(Name: "__HAVE_68881__");
116}
117
118ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const {
119 // FIXME: Implement.
120 return std::nullopt;
121}
122
123bool M68kTargetInfo::hasFeature(StringRef Feature) const {
124 // FIXME elaborate moar
125 return Feature == "M68000";
126}
127
128const 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
133ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const {
134 return llvm::ArrayRef(GCCRegNames);
135}
136
137const TargetInfo::GCCRegAlias M68kTargetInfo::GCCRegAliases[] = {
138 {.Aliases: {"bp"}, .Register: "a5"},
139 {.Aliases: {"fp"}, .Register: "a6"},
140 {.Aliases: {"usp", "ssp", "isp", "a7"}, .Register: "sp"},
141};
142
143ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const {
144 return llvm::ArrayRef(GCCRegAliases);
145}
146
147bool 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(Min: 1, Max: 8);
156 return true;
157 case 'J': // constant signed 16-bit integer
158 info.setRequiresImmediate(Min: std::numeric_limits<int16_t>::min(),
159 Max: 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(Min: -8, Max: -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(Min: 24, Max: 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(Min: 8, Max: 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
205std::optional<std::string>
206M68kTargetInfo::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
229std::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
237std::string_view M68kTargetInfo::getClobbers() const {
238 // FIXME: Is this really right?
239 return "";
240}
241
242TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const {
243 return TargetInfo::VoidPtrBuiltinVaList;
244}
245
246TargetInfo::CallingConvCheckResult
247M68kTargetInfo::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