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
24namespace clang {
25namespace targets {
26
27M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple,
28 const TargetOptions &Opts)
29 : TargetInfo(Triple), TargetOpts(Opts) {
30 resetDataLayout();
31
32 SizeType = UnsignedInt;
33 PtrDiffType = SignedInt;
34 IntPtrType = SignedInt;
35 IntAlign = LongAlign = PointerAlign = 16;
36}
37
38bool M68kTargetInfo::setCPU(const std::string &Name) {
39 StringRef N = Name;
40 CPU = llvm::StringSwitch<CPUKind>(N)
41 .Case(S: "generic", Value: CK_68000)
42 .Case(S: "M68000", Value: CK_68000)
43 .Case(S: "M68010", Value: CK_68010)
44 .Case(S: "M68020", Value: CK_68020)
45 .Case(S: "M68030", Value: CK_68030)
46 .Case(S: "M68040", Value: CK_68040)
47 .Case(S: "M68060", Value: CK_68060)
48 .Default(Value: CK_Unknown);
49 return CPU != CK_Unknown;
50}
51
52void M68kTargetInfo::getTargetDefines(const LangOptions &Opts,
53 MacroBuilder &Builder) const {
54 using llvm::Twine;
55
56 Builder.defineMacro(Name: "__m68k__");
57
58 DefineStd(Builder, MacroName: "mc68000", Opts);
59
60 // For sub-architecture
61 switch (CPU) {
62 case CK_68010:
63 DefineStd(Builder, MacroName: "mc68010", Opts);
64 break;
65 case CK_68020:
66 DefineStd(Builder, MacroName: "mc68020", Opts);
67 break;
68 case CK_68030:
69 DefineStd(Builder, MacroName: "mc68030", Opts);
70 break;
71 case CK_68040:
72 DefineStd(Builder, MacroName: "mc68040", Opts);
73 break;
74 case CK_68060:
75 DefineStd(Builder, MacroName: "mc68060", Opts);
76 break;
77 default:
78 break;
79 }
80
81 if (CPU >= CK_68020) {
82 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
83 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
84 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
85 }
86
87 // Floating point
88 if (TargetOpts.FeatureMap.lookup(Key: "isa-68881") ||
89 TargetOpts.FeatureMap.lookup(Key: "isa-68882"))
90 Builder.defineMacro(Name: "__HAVE_68881__");
91}
92
93llvm::SmallVector<Builtin::InfosShard>
94M68kTargetInfo::getTargetBuiltins() const {
95 // FIXME: Implement.
96 return {};
97}
98
99bool M68kTargetInfo::hasFeature(StringRef Feature) const {
100 // FIXME elaborate moar
101 return Feature == "M68000";
102}
103
104const char *const M68kTargetInfo::GCCRegNames[] = {
105 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
106 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
107 "pc"};
108
109ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const {
110 return llvm::ArrayRef(GCCRegNames);
111}
112
113const TargetInfo::GCCRegAlias M68kTargetInfo::GCCRegAliases[] = {
114 {.Aliases: {"bp"}, .Register: "a5"},
115 {.Aliases: {"fp"}, .Register: "a6"},
116 {.Aliases: {"usp", "ssp", "isp", "a7"}, .Register: "sp"},
117};
118
119ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const {
120 return llvm::ArrayRef(GCCRegAliases);
121}
122
123bool M68kTargetInfo::validateAsmConstraint(
124 const char *&Name, TargetInfo::ConstraintInfo &info) const {
125 switch (*Name) {
126 case 'a': // address register
127 case 'd': // data register
128 info.setAllowsRegister();
129 return true;
130 case 'I': // constant integer in the range [1,8]
131 info.setRequiresImmediate(Min: 1, Max: 8);
132 return true;
133 case 'J': // constant signed 16-bit integer
134 info.setRequiresImmediate(Min: std::numeric_limits<int16_t>::min(),
135 Max: std::numeric_limits<int16_t>::max());
136 return true;
137 case 'K': // constant that is NOT in the range of [-0x80, 0x80)
138 info.setRequiresImmediate();
139 return true;
140 case 'L': // constant integer in the range [-8,-1]
141 info.setRequiresImmediate(Min: -8, Max: -1);
142 return true;
143 case 'M': // constant that is NOT in the range of [-0x100, 0x100]
144 info.setRequiresImmediate();
145 return true;
146 case 'N': // constant integer in the range [24,31]
147 info.setRequiresImmediate(Min: 24, Max: 31);
148 return true;
149 case 'O': // constant integer 16
150 info.setRequiresImmediate(16);
151 return true;
152 case 'P': // constant integer in the range [8,15]
153 info.setRequiresImmediate(Min: 8, Max: 15);
154 return true;
155 case 'C':
156 ++Name;
157 switch (*Name) {
158 case '0': // constant integer 0
159 info.setRequiresImmediate(0);
160 return true;
161 case 'i': // constant integer
162 case 'j': // integer constant that doesn't fit in 16 bits
163 info.setRequiresImmediate();
164 return true;
165 default:
166 break;
167 }
168 break;
169 case 'Q': // address register indirect addressing
170 case 'U': // address register indirect w/ constant offset addressing
171 // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when
172 // '-mpcrel' flag is properly handled by the driver.
173 info.setAllowsMemory();
174 return true;
175 default:
176 break;
177 }
178 return false;
179}
180
181std::optional<std::string>
182M68kTargetInfo::handleAsmEscapedChar(char EscChar) const {
183 char C;
184 switch (EscChar) {
185 case '.':
186 case '#':
187 C = EscChar;
188 break;
189 case '/':
190 C = '%';
191 break;
192 case '$':
193 C = 's';
194 break;
195 case '&':
196 C = 'd';
197 break;
198 default:
199 return std::nullopt;
200 }
201
202 return std::string(1, C);
203}
204
205std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const {
206 if (*Constraint == 'C')
207 // Two-character constraint; add "^" hint for later parsing
208 return std::string("^") + std::string(Constraint++, 2);
209
210 return std::string(1, *Constraint);
211}
212
213std::string_view M68kTargetInfo::getClobbers() const {
214 // FIXME: Is this really right?
215 return "";
216}
217
218TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const {
219 return TargetInfo::VoidPtrBuiltinVaList;
220}
221
222TargetInfo::CallingConvCheckResult
223M68kTargetInfo::checkCallingConvention(CallingConv CC) const {
224 switch (CC) {
225 case CC_C:
226 case CC_M68kRTD:
227 return CCCR_OK;
228 default:
229 return TargetInfo::checkCallingConvention(CC);
230 }
231}
232} // namespace targets
233} // namespace clang
234