1 //= LoongArchBaseInfo.cpp - Top level definitions for LoongArch MC -*- C++ -*-//
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 helper functions for the LoongArch target useful for the
10 // compiler back-end and the MC libraries.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "LoongArchBaseInfo.h"
15 #include "LoongArchMCTargetDesc.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/MC/MCSubtargetInfo.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/TargetParser/Triple.h"
21
22 namespace llvm {
23
24 namespace LoongArchABI {
25
26 // Check if ABI has been standardized; issue a warning if it hasn't.
27 // FIXME: Once all ABIs are standardized, this will be removed.
checkABIStandardized(ABI Abi)28 static ABI checkABIStandardized(ABI Abi) {
29 StringRef ABIName;
30 switch (Abi) {
31 case ABI_ILP32S:
32 ABIName = "ilp32s";
33 break;
34 case ABI_ILP32F:
35 ABIName = "ilp32f";
36 break;
37 case ABI_ILP32D:
38 ABIName = "ilp32d";
39 break;
40 case ABI_LP64F:
41 ABIName = "lp64f";
42 break;
43 case ABI_LP64S:
44 case ABI_LP64D:
45 return Abi;
46 default:
47 llvm_unreachable("");
48 }
49 errs() << "warning: '" << ABIName << "' has not been standardized\n";
50 return Abi;
51 }
52
getTripleABI(const Triple & TT)53 static ABI getTripleABI(const Triple &TT) {
54 bool Is64Bit = TT.isArch64Bit();
55 ABI TripleABI;
56 switch (TT.getEnvironment()) {
57 case llvm::Triple::EnvironmentType::GNUSF:
58 TripleABI = Is64Bit ? ABI_LP64S : ABI_ILP32S;
59 break;
60 case llvm::Triple::EnvironmentType::GNUF32:
61 TripleABI = Is64Bit ? ABI_LP64F : ABI_ILP32F;
62 break;
63 // Let the fallback case behave like {ILP32,LP64}D.
64 case llvm::Triple::EnvironmentType::GNUF64:
65 default:
66 TripleABI = Is64Bit ? ABI_LP64D : ABI_ILP32D;
67 break;
68 }
69 return TripleABI;
70 }
71
computeTargetABI(const Triple & TT,const FeatureBitset & FeatureBits,StringRef ABIName)72 ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
73 StringRef ABIName) {
74 bool Is64Bit = TT.isArch64Bit();
75 ABI ArgProvidedABI = getTargetABI(ABIName);
76 ABI TripleABI = getTripleABI(TT);
77
78 auto IsABIValidForFeature = [=](ABI Abi) {
79 switch (Abi) {
80 default:
81 return false;
82 case ABI_ILP32S:
83 return !Is64Bit;
84 case ABI_ILP32F:
85 return !Is64Bit && FeatureBits[LoongArch::FeatureBasicF];
86 case ABI_ILP32D:
87 return !Is64Bit && FeatureBits[LoongArch::FeatureBasicD];
88 case ABI_LP64S:
89 return Is64Bit;
90 case ABI_LP64F:
91 return Is64Bit && FeatureBits[LoongArch::FeatureBasicF];
92 case ABI_LP64D:
93 return Is64Bit && FeatureBits[LoongArch::FeatureBasicD];
94 }
95 };
96
97 // 1. If the '-target-abi' is valid, use it.
98 if (IsABIValidForFeature(ArgProvidedABI)) {
99 if (TT.hasEnvironment() && ArgProvidedABI != TripleABI)
100 errs()
101 << "warning: triple-implied ABI conflicts with provided target-abi '"
102 << ABIName << "', using target-abi\n";
103 return checkABIStandardized(ArgProvidedABI);
104 }
105
106 // 2. If the triple-implied ABI is valid, use it.
107 if (IsABIValidForFeature(TripleABI)) {
108 // If target-abi is not specified, use the valid triple-implied ABI.
109 if (ABIName.empty())
110 return checkABIStandardized(TripleABI);
111
112 switch (ArgProvidedABI) {
113 case ABI_Unknown:
114 // Fallback to the triple-implied ABI if ABI name is specified but
115 // invalid.
116 errs() << "warning: the '" << ABIName
117 << "' is not a recognized ABI for this target, ignoring and "
118 "using triple-implied ABI\n";
119 return checkABIStandardized(TripleABI);
120 case ABI_ILP32S:
121 case ABI_ILP32F:
122 case ABI_ILP32D:
123 if (Is64Bit) {
124 errs() << "warning: 32-bit ABIs are not supported for 64-bit targets, "
125 "ignoring and using triple-implied ABI\n";
126 return checkABIStandardized(TripleABI);
127 }
128 break;
129 case ABI_LP64S:
130 case ABI_LP64F:
131 case ABI_LP64D:
132 if (!Is64Bit) {
133 errs() << "warning: 64-bit ABIs are not supported for 32-bit targets, "
134 "ignoring and using triple-implied ABI\n";
135 return checkABIStandardized(TripleABI);
136 }
137 break;
138 }
139
140 switch (ArgProvidedABI) {
141 case ABI_ILP32F:
142 case ABI_LP64F:
143 errs() << "warning: the '" << ABIName
144 << "' ABI can't be used for a target that doesn't support the 'F' "
145 "instruction set, ignoring and using triple-implied ABI\n";
146 break;
147 case ABI_ILP32D:
148 case ABI_LP64D:
149 errs() << "warning: the '" << ABIName
150 << "' ABI can't be used for a target that doesn't support the 'D' "
151 "instruction set, ignoring and using triple-implied ABI\n";
152 break;
153 default:
154 llvm_unreachable("");
155 }
156 return checkABIStandardized(TripleABI);
157 }
158
159 // 3. Parse the 'feature-abi', and use it.
160 auto GetFeatureABI = [=]() {
161 if (FeatureBits[LoongArch::FeatureBasicD])
162 return Is64Bit ? ABI_LP64D : ABI_ILP32D;
163 if (FeatureBits[LoongArch::FeatureBasicF])
164 return Is64Bit ? ABI_LP64F : ABI_ILP32F;
165 return Is64Bit ? ABI_LP64S : ABI_ILP32S;
166 };
167 if (ABIName.empty())
168 errs() << "warning: the triple-implied ABI is invalid, ignoring and using "
169 "feature-implied ABI\n";
170 else
171 errs() << "warning: both target-abi and the triple-implied ABI are "
172 "invalid, ignoring and using feature-implied ABI\n";
173 return checkABIStandardized(GetFeatureABI());
174 }
175
getTargetABI(StringRef ABIName)176 ABI getTargetABI(StringRef ABIName) {
177 auto TargetABI = StringSwitch<ABI>(ABIName)
178 .Case("ilp32s", ABI_ILP32S)
179 .Case("ilp32f", ABI_ILP32F)
180 .Case("ilp32d", ABI_ILP32D)
181 .Case("lp64s", ABI_LP64S)
182 .Case("lp64f", ABI_LP64F)
183 .Case("lp64d", ABI_LP64D)
184 .Default(ABI_Unknown);
185 return TargetABI;
186 }
187
188 // To avoid the BP value clobbered by a function call, we need to choose a
189 // callee saved register to save the value. The `last` `S` register (s9) is
190 // used for FP. So we choose the previous (s8) as BP.
getBPReg()191 MCRegister getBPReg() { return LoongArch::R31; }
192
193 } // end namespace LoongArchABI
194
195 } // end namespace llvm
196