xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //= LoongArchBaseInfo.cpp - Top level definitions for LoongArch MC -*- C++ -*-//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements helper functions for the LoongArch target useful for the
1081ad6265SDimitry Andric // compiler back-end and the MC libraries.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "LoongArchBaseInfo.h"
15*0fca6ea1SDimitry Andric #include "LoongArchMCTargetDesc.h"
1681ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1781ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
18*0fca6ea1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
1906c3fb27SDimitry Andric #include "llvm/Support/raw_ostream.h"
2006c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
2181ad6265SDimitry Andric 
2281ad6265SDimitry Andric namespace llvm {
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric namespace LoongArchABI {
2581ad6265SDimitry Andric 
26*0fca6ea1SDimitry Andric // Check if ABI has been standardized; issue a warning if it hasn't.
27*0fca6ea1SDimitry Andric // FIXME: Once all ABIs are standardized, this will be removed.
28*0fca6ea1SDimitry Andric static ABI checkABIStandardized(ABI Abi) {
29*0fca6ea1SDimitry Andric   StringRef ABIName;
30*0fca6ea1SDimitry Andric   switch (Abi) {
31*0fca6ea1SDimitry Andric   case ABI_ILP32S:
32*0fca6ea1SDimitry Andric     ABIName = "ilp32s";
33*0fca6ea1SDimitry Andric     break;
34*0fca6ea1SDimitry Andric   case ABI_ILP32F:
35*0fca6ea1SDimitry Andric     ABIName = "ilp32f";
36*0fca6ea1SDimitry Andric     break;
37*0fca6ea1SDimitry Andric   case ABI_ILP32D:
38*0fca6ea1SDimitry Andric     ABIName = "ilp32d";
39*0fca6ea1SDimitry Andric     break;
40*0fca6ea1SDimitry Andric   case ABI_LP64F:
41*0fca6ea1SDimitry Andric     ABIName = "lp64f";
42*0fca6ea1SDimitry Andric     break;
43*0fca6ea1SDimitry Andric   case ABI_LP64S:
44*0fca6ea1SDimitry Andric   case ABI_LP64D:
45*0fca6ea1SDimitry Andric     return Abi;
46*0fca6ea1SDimitry Andric   default:
47*0fca6ea1SDimitry Andric     llvm_unreachable("");
48*0fca6ea1SDimitry Andric   }
49*0fca6ea1SDimitry Andric   errs() << "warning: '" << ABIName << "' has not been standardized\n";
50*0fca6ea1SDimitry Andric   return Abi;
51*0fca6ea1SDimitry Andric }
52*0fca6ea1SDimitry Andric 
53*0fca6ea1SDimitry Andric static ABI getTripleABI(const Triple &TT) {
5406c3fb27SDimitry Andric   bool Is64Bit = TT.isArch64Bit();
5506c3fb27SDimitry Andric   ABI TripleABI;
5606c3fb27SDimitry Andric   switch (TT.getEnvironment()) {
5706c3fb27SDimitry Andric   case llvm::Triple::EnvironmentType::GNUSF:
58*0fca6ea1SDimitry Andric     TripleABI = Is64Bit ? ABI_LP64S : ABI_ILP32S;
5906c3fb27SDimitry Andric     break;
6006c3fb27SDimitry Andric   case llvm::Triple::EnvironmentType::GNUF32:
61*0fca6ea1SDimitry Andric     TripleABI = Is64Bit ? ABI_LP64F : ABI_ILP32F;
6206c3fb27SDimitry Andric     break;
6306c3fb27SDimitry Andric   // Let the fallback case behave like {ILP32,LP64}D.
6406c3fb27SDimitry Andric   case llvm::Triple::EnvironmentType::GNUF64:
6506c3fb27SDimitry Andric   default:
66*0fca6ea1SDimitry Andric     TripleABI = Is64Bit ? ABI_LP64D : ABI_ILP32D;
67*0fca6ea1SDimitry Andric     break;
68*0fca6ea1SDimitry Andric   }
69*0fca6ea1SDimitry Andric   return TripleABI;
70*0fca6ea1SDimitry Andric }
71*0fca6ea1SDimitry Andric 
72*0fca6ea1SDimitry Andric ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
73*0fca6ea1SDimitry Andric                      StringRef ABIName) {
74*0fca6ea1SDimitry Andric   bool Is64Bit = TT.isArch64Bit();
75*0fca6ea1SDimitry Andric   ABI ArgProvidedABI = getTargetABI(ABIName);
76*0fca6ea1SDimitry Andric   ABI TripleABI = getTripleABI(TT);
77*0fca6ea1SDimitry Andric 
78*0fca6ea1SDimitry Andric   auto IsABIValidForFeature = [=](ABI Abi) {
79*0fca6ea1SDimitry Andric     switch (Abi) {
80*0fca6ea1SDimitry Andric     default:
81*0fca6ea1SDimitry Andric       return false;
82*0fca6ea1SDimitry Andric     case ABI_ILP32S:
83*0fca6ea1SDimitry Andric       return !Is64Bit;
84*0fca6ea1SDimitry Andric     case ABI_ILP32F:
85*0fca6ea1SDimitry Andric       return !Is64Bit && FeatureBits[LoongArch::FeatureBasicF];
86*0fca6ea1SDimitry Andric     case ABI_ILP32D:
87*0fca6ea1SDimitry Andric       return !Is64Bit && FeatureBits[LoongArch::FeatureBasicD];
88*0fca6ea1SDimitry Andric     case ABI_LP64S:
89*0fca6ea1SDimitry Andric       return Is64Bit;
90*0fca6ea1SDimitry Andric     case ABI_LP64F:
91*0fca6ea1SDimitry Andric       return Is64Bit && FeatureBits[LoongArch::FeatureBasicF];
92*0fca6ea1SDimitry Andric     case ABI_LP64D:
93*0fca6ea1SDimitry Andric       return Is64Bit && FeatureBits[LoongArch::FeatureBasicD];
94*0fca6ea1SDimitry Andric     }
95*0fca6ea1SDimitry Andric   };
96*0fca6ea1SDimitry Andric 
97*0fca6ea1SDimitry Andric   // 1. If the '-target-abi' is valid, use it.
98*0fca6ea1SDimitry Andric   if (IsABIValidForFeature(ArgProvidedABI)) {
99*0fca6ea1SDimitry Andric     if (TT.hasEnvironment() && ArgProvidedABI != TripleABI)
100*0fca6ea1SDimitry Andric       errs()
101*0fca6ea1SDimitry Andric           << "warning: triple-implied ABI conflicts with provided target-abi '"
102*0fca6ea1SDimitry Andric           << ABIName << "', using target-abi\n";
103*0fca6ea1SDimitry Andric     return checkABIStandardized(ArgProvidedABI);
104*0fca6ea1SDimitry Andric   }
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric   // 2. If the triple-implied ABI is valid, use it.
107*0fca6ea1SDimitry Andric   if (IsABIValidForFeature(TripleABI)) {
108*0fca6ea1SDimitry Andric     // If target-abi is not specified, use the valid triple-implied ABI.
109*0fca6ea1SDimitry Andric     if (ABIName.empty())
110*0fca6ea1SDimitry Andric       return checkABIStandardized(TripleABI);
111*0fca6ea1SDimitry Andric 
112*0fca6ea1SDimitry Andric     switch (ArgProvidedABI) {
113*0fca6ea1SDimitry Andric     case ABI_Unknown:
114*0fca6ea1SDimitry Andric       // Fallback to the triple-implied ABI if ABI name is specified but
115*0fca6ea1SDimitry Andric       // invalid.
116*0fca6ea1SDimitry Andric       errs() << "warning: the '" << ABIName
117*0fca6ea1SDimitry Andric              << "' is not a recognized ABI for this target, ignoring and "
118*0fca6ea1SDimitry Andric                 "using triple-implied ABI\n";
119*0fca6ea1SDimitry Andric       return checkABIStandardized(TripleABI);
120*0fca6ea1SDimitry Andric     case ABI_ILP32S:
121*0fca6ea1SDimitry Andric     case ABI_ILP32F:
122*0fca6ea1SDimitry Andric     case ABI_ILP32D:
123*0fca6ea1SDimitry Andric       if (Is64Bit) {
124*0fca6ea1SDimitry Andric         errs() << "warning: 32-bit ABIs are not supported for 64-bit targets, "
125*0fca6ea1SDimitry Andric                   "ignoring and using triple-implied ABI\n";
126*0fca6ea1SDimitry Andric         return checkABIStandardized(TripleABI);
127*0fca6ea1SDimitry Andric       }
128*0fca6ea1SDimitry Andric       break;
129*0fca6ea1SDimitry Andric     case ABI_LP64S:
130*0fca6ea1SDimitry Andric     case ABI_LP64F:
131*0fca6ea1SDimitry Andric     case ABI_LP64D:
132*0fca6ea1SDimitry Andric       if (!Is64Bit) {
133*0fca6ea1SDimitry Andric         errs() << "warning: 64-bit ABIs are not supported for 32-bit targets, "
134*0fca6ea1SDimitry Andric                   "ignoring and using triple-implied ABI\n";
135*0fca6ea1SDimitry Andric         return checkABIStandardized(TripleABI);
136*0fca6ea1SDimitry Andric       }
13706c3fb27SDimitry Andric       break;
13806c3fb27SDimitry Andric     }
13906c3fb27SDimitry Andric 
14006c3fb27SDimitry Andric     switch (ArgProvidedABI) {
141*0fca6ea1SDimitry Andric     case ABI_ILP32F:
142*0fca6ea1SDimitry Andric     case ABI_LP64F:
143*0fca6ea1SDimitry Andric       errs() << "warning: the '" << ABIName
144*0fca6ea1SDimitry Andric              << "' ABI can't be used for a target that doesn't support the 'F' "
145*0fca6ea1SDimitry Andric                 "instruction set, ignoring and using triple-implied ABI\n";
14606c3fb27SDimitry Andric       break;
147*0fca6ea1SDimitry Andric     case ABI_ILP32D:
148*0fca6ea1SDimitry Andric     case ABI_LP64D:
149*0fca6ea1SDimitry Andric       errs() << "warning: the '" << ABIName
150*0fca6ea1SDimitry Andric              << "' ABI can't be used for a target that doesn't support the 'D' "
151*0fca6ea1SDimitry Andric                 "instruction set, ignoring and using triple-implied ABI\n";
15206c3fb27SDimitry Andric       break;
153*0fca6ea1SDimitry Andric     default:
154*0fca6ea1SDimitry Andric       llvm_unreachable("");
155*0fca6ea1SDimitry Andric     }
156*0fca6ea1SDimitry Andric     return checkABIStandardized(TripleABI);
15706c3fb27SDimitry Andric   }
15806c3fb27SDimitry Andric 
159*0fca6ea1SDimitry Andric   // 3. Parse the 'feature-abi', and use it.
160*0fca6ea1SDimitry Andric   auto GetFeatureABI = [=]() {
161*0fca6ea1SDimitry Andric     if (FeatureBits[LoongArch::FeatureBasicD])
162*0fca6ea1SDimitry Andric       return Is64Bit ? ABI_LP64D : ABI_ILP32D;
163*0fca6ea1SDimitry Andric     if (FeatureBits[LoongArch::FeatureBasicF])
164*0fca6ea1SDimitry Andric       return Is64Bit ? ABI_LP64F : ABI_ILP32F;
165*0fca6ea1SDimitry Andric     return Is64Bit ? ABI_LP64S : ABI_ILP32S;
166*0fca6ea1SDimitry Andric   };
167*0fca6ea1SDimitry Andric   if (ABIName.empty())
168*0fca6ea1SDimitry Andric     errs() << "warning: the triple-implied ABI is invalid, ignoring and using "
169*0fca6ea1SDimitry Andric               "feature-implied ABI\n";
170*0fca6ea1SDimitry Andric   else
171*0fca6ea1SDimitry Andric     errs() << "warning: both target-abi and the triple-implied ABI are "
172*0fca6ea1SDimitry Andric               "invalid, ignoring and using feature-implied ABI\n";
173*0fca6ea1SDimitry Andric   return checkABIStandardized(GetFeatureABI());
17406c3fb27SDimitry Andric }
17506c3fb27SDimitry Andric 
17681ad6265SDimitry Andric ABI getTargetABI(StringRef ABIName) {
17781ad6265SDimitry Andric   auto TargetABI = StringSwitch<ABI>(ABIName)
17881ad6265SDimitry Andric                        .Case("ilp32s", ABI_ILP32S)
17981ad6265SDimitry Andric                        .Case("ilp32f", ABI_ILP32F)
18081ad6265SDimitry Andric                        .Case("ilp32d", ABI_ILP32D)
18181ad6265SDimitry Andric                        .Case("lp64s", ABI_LP64S)
18281ad6265SDimitry Andric                        .Case("lp64f", ABI_LP64F)
18381ad6265SDimitry Andric                        .Case("lp64d", ABI_LP64D)
18481ad6265SDimitry Andric                        .Default(ABI_Unknown);
18581ad6265SDimitry Andric   return TargetABI;
18681ad6265SDimitry Andric }
18781ad6265SDimitry Andric 
18806c3fb27SDimitry Andric // To avoid the BP value clobbered by a function call, we need to choose a
18906c3fb27SDimitry Andric // callee saved register to save the value. The `last` `S` register (s9) is
19006c3fb27SDimitry Andric // used for FP. So we choose the previous (s8) as BP.
19181ad6265SDimitry Andric MCRegister getBPReg() { return LoongArch::R31; }
19281ad6265SDimitry Andric 
193972a253aSDimitry Andric } // end namespace LoongArchABI
19481ad6265SDimitry Andric 
195972a253aSDimitry Andric } // end namespace llvm
196