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