diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt --- a/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt @@ -2,11 +2,13 @@ LoongArchAsmBackend.cpp LoongArchBaseInfo.cpp LoongArchELFObjectWriter.cpp + LoongArchELFStreamer.cpp LoongArchInstPrinter.cpp LoongArchMCAsmInfo.cpp LoongArchMCTargetDesc.cpp LoongArchMCCodeEmitter.cpp LoongArchMatInt.cpp + LoongArchTargetStreamer.cpp LINK_COMPONENTS MC diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h @@ -0,0 +1,31 @@ +//==-- LoongArchELFStreamer.h - LoongArch ELF Target Streamer --*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHELFSTREAMER_H +#define LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHELFSTREAMER_H + +#include "LoongArchTargetStreamer.h" +#include "llvm/MC/MCELFStreamer.h" + +namespace llvm { + +class LoongArchTargetELFStreamer : public LoongArchTargetStreamer { +public: + MCELFStreamer &getStreamer(); + LoongArchTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); + + void finish() override; +}; + +MCELFStreamer *createLoongArchELFStreamer(MCContext &C, + std::unique_ptr MAB, + std::unique_ptr MOW, + std::unique_ptr MCE, + bool RelaxAll); +} // end namespace llvm +#endif diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp @@ -0,0 +1,95 @@ +//===-- LoongArchELFStreamer.cpp - LoongArch ELF Target Streamer Methods --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides LoongArch specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "LoongArchELFStreamer.h" +#include "LoongArchAsmBackend.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCObjectWriter.h" + +using namespace llvm; + +// This part is for ELF object output. +LoongArchTargetELFStreamer::LoongArchTargetELFStreamer( + MCStreamer &S, const MCSubtargetInfo &STI) + : LoongArchTargetStreamer(S) { + // FIXME: select appropriate ABI. + setTargetABI(STI.getTargetTriple().isArch64Bit() ? LoongArchABI::ABI_LP64D + : LoongArchABI::ABI_ILP32D); +} + +MCELFStreamer &LoongArchTargetELFStreamer::getStreamer() { + return static_cast(Streamer); +} + +void LoongArchTargetELFStreamer::finish() { + LoongArchTargetStreamer::finish(); + MCAssembler &MCA = getStreamer().getAssembler(); + LoongArchABI::ABI ABI = getTargetABI(); + + // FIXME: + // There are several PRs [1][2][3] that may affect the e_flags. + // After they got closed or merged, we should update the implementation here + // accordingly. + // + // [1] https://github.com/loongson/LoongArch-Documentation/pull/33 + // [2] https://github.com/loongson/LoongArch-Documentation/pull/47 + // [2] https://github.com/loongson/LoongArch-Documentation/pull/61 + unsigned EFlags = MCA.getELFHeaderEFlags(); + switch (ABI) { + case LoongArchABI::ABI_ILP32S: + EFlags |= ELF::EF_LOONGARCH_BASE_ABI_ILP32S; + break; + case LoongArchABI::ABI_ILP32F: + EFlags |= ELF::EF_LOONGARCH_BASE_ABI_ILP32F; + break; + case LoongArchABI::ABI_ILP32D: + EFlags |= ELF::EF_LOONGARCH_BASE_ABI_ILP32D; + break; + case LoongArchABI::ABI_LP64S: + EFlags |= ELF::EF_LOONGARCH_BASE_ABI_LP64S; + break; + case LoongArchABI::ABI_LP64F: + EFlags |= ELF::EF_LOONGARCH_BASE_ABI_LP64F; + break; + case LoongArchABI::ABI_LP64D: + EFlags |= ELF::EF_LOONGARCH_BASE_ABI_LP64D; + break; + case LoongArchABI::ABI_Unknown: + llvm_unreachable("Improperly initialized target ABI"); + } + MCA.setELFHeaderEFlags(EFlags); +} + +namespace { +class LoongArchELFStreamer : public MCELFStreamer { +public: + LoongArchELFStreamer(MCContext &C, std::unique_ptr MAB, + std::unique_ptr MOW, + std::unique_ptr MCE) + : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} +}; +} // end namespace + +namespace llvm { +MCELFStreamer *createLoongArchELFStreamer(MCContext &C, + std::unique_ptr MAB, + std::unique_ptr MOW, + std::unique_ptr MCE, + bool RelaxAll) { + LoongArchELFStreamer *S = new LoongArchELFStreamer( + C, std::move(MAB), std::move(MOW), std::move(MCE)); + S->getAssembler().setRelaxAll(RelaxAll); + return S; +} +} // end namespace llvm diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp @@ -12,13 +12,17 @@ #include "LoongArchMCTargetDesc.h" #include "LoongArchBaseInfo.h" +#include "LoongArchELFStreamer.h" #include "LoongArchInstPrinter.h" #include "LoongArchMCAsmInfo.h" #include "TargetInfo/LoongArchTargetInfo.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" @@ -76,6 +80,13 @@ return new LoongArchInstPrinter(MAI, MII, MRI); } +static MCTargetStreamer * +createLoongArchObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + return STI.getTargetTriple().isOSBinFormatELF() + ? new LoongArchTargetELFStreamer(S, STI) + : nullptr; +} + namespace { class LoongArchMCInstrAnalysis : public MCInstrAnalysis { @@ -101,6 +112,17 @@ return new LoongArchMCInstrAnalysis(Info); } +namespace { +MCStreamer *createLoongArchELFStreamer(const Triple &T, MCContext &Context, + std::unique_ptr &&MAB, + std::unique_ptr &&MOW, + std::unique_ptr &&MCE, + bool RelaxAll) { + return createLoongArchELFStreamer(Context, std::move(MAB), std::move(MOW), + std::move(MCE), RelaxAll); +} +} // end namespace + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTargetMC() { for (Target *T : {&getTheLoongArch32Target(), &getTheLoongArch64Target()}) { TargetRegistry::RegisterMCRegInfo(*T, createLoongArchMCRegisterInfo); @@ -111,5 +133,8 @@ TargetRegistry::RegisterMCAsmBackend(*T, createLoongArchAsmBackend); TargetRegistry::RegisterMCInstPrinter(*T, createLoongArchMCInstPrinter); TargetRegistry::RegisterMCInstrAnalysis(*T, createLoongArchInstrAnalysis); + TargetRegistry::RegisterELFStreamer(*T, createLoongArchELFStreamer); + TargetRegistry::RegisterObjectTargetStreamer( + *T, createLoongArchObjectTargetStreamer); } } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h @@ -0,0 +1,27 @@ +//===-- LoongArchTargetStreamer.h - LoongArch Target Streamer --*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHTARGETSTREAMER_H +#define LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_LOONGARCHTARGETSTREAMER_H + +#include "LoongArch.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" + +namespace llvm { +class LoongArchTargetStreamer : public MCTargetStreamer { + LoongArchABI::ABI TargetABI = LoongArchABI::ABI_Unknown; + +public: + LoongArchTargetStreamer(MCStreamer &S); + void setTargetABI(LoongArchABI::ABI ABI); + LoongArchABI::ABI getTargetABI() const { return TargetABI; } +}; + +} // end namespace llvm +#endif diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp @@ -0,0 +1,24 @@ +//===-- LoongArchTargetStreamer.cpp - LoongArch Target Streamer Methods ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides LoongArch specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "LoongArchTargetStreamer.h" + +using namespace llvm; + +LoongArchTargetStreamer::LoongArchTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S) {} + +void LoongArchTargetStreamer::setTargetABI(LoongArchABI::ABI ABI) { + assert(ABI != LoongArchABI::ABI_Unknown && + "Improperly initialized target ABI"); + TargetABI = ABI; +} diff --git a/llvm/test/CodeGen/LoongArch/e_flags.ll b/llvm/test/CodeGen/LoongArch/e_flags.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/e_flags.ll @@ -0,0 +1,15 @@ +; RUN: llc --mtriple=loongarch32 --filetype=obj %s -o %t-la32 +; RUN: llvm-readelf -h %t-la32 | FileCheck %s --check-prefix=ILP32D --match-full-lines +; RUN: llc --mtriple=loongarch64 --filetype=obj %s -o %t-la64 +; RUN: llvm-readelf -h %t-la64 | FileCheck %s --check-prefix=LP64D --match-full-lines + +;; Note that we have not support the -target-abi option to select specific ABI. +;; See comments in LoongArchELFStreamer.cpp. So here we only check the default behaviour. +;; After -target-abi is supported, we can add more tests. + +; LP64D: Flags: 0x3, LP64, DOUBLE-FLOAT +; ILP32D: Flags: 0x7, ILP32, DOUBLE-FLOAT + +define void @foo() { + ret void +}