diff --git a/llvm/lib/Target/LoongArch/LoongArchSubtarget.cpp b/llvm/lib/Target/LoongArch/LoongArchSubtarget.cpp index d8850f656d52f..a0136440ec0ee 100644 --- a/llvm/lib/Target/LoongArch/LoongArchSubtarget.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchSubtarget.cpp @@ -12,6 +12,7 @@ #include "LoongArchSubtarget.h" #include "LoongArchFrameLowering.h" +#include "MCTargetDesc/LoongArchBaseInfo.h" using namespace llvm; @@ -48,8 +49,8 @@ LoongArchSubtarget &LoongArchSubtarget::initializeSubtargetDependencies( if (!Is64Bit && HasLA64) report_fatal_error("Feature 64bit should be used for loongarch64 target."); - // TODO: ILP32{S,F} LP64{S,F} - TargetABI = Is64Bit ? LoongArchABI::ABI_LP64D : LoongArchABI::ABI_ILP32D; + TargetABI = LoongArchABI::computeTargetABI(TT, ABIName); + return *this; } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp index de2ba2833414b..c7b1e19daa8be 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.cpp @@ -15,11 +15,71 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { namespace LoongArchABI { +ABI computeTargetABI(const Triple &TT, StringRef ABIName) { + ABI ArgProvidedABI = getTargetABI(ABIName); + bool Is64Bit = TT.isArch64Bit(); + ABI TripleABI; + + // Figure out the ABI explicitly requested via the triple's environment type. + switch (TT.getEnvironment()) { + case llvm::Triple::EnvironmentType::GNUSF: + TripleABI = Is64Bit ? LoongArchABI::ABI_LP64S : LoongArchABI::ABI_ILP32S; + break; + case llvm::Triple::EnvironmentType::GNUF32: + TripleABI = Is64Bit ? LoongArchABI::ABI_LP64F : LoongArchABI::ABI_ILP32F; + break; + + // Let the fallback case behave like {ILP32,LP64}D. + case llvm::Triple::EnvironmentType::GNUF64: + default: + TripleABI = Is64Bit ? LoongArchABI::ABI_LP64D : LoongArchABI::ABI_ILP32D; + break; + } + + switch (ArgProvidedABI) { + case LoongArchABI::ABI_Unknown: + // Fallback to the triple-implied ABI if ABI name is not specified or + // invalid. + if (!ABIName.empty()) + errs() << "'" << ABIName + << "' is not a recognized ABI for this target, ignoring and using " + "triple-implied ABI\n"; + return TripleABI; + + case LoongArchABI::ABI_ILP32S: + case LoongArchABI::ABI_ILP32F: + case LoongArchABI::ABI_ILP32D: + if (Is64Bit) { + errs() << "32-bit ABIs are not supported for 64-bit targets, ignoring " + "target-abi and using triple-implied ABI\n"; + return TripleABI; + } + break; + + case LoongArchABI::ABI_LP64S: + case LoongArchABI::ABI_LP64F: + case LoongArchABI::ABI_LP64D: + if (!Is64Bit) { + errs() << "64-bit ABIs are not supported for 32-bit targets, ignoring " + "target-abi and using triple-implied ABI\n"; + return TripleABI; + } + break; + } + + if (!ABIName.empty() && ArgProvidedABI != TripleABI) + errs() << "warning: triple-implied ABI conflicts with provided target-abi '" + << ABIName << "', using target-abi\n"; + + return ArgProvidedABI; +} + ABI getTargetABI(StringRef ABIName) { auto TargetABI = StringSwitch(ABIName) .Case("ilp32s", ABI_ILP32S) diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h index c5f0726779999..cdbd1f5699dfd 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h @@ -54,6 +54,7 @@ enum ABI { ABI_Unknown }; +ABI computeTargetABI(const Triple &TT, StringRef ABIName); ABI getTargetABI(StringRef ABIName); // Returns the register used to hold the stack pointer after realignment. diff --git a/llvm/test/CodeGen/LoongArch/target-abi-from-triple-edge-cases.ll b/llvm/test/CodeGen/LoongArch/target-abi-from-triple-edge-cases.ll new file mode 100644 index 0000000000000..f30fcb8afeec2 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/target-abi-from-triple-edge-cases.ll @@ -0,0 +1,67 @@ +;; Check that an unknown --target-abi is ignored and the triple-implied ABI is +;; used. +; RUN: llc --mtriple=loongarch32-linux-gnu --target-abi=foo --mattr=+d < %s 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=ILP32D,UNKNOWN +; RUN: llc --mtriple=loongarch64-linux-gnu --target-abi=foo --mattr=+d < %s 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=LP64D,UNKNOWN + +; UNKNOWN: 'foo' is not a recognized ABI for this target, ignoring and using triple-implied ABI + +;; Check that --target-abi takes precedence over triple-supplied ABI modifiers. +; RUN: llc --mtriple=loongarch32-linux-gnusf --target-abi=ilp32d --mattr=+d < %s 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=ILP32D,CONFLICT-ILP32D +; RUN: llc --mtriple=loongarch64-linux-gnusf --target-abi=lp64d --mattr=+d < %s 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=LP64D,CONFLICT-LP64D + +; CONFLICT-ILP32D: warning: triple-implied ABI conflicts with provided target-abi 'ilp32d', using target-abi +; CONFLICT-LP64D: warning: triple-implied ABI conflicts with provided target-abi 'lp64d', using target-abi + +;; Check that ILP32-on-LA64 and LP64-on-LA32 combinations are handled properly. +; RUN: llc --mtriple=loongarch64 --target-abi=ilp32d --mattr=+d < %s 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=LP64D,32ON64 +; RUN: llc --mtriple=loongarch32 --target-abi=lp64d --mattr=+d < %s 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=ILP32D,64ON32 + +; 32ON64: 32-bit ABIs are not supported for 64-bit targets, ignoring target-abi and using triple-implied ABI +; 64ON32: 64-bit ABIs are not supported for 32-bit targets, ignoring target-abi and using triple-implied ABI + +define float @f(float %a) { +; ILP32D-LABEL: f: +; ILP32D: # %bb.0: +; ILP32D-NEXT: addi.w $a0, $zero, 1 +; ILP32D-NEXT: movgr2fr.w $fa1, $a0 +; ILP32D-NEXT: ffint.s.w $fa1, $fa1 +; ILP32D-NEXT: fadd.s $fa0, $fa0, $fa1 +; ILP32D-NEXT: ret +; +; LP64D-LABEL: f: +; LP64D: # %bb.0: +; LP64D-NEXT: addi.w $a0, $zero, 1 +; LP64D-NEXT: movgr2fr.w $fa1, $a0 +; LP64D-NEXT: ffint.s.w $fa1, $fa1 +; LP64D-NEXT: fadd.s $fa0, $fa0, $fa1 +; LP64D-NEXT: ret + %1 = fadd float %a, 1.0 + ret float %1 +} + +define double @g(double %a) { +; ILP32D-LABEL: g: +; ILP32D: # %bb.0: +; ILP32D-NEXT: addi.w $a0, $zero, 1 +; ILP32D-NEXT: movgr2fr.w $fa1, $a0 +; ILP32D-NEXT: ffint.s.w $fa1, $fa1 +; ILP32D-NEXT: fcvt.d.s $fa1, $fa1 +; ILP32D-NEXT: fadd.d $fa0, $fa0, $fa1 +; ILP32D-NEXT: ret +; +; LP64D-LABEL: g: +; LP64D: # %bb.0: +; LP64D-NEXT: addi.d $a0, $zero, 1 +; LP64D-NEXT: movgr2fr.d $fa1, $a0 +; LP64D-NEXT: ffint.d.l $fa1, $fa1 +; LP64D-NEXT: fadd.d $fa0, $fa0, $fa1 +; LP64D-NEXT: ret + %1 = fadd double %a, 1.0 + ret double %1 +} diff --git a/llvm/test/CodeGen/LoongArch/target-abi-from-triple.ll b/llvm/test/CodeGen/LoongArch/target-abi-from-triple.ll new file mode 100644 index 0000000000000..0aca339038860 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/target-abi-from-triple.ll @@ -0,0 +1,49 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py + +;; Check that the correct ABI is chosen based on the triple given. +;; TODO: enable the S and F ABIs once support is wired up. +; RUN: llc --mtriple=loongarch32-linux-gnuf64 --mattr=+d < %s \ +; RUN: | FileCheck %s --check-prefix=ILP32D +; RUN: llc --mtriple=loongarch64-linux-gnuf64 --mattr=+d < %s \ +; RUN: | FileCheck %s --check-prefix=LP64D + +define float @f(float %a) { +; ILP32D-LABEL: f: +; ILP32D: # %bb.0: +; ILP32D-NEXT: addi.w $a0, $zero, 1 +; ILP32D-NEXT: movgr2fr.w $fa1, $a0 +; ILP32D-NEXT: ffint.s.w $fa1, $fa1 +; ILP32D-NEXT: fadd.s $fa0, $fa0, $fa1 +; ILP32D-NEXT: ret +; +; LP64D-LABEL: f: +; LP64D: # %bb.0: +; LP64D-NEXT: addi.w $a0, $zero, 1 +; LP64D-NEXT: movgr2fr.w $fa1, $a0 +; LP64D-NEXT: ffint.s.w $fa1, $fa1 +; LP64D-NEXT: fadd.s $fa0, $fa0, $fa1 +; LP64D-NEXT: ret + %1 = fadd float %a, 1.0 + ret float %1 +} + +define double @g(double %a) { +; ILP32D-LABEL: g: +; ILP32D: # %bb.0: +; ILP32D-NEXT: addi.w $a0, $zero, 1 +; ILP32D-NEXT: movgr2fr.w $fa1, $a0 +; ILP32D-NEXT: ffint.s.w $fa1, $fa1 +; ILP32D-NEXT: fcvt.d.s $fa1, $fa1 +; ILP32D-NEXT: fadd.d $fa0, $fa0, $fa1 +; ILP32D-NEXT: ret +; +; LP64D-LABEL: g: +; LP64D: # %bb.0: +; LP64D-NEXT: addi.d $a0, $zero, 1 +; LP64D-NEXT: movgr2fr.d $fa1, $a0 +; LP64D-NEXT: ffint.d.l $fa1, $fa1 +; LP64D-NEXT: fadd.d $fa0, $fa0, $fa1 +; LP64D-NEXT: ret + %1 = fadd double %a, 1.0 + ret double %1 +}