From 87df1ee784b22df68bc35d59c670be49d018d3ca Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:02 +0300 Subject: [PATCH 001/150] [Xtensa] Recognize Xtensa in triple parsing code. --- llvm/include/llvm/ADT/Triple.h | 1 + llvm/lib/Support/Triple.cpp | 11 +++++++++++ llvm/unittests/ADT/TripleTest.cpp | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index ba4584dc60faf..71c15b1a86ee6 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -85,6 +85,7 @@ class Triple { x86, // X86: i[3-9]86 x86_64, // X86-64: amd64, x86_64 xcore, // XCore: xcore + xtensa, // Tensilica Xtensa nvptx, // NVPTX: 32-bit nvptx64, // NVPTX: 64-bit le32, // le32: generic little-endian 32-bit CPU (PNaCl) diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index 6696d158b2c1a..9377df8fee9f6 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -83,6 +83,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case x86: return "i386"; case x86_64: return "x86_64"; case xcore: return "xcore"; + case xtensa: return "xtensa"; } llvm_unreachable("Invalid ArchType!"); @@ -172,6 +173,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case loongarch64: return "loongarch"; case dxil: return "dx"; + + case xtensa: return "xtensa"; } } @@ -371,6 +374,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("loongarch32", loongarch32) .Case("loongarch64", loongarch64) .Case("dxil", dxil) + .Case("xtensa", xtensa) .Default(UnknownArch); } @@ -511,6 +515,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("loongarch32", Triple::loongarch32) .Case("loongarch64", Triple::loongarch64) .Case("dxil", Triple::dxil) + .Case("xtensa", Triple::xtensa) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the @@ -835,6 +840,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::thumbeb: case Triple::ve: case Triple::xcore: + case Triple::xtensa: return Triple::ELF; case Triple::ppc64: @@ -1411,6 +1417,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::wasm32: case llvm::Triple::x86: case llvm::Triple::xcore: + case llvm::Triple::xtensa: return 32; case llvm::Triple::aarch64: @@ -1501,6 +1508,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::wasm32: case Triple::x86: case Triple::xcore: + case Triple::xtensa: // Already 32-bit. break; @@ -1551,6 +1559,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::tce: case Triple::tcele: case Triple::xcore: + case Triple::xtensa: T.setArch(UnknownArch); break; @@ -1651,6 +1660,7 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::xcore: case Triple::ve: case Triple::csky: + case Triple::xtensa: // ARM is intentionally unsupported here, changing the architecture would // drop any arch suffixes. @@ -1760,6 +1770,7 @@ bool Triple::isLittleEndian() const { case Triple::x86: case Triple::x86_64: case Triple::xcore: + case Triple::xtensa: return true; default: return false; diff --git a/llvm/unittests/ADT/TripleTest.cpp b/llvm/unittests/ADT/TripleTest.cpp index 3b6a582c42fd1..55e2512cb91f9 100644 --- a/llvm/unittests/ADT/TripleTest.cpp +++ b/llvm/unittests/ADT/TripleTest.cpp @@ -790,6 +790,18 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::ShaderModel, T.getOS()); EXPECT_EQ(Triple::Amplification, T.getEnvironment()); + T = Triple("xtensa"); + EXPECT_EQ(Triple::xtensa, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::UnknownOS, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + + T = Triple("xtensa-unknown-unknown"); + EXPECT_EQ(Triple::xtensa, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::UnknownOS, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("huh"); EXPECT_EQ(Triple::UnknownArch, T.getArch()); } @@ -1151,6 +1163,11 @@ TEST(TripleTest, BitWidthPredicates) { EXPECT_TRUE(T.isArch32Bit()); EXPECT_FALSE(T.isArch64Bit()); EXPECT_TRUE(T.isDXIL()); + + T.setArch(Triple::xtensa); + EXPECT_FALSE(T.isArch16Bit()); + EXPECT_TRUE(T.isArch32Bit()); + EXPECT_FALSE(T.isArch64Bit()); } TEST(TripleTest, BitWidthArchVariants) { @@ -1345,6 +1362,10 @@ TEST(TripleTest, BitWidthArchVariants) { T.setArch(Triple::dxil); EXPECT_EQ(Triple::dxil, T.get32BitArchVariant().getArch()); EXPECT_EQ(Triple::UnknownArch, T.get64BitArchVariant().getArch()); + + T.setArch(Triple::xtensa); + EXPECT_EQ(Triple::xtensa, T.get32BitArchVariant().getArch()); + EXPECT_EQ(Triple::UnknownArch, T.get64BitArchVariant().getArch()); } TEST(TripleTest, EndianArchVariants) { From 0def3c206168e2359b921222a62d8a485011bd68 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:02 +0300 Subject: [PATCH 002/150] [Xtensa] Add definitions and relocs for Xtensa ELF. --- llvm/include/llvm/BinaryFormat/ELF.h | 15 ++ .../llvm/BinaryFormat/ELFRelocs/Xtensa.def | 59 ++++++ llvm/include/llvm/Object/ELFObjectFile.h | 5 + llvm/include/llvm/module.modulemap | 1 + llvm/lib/Object/ELF.cpp | 7 + llvm/lib/ObjectYAML/ELFYAML.cpp | 8 + llvm/test/Object/obj2yaml.test | 21 +- .../llvm-readobj/ELF/reloc-types-xtensa.test | 182 ++++++++++++++++++ .../llvm-readobj/ELF/xtensa-header-flags.test | 20 ++ llvm/tools/llvm-readobj/ELFDumper.cpp | 12 ++ llvm/unittests/Object/ELFObjectFileTest.cpp | 8 + 11 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def create mode 100644 llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test create mode 100644 llvm/test/tools/llvm-readobj/ELF/xtensa-header-flags.test diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 99e7a9868c296..aca8d5ccd23c4 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -925,6 +925,21 @@ enum { #include "ELFRelocs/LoongArch.def" }; +// Xtensa specific e_flags +enum : unsigned { + // Four-bit Xtensa machine type mask. + EF_XTENSA_MACH = 0x0000000f, + // Various CPU types. + EF_XTENSA_MACH_NONE = 0x00000000, // A base Xtensa implementation + EF_XTENSA_XT_INSN = 0x00000100, + EF_XTENSA_XT_LIT = 0x00000200, +}; + +// ELF Relocation types for Xtensa +enum { +#include "ELFRelocs/Xtensa.def" +}; + #undef ELF_RELOC // Section header. diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def new file mode 100644 index 0000000000000..51df120bb9ada --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def @@ -0,0 +1,59 @@ +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +ELF_RELOC(R_XTENSA_NONE, 0) +ELF_RELOC(R_XTENSA_32, 1) +ELF_RELOC(R_XTENSA_RTLD, 2) +ELF_RELOC(R_XTENSA_GLOB_DAT, 3) +ELF_RELOC(R_XTENSA_JMP_SLOT, 4) +ELF_RELOC(R_XTENSA_RELATIVE, 5) +ELF_RELOC(R_XTENSA_PLT, 6) +ELF_RELOC(R_XTENSA_OP0, 8) +ELF_RELOC(R_XTENSA_OP1, 9) +ELF_RELOC(R_XTENSA_OP2, 10) +ELF_RELOC(R_XTENSA_ASM_EXPAND, 11) +ELF_RELOC(R_XTENSA_ASM_SIMPLIFY, 12) +ELF_RELOC(R_XTENSA_32_PCREL, 14) +ELF_RELOC(R_XTENSA_GNU_VTINHERIT, 15) +ELF_RELOC(R_XTENSA_GNU_VTENTRY, 16) +ELF_RELOC(R_XTENSA_DIFF8, 17) +ELF_RELOC(R_XTENSA_DIFF16, 18) +ELF_RELOC(R_XTENSA_DIFF32, 19) +ELF_RELOC(R_XTENSA_SLOT0_OP, 20) +ELF_RELOC(R_XTENSA_SLOT1_OP, 21) +ELF_RELOC(R_XTENSA_SLOT2_OP, 22) +ELF_RELOC(R_XTENSA_SLOT3_OP, 23) +ELF_RELOC(R_XTENSA_SLOT4_OP, 24) +ELF_RELOC(R_XTENSA_SLOT5_OP, 25) +ELF_RELOC(R_XTENSA_SLOT6_OP, 26) +ELF_RELOC(R_XTENSA_SLOT7_OP, 27) +ELF_RELOC(R_XTENSA_SLOT8_OP, 28) +ELF_RELOC(R_XTENSA_SLOT9_OP, 29) +ELF_RELOC(R_XTENSA_SLOT10_OP, 30) +ELF_RELOC(R_XTENSA_SLOT11_OP, 31) +ELF_RELOC(R_XTENSA_SLOT12_OP, 32) +ELF_RELOC(R_XTENSA_SLOT13_OP, 33) +ELF_RELOC(R_XTENSA_SLOT14_OP, 34) +ELF_RELOC(R_XTENSA_SLOT0_ALT, 35) +ELF_RELOC(R_XTENSA_SLOT1_ALT, 36) +ELF_RELOC(R_XTENSA_SLOT2_ALT, 37) +ELF_RELOC(R_XTENSA_SLOT3_ALT, 38) +ELF_RELOC(R_XTENSA_SLOT4_ALT, 39) +ELF_RELOC(R_XTENSA_SLOT5_ALT, 40) +ELF_RELOC(R_XTENSA_SLOT6_ALT, 41) +ELF_RELOC(R_XTENSA_SLOT7_ALT, 42) +ELF_RELOC(R_XTENSA_SLOT8_ALT, 43) +ELF_RELOC(R_XTENSA_SLOT9_ALT, 44) +ELF_RELOC(R_XTENSA_SLOT10_ALT, 45) +ELF_RELOC(R_XTENSA_SLOT11_ALT, 46) +ELF_RELOC(R_XTENSA_SLOT12_ALT, 47) +ELF_RELOC(R_XTENSA_SLOT13_ALT, 48) +ELF_RELOC(R_XTENSA_SLOT14_ALT, 49) +ELF_RELOC(R_XTENSA_TLSDESC_FN, 50) +ELF_RELOC(R_XTENSA_TLSDESC_ARG, 51) +ELF_RELOC(R_XTENSA_TLS_DTPOFF, 52) +ELF_RELOC(R_XTENSA_TLS_TPOFF, 53) +ELF_RELOC(R_XTENSA_TLS_FUNC, 54) +ELF_RELOC(R_XTENSA_TLS_ARG, 55) +ELF_RELOC(R_XTENSA_TLS_CALL, 56) diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index ed2f70b0da251..0dfa00fe0e5cb 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -1213,6 +1213,8 @@ StringRef ELFObjectFile::getFileFormatName() const { return "elf32-amdgpu"; case ELF::EM_LOONGARCH: return "elf32-loongarch"; + case ELF::EM_XTENSA: + return "elf32-xtensa"; default: return "elf32-unknown"; } @@ -1337,6 +1339,9 @@ template Triple::ArchType ELFObjectFile::getArch() const { report_fatal_error("Invalid ELFCLASS!"); } + case ELF::EM_XTENSA: + return Triple::xtensa; + default: return Triple::UnknownArch; } diff --git a/llvm/include/llvm/module.modulemap b/llvm/include/llvm/module.modulemap index 76b10621541c4..80e0954242d46 100644 --- a/llvm/include/llvm/module.modulemap +++ b/llvm/include/llvm/module.modulemap @@ -83,6 +83,7 @@ module LLVM_BinaryFormat { textual header "BinaryFormat/ELFRelocs/SystemZ.def" textual header "BinaryFormat/ELFRelocs/VE.def" textual header "BinaryFormat/ELFRelocs/x86_64.def" + textual header "BinaryFormat/ELFRelocs/Xtensa.def" textual header "BinaryFormat/WasmRelocs.def" textual header "BinaryFormat/MsgPack.def" } diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 0d5aa91c1348e..b03f708432cc7 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -173,6 +173,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_XTENSA: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/Xtensa.def" + default: + break; + } + break; default: break; } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 9ad2c41351672..e286c189aea00 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -535,6 +535,11 @@ void ScalarBitSetTraits::bitset(IO &IO, BCase(EF_RISCV_RVE); BCase(EF_RISCV_TSO); break; + case ELF::EM_XTENSA: + BCase(EF_XTENSA_XT_INSN); + BCaseMask(EF_XTENSA_MACH_NONE, EF_XTENSA_MACH); + BCase(EF_XTENSA_XT_LIT); + break; case ELF::EM_AMDGPU: BCaseMask(EF_AMDGPU_MACH_NONE, EF_AMDGPU_MACH); BCaseMask(EF_AMDGPU_MACH_R600_R600, EF_AMDGPU_MACH); @@ -892,6 +897,9 @@ void ScalarEnumerationTraits::enumeration( case ELF::EM_LOONGARCH: #include "llvm/BinaryFormat/ELFRelocs/LoongArch.def" break; + case ELF::EM_XTENSA: +#include "llvm/BinaryFormat/ELFRelocs/Xtensa.def" + break; default: // Nothing to do. break; diff --git a/llvm/test/Object/obj2yaml.test b/llvm/test/Object/obj2yaml.test index 05860471e9126..f07172595173f 100644 --- a/llvm/test/Object/obj2yaml.test +++ b/llvm/test/Object/obj2yaml.test @@ -547,7 +547,7 @@ # ELF-MIPS64EL-NEXT: Binding: STB_GLOBAL # ELF-MIPS64EL-NEXT: ... -# RUN: yaml2obj %s -o %t-x86-64 +# RUN: yaml2obj --docnum=1 %s -o %t-x86-64 # RUN: obj2yaml %t-x86-64 | FileCheck %s --check-prefix ELF-X86-64 # ELF-X86-64: FileHeader: @@ -678,6 +678,25 @@ Symbols: - Name: puts Binding: STB_GLOBAL +# RUN: yaml2obj --docnum=2 %s -o %t-xtensa +# RUN: obj2yaml %t-xtensa | FileCheck %s --check-prefix ELF-XTENSA + +# ELF-XTENSA: FileHeader: +# ELF-XTENSA-NEXT: Class: ELFCLASS32 +# ELF-XTENSA-NEXT: Data: ELFDATA2LSB +# ELF-XTENSA-NEXT: Type: ET_EXEC +# ELF-XTENSA-NEXT: Machine: EM_XTENSA +## As EF_XTENSA_MACH_NONE == 0, it is always printed by obj2yaml. +# ELF-XTENSA-NEXT: Flags: [ EF_XTENSA_XT_INSN, EF_XTENSA_MACH_NONE, EF_XTENSA_XT_LIT ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_XTENSA + Flags: [ EF_XTENSA_XT_INSN, EF_XTENSA_XT_LIT ] + # RUN: obj2yaml %p/Inputs/trivial-object-test.elf-avr | FileCheck %s --check-prefix ELF-AVR # ELF-AVR: FileHeader: diff --git a/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test b/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test new file mode 100644 index 0000000000000..0356e4f53d48f --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/reloc-types-xtensa.test @@ -0,0 +1,182 @@ +## Test that llvm-readobj shows proper relocation type +## names and values for the Xtensa target. + +# RUN: yaml2obj %s -o %t-xtensa.o +# RUN: llvm-readobj -r %t-xtensa.o | FileCheck %s + +# CHECK: 0x0 R_XTENSA_NONE - 0x0 +# CHECK-NEXT: 0x4 R_XTENSA_32 - 0x0 +# CHECK-NEXT: 0x8 R_XTENSA_RTLD - 0x0 +# CHECK-NEXT: 0xC R_XTENSA_GLOB_DAT - 0x0 +# CHECK-NEXT: 0x10 R_XTENSA_JMP_SLOT - 0x0 +# CHECK-NEXT: 0x14 R_XTENSA_RELATIVE - 0x0 +# CHECK-NEXT: 0x18 R_XTENSA_PLT - 0x0 +# CHECK-NEXT: 0x1C R_XTENSA_OP0 - 0x0 +# CHECK-NEXT: 0x20 R_XTENSA_OP1 - 0x0 +# CHECK-NEXT: 0x24 R_XTENSA_OP2 - 0x0 +# CHECK-NEXT: 0x28 R_XTENSA_ASM_EXPAND - 0x0 +# CHECK-NEXT: 0x2C R_XTENSA_ASM_SIMPLIFY - 0x0 +# CHECK-NEXT: 0x30 R_XTENSA_32_PCREL - 0x0 +# CHECK-NEXT: 0x34 R_XTENSA_GNU_VTINHERIT - 0x0 +# CHECK-NEXT: 0x38 R_XTENSA_GNU_VTENTRY - 0x0 +# CHECK-NEXT: 0x3C R_XTENSA_DIFF8 - 0x0 +# CHECK-NEXT: 0x40 R_XTENSA_DIFF16 - 0x0 +# CHECK-NEXT: 0x44 R_XTENSA_DIFF32 - 0x0 +# CHECK-NEXT: 0x48 R_XTENSA_SLOT0_OP - 0x0 +# CHECK-NEXT: 0x4C R_XTENSA_SLOT1_OP - 0x0 +# CHECK-NEXT: 0x50 R_XTENSA_SLOT2_OP - 0x0 +# CHECK-NEXT: 0x54 R_XTENSA_SLOT3_OP - 0x0 +# CHECK-NEXT: 0x58 R_XTENSA_SLOT4_OP - 0x0 +# CHECK-NEXT: 0x5C R_XTENSA_SLOT5_OP - 0x0 +# CHECK-NEXT: 0x60 R_XTENSA_SLOT6_OP - 0x0 +# CHECK-NEXT: 0x64 R_XTENSA_SLOT7_OP - 0x0 +# CHECK-NEXT: 0x68 R_XTENSA_SLOT8_OP - 0x0 +# CHECK-NEXT: 0x6C R_XTENSA_SLOT9_OP - 0x0 +# CHECK-NEXT: 0x70 R_XTENSA_SLOT10_OP - 0x0 +# CHECK-NEXT: 0x74 R_XTENSA_SLOT11_OP - 0x0 +# CHECK-NEXT: 0x78 R_XTENSA_SLOT12_OP - 0x0 +# CHECK-NEXT: 0x7C R_XTENSA_SLOT13_OP - 0x0 +# CHECK-NEXT: 0x80 R_XTENSA_SLOT14_OP - 0x0 +# CHECK-NEXT: 0x84 R_XTENSA_SLOT0_ALT - 0x0 +# CHECK-NEXT: 0x88 R_XTENSA_SLOT1_ALT - 0x0 +# CHECK-NEXT: 0x8C R_XTENSA_SLOT2_ALT - 0x0 +# CHECK-NEXT: 0x90 R_XTENSA_SLOT3_ALT - 0x0 +# CHECK-NEXT: 0x94 R_XTENSA_SLOT4_ALT - 0x0 +# CHECK-NEXT: 0x98 R_XTENSA_SLOT5_ALT - 0x0 +# CHECK-NEXT: 0x9C R_XTENSA_SLOT6_ALT - 0x0 +# CHECK-NEXT: 0xA0 R_XTENSA_SLOT7_ALT - 0x0 +# CHECK-NEXT: 0xA4 R_XTENSA_SLOT8_ALT - 0x0 +# CHECK-NEXT: 0xA8 R_XTENSA_SLOT9_ALT - 0x0 +# CHECK-NEXT: 0xAC R_XTENSA_SLOT10_ALT - 0x0 +# CHECK-NEXT: 0xB0 R_XTENSA_SLOT11_ALT - 0x0 +# CHECK-NEXT: 0xB4 R_XTENSA_SLOT12_ALT - 0x0 +# CHECK-NEXT: 0xB8 R_XTENSA_SLOT13_ALT - 0x0 +# CHECK-NEXT: 0xBC R_XTENSA_SLOT14_ALT - 0x0 +# CHECK-NEXT: 0xC0 R_XTENSA_TLSDESC_FN - 0x0 +# CHECK-NEXT: 0xC4 R_XTENSA_TLSDESC_ARG - 0x0 +# CHECK-NEXT: 0xC8 R_XTENSA_TLS_DTPOFF - 0x0 +# CHECK-NEXT: 0xCC R_XTENSA_TLS_TPOFF - 0x0 +# CHECK-NEXT: 0xD0 R_XTENSA_TLS_FUNC - 0x0 +# CHECK-NEXT: 0xD4 R_XTENSA_TLS_ARG - 0x0 +# CHECK-NEXT: 0xD8 R_XTENSA_TLS_CALL - 0x0 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_XTENSA +Sections: + - Name: .rela.text + Type: SHT_RELA + Relocations: + - Offset: 0x0000000000000000 + Type: R_XTENSA_NONE + - Offset: 0x0000000000000004 + Type: R_XTENSA_32 + - Offset: 0x0000000000000008 + Type: R_XTENSA_RTLD + - Offset: 0x000000000000000C + Type: R_XTENSA_GLOB_DAT + - Offset: 0x0000000000000010 + Type: R_XTENSA_JMP_SLOT + - Offset: 0x0000000000000014 + Type: R_XTENSA_RELATIVE + - Offset: 0x0000000000000018 + Type: R_XTENSA_PLT + - Offset: 0x000000000000001C + Type: R_XTENSA_OP0 + - Offset: 0x0000000000000020 + Type: R_XTENSA_OP1 + - Offset: 0x0000000000000024 + Type: R_XTENSA_OP2 + - Offset: 0x0000000000000028 + Type: R_XTENSA_ASM_EXPAND + - Offset: 0x000000000000002C + Type: R_XTENSA_ASM_SIMPLIFY + - Offset: 0x0000000000000030 + Type: R_XTENSA_32_PCREL + - Offset: 0x0000000000000034 + Type: R_XTENSA_GNU_VTINHERIT + - Offset: 0x0000000000000038 + Type: R_XTENSA_GNU_VTENTRY + - Offset: 0x000000000000003C + Type: R_XTENSA_DIFF8 + - Offset: 0x0000000000000040 + Type: R_XTENSA_DIFF16 + - Offset: 0x0000000000000044 + Type: R_XTENSA_DIFF32 + - Offset: 0x0000000000000048 + Type: R_XTENSA_SLOT0_OP + - Offset: 0x000000000000004C + Type: R_XTENSA_SLOT1_OP + - Offset: 0x0000000000000050 + Type: R_XTENSA_SLOT2_OP + - Offset: 0x0000000000000054 + Type: R_XTENSA_SLOT3_OP + - Offset: 0x0000000000000058 + Type: R_XTENSA_SLOT4_OP + - Offset: 0x000000000000005C + Type: R_XTENSA_SLOT5_OP + - Offset: 0x0000000000000060 + Type: R_XTENSA_SLOT6_OP + - Offset: 0x0000000000000064 + Type: R_XTENSA_SLOT7_OP + - Offset: 0x0000000000000068 + Type: R_XTENSA_SLOT8_OP + - Offset: 0x000000000000006C + Type: R_XTENSA_SLOT9_OP + - Offset: 0x0000000000000070 + Type: R_XTENSA_SLOT10_OP + - Offset: 0x0000000000000074 + Type: R_XTENSA_SLOT11_OP + - Offset: 0x0000000000000078 + Type: R_XTENSA_SLOT12_OP + - Offset: 0x000000000000007C + Type: R_XTENSA_SLOT13_OP + - Offset: 0x0000000000000080 + Type: R_XTENSA_SLOT14_OP + - Offset: 0x0000000000000084 + Type: R_XTENSA_SLOT0_ALT + - Offset: 0x0000000000000088 + Type: R_XTENSA_SLOT1_ALT + - Offset: 0x000000000000008C + Type: R_XTENSA_SLOT2_ALT + - Offset: 0x0000000000000090 + Type: R_XTENSA_SLOT3_ALT + - Offset: 0x0000000000000094 + Type: R_XTENSA_SLOT4_ALT + - Offset: 0x0000000000000098 + Type: R_XTENSA_SLOT5_ALT + - Offset: 0x000000000000009C + Type: R_XTENSA_SLOT6_ALT + - Offset: 0x00000000000000A0 + Type: R_XTENSA_SLOT7_ALT + - Offset: 0x00000000000000A4 + Type: R_XTENSA_SLOT8_ALT + - Offset: 0x00000000000000A8 + Type: R_XTENSA_SLOT9_ALT + - Offset: 0x00000000000000AC + Type: R_XTENSA_SLOT10_ALT + - Offset: 0x00000000000000B0 + Type: R_XTENSA_SLOT11_ALT + - Offset: 0x00000000000000B4 + Type: R_XTENSA_SLOT12_ALT + - Offset: 0x00000000000000B8 + Type: R_XTENSA_SLOT13_ALT + - Offset: 0x00000000000000BC + Type: R_XTENSA_SLOT14_ALT + - Offset: 0x00000000000000C0 + Type: R_XTENSA_TLSDESC_FN + - Offset: 0x00000000000000C4 + Type: R_XTENSA_TLSDESC_ARG + - Offset: 0x00000000000000C8 + Type: R_XTENSA_TLS_DTPOFF + - Offset: 0x00000000000000CC + Type: R_XTENSA_TLS_TPOFF + - Offset: 0x00000000000000D0 + Type: R_XTENSA_TLS_FUNC + - Offset: 0x00000000000000D4 + Type: R_XTENSA_TLS_ARG + - Offset: 0x00000000000000D8 + Type: R_XTENSA_TLS_CALL diff --git a/llvm/test/tools/llvm-readobj/ELF/xtensa-header-flags.test b/llvm/test/tools/llvm-readobj/ELF/xtensa-header-flags.test new file mode 100644 index 0000000000000..a7934370940e3 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/xtensa-header-flags.test @@ -0,0 +1,20 @@ +## Check that we are able to dump EF_XTENSA_XT_* flags correctly + +# RUN: yaml2obj %s -o %t.insn -DFLAG=INSN +# RUN: llvm-readobj -S --file-headers %t.insn | FileCheck --check-prefixes=ALL,INSN %s + +# RUN: yaml2obj %s -o %t.lit -DFLAG=LIT +# RUN: llvm-readobj -S --file-headers %t.lit | FileCheck --check-prefixes=ALL,LIT %s + +# ALL: Flags [ +# INSN: EF_XTENSA_XT_INSN (0x100) +# LIT: EF_XTENSA_XT_LIT (0x200) +# ALL: ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_XTENSA + Flags: [ EF_XTENSA_XT_[[FLAG]] ] diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index ba7bae96ade36..addb9a226e900 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1657,6 +1657,12 @@ const EnumEntry ElfHeaderLoongArchFlags[] = { ENUM_ENT(EF_LOONGARCH_BASE_ABI_LP64D, "LP64, DOUBLE-FLOAT"), }; +static const EnumEntry ElfHeaderXtensaFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_MACH_NONE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_XT_INSN), + LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_XT_LIT) +}; + const EnumEntry ElfSymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL), @@ -3369,6 +3375,9 @@ template void GNUELFDumper::printFileHeaders() { else if (e.e_machine == EM_LOONGARCH) ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderLoongArchFlags), unsigned(ELF::EF_LOONGARCH_BASE_ABI_MASK)); + else if (e.e_machine == EM_XTENSA) + ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderXtensaFlags), + unsigned(ELF::EF_XTENSA_MACH)); Str = "0x" + utohexstr(e.e_flags); if (!ElfFlags.empty()) Str = Str + ", " + ElfFlags; @@ -6522,6 +6531,9 @@ template void LLVMELFDumper::printFileHeaders() { else if (E.e_machine == EM_LOONGARCH) W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderLoongArchFlags), unsigned(ELF::EF_LOONGARCH_BASE_ABI_MASK)); + else if (E.e_machine == EM_XTENSA) + W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderXtensaFlags), + unsigned(ELF::EF_XTENSA_MACH)); else W.printFlags("Flags", E.e_flags); W.printNumber("HeaderSize", E.e_ehsize); diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp index 877a140f969a7..25aa1f3b2606b 100644 --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -310,6 +310,14 @@ TEST(ELFObjectFileTest, MachineTestForCSKY) { checkFormatAndArch(D, Formats[I++], Triple::csky); } +TEST(ELFObjectFileTest, MachineTestForXtensa) { + std::array Formats = {"elf32-xtensa", "elf32-xtensa", + "elf64-unknown", "elf64-unknown"}; + size_t I = 0; + for (const DataForTest &D : generateData(ELF::EM_XTENSA)) + checkFormatAndArch(D, Formats[I++], Triple::xtensa); +} + // ELF relative relocation type test. TEST(ELFObjectFileTest, RelativeRelocationTypeTest) { EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY)); From 41bfeb85e375c3f79aad505a2fb63a8146549acc Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:03 +0300 Subject: [PATCH 003/150] [Xtensa] Add initial version of the Xtensa backend. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 18 +++++ .../Target/Xtensa/MCTargetDesc/CMakeLists.txt | 11 +++ .../MCTargetDesc/XtensaMCTargetDesc.cpp | 13 ++++ .../Xtensa/MCTargetDesc/XtensaMCTargetDesc.h | 18 +++++ .../Target/Xtensa/TargetInfo/CMakeLists.txt | 11 +++ .../Xtensa/TargetInfo/XtensaTargetInfo.cpp | 20 ++++++ .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 70 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaTargetMachine.h | 48 +++++++++++++ 8 files changed, 209 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/CMakeLists.txt create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h create mode 100644 llvm/lib/Target/Xtensa/TargetInfo/CMakeLists.txt create mode 100644 llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaTargetMachine.h diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt new file mode 100644 index 0000000000000..83fb0f15dd536 --- /dev/null +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -0,0 +1,18 @@ +add_llvm_component_group(Xtensa) + +add_llvm_target(XtensaCodeGen + XtensaTargetMachine.cpp + + LINK_COMPONENTS + CodeGen + Core + Support + Target + XtensaInfo + + ADD_TO_COMPONENT + Xtensa + ) + +add_subdirectory(MCTargetDesc) +add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt new file mode 100644 index 0000000000000..0febab437acb3 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,11 @@ +add_llvm_component_library(LLVMXtensaDesc + XtensaMCTargetDesc.cpp + + LINK_COMPONENTS + MC + Support + XtensaInfo + + ADD_TO_COMPONENT + Xtensa + ) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp new file mode 100644 index 0000000000000..c9c0996b07a94 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -0,0 +1,13 @@ +//===-- XtensaMCTargetDesc.cpp - Xtebsa target descriptions ---------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// +#include "XtensaMCTargetDesc.h" + +// We need to define this function for linking succeed +extern "C" void LLVMInitializeXtensaTargetMC() {} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h new file mode 100644 index 0000000000000..d3a9a24de4084 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h @@ -0,0 +1,18 @@ +//===-- XtensaMCTargetDesc.h - Xtensa Target Descriptions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 Xtensa specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H +#define LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H + +#endif /* LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H */ diff --git a/llvm/lib/Target/Xtensa/TargetInfo/CMakeLists.txt b/llvm/lib/Target/Xtensa/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000000000..870f875ccfdd0 --- /dev/null +++ b/llvm/lib/Target/Xtensa/TargetInfo/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_component_library(LLVMXtensaInfo + XtensaTargetInfo.cpp + + LINK_COMPONENTS + Support + + ADD_TO_COMPONENT + Xtensa + ) diff --git a/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp b/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp new file mode 100644 index 0000000000000..349dcafdd5d15 --- /dev/null +++ b/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp @@ -0,0 +1,20 @@ +//===-- XtensaTargetInfo.cpp - Xtensa Target Implementation ---------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; +namespace llvm { +Target TheXtensaTarget; +} +extern "C" void LLVMInitializeXtensaTargetInfo() { + RegisterTarget X(TheXtensaTarget, "xtensa", "Xtensa 32", + "XTENSA"); +} diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp new file mode 100644 index 0000000000000..bc257be92d802 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -0,0 +1,70 @@ +//===- XtensaTargetMachine.cpp - Define TargetMachine for Xtensa ----------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implements the info about Xtensa target spec. +// +//===----------------------------------------------------------------------===// + +#include "XtensaTargetMachine.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Scalar.h" + +using namespace llvm; + +extern "C" void LLVMInitializeXtensaTarget() { + // Register the target. + RegisterTargetMachine A(TheXtensaTarget); +} + +static std::string computeDataLayout(const Triple &TT, StringRef CPU, + const TargetOptions &Options, + bool IsLittle) { + std::string Ret = "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32"; + + return Ret; +} + +static Reloc::Model getEffectiveRelocModel(bool JIT, + Optional RM) { + if (!RM.hasValue() || JIT) + return Reloc::Static; + return *RM; +} + +XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Optional RM, + Optional CM, + CodeGenOpt::Level OL, bool JIT, + bool IsLittle) + : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, IsLittle), TT, + CPU, FS, Options, getEffectiveRelocModel(JIT, RM), + getEffectiveCodeModel(CM, CodeModel::Small), OL), + TLOF(std::make_unique()) { + initAsmInfo(); +} + +XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Optional RM, + Optional CM, + CodeGenOpt::Level OL, bool JIT) + : XtensaTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {} + +TargetPassConfig *XtensaTargetMachine::createPassConfig(PassManagerBase &PM) { + return new TargetPassConfig(*this, PM); +} diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.h b/llvm/lib/Target/Xtensa/XtensaTargetMachine.h new file mode 100644 index 0000000000000..cf1a064a730b4 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.h @@ -0,0 +1,48 @@ +//===-- XtensaTargetMachine.h - Define TargetMachine for Xtensa -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 declares the Xtensa specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSATARGETMACHINE_H +#define LLVM_LIB_TARGET_XTENSA_XTENSATARGETMACHINE_H + +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class TargetFrameLowering; + +extern Target TheXtensaTarget; + +class XtensaTargetMachine : public LLVMTargetMachine { + std::unique_ptr TLOF; + +public: + XtensaTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Optional RM, Optional CM, + CodeGenOpt::Level OL, bool JIT, bool isLittle); + + XtensaTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Optional RM, Optional CM, + CodeGenOpt::Level OL, bool JIT); + + // Override LLVMTargetMachine + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } +}; +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSATARGETMACHINE_H */ From 7029d2801bd2ce364f7dd47789156a242b093c45 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:03 +0300 Subject: [PATCH 004/150] [Xtensa] Add basic *td files with Xtensa architecture description. Add Xtensa.td, XtensaInstrInfo.td etc. Currently add just part of Core Instructions like ALU, processor control, memory barrier and some move instructions. Add instructions formats and basic registers. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 7 + llvm/lib/Target/Xtensa/Xtensa.td | 52 +++++ llvm/lib/Target/Xtensa/XtensaInstrFormats.td | 221 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 148 +++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 32 +++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 78 +++++++ 6 files changed, 538 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/Xtensa.td create mode 100644 llvm/lib/Target/Xtensa/XtensaInstrFormats.td create mode 100644 llvm/lib/Target/Xtensa/XtensaInstrInfo.td create mode 100644 llvm/lib/Target/Xtensa/XtensaOperands.td create mode 100644 llvm/lib/Target/Xtensa/XtensaRegisterInfo.td diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 83fb0f15dd536..75678b8fe1261 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -1,5 +1,12 @@ add_llvm_component_group(Xtensa) +set(LLVM_TARGET_DEFINITIONS Xtensa.td) + +tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) + +add_public_tablegen_target(XtensaCommonTableGen) + add_llvm_target(XtensaCodeGen XtensaTargetMachine.cpp diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td new file mode 100644 index 0000000000000..830fdec9860c9 --- /dev/null +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -0,0 +1,52 @@ +//===- Xtensa.td - Describe the Xtensa Target Machine ------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Subtarget Features. +//===----------------------------------------------------------------------===// +def FeatureDensity : SubtargetFeature<"density", "HasDensity", "true", + "Enable Density instructions">; +def HasDensity : Predicate<"Subtarget->hasDensity()">, + AssemblerPredicate<(all_of FeatureDensity)>; +//===----------------------------------------------------------------------===// +// Xtensa supported processors. +//===----------------------------------------------------------------------===// +class Proc Features> + : Processor; + +def : Proc<"generic", []>; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "XtensaRegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "XtensaInstrInfo.td" + +def XtensaInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def Xtensa : Target { + let InstructionSet = XtensaInstrInfo; +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrFormats.td b/llvm/lib/Target/Xtensa/XtensaInstrFormats.td new file mode 100644 index 0000000000000..9eba00565fede --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaInstrFormats.td @@ -0,0 +1,221 @@ +//===- XtensaInstrFormats.td - Xtensa Instruction Formats --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Base class for Xtensa 16 & 24 bit Formats +class XtensaInst pattern, + InstrItinClass itin = NoItinerary> + : Instruction { + let Namespace = "Xtensa"; + + let Size = size; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + +} + +// Base class for Xtensa 24 bit Format +class XtensaInst24 pattern, + InstrItinClass itin = NoItinerary> + : XtensaInst<3, outs, ins, asmstr, pattern, itin> { + field bits<24> Inst; + field bits<24> SoftFail = 0; +} + +// Base class for Xtensa 16 bit Format +class XtensaInst16 pattern, + InstrItinClass itin = NoItinerary> + : XtensaInst<2, outs, ins, asmstr, pattern, itin> { + field bits<16> Inst; + field bits<16> SoftFail = 0; + let Predicates = [HasDensity]; +} + +class RRR_Inst op0, bits<4> op1, bits<4> op2, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<4> r; + bits<4> s; + bits<4> t; + + let Inst{23-20} = op2; + let Inst{19-16} = op1; + let Inst{15-12} = r; + let Inst{11-8} = s; + let Inst{7-4} = t; + let Inst{3-0} = op0; +} + +class RRI4_Inst op0, bits<4> op1, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<4> r; + bits<4> s; + bits<4> t; + bits<4> imm4; + + let Inst{23-20} = imm4; + let Inst{19-16} = op1; + let Inst{15-12} = r; + let Inst{11-8} = s; + let Inst{7-4} = t; + let Inst{3-0} = op0; +} + +class RRI8_Inst op0, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<4> r; + bits<4> s; + bits<4> t; + bits<8> imm8; + + let Inst{23-16} = imm8; + let Inst{15-12} = r; + let Inst{11-8} = s; + let Inst{7-4} = t; + let Inst{3-0} = op0; +} + +class RI16_Inst op0, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<4> t; + bits<16> imm16; + + let Inst{23-8} = imm16; + let Inst{7-4} = t; + let Inst{3-0} = op0; +} + +class RSR_Inst op0, bits<4> op1, bits<4> op2, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<8> sr; + bits<4> t; + + let Inst{23-20} = op2; + let Inst{19-16} = op1; + let Inst{15-8} = sr; + let Inst{7-4} = t; + let Inst{3-0} = op0; +} + +class CALL_Inst op0, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<18> offset; + bits<2> n; + + let Inst{23-6} = offset; + let Inst{5-4} = n; + let Inst{3-0} = op0; +} + +class CALLX_Inst op0, bits<4> op1, bits<4> op2, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<4> r; + bits<4> s; + bits<2> m; + bits<2> n; + + let Inst{23-20} = op2; + let Inst{19-16} = op1; + let Inst{15-12} = r; + let Inst{11-8} = s; + let Inst{7-6} = m; + let Inst{5-4} = n; + let Inst{3-0} = op0; +} + +class BRI8_Inst op0, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<8> imm8; + bits<4> r; + bits<4> s; + bits<2> m; + bits<2> n; + + let Inst{23-16} = imm8; + let Inst{15-12} = r; + let Inst{11-8} = s; + let Inst{7-6} = m; + let Inst{5-4} = n; + let Inst{3-0} = op0; +} + +class BRI12_Inst op0, bits<2> n, bits<2> m, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst24 { + bits<12> imm12; + bits<4> s; + + let Inst{23-12} = imm12; + let Inst{11-8} = s; + let Inst{7-6} = m; + let Inst{5-4} = n; + let Inst{3-0} = op0; +} + +class RRRN_Inst op0, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst16 { + bits<4> r; + bits<4> s; + bits<4> t; + + let Inst{15-12} = r; + let Inst{11-8} = s; + let Inst{7-4} = t; + let Inst{3-0} = op0; +} + +class RI7_Inst op0, bits<1> i, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst16 { + bits<7> imm7; + bits<4> s; + + let Inst{15-12} = imm7{3-0}; + let Inst{11-8} = s; + let Inst{7} = i; + let Inst{6-4} = imm7{6-4}; + let Inst{3-0} = op0; +} + +class RI6_Inst op0, bits<1> i, bits<1> z, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : XtensaInst16 { + bits<6> imm6; + bits<4> s; + + let Inst{15-12} = imm6{3-0}; + let Inst{11-8} = s; + let Inst{7} = i; + let Inst{6} = z; + let Inst{5-4} = imm6{5-4}; + let Inst{3-0} = op0; +} + +// Pseudo instructions +class Pseudo pattern> + : XtensaInst<2, outs, ins, asmstr, pattern> { + field bits<16> Inst; + field bits<16> SoftFail = 0; + let Inst = 0x0; + let isPseudo = 1; + let isCodeGenOnly = 1; +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td new file mode 100644 index 0000000000000..3c44fbef6c866 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -0,0 +1,148 @@ +//===- XtensaInstrInfo.td - Target Description for Xtensa -*- tablegen -*--===// +// +// The LLVM Compiler Infrastructure +// +// 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 describes the Xtensa instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +include "XtensaInstrFormats.td" +include "XtensaOperands.td" + +//===----------------------------------------------------------------------===// +// Arithmetic & Logical instructions +//===----------------------------------------------------------------------===// + +class ArithLogic_RRR oper2, bits<4> oper1, string instrAsm, + SDPatternOperator opNode, bit isComm = 0> + : RRR_Inst<0x00, oper1, oper2, (outs AR:$r), (ins AR:$s, AR:$t), + instrAsm#"\t$r, $s, $t", + [(set AR:$r, (opNode AR:$s, AR:$t))]> { + let isCommutable = isComm; + let isReMaterializable = 0; +} + +def ADD : ArithLogic_RRR<0x08, 0x00, "add", add, 1>; +def SUB : ArithLogic_RRR<0x0C, 0x00, "sub", sub>; +def AND : ArithLogic_RRR<0x01, 0x00, "and", and, 1>; +def OR : ArithLogic_RRR<0x02, 0x00, "or", or, 1>; +def XOR : ArithLogic_RRR<0x03, 0x00, "xor", xor, 1>; + +class ADDX oper, string instrAsm, list pattern> + : RRR_Inst<0x00, 0x00, oper, (outs AR:$r), (ins AR:$s, AR:$t), + instrAsm#"\t$r, $s, $t", pattern>; + +def ADDX2 : ADDX<0x09, "addx2", [(set AR:$r, (add AR:$t, (shl AR:$s, (i32 1))))]>; +def ADDX4 : ADDX<0x0A, "addx4", [(set AR:$r, (add AR:$t, (shl AR:$s, (i32 2))))]>; +def ADDX8 : ADDX<0x0B, "addx8", [(set AR:$r, (add AR:$t, (shl AR:$s, (i32 3))))]>; + +class SUBX oper, string instrAsm, list pattern> + : RRR_Inst<0x00, 0x00, oper, (outs AR:$r), (ins AR:$s, AR:$t), + instrAsm#"\t$r, $s, $t", pattern>; + +def SUBX2 : SUBX<0x0D, "subx2", [(set AR:$r, (sub (shl AR:$s, (i32 1)), AR:$t))]>; +def SUBX4 : SUBX<0x0E, "subx4", [(set AR:$r, (sub (shl AR:$s, (i32 2)), AR:$t))]>; +def SUBX8 : SUBX<0x0F, "subx8", [(set AR:$r, (sub (shl AR:$s, (i32 3)), AR:$t))]>; + +def ABS : RRR_Inst<0x00, 0x00, 0x06, (outs AR:$r), (ins AR:$t), + "abs\t$r, $t", []> { + let s = 0x1; +} + +def ADDI : RRI8_Inst<0x02, (outs AR:$t), (ins AR:$s, imm8:$imm8), + "addi\t$t, $s, $imm8", + [(set AR:$t, (add AR:$s, imm8:$imm8))]> { + let r = 0x0C; +} + +def ADDMI : RRI8_Inst<0x02, (outs AR:$t), (ins AR:$s, imm8_sh8:$imm_sh8), + "addmi\t$t, $s, $imm_sh8", + [(set AR:$t, (add AR:$s, imm8_sh8:$imm_sh8))]> { + bits<16> imm_sh8; + + let r = 0x0D; + let imm8 = imm_sh8{15-8}; +} + +def NEG : RRR_Inst<0x00, 0x00, 0x06, (outs AR:$r), (ins AR:$t), + "neg\t$r, $t", + [(set AR:$r, (ineg AR:$t))]> { + let s = 0x00; +} + +//===----------------------------------------------------------------------===// +// Move instructions +//===----------------------------------------------------------------------===// + +// Conditional move +def MOVEQZ : RRR_Inst<0x00, 0x03, 0x08, (outs AR:$r), (ins AR:$s, AR:$t), + "moveqz\t$r, $s, $t", []>; +def MOVNEZ : RRR_Inst<0x00, 0x03, 0x09, (outs AR:$r), (ins AR:$s, AR:$t), + "movnez\t$r, $s, $t", []>; +def MOVLTZ : RRR_Inst<0x00, 0x03, 0x0A, (outs AR:$r), (ins AR:$s, AR:$t), + "movltz\t$r, $s, $t", []>; +def MOVGEZ : RRR_Inst<0x00, 0x03, 0x0B, (outs AR:$r), (ins AR:$s, AR:$t), + "movgez\t$r, $s, $t", []>; + +//===----------------------------------------------------------------------===// +// Mem barrier instructions +//===----------------------------------------------------------------------===// +def MEMW : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "memw", []> { + let r = 0x2; + let t = 0x0c; + let s = 0x0; + let hasSideEffects = 1; +} + +def EXTW : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "extw", []> { + let r = 0x2; + let s = 0x0; + let t = 0xd; +} + +//===----------------------------------------------------------------------===// +// Processor control instructions +//===----------------------------------------------------------------------===// + +def DSYNC : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "dsync", []> { + let r = 0x2; + let s = 0x0; + let t = 0x3; +} + +def ISYNC : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "isync", []> { + let r = 0x2; + let s = 0x0; + let t = 0x0; +} + +def RSYNC : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "rsync", []> { + let r = 0x2; + let s = 0x0; + let t = 0x1; +} + +def ESYNC : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "esync", []> { + let r = 0x2; + let s = 0x0; + let t = 0x2; +} + +def NOP : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "nop", []> { + let r = 0x02; + let s = 0x00; + let t = 0x0f; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td new file mode 100644 index 0000000000000..01ee274aca023 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -0,0 +1,32 @@ +//===- XtensaOperands.td - Xtensa instruction operands -------*- tblgen-*--===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Immediate operands with a shared generic render method. +class ImmAsmOperand : AsmOperandClass { + let Name = name; + let RenderMethod = "addImmOperands"; + let DiagnosticType = !strconcat("Invalid", name); +} + +class Immediate + : Operand, ImmLeaf { + let PrintMethod = "print"#asmop; + let ParserMatchClass = !cast(asmop); +} + +// imm8 predicate - Immediate in the range [-128,127] +def Imm8_AsmOperand : ImmAsmOperand<"Imm8">; +def imm8 : Immediate= -128 && Imm <= 127; }], "Imm8_AsmOperand">; + +// imm8_sh8 predicate - Immediate in the range [-32768,32512] with (bits[7-0] == 0) +// imm8 value left shifted by 8 bits +def Imm8_sh8_AsmOperand : ImmAsmOperand<"Imm8_sh8">; +def imm8_sh8 : Immediate= -32768 && Imm <= 32512 && ((Imm & 0xFF) == 0); }], + "Imm8_sh8_AsmOperand">; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td new file mode 100644 index 0000000000000..5c07386b060cd --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -0,0 +1,78 @@ +//===- XtensaRegisterInfo.td - Xtensa Register defs --------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Class definitions. +//===----------------------------------------------------------------------===// + +class XtensaReg : Register { + let Namespace = "Xtensa"; +} + +class XtensaRegWithSubRegs subregs> + : RegisterWithSubRegs { + let Namespace = "Xtensa"; +} + +//===----------------------------------------------------------------------===// +// General-purpose registers +//===----------------------------------------------------------------------===// + +// Xtensa general purpose regs +class ARReg num, string n, list alt = []> : XtensaReg { + let HWEncoding{3-0} = num; + let AltNames = alt; +} + +// Return Address +def A0 : ARReg<0, "a0">, DwarfRegNum<[0]>; + +// Stack Pointer (callee-saved) +def SP : ARReg<1, "a1", ["sp"]>, DwarfRegNum<[1]>; + +// Function Arguments +def A2 : ARReg<2, "a2">, DwarfRegNum<[2]>; +def A3 : ARReg<3, "a3">, DwarfRegNum<[3]>; +def A4 : ARReg<4, "a4">, DwarfRegNum<[4]>; +def A5 : ARReg<5, "a5">, DwarfRegNum<[5]>; +def A6 : ARReg<6, "a6">, DwarfRegNum<[6]>; +def A7 : ARReg<7, "a7">, DwarfRegNum<[7]>; + +// Static Chain +def A8 : ARReg<8, "a8">, DwarfRegNum<[8]>; + +def A9 : ARReg<9, "a9">, DwarfRegNum<[9]>; +def A10 : ARReg<10, "a10">, DwarfRegNum<[10]>; +def A11 : ARReg<11, "a11">, DwarfRegNum<[11]>; + +// Callee-saved +def A12 : ARReg<12, "a12">, DwarfRegNum<[12]>; +def A13 : ARReg<13, "a13">, DwarfRegNum<[13]>; +def A14 : ARReg<14, "a14">, DwarfRegNum<[14]>; + +// Stack-Frame Pointer (optional) - Callee-Saved +def A15 : ARReg<15, "a15">, DwarfRegNum<[15]>; + +// Register class with allocation order +def AR : RegisterClass<"Xtensa", [i32], 32, (add + A8, A9, A10, A11, A12, A13, A14, A15, + A7, A6, A5, A4, A3, A2, A0, SP)>; +//===----------------------------------------------------------------------===// +// Special-purpose registers +//===----------------------------------------------------------------------===// +class SRReg num, string n, list alt = []> : XtensaReg { + let HWEncoding{7-0} = num; + let AltNames = alt; +} + +// Shift Amount Register +def SAR : SRReg<3, "sar", ["SAR","3"]>; + +def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR)>; From 97bba5fcfea0604dea5943eb4c5696b16d51d675 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:04 +0300 Subject: [PATCH 005/150] [Xtensa] Add Xtensa MCTargetDescr initial functionality. Add FDE CFI encoding for Xtensa. --- llvm/lib/MC/MCObjectFileInfo.cpp | 3 + llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + .../Target/Xtensa/MCTargetDesc/CMakeLists.txt | 4 + .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp | 119 ++++++++++++++++ .../MCTargetDesc/XtensaELFObjectWriter.cpp | 60 ++++++++ .../Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp | 32 +++++ .../Xtensa/MCTargetDesc/XtensaMCAsmInfo.h | 30 ++++ .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 129 ++++++++++++++++++ .../MCTargetDesc/XtensaMCTargetDesc.cpp | 57 +++++++- .../Xtensa/MCTargetDesc/XtensaMCTargetDesc.h | 39 ++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 8 +- 11 files changed, 478 insertions(+), 4 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.h create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp index d6fe952c0c1d8..5aff940a3a7b5 100644 --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -361,6 +361,9 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { FDECFIEncoding = PositionIndependent ? dwarf::DW_EH_PE_pcrel : dwarf::DW_EH_PE_absptr; break; + case Triple::xtensa: + FDECFIEncoding = dwarf::DW_EH_PE_sdata4; + break; default: FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; break; diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 75678b8fe1261..17ef1f213ce9b 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_component_group(Xtensa) set(LLVM_TARGET_DEFINITIONS Xtensa.td) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) add_public_tablegen_target(XtensaCommonTableGen) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt index 0febab437acb3..b94e4e9c7923b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt @@ -1,4 +1,8 @@ add_llvm_component_library(LLVMXtensaDesc + XtensaAsmBackend.cpp + XtensaELFObjectWriter.cpp + XtensaMCAsmInfo.cpp + XtensaMCCodeEmitter.cpp XtensaMCTargetDesc.cpp LINK_COMPONENTS diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp new file mode 100644 index 0000000000000..bacc23b562564 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp @@ -0,0 +1,119 @@ +//===-- XtensaMCAsmBackend.cpp - Xtensa assembler backend -----------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace llvm { +class MCObjectTargetWriter; +class XtensaMCAsmBackend : public MCAsmBackend { + uint8_t OSABI; + bool IsLittleEndian; + +public: + XtensaMCAsmBackend(uint8_t osABI, bool isLE) + : MCAsmBackend(support::little), OSABI(osABI), IsLittleEndian(isLE) {} + + unsigned getNumFixupKinds() const override { return 1; } + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override; + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override; + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *Fragment, + const MCAsmLayout &Layout) const override; + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override; + bool writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const override; + + std::unique_ptr createObjectTargetWriter() const override { + return createXtensaObjectWriter(OSABI, IsLittleEndian); + } +}; +} // namespace llvm + +const MCFixupKindInfo & +XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + return MCAsmBackend::getFixupKindInfo(MCFixupKind::FK_NONE); +} +void XtensaMCAsmBackend::applyFixup(const MCAssembler &Asm, + const MCFixup &Fixup, const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsResolved, + const MCSubtargetInfo *STI) const {} + +bool XtensaMCAsmBackend::mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const { + return false; +} + +bool XtensaMCAsmBackend::fixupNeedsRelaxation( + const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *Fragment, + const MCAsmLayout &Layout) const { + return false; +} + +void XtensaMCAsmBackend::relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const {} + +bool XtensaMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const { + uint64_t NumNops24b = Count / 3; + + for (uint64_t i = 0; i != NumNops24b; ++i) { + // Currently just little-endian machine supported, + // but probably big-endian will be also implemented in future + if (IsLittleEndian) { + OS.write("\xf0", 1); + OS.write("\x20", 1); + OS.write("\0x00", 1); + } else { + report_fatal_error("Big-endian mode currently is not supported!"); + } + Count -= 3; + } + + // TODO maybe function should return error if (Count > 0) + switch (Count) { + default: + break; + case 1: + OS.write("\0", 1); + break; + case 2: + OS.write("\0\0", 2); + break; + } + + return true; +} + +MCAsmBackend *llvm::createXtensaMCAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + uint8_t OSABI = + MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); + return new llvm::XtensaMCAsmBackend(OSABI, true); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp new file mode 100644 index 0000000000000..d407e188ab81b --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp @@ -0,0 +1,60 @@ +//===-- XtensaMCObjectWriter.cpp - Xtensa ELF writer ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include + +using namespace llvm; + +namespace { +class XtensaObjectWriter : public MCELFObjectTargetWriter { +public: + XtensaObjectWriter(uint8_t OSABI); + + virtual ~XtensaObjectWriter(); + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; + bool needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const override; +}; +} // namespace + +XtensaObjectWriter::XtensaObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(false, OSABI, ELF::EM_XTENSA, + /*HasRelocationAddend=*/true) {} + +XtensaObjectWriter::~XtensaObjectWriter() {} + +unsigned XtensaObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + report_fatal_error("invalid fixup kind!"); +} + +std::unique_ptr +llvm::createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian) { + return std::make_unique(OSABI); +} + +bool XtensaObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const { + return false; +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp new file mode 100644 index 0000000000000..ce80722230bb2 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp @@ -0,0 +1,32 @@ +//===-- XtensaMCAsmInfo.cpp - Xtensa Asm Properties -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the declarations of the XtensaMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "XtensaMCAsmInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +XtensaMCAsmInfo::XtensaMCAsmInfo(const Triple &TT) { + CodePointerSize = 4; + CalleeSaveStackSlotSize = 4; + PrivateGlobalPrefix = ".L"; + CommentString = "#"; + ZeroDirective = "\t.space\t"; + Data64bitsDirective = "\t.quad\t"; + GlobalDirective = "\t.global\t"; + UsesELFSectionDirectiveForBSS = true; + SupportsDebugInformation = true; + ExceptionsType = ExceptionHandling::DwarfCFI; + AlignmentIsInBytes = false; +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.h new file mode 100644 index 0000000000000..921ccc88b827a --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.h @@ -0,0 +1,30 @@ +//===-- XtensaMCAsmInfo.h - Xtensa Asm Info --------------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the declaration of the XtensaMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSATARGETASMINFO_H +#define LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSATARGETASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { +class Triple; + +class XtensaMCAsmInfo : public MCAsmInfoELF { +public: + explicit XtensaMCAsmInfo(const Triple &TT); +}; + +} // namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSATARGETASMINFO_H */ diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp new file mode 100644 index 0000000000000..7c7751d5cf072 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -0,0 +1,129 @@ +//===-- XtensaMCCodeEmitter.cpp - Convert Xtensa Code to Machine Code -----===// +// +// The LLVM Compiler Infrastructure +// +// 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 implements the XtensaMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "mccodeemitter" + +namespace { +class XtensaMCCodeEmitter : public MCCodeEmitter { + const MCInstrInfo &MCII; + MCContext &Ctx; + bool IsLittleEndian; + +public: + XtensaMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx, bool isLE) + : MCII(mcii), Ctx(ctx), IsLittleEndian(isLE) {} + + ~XtensaMCCodeEmitter() {} + + // OVerride MCCodeEmitter. + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; + +private: + // Automatically generated by TableGen. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + // Called by the TableGen code to get the binary encoding of operand + // MO in MI. Fixups is the list of fixups against MI. + uint32_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm8OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; +}; +} // namespace + +MCCodeEmitter *llvm::createXtensaMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx) { + return new XtensaMCCodeEmitter(MCII, Ctx, true); +} + +void XtensaMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + unsigned Size = MCII.get(MI.getOpcode()).getSize(); + + if (IsLittleEndian) { + // Little-endian insertion of Size bytes. + unsigned ShiftValue = 0; + for (unsigned I = 0; I != Size; ++I) { + OS << uint8_t(Bits >> ShiftValue); + ShiftValue += 8; + } + } else { + // TODO Big-endian insertion of Size bytes. + report_fatal_error("Big-endian mode currently is not supported!"); + } +} + +uint32_t +XtensaMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) + return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); + if (MO.isImm()) { + uint32_t res = static_cast(MO.getImm()); + return res; + } + + report_fatal_error("Unhandled expression!"); + return 0; +} + +uint32_t XtensaMCCodeEmitter::getImm8OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = MO.getImm(); + + assert(((Res >= -128) && (Res <= 127)) && "Unexpected operand value!"); + + return (Res & 0xff); +} + +uint32_t +XtensaMCCodeEmitter::getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = MO.getImm(); + + assert(((Res >= -32768) && (Res <= 32512) && ((Res & 0xff) == 0)) && + "Unexpected operand value!"); + + return (Res & 0xffff); +} + +#include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index c9c0996b07a94..aa16108924f9b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -8,6 +8,59 @@ // //===----------------------------------------------------------------------===// #include "XtensaMCTargetDesc.h" +#include "XtensaMCAsmInfo.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/ErrorHandling.h" -// We need to define this function for linking succeed -extern "C" void LLVMInitializeXtensaTargetMC() {} +#define GET_INSTRINFO_MC_DESC +#include "XtensaGenInstrInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "XtensaGenRegisterInfo.inc" + +using namespace llvm; + +static MCAsmInfo *createXtensaMCAsmInfo(const MCRegisterInfo &MRI, + const Triple &TT, + const MCTargetOptions &Options) { + MCAsmInfo *MAI = new XtensaMCAsmInfo(TT); + return MAI; +} + +static MCInstrInfo *createXtensaMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitXtensaMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createXtensaMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitXtensaMCRegisterInfo(X, Xtensa::SP); + return X; +} + +extern "C" void LLVMInitializeXtensaTargetMC() { + // Register the MCAsmInfo. + TargetRegistry::RegisterMCAsmInfo(TheXtensaTarget, createXtensaMCAsmInfo); + + // Register the MCCodeEmitter. + TargetRegistry::RegisterMCCodeEmitter(TheXtensaTarget, + createXtensaMCCodeEmitter); + + // Register the MCInstrInfo. + TargetRegistry::RegisterMCInstrInfo(TheXtensaTarget, createXtensaMCInstrInfo); + + // Register the MCRegisterInfo. + TargetRegistry::RegisterMCRegInfo(TheXtensaTarget, + createXtensaMCRegisterInfo); + + // Register the MCAsmBackend. + TargetRegistry::RegisterMCAsmBackend(TheXtensaTarget, + createXtensaMCAsmBackend); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h index d3a9a24de4084..02489418754b5 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h @@ -14,5 +14,44 @@ #ifndef LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H #define LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { + +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectTargetWriter; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class MCTargetOptions; +class StringRef; +class Target; +class raw_ostream; + +extern Target TheXtensaTarget; + +MCCodeEmitter *createXtensaMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx); + +MCAsmBackend *createXtensaMCAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); +std::unique_ptr +createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian); +} // end namespace llvm + +// Defines symbolic names for Xtensa registers. +// This defines a mapping from register name to register number. +#define GET_REGINFO_ENUM +#include "XtensaGenRegisterInfo.inc" + +// Defines symbolic names for the Xtensa instructions. +#define GET_INSTRINFO_ENUM +#include "XtensaGenInstrInfo.inc" #endif /* LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 01ee274aca023..9a1ed0356cdb1 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -23,10 +23,14 @@ class Immediate // imm8 predicate - Immediate in the range [-128,127] def Imm8_AsmOperand : ImmAsmOperand<"Imm8">; -def imm8 : Immediate= -128 && Imm <= 127; }], "Imm8_AsmOperand">; +def imm8 : Immediate= -128 && Imm <= 127; }], "Imm8_AsmOperand"> { + let EncoderMethod = "getImm8OpValue"; +} // imm8_sh8 predicate - Immediate in the range [-32768,32512] with (bits[7-0] == 0) // imm8 value left shifted by 8 bits def Imm8_sh8_AsmOperand : ImmAsmOperand<"Imm8_sh8">; def imm8_sh8 : Immediate= -32768 && Imm <= 32512 && ((Imm & 0xFF) == 0); }], - "Imm8_sh8_AsmOperand">; + "Imm8_sh8_AsmOperand"> { + let EncoderMethod = "getImm8_sh8OpValue"; +} From 7c4adeb35c76a51938ff8cd695d8ba715d473bd2 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:04 +0300 Subject: [PATCH 006/150] [Xtensa] Add Xtensa basic assembler parser. --- .../Target/Xtensa/AsmParser/CMakeLists.txt | 17 + .../Xtensa/AsmParser/XtensaAsmParser.cpp | 458 ++++++++++++++++++ llvm/lib/Target/Xtensa/CMakeLists.txt | 4 + .../Xtensa/MCTargetDesc/XtensaMCTargetDesc.h | 3 + llvm/lib/Target/Xtensa/Xtensa.td | 5 + 5 files changed, 487 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt create mode 100644 llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp diff --git a/llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt b/llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt new file mode 100644 index 0000000000000..62bc6c2b99707 --- /dev/null +++ b/llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt @@ -0,0 +1,17 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_component_library(LLVMXtensaAsmParser + XtensaAsmParser.cpp + + LINK_COMPONENTS + MC + MCParser + Support + XtensaDesc + XtensaInfo + + ADD_TO_COMPONENT + Xtensa + ) + +add_dependencies(LLVMXtensaAsmParser XtensaCommonTableGen) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp new file mode 100644 index 0000000000000..027a2c974beb5 --- /dev/null +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -0,0 +1,458 @@ +//===- XtensaAsmParser.cpp - Parse Xtensa assembly to MCInst instructions -===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-asm-parser" + +struct XtensaOperand; + +class XtensaAsmParser : public MCTargetAsmParser { + + SMLoc getLoc() const { return getParser().getTok().getLoc(); } + + // Override MCTargetAsmParser. + bool ParseDirective(AsmToken DirectiveID) override; + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, + unsigned Kind) override; + +// Auto-generated instruction matching functions +#define GET_ASSEMBLER_HEADER +#include "XtensaGenAsmMatcher.inc" + + OperandMatchResultTy parseImmediate(OperandVector &Operands); + OperandMatchResultTy parseRegister(OperandVector &Operands, + bool AllowParens = false, bool SR = false); + OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); + bool parseOperand(OperandVector &Operands); + OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) override { + return MatchOperand_NoMatch; + } + +public: + enum XtensaMatchResultTy { + Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "XtensaGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + }; + + XtensaAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, STI, MII) { + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } +}; + +// Return true if Expr is in the range [MinValue, MaxValue]. +static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue) { + if (auto *CE = dyn_cast(Expr)) { + int64_t Value = CE->getValue(); + return Value >= MinValue && Value <= MaxValue; + } + return false; +} + +struct XtensaOperand : public MCParsedAsmOperand { + + enum KindTy { + Token, + Register, + Immediate, + } Kind; + + struct RegOp { + unsigned RegNum; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + SMLoc StartLoc, EndLoc; + union { + StringRef Tok; + RegOp Reg; + ImmOp Imm; + }; + + XtensaOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + +public: + XtensaOperand(const XtensaOperand &o) : MCParsedAsmOperand() { + Kind = o.Kind; + StartLoc = o.StartLoc; + EndLoc = o.EndLoc; + switch (Kind) { + case Register: + Reg = o.Reg; + break; + case Immediate: + Imm = o.Imm; + break; + case Token: + Tok = o.Tok; + break; + } + } + + bool isToken() const override { return Kind == Token; } + bool isReg() const override { return Kind == Register; } + bool isImm() const override { return Kind == Immediate; } + bool isMem() const override { return false; } + + bool isImm(int64_t MinValue, int64_t MaxValue) const { + return Kind == Immediate && inRange(getImm(), MinValue, MaxValue); + } + + bool isImm8() const { return isImm(-128, 127); } + + bool isImm8_sh8() const { + return isImm(-32768, 32512) && + ((dyn_cast(getImm())->getValue() & 0xFF) == 0); + } + + /// getStartLoc - Gets location of the first token of this operand + SMLoc getStartLoc() const override { return StartLoc; } + /// getEndLoc - Gets location of the last token of this operand + SMLoc getEndLoc() const override { return EndLoc; } + + unsigned getReg() const override { + assert(Kind == Register && "Invalid type access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert(Kind == Immediate && "Invalid type access!"); + return Imm.Val; + } + + StringRef getToken() const { + assert(Kind == Token && "Invalid type access!"); + return Tok; + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case Immediate: + OS << *getImm(); + break; + case Register: + OS << ""; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + } + } + + static std::unique_ptr createToken(StringRef Str, SMLoc S) { + auto Op = std::make_unique(Token); + Op->Tok = Str; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr createReg(unsigned RegNo, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(Register); + Op->Reg.RegNum = RegNo; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + assert(Expr && "Expr shouldn't be null!"); + int64_t Imm = 0; + bool IsConstant = false; + + if (auto *CE = dyn_cast(Expr)) { + IsConstant = true; + Imm = CE->getValue(); + } + + if (IsConstant) + Inst.addOperand(MCOperand::createImm(Imm)); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + // Used by the TableGen Code + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } +}; + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "XtensaGenAsmMatcher.inc" + +unsigned XtensaAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, + unsigned Kind) { + return Match_InvalidOperand; +} + +static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, + uint64_t ErrorInfo) { + if (ErrorInfo != ~0ULL && ErrorInfo < Operands.size()) { + SMLoc ErrorLoc = Operands[ErrorInfo]->getStartLoc(); + if (ErrorLoc == SMLoc()) + return Loc; + return ErrorLoc; + } + return Loc; +} + +bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + auto Result = + MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + + switch (Result) { + default: + break; + case Match_Success: + Inst.setLoc(IDLoc); + Out.emitInstruction(Inst, getSTI()); + return false; + case Match_MissingFeature: + return Error(IDLoc, "instruction use requires an option to be enabled"); + case Match_MnemonicFail: + return Error(IDLoc, "unrecognized instruction mnemonic"); + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(ErrorLoc, "too few operands for instruction"); + + ErrorLoc = ((XtensaOperand &)*Operands[ErrorInfo]).getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_InvalidImm8: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-128, 127]"); + case Match_InvalidImm8_sh8: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-32768, 32512], first 8 bits " + "should be zero"); + } + + report_fatal_error("Unknown match type detected!"); +} + +bool XtensaAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + const AsmToken &Tok = getParser().getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); + RegNo = 0; + StringRef Name = getLexer().getTok().getIdentifier(); + + if ((!MatchRegisterName(Name)) && (!MatchRegisterAltName(Name))) { + getParser().Lex(); // Eat identifier token. + return false; + } + + return Error(StartLoc, "invalid register name"); +} + +OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, + bool AllowParens, bool SR) { + SMLoc FirstS = getLoc(); + bool HadParens = false; + AsmToken Buf[2]; + StringRef RegName; + + // If this a parenthesised register name is allowed, parse it atomically + if (AllowParens && getLexer().is(AsmToken::LParen)) { + size_t ReadCount = getLexer().peekTokens(Buf); + if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { + HadParens = true; + getParser().Lex(); // Eat '(' + } + } + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::Identifier: + RegName = getLexer().getTok().getIdentifier(); + break; + } + + unsigned RegNo = MatchRegisterName(RegName); + if (RegNo == 0) + RegNo = MatchRegisterAltName(RegName); + + if (RegNo == 0) { + if (HadParens) + getLexer().UnLex(Buf[0]); + return MatchOperand_NoMatch; + } + if (HadParens) + Operands.push_back(XtensaOperand::createToken("(", FirstS)); + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + getLexer().Lex(); + Operands.push_back(XtensaOperand::createReg(RegNo, S, E)); + + if (HadParens) { + getParser().Lex(); // Eat ')' + Operands.push_back(XtensaOperand::createToken(")", getLoc())); + } + + return MatchOperand_Success; +} + +OperandMatchResultTy XtensaAsmParser::parseImmediate(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Tilde: + case AsmToken::Integer: + case AsmToken::String: + if (getParser().parseExpression(Res)) + return MatchOperand_ParseFail; + break; + case AsmToken::Identifier: { + StringRef Identifier; + if (getParser().parseIdentifier(Identifier)) + return MatchOperand_ParseFail; + + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + break; + } + case AsmToken::Percent: + return parseOperandWithModifier(Operands); + } + + Operands.push_back(XtensaOperand::createImm(Res, S, E)); + return MatchOperand_Success; +} + +OperandMatchResultTy +XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) { + return MatchOperand_ParseFail; +} + +/// Looks at a token type and creates the relevant operand +/// from this information, adding to Operands. +/// If operand was parsed, returns false, else true. +bool XtensaAsmParser::parseOperand(OperandVector &Operands) { + // Attempt to parse token as register + if (parseRegister(Operands, true) == MatchOperand_Success) + return false; + + // Attempt to parse token as an immediate + if (parseImmediate(Operands) == MatchOperand_Success) { + return false; + } + + // Finally we have exhausted all options and must declare defeat. + Error(getLoc(), "unknown operand"); + return true; +} + +bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, + StringRef Name, SMLoc NameLoc, + OperandVector &Operands) { + // First operand is token for instruction + Operands.push_back(XtensaOperand::createToken(Name, NameLoc)); + + // If there are no more operands, then finish + if (getLexer().is(AsmToken::EndOfStatement)) + return false; + + // Parse first operand + if (parseOperand(Operands)) + return true; + + // Parse until end of statement, consuming commas between operands + while (getLexer().is(AsmToken::Comma)) { + // Consume comma token + getLexer().Lex(); + + // Parse next operand + if (parseOperand(Operands)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getParser().Lex(); // Consume the EndOfStatement. + return false; +} + +bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } + +// Force static initialization. +extern "C" void LLVMInitializeXtensaAsmParser() { + RegisterMCAsmParser X(TheXtensaTarget); +} diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 17ef1f213ce9b..c142cfb00144b 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -2,9 +2,11 @@ add_llvm_component_group(Xtensa) set(LLVM_TARGET_DEFINITIONS Xtensa.td) +tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM XtensaGenSubtargetInfo.inc -gen-subtarget) add_public_tablegen_target(XtensaCommonTableGen) @@ -22,5 +24,7 @@ add_llvm_target(XtensaCodeGen Xtensa ) +add_subdirectory(AsmParser) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) + diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h index 02489418754b5..daa3f5cce70f6 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h @@ -54,4 +54,7 @@ createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian); #define GET_INSTRINFO_ENUM #include "XtensaGenInstrInfo.inc" +#define GET_SUBTARGETINFO_ENUM +#include "XtensaGenSubtargetInfo.inc" + #endif /* LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H */ diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 830fdec9860c9..b1c436b1c5f38 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -47,6 +47,11 @@ def XtensaInstrInfo : InstrInfo; // Target Declaration //===----------------------------------------------------------------------===// +def XtensaAsmParser : AsmParser { + let ShouldEmitMatchRegisterAltName = 1; +} + def Xtensa : Target { let InstructionSet = XtensaInstrInfo; + let AssemblyParsers = [XtensaAsmParser]; } From 780c83fe5f4c40fba6d1d7bf11b9bf6107cf30a6 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:05 +0300 Subject: [PATCH 007/150] [Xtensa] Add basic Xtensa instruction printer. Add instruction printer and basic tests of the Xtensa instructions. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 4 + .../Target/Xtensa/MCTargetDesc/CMakeLists.txt | 1 + .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 106 ++++++++++++++++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 52 +++++++++ .../MCTargetDesc/XtensaMCTargetDesc.cpp | 25 +++++ llvm/lib/Target/Xtensa/Xtensa.td | 7 ++ llvm/test/MC/Xtensa/elf-header.s | 31 +++++ llvm/test/MC/Xtensa/lit.local.cfg | 2 + llvm/test/MC/Xtensa/xtensa-invalid.s | 31 +++++ llvm/test/MC/Xtensa/xtensa-valid.s | 104 +++++++++++++++++ 10 files changed, 363 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h create mode 100644 llvm/test/MC/Xtensa/elf-header.s create mode 100644 llvm/test/MC/Xtensa/lit.local.cfg create mode 100644 llvm/test/MC/Xtensa/xtensa-invalid.s create mode 100644 llvm/test/MC/Xtensa/xtensa-valid.s diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index c142cfb00144b..62731a2cce34a 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_component_group(Xtensa) set(LLVM_TARGET_DEFINITIONS Xtensa.td) tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) @@ -14,10 +15,13 @@ add_llvm_target(XtensaCodeGen XtensaTargetMachine.cpp LINK_COMPONENTS + AsmPrinter CodeGen Core + MC Support Target + XtensaDesc XtensaInfo ADD_TO_COMPONENT diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt index b94e4e9c7923b..3dad67b1e9a6a 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_component_library(LLVMXtensaDesc XtensaAsmBackend.cpp XtensaELFObjectWriter.cpp + XtensaInstPrinter.cpp XtensaMCAsmInfo.cpp XtensaMCCodeEmitter.cpp XtensaMCTargetDesc.cpp diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp new file mode 100644 index 0000000000000..a648948770a90 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -0,0 +1,106 @@ +//===- XtensaInstPrinter.cpp - Convert Xtensa MCInst to asm syntax --------===// +// +// The LLVM Compiler Infrastructure +// +// 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 class prints an Xtensa MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "XtensaInstPrinter.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +#include "XtensaGenAsmWriter.inc" + +static void printExpr(const MCExpr *Expr, raw_ostream &OS) { + int Offset = 0; + const MCSymbolRefExpr *SRE; + + if (!(SRE = dyn_cast(Expr))) + assert(false && "Unexpected MCExpr type."); + + MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); + + switch (Kind) { + case MCSymbolRefExpr::VK_None: + break; + // TODO + default: + report_fatal_error("Invalid kind!"); + } + + OS << SRE->getSymbol(); + + if (Offset) { + if (Offset > 0) + OS << '+'; + OS << Offset; + } + + if (Kind != MCSymbolRefExpr::VK_None) + OS << ')'; +} + +void XtensaInstPrinter::printOperand(const MCOperand &MC, raw_ostream &O) { + if (MC.isReg()) + O << getRegisterName(MC.getReg()); + else if (MC.isImm()) + O << MC.getImm(); + else if (MC.isExpr()) + printExpr(MC.getExpr(), O); + else + report_fatal_error("Invalid operand"); +} + +void XtensaInstPrinter::printInst(const MCInst *MI, uint64_t Address, + StringRef Annot, const MCSubtargetInfo &STI, + raw_ostream &O) { + printInstruction(MI, Address, O); + printAnnotation(O, Annot); +} + +void XtensaInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const { + O << getRegisterName(RegNo); +} + +void XtensaInstPrinter::printOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + printOperand(MI->getOperand(OpNum), O); +} + +void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -128 && Value <= 127) && + "Invalid argument, value must be in ranges [-128,127]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -32768 && Value <= 32512 && ((Value & 0xFF) == 0)) && + "Invalid argument, value must be multiples of 256 in range " + "[-32768,32512]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h new file mode 100644 index 0000000000000..fcadfad1cc507 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -0,0 +1,52 @@ +//===- XtensaInstPrinter.h - Convert Xtensa MCInst to asm syntax -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// 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 class prints an Xtensa MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAINSTPRINTER_H +#define LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +class MCOperand; + +class XtensaInstPrinter : public MCInstPrinter { +public: + XtensaInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + // Automatically generated by tblgen. + std::pair getMnemonic(const MCInst *MI) override; + void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + // Print the given operand. + static void printOperand(const MCOperand &MO, raw_ostream &O); + + // Override MCInstPrinter. + void printRegName(raw_ostream &O, unsigned RegNo) const override; + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &O) override; + +private: + // Print various types of operand. + void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); + + void printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); +}; +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAINSTPRINTER_H */ diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index aa16108924f9b..29bd805d86260 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -8,6 +8,7 @@ // //===----------------------------------------------------------------------===// #include "XtensaMCTargetDesc.h" +#include "XtensaInstPrinter.h" #include "XtensaMCAsmInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" @@ -24,6 +25,9 @@ #define GET_REGINFO_MC_DESC #include "XtensaGenRegisterInfo.inc" +#define GET_SUBTARGETINFO_MC_DESC +#include "XtensaGenSubtargetInfo.inc" + using namespace llvm; static MCAsmInfo *createXtensaMCAsmInfo(const MCRegisterInfo &MRI, @@ -39,12 +43,25 @@ static MCInstrInfo *createXtensaMCInstrInfo() { return X; } +static MCInstPrinter *createXtensaMCInstPrinter(const Triple &TT, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + return new XtensaInstPrinter(MAI, MII, MRI); +} + static MCRegisterInfo *createXtensaMCRegisterInfo(const Triple &TT) { MCRegisterInfo *X = new MCRegisterInfo(); InitXtensaMCRegisterInfo(X, Xtensa::SP); return X; } +static MCSubtargetInfo * +createXtensaMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { + return createXtensaMCSubtargetInfoImpl(TT, CPU, CPU, FS); +} + extern "C" void LLVMInitializeXtensaTargetMC() { // Register the MCAsmInfo. TargetRegistry::RegisterMCAsmInfo(TheXtensaTarget, createXtensaMCAsmInfo); @@ -56,10 +73,18 @@ extern "C" void LLVMInitializeXtensaTargetMC() { // Register the MCInstrInfo. TargetRegistry::RegisterMCInstrInfo(TheXtensaTarget, createXtensaMCInstrInfo); + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheXtensaTarget, + createXtensaMCInstPrinter); + // Register the MCRegisterInfo. TargetRegistry::RegisterMCRegInfo(TheXtensaTarget, createXtensaMCRegisterInfo); + // Register the MCSubtargetInfo. + TargetRegistry::RegisterMCSubtargetInfo(TheXtensaTarget, + createXtensaMCSubtargetInfo); + // Register the MCAsmBackend. TargetRegistry::RegisterMCAsmBackend(TheXtensaTarget, createXtensaMCAsmBackend); diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index b1c436b1c5f38..4c0f9eeae1eba 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -51,7 +51,14 @@ def XtensaAsmParser : AsmParser { let ShouldEmitMatchRegisterAltName = 1; } +def XtensaInstPrinter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + def Xtensa : Target { let InstructionSet = XtensaInstrInfo; + let AssemblyWriters = [XtensaInstPrinter]; let AssemblyParsers = [XtensaAsmParser]; } + diff --git a/llvm/test/MC/Xtensa/elf-header.s b/llvm/test/MC/Xtensa/elf-header.s new file mode 100644 index 0000000000000..00afa15d7a98a --- /dev/null +++ b/llvm/test/MC/Xtensa/elf-header.s @@ -0,0 +1,31 @@ +# RUN: llvm-mc %s -filetype=obj -triple=xtensa | llvm-readobj -h - \ +# RUN: | FileCheck -check-prefix=Xtensa %s + +# Xtensa: Format: elf32-xtensa +# Xtensa: Arch: xtensa +# Xtensa: AddressSize: 32bit +# Xtensa: ElfHeader { +# Xtensa: Ident { +# Xtensa: Magic: (7F 45 4C 46) +# Xtensa: Class: 32-bit (0x1) +# Xtensa: DataEncoding: LittleEndian (0x1) +# Xtensa: FileVersion: 1 +# Xtensa: OS/ABI: SystemV (0x0) +# Xtensa: ABIVersion: 0 +# Xtensa: Unused: (00 00 00 00 00 00 00) +# Xtensa: } +# Xtensa: Type: Relocatable (0x1) +# Xtensa: Machine: EM_XTENSA (0x5E) +# Xtensa: Version: 1 +# Xtensa: Entry: 0x0 +# Xtensa: ProgramHeaderOffset: 0x0 +# Xtensa: SectionHeaderOffset: 0x5C +# Xtensa: Flags [ (0x0) +# Xtensa: ] +# Xtensa: HeaderSize: 52 +# Xtensa: ProgramHeaderEntrySize: 0 +# Xtensa: ProgramHeaderCount: 0 +# Xtensa: SectionHeaderEntrySize: 40 +# Xtensa: SectionHeaderCount: 4 +# Xtensa: StringTableSectionIndex: 1 +# Xtensa: } diff --git a/llvm/test/MC/Xtensa/lit.local.cfg b/llvm/test/MC/Xtensa/lit.local.cfg new file mode 100644 index 0000000000000..9e0be9979305d --- /dev/null +++ b/llvm/test/MC/Xtensa/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'Xtensa' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/MC/Xtensa/xtensa-invalid.s b/llvm/test/MC/Xtensa/xtensa-invalid.s new file mode 100644 index 0000000000000..86f4ff2e4c4b1 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-invalid.s @@ -0,0 +1,31 @@ +# RUN: not llvm-mc -triple xtensa < %s 2>&1 | FileCheck %s + +# Out of range immediates + +LBL0: + +# imm8 +addi a1, a2, 300 +# CHECK: error: expected immediate in range [-128, 127] + +addi a1, a2, -129 +# CHECK: error: expected immediate in range [-128, 127] + +# imm8_sh8 +addmi a1, a2, 33 +# CHECK: error: expected immediate in range [-32768, 32512], first 8 bits should be zero + +# Invalid number of operands +addi a1, a2 # CHECK: :[[@LINE]]:1: error: too few operands for instruction +addi a1, a2, 4, 4 # CHECK: :[[@LINE]]:17: error: invalid operand for instruction + +# Invalid mnemonics +aaa a10, a12 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic + +# Invalid register names +addi a101, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +or r2, sp, a3 # CHECK: :[[@LINE]]:4: error: invalid operand for instruction + +# Invalid operand types +and sp, a2, 10 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction +addi sp, a1, a2 # CHECK: :[[@LINE]]:14: error: expected immediate in range [-128, 127] diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s new file mode 100644 index 0000000000000..ae2bf4dc74163 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -0,0 +1,104 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# CHECK-INST: abs a5, a6 +# CHECK: encoding: [0x60,0x51,0x60] +abs a5, a6 + +# CHECK-INST: add a3, a9, a4 +# CHECK: encoding: [0x40,0x39,0x80] +add a3, a9, a4 +# CHECK-INST: add a15, a9, a1 +# CHECK: encoding: [0x10,0xf9,0x80] +add a15, a9, sp + +# CHECK-INST: addi a8, a1, -128 +# CHECK: encoding: [0x82,0xc1,0x80] +addi a8, sp, -128 +# CHECK-INST: addi a8, a1, -12 +# CHECK: encoding: [0x82,0xc1,0xf4] +addi a8, a1, -12 + +# CHECK-INST: addmi a1, a2, 32512 +# CHECK: encoding: [0x12,0xd2,0x7f] +addmi a1, a2, 32512 + +# CHECK-INST: addx2 a2, a1, a5 +# CHECK: encoding: [0x50,0x21,0x90] +addx2 a2, sp, a5 +# CHECK-INST: addx4 a3, a1, a6 +# CHECK: encoding: [0x60,0x31,0xa0] +addx4 a3, sp, a6 +# CHECK-INST: addx8 a4, a1, a7 +# CHECK: encoding: [0x70,0x41,0xb0] +addx8 a4, sp, a7 + +# CHECK-INST: dsync +# CHECK: encoding: [0x30,0x20,0x00] +dsync +# CHECK-INST: esync +# CHECK: encoding: [0x20,0x20,0x00] +esync + +# CHECK-INST: extw +# CHECK: encoding: [0xd0,0x20,0x00] +extw + +# CHECK-INST: isync +# CHECK: encoding: [0x00,0x20,0x00] +isync + +# CHECK-INST: memw +# CHECK: encoding: [0xc0,0x20,0x00] +memw + +# CHECK-INST: moveqz a2, a3, a4 +# CHECK: encoding: [0x40,0x23,0x83] +moveqz a2,a3,a4 +# CHECK-INST: movgez a3, a11, a12 +# CHECK: encoding: [0xc0,0x3b,0xb3] +movgez a3,a11,a12 + +# CHECK-INST: movltz a7, a8, a9 +# CHECK: encoding: [0x90,0x78,0xa3] +movltz a7, a8, a9 +# CHECK-INST: movnez a10, a11, a12 +# CHECK: encoding: [0xc0,0xab,0x93] +movnez a10,a11, a12 + +# CHECK-INST: neg a1, a3 +# CHECK: encoding: [0x30,0x10,0x60] +neg a1, a3 + +# CHECK-INST: nop +# CHECK: encoding: [0xf0,0x20,0x00] +nop + +# CHECK-INST: or a4, a5, a6 +# CHECK: encoding: [0x60,0x45,0x20] +or a4, a5, a6 + +# CHECK-INST: rsync +# CHECK: encoding: [0x10,0x20,0x00] +rsync + +# CHECK-INST: sub a8, a2, a1 +# CHECK: encoding: [0x10,0x82,0xc0] +sub a8, a2, a1 +# CHECK-INST: subx2 a2, a1, a5 +# CHECK: encoding: [0x50,0x21,0xd0] +subx2 a2, sp, a5 +# CHECK-INST: subx4 a3, a1, a6 +# CHECK: encoding: [0x60,0x31,0xe0] +subx4 a3, sp, a6 +# CHECK-INST: subx8 a4, a1, a7 +# CHECK: encoding: [0x70,0x41,0xf0] +subx8 a4, sp, a7 + +# CHECK-INST: xor a6, a4, a5 +# CHECK: encoding: [0x50,0x64,0x30] +xor a6, a4, a5 From 9fe2aa56aa084b80c5d0233f3156721ba91d7086 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:05 +0300 Subject: [PATCH 008/150] [Xtensa] Add shift/load/store instructions. Add td descriptions of the Xtensa shift/load/store instructions. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 153 ++++++++++++++++- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 116 +++++++++++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 11 ++ .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 121 +++++++++++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 156 +++++++++++++++++- llvm/lib/Target/Xtensa/XtensaOperands.td | 83 ++++++++++ llvm/test/MC/Xtensa/xtensa-invalid.s | 34 ++++ llvm/test/MC/Xtensa/xtensa-valid.s | 105 ++++++++++++ 8 files changed, 771 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 027a2c974beb5..1222c3f0112d4 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -53,7 +53,10 @@ class XtensaAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseRegister(OperandVector &Operands, bool AllowParens = false, bool SR = false); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); - bool parseOperand(OperandVector &Operands); + bool parseOperand(OperandVector &Operands, StringRef Mnemonic, + bool SR = false); + bool ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands); OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override { return MatchOperand_NoMatch; @@ -142,6 +145,39 @@ struct XtensaOperand : public MCParsedAsmOperand { ((dyn_cast(getImm())->getValue() & 0xFF) == 0); } + bool isImm12() const { return isImm(-2048, 2047); } + + bool isImm12m() const { return isImm(-2048, 2047); } + + bool isOffset4m32() const { + return isImm(0, 60) && + ((dyn_cast(getImm())->getValue() & 0x3) == 0); + } + + bool isOffset8m8() const { return isImm(0, 255); } + + bool isOffset8m16() const { + return isImm(0, 510) && + ((dyn_cast(getImm())->getValue() & 0x1) == 0); + } + + bool isOffset8m32() const { + return isImm(0, 1020) && + ((dyn_cast(getImm())->getValue() & 0x3) == 0); + } + + bool isUimm4() const { return isImm(0, 15); } + + bool isUimm5() const { return isImm(0, 31); } + + bool isImm8n_7() const { return isImm(-8, 7); } + + bool isShimm1_31() const { return isImm(1, 31); } + + bool isImm16_31() const { return isImm(16, 31); } + + bool isImm1_16() const { return isImm(1, 16); } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -290,6 +326,39 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-32768, 32512], first 8 bits " "should be zero"); + case Match_InvalidImm12: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-2048, 2047]"); + case Match_InvalidImm12m: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-2048, 2047]"); + case Match_InvalidImm1_16: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [1, 16]"); + case Match_InvalidShimm1_31: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [1, 31]"); + case Match_InvalidUimm4: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 15]"); + case Match_InvalidUimm5: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 31]"); + case Match_InvalidOffset8m8: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 255]"); + case Match_InvalidOffset8m16: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 510], first bit " + "should be zero"); + case Match_InvalidOffset8m32: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 1020], first 2 bits " + "should be zero"); + case Match_InvalidOffset4m32: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 60], first 2 bits " + "should be zero"); } report_fatal_error("Unknown match type detected!"); @@ -322,6 +391,8 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, if (AllowParens && getLexer().is(AsmToken::LParen)) { size_t ReadCount = getLexer().peekTokens(Buf); if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { + if ((Buf[0].getKind() == AsmToken::Integer) && (!SR)) + return MatchOperand_NoMatch; HadParens = true; getParser().Lex(); // Eat '(' } @@ -330,6 +401,11 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; + case AsmToken::Integer: + if (!SR) + return MatchOperand_NoMatch; + RegName = StringRef(std::to_string(getLexer().getTok().getIntVal())); + break; case AsmToken::Identifier: RegName = getLexer().getTok().getIdentifier(); break; @@ -401,9 +477,10 @@ XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) { /// Looks at a token type and creates the relevant operand /// from this information, adding to Operands. /// If operand was parsed, returns false, else true. -bool XtensaAsmParser::parseOperand(OperandVector &Operands) { +bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, + bool SR) { // Attempt to parse token as register - if (parseRegister(Operands, true) == MatchOperand_Success) + if (parseRegister(Operands, true, SR) == MatchOperand_Success) return false; // Attempt to parse token as an immediate @@ -416,9 +493,75 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands) { return true; } +bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info, + StringRef Name, SMLoc NameLoc, + OperandVector &Operands) { + if ((Name.startswith("wsr.") || Name.startswith("rsr.") || + Name.startswith("xsr.")) && + (Name.size() > 4)) { + // Parse case when instruction name is concatenated with SR register + // name, like "wsr.sar a1" + + // First operand is token for instruction + Operands.push_back(XtensaOperand::createToken(Name.take_front(3), NameLoc)); + + StringRef RegName = Name.drop_front(4); + unsigned RegNo = MatchRegisterName(RegName); + + if (RegNo == 0) + RegNo = MatchRegisterAltName(RegName); + + if (RegNo == 0) { + Error(NameLoc, "invalid register name"); + return true; + } + + // Parse operand + if (parseOperand(Operands, Name)) + return true; + + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + Operands.push_back(XtensaOperand::createReg(RegNo, S, E)); + } else { + // First operand is token for instruction + Operands.push_back(XtensaOperand::createToken(Name, NameLoc)); + + // Parse first operand + if (parseOperand(Operands, Name)) + return true; + + if (!getLexer().is(AsmToken::Comma)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getLexer().Lex(); + + // Parse second operand + if (parseOperand(Operands, Name, true)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getParser().Lex(); // Consume the EndOfStatement. + return false; +} + bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { + if (Name.startswith("wsr") || Name.startswith("rsr") || + Name.startswith("xsr")) { + return ParseInstructionWithSR(Info, Name, NameLoc, Operands); + } + // First operand is token for instruction Operands.push_back(XtensaOperand::createToken(Name, NameLoc)); @@ -427,7 +570,7 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, return false; // Parse first operand - if (parseOperand(Operands)) + if (parseOperand(Operands, Name)) return true; // Parse until end of statement, consuming commas between operands @@ -436,7 +579,7 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, getLexer().Lex(); // Parse next operand - if (parseOperand(Operands)) + if (parseOperand(Operands, Name)) return true; } diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index a648948770a90..1d4e99165765b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -82,6 +82,13 @@ void XtensaInstPrinter::printOperand(const MCInst *MI, int OpNum, printOperand(MI->getOperand(OpNum), O); } +void XtensaInstPrinter::printMemOperand(const MCInst *MI, int opNum, + raw_ostream &OS) { + OS << getRegisterName(MI->getOperand(opNum).getReg()); + OS << ", "; + printOperand(MI, opNum + 1, OS); +} + void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { @@ -104,3 +111,112 @@ void XtensaInstPrinter::printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, } else printOperand(MI, OpNum, O); } + +void XtensaInstPrinter::printImm12_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -2048 && Value <= 2047) && + "Invalid argument, value must be in ranges [-2048,2047]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm12m_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -2048 && Value <= 2047) && + "Invalid argument, value must be in ranges [-2048,2047]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printUimm4_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 15) && "Invalid argument"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printUimm5_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 31) && "Invalid argument"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printShimm1_31_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 1 && Value <= 31) && + "Invalid argument, value must be in range [1,31]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm1_16_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 1 && Value <= 16) && + "Invalid argument, value must be in range [1,16]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 255) && + "Invalid argument, value must be in range [0,255]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 510 && ((Value & 0x1) == 0)) && + "Invalid argument, value must be multiples of two in range [0,510]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert( + (Value >= 0 && Value <= 1020 && ((Value & 0x3) == 0)) && + "Invalid argument, value must be multiples of four in range [0,1020]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 60 && ((Value & 0x3) == 0)) && + "Invalid argument, value must be multiples of four in range [0,60]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index fcadfad1cc507..5d62a9c3011fd 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -43,9 +43,20 @@ class XtensaInstPrinter : public MCInstPrinter { private: // Print various types of operand. void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O); void printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm12m_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printUimm4_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printUimm5_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printShimm1_31_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm1_16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 7c7751d5cf072..c52bfd33ce6b9 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -53,6 +53,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getMemRegEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getImm8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -60,6 +64,26 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { uint32_t getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + uint32_t getImm12OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getUimm4OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getUimm5OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm1_16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // namespace @@ -94,14 +118,48 @@ XtensaMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); if (MO.isImm()) { - uint32_t res = static_cast(MO.getImm()); - return res; + uint32_t Res = static_cast(MO.getImm()); + return Res; } report_fatal_error("Unhandled expression!"); return 0; } +uint32_t +XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(OpNo + 1).isImm()); + + uint32_t Res = static_cast(MI.getOperand(OpNo + 1).getImm()); + + switch (MI.getOpcode()) { + case Xtensa::S16I: + case Xtensa::L16SI: + case Xtensa::L16UI: + if (Res & 0x1) { + report_fatal_error("Unexpected operand value!"); + } + Res >>= 1; + break; + case Xtensa::S32I: + case Xtensa::L32I: + if (Res & 0x3) { + report_fatal_error("Unexpected operand value!"); + } + Res >>= 2; + break; + } + + assert((isUInt<8>(Res)) && "Unexpected operand value!"); + + uint32_t OffBits = Res << 4; + uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + + return ((OffBits & 0xFF0) | RegBits); +} + uint32_t XtensaMCCodeEmitter::getImm8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -126,4 +184,63 @@ XtensaMCCodeEmitter::getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, return (Res & 0xffff); } +uint32_t +XtensaMCCodeEmitter::getImm12OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = MO.getImm(); + + assert(((Res >= -2048) && (Res <= 2047)) && "Unexpected operand value!"); + + return (Res & 0xfff); +} + +uint32_t +XtensaMCCodeEmitter::getUimm4OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert((Res <= 15) && "Unexpected operand value!"); + + return Res & 0xf; +} + +uint32_t +XtensaMCCodeEmitter::getUimm5OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert((Res <= 31) && "Unexpected operand value!"); + + return (Res & 0x1f); +} + +uint32_t +XtensaMCCodeEmitter::getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert(((Res >= 1) && (Res <= 31)) && "Unexpected operand value!"); + + return ((32 - Res) & 0x1f); +} + +uint32_t +XtensaMCCodeEmitter::getImm1_16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert(((Res >= 1) && (Res <= 16)) && "Unexpected operand value!"); + + return (Res - 1); +} #include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 3c44fbef6c866..f0741eaf554f8 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -79,8 +79,16 @@ def NEG : RRR_Inst<0x00, 0x00, 0x06, (outs AR:$r), (ins AR:$t), //===----------------------------------------------------------------------===// // Move instructions //===----------------------------------------------------------------------===// +def MOVI : RRI8_Inst<0x02, (outs AR:$t), (ins imm12m:$imm), + "movi\t$t, $imm", + [(set AR:$t, imm12m:$imm)]> { + bits<12> imm; + + let imm8{7-0} = imm{7-0}; + let s{3-0} = imm{11-8}; + let r = 0xa; +} -// Conditional move def MOVEQZ : RRR_Inst<0x00, 0x03, 0x08, (outs AR:$r), (ins AR:$s, AR:$t), "moveqz\t$r, $s, $t", []>; def MOVNEZ : RRR_Inst<0x00, 0x03, 0x09, (outs AR:$r), (ins AR:$s, AR:$t), @@ -90,9 +98,144 @@ def MOVLTZ : RRR_Inst<0x00, 0x03, 0x0A, (outs AR:$r), (ins AR:$s, AR:$t), def MOVGEZ : RRR_Inst<0x00, 0x03, 0x0B, (outs AR:$r), (ins AR:$s, AR:$t), "movgez\t$r, $s, $t", []>; +//===----------------------------------------------------------------------===// +// Shift instructions +//===----------------------------------------------------------------------===// + +let Uses = [SAR] in { + def SLL : RRR_Inst<0x00, 0x01, 0x0A, (outs AR:$r), (ins AR:$s), + "sll\t$r, $s", []> { + let t = 0x00; + } + + def SRA : RRR_Inst<0x00, 0x01, 0x0B, (outs AR:$r), (ins AR:$t), + "sra\t$r, $t", []> { + let s = 0x00; + } + + def SRC : RRR_Inst<0x00, 0x01, 0x08, (outs AR:$r), (ins AR:$s, AR:$t), + "src\t$r, $s, $t", []>; + + def SRL : RRR_Inst<0x00, 0x01, 0x09, (outs AR:$r), (ins AR:$t), + "srl\t$r, $t", []> { + let s = 0x00; + } +} + +let Defs = [SAR] in { + def SSL : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), + "ssl\t$s", []> { + let r = 0x01; + let t = 0x00; + } + + def SSR : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), + "ssr\t$s", []> { + let r = 0x00; + let t = 0x00; + } +} + +def EXTUI : RRR_Inst<0x00, 0x04, 0x00, (outs AR:$r), (ins AR:$t, uimm5:$imm1, imm1_16:$imm2), + "extui\t$r, $t, $imm1, $imm2", []> { + bits<5> imm1; + bits<4> imm2; + + let s = imm1{3-0}; + let Inst{16} = imm1{4}; + let Inst{23-20} = imm2; +} + +def SRAI : RRR_Inst<0x00, 0x01, 0x02, (outs AR:$r), (ins AR:$t, uimm5:$sa), + "srai\t$r, $t, $sa", + [(set AR:$r, (sra AR:$t, uimm5:$sa))]> { + bits<5> sa; + + let Inst{20} = sa{4}; + let s = sa{3-0}; +} + +def SRLI : RRR_Inst<0x00, 0x01, 0x04, (outs AR:$r), (ins AR:$t, uimm4:$sa), + "srli\t$r, $t, $sa", + [(set AR:$r, (srl AR:$t, uimm4:$sa))]> { + bits<4> sa; + + let s = sa; +} + +def SLLI : RRR_Inst<0x00, 0x01, 0x00, (outs AR:$r), (ins AR:$s, shimm1_31:$sa), + "slli\t$r, $s, $sa", + [(set AR:$r, (shl AR:$s, shimm1_31:$sa))]> { + bits<5> sa; + + let Inst{20} = sa{4}; + let t = sa{3-0}; +} + +def SSA8L : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), + "ssa8l\t$s", []> { + let r = 0x2; + let t = 0x0; +} + +def SSAI : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins uimm5:$imm), + "ssai\t$imm", []> { + bits<5> imm; + + let r = 0x04; + let s = imm{3-0}; + let t{3-1} = 0; + let t{0} = imm{4}; +} + +//===----------------------------------------------------------------------===// +// Load and store instructions +//===----------------------------------------------------------------------===// + +// Load instructions +let mayLoad = 1 in { + + class Load_RRI8 oper, string instrAsm, SDPatternOperator opNode, + ComplexPattern addrOp, Operand memOp> + : RRI8_Inst<0x02, (outs AR:$t), (ins memOp:$addr), + instrAsm#"\t$t, $addr", + [(set AR:$t, (opNode addrOp:$addr))]> { + bits<12> addr; + + let r = oper; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +def L8UI : Load_RRI8<0x00, "l8ui", zextloadi8, addr_ish1, mem8>; +def L16SI : Load_RRI8<0x09, "l16si", sextloadi16, addr_ish2, mem16>; +def L16UI : Load_RRI8<0x01, "l16ui", zextloadi16, addr_ish2, mem16>; +def L32I : Load_RRI8<0x02, "l32i", load, addr_ish4, mem32>; + +// Store instructions +let mayStore = 1 in { + class Store_II8 oper, string instrAsm, SDPatternOperator opNode, + ComplexPattern addrOp, Operand memOp> + : RRI8_Inst<0x02, (outs), (ins AR:$t, memOp:$addr), + instrAsm#"\t$t, $addr", + [(opNode AR:$t, addrOp:$addr)]> { + bits<12> addr; + + let r = oper; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +def S8I : Store_II8<0x04, "s8i", truncstorei8, addr_ish1, mem8>; +def S16I : Store_II8<0x05, "s16i", truncstorei16, addr_ish2, mem16>; +def S32I : Store_II8<0x06, "s32i", store, addr_ish4, mem32>; + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// + def MEMW : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), "memw", []> { let r = 0x2; @@ -146,3 +289,14 @@ def NOP : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), let s = 0x00; let t = 0x0f; } + +def WSR : RSR_Inst<0x00, 0x03, 0x01, (outs SR:$sr), (ins AR:$t), + "wsr\t$t, $sr", []>; + +def RSR : RSR_Inst<0x00, 0x03, 0x00, (outs AR:$t), (ins SR:$sr), + "rsr\t$t, $sr", []>; + +def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr), + "xsr\t$t, $sr", []> { + let Constraints = "$ard = $t, $srd = $sr"; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 9a1ed0356cdb1..c8fca6f5e7bff 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -34,3 +34,86 @@ def imm8_sh8 : Immediate= -32768 && Imm <= 32512 && ((Imm & "Imm8_sh8_AsmOperand"> { let EncoderMethod = "getImm8_sh8OpValue"; } + +// imm12 predicate - Immediate in the range [-2048,2047] +def Imm12_AsmOperand : ImmAsmOperand<"Imm12">; +def imm12 : Immediate= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> { + let EncoderMethod = "getImm12OpValue"; +} + +// imm12m predicate - Immediate for MOV operation +def Imm12m_AsmOperand : ImmAsmOperand<"Imm12m">; +def imm12m : Immediate= -2048 && Imm <= 2047; }], "Imm12m_AsmOperand"> { + let EncoderMethod = "getImm12OpValue"; +} + +// uimm4 predicate - Immediate in the range [0,15] +def Uimm4_AsmOperand : ImmAsmOperand<"Uimm4">; +def uimm4 : Immediate= 0 && Imm <= 15; }], "Uimm4_AsmOperand"> { + let EncoderMethod = "getUimm4OpValue"; +} + +// uimm5 predicate - Immediate in the range [0,31] +def Uimm5_AsmOperand : ImmAsmOperand<"Uimm5">; +def uimm5 : Immediate= 0 && Imm <= 31; }], "Uimm5_AsmOperand"> { + let EncoderMethod = "getUimm5OpValue"; +} + +// imm1_16 predicate - Immediate in the range [1,16] +def Imm1_16_AsmOperand : ImmAsmOperand<"Imm1_16">; +def imm1_16 : Immediate= 1 && Imm <= 16; }], "Imm1_16_AsmOperand"> { + let EncoderMethod = "getImm1_16OpValue"; +} + +// shimm1_31 predicate - Immediate in the range [1,31] +def Shimm1_31_AsmOperand : ImmAsmOperand<"Shimm1_31">; +def shimm1_31 : Immediate= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> { + let EncoderMethod = "getShimm1_31OpValue"; +} + +// Memory offset 0..255 for 8-bit memory accesses +def Offset8m8_AsmOperand : ImmAsmOperand<"Offset8m8">; +def offset8m8 : Immediate= 0 && Imm <= 255; }], + "Offset8m8_AsmOperand">; + +// Memory offset 0..510 for 16-bit memory accesses +def Offset8m16_AsmOperand : ImmAsmOperand<"Offset8m16">; +def offset8m16 : Immediate= 0 && Imm <= 510 && (Imm & 0x1 == 0); }], + "Offset8m16_AsmOperand">; + +// Memory offset 0..1020 for 32-bit memory accesses +def Offset8m32_AsmOperand : ImmAsmOperand<"Offset8m32">; +def offset8m32 : Immediate= 0 && Imm <= 1020 && (Imm & 0x3 == 0); }], + "Offset8m32_AsmOperand">; + +// Memory offset 0..60 for 32-bit memory accesses +def Offset4m32_AsmOperand : ImmAsmOperand<"Offset4m32">; +def offset4m32 : Immediate= 0 && Imm <= 60 && (Imm & 0x3 == 0); }], + "Offset4m32_AsmOperand">; +//===----------------------------------------------------------------------===// +// Memory address operands +//===----------------------------------------------------------------------===// + +class mem : Operand { + let MIOperandInfo = (ops AR, offset); + let EncoderMethod = "getMemRegEncoding"; + let OperandType = "OPERAND_MEMORY"; + let PrintMethod = "printMemOperand"; +} + +def mem8 : mem; + +def mem16 : mem; + +def mem32 : mem; + +def mem32n : mem; + +//Add patterns for future use in stack addressing mode +def addr_ish1 : ComplexPattern; +def addr_ish2 : ComplexPattern; +def addr_ish4 : ComplexPattern; diff --git a/llvm/test/MC/Xtensa/xtensa-invalid.s b/llvm/test/MC/Xtensa/xtensa-invalid.s index 86f4ff2e4c4b1..555263f9c1876 100644 --- a/llvm/test/MC/Xtensa/xtensa-invalid.s +++ b/llvm/test/MC/Xtensa/xtensa-invalid.s @@ -4,10 +4,15 @@ LBL0: +# imm12m +movi a1, 3000 +# CHECK: error: expected immediate in range [-2048, 2047] + # imm8 addi a1, a2, 300 # CHECK: error: expected immediate in range [-128, 127] +# imm8 addi a1, a2, -129 # CHECK: error: expected immediate in range [-128, 127] @@ -15,6 +20,34 @@ addi a1, a2, -129 addmi a1, a2, 33 # CHECK: error: expected immediate in range [-32768, 32512], first 8 bits should be zero +# shimm1_31 +slli a1, a2, 0 +# CHECK: error: expected immediate in range [1, 31] + +# uimm4 +srli a1, a2, 16 +# CHECK: error: expected immediate in range [0, 15] + +# uimm5 +ssai 32 +# CHECK: error: expected immediate in range [0, 31] + +# imm64n_4n +ssai 32 +# CHECK: error: expected immediate in range [0, 31] + +# offset8m8 +s8i a1, a2, 300 +# CHECK: error: expected immediate in range [0, 255] + +# offset16m8 +l16si a1, a2, 512 +# CHECK: error: expected immediate in range [0, 510], first bit should be zero + +# offset32m8 +l32i a1, a2, 1024 +# CHECK: error: expected immediate in range [0, 1020], first 2 bits should be zero + # Invalid number of operands addi a1, a2 # CHECK: :[[@LINE]]:1: error: too few operands for instruction addi a1, a2, 4, 4 # CHECK: :[[@LINE]]:17: error: invalid operand for instruction @@ -24,6 +57,7 @@ aaa a10, a12 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic # Invalid register names addi a101, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +wsr.uregister a2 # CHECK: :[[@LINE]]:1: error: invalid register name or r2, sp, a3 # CHECK: :[[@LINE]]:4: error: invalid operand for instruction # Invalid operand types diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s index ae2bf4dc74163..8fddf99fe961a 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -44,6 +44,10 @@ dsync # CHECK: encoding: [0x20,0x20,0x00] esync +# CHECK-INST: extui a1, a2, 7, 8 +# CHECK: encoding: [0x20,0x17,0x74] +extui a1, a2, 7, 8 + # CHECK-INST: extw # CHECK: encoding: [0xd0,0x20,0x00] extw @@ -52,6 +56,19 @@ extw # CHECK: encoding: [0x00,0x20,0x00] isync +# CHECK-INST: l8ui a2, a1, 3 +# CHECK: encoding: [0x22,0x01,0x03] +l8ui a2, sp, 3 +# CHECK-INST: l16si a3, a1, 4 +# CHECK: encoding: [0x32,0x91,0x02] +l16si a3, sp, 4 +# CHECK-INST: l16ui a4, a1, 6 +# CHECK: encoding: [0x42,0x11,0x03] +l16ui a4, sp, 6 +# CHECK-INST: l32i a5, a1, 8 +# CHECK: encoding: [0x52,0x21,0x02] +l32i a5, sp, 8 + # CHECK-INST: memw # CHECK: encoding: [0xc0,0x20,0x00] memw @@ -63,6 +80,10 @@ moveqz a2,a3,a4 # CHECK: encoding: [0xc0,0x3b,0xb3] movgez a3,a11,a12 +# CHECK-INST: movi a1, -2048 +# CHECK: encoding: [0x12,0xa8,0x00] +movi a1, -2048 + # CHECK-INST: movltz a7, a8, a9 # CHECK: encoding: [0x90,0x78,0xa3] movltz a7, a8, a9 @@ -82,10 +103,74 @@ nop # CHECK: encoding: [0x60,0x45,0x20] or a4, a5, a6 +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr a8, sar +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr.sar a8 +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr a8, 3 + # CHECK-INST: rsync # CHECK: encoding: [0x10,0x20,0x00] rsync +# CHECK-INST: s8i a2, a1, 3 +# CHECK: encoding: [0x22,0x41,0x03] +s8i a2, sp, 3 +# CHECK-INST: s16i a3, a1, 4 +# CHECK: encoding: [0x32,0x51,0x02] +s16i a3, sp, 4 +# CHECK-INST: s32i a5, a1, 8 +# CHECK: encoding: [0x52,0x61,0x02] +s32i a5, sp, 8 + +# CHECK-INST: sll a10, a11 +# CHECK: encoding: [0x00,0xab,0xa1] +sll a10, a11 + +# CHECK-INST: slli a5, a1, 15 +# CHECK: encoding: [0x10,0x51,0x11] +slli a5, a1, 15 + +# CHECK-INST: sra a12, a3 +# CHECK: encoding: [0x30,0xc0,0xb1] +sra a12, a3 + +# CHECK-INST: srai a8, a5, 0 +# CHECK: encoding: [0x50,0x80,0x21] +srai a8, a5, 0 + +# CHECK-INST: src a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x81] +src a3, a4, a5 + +# CHECK-INST: srl a6, a7 +# CHECK: encoding: [0x70,0x60,0x91] +srl a6, a7 + +# CHECK-INST: srli a3, a4, 8 +# CHECK: encoding: [0x40,0x38,0x41] +srli a3, a4, 8 + +# CHECK-INST: ssa8l a14 +# CHECK: encoding: [0x00,0x2e,0x40] +ssa8l a14 + +# CHECK-INST: ssai 31 +# CHECK: encoding: [0x10,0x4f,0x40] +ssai 31 + +# CHECK-INST: ssl a0 +# CHECK: encoding: [0x00,0x10,0x40] +ssl a0 + +# CHECK-INST: ssr a2 +# CHECK: encoding: [0x00,0x02,0x40] +ssr a2 + # CHECK-INST: sub a8, a2, a1 # CHECK: encoding: [0x10,0x82,0xc0] sub a8, a2, a1 @@ -99,6 +184,26 @@ subx4 a3, sp, a6 # CHECK: encoding: [0x70,0x41,0xf0] subx8 a4, sp, a7 +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, sar +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr.sar a8 +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, 3 + # CHECK-INST: xor a6, a4, a5 # CHECK: encoding: [0x50,0x64,0x30] xor a6, a4, a5 + +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr a8, sar +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61 +xsr.sar a8 +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61 +xsr a8, 3 From 1fabd10ab3ee040f926404390da988a39a826f8e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:05 +0300 Subject: [PATCH 009/150] [Xtensa] Add basic support of Xtensa disassembler. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 2 + .../Target/Xtensa/Disassembler/CMakeLists.txt | 11 + .../Disassembler/XtensaDisassembler.cpp | 207 ++++++++++++++++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 6 +- llvm/lib/Target/Xtensa/XtensaOperands.td | 24 +- 5 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt create mode 100644 llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 62731a2cce34a..7192f7392072b 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_TARGET_DEFINITIONS Xtensa.td) tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) @@ -29,6 +30,7 @@ add_llvm_target(XtensaCodeGen ) add_subdirectory(AsmParser) +add_subdirectory(Disassembler) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt b/llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt new file mode 100644 index 0000000000000..43f235b7cd31d --- /dev/null +++ b/llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt @@ -0,0 +1,11 @@ +add_llvm_component_library(LLVMXtensaDisassembler + XtensaDisassembler.cpp + + LINK_COMPONENTS + MCDisassembler + Support + XtensaInfo + + ADD_TO_COMPONENT + Xtensa + ) diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp new file mode 100644 index 0000000000000..c3fca21d2a0cf --- /dev/null +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -0,0 +1,207 @@ +//===-- XtensaDisassembler.cpp - Disassembler for Xtensa ------------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 implements the XtensaDisassembler class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDecoderOps.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; + +#define DEBUG_TYPE "Xtensa-disassembler" + +using DecodeStatus = MCDisassembler::DecodeStatus; + +namespace { + +class XtensaDisassembler : public MCDisassembler { + bool IsLittleEndian; + +public: + XtensaDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool isLE) + : MCDisassembler(STI, Ctx), IsLittleEndian(isLE) {} + + bool hasDensity() const { + return STI.getFeatureBits()[Xtensa::FeatureDensity]; + } + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &CStream) const override; +}; +} // end anonymous namespace + +static MCDisassembler *createXtensaDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new XtensaDisassembler(STI, Ctx, true); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaDisassembler() { + TargetRegistry::RegisterMCDisassembler(TheXtensaTarget, + createXtensaDisassembler); +} + +static const unsigned ARDecoderTable[] = { + Xtensa::A0, Xtensa::SP, Xtensa::A2, Xtensa::A3, Xtensa::A4, Xtensa::A5, + Xtensa::A6, Xtensa::A7, Xtensa::A8, Xtensa::A9, Xtensa::A10, Xtensa::A11, + Xtensa::A12, Xtensa::A13, Xtensa::A14, Xtensa::A15}; + +static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= array_lengthof(ARDecoderTable)) + return MCDisassembler::Fail; + + unsigned Reg = ARDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3}; + +static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 255) + return MCDisassembler::Fail; + + for (unsigned i = 0; i < array_lengthof(SRDecoderTable); i += 2) { + if (SRDecoderTable[i + 1] == RegNo) { + unsigned Reg = SRDecoderTable[i]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; + } + } + + return MCDisassembler::Fail; +} + +static DecodeStatus decodeImm8Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm8_sh8Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Imm << 8))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm12Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeUimm4Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeUimm5Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<5>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm + 1)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<5>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(32 - Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 4) & 0xff)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem16Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 3) & 0x1fe)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem32Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3fc)); + return MCDisassembler::Success; +} + +/// Read four bytes from the ArrayRef and return 24 bit data sorted +/// according to the given endianness. +static DecodeStatus readInstruction24(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsLittleEndian) { + // We want to read exactly 3 Bytes of data. + if (Bytes.size() < 3) { + Size = 0; + return MCDisassembler::Fail; + } + + if (!IsLittleEndian) { + report_fatal_error("Big-endian mode currently is not supported!"); + } else { + Insn = (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0); + } + + return MCDisassembler::Success; +} + +#include "XtensaGenDisassemblerTables.inc" + +DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &CS) const { + uint32_t Insn; + DecodeStatus Result; + + Result = readInstruction24(Bytes, Address, Size, Insn, IsLittleEndian); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + LLVM_DEBUG(dbgs() << "Trying Xtensa 24-bit instruction table :\n"); + Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI); + Size = 3; + return Result; +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index 1d4e99165765b..c494ca7825ad0 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -82,11 +82,11 @@ void XtensaInstPrinter::printOperand(const MCInst *MI, int OpNum, printOperand(MI->getOperand(OpNum), O); } -void XtensaInstPrinter::printMemOperand(const MCInst *MI, int opNum, +void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum, raw_ostream &OS) { - OS << getRegisterName(MI->getOperand(opNum).getReg()); + OS << getRegisterName(MI->getOperand(OpNum).getReg()); OS << ", "; - printOperand(MI, opNum + 1, OS); + printOperand(MI, OpNum + 1, OS); } void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum, diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index c8fca6f5e7bff..3f73f91fe16e1 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -25,6 +25,7 @@ class Immediate def Imm8_AsmOperand : ImmAsmOperand<"Imm8">; def imm8 : Immediate= -128 && Imm <= 127; }], "Imm8_AsmOperand"> { let EncoderMethod = "getImm8OpValue"; + let DecoderMethod = "decodeImm8Operand"; } // imm8_sh8 predicate - Immediate in the range [-32768,32512] with (bits[7-0] == 0) @@ -33,42 +34,49 @@ def Imm8_sh8_AsmOperand : ImmAsmOperand<"Imm8_sh8">; def imm8_sh8 : Immediate= -32768 && Imm <= 32512 && ((Imm & 0xFF) == 0); }], "Imm8_sh8_AsmOperand"> { let EncoderMethod = "getImm8_sh8OpValue"; + let DecoderMethod = "decodeImm8_sh8Operand"; } // imm12 predicate - Immediate in the range [-2048,2047] def Imm12_AsmOperand : ImmAsmOperand<"Imm12">; def imm12 : Immediate= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> { let EncoderMethod = "getImm12OpValue"; + let DecoderMethod = "decodeImm12Operand"; } // imm12m predicate - Immediate for MOV operation def Imm12m_AsmOperand : ImmAsmOperand<"Imm12m">; def imm12m : Immediate= -2048 && Imm <= 2047; }], "Imm12m_AsmOperand"> { let EncoderMethod = "getImm12OpValue"; + let DecoderMethod = "decodeImm12Operand"; } // uimm4 predicate - Immediate in the range [0,15] def Uimm4_AsmOperand : ImmAsmOperand<"Uimm4">; def uimm4 : Immediate= 0 && Imm <= 15; }], "Uimm4_AsmOperand"> { let EncoderMethod = "getUimm4OpValue"; + let DecoderMethod = "decodeUimm4Operand"; } // uimm5 predicate - Immediate in the range [0,31] def Uimm5_AsmOperand : ImmAsmOperand<"Uimm5">; def uimm5 : Immediate= 0 && Imm <= 31; }], "Uimm5_AsmOperand"> { let EncoderMethod = "getUimm5OpValue"; + let DecoderMethod = "decodeUimm5Operand"; } // imm1_16 predicate - Immediate in the range [1,16] def Imm1_16_AsmOperand : ImmAsmOperand<"Imm1_16">; def imm1_16 : Immediate= 1 && Imm <= 16; }], "Imm1_16_AsmOperand"> { let EncoderMethod = "getImm1_16OpValue"; + let DecoderMethod = "decodeImm1_16Operand"; } // shimm1_31 predicate - Immediate in the range [1,31] def Shimm1_31_AsmOperand : ImmAsmOperand<"Shimm1_31">; def shimm1_31 : Immediate= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> { let EncoderMethod = "getShimm1_31OpValue"; + let DecoderMethod = "decodeShimm1_31Operand"; } // Memory offset 0..255 for 8-bit memory accesses @@ -105,13 +113,21 @@ class mem : Operand { let PrintMethod = "printMemOperand"; } -def mem8 : mem; +def mem8 : mem { + let DecoderMethod = "decodeMem8Operand"; +} -def mem16 : mem; +def mem16 : mem { + let DecoderMethod = "decodeMem16Operand"; +} -def mem32 : mem; +def mem32 : mem { + let DecoderMethod = "decodeMem32Operand"; +} -def mem32n : mem; +def mem32n : mem { + let DecoderMethod = "decodeMem32nOperand"; +} //Add patterns for future use in stack addressing mode def addr_ish1 : ComplexPattern; From edd85c21bb1b1fd8f3003e2f5550831905d11fca Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:06 +0300 Subject: [PATCH 010/150] [Xtensa] Add support of the rest part of Xtensa Core Instructions. Add relocations and fixups support in object files generation. Modify tests to support new instructions. Add tests for relocations and fixups. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 103 +++++++++ .../Disassembler/XtensaDisassembler.cpp | 74 +++++++ .../Target/Xtensa/MCTargetDesc/CMakeLists.txt | 1 + .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp | 109 ++++++++- .../MCTargetDesc/XtensaELFObjectWriter.cpp | 8 +- .../Xtensa/MCTargetDesc/XtensaFixupKinds.h | 32 +++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 126 +++++++++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 6 + .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 207 ++++++++++++++++++ .../Xtensa/MCTargetDesc/XtensaMCExpr.cpp | 63 ++++++ .../Target/Xtensa/MCTargetDesc/XtensaMCExpr.h | 58 +++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 202 +++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 68 ++++++ llvm/test/MC/Xtensa/fixups-diagnostics.s | 14 ++ llvm/test/MC/Xtensa/fixups.s | 54 +++++ llvm/test/MC/Xtensa/relocations.s | 177 +++++++++++++++ llvm/test/MC/Xtensa/xtensa-invalid.s | 12 + llvm/test/MC/Xtensa/xtensa-valid.s | 117 +++++++++- 18 files changed, 1426 insertions(+), 5 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.h create mode 100644 llvm/test/MC/Xtensa/fixups-diagnostics.s create mode 100644 llvm/test/MC/Xtensa/fixups.s create mode 100644 llvm/test/MC/Xtensa/relocations.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 1222c3f0112d4..cc97e03e0b806 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -61,6 +61,7 @@ class XtensaAsmParser : public MCTargetAsmParser { SMLoc &EndLoc) override { return MatchOperand_NoMatch; } + OperandMatchResultTy parsePCRelTarget(OperandVector &Operands); public: enum XtensaMatchResultTy { @@ -178,6 +179,66 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm1_16() const { return isImm(1, 16); } + bool isB4const() const { + if (Kind != Immediate) + return false; + if (auto *CE = dyn_cast(getImm())) { + int64_t Value = CE->getValue(); + switch (Value) { + case -1: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 16: + case 32: + case 64: + case 128: + case 256: + return true; + default: + return false; + } + } + return false; + } + + bool isB4constu() const { + if (Kind != Immediate) + return false; + if (auto *CE = dyn_cast(getImm())) { + int64_t Value = CE->getValue(); + switch (Value) { + case 32768: + case 65536: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 16: + case 32: + case 64: + case 128: + case 256: + return true; + default: + return false; + } + } + return false; + } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -326,6 +387,12 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-32768, 32512], first 8 bits " "should be zero"); + case Match_InvalidB4const: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected b4const immediate"); + case Match_InvalidB4constu: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected b4constu immediate"); case Match_InvalidImm12: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-2048, 2047]"); @@ -364,6 +431,30 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, report_fatal_error("Unknown match type detected!"); } +OperandMatchResultTy +XtensaAsmParser::parsePCRelTarget(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + LLVM_DEBUG(dbgs() << "parsePCRelTarget\n"); + + SMLoc S = getLexer().getLoc(); + + // Expressions are acceptable + const MCExpr *Expr = nullptr; + if (Parser.parseExpression(Expr)) { + // We have no way of knowing if a symbol was consumed so we must ParseFail + return MatchOperand_ParseFail; + } + + // Currently not support constants + if (Expr->getKind() == MCExpr::ExprKind::Constant) { + Error(getLoc(), "unknown operand"); + return MatchOperand_ParseFail; + } + + Operands.push_back(XtensaOperand::createImm(Expr, S, getLexer().getLoc())); + return MatchOperand_Success; +} + bool XtensaAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { const AsmToken &Tok = getParser().getTok(); @@ -479,6 +570,18 @@ XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) { /// If operand was parsed, returns false, else true. bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, bool SR) { + // Check if the current operand has a custom associated parser, if so, try to + // custom parse the operand, or fallback to the general approach. + OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); + if (ResTy == MatchOperand_Success) + return false; + + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. + if (ResTy == MatchOperand_ParseFail) + return true; + // Attempt to parse token as register if (parseRegister(Operands, true, SR) == MatchOperand_Success) return false; diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index c3fca21d2a0cf..b98613fe175a4 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -93,6 +93,59 @@ static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Fail; } +static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch, + uint64_t Address, uint64_t Offset, + uint64_t InstSize, MCInst &MI, + const void *Decoder) { + const MCDisassembler *Dis = static_cast(Decoder); + return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch, Offset, /*OpSize=*/0, + InstSize); +} + +static DecodeStatus decodeCallOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<18>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Imm << 2))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeJumpOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<18>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<18>(Imm))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + switch (Inst.getOpcode()) { + case Xtensa::BEQZ: + case Xtensa::BGEZ: + case Xtensa::BLTZ: + case Xtensa::BNEZ: + assert(isUInt<12>(Imm) && "Invalid immediate"); + if (!tryAddingSymbolicOperand(SignExtend64<12>(Imm) + 4 + Address, true, + Address, 0, 3, Inst, Decoder)) + Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm))); + break; + default: + assert(isUInt<8>(Imm) && "Invalid immediate"); + if (!tryAddingSymbolicOperand(SignExtend64<8>(Imm) + 4 + Address, true, + Address, 0, 3, Inst, Decoder)) + Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm))); + } + return MCDisassembler::Success; +} + +static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + + assert(isUInt<16>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm( + SignExtend64<17>((Imm << 2) + 0x40000 + (Address & 0x3)))); + return MCDisassembler::Success; +} + static DecodeStatus decodeImm8Operand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { assert(isUInt<8>(Imm) && "Invalid immediate"); @@ -144,6 +197,27 @@ static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static int64_t TableB4const[16] = {-1, 1, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 16, 32, 64, 128, 256}; +static DecodeStatus decodeB4constOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + + Inst.addOperand(MCOperand::createImm(TableB4const[Imm])); + return MCDisassembler::Success; +} + +static int64_t TableB4constu[16] = {32768, 65536, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 16, 32, 64, 128, 256}; +static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + + Inst.addOperand(MCOperand::createImm(TableB4constu[Imm])); + return MCDisassembler::Success; +} + static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { assert(isUInt<12>(Imm) && "Invalid immediate"); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt index 3dad67b1e9a6a..6841b44f9d569 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt @@ -4,6 +4,7 @@ add_llvm_component_library(LLVMXtensaDesc XtensaInstPrinter.cpp XtensaMCAsmInfo.cpp XtensaMCCodeEmitter.cpp + XtensaMCExpr.cpp XtensaMCTargetDesc.cpp LINK_COMPONENTS diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp index bacc23b562564..6f47c77f64c8f 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp @@ -8,6 +8,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/XtensaFixupKinds.h" #include "MCTargetDesc/XtensaMCTargetDesc.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" @@ -31,7 +32,9 @@ class XtensaMCAsmBackend : public MCAsmBackend { XtensaMCAsmBackend(uint8_t osABI, bool isLE) : MCAsmBackend(support::little), OSABI(osABI), IsLittleEndian(isLE) {} - unsigned getNumFixupKinds() const override { return 1; } + unsigned getNumFixupKinds() const override { + return Xtensa::NumTargetFixupKinds; + } const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, @@ -55,13 +58,113 @@ class XtensaMCAsmBackend : public MCAsmBackend { const MCFixupKindInfo & XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { - return MCAsmBackend::getFixupKindInfo(MCFixupKind::FK_NONE); + const static MCFixupKindInfo Infos[Xtensa::NumTargetFixupKinds] = { + // name offset bits flags + {"fixup_xtensa_branch_6", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_xtensa_branch_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_xtensa_branch_12", 12, 12, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_xtensa_jump_18", 6, 18, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_xtensa_call_18", 6, 18, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, + {"fixup_xtensa_l32r_16", 8, 16, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; +} + +static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + MCContext &Ctx) { + unsigned Kind = Fixup.getKind(); + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + return Value; + case Xtensa::fixup_xtensa_branch_6: { + Value -= 4; + if (!isInt<6>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + unsigned Hi2 = (Value >> 4) & 0x3; + unsigned Lo4 = Value & 0xf; + return (Hi2 << 4) | (Lo4 << 12); + } + case Xtensa::fixup_xtensa_branch_8: + Value -= 4; + if (!isInt<8>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + return (Value & 0xff); + case Xtensa::fixup_xtensa_branch_12: + Value -= 4; + if (!isInt<12>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + return (Value & 0xfff); + case Xtensa::fixup_xtensa_jump_18: + Value -= 4; + if (!isInt<18>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + return (Value & 0x3ffff); + case Xtensa::fixup_xtensa_call_18: + Value -= 4; + if (!isInt<20>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); + return (Value & 0xffffc) >> 2; + case Xtensa::fixup_xtensa_l32r_16: + unsigned Offset = Fixup.getOffset(); + if (Offset & 0x3) + Value -= 4; + if (!isInt<18>(Value) && (Value & 0x20000)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); + return (Value & 0x3fffc) >> 2; + } } + +static unsigned getSize(unsigned Kind) { + switch (Kind) { + default: + return 3; + case MCFixupKind::FK_Data_4: + return 4; + case Xtensa::fixup_xtensa_branch_6: + return 2; + } +} + void XtensaMCAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, uint64_t Value, bool IsResolved, - const MCSubtargetInfo *STI) const {} + const MCSubtargetInfo *STI) const { + MCContext &Ctx = Asm.getContext(); + MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + + Value = adjustFixupValue(Fixup, Value, Ctx); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + if (!Value) + return; // Doesn't change encoding. + + unsigned Offset = Fixup.getOffset(); + unsigned FullSize = getSize(Fixup.getKind()); + + for (unsigned i = 0; i != FullSize; ++i) { + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); + } +} bool XtensaMCAsmBackend::mayNeedRelaxation(const MCInst &Inst, const MCSubtargetInfo &STI) const { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp index d407e188ab81b..7788790ee66c2 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp @@ -46,7 +46,13 @@ XtensaObjectWriter::~XtensaObjectWriter() {} unsigned XtensaObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { - report_fatal_error("invalid fixup kind!"); + + switch ((unsigned)Fixup.getKind()) { + case FK_Data_4: + return ELF::R_XTENSA_32; + default: + return ELF::R_XTENSA_SLOT0_OP; + } } std::unique_ptr diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h new file mode 100644 index 0000000000000..ebbfe0320afd4 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h @@ -0,0 +1,32 @@ +//===-- XtensaMCFixups.h - Xtensa-specific fixup entries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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_XTENSA_MCTARGETDESC_XTENSAMCFIXUPS_H +#define LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCFIXUPS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace Xtensa { +enum FixupKind { + fixup_xtensa_branch_6 = FirstTargetFixupKind, + fixup_xtensa_branch_8, + fixup_xtensa_branch_12, + fixup_xtensa_jump_18, + fixup_xtensa_call_18, + fixup_xtensa_l32r_16, + fixup_xtensa_invalid, + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} // end namespace Xtensa +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCFIXUPS_H */ diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index c494ca7825ad0..81b375a783206 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -89,6 +89,70 @@ void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum, printOperand(MI, OpNum + 1, OS); } +void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum, + raw_ostream &OS) { + const MCOperand &MC = MI->getOperand(OpNum); + if (MI->getOperand(OpNum).isImm()) { + int64_t Val = MC.getImm() + 4; + OS << ". "; + if (Val > 0) + OS << '+'; + OS << Val; + } else if (MC.isExpr()) + MC.getExpr()->print(OS, &MAI, true); + else + llvm_unreachable("Invalid operand"); +} + +void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum, + raw_ostream &OS) { + const MCOperand &MC = MI->getOperand(OpNum); + if (MC.isImm()) { + int64_t Val = MC.getImm() + 4; + OS << ". "; + if (Val > 0) + OS << '+'; + OS << Val; + } else if (MC.isExpr()) + MC.getExpr()->print(OS, &MAI, true); + else + llvm_unreachable("Invalid operand"); + ; +} + +void XtensaInstPrinter::printCallOperand(const MCInst *MI, int OpNum, + raw_ostream &OS) { + const MCOperand &MC = MI->getOperand(OpNum); + if (MC.isImm()) { + int64_t Val = MC.getImm() + 4; + OS << ". "; + if (Val > 0) + OS << '+'; + OS << Val; + } else if (MC.isExpr()) + MC.getExpr()->print(OS, &MAI, true); + else + llvm_unreachable("Invalid operand"); +} + +void XtensaInstPrinter::printL32RTarget(const MCInst *MI, int OpNum, + raw_ostream &O) { + const MCOperand &MC = MI->getOperand(OpNum); + if (MC.isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + int64_t InstrOff = Value & 0x3; + Value -= InstrOff; + assert((Value >= -262144 && Value <= -4) && + "Invalid argument, value must be in ranges [-262144,-4]"); + Value += ((InstrOff + 0x3) & 0x4) - InstrOff; + O << ". "; + O << Value; + } else if (MC.isExpr()) + MC.getExpr()->print(O, &MAI, true); + else + llvm_unreachable("Invalid operand"); +} + void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { @@ -220,3 +284,65 @@ void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, } else printOperand(MI, OpNum, O); } + +void XtensaInstPrinter::printB4const_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + + switch (Value) { + case -1: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 16: + case 32: + case 64: + case 128: + case 256: + break; + default: + assert((0) && "Invalid B4const argument"); + } + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + + switch (Value) { + case 32768: + case 65536: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 16: + case 32: + case 64: + case 128: + case 256: + break; + default: + assert((0) && "Invalid B4constu argument"); + } + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index 5d62a9c3011fd..ebbfda967f26a 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -44,6 +44,10 @@ class XtensaInstPrinter : public MCInstPrinter { // Print various types of operand. void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O); + void printBranchTarget(const MCInst *MI, int OpNum, raw_ostream &O); + void printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &O); + void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printL32RTarget(const MCInst *MI, int OpNum, raw_ostream &O); void printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); @@ -57,6 +61,8 @@ class XtensaInstPrinter : public MCInstPrinter { void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index c52bfd33ce6b9..1ef5b110c927e 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/XtensaFixupKinds.h" +#include "MCTargetDesc/XtensaMCExpr.h" #include "MCTargetDesc/XtensaMCTargetDesc.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -20,6 +22,10 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#define GET_INSTRMAP_INFO +#include "XtensaGenInstrInfo.inc" +#undef GET_INSTRMAP_INFO + using namespace llvm; #define DEBUG_TYPE "mccodeemitter" @@ -53,6 +59,22 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getJumpTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getBranchTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getL32RTargetEncoding(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getMemRegEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -84,6 +106,14 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + uint32_t getB4constOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // namespace @@ -126,6 +156,85 @@ XtensaMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, return 0; } +uint32_t +XtensaMCCodeEmitter::getJumpTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNum); + + if (MO.isImm()) + return MO.getImm(); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_jump_18), MI.getLoc())); + return 0; +} + +uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding( + const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNum); + if (MO.isImm()) + return static_cast(MO.getImm()); + + const MCExpr *Expr = MO.getExpr(); + switch (MI.getOpcode()) { + case Xtensa::BEQZ: + case Xtensa::BGEZ: + case Xtensa::BLTZ: + case Xtensa::BNEZ: + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_12), MI.getLoc())); + return 0; + default: + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_branch_8), MI.getLoc())); + return 0; + } +} + +uint32_t +XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNum); + if (MO.isImm()) { + int32_t Res = MO.getImm(); + if (Res & 0x3) { + llvm_unreachable("Unexpected operand value!"); + } + Res >>= 2; + return Res; + } + + assert((MO.isExpr()) && "Unexpected operand value!"); + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_call_18), MI.getLoc())); + return 0; +} + +uint32_t +XtensaMCCodeEmitter::getL32RTargetEncoding(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNum); + if (MO.isImm()) { + int32_t Res = MO.getImm(); + // We don't check first 2 bits, because in these bits we could store first 2 + // bits of instruction address + Res >>= 2; + return Res; + } + + assert((MO.isExpr()) && "Unexpected operand value!"); + + Fixups.push_back(MCFixup::create( + 0, MO.getExpr(), MCFixupKind(Xtensa::fixup_xtensa_l32r_16), MI.getLoc())); + return 0; +} + uint32_t XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, @@ -243,4 +352,102 @@ XtensaMCCodeEmitter::getImm1_16OpValue(const MCInst &MI, unsigned OpNo, return (Res - 1); } + +uint32_t +XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + switch (Res) { + case 0xffffffff: + Res = 0; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + break; + case 10: + Res = 9; + break; + case 12: + Res = 10; + break; + case 16: + Res = 11; + break; + case 32: + Res = 12; + break; + case 64: + Res = 13; + break; + case 128: + Res = 14; + break; + case 256: + Res = 15; + break; + default: + llvm_unreachable("Unexpected operand value!"); + } + + return Res; +} + +uint32_t +XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + switch (Res) { + case 32768: + Res = 0; + break; + case 65536: + Res = 1; + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + break; + case 10: + Res = 9; + break; + case 12: + Res = 10; + break; + case 16: + Res = 11; + break; + case 32: + Res = 12; + break; + case 64: + Res = 13; + break; + case 128: + Res = 14; + break; + case 256: + Res = 15; + break; + default: + llvm_unreachable("Unexpected operand value!"); + } + + return Res; +} #include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.cpp new file mode 100644 index 0000000000000..cafd8b7e29782 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.cpp @@ -0,0 +1,63 @@ +//===-- XtensaMCExpr.cpp - Xtensa specific MC expression classes ----------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the implementation of the assembly expression modifiers +// accepted by the Xtensa architecture +// +//===----------------------------------------------------------------------===// + +#include "XtensaMCExpr.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensamcexpr" + +const XtensaMCExpr *XtensaMCExpr::create(const MCExpr *Expr, VariantKind Kind, + MCContext &Ctx) { + return new (Ctx) XtensaMCExpr(Expr, Kind); +} + +void XtensaMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + bool HasVariant = getKind() != VK_Xtensa_None; + if (HasVariant) + OS << '%' << getVariantKindName(getKind()) << '('; + Expr->print(OS, MAI); + if (HasVariant) + OS << ')'; +} + +bool XtensaMCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); +} + +void XtensaMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} + +XtensaMCExpr::VariantKind XtensaMCExpr::getVariantKindForName(StringRef name) { + return StringSwitch(name).Default( + VK_Xtensa_Invalid); +} + +StringRef XtensaMCExpr::getVariantKindName(VariantKind Kind) { + switch (Kind) { + default: + llvm_unreachable("Invalid ELF symbol kind"); + } +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.h new file mode 100644 index 0000000000000..f72b832024369 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCExpr.h @@ -0,0 +1,58 @@ +//===-- XtensaMCExpr.h - Xtensa specific MC expression classes --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 describes Xtensa-specific MCExprs +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_Xtensa_MCTARGETDESC_XtensaMCEXPR_H +#define LLVM_LIB_TARGET_Xtensa_MCTARGETDESC_XtensaMCEXPR_H + +#include "llvm/MC/MCExpr.h" + +namespace llvm { + +class StringRef; +class XtensaMCExpr : public MCTargetExpr { +public: + enum VariantKind { VK_Xtensa_None, VK_Xtensa_Invalid }; + +private: + const MCExpr *Expr; + const VariantKind Kind; + + explicit XtensaMCExpr(const MCExpr *Expr, VariantKind Kind) + : Expr(Expr), Kind(Kind) {} + +public: + static const XtensaMCExpr *create(const MCExpr *Expr, VariantKind Kind, + MCContext &Ctx); + + VariantKind getKind() const { return Kind; } + + const MCExpr *getSubExpr() const { return Expr; } + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + MCFragment *findAssociatedFragment() const override { + return getSubExpr()->findAssociatedFragment(); + } + + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + static VariantKind getVariantKindForName(StringRef name); + static StringRef getVariantKindName(VariantKind Kind); +}; + +} // end namespace llvm. + +#endif diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index f0741eaf554f8..78319dd458791 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -232,6 +232,208 @@ def S8I : Store_II8<0x04, "s8i", truncstorei8, addr_ish1, mem8>; def S16I : Store_II8<0x05, "s16i", truncstorei16, addr_ish2, mem16>; def S32I : Store_II8<0x06, "s32i", store, addr_ish4, mem32>; +def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label), + "l32r\t$t, $label", []> { + bits<16> label; + let imm16 = label; +} + +//===----------------------------------------------------------------------===// +// Conditional branch instructions +//===----------------------------------------------------------------------===// +let isBranch = 1, isTerminator = 1 in { + class Branch_RR oper, string instrAsm, CondCode CC> + : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + instrAsm#"\t$s, $t, $target", + [(brcc CC, AR:$s, AR:$t, bb:$target)]> { + bits<8> target; + + let r = oper; + let imm8 = target; + } + + class Branch_RI oper, string instrAsm, CondCode CC> + : RRI8_Inst<0x06, (outs), + (ins AR:$s, b4const:$imm, brtarget:$target), + instrAsm#"\t$s, $imm, $target", + [(brcc CC, AR:$s, b4const:$imm, bb:$target)]> { + bits<4> imm; + bits<8> target; + + let t = oper; + let r = imm; + let imm8 = target; + } + + class Branch_RIU oper, string instrAsm, CondCode CC> + : RRI8_Inst<0x06, (outs), + (ins AR:$s, b4constu:$imm, brtarget:$target), + instrAsm#"\t$s, $imm, $target", + [(brcc CC, AR:$s, b4constu:$imm, bb:$target)]> { + bits<4> imm; + bits<8> target; + + let t = oper; + let r = imm; + let imm8 = target; + } + + class Branch_RZ n, bits<2> m, string instrAsm, CondCode CC> + : BRI12_Inst<0x06, n, m, (outs), + (ins AR:$s, brtarget:$target), + instrAsm#"\t$s, $target", + [(brcc CC, AR:$s, (i32 0), bb:$target)]> { + bits<12> target; + + let imm12 = target; + } +} + +def BEQ : Branch_RR<0x01, "beq", SETEQ>; +def BNE : Branch_RR<0x09, "bne", SETNE>; +def BGE : Branch_RR<0x0A, "bge", SETGE>; +def BLT : Branch_RR<0x02, "blt", SETLT>; +def BGEU : Branch_RR<0x0B, "bgeu", SETUGE>; +def BLTU : Branch_RR<0x03, "bltu", SETULT>; + +def BEQI : Branch_RI<0x02, "beqi", SETEQ>; +def BNEI : Branch_RI<0x06, "bnei", SETNE>; +def BGEI : Branch_RI<0x0E, "bgei", SETGE>; +def BLTI : Branch_RI<0x0A, "blti", SETLT>; +def BGEUI : Branch_RIU<0x0F, "bgeui", SETUGE>; +def BLTUI : Branch_RIU<0x0B, "bltui", SETULT>; + +def BEQZ : Branch_RZ<0x01, 0x00, "beqz", SETEQ>; +def BNEZ : Branch_RZ<0x01, 0x01, "bnez", SETNE>; +def BGEZ : Branch_RZ<0x01, 0x03, "bgez", SETGE>; +def BLTZ : Branch_RZ<0x01, 0x02, "bltz", SETLT>; + +def BALL : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + "ball\t$s, $t, $target", []> { + bits<8> target; + + let r = 0x04; + let imm8 = target; +} + +def BANY : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + "bany\t$s, $t, $target", []> { + bits<8> target; + + let r = 0x08; + let imm8 = target; +} + +def BBC : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + "bbc\t$s, $t, $target", []> { + bits<8> target; + + let r = 0x05; + let imm8 = target; +} + +def BBS : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + "bbs\t$s, $t, $target", []> { + bits<8> target; + + let r = 0x0d; + let imm8 = target; +} + +def BNALL : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + "bnall\t$s, $t, $target", []> { + bits<8> target; + + let r = 0x0c; + let imm8 = target; +} + +def BNONE : RRI8_Inst<0x07, (outs), + (ins AR:$s, AR:$t, brtarget:$target), + "bnone\t$s, $t, $target", []> { + bits<8> target; + + let r = 0x00; + let imm8 = target; +} + +def BBCI : RRI8_Inst<0x07, (outs), + (ins AR:$s, uimm5:$imm, brtarget:$target), + "bbci\t$s, $imm, $target", []> { + bits<8> target; + bits<5> imm; + + let r{3-1} = 0x3; + let r{0} = imm{4}; + let t{3-0} = imm{3-0}; + let imm8 = target; +} + +def BBSI : RRI8_Inst<0x07, (outs), + (ins AR:$s, uimm5:$imm, brtarget:$target), + "bbsi\t$s, $imm, $target", []> { + bits<8> target; + bits<5> imm; + + let r{3-1} = 0x7; + let r{0} = imm{4}; + let t{3-0} = imm{3-0}; + let imm8 = target; +} + +//===----------------------------------------------------------------------===// +// Call and jump instructions +//===----------------------------------------------------------------------===// + +let isBranch = 1, isTerminator = 1, isBarrier = 1 in { + def J : CALL_Inst<0x06, (outs), (ins jumptarget:$offset), + "j\t$offset", + [(br bb:$offset)]> { + let n = 0x0; + } + + def JX : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s), + "jx\t$s", + [(brind AR:$s)]> { + let m = 0x2; + let n = 0x2; + let r = 0; + let isIndirectBranch = 1; + } +} + +let isCall = 1, Defs = [A0] in { + def CALL0 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset), + "call0\t$offset", []> { + let n = 0; + } + + def CALLX0 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s), + "callx0\t$s", []> { + let m = 0x3; + let n = 0x0; + let r = 0; + } +} + +let isReturn = 1, isTerminator = 1, + isBarrier = 1, Uses = [A0] in { + + def RET : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins), + "ret", []> { + let m = 0x2; + let n = 0x0; + let s = 0; + let r = 0; + } +} + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 3f73f91fe16e1..7a1a2e86e8c20 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -102,6 +102,36 @@ def Offset4m32_AsmOperand : ImmAsmOperand<"Offset4m32">; def offset4m32 : Immediate= 0 && Imm <= 60 && (Imm & 0x3 == 0); }], "Offset4m32_AsmOperand">; + +// b4const predicate - Branch Immediate 4-bit signed operand +def B4const_AsmOperand: ImmAsmOperand<"B4const">; +def b4const: Immediate { + let EncoderMethod = "getB4constOpValue"; + let DecoderMethod = "decodeB4constOperand"; +} + +// b4constu predicate - Branch Immediate 4-bit unsigned operand +def B4constu_AsmOperand: ImmAsmOperand<"B4constu">; +def b4constu: Immediate { + let EncoderMethod = "getB4constuOpValue"; + let DecoderMethod = "decodeB4constuOperand"; +} //===----------------------------------------------------------------------===// // Memory address operands //===----------------------------------------------------------------------===// @@ -133,3 +163,41 @@ def mem32n : mem { def addr_ish1 : ComplexPattern; def addr_ish2 : ComplexPattern; def addr_ish4 : ComplexPattern; + +//===----------------------------------------------------------------------===// +// Symbolic address operands +//===----------------------------------------------------------------------===// +def XtensaPCRelTargetAsmOperand : AsmOperandClass { + let Name = "PCRelTarget"; + let ParserMethod = "parsePCRelTarget"; + let PredicateMethod = "isImm"; + let RenderMethod = "addImmOperands"; +} + +def pcrel32call : Operand { + let PrintMethod = "printCallOperand"; + let EncoderMethod = "getCallEncoding"; + let DecoderMethod = "decodeCallOperand"; + let ParserMatchClass = XtensaPCRelTargetAsmOperand; +} + +def brtarget : Operand { + let PrintMethod = "printBranchTarget"; + let EncoderMethod = "getBranchTargetEncoding"; + let DecoderMethod = "decodeBranchOperand"; + let ParserMatchClass = XtensaPCRelTargetAsmOperand; +} + +def jumptarget : Operand { + let PrintMethod = "printJumpTarget"; + let EncoderMethod = "getJumpTargetEncoding"; + let DecoderMethod = "decodeJumpOperand"; + let ParserMatchClass = XtensaPCRelTargetAsmOperand; +} + +def L32Rtarget : Operand { + let PrintMethod = "printL32RTarget"; + let EncoderMethod = "getL32RTargetEncoding"; + let DecoderMethod = "decodeL32ROperand"; + let ParserMatchClass = XtensaPCRelTargetAsmOperand; +} diff --git a/llvm/test/MC/Xtensa/fixups-diagnostics.s b/llvm/test/MC/Xtensa/fixups-diagnostics.s new file mode 100644 index 0000000000000..e0eac900552ce --- /dev/null +++ b/llvm/test/MC/Xtensa/fixups-diagnostics.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc -triple xtensa -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s + + .align 4 + + beq a0, a1, LBL1 # CHECK: :[[@LINE]]:3: error: fixup value out of range +LBL0: + beqz a0, LBL2 # CHECK: :[[@LINE]]:3: error: fixup value out of range + + call0 LBL0 # CHECK: :[[@LINE]]:3: error: fixup value must be 4-byte aligned + + .space 1<<8 +LBL1: + .space 1<<12 +LBL2: diff --git a/llvm/test/MC/Xtensa/fixups.s b/llvm/test/MC/Xtensa/fixups.s new file mode 100644 index 0000000000000..cd76f2a23322d --- /dev/null +++ b/llvm/test/MC/Xtensa/fixups.s @@ -0,0 +1,54 @@ +# RUN: llvm-mc -triple xtensa < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s +# RUN: llvm-mc -filetype=obj -triple xtensa < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s + + +# Checks that fixups that can be resolved within the same object file are +# applied correctly +.align 4 +LBL0: + +.fill 12 + +beq a0, a1, LBL0 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_8 +# CHECK-INSTR: beq a0, a1, . -12 + +beq a0, a1, LBL1 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_8 +# CHECK-INSTR: beq a0, a1, . +24 + +beqz a2, LBL0 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_12 +# CHECK-INSTR: beqz a2, . -18 + +beqz a2, LBL1 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_12 +# CHECK-INSTR: beqz a2, . +18 + +call0 LBL0 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_call_18 +# CHECK-INSTR: call0 . -24 + +call0 LBL2 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_call_18 +# CHECK-INSTR: call0 . +2056 + +j LBL0 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_jump_18 +# CHECK-INSTR: j . -30 + +j LBL2 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_jump_18 +# CHECK-INSTR: j . +2047 + +l32r a1, LBL0 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_l32r_16 +# CHECK-INSTR: l32r a1, . -36 + +LBL1: + +.fill 2041 + +LBL2: diff --git a/llvm/test/MC/Xtensa/relocations.s b/llvm/test/MC/Xtensa/relocations.s new file mode 100644 index 0000000000000..19c2e16352509 --- /dev/null +++ b/llvm/test/MC/Xtensa/relocations.s @@ -0,0 +1,177 @@ +# RUN: llvm-mc -triple xtensa < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s +# RUN: llvm-mc -filetype=obj -triple xtensa < %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s + +# Check prefixes: +# RELOC - Check the relocation in the object. +# FIXUP - Check the fixup on the instruction. +# INSTR - Check the instruction is handled properly by the ASMPrinter + +.long func +# RELOC: R_XTENSA_32 func + +ball a1, a3, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: ball a1, a3, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bany a8, a13, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bany a8, a13, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bbc a8, a7, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bbc a8, a7, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bbci a3, 16, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bbci a3, 16, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bbs a12, a5, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bbs a12, a5, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bbsi a3, 16, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bbsi a3, 16, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bnall a7, a3, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bnall a7, a3, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bnone a2, a4, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bnone a2, a4, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +beq a1, a2, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: beq a1, a2, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +beq a11, a5, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: beq a11, a5, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +beqi a1, 256, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: beqi a1, 256, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +beqi a11, -1, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: beqi a11, -1, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +beqz a8, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: beqz a8, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_12 + +bge a14, a2, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bge a14, a2, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgei a11, -1, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgei a11, -1, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgei a11, 128, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgei a11, 128, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgeu a14, a2, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgeu a14, a2, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgeui a9, 32768, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgeui a9, 32768, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgeui a7, 65536, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgeui a7, 65536, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgeui a7, 64, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgeui a7, 64, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgez a8, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgez a8, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_12 + +blt a14, a2, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: blt a14, a2, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +blti a12, -1, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: blti a12, -1, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +blti a0, 32, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: blti a0, 32, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bgeu a13, a1, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bgeu a13, a1, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bltui a7, 16, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bltui a7, 16, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bltz a6, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bltz a6, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_12 + +bne a3, a4, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bne a3, a4, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bnei a5, 12, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bnei a5, 12, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_8 + +bnez a5, func +# RELOC: R_XTENSA_SLOT0_OP +# INST: bnez a5, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_branch_12 + +call0 func +# RELOC: R_XTENSA_SLOT0_OP +# INST: call0 func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_call_18 + +j func +# RELOC: R_XTENSA_SLOT0_OP +# INSTR: j func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_jump_18 + +l32r a6, func +# RELOC: R_XTENSA_SLOT0_OP +# INSTR: l32r a6, func +# FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_l32r_16 diff --git a/llvm/test/MC/Xtensa/xtensa-invalid.s b/llvm/test/MC/Xtensa/xtensa-invalid.s index 555263f9c1876..3cf16d44bd35c 100644 --- a/llvm/test/MC/Xtensa/xtensa-invalid.s +++ b/llvm/test/MC/Xtensa/xtensa-invalid.s @@ -16,6 +16,10 @@ addi a1, a2, 300 addi a1, a2, -129 # CHECK: error: expected immediate in range [-128, 127] +# imm1_16 +extui a1, a2, 5, 17 +# CHECK: error: expected immediate in range [1, 16] + # imm8_sh8 addmi a1, a2, 33 # CHECK: error: expected immediate in range [-32768, 32512], first 8 bits should be zero @@ -48,6 +52,14 @@ l16si a1, a2, 512 l32i a1, a2, 1024 # CHECK: error: expected immediate in range [0, 1020], first 2 bits should be zero +# b4const +beqi a1, 257, LBL0 +# CHECK: error: expected b4const immediate + +# b4constu +bgeui a9, 32000, LBL0 +# CHECK: error: expected b4constu immediate + # Invalid number of operands addi a1, a2 # CHECK: :[[@LINE]]:1: error: too few operands for instruction addi a1, a2, 4, 4 # CHECK: :[[@LINE]]:17: error: invalid operand for instruction diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s index 8fddf99fe961a..a2d4fe5274ed5 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -1,7 +1,6 @@ # RUN: llvm-mc %s -triple=xtensa -show-encoding \ # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s - .align 4 LBL0: @@ -37,6 +36,107 @@ addx4 a3, sp, a6 # CHECK: encoding: [0x70,0x41,0xb0] addx8 a4, sp, a7 +# CHECK-INST: ball a1, a3, LBL0 +# CHECK: encoding: [0x37,0x41,A] +ball a1, a3, LBL0 +# CHECK-INST: bany a8, a13, LBL0 +# CHECK: encoding: [0xd7,0x88,A] +bany a8, a13, LBL0 +# CHECK-INST: bbc a8, a7, LBL0 +# CHECK: encoding: [0x77,0x58,A] +bbc a8, a7, LBL0 +# CHECK-INST: bbci a3, 16, LBL0 +# CHECK: encoding: [0x07,0x73,A] +bbci a3, 16, LBL0 +# CHECK-INST: bbci a3, 16, LBL0 +# CHECK: encoding: [0x07,0x73,A] +bbci a3, (16), LBL0 +# CHECK-INST: bbs a12, a5, LBL0 +# CHECK: encoding: [0x57,0xdc,A] +bbs a12, a5, LBL0 +# CHECK-INST: bbsi a3, 16, LBL0 +# CHECK: encoding: [0x07,0xf3,A] +bbsi a3, 16, LBL0 +# CHECK-INST: bnall a7, a3, LBL0 +# CHECK: encoding: [0x37,0xc7,A] +bnall a7, a3, LBL0 +# CHECK-INST: bnone a2, a4, LBL0 +# CHECK: encoding: [0x47,0x02,A] +bnone a2, a4, LBL0 + +# CHECK-INST: beq a1, a2, LBL0 +# CHECK: encoding: [0x27,0x11,A] +beq a1, a2, LBL0 +# CHECK-INST: beq a11, a5, LBL0 +# CHECK: encoding: [0x57,0x1b,A] +beq a11, a5, LBL0 +# CHECK-INST: beqi a1, 256, LBL0 +# CHECK: encoding: [0x26,0xf1,A] +beqi a1, 256, LBL0 +# CHECK-INST: beqi a11, -1, LBL0 +# CHECK: encoding: [0x26,0x0b,A] +beqi a11, -1, LBL0 +# CHECK-INST: beqz a8, LBL0 +# CHECK: encoding: [0x16,0bAAAA1000,A] +beqz a8, LBL0 +# CHECK-INST: bge a14, a2, LBL0 +# CHECK: encoding: [0x27,0xae,A] +bge a14, a2, LBL0 +# CHECK-INST: bgei a11, -1, LBL0 +# CHECK: encoding: [0xe6,0x0b,A] +bgei a11, -1, LBL0 +# CHECK-INST: bgei a11, 128, LBL0 +# CHECK: encoding: [0xe6,0xeb,A] +bgei a11, 128, LBL0 +# CHECK-INST: bgeu a14, a2, LBL0 +# CHECK: encoding: [0x27,0xbe,A] +bgeu a14, a2, LBL0 +# CHECK-INST: bgeui a9, 32768, LBL0 +# CHECK: encoding: [0xf6,0x09,A] +bgeui a9, 32768, LBL0 +# CHECK-INST: bgeui a7, 65536, LBL0 +# CHECK: encoding: [0xf6,0x17,A] +bgeui a7, 65536, LBL0 +# CHECK-INST: bgeui a7, 64, LBL0 +# CHECK: encoding: [0xf6,0xd7,A] +bgeui a7, 64, LBL0 +# CHECK-INST: bgez a8, LBL0 +# CHECK: encoding: [0xd6,0bAAAA1000,A] +bgez a8, LBL0 +# CHECK-INST: blt a14, a2, LBL0 +# CHECK: encoding: [0x27,0x2e,A] +blt a14, a2, LBL0 +# CHECK-INST: blti a12, -1, LBL0 +# CHECK: encoding: [0xa6,0x0c,A] +blti a12, -1, LBL0 +# CHECK-INST: blti a0, 32, LBL0 +# CHECK: encoding: [0xa6,0xc0,A] +blti a0, 32, LBL0 +# CHECK-INST: bgeu a13, a1, LBL0 +# CHECK: encoding: [0x17,0xbd,A] +bgeu a13, a1, LBL0 +# CHECK-INST: bltui a7, 16, LBL0 +# CHECK: encoding: [0xb6,0xb7,A] +bltui a7, 16, LBL0 +# CHECK-INST: bltz a6, LBL0 +# CHECK: encoding: [0x96,0bAAAA0110,A] +bltz a6, LBL0 +# CHECK-INST: bne a3, a4, LBL0 +# CHECK: encoding: [0x47,0x93,A] +bne a3, a4, LBL0 +# CHECK-INST: bnei a5, 12, LBL0 +# CHECK: encoding: [0x66,0xa5,A] +bnei a5, 12, LBL0 +# CHECK-INST: bnez a5, LBL0 +# CHECK: encoding: [0x56,0bAAAA0101,A] +bnez a5, LBL0 + +# CHECK-INST: call0 LBL0 +# CHECK: encoding: [0bAA000101,A,A] +call0 LBL0 +# CHECK-INST: callx0 a1 +# CHECK: encoding: [0xc0,0x01,0x00] +callx0 a1 # CHECK-INST: dsync # CHECK: encoding: [0x30,0x20,0x00] dsync @@ -56,6 +156,13 @@ extw # CHECK: encoding: [0x00,0x20,0x00] isync +# CHECK-INST: j LBL0 +# CHECK: encoding: [0bAA000110,A,A] +j LBL0 +# CHECK-INST: jx a2 +# CHECK: encoding: [0xa0,0x02,0x00] +jx a2 + # CHECK-INST: l8ui a2, a1, 3 # CHECK: encoding: [0x22,0x01,0x03] l8ui a2, sp, 3 @@ -68,6 +175,9 @@ l16ui a4, sp, 6 # CHECK-INST: l32i a5, a1, 8 # CHECK: encoding: [0x52,0x21,0x02] l32i a5, sp, 8 +# CHECK-INST: l32r a6, LBL0 +# CHECK: encoding: [0x61,A,A] +l32r a6, LBL0 # CHECK-INST: memw # CHECK: encoding: [0xc0,0x20,0x00] @@ -103,6 +213,10 @@ nop # CHECK: encoding: [0x60,0x45,0x20] or a4, a5, a6 +# CHECK-INST: ret +# CHECK: encoding: [0x80,0x00,0x00] +ret + # CHECK-INST: rsr a8, sar # CHECK: encoding: [0x80,0x03,0x03] rsr a8, sar @@ -113,6 +227,7 @@ rsr.sar a8 # CHECK: encoding: [0x80,0x03,0x03] rsr a8, 3 + # CHECK-INST: rsync # CHECK: encoding: [0x10,0x20,0x00] rsync From a4a95a01a1c63798fd59a10b5aa543f9c1007e1e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:06 +0300 Subject: [PATCH 011/150] [Xtensa] Initial support of the ALU operations. Initial codegen support for simple ALU operations. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 11 + llvm/lib/Target/Xtensa/Xtensa.h | 30 ++ llvm/lib/Target/Xtensa/Xtensa.td | 6 + llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 40 +++ llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 42 +++ llvm/lib/Target/Xtensa/XtensaCallingConv.td | 34 ++ .../lib/Target/Xtensa/XtensaFrameLowering.cpp | 43 +++ llvm/lib/Target/Xtensa/XtensaFrameLowering.h | 34 ++ llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 83 +++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 313 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 65 ++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 27 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 43 +++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 3 +- llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp | 63 ++++ llvm/lib/Target/Xtensa/XtensaMCInstLower.h | 43 +++ llvm/lib/Target/Xtensa/XtensaOperators.td | 15 + llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 69 ++++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.h | 56 ++++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 46 +++ llvm/lib/Target/Xtensa/XtensaSubtarget.h | 66 ++++ .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 30 +- llvm/lib/Target/Xtensa/XtensaTargetMachine.h | 7 + 23 files changed, 1166 insertions(+), 3 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/Xtensa.h create mode 100644 llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaAsmPrinter.h create mode 100644 llvm/lib/Target/Xtensa/XtensaCallingConv.td create mode 100644 llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaFrameLowering.h create mode 100644 llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaISelLowering.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaISelLowering.h create mode 100644 llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaInstrInfo.h create mode 100644 llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaMCInstLower.h create mode 100644 llvm/lib/Target/Xtensa/XtensaOperators.td create mode 100644 llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaRegisterInfo.h create mode 100644 llvm/lib/Target/Xtensa/XtensaSubtarget.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaSubtarget.h diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 7192f7392072b..bb1e09cb0652e 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -4,6 +4,8 @@ set(LLVM_TARGET_DEFINITIONS Xtensa.td) tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv) +tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel) tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) @@ -13,6 +15,14 @@ tablegen(LLVM XtensaGenSubtargetInfo.inc -gen-subtarget) add_public_tablegen_target(XtensaCommonTableGen) add_llvm_target(XtensaCodeGen + XtensaAsmPrinter.cpp + XtensaFrameLowering.cpp + XtensaInstrInfo.cpp + XtensaISelDAGToDAG.cpp + XtensaISelLowering.cpp + XtensaMCInstLower.cpp + XtensaRegisterInfo.cpp + XtensaSubtarget.cpp XtensaTargetMachine.cpp LINK_COMPONENTS @@ -20,6 +30,7 @@ add_llvm_target(XtensaCodeGen CodeGen Core MC + SelectionDAG Support Target XtensaDesc diff --git a/llvm/lib/Target/Xtensa/Xtensa.h b/llvm/lib/Target/Xtensa/Xtensa.h new file mode 100644 index 0000000000000..43eadf88c7792 --- /dev/null +++ b/llvm/lib/Target/Xtensa/Xtensa.h @@ -0,0 +1,30 @@ +//===- Xtensa.h - Top-level interface for Xtensa representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the entry points for global functions defined in +// the LLVM Xtensa back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSA_H +#define LLVM_LIB_TARGET_XTENSA_XTENSA_H + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/PassRegistry.h" +#include "llvm/Support/CodeGen.h" + +namespace llvm { +class XtensaTargetMachine; +class FunctionPass; + +FunctionPass *createXtensaISelDag(XtensaTargetMachine &TM, + CodeGenOpt::Level OptLevel); +} // namespace llvm +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSA_H */ diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 4c0f9eeae1eba..db18be02b192c 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -35,6 +35,12 @@ def : Proc<"generic", []>; include "XtensaRegisterInfo.td" +//===----------------------------------------------------------------------===// +// Calling Convention Description +//===----------------------------------------------------------------------===// + +include "XtensaCallingConv.td" + //===----------------------------------------------------------------------===// // Instruction Descriptions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp new file mode 100644 index 0000000000000..0f129c61390c7 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -0,0 +1,40 @@ +//===- XtensaAsmPrinter.cpp Xtensa LLVM Assembly Printer ------------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format Xtensa assembly language. +// +//===----------------------------------------------------------------------===// + +#include "XtensaAsmPrinter.h" +#include "XtensaMCInstLower.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; + +void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { + XtensaMCInstLower Lower(MF->getContext(), *this); + MCInst LoweredMI; + Lower.lower(MI, LoweredMI); + EmitToStreamer(*OutStreamer, LoweredMI); +} + +// Force static initialization. +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmPrinter() { + RegisterAsmPrinter A(TheXtensaTarget); +} diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h new file mode 100644 index 0000000000000..d23fa5dbeadb2 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -0,0 +1,42 @@ +//===- XtensaAsmPrinter.h - Xtensa LLVM Assembly Printer --------*- C++-*--===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Xtensa Assembly printer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAASMPRINTER_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAASMPRINTER_H + +#include "XtensaTargetMachine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +class MCStreamer; +class MachineBasicBlock; +class MachineInstr; +class Module; +class raw_ostream; + +class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { + const MCSubtargetInfo *STI; +public: + explicit XtensaAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)), STI(TM.getMCSubtargetInfo()) {} + + // Override AsmPrinter. + StringRef getPassName() const override { return "Xtensa Assembly Printer"; } + void emitInstruction(const MachineInstr *MI) override; +}; +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSAASMPRINTER_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td new file mode 100644 index 0000000000000..c39eb665b4d33 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td @@ -0,0 +1,34 @@ +//===- XtensaCallingConv.td - Xtensa Calling Conventions -*- tablegen ---*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 describes the calling conventions for the Xtensa ABI. +//===----------------------------------------------------------------------===// + +/// CCIfAlign - Match of the original alignment of the arg +class CCIfAlign + : CCIf; + +//===----------------------------------------------------------------------===// +// Xtensa return value calling convention +//===----------------------------------------------------------------------===// +def RetCC_Xtensa : CallingConv<[ + CCIfType<[i1, i8, i16], CCPromoteToType>, + CCIfType<[f32], CCBitConvertToType>, + + //First two return values go in a2, a3, a4, a5 + CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>, + CCIfType<[f32], CCAssignToReg<[A2, A3, A4, A5]>>, + CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>> +]>; + +//===----------------------------------------------------------------------===// +// Callee-saved register lists. +//===----------------------------------------------------------------------===// + +def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>; diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp new file mode 100644 index 0000000000000..69602e4f30136 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -0,0 +1,43 @@ +//===- XtensaFrameLowering.cpp - Xtensa Frame Information -----------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the Xtensa implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "XtensaFrameLowering.h" +#include "XtensaInstrInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/Function.h" + +using namespace llvm; + +XtensaFrameLowering::XtensaFrameLowering() + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0, + Align(4)) {} + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + return MF.getTarget().Options.DisableFramePointerElim(MF) || + MFI.hasVarSizedObjects(); +} + +void XtensaFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const {} + +void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const {} diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h new file mode 100644 index 0000000000000..a5dfc83b94059 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h @@ -0,0 +1,34 @@ +//===- XtensaFrameLowering.h - Define frame lowering for Xtensa --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// 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_XTENSA_XTENSAFRAMELOWERING_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAFRAMELOWERING_H + +#include "llvm/CodeGen/TargetFrameLowering.h" + +namespace llvm { +class XtensaTargetMachine; +class XtensaSubtarget; + +class XtensaFrameLowering : public TargetFrameLowering { +public: + XtensaFrameLowering(); + + bool hasFP(const MachineFunction &MF) const override; + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &, MachineBasicBlock &) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; +}; + +} // namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSAFRAMELOWERING_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp new file mode 100644 index 0000000000000..d5244a74b0b16 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp @@ -0,0 +1,83 @@ +//===- XtensaISelDAGToDAG.cpp - A dag to dag inst selector for Xtensa -----===// +// +// The LLVM Compiler Infrastructure +// +// 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 defines an instruction selector for the Xtensa target. +// +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "XtensaTargetMachine.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-isel" + +namespace { + +class XtensaDAGToDAGISel : public SelectionDAGISel { + +public: + XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(TM, OptLevel) {} + + // Override MachineFunctionPass. + StringRef getPassName() const override { + return "Xtensa DAG->DAG Pattern Instruction Selection"; + } + + // Override SelectionDAGISel. + void Select(SDNode *Node) override; + + bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset, + int Scale) { + report_fatal_error("MemReg address is not implemented yet"); + return true; + } + + bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) { + return selectMemRegAddr(Addr, Base, Offset, 1); + } + + bool selectMemRegAddrISH2(SDValue Addr, SDValue &Base, SDValue &Offset) { + return selectMemRegAddr(Addr, Base, Offset, 2); + } + + bool selectMemRegAddrISH4(SDValue Addr, SDValue &Base, SDValue &Offset) { + return selectMemRegAddr(Addr, Base, Offset, 4); + } + +// Include the pieces autogenerated from the target description. +#include "XtensaGenDAGISel.inc" +}; // namespace +} // end anonymous namespace + +FunctionPass *llvm::createXtensaISelDag(XtensaTargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new XtensaDAGToDAGISel(TM, OptLevel); +} + +void XtensaDAGToDAGISel::Select(SDNode *Node) { + SDLoc DL(Node); + // Dump information about the Node being selected + LLVM_DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + return; + } + + SelectCode(Node); +} diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp new file mode 100644 index 0000000000000..3228fab77e629 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -0,0 +1,313 @@ +//===- XtensaISelLowering.cpp - Xtensa DAG Lowering Implementation --------===// +// +// The LLVM Compiler Infrastructure +// +// 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 defines the interfaces that Xtensa uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#include "XtensaISelLowering.h" +#include "XtensaSubtarget.h" +#include "XtensaTargetMachine.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-lower" + +XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, + const XtensaSubtarget &STI) + : TargetLowering(tm), Subtarget(STI) { + // Set up the register classes. + addRegisterClass(MVT::i32, &Xtensa::ARRegClass); + + // Set up special registers. + setStackPointerRegisterToSaveRestore(Xtensa::SP); + + setSchedulingPreference(Sched::RegPressure); + + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrOneBooleanContent); + + setMinFunctionAlignment(Align(4)); + + // Compute derived properties from the register classes + computeRegisterProperties(STI.getRegisterInfo()); +} + +//===----------------------------------------------------------------------===// +// Calling conventions +//===----------------------------------------------------------------------===// + +#include "XtensaGenCallingConv.inc" + +static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4, + Xtensa::A5, Xtensa::A6, Xtensa::A7}; + + if (ArgFlags.isByVal()) { + Align ByValAlign = ArgFlags.getNonZeroByValAlign(); + unsigned Offset = State.AllocateStack(ArgFlags.getByValSize(), ByValAlign); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + // Allocate rest of registers, because rest part is not used to pass + // arguments + while (State.AllocateReg(IntRegs)) { + } + return false; + } + + // Promote i8 and i16 + if (LocVT == MVT::i8 || LocVT == MVT::i16) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExt; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExt; + else + LocInfo = CCValAssign::AExt; + } + + unsigned Reg; + + Align OrigAlign = ArgFlags.getNonZeroOrigAlign(); + bool isI64 = (ValVT == MVT::i32 && OrigAlign == Align(8)); + + if (ValVT == MVT::i32 || ValVT == MVT::f32) { + Reg = State.AllocateReg(IntRegs); + // If this is the first part of an i64 arg, + // the allocated register must be either A2, A4 or A6. + if (isI64 && (Reg == Xtensa::A3 || Reg == Xtensa::A5 || Reg == Xtensa::A7)) + Reg = State.AllocateReg(IntRegs); + LocVT = MVT::i32; + } else if (ValVT == MVT::f64) { + // Allocate int register and shadow next int register. + Reg = State.AllocateReg(IntRegs); + if (Reg == Xtensa::A3 || Reg == Xtensa::A5 || Reg == Xtensa::A7) + Reg = State.AllocateReg(IntRegs); + State.AllocateReg(IntRegs); + LocVT = MVT::i32; + } else + llvm_unreachable("Cannot handle this ValVT."); + + if (!Reg) { + unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + } else + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + + return false; +} + +CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC, + bool IsVarArg) const { + return CC_Xtensa_Custom; +} + +// Value is a value of type VA.getValVT() that we need to copy into +// the location described by VA. Return a copy of Value converted to +// VA.getValVT(). The caller is responsible for handling indirect values. +static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDLoc DL, CCValAssign &VA, + SDValue Value) { + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + return DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::ZExt: + return DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::AExt: + return DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::BCvt: + return DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Value); + case CCValAssign::Full: + return Value; + default: + llvm_unreachable("Unhandled getLocInfo()"); + } +} + +SDValue XtensaTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + // Used with vargs to acumulate store chains. + std::vector OutChains; + + if (IsVarArg) { + llvm_unreachable("Var arg not supported by FormalArguments Lowering"); + } + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + + CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg)); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + // Arguments stored on registers + if (VA.isRegLoc()) { + EVT RegVT = VA.getLocVT(); + const TargetRegisterClass *RC; + + if (RegVT == MVT::i32) { + RC = &Xtensa::ARRegClass; + } else + llvm_unreachable("RegVT not supported by FormalArguments Lowering"); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT); + + // If this is an 8 or 16-bit value, it has been passed promoted + // to 32 bits. Insert an assert[sz]ext to capture this, then + // truncate to the right size. + if (VA.getLocInfo() != CCValAssign::Full) { + unsigned Opcode = 0; + if (VA.getLocInfo() == CCValAssign::SExt) + Opcode = ISD::AssertSext; + else if (VA.getLocInfo() == CCValAssign::ZExt) + Opcode = ISD::AssertZext; + if (Opcode) + ArgValue = DAG.getNode(Opcode, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + if (VA.getValVT() == MVT::f32) + ArgValue = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), ArgValue); + else + ArgValue = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), ArgValue); + } + + InVals.push_back(ArgValue); + + } else { // !VA.isRegLoc() + // sanity check + assert(VA.isMemLoc()); + + EVT ValVT = VA.getValVT(); + + // The stack pointer offset is relative to the caller stack frame. + int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, + VA.getLocMemOffset(), true); + + if (Ins[VA.getValNo()].Flags.isByVal()) { + // Assume that in this case load operation is created + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + InVals.push_back(FIN); + } else { + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + InVals.push_back(DAG.getLoad( + ValVT, DL, Chain, FIN, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI))); + } + } + } + + // All stores are grouped in one node to allow the matching between + // the size of Ins and InVals. This only happens when on varg functions + if (!OutChains.empty()) { + OutChains.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); + } + + return Chain; +} + +bool XtensaTargetLowering::CanLowerReturn( + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl &Outs, LLVMContext &Context) const { + SmallVector RVLocs; + CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); + return CCInfo.CheckReturn(Outs, RetCC_Xtensa); +} + +SDValue +XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SDLoc &DL, SelectionDAG &DAG) const { + if (IsVarArg) { + report_fatal_error("VarArg not supported"); + } + + MachineFunction &MF = DAG.getMachineFunction(); + + // Assign locations to each returned value. + SmallVector RetLocs; + CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext()); + RetCCInfo.AnalyzeReturn(Outs, RetCC_Xtensa); + + SDValue Glue; + // Quick exit for void returns + if (RetLocs.empty()) + return DAG.getNode(XtensaISD::RET_FLAG, DL, MVT::Other, Chain); + + // Copy the result values into the output registers. + SmallVector RetOps; + RetOps.push_back(Chain); + for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { + CCValAssign &VA = RetLocs[I]; + SDValue RetValue = OutVals[I]; + + // Make the return register live on exit. + assert(VA.isRegLoc() && "Can only return in registers!"); + + // Promote the value as required. + RetValue = convertValVTToLocVT(DAG, DL, VA, RetValue); + + // Chain and glue the copies together. + unsigned Reg = VA.getLocReg(); + Chain = DAG.getCopyToReg(Chain, DL, Reg, RetValue, Glue); + Glue = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(Reg, VA.getLocVT())); + } + + // Update chain and glue. + RetOps[0] = Chain; + if (Glue.getNode()) + RetOps.push_back(Glue); + + return DAG.getNode(XtensaISD::RET_FLAG, DL, MVT::Other, RetOps); +} + +SDValue XtensaTargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + default: + llvm_unreachable("Unexpected node to lower"); + } +} + +const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { +#define OPCODE(NAME) \ + case XtensaISD::NAME: \ + return "XtensaISD::" #NAME + switch (Opcode) { + case XtensaISD::FIRST_NUMBER: + break; + case XtensaISD::RET_FLAG: + return "XtensaISD::RET_FLAG"; + } + return NULL; +#undef OPCODE +} diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h new file mode 100644 index 0000000000000..2df2a074fe25f --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -0,0 +1,65 @@ +//===- XtensaISelLowering.h - Xtensa DAG Lowering Interface -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 defines the interfaces that Xtensa uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAISELLOWERING_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAISELLOWERING_H + +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/TargetLowering.h" + +namespace llvm { +namespace XtensaISD { +enum { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + // Return with a flag operand. Operand 0 is the chain operand. + RET_FLAG +}; +} + +class XtensaSubtarget; + +class XtensaTargetLowering : public TargetLowering { +public: + explicit XtensaTargetLowering(const TargetMachine &TM, + const XtensaSubtarget &STI); + + const char *getTargetNodeName(unsigned Opcode) const override; + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool isVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, const SDLoc &DL, + SelectionDAG &DAG) const override; + +private: + const XtensaSubtarget &Subtarget; + + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; +}; + +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSAISELLOWERING_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp new file mode 100644 index 0000000000000..52a87fe4b9343 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -0,0 +1,27 @@ +//===- XtensaInstrInfo.cpp - Xtensa Instruction Information ---------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the Xtensa implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "XtensaInstrInfo.h" +#include "XtensaTargetMachine.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "XtensaGenInstrInfo.inc" + +using namespace llvm; + +XtensaInstrInfo::XtensaInstrInfo(XtensaSubtarget &sti) + : XtensaGenInstrInfo(), RI(sti), STI(sti) {} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h new file mode 100644 index 0000000000000..7225886b2ce11 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -0,0 +1,43 @@ +//===-- XtensaInstrInfo.h - Xtensa Instruction Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the Xtensa implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAINSTRINFO_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAINSTRINFO_H + +#include "Xtensa.h" +#include "XtensaRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_INSTRINFO_HEADER + +#include "XtensaGenInstrInfo.inc" + +namespace llvm { + +class XtensaTargetMachine; +class XtensaSubtarget; +class XtensaInstrInfo : public XtensaGenInstrInfo { + const XtensaRegisterInfo RI; + XtensaSubtarget &STI; + +public: + XtensaInstrInfo(XtensaSubtarget &STI); + + // Return the XtensaRegisterInfo, which this class owns. + const XtensaRegisterInfo &getRegisterInfo() const { return RI; } +}; +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSAINSTRINFO_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 78319dd458791..06ebb2400d43c 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -14,6 +14,7 @@ include "XtensaInstrFormats.td" include "XtensaOperands.td" +include "XtensaOperators.td" //===----------------------------------------------------------------------===// // Arithmetic & Logical instructions @@ -426,7 +427,7 @@ let isReturn = 1, isTerminator = 1, isBarrier = 1, Uses = [A0] in { def RET : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins), - "ret", []> { + "ret", [(Xtensa_retflag)]> { let m = 0x2; let n = 0x0; let s = 0; diff --git a/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp b/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp new file mode 100644 index 0000000000000..114c562b6f4ef --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp @@ -0,0 +1,63 @@ +//===- XtensaMCInstLower.cpp - Convert Xtensa MachineInstr to MCInst ------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains code to lower Xtensa MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "XtensaMCInstLower.h" +#include "MCTargetDesc/XtensaMCExpr.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +XtensaMCInstLower::XtensaMCInstLower(MCContext &ctx, + XtensaAsmPrinter &asmPrinter) + : Ctx(ctx), Printer(asmPrinter) {} + + +MCOperand XtensaMCInstLower::lowerOperand(const MachineOperand &MO, + unsigned Offset) const { + MachineOperand::MachineOperandType MOTy = MO.getType(); + + switch (MOTy) { + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) + break; + return MCOperand::createReg(MO.getReg()); + case MachineOperand::MO_Immediate: + return MCOperand::createImm(MO.getImm() + Offset); + case MachineOperand::MO_RegisterMask: + break; + default: + llvm_unreachable("unknown operand type"); + } + + return MCOperand(); +} + +void XtensaMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + MCOperand MCOp = lowerOperand(MO); + + if (MCOp.isValid()) + OutMI.addOperand(MCOp); + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaMCInstLower.h b/llvm/lib/Target/Xtensa/XtensaMCInstLower.h new file mode 100644 index 0000000000000..2b238417ae3eb --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaMCInstLower.h @@ -0,0 +1,43 @@ +//===- XtensaMCInstLower.h - Lower MachineInstr to MCInst ------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// 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_XTENSA_XTENSAMCINSTLOWER_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAMCINSTLOWER_H + +#include "XtensaAsmPrinter.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCContext; +class MCInst; +class MCOperand; +class MCSymbol; +class MachineInstr; +class MachineOperand; +class XtensaAsmPrinter; + +class LLVM_LIBRARY_VISIBILITY XtensaMCInstLower { + MCContext &Ctx; + XtensaAsmPrinter &Printer; + +public: + XtensaMCInstLower(MCContext &ctx, XtensaAsmPrinter &asmPrinter); + + // Lower MachineInstr MI to MCInst OutMI. + void lower(const MachineInstr *MI, MCInst &OutMI) const; + + // Return an MCOperand for MO. Return an empty operand if MO is implicit. + MCOperand lowerOperand(const MachineOperand &MO, unsigned Offset = 0) const; +}; +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSAMCINSTLOWER_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td new file mode 100644 index 0000000000000..6b1f8e4f9b08e --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -0,0 +1,15 @@ +//===- XtensaOperators.td - Xtensa-specific operators ---------*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Node definitions +//===----------------------------------------------------------------------===// +def Xtensa_retflag: SDNode<"XtensaISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp new file mode 100644 index 0000000000000..9431d12aa0526 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -0,0 +1,69 @@ +//===- XtensaRegisterInfo.cpp - Xtensa Register Information ---------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the Xtensa implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "XtensaRegisterInfo.h" +#include "XtensaInstrInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "xtensa-reg-info" + +#define GET_REGINFO_TARGET_DESC +#include "XtensaGenRegisterInfo.inc" + +using namespace llvm; + +XtensaRegisterInfo::XtensaRegisterInfo(const XtensaSubtarget &STI) + : XtensaGenRegisterInfo(Xtensa::A0), Subtarget(STI) {} + +const uint16_t * +XtensaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_Xtensa_SaveList; +} + +const uint32_t * +XtensaRegisterInfo::getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const { + return CSR_Xtensa_RegMask; +} + +BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + + Reserved.set(Xtensa::A0); + if (TFI->hasFP(MF)) { + // Reserve frame pointer. + Reserved.set(getFrameRegister(MF)); + } + + // Reserve stack pointer. + Reserved.set(Xtensa::SP); + return Reserved; +} + +void XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + report_fatal_error("Eliminate frame index not supported yet"); +} + +Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + return TFI->hasFP(MF) ? (Xtensa::A15) : Xtensa::SP; +} diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h new file mode 100644 index 0000000000000..f951219da3eb4 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h @@ -0,0 +1,56 @@ +//===-- XtensaRegisterInfo.h - Xtensa Register Information Impl -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains the Xtensa implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAREGISTERINFO_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAREGISTERINFO_H + +#include "Xtensa.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "XtensaGenRegisterInfo.inc" + +namespace llvm { +class TargetRegisterClass; +class XtensaInstrInfo; +class XtensaSubtarget; + +struct XtensaRegisterInfo : public XtensaGenRegisterInfo { +public: + const XtensaSubtarget &Subtarget; + + XtensaRegisterInfo(const XtensaSubtarget &STI); + + bool requiresRegisterScavenging(const MachineFunction &MF) const override { + return true; + } + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override { + return true; + } + + const uint16_t * + getCalleeSavedRegs(const MachineFunction *MF = 0) const override; + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const override; + BitVector getReservedRegs(const MachineFunction &MF) const override; + void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS) const override; + Register getFrameRegister(const MachineFunction &MF) const override; +}; + +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_REGISTERINFO_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp new file mode 100644 index 0000000000000..f76af66cac1ef --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -0,0 +1,46 @@ +//===- XtensaSubtarget.cpp - Xtensa Subtarget Information -----------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 implements the Xtensa specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "XtensaSubtarget.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "xtensa-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "XtensaGenSubtargetInfo.inc" + +using namespace llvm; + +XtensaSubtarget & +XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { + StringRef CPUName = CPU; + if (CPUName.empty()) { + // set default cpu name + CPUName = "generic"; + } + + HasDensity = false; + + // Parse features string. + ParseSubtargetFeatures(CPUName, CPUName, FS); + return *this; +} + +XtensaSubtarget::XtensaSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, const TargetMachine &TM) + : XtensaGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TargetTriple(TT), + InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), + TSInfo(), FrameLowering() {} diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h new file mode 100644 index 0000000000000..476f1f943a9ea --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -0,0 +1,66 @@ +//===-- XtensaSubtarget.h - Define Subtarget for the Xtensa ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// 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 declares the Xtensa specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSASUBTARGET_H +#define LLVM_LIB_TARGET_XTENSA_XTENSASUBTARGET_H + +#include "XtensaFrameLowering.h" +#include "XtensaISelLowering.h" +#include "XtensaInstrInfo.h" +#include "XtensaRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "XtensaGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class XtensaSubtarget : public XtensaGenSubtargetInfo { +private: + Triple TargetTriple; + XtensaInstrInfo InstrInfo; + XtensaTargetLowering TLInfo; + SelectionDAGTargetInfo TSInfo; + XtensaFrameLowering FrameLowering; + + // Enabled Xtensa Density extension + bool HasDensity; + + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); + +public: + XtensaSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, const TargetMachine &TM); + + const TargetFrameLowering *getFrameLowering() const override { return &FrameLowering; } + const XtensaInstrInfo *getInstrInfo() const override { return &InstrInfo; } + const XtensaRegisterInfo *getRegisterInfo() const override { + return &InstrInfo.getRegisterInfo(); + } + + const XtensaTargetLowering *getTargetLowering() const override { return &TLInfo; } + const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { return &TSInfo; } + + bool hasDensity() const { return HasDensity; } + + // Automatically generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); +}; +} // end namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSASUBTARGET_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index bc257be92d802..cce388bcd8c6b 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -53,7 +53,8 @@ XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, IsLittle), TT, CPU, FS, Options, getEffectiveRelocModel(JIT, RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), - TLOF(std::make_unique()) { + TLOF(std::make_unique()), + Subtarget(TT, std::string(CPU), std::string(FS), *this) { initAsmInfo(); } @@ -65,6 +66,31 @@ XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, CodeGenOpt::Level OL, bool JIT) : XtensaTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {} +const XtensaSubtarget * +XtensaTargetMachine::getSubtargetImpl(const Function &F) const { + return &Subtarget; +} + +namespace { +/// Xtensa Code Generator Pass Configuration Options. +class XtensaPassConfig : public TargetPassConfig { +public: + XtensaPassConfig(XtensaTargetMachine &TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + XtensaTargetMachine &getXtensaTargetMachine() const { + return getTM(); + } + + bool addInstSelector() override; +}; +} // end anonymous namespace + +bool XtensaPassConfig::addInstSelector() { + addPass(createXtensaISelDag(getXtensaTargetMachine(), getOptLevel())); + return false; +} + TargetPassConfig *XtensaTargetMachine::createPassConfig(PassManagerBase &PM) { - return new TargetPassConfig(*this, PM); + return new XtensaPassConfig(*this, PM); } diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.h b/llvm/lib/Target/Xtensa/XtensaTargetMachine.h index cf1a064a730b4..db99df12c6249 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.h +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.h @@ -15,6 +15,7 @@ #ifndef LLVM_LIB_TARGET_XTENSA_XTENSATARGETMACHINE_H #define LLVM_LIB_TARGET_XTENSA_XTENSATARGETMACHINE_H +#include "XtensaSubtarget.h" #include "llvm/Target/TargetMachine.h" namespace llvm { @@ -37,11 +38,17 @@ class XtensaTargetMachine : public LLVMTargetMachine { Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT); + // Override TargetMachine. + const XtensaSubtarget *getSubtargetImpl() const { return &Subtarget; } + const XtensaSubtarget *getSubtargetImpl(const Function &F) const override; // Override LLVMTargetMachine TargetPassConfig *createPassConfig(PassManagerBase &PM) override; TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } + +protected: + XtensaSubtarget Subtarget; }; } // end namespace llvm From 5af39bc7cd287463ccbb48b5d3c903a70ad4890b Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:07 +0300 Subject: [PATCH 012/150] [Xtensa] Codegen support for memory operations --- llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 57 ++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 7 +++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp index d5244a74b0b16..456ecc1ae8d0b 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp @@ -42,7 +42,62 @@ class XtensaDAGToDAGISel : public SelectionDAGISel { bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset, int Scale) { - report_fatal_error("MemReg address is not implemented yet"); + EVT ValTy = Addr.getValueType(); + + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy); + + return true; + } + + if (TM.isPositionIndependent()) + report_fatal_error("PIC relocations is not supported"); + + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + + // Addresses of the form FI+const or FI|const + bool Valid = false; + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + int64_t OffsetVal = CN->getSExtValue(); + + switch (Scale) { + case 1: + Valid = (OffsetVal >= 0 && OffsetVal <= 255); + break; + case 2: + Valid = + (OffsetVal >= 0 && OffsetVal <= 510) && ((OffsetVal & 0x1) == 0); + break; + case 4: + Valid = + (OffsetVal >= 0 && OffsetVal <= 1020) && ((OffsetVal & 0x3) == 0); + break; + default: + break; + } + + if (Valid) { + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = + dyn_cast(Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + else + Base = Addr.getOperand(0); + + Offset = + CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy); + return true; + } + } + + // Last case + Base = Addr; + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType()); return true; } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 3228fab77e629..00fb841ba0839 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -44,6 +44,13 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setBooleanVectorContents(ZeroOrOneBooleanContent); setMinFunctionAlignment(Align(4)); + + // No sign extend instructions for i1 + for (MVT VT : MVT::integer_valuetypes()) { + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); + } // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); From 795cad0c6043627ad949ddfa8b24259b886984a2 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:07 +0300 Subject: [PATCH 013/150] [Xtensa] Add Constant Pool --- llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + .../Target/Xtensa/XtensaConstantPoolValue.cpp | 234 +++++++++++++++ .../Target/Xtensa/XtensaConstantPoolValue.h | 280 ++++++++++++++++++ 3 files changed, 515 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index bb1e09cb0652e..d4300678a0434 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -16,6 +16,7 @@ add_public_tablegen_target(XtensaCommonTableGen) add_llvm_target(XtensaCodeGen XtensaAsmPrinter.cpp + XtensaConstantPoolValue.cpp XtensaFrameLowering.cpp XtensaInstrInfo.cpp XtensaISelDAGToDAG.cpp diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp new file mode 100644 index 0000000000000..b7502eabbf716 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp @@ -0,0 +1,234 @@ +//===- XtensaConstantPoolValue.cpp - Xtensa constantpool value ------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 implements the Xtensa specific constantpool value class. +// +//===----------------------------------------------------------------------===// + +#include "XtensaConstantPoolValue.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/raw_ostream.h" +#include +using namespace llvm; + +XtensaConstantPoolValue::XtensaConstantPoolValue( + Type *Ty, unsigned id, XtensaCP::XtensaCPKind kind, bool addCurrentAddress, + XtensaCP::XtensaCPModifier modifier) + : MachineConstantPoolValue(Ty), LabelId(id), Kind(kind), Modifier(modifier), + AddCurrentAddress(addCurrentAddress) {} + +XtensaConstantPoolValue::XtensaConstantPoolValue( + LLVMContext &C, unsigned id, XtensaCP::XtensaCPKind kind, + bool addCurrentAddress, XtensaCP::XtensaCPModifier modifier) + : MachineConstantPoolValue((Type *)Type::getInt32Ty(C)), LabelId(id), + Kind(kind), Modifier(modifier), AddCurrentAddress(addCurrentAddress) {} + +XtensaConstantPoolValue::~XtensaConstantPoolValue() {} + +StringRef XtensaConstantPoolValue::getModifierText() const { + switch (Modifier) { + case XtensaCP::no_modifier: + return ""; + case XtensaCP::TPOFF: + return "@TPOFF"; + } + llvm_unreachable("Unknown modifier!"); +} + +int XtensaConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) { + llvm_unreachable("Shouldn't be calling this directly!"); +} + +void XtensaConstantPoolValue::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddInteger(LabelId); +} + +bool XtensaConstantPoolValue::hasSameValue(XtensaConstantPoolValue *ACPV) { + if (ACPV->Kind == Kind) { + if (ACPV->LabelId == LabelId) + return true; + // Two PC relative constpool entries containing the same GV address or + // external symbols. FIXME: What about blockaddress? + if (Kind == XtensaCP::CPValue || Kind == XtensaCP::CPExtSymbol) + return true; + } + return false; +} + +void XtensaConstantPoolValue::dump() const { errs() << " " << *this; } + +void XtensaConstantPoolValue::print(raw_ostream &O) const {} + +//===----------------------------------------------------------------------===// +// XtensaConstantPoolConstant +//===----------------------------------------------------------------------===// + +XtensaConstantPoolConstant::XtensaConstantPoolConstant( + Type *Ty, const Constant *C, unsigned ID, XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress) + : XtensaConstantPoolValue((Type *)C->getType(), ID, Kind, + AddCurrentAddress), + CVal(C) {} + +XtensaConstantPoolConstant::XtensaConstantPoolConstant( + const Constant *C, unsigned ID, XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress) + : XtensaConstantPoolValue((Type *)C->getType(), ID, Kind, + AddCurrentAddress), + CVal(C) {} + +XtensaConstantPoolConstant * +XtensaConstantPoolConstant::Create(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind) { + return new XtensaConstantPoolConstant(C, ID, Kind, false); +} + +XtensaConstantPoolConstant * +XtensaConstantPoolConstant::Create(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress) { + return new XtensaConstantPoolConstant(C, ID, Kind, AddCurrentAddress); +} + +const GlobalValue *XtensaConstantPoolConstant::getGV() const { + return dyn_cast_or_null(CVal); +} + +const BlockAddress *XtensaConstantPoolConstant::getBlockAddress() const { + return dyn_cast_or_null(CVal); +} + +int XtensaConstantPoolConstant::getExistingMachineCPValue( + MachineConstantPool *CP, Align Alignment) { + return getExistingMachineCPValueImpl(CP, + Alignment); +} + +bool XtensaConstantPoolConstant::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolConstant *ACPC = + dyn_cast(ACPV); + return ACPC && ACPC->CVal == CVal && + XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolConstant::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddPointer(CVal); + XtensaConstantPoolValue::addSelectionDAGCSEId(ID); +} + +void XtensaConstantPoolConstant::print(raw_ostream &O) const { + O << CVal->getName(); + XtensaConstantPoolValue::print(O); +} + +XtensaConstantPoolSymbol::XtensaConstantPoolSymbol( + LLVMContext &C, const char *s, unsigned id, bool AddCurrentAddress, + bool PrivLinkage, XtensaCP::XtensaCPModifier Modifier) + : XtensaConstantPoolValue(C, id, XtensaCP::CPExtSymbol, AddCurrentAddress, + Modifier), + S(s), PrivateLinkage(PrivLinkage) {} + +XtensaConstantPoolSymbol * +XtensaConstantPoolSymbol::Create(LLVMContext &C, const char *s, unsigned ID, + bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier) + +{ + return new XtensaConstantPoolSymbol(C, s, ID, false, PrivLinkage, Modifier); +} + +int XtensaConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) { + return getExistingMachineCPValueImpl(CP, Alignment); +} + +bool XtensaConstantPoolSymbol::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolSymbol *ACPS = + dyn_cast(ACPV); + return ACPS && ACPS->S == S && XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolSymbol::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddString(S); + XtensaConstantPoolValue::addSelectionDAGCSEId(ID); +} + +void XtensaConstantPoolSymbol::print(raw_ostream &O) const { + O << S; + XtensaConstantPoolValue::print(O); +} + +XtensaConstantPoolMBB::XtensaConstantPoolMBB(LLVMContext &C, + const MachineBasicBlock *mbb, + unsigned id) + : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock, false), + MBB(mbb) {} + +XtensaConstantPoolMBB * +XtensaConstantPoolMBB::Create(LLVMContext &C, const MachineBasicBlock *mbb, + unsigned idx) { + return new XtensaConstantPoolMBB(C, mbb, idx); +} + +int XtensaConstantPoolMBB::getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) { + return getExistingMachineCPValueImpl(CP, Alignment); +} + +bool XtensaConstantPoolMBB::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolMBB *ACPMBB = dyn_cast(ACPV); + return ACPMBB && ACPMBB->MBB == MBB && + XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolMBB::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddPointer(MBB); + XtensaConstantPoolValue::addSelectionDAGCSEId(ID); +} + +void XtensaConstantPoolMBB::print(raw_ostream &O) const { + O << "BB#" << MBB->getNumber(); + XtensaConstantPoolValue::print(O); +} + +XtensaConstantPoolJumpTable::XtensaConstantPoolJumpTable(LLVMContext &C, + unsigned idx) + : XtensaConstantPoolValue(C, 0, XtensaCP::CPJumpTable, false), IDX(idx) {} + +XtensaConstantPoolJumpTable *XtensaConstantPoolJumpTable::Create(LLVMContext &C, + unsigned idx) { + return new XtensaConstantPoolJumpTable(C, idx); +} + +int XtensaConstantPoolJumpTable::getExistingMachineCPValue( + MachineConstantPool *CP, Align Alignment) { + return getExistingMachineCPValueImpl(CP, + Alignment); +} + +bool XtensaConstantPoolJumpTable::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolJumpTable *ACPJT = + dyn_cast(ACPV); + return ACPJT && ACPJT->IDX == IDX && + XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolJumpTable::addSelectionDAGCSEId(FoldingSetNodeID &ID) {} + +void XtensaConstantPoolJumpTable::print(raw_ostream &O) const { + O << "JT" << IDX; + XtensaConstantPoolValue::print(O); +} diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h new file mode 100644 index 0000000000000..094394e5b70e0 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h @@ -0,0 +1,280 @@ +//===- XtensaConstantPoolValue.h - Xtensa constantpool value ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 implements the Xtensa specific constantpool value class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H +#define LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H + +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include + +namespace llvm { + +class BlockAddress; +class Constant; +class GlobalValue; +class LLVMContext; +class MachineBasicBlock; + +namespace XtensaCP { +enum XtensaCPKind { + CPValue, + CPExtSymbol, + CPBlockAddress, + CPMachineBasicBlock, + CPJumpTable +}; + +enum XtensaCPModifier { + no_modifier, // None + TPOFF // Thread Pointer Offset +}; +} // namespace XtensaCP + +/// XtensaConstantPoolValue - Xtensa specific constantpool value. This is used +/// to represent PC-relative displacement between the address of the load +/// instruction and the constant being loaded, i.e. (&GV-(LPIC+8)). +class XtensaConstantPoolValue : public MachineConstantPoolValue { + unsigned LabelId; // Label id of the load. + XtensaCP::XtensaCPKind Kind; // Kind of constant. + XtensaCP::XtensaCPModifier Modifier; // GV modifier + bool AddCurrentAddress; + +protected: + XtensaConstantPoolValue( + Type *Ty, unsigned id, XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + + XtensaConstantPoolValue( + LLVMContext &C, unsigned id, XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + + template + int getExistingMachineCPValueImpl(MachineConstantPool *CP, + Align Alignment) { + const std::vector &Constants = CP->getConstants(); + for (unsigned i = 0, e = Constants.size(); i != e; ++i) { + if (Constants[i].isMachineConstantPoolEntry() && + (Constants[i].getAlign() >= Alignment)) { + XtensaConstantPoolValue *CPV = + (XtensaConstantPoolValue *)Constants[i].Val.MachineCPVal; + if (Derived *APC = dyn_cast(CPV)) + if (cast(this)->equals(APC)) + return i; + } + } + + return -1; + } + +public: + ~XtensaConstantPoolValue() override; + + XtensaCP::XtensaCPModifier getModifier() const { return Modifier; } + bool hasModifier() const { return Modifier != XtensaCP::no_modifier; } + StringRef getModifierText() const; + + bool mustAddCurrentAddress() const { return AddCurrentAddress; } + + unsigned getLabelId() const { return LabelId; } + void setLabelId(unsigned id) { LabelId = id; } + + bool isGlobalValue() const { return Kind == XtensaCP::CPValue; } + bool isExtSymbol() const { return Kind == XtensaCP::CPExtSymbol; } + bool isBlockAddress() const { return Kind == XtensaCP::CPBlockAddress; } + bool isMachineBasicBlock() const { + return Kind == XtensaCP::CPMachineBasicBlock; + } + bool isJumpTable() const { return Kind == XtensaCP::CPJumpTable; } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + virtual bool hasSameValue(XtensaConstantPoolValue *ACPV); + + bool equals(const XtensaConstantPoolValue *A) const { + return this->LabelId == A->LabelId && this->Modifier == A->Modifier; + } + + void print(raw_ostream &O) const override; + void print(raw_ostream *O) const { + if (O) + print(*O); + } + void dump() const; +}; + +inline raw_ostream &operator<<(raw_ostream &O, + const XtensaConstantPoolValue &V) { + V.print(O); + return O; +} + +/// XtensaConstantPoolConstant - Xtensa-specific constant pool values for +/// Constants, Functions, and BlockAddresses. +class XtensaConstantPoolConstant : public XtensaConstantPoolValue { + const Constant *CVal; // Constant being loaded. + + XtensaConstantPoolConstant(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress); + XtensaConstantPoolConstant(Type *Ty, const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress); + +public: + static XtensaConstantPoolConstant *Create(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind); + static XtensaConstantPoolConstant *Create(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind, + bool AddCurrentAddress); + + const GlobalValue *getGV() const; + const BlockAddress *getBlockAddress() const; + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + void print(raw_ostream &O) const override; + static bool classof(const XtensaConstantPoolValue *APV) { + return APV->isGlobalValue() || APV->isBlockAddress(); + } + + bool equals(const XtensaConstantPoolConstant *A) const { + return CVal == A->CVal && XtensaConstantPoolValue::equals(A); + } +}; + +/// XtensaConstantPoolSymbol - Xtensa-specific constantpool values for external +/// symbols. +class XtensaConstantPoolSymbol : public XtensaConstantPoolValue { + const std::string S; // ExtSymbol being loaded. + bool PrivateLinkage; + + XtensaConstantPoolSymbol( + LLVMContext &C, const char *s, unsigned id, bool AddCurrentAddress, + bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + +public: + static XtensaConstantPoolSymbol * + Create(LLVMContext &C, const char *s, unsigned ID, bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + + const char *getSymbol() const { return S.c_str(); } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + bool isPrivateLinkage() { return PrivateLinkage; } + + void print(raw_ostream &O) const override; + + static bool classof(const XtensaConstantPoolValue *ACPV) { + return ACPV->isExtSymbol(); + } + + bool equals(const XtensaConstantPoolSymbol *A) const { + return S == A->S && XtensaConstantPoolValue::equals(A); + } +}; + +/// XtensaConstantPoolMBB - Xtensa-specific constantpool value of a machine +/// basic block. +class XtensaConstantPoolMBB : public XtensaConstantPoolValue { + const MachineBasicBlock *MBB; // Machine basic block. + + XtensaConstantPoolMBB(LLVMContext &C, const MachineBasicBlock *mbb, + unsigned id); + +public: + static XtensaConstantPoolMBB * + Create(LLVMContext &C, const MachineBasicBlock *mbb, unsigned ID); + + const MachineBasicBlock *getMBB() const { return MBB; } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + void print(raw_ostream &O) const override; + + static bool classof(const XtensaConstantPoolValue *ACPV) { + return ACPV->isMachineBasicBlock(); + } + + bool equals(const XtensaConstantPoolMBB *A) const { + return MBB == A->MBB && XtensaConstantPoolValue::equals(A); + } +}; + +/// XtensaConstantPoolJumpTable - Xtensa-specific constantpool values for Jump +/// Table symbols. +class XtensaConstantPoolJumpTable : public XtensaConstantPoolValue { + unsigned IDX; // Jump Table Index. + + XtensaConstantPoolJumpTable(LLVMContext &C, unsigned idx); + +public: + static XtensaConstantPoolJumpTable *Create(LLVMContext &C, unsigned idx); + + unsigned getIndex() const { return IDX; } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + void print(raw_ostream &O) const override; + + static bool classof(const XtensaConstantPoolValue *ACPV) { + return ACPV->isJumpTable(); + } + + bool equals(const XtensaConstantPoolJumpTable *A) const { + return IDX == A->IDX && XtensaConstantPoolValue::equals(A); + } +}; + +} // namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H */ From 8a353ec89efcdf7ea521b40f36386915bd58ef82 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:08 +0300 Subject: [PATCH 014/150] [Xtensa] Implement assembler representation of the Constant Pool. --- llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 170 ++++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 2 + 2 files changed, 172 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 0f129c61390c7..3f9d8d4d355fb 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "XtensaAsmPrinter.h" +#include "XtensaConstantPoolValue.h" #include "XtensaMCInstLower.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" @@ -27,6 +28,17 @@ using namespace llvm; +static MCSymbolRefExpr::VariantKind +getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) { + switch (Modifier) { + case XtensaCP::no_modifier: + return MCSymbolRefExpr::VK_None; + case XtensaCP::TPOFF: + return MCSymbolRefExpr::VK_TPOFF; + } + llvm_unreachable("Invalid XtensaCPModifier!"); +} + void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { XtensaMCInstLower Lower(MF->getContext(), *this); MCInst LoweredMI; @@ -34,6 +46,164 @@ void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, LoweredMI); } +/// EmitConstantPool - Print to the current output stream assembly +/// representations of the constants in the constant pool MCP. This is +/// used to print out constants which have been "spilled to memory" by +/// the code generator. +void XtensaAsmPrinter::emitConstantPool() { + const Function &F = MF->getFunction(); + const MachineConstantPool *MCP = MF->getConstantPool(); + const std::vector &CP = MCP->getConstants(); + if (CP.empty()) + return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + const MachineConstantPoolEntry &CPE = CP[i]; + + if (i == 0) { + if (OutStreamer->hasRawTextSupport()) { + OutStreamer->switchSection( + getObjFileLowering().SectionForGlobal(&F, TM)); + OutStreamer->emitRawText(StringRef("\t.literal_position\n")); + } else { + MCSectionELF *CS = + (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); + std::string CSectionName = CS->getName().str(); + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + if (Pos > 0) + SectionName = CSectionName.substr(0, Pos + 5); + else + SectionName = ""; + SectionName += ".literal"; + SectionName += CSectionName.substr(Pos + 5); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } + + MCSectionELF *S = + OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); + S->setAlignment(Align(4)); + OutStreamer->switchSection(S); + } + } + + if (CPE.isMachineConstantPoolEntry()) { + XtensaConstantPoolValue *ACPV = + static_cast(CPE.Val.MachineCPVal); + ACPV->setLabelId(i); + emitMachineConstantPoolValue(CPE.Val.MachineCPVal); + } else { + MCSymbol *LblSym = GetCPISymbol(i); + // TODO find a better way to check whether we emit data to .s file + if (OutStreamer->hasRawTextSupport()) { + std::string str("\t.literal "); + str += LblSym->getName(); + str += ", "; + const Constant *C = CPE.Val.ConstVal; + + Type *Ty = C->getType(); + if (const auto *CFP = dyn_cast(C)) { + str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); + } else if (const auto *CI = dyn_cast(C)) { + str += toString(CI->getValue(), 10, true); + } else if (isa(Ty)) { + const MCExpr *ME = lowerConstant(C); + const MCSymbolRefExpr &SRE = cast(*ME); + const MCSymbol &Sym = SRE.getSymbol(); + str += Sym.getName(); + } else { + unsigned NumElements; + if (isa(Ty)) + NumElements = (cast(Ty))->getNumElements(); + else + NumElements = Ty->getArrayNumElements(); + + for (unsigned I = 0; I < NumElements; I++) { + const Constant *CAE = C->getAggregateElement(I); + if (I > 0) + str += ", "; + if (const auto *CFP = dyn_cast(CAE)) { + str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); + } else if (const auto *CI = dyn_cast(CAE)) { + str += toString(CI->getValue(), 10, true); + } + } + } + + OutStreamer->emitRawText(StringRef(str)); + } else { + OutStreamer->emitLabel(LblSym); + emitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); + } + } + } +} + +void XtensaAsmPrinter::emitMachineConstantPoolValue( + MachineConstantPoolValue *MCPV) { + XtensaConstantPoolValue *ACPV = static_cast(MCPV); + + MCSymbol *MCSym; + if (ACPV->isBlockAddress()) { + const BlockAddress *BA = + cast(ACPV)->getBlockAddress(); + MCSym = GetBlockAddressSymbol(BA); + } else if (ACPV->isGlobalValue()) { + const GlobalValue *GV = cast(ACPV)->getGV(); + // TODO some modifiers + MCSym = getSymbol(GV); + } else if (ACPV->isMachineBasicBlock()) { + const MachineBasicBlock *MBB = cast(ACPV)->getMBB(); + MCSym = MBB->getSymbol(); + } else if (ACPV->isJumpTable()) { + unsigned idx = cast(ACPV)->getIndex(); + MCSym = this->GetJTISymbol(idx, false); + } else { + assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); + XtensaConstantPoolSymbol *XtensaSym = cast(ACPV); + const char *Sym = XtensaSym->getSymbol(); + // TODO it's a trick to distinguish static references and generated rodata + // references Some clear method required + { + std::string SymName(Sym); + if (XtensaSym->isPrivateLinkage()) + SymName = ".L" + SymName; + MCSym = GetExternalSymbolSymbol(StringRef(SymName)); + } + } + + MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId()); + // TODO find a better way to check whether we emit data to .s file + if (OutStreamer->hasRawTextSupport()) { + std::string SymName("\t.literal "); + SymName += LblSym->getName(); + SymName += ", "; + SymName += MCSym->getName(); + + StringRef Modifier = ACPV->getModifierText(); + SymName += Modifier; + + OutStreamer->emitRawText(StringRef(SymName)); + } else { + MCSymbolRefExpr::VariantKind VK = + getModifierVariantKind(ACPV->getModifier()); + + if (ACPV->getModifier() != XtensaCP::no_modifier) { + std::string SymName(MCSym->getName()); + MCSym = GetExternalSymbolSymbol(StringRef(SymName)); + } + + const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); + uint64_t Size = getDataLayout().getTypeAllocSize(ACPV->getType()); + OutStreamer->emitLabel(LblSym); + OutStreamer->emitValue(Expr, Size); + } +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmPrinter() { RegisterAsmPrinter A(TheXtensaTarget); diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h index d23fa5dbeadb2..0ba80bc18c1c2 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -36,6 +36,8 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { // Override AsmPrinter. StringRef getPassName() const override { return "Xtensa Assembly Printer"; } void emitInstruction(const MachineInstr *MI) override; + void emitConstantPool() override; + void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; }; } // end namespace llvm From 9fa51dfd1ddff2465b2dd3c8aaa818b702c29a1d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:08 +0300 Subject: [PATCH 015/150] [Xtensa] Implement lowering constants. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 48 ++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 5 ++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 00fb841ba0839..c541b30079e7b 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -44,7 +44,12 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setBooleanVectorContents(ZeroOrOneBooleanContent); setMinFunctionAlignment(Align(4)); - + + setOperationAction(ISD::Constant, MVT::i32, Custom); + setOperationAction(ISD::Constant, MVT::i64, Expand); + setOperationAction(ISD::ConstantFP, MVT::f32, Custom); + setOperationAction(ISD::ConstantFP, MVT::f64, Expand); + // No sign extend instructions for i1 for (MVT VT : MVT::integer_valuetypes()) { setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); @@ -56,6 +61,11 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, computeRegisterProperties(STI.getRegisterInfo()); } +bool XtensaTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, + bool ForCodeSize) const { + return false; +} + //===----------------------------------------------------------------------===// // Calling conventions //===----------------------------------------------------------------------===// @@ -297,9 +307,45 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, return DAG.getNode(XtensaISD::RET_FLAG, DL, MVT::Other, RetOps); } +SDValue XtensaTargetLowering::LowerImmediate(SDValue Op, + SelectionDAG &DAG) const { + const ConstantSDNode *CN = cast(Op); + SDLoc DL(CN); + APInt apval = CN->getAPIntValue(); + int64_t value = apval.getSExtValue(); + if (Op.getValueType() == MVT::i32) { + if (value > -2048 && value <= 2047) + return Op; + Type *Ty = Type::getInt32Ty(*DAG.getContext()); + Constant *CV = ConstantInt::get(Ty, value); + SDValue CP = DAG.getConstantPool(CV, MVT::i32); + return CP; + } + return Op; +} + +SDValue XtensaTargetLowering::LowerImmediateFP(SDValue Op, + SelectionDAG &DAG) const { + const ConstantFPSDNode *CN = cast(Op); + SDLoc DL(CN); + APFloat apval = CN->getValueAPF(); + int64_t value = FloatToBits(CN->getValueAPF().convertToFloat()); + if (Op.getValueType() == MVT::f32) { + Type *Ty = Type::getInt32Ty(*DAG.getContext()); + Constant *CV = ConstantInt::get(Ty, value); + SDValue CP = DAG.getConstantPool(CV, MVT::i32); + return DAG.getNode(ISD::BITCAST, DL, MVT::f32, CP); + } + return Op; +} + SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::Constant: + return LowerImmediate(Op, DAG); + case ISD::ConstantFP: + return LowerImmediateFP(Op, DAG); default: llvm_unreachable("Unexpected node to lower"); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 2df2a074fe25f..e2ed301e45ebe 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -36,6 +36,8 @@ class XtensaTargetLowering : public TargetLowering { explicit XtensaTargetLowering(const TargetMachine &TM, const XtensaSubtarget &STI); + bool isFPImmLegal(const APFloat &Imm, EVT VT, + bool ForCodeSize) const override; const char *getTargetNodeName(unsigned Opcode) const override; SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, @@ -57,6 +59,9 @@ class XtensaTargetLowering : public TargetLowering { private: const XtensaSubtarget &Subtarget; + SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const; + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; }; From 074de8e5619df49ccc5874345351eba0fe8eed88 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:08 +0300 Subject: [PATCH 016/150] [Xtensa] Add support of the Xtensa function calls --- .../lib/Target/Xtensa/XtensaFrameLowering.cpp | 21 ++ llvm/lib/Target/Xtensa/XtensaFrameLowering.h | 4 + llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 241 +++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 14 + llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 133 +++++++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 25 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 47 ++++ llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp | 50 ++++ llvm/lib/Target/Xtensa/XtensaMCInstLower.h | 7 + llvm/lib/Target/Xtensa/XtensaOperands.td | 2 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 26 +- llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 108 +++++++- llvm/lib/Target/Xtensa/XtensaRegisterInfo.h | 5 + 13 files changed, 674 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index 69602e4f30136..71941e7671930 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -15,6 +15,7 @@ #include "XtensaFrameLowering.h" #include "XtensaInstrInfo.h" #include "XtensaSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -41,3 +42,23 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF, void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const {} + +// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions +MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr( + MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + const XtensaInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + + if (!hasReservedCallFrame(MF)) { + int64_t Amount = I->getOperand(0).getImm(); + + if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN) + Amount = -Amount; + + unsigned SP = Xtensa::SP; + TII.adjustStackPtr(SP, Amount, MBB, I); + } + + return MBB.erase(I); +} diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h index a5dfc83b94059..584438d179bb8 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h @@ -27,6 +27,10 @@ class XtensaFrameLowering : public TargetFrameLowering { /// the function. void emitPrologue(MachineFunction &, MachineBasicBlock &) const override; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + MachineBasicBlock::iterator + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; }; } // namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index c541b30079e7b..6983978f6f0a5 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -14,9 +14,11 @@ //===----------------------------------------------------------------------===// #include "XtensaISelLowering.h" +#include "XtensaConstantPoolValue.h" #include "XtensaSubtarget.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -24,11 +26,20 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include using namespace llvm; #define DEBUG_TYPE "xtensa-lower" +// Return true if we must use long (in fact, indirect) function call. +// It's simplified version, production implimentation must +// resolve a functions in ROM (usually glibc functions) +static bool isLongCall(const char *str) { + // Currently always use long calls + return true; +} + XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, const XtensaSubtarget &STI) : TargetLowering(tm), Subtarget(STI) { @@ -136,6 +147,32 @@ CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC, return CC_Xtensa_Custom; } +// Value is a value that has been passed to us in the location described by VA +// (and so has type VA.getLocVT()). Convert Value to VA.getValVT(), chaining +// any loads onto Chain. +static SDValue convertLocVTToValVT(SelectionDAG &DAG, const SDLoc &DL, + CCValAssign &VA, SDValue Chain, + SDValue Value) { + // If the argument has been promoted from a smaller type, insert an + // assertion to capture this. + if (VA.getLocInfo() == CCValAssign::SExt) + Value = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Value, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + Value = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Value, + DAG.getValueType(VA.getValVT())); + + if (VA.isExtInLoc()) + Value = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Value); + else if (VA.getLocInfo() == CCValAssign::Indirect) + Value = DAG.getLoad(VA.getValVT(), DL, Chain, Value, MachinePointerInfo()); + else if (VA.getValVT() == MVT::f32) + Value = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Value); + else + assert(VA.getLocInfo() == CCValAssign::Full && "Unsupported getLocInfo"); + return Value; +} + // Value is a value of type VA.getValVT() that we need to copy into // the location described by VA. Return a copy of Value converted to // VA.getValVT(). The caller is responsible for handling indirect values. @@ -249,8 +286,203 @@ SDValue XtensaTargetLowering::LowerFormalArguments( return Chain; } +SDValue XtensaTargetLowering::getAddrPCRel(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT Ty = Op.getValueType(); + return DAG.getNode(XtensaISD::PCREL_WRAPPER, DL, Ty, Op); +} + +SDValue +XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc &DL = CLI.DL; + SmallVector &Outs = CLI.Outs; + SmallVector &OutVals = CLI.OutVals; + SmallVector &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + + MachineFunction &MF = DAG.getMachineFunction(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + const TargetFrameLowering *TFL = Subtarget.getFrameLowering(); + + // TODO: Support tail call optimization. + IsTailCall = false; + + // Analyze the operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); + + CCAssignFn *CC = CCAssignFnForCall(CallConv, IsVarArg); + + CCInfo.AnalyzeCallOperands(Outs, CC); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + unsigned StackAlignment = TFL->getStackAlignment(); + unsigned NextStackOffset = alignTo(NumBytes, StackAlignment); + + Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL); + + // Copy argument values to their designated locations. + std::deque> RegsToPass; + SmallVector MemOpChains; + SDValue StackPtr; + for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) { + CCValAssign &VA = ArgLocs[I]; + SDValue ArgValue = OutVals[I]; + ISD::ArgFlagsTy Flags = Outs[I].Flags; + + ArgValue = convertValVTToLocVT(DAG, DL, VA, ArgValue); + + if (VA.isRegLoc()) + // Queue up the argument copies and emit them at the end. + RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); + else if (Flags.isByVal()) { + assert(VA.isMemLoc()); + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + assert(!IsTailCall && + "Do not tail-call optimize if there is a byval argument."); + + if (!StackPtr.getNode()) + StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT); + unsigned Offset = VA.getLocMemOffset(); + SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, + DAG.getIntPtrConstant(Offset, DL)); + SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), DL, MVT::i32); + SDValue Memcpy = DAG.getMemcpy( + Chain, DL, Address, ArgValue, SizeNode, Flags.getNonZeroByValAlign(), + /*isVolatile=*/false, /*AlwaysInline=*/false, + /*isTailCall=*/false, MachinePointerInfo(), MachinePointerInfo()); + MemOpChains.push_back(Memcpy); + } else { + assert(VA.isMemLoc() && "Argument not register or memory"); + + // Work out the address of the stack slot. Unpromoted ints and + // floats are passed as right-justified 8-byte values. + if (!StackPtr.getNode()) + StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT); + unsigned Offset = VA.getLocMemOffset(); + SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, + DAG.getIntPtrConstant(Offset, DL)); + + // Emit the store. + MemOpChains.push_back( + DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); + } + } + + // Join the stores, which are independent of one another. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); + + // Build a sequence of copy-to-reg nodes, chained and glued together. + SDValue Glue; + for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { + unsigned Reg = RegsToPass[I].first; + Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue); + Glue = Chain.getValue(1); + } + + std::string name; + unsigned char TF = 0; + + // Accept direct calls by converting symbolic call addresses to the + // associated Target* opcodes. + if (ExternalSymbolSDNode *E = dyn_cast(Callee)) { + name = E->getSymbol(); + TF = E->getTargetFlags(); + if (isPositionIndependent()) { + report_fatal_error("PIC relocations is not supported"); + } else + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, TF); + } else if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + // TODO replace GlobalAddress to some special operand instead of + // ExternalSymbol + // Callee = + // DAG.getTargetExternalSymbol(strdup(G->getGlobal()->getName().str().c_str()), + // PtrVT); + + const GlobalValue *GV = G->getGlobal(); + name = GV->getName().str(); + } + + if ((!name.empty()) && isLongCall(name.c_str())) { + // Create a constant pool entry for the callee address + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier; + + XtensaConstantPoolValue *CPV = XtensaConstantPoolSymbol::Create( + *DAG.getContext(), name.c_str(), 0 /* XtensaCLabelIndex */, false, + Modifier); + + // Get the address of the callee into a register + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4), 0, TF); + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + Callee = CPWrap; + } + + // The first call operand is the chain and the second is the target address. + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add a register mask operand representing the call-preserved registers. + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { + unsigned Reg = RegsToPass[I].first; + Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType())); + } + + // Glue the call to the argument copies, if any. + if (Glue.getNode()) + Ops.push_back(Glue); + + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops); + Glue = Chain.getValue(1); + + // Mark the end of the call, which is glued to the call itself. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true), + DAG.getConstant(0, DL, PtrVT, true), Glue, DL); + Glue = Chain.getValue(1); + + // Assign locations to each value returned by this call. + SmallVector RetLocs; + CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext()); + RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa); + + // Copy all of the result registers out of their specified physreg. + for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { + CCValAssign &VA = RetLocs[I]; + + // Copy the value out, gluing the copy to the end of the call sequence. + unsigned Reg = VA.getLocReg(); + SDValue RetValue = DAG.getCopyFromReg(Chain, DL, Reg, VA.getLocVT(), Glue); + Chain = RetValue.getValue(1); + Glue = RetValue.getValue(2); + + // Convert the value of the return register into the value that's + // being returned. + InVals.push_back(convertLocVTToValVT(DAG, DL, VA, Chain, RetValue)); + } + return Chain; +} + bool XtensaTargetLowering::CanLowerReturn( - CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, + CallingConv::ID CallConv, MachineFunction & MF, bool IsVarArg, const SmallVectorImpl &Outs, LLVMContext &Context) const { SmallVector RVLocs; CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); @@ -356,10 +588,9 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { case XtensaISD::NAME: \ return "XtensaISD::" #NAME switch (Opcode) { - case XtensaISD::FIRST_NUMBER: - break; - case XtensaISD::RET_FLAG: - return "XtensaISD::RET_FLAG"; + OPCODE(RET_FLAG); + OPCODE(CALL); + OPCODE(PCREL_WRAPPER); } return NULL; #undef OPCODE diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index e2ed301e45ebe..18c7772a43451 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -24,6 +24,16 @@ namespace llvm { namespace XtensaISD { enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Calls a function. Operand 0 is the chain operand and operand 1 + // is the target address. The arguments start at operand 2. + // There is an optional glue operand at the end. + CALL, + + // Wraps a TargetGlobalAddress that should be loaded using PC-relative + // accesses. Operand 0 is the address. + PCREL_WRAPPER, + // Return with a flag operand. Operand 0 is the chain operand. RET_FLAG }; @@ -45,6 +55,8 @@ class XtensaTargetLowering : public TargetLowering { const SmallVectorImpl &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const override; + SDValue LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg, @@ -62,6 +74,8 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const; + SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; }; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 52a87fe4b9343..489f405efcb1f 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -15,6 +15,7 @@ #include "XtensaInstrInfo.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -23,5 +24,135 @@ using namespace llvm; +static inline const MachineInstrBuilder & +addFrameReference(const MachineInstrBuilder &MIB, int FI) { + MachineInstr *MI = MIB; + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo &MFFrame = MF.getFrameInfo(); + const MCInstrDesc &MCID = MI->getDesc(); + MachineMemOperand::Flags Flags = MachineMemOperand::MONone; + if (MCID.mayLoad()) + Flags |= MachineMemOperand::MOLoad; + if (MCID.mayStore()) + Flags |= MachineMemOperand::MOStore; + int64_t Offset = 0; + Align Alignment = MFFrame.getObjectAlign(FI); + + MachineMemOperand *MMO = + MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI, Offset), + Flags, MFFrame.getObjectSize(FI), Alignment); + return MIB.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO); +} + XtensaInstrInfo::XtensaInstrInfo(XtensaSubtarget &sti) - : XtensaGenInstrInfo(), RI(sti), STI(sti) {} + : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP), RI(sti), STI(sti) {} + +/// Adjust SP by Amount bytes. +void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + + if (Amount == 0) + return; + + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Xtensa::ARRegClass; + + // create virtual reg to store immediate + unsigned Reg = RegInfo.createVirtualRegister(RC); + + if (isInt<8>(Amount)) // addi sp, sp, amount + BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount); + else { // Expand immediate that doesn't fit in 12-bit. + unsigned Reg1; + loadImmediate(MBB, I, &Reg1, Amount); + BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg) + .addReg(SP) + .addReg(Reg1, RegState::Kill); + } + + BuildMI(MBB, I, DL, get(Xtensa::OR), SP).addReg(Reg, RegState::Kill).addReg(Reg, RegState::Kill); +} + +void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, MCRegister DestReg, + MCRegister SrcReg, bool KillSrc) const { + // when we are copying a phys reg we want the bits for fp + if (Xtensa::ARRegClass.contains(DestReg, SrcReg)) + BuildMI(MBB, MBBI, DL, get(Xtensa::OR), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)) + .addReg(SrcReg, getKillRegState(KillSrc)); + else + llvm_unreachable("Impossible reg-to-reg copy"); +} + +void XtensaInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + Register SrcReg, bool isKill, + int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned LoadOpcode, StoreOpcode; + getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx); + addFrameReference(BuildMI(MBB, MBBI, DL, get(StoreOpcode)) + .addReg(SrcReg, getKillRegState(isKill)), + FrameIdx); +} + +void XtensaInstrInfo::loadRegFromStackSlot( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg, + int FrameIdx, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned LoadOpcode, StoreOpcode; + getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx); + addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), FrameIdx); +} + +void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, + unsigned &LoadOpcode, + unsigned &StoreOpcode, + int64_t offset) const { + if (RC == &Xtensa::ARRegClass) { + LoadOpcode = Xtensa::L32I; + StoreOpcode = Xtensa::S32I; + } else + llvm_unreachable("Unsupported regclass to load or store"); +} + +void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned *Reg, int64_t Value) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Xtensa::ARRegClass; + + // create virtual reg to store immediate + *Reg = RegInfo.createVirtualRegister(RC); + if (Value >= -2048 && Value <= 2047) { + BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Value); + } else if (Value >= -32768 && Value <= 32767) { + int Low = Value & 0xFF; + int High = Value & ~0xFF; + + BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Low); + BuildMI(MBB, MBBI, DL, get(Xtensa::ADDMI), *Reg).addReg(*Reg).addImm(High); + } else if (Value >= -4294967296LL && Value <= 4294967295LL) { + // 32 bit arbirary constant + MachineConstantPool *MCP = MBB.getParent()->getConstantPool(); + uint64_t UVal = ((uint64_t)Value) & 0xFFFFFFFFLL; + const Constant *CVal = ConstantInt::get( + Type::getInt32Ty(MBB.getParent()->getFunction().getContext()), UVal, + false); + unsigned Idx = MCP->getConstantPoolIndex(CVal, Align(2U)); + // MCSymbol MSym + BuildMI(MBB, MBBI, DL, get(Xtensa::L32R), *Reg).addConstantPoolIndex(Idx); + } else { + // use L32R to let assembler load immediate best + // TODO replace to L32R + llvm_unreachable("Unsupported load immediate value"); + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h index 7225886b2ce11..887ec99b8ccba 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -35,8 +35,33 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { public: XtensaInstrInfo(XtensaSubtarget &STI); + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + // Return the XtensaRegisterInfo, which this class owns. const XtensaRegisterInfo &getRegisterInfo() const { return RI; } + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, + bool KillSrc) const override; + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, Register SrcReg, + bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, Register DestReg, + int FrameIdx, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + // Get the load and store opcodes for a given register class and offset. + void getLoadStoreOpcodes(const TargetRegisterClass *RC, unsigned &LoadOpcode, + unsigned &StoreOpcode, int64_t offset) const; + + // Emit code before MBBI in MI to move immediate value Value into + // physical register Reg. + void loadImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + unsigned *Reg, int64_t Value) const; }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 06ebb2400d43c..9dea877c2a983 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -239,6 +239,29 @@ def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label), let imm16 = label; } +//pcrel addr loading using L32R +def : Pat<(Xtensa_pcrel_wrapper tconstpool:$in), (L32R tconstpool:$in)>; + +// FrameIndexes are legalized when they are operands from load/store +// instructions. The same not happens for stack address copies, so an +// add op with mem ComplexPattern is used and the stack address copy +// can be matched. +// Setting of attribute mayLoad is trick to process instruction operands +// in function XtensaRegisterInfo::eliminateFI + +let isCodeGenOnly = 1, mayLoad = 1 in { + + def LEA_ADD : RRI8_Inst<0x02, (outs AR:$t), (ins mem32:$addr), + "addi\t$t, $addr", + [(set AR:$t, addr_ish4:$addr)]> { + bits<12> addr; + + let r = 0x0C; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + //===----------------------------------------------------------------------===// // Conditional branch instructions //===----------------------------------------------------------------------===// @@ -435,6 +458,14 @@ let isReturn = 1, isTerminator = 1, } } +// Call patterns +def : Pat<(Xtensa_call (i32 tglobaladdr:$dst)), + (CALL0 tglobaladdr:$dst)>; +def : Pat<(Xtensa_call (i32 texternalsym:$dst)), + (CALL0 texternalsym:$dst)>; +def : Pat<(Xtensa_call AR:$dst), + (CALLX0 AR:$dst)>; + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// @@ -503,3 +534,19 @@ def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr "xsr\t$t, $sr", []> { let Constraints = "$ard = $t, $srd = $sr"; } + +//===----------------------------------------------------------------------===// +// Stack allocation +//===----------------------------------------------------------------------===// + +// ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into +// a stack adjustment and the codegen must know that they may modify the stack +// pointer before prolog-epilog rewriting occurs. +let Defs = [SP], Uses = [SP] in { + def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "#ADJCALLSTACKDOWN", + [(Xtensa_callseq_start timm:$amt1, timm:$amt2)]>; + def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "#ADJCALLSTACKUP", + [(Xtensa_callseq_end timm:$amt1, timm:$amt2)]>; +} diff --git a/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp b/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp index 114c562b6f4ef..4688091a26bb7 100644 --- a/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp +++ b/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp @@ -28,6 +28,54 @@ XtensaMCInstLower::XtensaMCInstLower(MCContext &ctx, XtensaAsmPrinter &asmPrinter) : Ctx(ctx), Printer(asmPrinter) {} +MCSymbol * +XtensaMCInstLower::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + // Create a symbol for the name. + return Printer.GetCPISymbol(MO.getIndex()); +} + +MCOperand +XtensaMCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MachineOperand::MachineOperandType MOTy, + unsigned Offset) const { + const MCSymbol *Symbol; + XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; + + switch (MOTy) { + case MachineOperand::MO_MachineBasicBlock: + Symbol = MO.getMBB()->getSymbol(); + break; + case MachineOperand::MO_GlobalAddress: + Symbol = Printer.getSymbol(MO.getGlobal()); + Offset += MO.getOffset(); + break; + case MachineOperand::MO_BlockAddress: + Symbol = Printer.GetBlockAddressSymbol(MO.getBlockAddress()); + Offset += MO.getOffset(); + break; + case MachineOperand::MO_ConstantPoolIndex: + Symbol = GetConstantPoolIndexSymbol(MO); + Offset += MO.getOffset(); + break; + default: + llvm_unreachable(""); + } + + const MCExpr *ME = + MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, Ctx); + + ME = XtensaMCExpr::create(ME, Kind, Ctx); + + if (Offset) { + // Assume offset is never negative. + assert(Offset > 0); + + const MCConstantExpr *OffsetExpr = MCConstantExpr::create(Offset, Ctx); + ME = MCBinaryExpr::createAdd(ME, OffsetExpr, Ctx); + } + + return MCOperand::createExpr(ME); +} MCOperand XtensaMCInstLower::lowerOperand(const MachineOperand &MO, unsigned Offset) const { @@ -43,6 +91,8 @@ MCOperand XtensaMCInstLower::lowerOperand(const MachineOperand &MO, return MCOperand::createImm(MO.getImm() + Offset); case MachineOperand::MO_RegisterMask: break; + case MachineOperand::MO_ConstantPoolIndex: + return LowerSymbolOperand(MO, MOTy, Offset); default: llvm_unreachable("unknown operand type"); } diff --git a/llvm/lib/Target/Xtensa/XtensaMCInstLower.h b/llvm/lib/Target/Xtensa/XtensaMCInstLower.h index 2b238417ae3eb..32a0ad86a3850 100644 --- a/llvm/lib/Target/Xtensa/XtensaMCInstLower.h +++ b/llvm/lib/Target/Xtensa/XtensaMCInstLower.h @@ -37,6 +37,13 @@ class LLVM_LIBRARY_VISIBILITY XtensaMCInstLower { // Return an MCOperand for MO. Return an empty operand if MO is implicit. MCOperand lowerOperand(const MachineOperand &MO, unsigned Offset = 0) const; + +private: + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, + MachineOperand::MachineOperandType MOTy, + unsigned Offset) const; }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 7a1a2e86e8c20..034aef55f7635 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -195,7 +195,7 @@ def jumptarget : Operand { let ParserMatchClass = XtensaPCRelTargetAsmOperand; } -def L32Rtarget : Operand { +def L32Rtarget: Operand { let PrintMethod = "printL32RTarget"; let EncoderMethod = "getL32RTargetEncoding"; let DecoderMethod = "decodeL32ROperand"; diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index 6b1f8e4f9b08e..bb764d2c9247b 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -8,8 +8,32 @@ // //===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// Type profiles +//===----------------------------------------------------------------------===// + +def SDT_XtensaCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; +def SDT_XtensaWrapPtr : SDTypeProfile<1, 1, + [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; + //===----------------------------------------------------------------------===// // Node definitions //===----------------------------------------------------------------------===// + +def Xtensa_call: SDNode<"XtensaISD::CALL", SDT_XtensaCall, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; + def Xtensa_retflag: SDNode<"XtensaISD::RET_FLAG", SDTNone, - [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + + +def Xtensa_callseq_start: SDNode<"ISD::CALLSEQ_START", SDT_XtensaCallSeqStart, + [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; +def Xtensa_callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_XtensaCallSeqEnd, + [SDNPHasChain, SDNPSideEffect, SDNPOptInGlue, + SDNPOutGlue]>; + +def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, []>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp index 9431d12aa0526..e5efd5a958aa2 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -15,6 +15,7 @@ #include "XtensaRegisterInfo.h" #include "XtensaInstrInfo.h" #include "XtensaSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" @@ -57,10 +58,115 @@ BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const { return Reserved; } +void XtensaRegisterInfo::eliminateFI(MachineBasicBlock::iterator II, + unsigned OpNo, int FrameIndex, + uint64_t StackSize, + int64_t SPOffset) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + + const std::vector &CSI = MFI.getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + // The following stack frame objects are always referenced relative to $sp: + // 1. Outgoing arguments. + // 2. Pointer to dynamically allocated stack space. + // 3. Locations for callee-saved registers. + // 4. Locations for eh data registers. + // Everything else is referenced relative to whatever register + // getFrameRegister() returns. + unsigned FrameReg; + + if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)) + FrameReg = Xtensa::SP; + else + FrameReg = getFrameRegister(MF); + + // Calculate final offset. + // - There is no need to change the offset if the frame object is one of the + // following: an outgoing argument, pointer to a dynamically allocated + // stack space or a $gp restore location, + // - If the frame object is any of the following, its offset must be adjusted + // by adding the size of the stack: + // incoming argument, callee-saved register location or local variable. + bool IsKill = false; + int64_t Offset; + + Offset = SPOffset + (int64_t)StackSize; + Offset += MI.getOperand(OpNo + 1).getImm(); + + LLVM_DEBUG(errs() << "Offset : " << Offset << "\n" + << "<--------->\n"); + + bool Valid = false; + switch (MI.getOpcode()) { + case Xtensa::L8UI: + case Xtensa::S8I: + Valid = (Offset >= 0 && Offset <= 255); + break; + case Xtensa::L16SI: + case Xtensa::L16UI: + case Xtensa::S16I: + Valid = (Offset >= 0 && Offset <= 510); + break; + case Xtensa::LEA_ADD: + Valid = (Offset >= -128 && Offset <= 127); + break; + default: + Valid = (Offset >= 0 && Offset <= 1020); + break; + } + + // If MI is not a debug value, make sure Offset fits in the 16-bit immediate + // field. + if (!MI.isDebugValue() && !Valid) { + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned ADD = Xtensa::ADD; + unsigned Reg; + const XtensaInstrInfo &TII = *static_cast( + MBB.getParent()->getSubtarget().getInstrInfo()); + + TII.loadImmediate(MBB, II, &Reg, Offset); + BuildMI(MBB, II, DL, TII.get(ADD), Reg) + .addReg(FrameReg) + .addReg(Reg, RegState::Kill); + + FrameReg = Reg; + Offset = 0; + IsKill = true; + } + + MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false, IsKill); + MI.getOperand(OpNo + 1).ChangeToImmediate(Offset); +} + void XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { - report_fatal_error("Eliminate frame index not supported yet"); + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + LLVM_DEBUG(errs() << "\nFunction : " << MF.getName() << "\n"; + errs() << "<--------->\n" + << MI); + + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + uint64_t stackSize = MF.getFrameInfo().getStackSize(); + int64_t spOffset = MF.getFrameInfo().getObjectOffset(FrameIndex); + + LLVM_DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << spOffset << "\n" + << "stackSize : " << stackSize << "\n"); + + eliminateFI(MI, FIOperandNum, FrameIndex, stackSize, spOffset); } Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const { diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h index f951219da3eb4..058d5950cadc0 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h @@ -49,6 +49,11 @@ struct XtensaRegisterInfo : public XtensaGenRegisterInfo { unsigned FIOperandNum, RegScavenger *RS) const override; Register getFrameRegister(const MachineFunction &MF) const override; + +private: + void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const; }; } // end namespace llvm From 57e4efc0fc9872864d158ae9521770380f6d983d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:09 +0300 Subject: [PATCH 017/150] [Xtensa] Implement lowering ConstantPool and address operations. Lower ConstantPool, GlobalAddress, BlockAddress and JumpTable. Implement lowering of External and JumpTable symbols to MCInst representation. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 103 +++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 5 + llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp | 22 ++++ llvm/lib/Target/Xtensa/XtensaMCInstLower.h | 4 + 4 files changed, 133 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 6983978f6f0a5..330954e8e086f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -43,6 +43,7 @@ static bool isLongCall(const char *str) { XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, const XtensaSubtarget &STI) : TargetLowering(tm), Subtarget(STI) { + MVT PtrVT = MVT::i32; // Set up the register classes. addRegisterClass(MVT::i32, &Xtensa::ARRegClass); @@ -68,10 +69,22 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); } + // Handle the various types of symbolic address. + setOperationAction(ISD::ConstantPool, PtrVT, Custom); + setOperationAction(ISD::GlobalAddress, PtrVT, Custom); + setOperationAction(ISD::BlockAddress, PtrVT, Custom); + setOperationAction(ISD::JumpTable, PtrVT, Custom); + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); } +bool XtensaTargetLowering::isOffsetFoldingLegal( + const GlobalAddressSDNode *GA) const { + // The Xtensa target isn't yet aware of offsets. + return false; +} + bool XtensaTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const { return false; @@ -482,7 +495,7 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, } bool XtensaTargetLowering::CanLowerReturn( - CallingConv::ID CallConv, MachineFunction & MF, bool IsVarArg, + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl &Outs, LLVMContext &Context) const { SmallVector RVLocs; CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); @@ -571,6 +584,86 @@ SDValue XtensaTargetLowering::LowerImmediateFP(SDValue Op, return Op; } +SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + // Reloc::Model RM = DAG.getTarget().getRelocationModel(); + SDLoc DL(Op); + + if (GlobalAddressSDNode *G = dyn_cast(Op)) { + auto PtrVt = getPointerTy(DAG.getDataLayout()); + const GlobalValue *GV = G->getGlobal(); + + // Check Op SDNode users + // If there are only CALL nodes, don't expand Global Address + SDNode &OpNode = *Op.getNode(); + bool Val = false; + for (SDNode::use_iterator UI = OpNode.use_begin(); UI != OpNode.use_end(); + ++UI) { + SDNode &User = *UI.getUse().getUser(); + unsigned OpCode = User.getOpcode(); + if (OpCode != XtensaISD::CALL) { + Val = true; + break; + } + } + if (!Val) { + SDValue TargAddr = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVt, + 0, 0 /* TargetFlags */); + return TargAddr; + } + + SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVt, Align(4)); + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + + return CPWrap; + } + llvm_unreachable("invalid global addresses to lower"); +} + +SDValue XtensaTargetLowering::LowerBlockAddress(BlockAddressSDNode *Node, + SelectionDAG &DAG) const { + const BlockAddress *BA = Node->getBlockAddress(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + XtensaConstantPoolValue *CPV = + XtensaConstantPoolConstant::Create(BA, 0, XtensaCP::CPBlockAddress, 0); + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); + + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + return CPWrap; +} + +SDValue XtensaTargetLowering::LowerJumpTable(JumpTableSDNode *JT, + SelectionDAG &DAG) const { + SDLoc DL(JT); + EVT PtrVt = getPointerTy(DAG.getDataLayout()); + + // Create a constant pool entry for the callee address + XtensaConstantPoolValue *CPV = + XtensaConstantPoolJumpTable::Create(*DAG.getContext(), JT->getIndex()); + + // Get the address of the callee into a register + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4)); + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + + return CPWrap; +} + +SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP, + SelectionDAG &DAG) const { + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + SDValue Result; + if (CP->isMachineConstantPoolEntry()) + Result = + DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, CP->getAlign()); + else + Result = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlign(), + CP->getOffset()); + + return getAddrPCRel(Result, DAG); +} + SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { @@ -578,6 +671,14 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerImmediate(Op, DAG); case ISD::ConstantFP: return LowerImmediateFP(Op, DAG); + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: + return LowerBlockAddress(cast(Op), DAG); + case ISD::JumpTable: + return LowerJumpTable(cast(Op), DAG); + case ISD::ConstantPool: + return LowerConstantPool(cast(Op), DAG); default: llvm_unreachable("Unexpected node to lower"); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 18c7772a43451..0fbfffe34d43f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -46,6 +46,7 @@ class XtensaTargetLowering : public TargetLowering { explicit XtensaTargetLowering(const TargetMachine &TM, const XtensaSubtarget &STI); + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; const char *getTargetNodeName(unsigned Opcode) const override; @@ -73,6 +74,10 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBlockAddress(BlockAddressSDNode *Node, SelectionDAG &DAG) const; + SDValue LowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; + SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp b/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp index 4688091a26bb7..d3dc082617e15 100644 --- a/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp +++ b/llvm/lib/Target/Xtensa/XtensaMCInstLower.cpp @@ -28,6 +28,16 @@ XtensaMCInstLower::XtensaMCInstLower(MCContext &ctx, XtensaAsmPrinter &asmPrinter) : Ctx(ctx), Printer(asmPrinter) {} +MCSymbol * +XtensaMCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const { + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + +MCSymbol * +XtensaMCInstLower::GetJumpTableSymbol(const MachineOperand &MO) const { + return Printer.GetJTISymbol(MO.getIndex()); +} + MCSymbol * XtensaMCInstLower::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { // Create a symbol for the name. @@ -53,6 +63,13 @@ XtensaMCInstLower::LowerSymbolOperand(const MachineOperand &MO, Symbol = Printer.GetBlockAddressSymbol(MO.getBlockAddress()); Offset += MO.getOffset(); break; + case MachineOperand::MO_ExternalSymbol: + Symbol = GetExternalSymbolSymbol(MO); + Offset += MO.getOffset(); + break; + case MachineOperand::MO_JumpTableIndex: + Symbol = GetJumpTableSymbol(MO); + break; case MachineOperand::MO_ConstantPoolIndex: Symbol = GetConstantPoolIndexSymbol(MO); Offset += MO.getOffset(); @@ -91,7 +108,12 @@ MCOperand XtensaMCInstLower::lowerOperand(const MachineOperand &MO, return MCOperand::createImm(MO.getImm() + Offset); case MachineOperand::MO_RegisterMask: break; + case MachineOperand::MO_MachineBasicBlock: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: + case MachineOperand::MO_JumpTableIndex: case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_BlockAddress: return LowerSymbolOperand(MO, MOTy, Offset); default: llvm_unreachable("unknown operand type"); diff --git a/llvm/lib/Target/Xtensa/XtensaMCInstLower.h b/llvm/lib/Target/Xtensa/XtensaMCInstLower.h index 32a0ad86a3850..344c28058adcf 100644 --- a/llvm/lib/Target/Xtensa/XtensaMCInstLower.h +++ b/llvm/lib/Target/Xtensa/XtensaMCInstLower.h @@ -39,6 +39,10 @@ class LLVM_LIBRARY_VISIBILITY XtensaMCInstLower { MCOperand lowerOperand(const MachineOperand &MO, unsigned Offset = 0) const; private: + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; MCOperand LowerSymbolOperand(const MachineOperand &MO, From 5d2d8426fe44659bcfe6e17227d6ee1ca936e100 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:09 +0300 Subject: [PATCH 018/150] [Xtensa] Implement emitPrologue/emitEpilogue --- .../lib/Target/Xtensa/XtensaFrameLowering.cpp | 223 +++++++++++++++++- llvm/lib/Target/Xtensa/XtensaFrameLowering.h | 13 + 2 files changed, 234 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index 71941e7671930..453d6c48b2f23 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -28,6 +28,48 @@ XtensaFrameLowering::XtensaFrameLowering() : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0, Align(4)) {} +/* Xtensa stack frames look like: + + +-------------------------------+ + | incoming stack arguments | + +-------------------------------+ + A | caller-allocated save area | + | for register arguments | + +-------------------------------+ <-- incoming stack pointer + B | CALL0 ABI: | + | callee-allocated save area | + | for arguments that are | + | split between registers and | + | the stack (Register-Spill | + | Area) | + | | + | Win ABI: | + | Register-Spill Overflow | + | 8 words for CALL8/CALLX8 | + +-------------------------------+ <-- arg_pointer_rtx + C | callee-allocated save area | + | for register varargs | + +-------------------------------+ <-- hard_frame_pointer_rtx; + | | stack_pointer_rtx + gp_sp_offset + | GPR save area | + UNITS_PER_WORD + +-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset + | | + UNITS_PER_HWVALUE + | FPR save area | + +-------------------------------+ <-- frame_pointer_rtx (virtual) + | local variables | + P +-------------------------------+ + | outgoing stack arguments | + +-------------------------------+ + | caller-allocated save area | + | for register arguments | + +-------------------------------+ <-- stack_pointer_rtx + + At least two of A, B and C will be empty. + + Dynamic stack allocations such as alloca insert data at point P. + They decrease stack_pointer_rtx but leave frame_pointer_rtx and + hard_frame_pointer_rtx unchanged. */ + // hasFP - Return true if the specified function should have a dedicated frame // pointer register. This is true if the function has variable sized allocas or // if frame pointer elimination is disabled. @@ -38,10 +80,159 @@ bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const { } void XtensaFrameLowering::emitPrologue(MachineFunction &MF, - MachineBasicBlock &MBB) const {} + MachineBasicBlock &MBB) const { + assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented"); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const XtensaRegisterInfo *RegInfo = static_cast( + MF.getSubtarget().getRegisterInfo()); + const XtensaInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned SP = Xtensa::SP; + unsigned FP = RegInfo->getFrameRegister(MF); + MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + + // First, compute final stack size. + uint64_t StackSize = MFI.getStackSize(); + uint64_t PrevStackSize = StackSize; + + // Round up StackSize to 16*N + StackSize += (16 - StackSize) & 0xf; + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI.adjustsStack()) + return; + + // Adjust stack. + TII.adjustStackPtr(SP, -StackSize, MBB, MBBI); + + // emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + const std::vector &CSI = MFI.getCalleeSavedInfo(); + + if (CSI.size()) { + // Find the instruction past the last instruction that saves a + // callee-saved register to the stack. + for (unsigned i = 0; i < CSI.size(); ++i) + ++MBBI; + + // Iterate over list of callee-saved registers and emit .cfi_offset + // directives. + for (const auto &I : CSI) { + int64_t Offset = MFI.getObjectOffset(I.getFrameIdx()); + unsigned Reg = I.getReg(); + + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( + nullptr, MRI->getDwarfRegNum(Reg, 1), Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + + // if framepointer enabled, set it to point to the stack pointer. + if (hasFP(MF)) { + // Insert instruction "move $fp, $sp" at this location. + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), FP) + .addReg(SP) + .addReg(SP) + .setMIFlag(MachineInstr::FrameSetup); + + // emit ".cfi_def_cfa_register $fp" + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( + nullptr, MRI->getDwarfRegNum(FP, true))); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + + if (StackSize != PrevStackSize) { + MFI.setStackSize(StackSize); + + for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) { + if (!MFI.isDeadObjectIndex(i)) { + int64_t SPOffset = MFI.getObjectOffset(i); + + if (SPOffset < 0) + MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize); + } + } + } +} void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, - MachineBasicBlock &MBB) const {} + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const XtensaRegisterInfo *RegInfo = static_cast( + MF.getSubtarget().getRegisterInfo()); + const XtensaInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + DebugLoc dl = MBBI->getDebugLoc(); + unsigned SP = Xtensa::SP; + unsigned FP = RegInfo->getFrameRegister(MF); + + // if framepointer enabled, restore the stack pointer. + if (hasFP(MF)) { + // Find the first instruction that restores a callee-saved register. + MachineBasicBlock::iterator I = MBBI; + + for (unsigned i = 0; i < MFI.getCalleeSavedInfo().size(); ++i) + --I; + + BuildMI(MBB, I, dl, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP); + } + + // Get the number of bytes from FrameInfo + uint64_t StackSize = MFI.getStackSize(); + + if (!StackSize) + return; + + // Adjust stack. + TII.adjustStackPtr(SP, StackSize, MBB, MBBI); +} + +bool XtensaFrameLowering::spillCalleeSavedRegisters( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + ArrayRef CSI, const TargetRegisterInfo *TRI) const { + MachineFunction *MF = MBB.getParent(); + + MachineBasicBlock &EntryBlock = *(MF->begin()); + const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); + + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + // Add the callee-saved register as live-in. Do not add if the register is + // A0 and return address is taken, because it will be implemented in + // method XtensaTargetLowering::LowerRETURNADDR. + // It's killed at the spill, unless the register is RA and return address + // is taken. + unsigned Reg = CSI[i].getReg(); + bool IsA0AndRetAddrIsTaken = + (Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken(); + if (!IsA0AndRetAddrIsTaken) + EntryBlock.addLiveIn(Reg); + + // Insert the spill to the stack frame. + bool IsKill = !IsA0AndRetAddrIsTaken; + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); + TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(), + RC, TRI); + } + + return true; +} + +bool XtensaFrameLowering::restoreCalleeSavedRegisters( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + MutableArrayRef CSI, + const TargetRegisterInfo *TRI) const { + return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI); +} // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr( @@ -62,3 +253,31 @@ MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr( return MBB.erase(I); } + +void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF, + BitVector &SavedRegs, + RegScavenger *RS) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const XtensaRegisterInfo *RegInfo = static_cast( + MF.getSubtarget().getRegisterInfo()); + unsigned FP = RegInfo->getFrameRegister(MF); + + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); + + // Mark $fp as used if function has dedicated frame pointer. + if (hasFP(MF)) + SavedRegs.set(FP); + + // Set scavenging frame index if necessary. + uint64_t MaxSPOffset = MFI.estimateStackSize(MF); + + if (isInt<12>(MaxSPOffset)) + return; + + const TargetRegisterClass &RC = Xtensa::ARRegClass; + const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); + unsigned Size = TRI->getSpillSize(RC); + Align Alignment = TRI->getSpillAlign(RC); + int FI = MF.getFrameInfo().CreateStackObject(Size, Alignment, false); + RS->addScavengingFrameIndex(FI); +} diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h index 584438d179bb8..b112f069cd618 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h @@ -31,6 +31,19 @@ class XtensaFrameLowering : public TargetFrameLowering { MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + ArrayRef CSI, + const TargetRegisterInfo *TRI) const override; + bool + restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + MutableArrayRef CSI, + const TargetRegisterInfo *TRI) const override; + + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, + RegScavenger *RS) const override; }; } // namespace llvm From 874d3954b9f74b0260b349a87e47aaf4079ef0d9 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:10 +0300 Subject: [PATCH 019/150] [Xtensa] Lower stack operations Implement lowering of dynamic_stackalloc, stacksave, stackrestore. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 49 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 4 ++ 2 files changed, 53 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 330954e8e086f..e3d862cc281e7 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -75,6 +75,12 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::BlockAddress, PtrVT, Custom); setOperationAction(ISD::JumpTable, PtrVT, Custom); + // Implement custom stack allocations + setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); + // Implement custom stack save and restore + setOperationAction(ISD::STACKSAVE, MVT::Other, Custom); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom); + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); } @@ -664,6 +670,43 @@ SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP, return getAddrPCRel(Result, DAG); } +SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op, + SelectionDAG &DAG) const { + unsigned sp = Xtensa::SP; + return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op), sp, Op.getValueType()); +} + +SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op, + SelectionDAG &DAG) const { + unsigned sp = Xtensa::SP; + return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), sp, Op.getOperand(1)); +} + +SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, + SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); // Legalize the chain. + SDValue Size = Op.getOperand(1); // Legalize the size. + EVT VT = Size->getValueType(0); + SDLoc DL(Op); + + // Round up Size to 32 + SDValue Size1 = + DAG.getNode(ISD::ADD, DL, VT, Size, DAG.getConstant(31, DL, MVT::i32)); + SDValue SizeRoundUp = + DAG.getNode(ISD::AND, DL, VT, Size1, DAG.getConstant(~31, DL, MVT::i32)); + + unsigned SPReg = Xtensa::SP; + SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT); + SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value + Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain + + SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32); + Chain = NewVal.getValue(1); + + SDValue Ops[2] = {NewVal, Chain}; + return DAG.getMergeValues(Ops, DL); +} + SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { @@ -679,6 +722,12 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerJumpTable(cast(Op), DAG); case ISD::ConstantPool: return LowerConstantPool(cast(Op), DAG); + case ISD::STACKSAVE: + return LowerSTACKSAVE(Op, DAG); + case ISD::STACKRESTORE: + return LowerSTACKRESTORE(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: + return LowerDYNAMIC_STACKALLOC(Op, DAG); default: llvm_unreachable("Unexpected node to lower"); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 0fbfffe34d43f..f2435cc188346 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -79,6 +79,10 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; + SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; + SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; From 19d5a897d334302dd9eefcbc5da1852ec3978376 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:11:10 +0300 Subject: [PATCH 020/150] [Xtensa] Implement lowering SELECT_CC, SETCC --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 208 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 27 ++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 41 ++++ llvm/lib/Target/Xtensa/XtensaOperators.td | 8 + 4 files changed, 283 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index e3d862cc281e7..1f17ec7f232ac 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -75,6 +75,27 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::BlockAddress, PtrVT, Custom); setOperationAction(ISD::JumpTable, PtrVT, Custom); + // Used by legalize types to correctly generate the setcc result. + // AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32); + setOperationPromotedToType(ISD::SETCC, MVT::i1, MVT::i32); + setOperationPromotedToType(ISD::BR_CC, MVT::i1, MVT::i32); + + setOperationAction(ISD::BR_CC, MVT::i32, Legal); + setOperationAction(ISD::BR_CC, MVT::i64, Expand); + + setOperationAction(ISD::SELECT, MVT::i32, Expand); + setOperationAction(ISD::SELECT, MVT::i64, Expand); + + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); + + setOperationAction(ISD::SETCC, MVT::i32, + Custom); // folds into brcond + setOperationAction(ISD::SETCC, MVT::i64, Expand); + + // make BRCOND legal, its actually only legal for a subset of conds + setOperationAction(ISD::BRCOND, MVT::Other, Legal); + // Implement custom stack allocations setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); // Implement custom stack save and restore @@ -558,6 +579,56 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, return DAG.getNode(XtensaISD::RET_FLAG, DL, MVT::Other, RetOps); } +SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT Ty = Op.getOperand(0).getValueType(); + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueV = Op.getOperand(2); + SDValue FalseV = Op.getOperand(3); + ISD::CondCode CC = cast(Op->getOperand(4))->get(); + SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); + + // Wrap select nodes + return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueV, FalseV, + TargetCC); +} + +SDValue XtensaTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT Ty = Op.getOperand(0).getValueType(); + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + ISD::CondCode CC = cast(Op.getOperand(2))->get(); + SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); + + // Check Op SDNode users + // If there are only CALL/CALLW nodes, don't expand Global Address + SDNode &OpNode = *Op.getNode(); + bool Val = false; + for (SDNode::use_iterator UI = OpNode.use_begin(); UI != OpNode.use_end(); + ++UI) { + SDNode &User = *UI.getUse().getUser(); + unsigned OpCode = User.getOpcode(); + if (OpCode == ISD::BRCOND) { + Val = true; + break; + } + } + + // SETCC has BRCOND predecessor, return original operation + if (Val) + return Op; + + // Expand to target SELECT_CC + SDValue TrueV = DAG.getConstant(1, DL, Op.getValueType()); + SDValue FalseV = DAG.getConstant(0, DL, Op.getValueType()); + + return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueV, FalseV, + TargetCC); +} + SDValue XtensaTargetLowering::LowerImmediate(SDValue Op, SelectionDAG &DAG) const { const ConstantSDNode *CN = cast(Op); @@ -714,6 +785,10 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerImmediate(Op, DAG); case ISD::ConstantFP: return LowerImmediateFP(Op, DAG); + case ISD::SETCC: + return LowerSETCC(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: @@ -741,7 +816,140 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(RET_FLAG); OPCODE(CALL); OPCODE(PCREL_WRAPPER); + OPCODE(SELECT); + OPCODE(SELECT_CC); } return NULL; #undef OPCODE } + +//===----------------------------------------------------------------------===// +// Custom insertion +//===----------------------------------------------------------------------===// + +static int GetBranchKind(int Cond, bool &BrInv) { + switch (Cond) { + case ISD::SETEQ: + case ISD::SETOEQ: + case ISD::SETUEQ: + return Xtensa::BEQ; + case ISD::SETNE: + case ISD::SETONE: + case ISD::SETUNE: + return Xtensa::BNE; + case ISD::SETLT: + case ISD::SETOLT: + return Xtensa::BLT; + case ISD::SETLE: + case ISD::SETOLE: + BrInv = true; + return Xtensa::BGE; + case ISD::SETGT: + case ISD::SETOGT: + BrInv = true; + return Xtensa::BLT; + case ISD::SETGE: + case ISD::SETOGE: + return Xtensa::BGE; + case ISD::SETULT: + return Xtensa::BLTU; + case ISD::SETULE: + BrInv = true; + return Xtensa::BGEU; + case ISD::SETUGT: + BrInv = true; + return Xtensa::BLTU; + case ISD::SETUGE: + return Xtensa::BGEU; + default: + return -1; + } +} + +MachineBasicBlock * +XtensaTargetLowering::emitSelectCC(MachineInstr &MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + MachineOperand &LHS = MI.getOperand(1); + MachineOperand &RHS = MI.getOperand(2); + MachineOperand &TrueV = MI.getOperand(3); + MachineOperand &FalseV = MI.getOperand(4); + MachineOperand &Cond = MI.getOperand(5); + + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + // thisMBB: + // ... + // TrueVal = ... + // cmpTY ccX, r1, r2 + // bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + bool BrInv = false; + int BrKind = GetBranchKind(Cond.getImm(), BrInv); + if (BrInv) { + BuildMI(BB, DL, TII.get(BrKind)) + .addReg(RHS.getReg()) + .addReg(LHS.getReg()) + .addMBB(sinkMBB); + } else { + BuildMI(BB, DL, TII.get(BrKind)) + .addReg(LHS.getReg()) + .addReg(RHS.getReg()) + .addMBB(sinkMBB); + } + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, TII.get(Xtensa::PHI), MI.getOperand(0).getReg()) + .addReg(FalseV.getReg()) + .addMBB(copy0MBB) + .addReg(TrueV.getReg()) + .addMBB(thisMBB); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( + MachineInstr &MI, MachineBasicBlock *MBB) const { + switch (MI.getOpcode()) { + case Xtensa::SELECT: + return emitSelectCC(MI, MBB); + default: + llvm_unreachable("Unexpected instr type to insert"); + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index f2435cc188346..f8da0ab75913a 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -35,7 +35,14 @@ enum { PCREL_WRAPPER, // Return with a flag operand. Operand 0 is the chain operand. - RET_FLAG + RET_FLAG, + + // Selects between operand 0 and operand 1. Operand 2 is the + // mask of condition-code values for which operand 0 should be + // chosen over operand 1; it has the same form as BR_CCMASK. + // Operand 3 is the flag operand. + SELECT, + SELECT_CC }; } @@ -46,6 +53,13 @@ class XtensaTargetLowering : public TargetLowering { explicit XtensaTargetLowering(const TargetMachine &TM, const XtensaSubtarget &STI); + EVT getSetCCResultType(const DataLayout &, LLVMContext &, + EVT VT) const override { + if (!VT.isVector()) + return MVT::i32; + return VT.changeVectorElementTypeToInteger(); + } + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; @@ -69,6 +83,10 @@ class XtensaTargetLowering : public TargetLowering { const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override; + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const override; + private: const XtensaSubtarget &Subtarget; @@ -79,6 +97,9 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; + SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; @@ -86,6 +107,10 @@ class XtensaTargetLowering : public TargetLowering { SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; + + // Implement EmitInstrWithCustomInserter for individual operation types. + MachineBasicBlock *emitSelectCC(MachineInstr &MI, + MachineBasicBlock *BB) const; }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 9dea877c2a983..da7413f4fc784 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -411,6 +411,38 @@ def BBSI : RRI8_Inst<0x07, (outs), let imm8 = target; } +def : Pat<(brcc SETGT, AR:$s, AR:$t, bb:$target), + (BLT AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcc SETUGT, AR:$s, AR:$t, bb:$target), + (BLTU AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcc SETLE, AR:$s, AR:$t, bb:$target), + (BGE AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcc SETULE, AR:$s, AR:$t, bb:$target), + (BGEU AR:$t, AR:$s, bb:$target)>; + +def : Pat<(brcond (i32 (seteq AR:$s, AR:$t)), bb:$target), + (BEQ AR:$s, AR:$t, bb:$target)>; +def : Pat<(brcond (i32 (setne AR:$s, AR:$t)), bb:$target), + (BNE AR:$s, AR:$t, bb:$target)>; +def : Pat<(brcond (i32 (setge AR:$s, AR:$t)), bb:$target), + (BGE AR:$s, AR:$t, bb:$target)>; +def : Pat<(brcond (i32 (setle AR:$s, AR:$t)), bb:$target), + (BLT AR:$s, AR:$t, bb:$target)>; +def : Pat<(brcond (i32 (setuge AR:$s, AR:$t)), bb:$target), + (BGEU AR:$s, AR:$t, bb:$target)>; +def : Pat<(brcond (i32 (setult AR:$s, AR:$t)), bb:$target), + (BLTU AR:$s, AR:$t, bb:$target)>; +def : Pat<(brcond (i32 (setgt AR:$s, AR:$t)), bb:$target), + (BLT AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcond (i32 (setugt AR:$s, AR:$t)), bb:$target), + (BLTU AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcond (i32 (setle AR:$s, AR:$t)), bb:$target), + (BGE AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcond (i32 (setule AR:$s, AR:$t)), bb:$target), + (BGEU AR:$t, AR:$s, bb:$target)>; + +def : Pat<(brcond AR:$s, bb:$target), (BNEZ AR:$s, bb:$target)>; + //===----------------------------------------------------------------------===// // Call and jump instructions //===----------------------------------------------------------------------===// @@ -550,3 +582,12 @@ let Defs = [SP], Uses = [SP] in { "#ADJCALLSTACKUP", [(Xtensa_callseq_end timm:$amt1, timm:$amt2)]>; } + +//===----------------------------------------------------------------------===// +// Generic select instruction +//===----------------------------------------------------------------------===// +let usesCustomInserter = 1 in { + def SELECT : Pseudo<(outs AR:$dst), (ins AR:$lhs, AR:$rhs, AR:$t, AR:$f, i32imm:$cond), + "!select $dst, $lhs, $rhs, $t, $f, $cond", + [(set AR:$dst, (Xtensa_select_cc AR:$lhs, AR:$rhs, AR:$t, AR:$f, imm:$cond))]>; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index bb764d2c9247b..a85550c46531e 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -19,6 +19,10 @@ def SDT_XtensaWrapPtr : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; +def SDT_XtensaSelectCC : SDTypeProfile<1, 5, + [SDTCisSameAs<0, 1>, + SDTCisSameAs<2, 3>, + SDTCisVT<5, i32>]>; //===----------------------------------------------------------------------===// // Node definitions //===----------------------------------------------------------------------===// @@ -37,3 +41,7 @@ def Xtensa_callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_XtensaCallSeqEnd, SDNPOutGlue]>; def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, []>; + +def Xtensa_select : SDNode<"XtensaISD::SELECT", SDTSelect>; +def Xtensa_select_cc: SDNode<"XtensaISD::SELECT_CC", SDT_XtensaSelectCC, + [SDNPInGlue]>; From 623ab15d539ae4a601c2acfd10fc0cce38b73a9d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:23 +0300 Subject: [PATCH 021/150] [Xtensa] Support for a variety of additional LLVM IR constructs. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 1f17ec7f232ac..2e9c28d3b8a2f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -96,6 +96,64 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, // make BRCOND legal, its actually only legal for a subset of conds setOperationAction(ISD::BRCOND, MVT::Other, Legal); + // Handle integer types. + for (unsigned I = MVT::FIRST_INTEGER_VALUETYPE; + I <= MVT::LAST_INTEGER_VALUETYPE; ++I) { + MVT VT = MVT::SimpleValueType(I); + if (isTypeLegal(VT)) { + // No support at all + setOperationAction(ISD::SDIVREM, VT, Expand); + setOperationAction(ISD::UDIVREM, VT, Expand); + } + } + + setOperationAction(ISD::MUL, MVT::i32, Expand); + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + setOperationAction(ISD::MUL, MVT::i64, Expand); + setOperationAction(ISD::MULHS, MVT::i64, Expand); + setOperationAction(ISD::MULHU, MVT::i64, Expand); + + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + + setOperationAction(ISD::SDIV, MVT::i64, Expand); + setOperationAction(ISD::UDIV, MVT::i64, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::UREM, MVT::i64, Expand); + + // Xtensa doesn't support [ADD,SUB][E,C] + setOperationAction(ISD::ADDC, MVT::i32, Expand); + setOperationAction(ISD::ADDE, MVT::i32, Expand); + setOperationAction(ISD::SUBC, MVT::i32, Expand); + setOperationAction(ISD::SUBE, MVT::i32, Expand); + + setOperationAction(ISD::ADD, MVT::i64, Expand); + setOperationAction(ISD::SUB, MVT::i64, Expand); + + // Bit Manipulation + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::ROTR, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand); + // Implement custom stack allocations setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); // Implement custom stack save and restore From ffa7c6fc3e983acfbe9fb0a104b429d5b45fbd15 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:24 +0300 Subject: [PATCH 022/150] [Xtensa] Lower SHIFT PARTS and shift operations. Also lower SHL, SRA, SRL with register operands. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 129 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 17 ++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 34 ++++- llvm/lib/Target/Xtensa/XtensaOperators.td | 16 +++ 4 files changed, 189 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 2e9c28d3b8a2f..c523bf8b291f7 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -133,6 +133,11 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::ADD, MVT::i64, Expand); setOperationAction(ISD::SUB, MVT::i64, Expand); + // Xtensa doesn't support s[hl,rl,ra]_parts + setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); + // Bit Manipulation setOperationAction(ISD::BSWAP, MVT::i32, Expand); setOperationAction(ISD::BSWAP, MVT::i64, Expand); @@ -836,6 +841,83 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, return DAG.getMergeValues(Ops, DL); } +SDValue XtensaTargetLowering::LowerShiftLeftParts(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + MVT VT = MVT::i32; + + SDValue Lo = Op.getOperand(0), Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + + SDValue SetShiftLeft = DAG.getNode(XtensaISD::SSL, DL, MVT::Glue, Shamt); + SDValue ShiftLeftHi = + DAG.getNode(XtensaISD::SRC, DL, VT, Hi, Lo, SetShiftLeft); + SDValue SetShiftLeft1 = DAG.getNode(XtensaISD::SSL, DL, MVT::Glue, Shamt); + SDValue ShiftLeftLo = DAG.getNode(XtensaISD::SHL, DL, VT, Lo, SetShiftLeft1); + SDValue Cond = DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(VT.getSizeInBits(), DL, MVT::i32)); + Lo = DAG.getNode(ISD::SELECT, DL, VT, Cond, DAG.getConstant(0, DL, VT), + ShiftLeftLo); + Hi = DAG.getNode(ISD::SELECT, DL, VT, Cond, ShiftLeftLo, ShiftLeftHi); + + SDValue Ops[2] = {Lo, Hi}; + return DAG.getMergeValues(Ops, DL); +} + +SDValue XtensaTargetLowering::LowerShiftRightParts(SDValue Op, + SelectionDAG &DAG, + bool IsSRA) const { + SDLoc DL(Op); + SDValue Lo = Op.getOperand(0), Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + MVT VT = MVT::i32; + + if (IsSRA) { + SDValue SetShiftRight1 = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); + SDValue ShiftRightLo1 = + DAG.getNode(XtensaISD::SRC, DL, VT, Hi, Lo, SetShiftRight1); + + SDValue SetShiftRight2 = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); + SDValue ShiftRightHi1 = + DAG.getNode(XtensaISD::SRA, DL, VT, Hi, SetShiftRight2); + + SDValue SetShiftRight3 = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); + SDValue ShiftRightLo2 = + DAG.getNode(XtensaISD::SRA, DL, VT, Hi, SetShiftRight3); + + SDValue ShiftRightHi2 = + DAG.getNode(ISD::SRA, DL, VT, Hi, DAG.getConstant(31, DL, VT)); + + SDValue Cond = + DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(VT.getSizeInBits(), DL, MVT::i32)); + Hi = DAG.getNode(ISD::SELECT, DL, VT, Cond, ShiftRightHi2, ShiftRightHi1); + Lo = DAG.getNode(ISD::SELECT, DL, VT, Cond, ShiftRightLo2, ShiftRightLo1); + } else { + SDValue SetShiftRight1 = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); + SDValue ShiftRightLo1 = + DAG.getNode(XtensaISD::SRC, DL, VT, Hi, Lo, SetShiftRight1); + + SDValue SetShiftRight2 = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); + SDValue ShiftRightHi1 = + DAG.getNode(XtensaISD::SRL, DL, VT, Hi, SetShiftRight2); + + SDValue SetShiftRight3 = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); + SDValue ShiftRightLo2 = + DAG.getNode(XtensaISD::SRL, DL, VT, Hi, SetShiftRight3); + + SDValue Cond = + DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(VT.getSizeInBits(), DL, MVT::i32)); + Hi = DAG.getNode(ISD::SELECT, DL, VT, Cond, DAG.getConstant(0, DL, VT), + ShiftRightHi1); + Lo = DAG.getNode(ISD::SELECT, DL, VT, Cond, ShiftRightLo2, ShiftRightLo1); + } + + SDValue Ops[2] = {Lo, Hi}; + return DAG.getMergeValues(Ops, DL); +} + SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { @@ -861,6 +943,12 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerSTACKRESTORE(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::SHL_PARTS: + return LowerShiftLeftParts(Op, DAG); + case ISD::SRA_PARTS: + return LowerShiftRightParts(Op, DAG, true); + case ISD::SRL_PARTS: + return LowerShiftRightParts(Op, DAG, false); default: llvm_unreachable("Unexpected node to lower"); } @@ -876,6 +964,12 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(PCREL_WRAPPER); OPCODE(SELECT); OPCODE(SELECT_CC); + OPCODE(SHL); + OPCODE(SRA); + OPCODE(SRL); + OPCODE(SRC); + OPCODE(SSL); + OPCODE(SSR); } return NULL; #undef OPCODE @@ -1004,9 +1098,44 @@ XtensaTargetLowering::emitSelectCC(MachineInstr &MI, MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + switch (MI.getOpcode()) { case Xtensa::SELECT: return emitSelectCC(MI, MBB); + + case Xtensa::SLL_P: { + MachineOperand &R = MI.getOperand(0); + MachineOperand &S = MI.getOperand(1); + MachineOperand &SA = MI.getOperand(2); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SSL)).addReg(SA.getReg()); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SLL), R.getReg()).addReg(S.getReg()); + MI.eraseFromParent(); + return MBB; + } + case Xtensa::SRA_P: { + MachineOperand &R = MI.getOperand(0); + MachineOperand &T = MI.getOperand(1); + MachineOperand &SA = MI.getOperand(2); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SSR)).addReg(SA.getReg()); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SRA), R.getReg()).addReg(T.getReg()); + MI.eraseFromParent(); + return MBB; + } + case Xtensa::SRL_P: { + MachineOperand &R = MI.getOperand(0); + MachineOperand &T = MI.getOperand(1); + MachineOperand &SA = MI.getOperand(2); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SSR)).addReg(SA.getReg()); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SRL), R.getReg()).addReg(T.getReg()); + MI.eraseFromParent(); + return MBB; + } + default: llvm_unreachable("Unexpected instr type to insert"); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index f8da0ab75913a..00222e9bee391 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -42,7 +42,15 @@ enum { // chosen over operand 1; it has the same form as BR_CCMASK. // Operand 3 is the flag operand. SELECT, - SELECT_CC + SELECT_CC, + + // Shift + SHL, + SRA, + SRL, + SRC, + SSL, + SSR }; } @@ -53,6 +61,10 @@ class XtensaTargetLowering : public TargetLowering { explicit XtensaTargetLowering(const TargetMachine &TM, const XtensaSubtarget &STI); + MVT getScalarShiftAmountTy(const DataLayout &, EVT LHSTy) const override { + return LHSTy.getSizeInBits() <= 32 ? MVT::i32 : MVT::i64; + } + EVT getSetCCResultType(const DataLayout &, LLVMContext &, EVT VT) const override { if (!VT.isVector()) @@ -104,6 +116,9 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; + SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index da7413f4fc784..6db7c6a093362 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -105,33 +105,39 @@ def MOVGEZ : RRR_Inst<0x00, 0x03, 0x0B, (outs AR:$r), (ins AR:$s, AR:$t), let Uses = [SAR] in { def SLL : RRR_Inst<0x00, 0x01, 0x0A, (outs AR:$r), (ins AR:$s), - "sll\t$r, $s", []> { + "sll\t$r, $s", + [(set AR:$r, (Xtensa_shl AR:$s))]> { let t = 0x00; } def SRA : RRR_Inst<0x00, 0x01, 0x0B, (outs AR:$r), (ins AR:$t), - "sra\t$r, $t", []> { + "sra\t$r, $t", + [(set AR:$r, (Xtensa_sra AR:$t))]> { let s = 0x00; } def SRC : RRR_Inst<0x00, 0x01, 0x08, (outs AR:$r), (ins AR:$s, AR:$t), - "src\t$r, $s, $t", []>; + "src\t$r, $s, $t", + [(set AR:$r, (Xtensa_src AR:$s, AR:$t))]>; def SRL : RRR_Inst<0x00, 0x01, 0x09, (outs AR:$r), (ins AR:$t), - "srl\t$r, $t", []> { + "srl\t$r, $t", + [(set AR:$r, (Xtensa_srl AR:$t))]> { let s = 0x00; } } let Defs = [SAR] in { def SSL : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), - "ssl\t$s", []> { + "ssl\t$s", + [(Xtensa_ssl AR:$s)]> { let r = 0x01; let t = 0x00; } def SSR : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), - "ssr\t$s", []> { + "ssr\t$s", + [(Xtensa_ssr AR:$s)]> { let r = 0x00; let t = 0x00; } @@ -189,6 +195,22 @@ def SSAI : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins uimm5:$imm), let t{0} = imm{4}; } +// Shift Pseudo instructions: +// SSL/SSR + Shift combination +let usesCustomInserter = 1 in { + def SLL_P : Pseudo<(outs AR:$r), (ins AR:$s, AR:$sa), + "# SLL_P $r, $s, $sa", + [(set AR:$r, (shl AR:$s, AR:$sa))]>; + + def SRA_P : Pseudo<(outs AR:$r), (ins AR:$t, AR:$sa), + "# SRA_P $r, $t, $sa", + [(set AR:$r, (sra AR:$t, AR:$sa))]>; + + def SRL_P : Pseudo<(outs AR:$r), (ins AR:$t, AR:$sa), + "# SRL_P $r, $t, $sa", + [(set AR:$r, (srl AR:$t, AR:$sa))]>; +} + //===----------------------------------------------------------------------===// // Load and store instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index a85550c46531e..3ed6b9791cf9f 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -23,6 +23,15 @@ def SDT_XtensaSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<0, 1>, SDTCisSameAs<2, 3>, SDTCisVT<5, i32>]>; + +def SDT_XtensaSHL : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaSRA : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaSRL : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaSRC : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, + SDTCisVT<2, i32>]>; +def SDT_XtensaSSL : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; +def SDT_XtensaSSR : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; + //===----------------------------------------------------------------------===// // Node definitions //===----------------------------------------------------------------------===// @@ -45,3 +54,10 @@ def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, def Xtensa_select : SDNode<"XtensaISD::SELECT", SDTSelect>; def Xtensa_select_cc: SDNode<"XtensaISD::SELECT_CC", SDT_XtensaSelectCC, [SDNPInGlue]>; + +def Xtensa_shl: SDNode<"XtensaISD::SHL", SDT_XtensaSHL, [SDNPInGlue]>; +def Xtensa_sra: SDNode<"XtensaISD::SRA", SDT_XtensaSRA, [SDNPInGlue]>; +def Xtensa_srl: SDNode<"XtensaISD::SRL", SDT_XtensaSRL, [SDNPInGlue]>; +def Xtensa_src: SDNode<"XtensaISD::SRC", SDT_XtensaSRC, [SDNPInGlue]>; +def Xtensa_ssl: SDNode<"XtensaISD::SSL", SDT_XtensaSSL, [SDNPOutGlue]>; +def Xtensa_ssr: SDNode<"XtensaISD::SSR", SDT_XtensaSSR, [SDNPOutGlue]>; From a729ef204a3b723895b3c48fc20ed8a5be09b764 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:24 +0300 Subject: [PATCH 023/150] [Xtensa] Implement load pseudo operations and patterns. Implement load unsigned 8-bit pseudo operation. Implement extending loads patterns extloadi1/i8/i16. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 20 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 12 +++++++++++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 1 + 3 files changed, 33 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index c523bf8b291f7..9248c5e682557 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -1099,6 +1099,8 @@ XtensaTargetLowering::emitSelectCC(MachineInstr &MI, MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); DebugLoc DL = MI.getDebugLoc(); switch (MI.getOpcode()) { @@ -1136,6 +1138,24 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( return MBB; } + case Xtensa::L8I_P: { + MachineOperand &R = MI.getOperand(0); + MachineOperand &Op1 = MI.getOperand(1); + MachineOperand &Op2 = MI.getOperand(2); + + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned R1 = MRI.createVirtualRegister(RC); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::L8UI), R1).add(Op1).add(Op2); + + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SLLI), R2).addReg(R1).addImm(24); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SRAI), R.getReg()) + .addReg(R2) + .addImm(24); + MI.eraseFromParent(); + return MBB; + } default: llvm_unreachable("Unexpected instr type to insert"); } diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 6db7c6a093362..d3c37c509115c 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -284,6 +284,18 @@ let isCodeGenOnly = 1, mayLoad = 1 in { } } +// Xtensa missed L8I load operation, use pseudo operation +let usesCustomInserter = 1 in +def L8I_P: Pseudo<(outs AR:$t), (ins mem8:$addr), + "!L8I_P $t, $addr", + [(set AR:$t, (sextloadi8 + addr_ish1:$addr))]>; + +//extending loads +def : Pat<(i32 (extloadi1 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; +def : Pat<(i32 (extloadi8 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; +def : Pat<(i32 (extloadi16 addr_ish2:$addr)), (L16UI addr_ish2:$addr)>; + //===----------------------------------------------------------------------===// // Conditional branch instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp index e5efd5a958aa2..0bd6077aa5a43 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -107,6 +107,7 @@ void XtensaRegisterInfo::eliminateFI(MachineBasicBlock::iterator II, bool Valid = false; switch (MI.getOpcode()) { + case Xtensa::L8I_P: case Xtensa::L8UI: case Xtensa::S8I: Valid = (Offset >= 0 && Offset <= 255); From f6ad2a7ade11fab8a043fce2adcf0896220f0104 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:25 +0300 Subject: [PATCH 024/150] [Xtensa] Support for variable arguments --- llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + .../lib/Target/Xtensa/XtensaFrameLowering.cpp | 2 +- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 191 +++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 7 + llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 2 +- .../Xtensa/XtensaMachineFunctionInfo.cpp | 19 ++ .../Target/Xtensa/XtensaMachineFunctionInfo.h | 56 +++++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 2 +- 8 files changed, 268 insertions(+), 12 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index d4300678a0434..2208428f4c10c 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -21,6 +21,7 @@ add_llvm_target(XtensaCodeGen XtensaInstrInfo.cpp XtensaISelDAGToDAG.cpp XtensaISelLowering.cpp + XtensaMachineFunctionInfo.cpp XtensaMCInstLower.cpp XtensaRegisterInfo.cpp XtensaSubtarget.cpp diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index 453d6c48b2f23..ca2c806ef8a7f 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -14,8 +14,8 @@ #include "XtensaFrameLowering.h" #include "XtensaInstrInfo.h" +#include "XtensaMachineFunctionInfo.h" #include "XtensaSubtarget.h" -#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 9248c5e682557..bac8298ce9010 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -15,10 +15,10 @@ #include "XtensaISelLowering.h" #include "XtensaConstantPoolValue.h" +#include "XtensaMachineFunctionInfo.h" #include "XtensaSubtarget.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/CallingConvLower.h" -#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -32,6 +32,9 @@ using namespace llvm; #define DEBUG_TYPE "xtensa-lower" +static const MCPhysReg XtensaArgRegs[6] = {Xtensa::A2, Xtensa::A3, Xtensa::A4, + Xtensa::A5, Xtensa::A6, Xtensa::A7}; + // Return true if we must use long (in fact, indirect) function call. // It's simplified version, production implimentation must // resolve a functions in ROM (usually glibc functions) @@ -165,6 +168,14 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::STACKSAVE, MVT::Other, Custom); setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom); + // VASTART and VACOPY need to deal with the Xtensa-specific varargs + // structure, but VAEND is a no-op. + setOperationAction(ISD::VASTART, MVT::Other, Custom); + // we use special va_list structure so we have to customize this + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Custom); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); } @@ -180,6 +191,11 @@ bool XtensaTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, return false; } +unsigned XtensaTargetLowering::getVaListSizeInBits(const DataLayout &DL) const { + // 2 * sizeof(int*) + sizeof(int) + return 3 * 4; +} + //===----------------------------------------------------------------------===// // Calling conventions //===----------------------------------------------------------------------===// @@ -303,14 +319,14 @@ SDValue XtensaTargetLowering::LowerFormalArguments( SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); + XtensaFunctionInfo *XtensaFI = MF.getInfo(); + EVT PtrVT = getPointerTy(MF.getDataLayout()); + + XtensaFI->setVarArgsFrameIndex(0); // Used with vargs to acumulate store chains. std::vector OutChains; - if (IsVarArg) { - llvm_unreachable("Var arg not supported by FormalArguments Lowering"); - } - // Assign locations to all of the incoming arguments. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, @@ -379,6 +395,66 @@ SDValue XtensaTargetLowering::LowerFormalArguments( } } + if (IsVarArg) { + ArrayRef ArgRegs = makeArrayRef(XtensaArgRegs); + unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); + const TargetRegisterClass *RC = &Xtensa::ARRegClass; + MachineFrameInfo &MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + unsigned RegSize = 4; + MVT RegTy = MVT::getIntegerVT(RegSize * 8); + + XtensaFI->setVarArgsFirstGPR(Idx + 2); // 2 - number of a2 register + + XtensaFI->setVarArgsStackOffset(MFI.CreateFixedObject( + PtrVT.getSizeInBits() / 8, CCInfo.getNextStackOffset(), true)); + + // Offset of the first variable argument from stack pointer, and size of + // the vararg save area. For now, the varargs save area is either zero or + // large enough to hold a0-a7. + int VaArgOffset, VarArgsSaveSize; + + // If all registers are allocated, then all varargs must be passed on the + // stack and we don't need to save any argregs. + if (ArgRegs.size() == Idx) { + VaArgOffset = CCInfo.getNextStackOffset(); + VarArgsSaveSize = 0; + } else { + VarArgsSaveSize = RegSize * (ArgRegs.size() - Idx); + VaArgOffset = -VarArgsSaveSize; + } + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + int FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true); + XtensaFI->setVarArgsFrameIndex(FI); + + // Copy the integer registers that may have been used for passing varargs + // to the vararg save area. + for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += RegSize) { + const unsigned Reg = RegInfo.createVirtualRegister(RC); + unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); + + // Argument passed in FrameReg we save in A8 (in emitPrologue), + // so load argument from A8 + if (ArgRegs[I] == FrameReg) { + RegInfo.addLiveIn(Xtensa::A8, Reg); + } else { + RegInfo.addLiveIn(ArgRegs[I], Reg); + } + + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy); + FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, + MachinePointerInfo::getFixedStack(MF, FI)); + cast(Store.getNode()) + ->getMemOperand() + ->setValue((Value *)nullptr); + OutChains.push_back(Store); + } + } + // All stores are grouped in one node to allow the matching between // the size of Ins and InVals. This only happens when on varg functions if (!OutChains.empty()) { @@ -598,10 +674,6 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { - if (IsVarArg) { - report_fatal_error("VarArg not supported"); - } - MachineFunction &MF = DAG.getMachineFunction(); // Assign locations to each returned value. @@ -841,6 +913,103 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, return DAG.getMergeValues(Ops, DL); } +SDValue XtensaTargetLowering::LowerVASTART(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + XtensaFunctionInfo *XtensaFI = MF.getInfo(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + SDLoc DL(Op); + + SDValue Chain = Op.getOperand(0); + SDValue Addr = Op.getOperand(1); + + // typedef struct __va_list_tag { + // int32_t *__va_stk; /* Initialized to point to the position of the + // * first argument in memory offset to account for + // the + // * arguments passed in registers and to account for + // * the size of the argument registers not being + // 16-byte + // * aligned. E.G., there are 6 argument registers + // * of 4 bytes each, but we want the __va_ndx for the + // * first stack argument to have the maximal + // * alignment of 16 bytes, so we offset the __va_stk + // address by + // * 32 bytes so that __va_stk[32] references the + // first + // * argument on the stack. + // */ + // int32_t *__va_reg; /* Points to a stack-allocated region holding the + // * contents + // * of the incoming argument registers + // */ + // int32_t __va_ndx; /* Index initialized to the position of the first + // * unnamed (variable) argument. This same index is + // also + // * used to address the arguments passed in memory. + // */ + // } __va_list_tag[1]; + + SDValue ArgAR; + SDValue OverflowPtrAdvance; + SDValue StackOffsetFI = + DAG.getFrameIndex(XtensaFI->getVarArgsStackOffset(), PtrVT); + + if (XtensaFI->getVarArgsFirstGPR() < 8) { + ArgAR = + DAG.getConstant(XtensaFI->getVarArgsFirstGPR() * 4 - 8, DL, MVT::i32); + OverflowPtrAdvance = DAG.getConstant(32, DL, PtrVT); + } else { + OverflowPtrAdvance = DAG.getNode(ISD::AND, DL, PtrVT, StackOffsetFI, + DAG.getConstant(0xf, DL, PtrVT)); + OverflowPtrAdvance = DAG.getNode(ISD::ADD, DL, PtrVT, OverflowPtrAdvance, + DAG.getConstant(32, DL, PtrVT)); + ArgAR = OverflowPtrAdvance; + } + + SDValue FR = DAG.getFrameIndex(XtensaFI->getVarArgsFrameIndex(), PtrVT); + + uint64_t FrameOffset = PtrVT.getSizeInBits() / 8; + SDValue ConstFrameOffset1 = DAG.getConstant(FrameOffset, DL, PtrVT); + SDValue ConstFrameOffset2 = DAG.getConstant(FrameOffset * 2, DL, PtrVT); + + const Value *SV = cast(Op.getOperand(2))->getValue(); + + // Store first word : arguments given in stack (__va_stk) + // Advance Argument Overflow pointer down, lest it will point to start + // after register argument va_arg finished + SDValue StackOffsetFICorr = + DAG.getNode(ISD::SUB, DL, PtrVT, StackOffsetFI, OverflowPtrAdvance); + SDValue firstStore = + DAG.getStore(Chain, DL, StackOffsetFICorr, Addr, MachinePointerInfo(SV)); + + uint64_t nextOffset = FrameOffset; + SDValue nextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, Addr, ConstFrameOffset1); + + // Store second word : arguments given on registers (__va_reg) + SDValue FRAdvance = + DAG.getConstant(XtensaFI->getVarArgsFirstGPR() * 4 - 8, DL, PtrVT); + SDValue FRDecr = DAG.getNode(ISD::SUB, DL, PtrVT, FR, FRAdvance); + SDValue secondStore = DAG.getStore(firstStore, DL, FRDecr, nextPtr, + MachinePointerInfo(SV, nextOffset)); + nextOffset += FrameOffset; + nextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, Addr, ConstFrameOffset2); + + // Store first word : number of int regs (__va_ndx) + return DAG.getStore(secondStore, DL, ArgAR, nextPtr, + MachinePointerInfo(SV, nextOffset)); +} + +SDValue XtensaTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const { + // We have to copy the entire va_list struct: + // 2*sizeof(int*) + sizeof(int) = 12 Byte + unsigned VAListSize = 12; + return DAG.getMemcpy(Op.getOperand(0), Op, Op.getOperand(1), Op.getOperand(2), + DAG.getConstant(VAListSize, SDLoc(Op), MVT::i32), Align(8), + false, true, false, MachinePointerInfo(), + MachinePointerInfo()); +} + SDValue XtensaTargetLowering::LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -943,6 +1112,10 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerSTACKRESTORE(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::VASTART: + return LowerVASTART(Op, DAG); + case ISD::VACOPY: + return LowerVACOPY(Op, DAG); case ISD::SHL_PARTS: return LowerShiftLeftParts(Op, DAG); case ISD::SRA_PARTS: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 00222e9bee391..e56cab673c59f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -76,6 +76,10 @@ class XtensaTargetLowering : public TargetLowering { bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; const char *getTargetNodeName(unsigned Opcode) const override; + + /// Returns the size of the platform's va_list object. + unsigned getVaListSizeInBits(const DataLayout &DL) const override; + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, @@ -112,6 +116,9 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 489f405efcb1f..41085edfbc251 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "XtensaInstrInfo.h" +#include "XtensaMachineFunctionInfo.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/MachineConstantPool.h" -#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" diff --git a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.cpp b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.cpp new file mode 100644 index 0000000000000..1a285b2aa5310 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.cpp @@ -0,0 +1,19 @@ +//===- XtensaMachineFunctionInfo.cpp - Private data used for Xtensa -------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "XtensaMachineFunctionInfo.h" +//#include "MCTargetDesc/XtensaBaseInfo.h" +#include "XtensaInstrInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" + +using namespace llvm; diff --git a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h new file mode 100644 index 0000000000000..f84d48bb6b761 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h @@ -0,0 +1,56 @@ +//==- XtensaMachineFunctionInfo.h - Xtensa machine function info --*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// 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 declares Xtensa-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAMACHINEFUNCTIONINFO_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAMACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class XtensaFunctionInfo : public MachineFunctionInfo { + MachineFunction &MF; + + unsigned VarArgsFirstGPR; + int VarArgsStackOffset; + unsigned VarArgsFrameIndex; + +public: + explicit XtensaFunctionInfo(MachineFunction &MF) + : MF(MF), VarArgsFirstGPR(0), VarArgsStackOffset(0), + VarArgsFrameIndex(0) { + MF.setAlignment(Align(4)); + } + + unsigned getVarArgsFirstGPR() const { return VarArgsFirstGPR; } + void setVarArgsFirstGPR(unsigned GPR) { VarArgsFirstGPR = GPR; } + + int getVarArgsStackOffset() const { return VarArgsStackOffset; } + void setVarArgsStackOffset(int Offset) { VarArgsStackOffset = Offset; } + + // Get and set the frame index of the first stack vararg. + unsigned getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(unsigned FI) { VarArgsFrameIndex = FI; } + + // TODO: large frame size definition should be specified more precisely + bool isLargeFrame() { + return (MF.getFrameInfo().estimateStackSize(MF) > 512) ? true : false; + } +}; + +} // namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSAMACHINEFUNCTIONINFO_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp index 0bd6077aa5a43..198517a75451f 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -14,8 +14,8 @@ #include "XtensaRegisterInfo.h" #include "XtensaInstrInfo.h" +#include "XtensaMachineFunctionInfo.h" #include "XtensaSubtarget.h" -#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" From 2d31297d55fb117707b750a9c262ac27bbf6ba95 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:25 +0300 Subject: [PATCH 025/150] [Xtensa] Implement lowering BR_JT operation --- llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 11 ++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 36 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 3 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 6 ++++ llvm/lib/Target/Xtensa/XtensaOperators.td | 4 +++ 5 files changed, 60 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 3f9d8d4d355fb..a2c0de031a750 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -20,6 +20,7 @@ #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -42,6 +43,16 @@ getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) { void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { XtensaMCInstLower Lower(MF->getContext(), *this); MCInst LoweredMI; + unsigned Opc = MI->getOpcode(); + + switch (Opc) { + case Xtensa::BR_JT: { + EmitToStreamer( + *OutStreamer, + MCInstBuilder(Xtensa::JX).addReg(MI->getOperand(0).getReg())); + return; + } + } Lower.lower(MI, LoweredMI); EmitToStreamer(*OutStreamer, LoweredMI); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index bac8298ce9010..995ba907aad9f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -95,6 +95,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::SETCC, MVT::i32, Custom); // folds into brcond setOperationAction(ISD::SETCC, MVT::i64, Expand); + + // Expand jump table branches as address arithmetic followed by an + // indirect jump. + setOperationAction(ISD::BR_JT, MVT::Other, Custom); // make BRCOND legal, its actually only legal for a subset of conds setOperationAction(ISD::BRCOND, MVT::Other, Legal); @@ -845,6 +849,35 @@ SDValue XtensaTargetLowering::LowerBlockAddress(BlockAddressSDNode *Node, return CPWrap; } +SDValue XtensaTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Table = Op.getOperand(1); + SDValue Index = Op.getOperand(2); + SDLoc DL(Op); + JumpTableSDNode *JT = cast(Table); + MachineFunction &MF = DAG.getMachineFunction(); + const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo(); + + SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32); + + const DataLayout &TD = DAG.getDataLayout(); + EVT PTy = getPointerTy(TD); + + unsigned EntrySize = MJTI->getEntrySize(TD); + + Index = DAG.getNode(ISD::MUL, DL, Index.getValueType(), Index, + DAG.getConstant(EntrySize, DL, Index.getValueType())); + SDValue Addr = DAG.getNode(ISD::ADD, DL, Index.getValueType(), Index, Table); + + EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8); + SDValue LD = DAG.getExtLoad(ISD::SEXTLOAD, DL, PTy, Chain, Addr, + MachinePointerInfo::getJumpTable(MF), MemVT); + Addr = LD; + + return DAG.getNode(XtensaISD::BR_JT, DL, MVT::Other, LD.getValue(1), Addr, + TargetJT); +} + SDValue XtensaTargetLowering::LowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const { SDLoc DL(JT); @@ -1090,6 +1123,8 @@ SDValue XtensaTargetLowering::LowerShiftRightParts(SDValue Op, SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::BR_JT: + return LowerBR_JT(Op, DAG); case ISD::Constant: return LowerImmediate(Op, DAG); case ISD::ConstantFP: @@ -1137,6 +1172,7 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(PCREL_WRAPPER); OPCODE(SELECT); OPCODE(SELECT_CC); + OPCODE(BR_JT); OPCODE(SHL); OPCODE(SRA); OPCODE(SRL); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index e56cab673c59f..99febf0d453be 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -25,6 +25,8 @@ namespace XtensaISD { enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, + BR_JT, + // Calls a function. Operand 0 is the chain operand and operand 1 // is the target address. The arguments start at operand 2. // There is an optional glue operand at the end. @@ -106,6 +108,7 @@ class XtensaTargetLowering : public TargetLowering { private: const XtensaSubtarget &Subtarget; + SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index d3c37c509115c..3e74dd1821105 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -532,6 +532,12 @@ def : Pat<(Xtensa_call (i32 texternalsym:$dst)), def : Pat<(Xtensa_call AR:$dst), (CALLX0 AR:$dst)>; +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, Size = 3 in { + def BR_JT: Pseudo<(outs), (ins AR:$s, i32imm:$jt), + "!br_jt_p, $s, $jt", + [(Xtensa_brjt AR:$s, tjumptable:$jt)]>; +} + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index 3ed6b9791cf9f..ca8ec55c56709 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -23,6 +23,8 @@ def SDT_XtensaSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<0, 1>, SDTCisSameAs<2, 3>, SDTCisVT<5, i32>]>; +def SDT_XtensaBrJT : SDTypeProfile<0, 2, + [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; def SDT_XtensaSHL : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_XtensaSRA : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; @@ -61,3 +63,5 @@ def Xtensa_srl: SDNode<"XtensaISD::SRL", SDT_XtensaSRL, [SDNPInGlue]>; def Xtensa_src: SDNode<"XtensaISD::SRC", SDT_XtensaSRC, [SDNPInGlue]>; def Xtensa_ssl: SDNode<"XtensaISD::SSL", SDT_XtensaSSL, [SDNPOutGlue]>; def Xtensa_ssr: SDNode<"XtensaISD::SSR", SDT_XtensaSSR, [SDNPOutGlue]>; + +def Xtensa_brjt: SDNode<"XtensaISD::BR_JT", SDT_XtensaBrJT, [SDNPHasChain]>; From 18b90072ed55ecf0f6b606ef3d709e2d3fdf266c Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:25 +0300 Subject: [PATCH 026/150] [Xtensa] Support for address intrinsics. Add support for llvm.{frameaddress,returnaddress} intrinsics. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 41 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 2 + 2 files changed, 43 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 995ba907aad9f..ee5b3d064c64f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -768,6 +768,26 @@ SDValue XtensaTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { TargetCC); } +SDValue XtensaTargetLowering::LowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + // check the depth + // TODO: xtensa-gcc can handle this, by navigating through the stack, we + // should be able to do this too + assert((cast(Op.getOperand(0))->getZExtValue() == 0) && + "Return address can be determined only for current frame."); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + MVT VT = Op.getSimpleValueType(); + unsigned RA = Xtensa::A0; + MFI.setReturnAddressIsTaken(true); + + // Return RA, which contains the return address. Mark it an implicit + // live-in. + unsigned Reg = MF.addLiveIn(RA, getRegClassFor(VT)); + return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, VT); +} + SDValue XtensaTargetLowering::LowerImmediate(SDValue Op, SelectionDAG &DAG) const { const ConstantSDNode *CN = cast(Op); @@ -921,6 +941,23 @@ SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op, return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), sp, Op.getOperand(1)); } +SDValue XtensaTargetLowering::LowerFRAMEADDR(SDValue Op, + SelectionDAG &DAG) const { + // check the depth + assert((cast(Op.getOperand(0))->getZExtValue() == 0) && + "Frame address can only be determined for current frame."); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); + MFI.setFrameAddressIsTaken(true); + EVT VT = Op.getValueType(); + SDLoc DL(Op); + + unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); + return FrameAddr; +} + SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); // Legalize the chain. @@ -1129,6 +1166,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerImmediate(Op, DAG); case ISD::ConstantFP: return LowerImmediateFP(Op, DAG); + case ISD::RETURNADDR: + return LowerRETURNADDR(Op, DAG); case ISD::SETCC: return LowerSETCC(Op, DAG); case ISD::SELECT_CC: @@ -1145,6 +1184,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerSTACKSAVE(Op, DAG); case ISD::STACKRESTORE: return LowerSTACKRESTORE(Op, DAG); + case ISD::FRAMEADDR: + return LowerFRAMEADDR(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); case ISD::VASTART: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 99febf0d453be..af8cc64b730a7 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -118,6 +118,7 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const; @@ -125,6 +126,7 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; From dbe85b0abb50874ea893da7a583a30c515185bc3 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:26 +0300 Subject: [PATCH 027/150] [Xtensa] Add basic support for inline asm constraints --- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 9 +++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 3 + llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 55 ++++++++++++++ llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 6 ++ llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 25 ++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 76 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 21 +++++ 7 files changed, 195 insertions(+) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index 81b375a783206..d46ed47c1d0a1 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -26,6 +26,15 @@ using namespace llvm; #include "XtensaGenAsmWriter.inc" +void XtensaInstPrinter::printAddress(unsigned Base, int64_t Disp, + raw_ostream &O) { + O << Disp; + if (Base) { + O << '('; + O << getRegisterName(Base) << ')'; + } +} + static void printExpr(const MCExpr *Expr, raw_ostream &OS) { int Offset = 0; const MCSymbolRefExpr *SRE; diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index ebbfda967f26a..befee7d3f564a 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -35,6 +35,9 @@ class XtensaInstPrinter : public MCInstPrinter { // Print the given operand. static void printOperand(const MCOperand &MO, raw_ostream &O); + // Print an address + static void printAddress(unsigned Base, int64_t Disp, raw_ostream &O); + // Override MCInstPrinter. void printRegName(raw_ostream &O, unsigned RegNo) const override; void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index a2c0de031a750..8c27af73945d2 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "XtensaAsmPrinter.h" +#include "MCTargetDesc/XtensaInstPrinter.h" #include "XtensaConstantPoolValue.h" #include "XtensaMCInstLower.h" #include "llvm/BinaryFormat/ELF.h" @@ -215,6 +216,60 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue( } } +void XtensaAsmPrinter::printOperand(const MachineInstr *MI, int OpNo, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNo); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + case MachineOperand::MO_Immediate: { + XtensaMCInstLower Lower(MF->getContext(), *this); + MCOperand MC(Lower.lowerOperand(MI->getOperand(OpNo))); + XtensaInstPrinter::printOperand(MC, O); + break; + } + case MachineOperand::MO_GlobalAddress: + O << *getSymbol(MO.getGlobal()); + break; + default: + llvm_unreachable(""); + } + + if (MO.getTargetFlags()) { + O << ")"; + } +} + +bool XtensaAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &O) { + if (ExtraCode && *ExtraCode == 'n') { + if (!MI->getOperand(OpNo).isImm()) + return true; + O << -int64_t(MI->getOperand(OpNo).getImm()); + } else { + printOperand(MI, OpNo, O); + } + return false; +} + +bool XtensaAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, + const char *ExtraCode, + raw_ostream &OS) { + XtensaInstPrinter::printAddress(MI->getOperand(OpNo).getReg(), + MI->getOperand(OpNo + 1).getImm(), OS); + return false; +} + +void XtensaAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, + raw_ostream &OS) { + OS << '%' + << XtensaInstPrinter::getRegisterName(MI->getOperand(opNum).getReg()); + OS << "("; + OS << MI->getOperand(opNum + 1).getImm(); + OS << ")"; +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmPrinter() { RegisterAsmPrinter A(TheXtensaTarget); diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h index 0ba80bc18c1c2..50feaa0fcd2c0 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -38,6 +38,12 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { void emitInstruction(const MachineInstr *MI) override; void emitConstantPool() override; void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; + void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &O) override; + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &OS) override; + void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp index 456ecc1ae8d0b..57e722a4fe13f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp @@ -40,6 +40,9 @@ class XtensaDAGToDAGISel : public SelectionDAGISel { // Override SelectionDAGISel. void Select(SDNode *Node) override; + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector &OutOps) override; + bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset, int Scale) { EVT ValTy = Addr.getValueType(); @@ -136,3 +139,25 @@ void XtensaDAGToDAGISel::Select(SDNode *Node) { SelectCode(Node); } + +bool XtensaDAGToDAGISel::SelectInlineAsmMemoryOperand( + const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { + switch (ConstraintID) { + default: + llvm_unreachable("Unexpected asm memory constraint"); + case InlineAsm::Constraint_m: { + SDValue Base, Offset; + // TODO + selectMemRegAddr(Op, Base, Offset, 4); + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + case InlineAsm::Constraint_i: + case InlineAsm::Constraint_R: + case InlineAsm::Constraint_ZC: + OutOps.push_back(Op); + return false; + } + return false; +} diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index ee5b3d064c64f..e0c51adb322c3 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -200,6 +200,82 @@ unsigned XtensaTargetLowering::getVaListSizeInBits(const DataLayout &DL) const { return 3 * 4; } +//===----------------------------------------------------------------------===// +// Inline asm support +//===----------------------------------------------------------------------===// +TargetLowering::ConstraintType +XtensaTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'a': + case 'd': + case 'r': + return C_RegisterClass; + + default: + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +TargetLowering::ConstraintWeight +XtensaTargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + + // Look at the constraint type. + switch (*constraint) { + default: + weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + + case 'a': + case 'd': + case 'r': + if (CallOperandVal->getType()->isIntegerTy()) + weight = CW_Register; + break; + } + return weight; +} + +std::pair +XtensaTargetLowering::getRegForInlineAsmConstraint( + const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { + if (Constraint.size() == 1) { + // GCC Constraint Letters + switch (Constraint[0]) { + default: + break; + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'r': // General-purpose register + return std::make_pair(0U, &Xtensa::ARRegClass); + } + } + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} + +/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops +/// vector. If it is invalid, don't add anything to Ops. +void XtensaTargetLowering::LowerAsmOperandForConstraint( + SDValue Op, std::string &Constraint, std::vector &Ops, + SelectionDAG &DAG) const { + SDLoc DL(Op); + + // Only support length 1 constraints for now. + if (Constraint.length() > 1) + return; + + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + //===----------------------------------------------------------------------===// // Calling conventions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index af8cc64b730a7..cc811c435c8aa 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -82,6 +82,19 @@ class XtensaTargetLowering : public TargetLowering { /// Returns the size of the platform's va_list object. unsigned getVaListSizeInBits(const DataLayout &DL) const override; + std::pair + getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, MVT VT) const override; + TargetLowering::ConstraintType + getConstraintType(StringRef Constraint) const override; + TargetLowering::ConstraintWeight + getSingleConstraintMatchWeight(AsmOperandInfo &info, + const char *constraint) const override; + + void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, + std::vector &Ops, + SelectionDAG &DAG) const override; + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, @@ -138,6 +151,14 @@ class XtensaTargetLowering : public TargetLowering { // Implement EmitInstrWithCustomInserter for individual operation types. MachineBasicBlock *emitSelectCC(MachineInstr &MI, MachineBasicBlock *BB) const; + + unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override { + if (ConstraintCode == "R") + return InlineAsm::Constraint_R; + else if (ConstraintCode == "ZC") + return InlineAsm::Constraint_ZC; + return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); + } }; } // end namespace llvm From 2d3fb99ce35cb7896cbc48dedda51b73c0aad4e7 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:26 +0300 Subject: [PATCH 028/150] [Xtensa] Implement volatile load/store. Implement volatile load/store from/to volatile memory location. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 20 ++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index e0c51adb322c3..515e951513962 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -95,7 +95,7 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::SETCC, MVT::i32, Custom); // folds into brcond setOperationAction(ISD::SETCC, MVT::i64, Expand); - + // Expand jump table branches as address arithmetic followed by an // indirect jump. setOperationAction(ISD::BR_JT, MVT::Other, Custom); @@ -1472,6 +1472,11 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( const TargetRegisterClass *RC = getRegClassFor(MVT::i32); unsigned R1 = MRI.createVirtualRegister(RC); + const MachineMemOperand &MMO = **MI.memoperands_begin(); + if (MMO.isVolatile()) { + BuildMI(*MBB, MI, DL, TII.get(Xtensa::MEMW)); + } + BuildMI(*MBB, MI, DL, TII.get(Xtensa::L8UI), R1).add(Op1).add(Op2); unsigned R2 = MRI.createVirtualRegister(RC); @@ -1482,6 +1487,19 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MI.eraseFromParent(); return MBB; } + case Xtensa::S8I: + case Xtensa::S16I: + case Xtensa::S32I: + case Xtensa::L8UI: + case Xtensa::L16SI: + case Xtensa::L16UI: + case Xtensa::L32I: { + const MachineMemOperand &MMO = **MI.memoperands_begin(); + if (MMO.isVolatile()) { + BuildMI(*MBB, MI, DL, TII.get(Xtensa::MEMW)); + } + return MBB; + } default: llvm_unreachable("Unexpected instr type to insert"); } diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 3e74dd1821105..d7f8fc1910d31 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -216,7 +216,7 @@ let usesCustomInserter = 1 in { //===----------------------------------------------------------------------===// // Load instructions -let mayLoad = 1 in { +let mayLoad = 1, usesCustomInserter = 1 in { class Load_RRI8 oper, string instrAsm, SDPatternOperator opNode, ComplexPattern addrOp, Operand memOp> @@ -237,7 +237,7 @@ def L16UI : Load_RRI8<0x01, "l16ui", zextloadi16, addr_ish2, mem16>; def L32I : Load_RRI8<0x02, "l32i", load, addr_ish4, mem32>; // Store instructions -let mayStore = 1 in { +let mayStore = 1, usesCustomInserter = 1 in { class Store_II8 oper, string instrAsm, SDPatternOperator opNode, ComplexPattern addrOp, Operand memOp> : RRI8_Inst<0x02, (outs), (ins AR:$t, memOp:$addr), From 715267691bf261451188dd18672dbdcd0c9d07d3 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:27 +0300 Subject: [PATCH 029/150] [Xtensa] Implement branch analysis --- llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 305 ++++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 27 ++ 2 files changed, 330 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 41085edfbc251..38869fc252bd3 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -45,7 +45,8 @@ addFrameReference(const MachineInstrBuilder &MIB, int FI) { } XtensaInstrInfo::XtensaInstrInfo(XtensaSubtarget &sti) - : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP), RI(sti), STI(sti) {} + : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP), + RI(sti), STI(sti) {} /// Adjust SP by Amount bytes. void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, @@ -72,7 +73,9 @@ void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, .addReg(Reg1, RegState::Kill); } - BuildMI(MBB, I, DL, get(Xtensa::OR), SP).addReg(Reg, RegState::Kill).addReg(Reg, RegState::Kill); + BuildMI(MBB, I, DL, get(Xtensa::OR), SP) + .addReg(Reg, RegState::Kill) + .addReg(Reg, RegState::Kill); } void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, @@ -156,3 +159,301 @@ void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB, llvm_unreachable("Unsupported load immediate value"); } } + +bool XtensaInstrInfo::reverseBranchCondition( + SmallVectorImpl &Cond) const { + assert(Cond.size() <= 4 && "Invalid branch condition!"); + + switch (Cond[0].getImm()) { + case Xtensa::BEQ: + Cond[0].setImm(Xtensa::BNE); + return false; + case Xtensa::BNE: + Cond[0].setImm(Xtensa::BEQ); + return false; + case Xtensa::BLT: + Cond[0].setImm(Xtensa::BGE); + return false; + case Xtensa::BGE: + Cond[0].setImm(Xtensa::BLT); + return false; + case Xtensa::BLTU: + Cond[0].setImm(Xtensa::BGEU); + return false; + case Xtensa::BGEU: + Cond[0].setImm(Xtensa::BLTU); + return false; + + case Xtensa::BEQI: + Cond[0].setImm(Xtensa::BNEI); + return false; + case Xtensa::BNEI: + Cond[0].setImm(Xtensa::BEQI); + return false; + case Xtensa::BGEI: + Cond[0].setImm(Xtensa::BLTI); + return false; + case Xtensa::BLTI: + Cond[0].setImm(Xtensa::BGEI); + return false; + case Xtensa::BGEUI: + Cond[0].setImm(Xtensa::BLTUI); + return false; + case Xtensa::BLTUI: + Cond[0].setImm(Xtensa::BGEUI); + return false; + + case Xtensa::BEQZ: + Cond[0].setImm(Xtensa::BNEZ); + return false; + case Xtensa::BNEZ: + Cond[0].setImm(Xtensa::BEQZ); + return false; + case Xtensa::BLTZ: + Cond[0].setImm(Xtensa::BGEZ); + return false; + case Xtensa::BGEZ: + Cond[0].setImm(Xtensa::BLTZ); + return false; + + default: + llvm_unreachable("Invalid branch condition!"); + } +} + +bool XtensaInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify = false) const { + // Most of the code and comments here are boilerplate. + + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + + // Working from the bottom, when we see a non-terminator instruction, we're + // done. + if (!isUnpredicatedTerminator(*I)) + break; + + // A terminator that isn't a branch can't easily be handled by this + // analysis. + SmallVector ThisCond; + ThisCond.push_back(MachineOperand::CreateImm(0)); + const MachineOperand *ThisTarget; + if (!isBranch(I, ThisCond, ThisTarget)) + return true; + + // Can't handle indirect branches. + if (!ThisTarget->isMBB()) + return true; + + if (ThisCond[0].getImm() == Xtensa::J) { + // Handle unconditional branches. + if (!AllowModify) { + TBB = ThisTarget->getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (std::next(I) != MBB.end()) + std::next(I)->eraseFromParent(); + + Cond.clear(); + FBB = 0; + + // TBB is used to indicate the unconditinal destination. + TBB = ThisTarget->getMBB(); + continue; + } + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + // FIXME: add X86-style branch swap + FBB = TBB; + TBB = ThisTarget->getMBB(); + Cond.push_back(MachineOperand::CreateImm(ThisCond[0].getImm())); + + // push remaining operands + for (unsigned int i = 0; i < (I->getNumExplicitOperands() - 1); i++) + Cond.push_back(I->getOperand(i)); + + continue; + } + + // Handle subsequent conditional branches. + assert(Cond.size() <= 4); + assert(TBB); + + // Only handle the case where all conditional branches branch to the same + // destination. + if (TBB != ThisTarget->getMBB()) + return true; + + // If the conditions are the same, we can leave them alone. + unsigned OldCond = Cond[0].getImm(); + if (OldCond == ThisCond[0].getImm()) + continue; + } + + return false; +} + +unsigned XtensaInstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + // Most of the code and comments here are boilerplate. + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + if (BytesRemoved) + *BytesRemoved = 0; + + while (I != MBB.begin()) { + --I; + SmallVector Cond; + Cond.push_back(MachineOperand::CreateImm(0)); + const MachineOperand *Target; + if (!isBranch(I, Cond, Target)) + break; + if (!Target->isMBB()) + break; + // Remove the branch. + if (BytesRemoved) + *BytesRemoved += getInstSizeInBytes(*I); + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + return Count; +} + +unsigned XtensaInstrInfo::insertBranch( + MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, + ArrayRef Cond, const DebugLoc &DL, int *BytesAdded) const { + unsigned Count = 0; + if (BytesAdded) + *BytesAdded = 0; + if (FBB) { + // Need to build two branches then + // one to branch to TBB on Cond + // and a second one immediately after to unconditionally jump to FBB + Count = InsertBranchAtInst(MBB, MBB.end(), TBB, Cond, DL, BytesAdded); + auto &MI = *BuildMI(&MBB, DL, get(Xtensa::J)).addMBB(FBB); + Count++; + if (BytesAdded) + *BytesAdded += getInstSizeInBytes(MI); + return Count; + } + // This function inserts the branch at the end of the MBB + Count += InsertBranchAtInst(MBB, MBB.end(), TBB, Cond, DL, BytesAdded); + return Count; +} + +unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock *TBB, + ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert(Cond.size() <= 4 && + "Xtensa branch conditions have less than four components!"); + + if (Cond.empty() || (Cond[0].getImm() == Xtensa::J)) { + // Unconditional branch + MachineInstr *MI = BuildMI(MBB, I, DL, get(Xtensa::J)).addMBB(TBB); + if (BytesAdded && MI) + *BytesAdded += getInstSizeInBytes(*MI); + return 1; + } + + unsigned Count = 0; + unsigned BR_C = Cond[0].getImm(); + MachineInstr *MI = nullptr; + switch (BR_C) { + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + MI = BuildMI(MBB, I, DL, get(BR_C)) + .addReg(Cond[1].getReg()) + .addReg(Cond[2].getReg()) + .addMBB(TBB); + break; + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + MI = BuildMI(MBB, I, DL, get(BR_C)) + .addReg(Cond[1].getReg()) + .addImm(Cond[2].getImm()) + .addMBB(TBB); + break; + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB); + break; + default: + llvm_unreachable("Invalid branch type!"); + } + if (BytesAdded && MI) + *BytesAdded += getInstSizeInBytes(*MI); + ++Count; + return Count; +} + +bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI, + SmallVectorImpl &Cond, + const MachineOperand *&Target) const { + unsigned OpCode = MI->getOpcode(); + switch (OpCode) { + case Xtensa::J: + case Xtensa::JX: + case Xtensa::BR_JT: + Cond[0].setImm(OpCode); + Target = &MI->getOperand(0); + return true; + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + Cond[0].setImm(OpCode); + Target = &MI->getOperand(2); + return true; + + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + Cond[0].setImm(OpCode); + Target = &MI->getOperand(2); + return true; + + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + Cond[0].setImm(OpCode); + Target = &MI->getOperand(1); + return true; + + default: + assert(!MI->getDesc().isBranch() && "Unknown branch opcode"); + return false; + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h index 887ec99b8ccba..120323747b783 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -62,6 +62,33 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { // physical register Reg. void loadImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned *Reg, int64_t Value) const; + bool + reverseBranchCondition(SmallVectorImpl &Cond) const override; + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; + + unsigned InsertBranchAtInst(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock *TBB, + ArrayRef Cond, const DebugLoc &DL, + int *BytesAdded) const; + + // Return true if MI is a conditional or unconditional branch. + // When returning true, set Cond to the mask of condition-code + // values on which the instruction will branch, and set Target + // to the operand that contains the branch target. This target + // can be a register or a basic block. + bool isBranch(const MachineBasicBlock::iterator &MI, + SmallVectorImpl &Cond, + const MachineOperand *&Target) const; }; } // end namespace llvm From e40c9a11241b11e5f2fdde9ace3804a6e71381a0 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:12:27 +0300 Subject: [PATCH 030/150] [Xtensa] Implement support for the BranchRelaxation --- llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 181 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 16 +- llvm/lib/Target/Xtensa/XtensaRegisterInfo.h | 7 +- .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 3 + 4 files changed, 203 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 38869fc252bd3..387f96b8c9e67 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -13,11 +13,13 @@ //===----------------------------------------------------------------------===// #include "XtensaInstrInfo.h" +#include "XtensaConstantPoolValue.h" #include "XtensaMachineFunctionInfo.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" #define GET_INSTRINFO_CTOR_DTOR #include "XtensaGenInstrInfo.inc" @@ -160,6 +162,18 @@ void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB, } } +unsigned XtensaInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + case TargetOpcode::INLINEASM: { // Inline Asm: Variable size. + const MachineFunction *MF = MI.getParent()->getParent(); + const char *AsmStr = MI.getOperand(0).getSymbolName(); + return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); + } + default: + return MI.getDesc().getSize(); + } +} + bool XtensaInstrInfo::reverseBranchCondition( SmallVectorImpl &Cond) const { assert(Cond.size() <= 4 && "Invalid branch condition!"); @@ -221,6 +235,77 @@ bool XtensaInstrInfo::reverseBranchCondition( } } +MachineBasicBlock * +XtensaInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { + unsigned OpCode = MI.getOpcode(); + switch (OpCode) { + case Xtensa::BR_JT: + case Xtensa::JX: + return nullptr; + case Xtensa::J: + return MI.getOperand(0).getMBB(); + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + return MI.getOperand(2).getMBB(); + + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + return MI.getOperand(2).getMBB(); + + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + return MI.getOperand(1).getMBB(); + + default: + llvm_unreachable("Unknown branch opcode"); + } +} + +bool XtensaInstrInfo::isBranchOffsetInRange(unsigned BranchOp, + int64_t BrOffset) const { + switch (BranchOp) { + case Xtensa::J: + BrOffset -= 4; + return isIntN(18, BrOffset); + case Xtensa::JX: + return true; + case Xtensa::BR_JT: + return true; + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + BrOffset -= 4; + return isIntN(8, BrOffset); + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + BrOffset -= 4; + return isIntN(12, BrOffset); + default: + llvm_unreachable("Unknown branch opcode"); + } +} + bool XtensaInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, @@ -353,6 +438,102 @@ unsigned XtensaInstrInfo::insertBranch( return Count; } +void XtensaInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, + MachineBasicBlock &DestBB, + MachineBasicBlock &RestoreBB, + const DebugLoc &DL, + int64_t BrOffset, + RegScavenger *RS) const { + assert(RS && "RegScavenger required for long branching"); + assert(MBB.empty() && + "new block should be inserted for expanding unconditional branch"); + assert(MBB.pred_size() == 1); + + MachineFunction *MF = MBB.getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineConstantPool *ConstantPool = MF->getConstantPool(); + + if (!isInt<32>(BrOffset)) + report_fatal_error( + "Branch offsets outside of the signed 32-bit range not supported"); + XtensaConstantPoolValue *C = + XtensaConstantPoolMBB::Create(MF->getFunction().getContext(), &DestBB, 0); + unsigned Idx = ConstantPool->getConstantPoolIndex(C, Align(4)); + + // FIXME: A virtual register must be used initially, as the register + // scavenger won't work with empty blocks (SIInstrInfo::insertIndirectBranch + // uses the same workaround). + Register ScratchReg = MRI.createVirtualRegister(&Xtensa::ARRegClass); + auto II = MBB.end(); + + MachineInstr &L32R = *BuildMI(MBB, II, DL, get(Xtensa::L32R), ScratchReg) + .addConstantPoolIndex(Idx); + BuildMI(MBB, II, DL, get(Xtensa::JX)).addReg(ScratchReg, RegState::Kill); + RS->enterBasicBlockEnd(MBB); + unsigned Scav = RS->scavengeRegisterBackwards(Xtensa::ARRegClass, + L32R.getIterator(), false, 0); + MRI.replaceRegWith(ScratchReg, Scav); + MRI.clearVirtRegs(); + RS->setRegUsed(Scav); +} + +unsigned XtensaInstrInfo::InsertConstBranchAtInst( + MachineBasicBlock &MBB, MachineInstr *I, int64_t offset, + ArrayRef Cond, DebugLoc DL, int *BytesAdded) const { + // Shouldn't be a fall through. + assert(&MBB && "InsertBranch must not be told to insert a fallthrough"); + assert(Cond.size() <= 4 && + "Xtensa branch conditions have less than four components!"); + + if (Cond.empty() || (Cond[0].getImm() == Xtensa::J)) { + // Unconditional branch + MachineInstr *MI = BuildMI(MBB, I, DL, get(Xtensa::J)).addImm(offset); + if (BytesAdded && MI) + *BytesAdded += getInstSizeInBytes(*MI); + return 1; + } + + unsigned Count = 0; + unsigned BR_C = Cond[0].getImm(); + MachineInstr *MI = nullptr; + switch (BR_C) { + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + MI = BuildMI(MBB, I, DL, get(BR_C)) + .addImm(offset) + .addReg(Cond[1].getReg()) + .addReg(Cond[2].getReg()); + break; + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + MI = BuildMI(MBB, I, DL, get(BR_C)) + .addImm(offset) + .addReg(Cond[1].getReg()) + .addImm(Cond[2].getImm()); + break; + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + MI = BuildMI(MBB, I, DL, get(BR_C)).addImm(offset).addReg(Cond[1].getReg()); + break; + default: + llvm_unreachable("Invalid branch type!"); + } + if (BytesAdded && MI) + *BytesAdded += getInstSizeInBytes(*MI); + ++Count; + return Count; +} + unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineBasicBlock *TBB, diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h index 120323747b783..25597d9b0a220 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -37,6 +37,7 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; + unsigned getInstSizeInBytes(const MachineInstr &MI) const override; // Return the XtensaRegisterInfo, which this class owns. const XtensaRegisterInfo &getRegisterInfo() const { return RI; } @@ -64,6 +65,10 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { unsigned *Reg, int64_t Value) const; bool reverseBranchCondition(SmallVectorImpl &Cond) const override; + MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override; + + bool isBranchOffsetInRange(unsigned BranchOpc, + int64_t BrOffset) const override; bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl &Cond, @@ -74,13 +79,20 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { MachineBasicBlock *FBB, ArrayRef Cond, const DebugLoc &DL, int *BytesAdded = nullptr) const override; - + void insertIndirectBranch(MachineBasicBlock &MBB, + MachineBasicBlock &DestBB, + MachineBasicBlock &RestoreBB, const DebugLoc &DL, + int64_t BrOffset = 0, + RegScavenger *RS = nullptr) const override; unsigned InsertBranchAtInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineBasicBlock *TBB, ArrayRef Cond, const DebugLoc &DL, int *BytesAdded) const; - + unsigned InsertConstBranchAtInst(MachineBasicBlock &MBB, MachineInstr *I, + int64_t offset, + ArrayRef Cond, DebugLoc DL, + int *BytesAdded) const; // Return true if MI is a conditional or unconditional branch. // When returning true, set Cond to the mask of condition-code // values on which the instruction will branch, and set Target diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h index 058d5950cadc0..7f3506569d8c2 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.h @@ -40,6 +40,10 @@ struct XtensaRegisterInfo : public XtensaGenRegisterInfo { return true; } + bool trackLivenessAfterRegAlloc(const MachineFunction &) const override { + return true; + } + const uint16_t * getCalleeSavedRegs(const MachineFunction *MF = 0) const override; const uint32_t *getCallPreservedMask(const MachineFunction &MF, @@ -52,8 +56,7 @@ struct XtensaRegisterInfo : public XtensaGenRegisterInfo { private: void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, - int FrameIndex, uint64_t StackSize, - int64_t SPOffset) const; + int FrameIndex, uint64_t StackSize, int64_t SPOffset) const; }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index cce388bcd8c6b..fa8352cde8dbc 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -83,6 +83,7 @@ class XtensaPassConfig : public TargetPassConfig { } bool addInstSelector() override; + void addPreEmitPass() override; }; } // end anonymous namespace @@ -91,6 +92,8 @@ bool XtensaPassConfig::addInstSelector() { return false; } +void XtensaPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } + TargetPassConfig *XtensaTargetMachine::createPassConfig(PassManagerBase &PM) { return new XtensaPassConfig(*this, PM); } From e0cb2ab177854f596bff4a665a6eb14394392154 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:55 +0300 Subject: [PATCH 031/150] [Xtensa] Implement code density feature operations --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 10 +++ .../Disassembler/XtensaDisassembler.cpp | 64 ++++++++++++++++- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 22 ++++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 2 + .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 48 ++++++++++++- llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 3 +- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 4 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 68 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 14 ++++ 9 files changed, 231 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index cc97e03e0b806..37107e32bb5ab 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -179,6 +179,10 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm1_16() const { return isImm(1, 16); } + bool isImm1n_15() const { return (isImm(1, 15) || isImm(-1, -1)); } + + bool isImm32n_95() const { return isImm(-32, 95); } + bool isB4const() const { if (Kind != Immediate) return false; @@ -402,6 +406,12 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidImm1_16: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [1, 16]"); + case Match_InvalidImm1n_15: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-1, 15] except 0"); + case Match_InvalidImm32n_95: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-32, 95] except 0"); case Match_InvalidShimm1_31: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [1, 31]"); diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index b98613fe175a4..4b9aecedee3f4 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -189,6 +189,28 @@ static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeImm1n_15Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + if (!Imm) + Inst.addOperand(MCOperand::createImm(-1)); + else + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm32n_95Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<7>(Imm) && "Invalid immediate"); + if ((Imm & 0x60) == 0x60) + Inst.addOperand(MCOperand::createImm((~0x1f) | Imm)); + else + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { @@ -242,6 +264,34 @@ static DecodeStatus decodeMem32Operand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeMem32nOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3c)); + return MCDisassembler::Success; +} + +/// Read two bytes from the ArrayRef and return 16 bit data sorted +/// according to the given endianness. +static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsLittleEndian) { + // We want to read exactly 2 Bytes of data. + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + + if (!IsLittleEndian) { + llvm_unreachable("Big-endian mode currently is not supported!"); + } else { + Insn = (Bytes[1] << 8) | Bytes[0]; + } + + return MCDisassembler::Success; +} + /// Read four bytes from the ArrayRef and return 24 bit data sorted /// according to the given endianness. static DecodeStatus readInstruction24(ArrayRef Bytes, uint64_t Address, @@ -271,6 +321,18 @@ DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size, uint32_t Insn; DecodeStatus Result; + if (hasDensity()) { + Result = readInstruction16(Bytes, Address, Size, Insn, IsLittleEndian); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + LLVM_DEBUG(dbgs() << "Trying Xtensa 16-bit instruction table :\n"); + Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 2; + return Result; + } + } + Result = readInstruction24(Bytes, Address, Size, Insn, IsLittleEndian); if (Result == MCDisassembler::Fail) return MCDisassembler::Fail; @@ -278,4 +340,4 @@ DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size, Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI); Size = 3; return Result; -} +} \ No newline at end of file diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index d46ed47c1d0a1..d2c204a724cb0 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -249,6 +249,28 @@ void XtensaInstPrinter::printImm1_16_AsmOperand(const MCInst *MI, int OpNum, printOperand(MI, OpNum, O); } +void XtensaInstPrinter::printImm1n_15_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -1 && (Value != 0) && Value <= 15) && + "Invalid argument, value must be in ranges <-1,-1> or <1,15>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm32n_95_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -32 && Value <= 95) && + "Invalid argument, value must be in ranges <-32,95>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index befee7d3f564a..ec0fbf5e6d03b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -60,6 +60,8 @@ class XtensaInstPrinter : public MCInstPrinter { void printUimm5_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printShimm1_31_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm1_16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm1n_15_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm32n_95_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 1ef5b110c927e..7b8887e2059af 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -103,6 +103,14 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getImm1n_15OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm32n_95OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -254,6 +262,8 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, break; case Xtensa::S32I: case Xtensa::L32I: + case Xtensa::S32I_N: + case Xtensa::L32I_N: if (Res & 0x3) { report_fatal_error("Unexpected operand value!"); } @@ -261,7 +271,15 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, break; } - assert((isUInt<8>(Res)) && "Unexpected operand value!"); + switch (MI.getOpcode()) { + case Xtensa::S32I_N: + case Xtensa::L32I_N: + assert((isUInt<4>(Res)) && "Unexpected operand value!"); + break; + default: + assert((isUInt<8>(Res)) && "Unexpected operand value!"); + break; + } uint32_t OffBits = Res << 4; uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); @@ -353,6 +371,34 @@ XtensaMCCodeEmitter::getImm1_16OpValue(const MCInst &MI, unsigned OpNo, return (Res - 1); } +uint32_t +XtensaMCCodeEmitter::getImm1n_15OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = static_cast(MO.getImm()); + + assert(((Res >= -1) && (Res <= 15) && (Res != 0)) && + "Unexpected operand value!"); + + if (Res < 0) + Res = 0; + + return Res; +} + +uint32_t +XtensaMCCodeEmitter::getImm32n_95OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = static_cast(MO.getImm()); + + assert(((Res >= -32) && (Res <= 95)) && "Unexpected operand value!"); + + return Res; +} + uint32_t XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp index 57e722a4fe13f..fc4155ec54a1c 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp @@ -27,10 +27,11 @@ using namespace llvm; namespace { class XtensaDAGToDAGISel : public SelectionDAGISel { + const XtensaSubtarget *Subtarget; public: XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOpt::Level OptLevel) - : SelectionDAGISel(TM, OptLevel) {} + : SelectionDAGISel(TM, OptLevel), Subtarget(TM.getSubtargetImpl()) {} // Override MachineFunctionPass. StringRef getPassName() const override { diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 515e951513962..c394839481b03 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -1490,10 +1490,12 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( case Xtensa::S8I: case Xtensa::S16I: case Xtensa::S32I: + case Xtensa::S32I_N: case Xtensa::L8UI: case Xtensa::L16SI: case Xtensa::L16UI: - case Xtensa::L32I: { + case Xtensa::L32I: + case Xtensa::L32I_N: { const MachineMemOperand &MMO = **MI.memoperands_begin(); if (MMO.isVolatile()) { BuildMI(*MBB, MI, DL, TII.get(Xtensa::MEMW)); diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index d7f8fc1910d31..3089b87ef1da8 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -631,3 +631,71 @@ let usesCustomInserter = 1 in { "!select $dst, $lhs, $rhs, $t, $f, $cond", [(set AR:$dst, (Xtensa_select_cc AR:$lhs, AR:$rhs, AR:$t, AR:$f, imm:$cond))]>; } + +//===----------------------------------------------------------------------===// +// Code Density instructions +//===----------------------------------------------------------------------===// + +class ArithLogic_RRRN oper0, string instrAsm, + SDPatternOperator opNode, bit isComm = 0> + : RRRN_Inst, Requires<[HasDensity]> { + let isCommutable = isComm; + let isReMaterializable = 0; +} + +def ADD_N : ArithLogic_RRRN<0x0a, "add.n", add, 1>; + +def ADDI_N : RRRN_Inst<0x0B, (outs AR:$r), (ins AR:$s, imm1n_15:$imm), + "addi.n\t$r, $s, $imm", + [(set AR:$r, (add AR:$s, imm1n_15:$imm))]>, Requires<[HasDensity]> { + bits<4> imm; + + let t = imm; +} + +def MOV_N : RRRN_Inst<0x0D, (outs AR:$t), (ins AR:$s), + "mov.n\t$t, $s", []>, Requires<[HasDensity]> { + let r = 0; +} + +def : InstAlias<"mov\t $t, $s", (OR AR:$t, AR:$s, AR:$s)>; + +def MOVI_N : RI7_Inst<0xc, 0x0, (outs AR:$s), (ins imm32n_95:$imm7), + "movi.n\t$s, $imm7", + [(set AR:$s, imm32n_95:$imm7)]>, Requires<[HasDensity]>; + +// Load instruction +let mayLoad = 1, usesCustomInserter = 1 in { + def L32I_N : RRRN_Inst<0x8, (outs AR:$t), (ins mem32n:$addr), + "l32i.n\t$t, $addr", []>, Requires<[HasDensity]> { + bits<8> addr; + + let r{3-0} = addr{7-4}; + let s{3-0} = addr{3-0}; + } +} + +// Store instruction +let mayStore = 1, usesCustomInserter = 1 in { + def S32I_N : RRRN_Inst<0x9, (outs), (ins AR:$t, mem32n:$addr), + "s32i.n\t$t, $addr", []>, Requires<[HasDensity]> { + bits<8> addr; + + let r{3-0} = addr{7-4}; + let s{3-0} = addr{3-0}; + } +} + +//Return instruction +let isReturn = 1, isTerminator = 1, + isBarrier = 1, Uses = [A0] in { + def RET_N : RRRN_Inst<0x0D, (outs), (ins), + "ret.n", [(Xtensa_retflag)]>, + Requires<[HasDensity]> { + let r = 0x0F; + let s = 0; + let t = 0; + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 034aef55f7635..a1db366e2425f 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -72,6 +72,20 @@ def imm1_16 : Immediate= 1 && Imm <= 16; }], "Imm1_16_AsmOp let DecoderMethod = "decodeImm1_16Operand"; } +// imm1n_15 predicate - Immediate in the range [-1,15], except 0 +def Imm1n_15_AsmOperand: ImmAsmOperand<"Imm1n_15">; +def imm1n_15: Immediate= -1 && Imm <= 15 && Imm != 0; }], "Imm1n_15_AsmOperand"> { + let EncoderMethod = "getImm1n_15OpValue"; + let DecoderMethod = "decodeImm1n_15Operand"; +} + +// imm32n_95 predicate - Immediate in the range [-32,95] +def Imm32n_95_AsmOperand: ImmAsmOperand<"Imm32n_95">; +def imm32n_95: Immediate= -32 && Imm <= 95; }], "Imm32n_95_AsmOperand"> { + let EncoderMethod = "getImm32n_95OpValue"; + let DecoderMethod = "decodeImm32n_95Operand"; +} + // shimm1_31 predicate - Immediate in the range [1,31] def Shimm1_31_AsmOperand : ImmAsmOperand<"Shimm1_31">; def shimm1_31 : Immediate= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> { From c43de6ee91262ab9f293158842f50a4892893f2e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:55 +0300 Subject: [PATCH 032/150] [Xtensa] Add code size reduction pass. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + llvm/lib/Target/Xtensa/Xtensa.h | 1 + .../Target/Xtensa/XtensaSizeReductionPass.cpp | 253 ++++++++++++++++++ .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 5 +- 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 2208428f4c10c..1a3ff0c5311fe 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -24,6 +24,7 @@ add_llvm_target(XtensaCodeGen XtensaMachineFunctionInfo.cpp XtensaMCInstLower.cpp XtensaRegisterInfo.cpp + XtensaSizeReductionPass.cpp XtensaSubtarget.cpp XtensaTargetMachine.cpp diff --git a/llvm/lib/Target/Xtensa/Xtensa.h b/llvm/lib/Target/Xtensa/Xtensa.h index 43eadf88c7792..ee054d131f35d 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.h +++ b/llvm/lib/Target/Xtensa/Xtensa.h @@ -26,5 +26,6 @@ class FunctionPass; FunctionPass *createXtensaISelDag(XtensaTargetMachine &TM, CodeGenOpt::Level OptLevel); +FunctionPass *createXtensaSizeReductionPass(); } // namespace llvm #endif /* LLVM_LIB_TARGET_XTENSA_XTENSA_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp b/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp new file mode 100644 index 0000000000000..f69c1e601a788 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp @@ -0,0 +1,253 @@ +//===- XtensaSizeReductionPass.cpp - Xtensa Size Reduction ----------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "XtensaInstrInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen//MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-size-reduce-pass" + +STATISTIC(NumReduced, "Number of 24-bit instructions reduced to 16-bit ones"); + +class XtensaSizeReduce : public MachineFunctionPass { +public: + static char ID; + XtensaSizeReduce() : MachineFunctionPass(ID) {} + + const XtensaSubtarget *Subtarget; + static const XtensaInstrInfo *XtensaII; + + bool runOnMachineFunction(MachineFunction &MF) override; + + llvm::StringRef getPassName() const override { + return "Xtensa instruction size reduction pass"; + } + +private: + /// Reduces width of instructions in the specified basic block. + bool ReduceMBB(MachineBasicBlock &MBB); + + /// Attempts to reduce MI, returns true on success. + bool ReduceMI(const MachineBasicBlock::instr_iterator &MII); +}; + +char XtensaSizeReduce::ID = 0; +const XtensaInstrInfo *XtensaSizeReduce::XtensaII; + +bool XtensaSizeReduce::ReduceMI(const MachineBasicBlock::instr_iterator &MII) { + MachineInstr *MI = &*MII; + MachineBasicBlock &MBB = *MI->getParent(); + unsigned Opcode = MI->getOpcode(); + + switch (Opcode) { + case Xtensa::L32I: { + MachineOperand Op0 = MI->getOperand(0); + MachineOperand Op1 = MI->getOperand(1); + MachineOperand Op2 = MI->getOperand(2); + + int64_t Imm = Op2.getImm(); + if (Imm >= 0 && Imm <= 60) { + // Replace L32I to L32I.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::L32I_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + MIB.add(Op0); + MIB.add(Op1); + MIB.add(Op2); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } + } break; + + case Xtensa::S32I: { + MachineOperand Op0 = MI->getOperand(0); + MachineOperand Op1 = MI->getOperand(1); + MachineOperand Op2 = MI->getOperand(2); + + int64_t Imm = Op2.getImm(); + if (Imm >= 0 && Imm <= 60) { + // Replace S32I to S32I.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::S32I_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + MIB.add(Op0); + MIB.add(Op1); + MIB.add(Op2); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } + + } break; + + case Xtensa::MOVI: { + MachineOperand Op0 = MI->getOperand(0); + MachineOperand Op1 = MI->getOperand(1); + + int64_t Imm = Op1.getImm(); + if (Imm >= -32 && Imm <= 95) { + // Replace MOVI to MOVI.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MOVI_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + MIB.add(Op0); + MIB.add(Op1); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } + + } break; + + case Xtensa::ADD: { + MachineOperand Op0 = MI->getOperand(0); + MachineOperand Op1 = MI->getOperand(1); + MachineOperand Op2 = MI->getOperand(2); + + // Replace ADD to ADD.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::ADD_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + MIB.add(Op0); + MIB.add(Op1); + MIB.add(Op2); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + + } break; + + case Xtensa::ADDI: { + MachineOperand Op0 = MI->getOperand(0); + MachineOperand Op1 = MI->getOperand(1); + MachineOperand Op2 = MI->getOperand(2); + + int64_t Imm = Op2.getImm(); + if ((Imm >= 1 && Imm <= 15) || (Imm == -1)) { + // Replace ADDI to ADDI.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::ADDI_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + MIB.add(Op0); + MIB.add(Op1); + MIB.add(Op2); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } + } break; + + case Xtensa::OR: { + MachineOperand Op0 = MI->getOperand(0); + MachineOperand Op1 = MI->getOperand(1); + MachineOperand Op2 = MI->getOperand(2); + + if (Op1.getReg() != Op2.getReg()) + break; + + // Replace OR R1, R2, R2 to MOV.N R1, R2 + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MOV_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + MIB.add(Op0); + MIB.add(Op1); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } break; + + case Xtensa::RET: { + // Replace RET to RET.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::RET_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } break; + + default: + break; + } + + return false; +} + +bool XtensaSizeReduce::ReduceMBB(MachineBasicBlock &MBB) { + bool Modified = false; + MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), + E = MBB.instr_end(); + MachineBasicBlock::instr_iterator NextMII; + + // Iterate through the instructions in the basic block + for (; MII != E; MII = NextMII) { + NextMII = std::next(MII); + MachineInstr *MI = &*MII; + + // Don't reduce bundled instructions or pseudo operations + if (MI->isBundle() || MI->isTransient()) + continue; + + // Try to reduce 24-bit instruction into 16-bit instruction + Modified |= ReduceMI(MII); + } + + return Modified; +} + +bool XtensaSizeReduce::runOnMachineFunction(MachineFunction &MF) { + + Subtarget = &static_cast(MF.getSubtarget()); + XtensaII = static_cast(Subtarget->getInstrInfo()); + bool Modified = false; + + if (!Subtarget->hasDensity()) + return Modified; + + MachineFunction::iterator I = MF.begin(), E = MF.end(); + + for (; I != E; ++I) + Modified |= ReduceMBB(*I); + return Modified; +} + +FunctionPass *llvm::createXtensaSizeReductionPass() { + return new XtensaSizeReduce(); +} diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index fa8352cde8dbc..8740b31216ec4 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -92,7 +92,10 @@ bool XtensaPassConfig::addInstSelector() { return false; } -void XtensaPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } +void XtensaPassConfig::addPreEmitPass() { + addPass(createXtensaSizeReductionPass()); + addPass(&BranchRelaxationPassID); +} TargetPassConfig *XtensaTargetMachine::createPassConfig(PassManagerBase &PM) { return new XtensaPassConfig(*this, PM); From 5a84826f12082769c6dccd01301485371d04b75b Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:56 +0300 Subject: [PATCH 033/150] [Xtensa] Implement Windowed feature operations --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 16 +++ .../Disassembler/XtensaDisassembler.cpp | 29 +++- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 34 +++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 3 + .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 52 +++++++ llvm/lib/Target/Xtensa/Xtensa.td | 5 + llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 3 + llvm/lib/Target/Xtensa/XtensaISelLowering.h | 6 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 135 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 21 +++ llvm/lib/Target/Xtensa/XtensaOperators.td | 10 +- llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 6 +- .../Target/Xtensa/XtensaSizeReductionPass.cpp | 15 +- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 7 + 15 files changed, 339 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 37107e32bb5ab..22fdf6ac652d5 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -167,6 +167,8 @@ struct XtensaOperand : public MCParsedAsmOperand { ((dyn_cast(getImm())->getValue() & 0x3) == 0); } + bool isentry_imm12() const { return isImm(0, 32760); } + bool isUimm4() const { return isImm(0, 15); } bool isUimm5() const { return isImm(0, 31); } @@ -183,6 +185,11 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm32n_95() const { return isImm(-32, 95); } + bool isImm64n_4n() const { + return isImm(-64, -4) && + ((dyn_cast(getImm())->getValue() & 0x3) == 0); + } + bool isB4const() const { if (Kind != Immediate) return false; @@ -412,6 +419,12 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidImm32n_95: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-32, 95] except 0"); + case Match_InvalidImm64n_4n: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-64, -4]"); + case Match_InvalidImm8n_7: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-8, 7]"); case Match_InvalidShimm1_31: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [1, 31]"); @@ -436,6 +449,9 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [0, 60], first 2 bits " "should be zero"); + case Match_Invalidentry_imm12: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 32760]"); } report_fatal_error("Unknown match type detected!"); diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index 4b9aecedee3f4..ffd71ddb6a22d 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -74,7 +74,8 @@ static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Success; } -static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3}; +static const unsigned SRDecoderTable[] = { + Xtensa::SAR, 3, Xtensa::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73}; static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, @@ -211,6 +212,32 @@ static DecodeStatus decodeImm32n_95Operand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeImm8n_7Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + if (Imm > 7) + Inst.addOperand(MCOperand::createImm(Imm - 16)); + else + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm64n_4nOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm((~0x3f) | (Imm << 2))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeEntry_Imm12OpValue(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm << 3)); + return MCDisassembler::Success; +} + static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index d2c204a724cb0..489e4eba2d258 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -271,6 +271,28 @@ void XtensaInstPrinter::printImm32n_95_AsmOperand(const MCInst *MI, int OpNum, printOperand(MI, OpNum, O); } +void XtensaInstPrinter::printImm8n_7_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -8 && Value <= 7) && + "Invalid argument, value must be in ranges <-8,7>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm64n_4n_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -64 && Value <= -4) & ((Value & 0x3) == 0) && + "Invalid argument, value must be in ranges <-64,-4>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { @@ -316,6 +338,18 @@ void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, printOperand(MI, OpNum, O); } +void XtensaInstPrinter::printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 32760) && + "Invalid argument, value must be multiples of eight in range " + "<0,32760>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + void XtensaInstPrinter::printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index ec0fbf5e6d03b..b4f75f0b9c016 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -62,10 +62,13 @@ class XtensaInstPrinter : public MCInstPrinter { void printImm1_16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm1n_15_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm32n_95_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm8n_7_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm64n_4n_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 7b8887e2059af..d5b61985d09da 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -111,6 +111,18 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getImm8n_7OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm64n_4nOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getEntry_Imm12OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -399,6 +411,46 @@ XtensaMCCodeEmitter::getImm32n_95OpValue(const MCInst &MI, unsigned OpNo, return Res; } +uint32_t +XtensaMCCodeEmitter::getImm8n_7OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = static_cast(MO.getImm()); + + assert(((Res >= -8) && (Res <= 7)) && "Unexpected operand value!"); + + if (Res < 0) + return Res + 16; + + return Res; +} + +uint32_t +XtensaMCCodeEmitter::getImm64n_4nOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = static_cast(MO.getImm()); + + assert(((Res >= -64) && (Res <= -4) && ((Res & 0x3) == 0)) && + "Unexpected operand value!"); + + return Res & 0x3f; +} + +uint32_t +XtensaMCCodeEmitter::getEntry_Imm12OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t res = static_cast(MO.getImm()); + + assert(((res & 0x7) == 0) && "Unexpected operand value!"); + + return res; +} + uint32_t XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index db18be02b192c..29b2164b398df 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -21,6 +21,11 @@ def FeatureDensity : SubtargetFeature<"density", "HasDensity", "true", "Enable Density instructions">; def HasDensity : Predicate<"Subtarget->hasDensity()">, AssemblerPredicate<(all_of FeatureDensity)>; + +def FeatureWindowed : SubtargetFeature<"windowed", "HasWindowed", "true", + "Enable Xtensa Windowed Register option">; +def HasWindowed : Predicate<"Subtarget->hasWindowed()">, + AssemblerPredicate<(all_of FeatureWindowed)>; //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index c394839481b03..41f2c2978b1b1 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -1285,11 +1285,14 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { return "XtensaISD::" #NAME switch (Opcode) { OPCODE(RET_FLAG); + OPCODE(RETW_FLAG); OPCODE(CALL); + OPCODE(CALLW); OPCODE(PCREL_WRAPPER); OPCODE(SELECT); OPCODE(SELECT_CC); OPCODE(BR_JT); + OPCODE(MOVSP); OPCODE(SHL); OPCODE(SRA); OPCODE(SRL); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index cc811c435c8aa..562d59abf64d0 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -31,6 +31,10 @@ enum { // is the target address. The arguments start at operand 2. // There is an optional glue operand at the end. CALL, + // WinABI Call version + CALLW, + + MOVSP, // Wraps a TargetGlobalAddress that should be loaded using PC-relative // accesses. Operand 0 is the address. @@ -38,6 +42,8 @@ enum { // Return with a flag operand. Operand 0 is the chain operand. RET_FLAG, + // WinABI Return + RETW_FLAG, // Selects between operand 0 and operand 1. Operand 2 is the // mask of condition-code values for which operand 0 should be diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 3089b87ef1da8..cd65344318a1f 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -699,3 +699,138 @@ let isReturn = 1, isTerminator = 1, let t = 0; } } + +//===----------------------------------------------------------------------===// +// Windowed instructions +//===----------------------------------------------------------------------===// + +def ENTRY : BRI12_Inst<0x06, 0x3, 0x0, (outs), (ins AR:$s, entry_imm12:$imm), + "entry\t$s, $imm", []>, Requires<[HasWindowed]> { + bits<15> imm; + + let imm12{11-0} = imm{14-3}; + let Defs = [SP]; +} + +//Call instructions +let isCall = 1, Defs = [A0] in { + def CALL4 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset), + "call4\t$offset", []>, Requires<[HasWindowed]> { + let n = 1; + } + + def CALL8 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset), + "call8\t$offset", []>, Requires<[HasWindowed]> { + let n = 2; + } + + def CALL12 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset), + "call12\t$offset", []>, Requires<[HasWindowed]> { + let n = 3; + } + + def CALLX4 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s), + "callx4\t$s", []>, Requires<[HasWindowed]> { + let m = 0x3; + let n = 0x1; + let r = 0; + } + + def CALLX8 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s), + "callx8\t$s", []>, Requires<[HasWindowed]> { + let m = 0x3; + let n = 0x2; + let r = 0; + } + + def CALLX12 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s), + "callx12\t$s", []>, Requires<[HasWindowed]> { + let m = 0x3; + let n = 0x3; + let r = 0; + } +} + +//Windowed call patterns +def : Pat<(Xtensa_callw (i32 tglobaladdr:$dst)), + (CALL8 tglobaladdr:$dst)>; +def : Pat<(Xtensa_callw (i32 texternalsym:$dst)), + (CALL8 texternalsym:$dst)>; +def : Pat<(Xtensa_callw AR:$dst), + (CALLX8 AR:$dst)>; + +def MOVSP : RRR_Inst<0x00, 0x00, 0x00, (outs AR:$t), (ins AR:$s), + "movsp\t$t, $s", + [(set AR:$t, (Xtensa_movsp AR:$s))]>, + Requires<[HasWindowed]> { + let r = 0x01; +} + +//Return instructions +let isReturn = 1, isTerminator = 1, + isBarrier = 1, Uses = [A0] in { + def RETW_N : RRRN_Inst<0x0D, (outs), (ins), + "retw.n", [(Xtensa_retWflag)]>, + Requires<[HasWindowed, HasDensity]> { + let r = 0x0F; + let s = 0; + let t = 1; + } + + def RETW : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins), + "retw", [(Xtensa_retWflag)]>, + Requires<[HasWindowed]> { + let m = 0x2; + let n = 0x1; + let s = 0; + let r = 0; + } +} + +//Store 32-bit for Window Exceptions +def S32E : RRI4_Inst<0x00, 0x09, (outs), (ins AR:$t, AR:$s, imm64n_4n:$imm), + "s32e\t$t, $s, $imm", []>, Requires<[HasWindowed]> { + bits<6> imm; + + let r = imm{5-2}; + let imm4 = 0x4; + let mayStore = 1; +} + +def L32E : RRI4_Inst<0x00, 0x09, (outs), (ins AR:$t, AR:$s, imm64n_4n:$imm), + "l32e\t$t, $s, $imm", []>, Requires<[HasWindowed]> { + bits<6> imm; + + let r = imm{5-2}; + let imm4 = 0x0; + let mayLoad = 1; +} + +//Return from window +def RFWU : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "rfwu", []>, Requires<[HasWindowed]> { + bits<4> imm; + + let r = 0x3; + let s = 0x5; + let t = 0x0; +} + +def RFWO : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "rfwo", []>, Requires<[HasWindowed]> { + bits<4> imm; + + let r = 0x3; + let s = 0x4; + let t = 0x0; +} + +//Rotate window +def ROTW : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins imm8n_7:$imm), + "rotw\t$imm", []>, Requires<[HasWindowed]> { + bits<4> imm; + + let r = 0x8; + let s = 0x0; + let t = imm{3-0}; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index a1db366e2425f..47946596282ad 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -37,6 +37,20 @@ def imm8_sh8 : Immediate= -32768 && Imm <= 32512 && ((Imm & let DecoderMethod = "decodeImm8_sh8Operand"; } +// imm8n_7 predicate - Immediate in the range [-8,7] +def Imm8n_7_AsmOperand: ImmAsmOperand<"Imm8n_7">; +def imm8n_7: Immediate= -8 && Imm <= 7; }], "Imm8n_7_AsmOperand"> { + let EncoderMethod = "getImm8n_7OpValue"; + let DecoderMethod = "decodeImm8n_7Operand"; +} + +// imm64n_4n predicate - Immediate in the range [-64,-4] +def Imm64n_4n_AsmOperand: ImmAsmOperand<"Imm64n_4n">; +def imm64n_4n: Immediate= -64 && Imm <= -4; }], "Imm64n_4n_AsmOperand"> { + let EncoderMethod = "getImm64n_4nOpValue"; + let DecoderMethod = "decodeImm64n_4nOperand"; +} + // imm12 predicate - Immediate in the range [-2048,2047] def Imm12_AsmOperand : ImmAsmOperand<"Imm12">; def imm12 : Immediate= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> { @@ -117,6 +131,13 @@ def offset4m32 : Immediate= 0 && Imm <= 60 && (Imm & 0x3 == 0); }], "Offset4m32_AsmOperand">; +// entry_imm12 predicate - Immediate in the range [0,32760], ENTRY parameter +def Entry_Imm12_AsmOperand: ImmAsmOperand<"entry_imm12">; +def entry_imm12: Immediate= 0 && Imm <= 32760 && (Imm & 0x3 == 0); }], "Entry_Imm12_AsmOperand"> { + let EncoderMethod = "getEntry_Imm12OpValue"; + let DecoderMethod = "decodeEntry_Imm12OpValue"; +} + // b4const predicate - Branch Immediate 4-bit signed operand def B4const_AsmOperand: ImmAsmOperand<"B4const">; def b4const: Immediate, SDTCisSameAs<2, 3>, SDTCisVT<5, i32>]>; + +def SDT_XtensaMOVSP : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>; def SDT_XtensaBrJT : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; @@ -43,7 +45,8 @@ def Xtensa_call: SDNode<"XtensaISD::CALL", SDT_XtensaCall, def Xtensa_retflag: SDNode<"XtensaISD::RET_FLAG", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; - +def Xtensa_retWflag: SDNode<"XtensaISD::RETW_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def Xtensa_callseq_start: SDNode<"ISD::CALLSEQ_START", SDT_XtensaCallSeqStart, [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; @@ -57,6 +60,9 @@ def Xtensa_select : SDNode<"XtensaISD::SELECT", SDTSelect>; def Xtensa_select_cc: SDNode<"XtensaISD::SELECT_CC", SDT_XtensaSelectCC, [SDNPInGlue]>; +def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP, + [SDNPInGlue]>; + def Xtensa_shl: SDNode<"XtensaISD::SHL", SDT_XtensaSHL, [SDNPInGlue]>; def Xtensa_sra: SDNode<"XtensaISD::SRA", SDT_XtensaSRA, [SDNPInGlue]>; def Xtensa_srl: SDNode<"XtensaISD::SRL", SDT_XtensaSRL, [SDNPInGlue]>; @@ -65,3 +71,5 @@ def Xtensa_ssl: SDNode<"XtensaISD::SSL", SDT_XtensaSSL, [SDNPOutGlue]>; def Xtensa_ssr: SDNode<"XtensaISD::SSR", SDT_XtensaSSR, [SDNPOutGlue]>; def Xtensa_brjt: SDNode<"XtensaISD::BR_JT", SDT_XtensaBrJT, [SDNPHasChain]>; +def Xtensa_callw: SDNode<"XtensaISD::CALLW", SDT_XtensaCall, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 5c07386b060cd..9939d19ef1907 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -75,4 +75,8 @@ class SRReg num, string n, list alt = []> : XtensaReg { // Shift Amount Register def SAR : SRReg<3, "sar", ["SAR","3"]>; -def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR)>; +def WINDOWBASE : SRReg<72, "windowbase", ["WINDOWBASE", "72"]>; +def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>; + +def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR, + WINDOWBASE, WINDOWSTART)>; diff --git a/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp b/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp index f69c1e601a788..1377d7fccf1e0 100644 --- a/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSizeReductionPass.cpp @@ -173,7 +173,7 @@ bool XtensaSizeReduce::ReduceMI(const MachineBasicBlock::instr_iterator &MII) { MachineOperand Op1 = MI->getOperand(1); MachineOperand Op2 = MI->getOperand(2); - if (Op1.getReg() != Op2.getReg()) + if (Op1.getReg() != Op2.getReg()) break; // Replace OR R1, R2, R2 to MOV.N R1, R2 @@ -203,6 +203,19 @@ bool XtensaSizeReduce::ReduceMI(const MachineBasicBlock::instr_iterator &MII) { return true; } break; + case Xtensa::RETW: { + // Replace RETW to RETW.N + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::RETW_N); + MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID); + // Transfer MI flags. + MIB.setMIFlags(MI->getFlags()); + LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB); + NumReduced++; + MBB.erase_instr(MI); + return true; + } break; + default: break; } diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index f76af66cac1ef..fe47de0f95271 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -33,6 +33,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { } HasDensity = false; + HasWindowed = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index 476f1f943a9ea..aea0a9ed9b452 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -41,6 +41,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enabled Xtensa Density extension bool HasDensity; + // Enabled Xtensa Windowed Register option + bool HasWindowed; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -56,8 +59,12 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { const XtensaTargetLowering *getTargetLowering() const override { return &TLInfo; } const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { return &TSInfo; } + bool isWinABI() const { return hasWindowed(); } + bool hasDensity() const { return HasDensity; } + bool hasWindowed() const { return HasWindowed; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; From 839062e865c825b571283c7d9a56002af36f56e1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:56 +0300 Subject: [PATCH 034/150] [Xtensa] Implement Windowed Call ABI --- llvm/lib/Target/Xtensa/XtensaCallingConv.td | 14 ++ .../lib/Target/Xtensa/XtensaFrameLowering.cpp | 167 +++++++++++++----- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 58 +++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 10 +- llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 13 +- 5 files changed, 203 insertions(+), 59 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td index c39eb665b4d33..adfb8656b32d3 100644 --- a/llvm/lib/Target/Xtensa/XtensaCallingConv.td +++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td @@ -32,3 +32,17 @@ def RetCC_Xtensa : CallingConv<[ //===----------------------------------------------------------------------===// def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>; +def CSRWE_Xtensa : CalleeSavedRegs<(add)> { + let OtherPreserved = (add A0, SP, A2, A3, A4, A5, A6, A7); +} +//===----------------------------------------------------------------------===// + +def RetCCW_Xtensa : CallingConv<[ + CCIfType<[i1, i8, i16], CCPromoteToType>, + CCIfType<[f32], CCBitConvertToType>, + + //First two return values go in a10, a11, a12, a13 + CCIfType<[i32], CCAssignToReg<[A10, A11, A12, A13]>>, + CCIfType<[f32], CCAssignToReg<[A10, A11, A12, A13]>>, + CCIfType<[i64], CCAssignToRegWithShadow<[A10, A12], [A11, A13]>> +]>; diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index ca2c806ef8a7f..b7c9cb161fdad 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -79,6 +79,12 @@ bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const { MFI.hasVarSizedObjects(); } +/* minimum frame = reg save area (4 words) plus static chain (1 word) + and the total number of words must be a multiple of 128 bits. */ +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 +#define MIN_FRAME_SIZE (8 * UNITS_PER_WORD) + void XtensaFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented"); @@ -88,6 +94,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF, const XtensaInstrInfo &TII = *static_cast(MF.getSubtarget().getInstrInfo()); MachineBasicBlock::iterator MBBI = MBB.begin(); + const XtensaSubtarget &STI = MF.getSubtarget(); DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); unsigned SP = Xtensa::SP; unsigned FP = RegInfo->getFrameRegister(MF); @@ -101,53 +108,105 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF, // Round up StackSize to 16*N StackSize += (16 - StackSize) & 0xf; - // No need to allocate space on the stack. - if (StackSize == 0 && !MFI.adjustsStack()) - return; + if (STI.isWinABI()) { + StackSize += 32; + + if (StackSize <= 32760) { + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::ENTRY)) + .addReg(SP) + .addImm(StackSize); + } else { + /* Use a8 as a temporary since a0-a7 may be live. */ + unsigned TmpReg = Xtensa::A8; + + const XtensaInstrInfo &TII = *static_cast( + MBB.getParent()->getSubtarget().getInstrInfo()); + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::ENTRY)) + .addReg(SP) + .addImm(MIN_FRAME_SIZE); + TII.loadImmediate(MBB, MBBI, &TmpReg, StackSize - MIN_FRAME_SIZE); + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::SUB), TmpReg) + .addReg(SP) + .addReg(TmpReg); + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::MOVSP), SP).addReg(TmpReg); + } - // Adjust stack. - TII.adjustStackPtr(SP, -StackSize, MBB, MBBI); - - // emit ".cfi_def_cfa_offset StackSize" - unsigned CFIIndex = MF.addFrameInst( - MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); - BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - - const std::vector &CSI = MFI.getCalleeSavedInfo(); - - if (CSI.size()) { - // Find the instruction past the last instruction that saves a - // callee-saved register to the stack. - for (unsigned i = 0; i < CSI.size(); ++i) - ++MBBI; - - // Iterate over list of callee-saved registers and emit .cfi_offset - // directives. - for (const auto &I : CSI) { - int64_t Offset = MFI.getObjectOffset(I.getFrameIdx()); - unsigned Reg = I.getReg(); - - unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( - nullptr, MRI->getDwarfRegNum(Reg, 1), Offset)); + // Store FP register in A8, because FP may be used to pass function + // arguments + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), Xtensa::A8) + .addReg(FP) + .addReg(FP); + + // if framepointer enabled, set it to point to the stack pointer. + if (hasFP(MF)) { + // Insert instruction "move $fp, $sp" at this location. + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), FP) + .addReg(SP) + .addReg(SP) + .setMIFlag(MachineInstr::FrameSetup); + + MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa( + nullptr, MRI->getDwarfRegNum(FP, true), StackSize); + unsigned CFIIndex = MF.addFrameInst(Inst); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } else { + // emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } - } + } else { + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI.adjustsStack()) + return; - // if framepointer enabled, set it to point to the stack pointer. - if (hasFP(MF)) { - // Insert instruction "move $fp, $sp" at this location. - BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), FP) - .addReg(SP) - .addReg(SP) - .setMIFlag(MachineInstr::FrameSetup); - - // emit ".cfi_def_cfa_register $fp" - unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( - nullptr, MRI->getDwarfRegNum(FP, true))); + // Adjust stack. + TII.adjustStackPtr(SP, -StackSize, MBB, MBBI); + + // emit ".cfi_def_cfa_offset StackSize" + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize)); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); + + const std::vector &CSI = MFI.getCalleeSavedInfo(); + + if (CSI.size()) { + // Find the instruction past the last instruction that saves a + // callee-saved register to the stack. + for (unsigned i = 0; i < CSI.size(); ++i) + ++MBBI; + + // Iterate over list of callee-saved registers and emit .cfi_offset + // directives. + for (const auto &I : CSI) { + int64_t Offset = MFI.getObjectOffset(I.getFrameIdx()); + unsigned Reg = I.getReg(); + + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( + nullptr, MRI->getDwarfRegNum(Reg, 1), Offset)); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + + // if framepointer enabled, set it to point to the stack pointer. + if (hasFP(MF)) { + // Insert instruction "move $fp, $sp" at this location. + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), FP) + .addReg(SP) + .addReg(SP) + .setMIFlag(MachineInstr::FrameSetup); + + // emit ".cfi_def_cfa_register $fp" + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( + nullptr, MRI->getDwarfRegNum(FP, true))); + BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } } if (StackSize != PrevStackSize) { @@ -172,6 +231,7 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, MF.getSubtarget().getRegisterInfo()); const XtensaInstrInfo &TII = *static_cast(MF.getSubtarget().getInstrInfo()); + const XtensaSubtarget &STI = MF.getSubtarget(); DebugLoc dl = MBBI->getDebugLoc(); unsigned SP = Xtensa::SP; unsigned FP = RegInfo->getFrameRegister(MF); @@ -183,10 +243,17 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, for (unsigned i = 0; i < MFI.getCalleeSavedInfo().size(); ++i) --I; - - BuildMI(MBB, I, dl, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP); + if (STI.isWinABI()) { + // Insert instruction "movsp $sp, $fp" at this location. + BuildMI(MBB, I, dl, TII.get(Xtensa::MOVSP), SP).addReg(FP); + } else { + BuildMI(MBB, I, dl, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP); + } } + if (STI.isWinABI()) + return; + // Get the number of bytes from FrameInfo uint64_t StackSize = MFI.getStackSize(); @@ -201,6 +268,10 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef CSI, const TargetRegisterInfo *TRI) const { MachineFunction *MF = MBB.getParent(); + const XtensaSubtarget &STI = MF->getSubtarget(); + + if (STI.isWinABI()) + return true; MachineBasicBlock &EntryBlock = *(MF->begin()); const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); @@ -229,8 +300,11 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters( bool XtensaFrameLowering::restoreCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, - MutableArrayRef CSI, - const TargetRegisterInfo *TRI) const { + MutableArrayRef CSI, const TargetRegisterInfo *TRI) const { + MachineFunction *MF = MBB.getParent(); + const XtensaSubtarget &STI = MF->getSubtarget(); + if (STI.isWinABI()) + return true; return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI); } @@ -257,11 +331,16 @@ MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr( void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const { + const XtensaSubtarget &STI = MF.getSubtarget(); MachineFrameInfo &MFI = MF.getFrameInfo(); const XtensaRegisterInfo *RegInfo = static_cast( MF.getSubtarget().getRegisterInfo()); unsigned FP = RegInfo->getFrameRegister(MF); + if (STI.isWinABI()) { + return; + } + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); // Mark $fp as used if function has dedicated frame pointer. diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 41f2c2978b1b1..5901bcd4b1823 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -43,6 +43,15 @@ static bool isLongCall(const char *str) { return true; } +// The calling conventions in XtensaCallingConv.td are described in terms of the +// callee's register window. This function translates registers to the +// corresponding caller window %o register. +static unsigned toCallerWindow(unsigned Reg) { + if (Reg >= Xtensa::A2 && Reg <= Xtensa::A7) + return Reg - Xtensa::A2 + Xtensa::A10; + return Reg; +} + XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, const XtensaSubtarget &STI) : TargetLowering(tm), Subtarget(STI) { @@ -428,7 +437,17 @@ SDValue XtensaTargetLowering::LowerFormalArguments( // Transform the arguments stored on // physical registers into virtual ones - unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); + unsigned Reg = 0; + unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); + + // Argument passed in FrameReg in WinABI we save in A8 (in emitPrologue), + // so load argument from A8 + if (Subtarget.isWinABI() && (VA.getLocReg() == FrameReg)) { + Reg = MF.addLiveIn(Xtensa::A8, RC); + } else { + Reg = MF.addLiveIn(VA.getLocReg(), RC); + } + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT); // If this is an 8 or 16-bit value, it has been passed promoted @@ -646,6 +665,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, SDValue Glue; for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { unsigned Reg = RegsToPass[I].first; + if (Subtarget.isWinABI()) + Reg = toCallerWindow(Reg); Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue); Glue = Chain.getValue(1); } @@ -702,6 +723,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, // known live into the call. for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { unsigned Reg = RegsToPass[I].first; + if (Subtarget.isWinABI()) + Reg = toCallerWindow(Reg); Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType())); } @@ -710,7 +733,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, Ops.push_back(Glue); SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); - Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops); + Chain = DAG.getNode(Subtarget.isWinABI() ? XtensaISD::CALLW : XtensaISD::CALL, + DL, NodeTys, Ops); Glue = Chain.getValue(1); // Mark the end of the call, which is glued to the call itself. @@ -721,7 +745,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, // Assign locations to each value returned by this call. SmallVector RetLocs; CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext()); - RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa); + RetCCInfo.AnalyzeCallResult(Ins, Subtarget.isWinABI() ? RetCCW_Xtensa + : RetCC_Xtensa); // Copy all of the result registers out of their specified physreg. for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { @@ -764,7 +789,9 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, SDValue Glue; // Quick exit for void returns if (RetLocs.empty()) - return DAG.getNode(XtensaISD::RET_FLAG, DL, MVT::Other, Chain); + return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW_FLAG + : XtensaISD::RET_FLAG, + DL, MVT::Other, Chain); // Copy the result values into the output registers. SmallVector RetOps; @@ -791,7 +818,9 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, if (Glue.getNode()) RetOps.push_back(Glue); - return DAG.getNode(XtensaISD::RET_FLAG, DL, MVT::Other, RetOps); + return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW_FLAG + : XtensaISD::RET_FLAG, + DL, MVT::Other, RetOps); } SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op, @@ -906,14 +935,14 @@ SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op, const GlobalValue *GV = G->getGlobal(); // Check Op SDNode users - // If there are only CALL nodes, don't expand Global Address + // If there are only CALL/CALLW nodes, don't expand Global Address SDNode &OpNode = *Op.getNode(); bool Val = false; for (SDNode::use_iterator UI = OpNode.use_begin(); UI != OpNode.use_end(); ++UI) { SDNode &User = *UI.getUse().getUser(); unsigned OpCode = User.getOpcode(); - if (OpCode != XtensaISD::CALL) { + if (OpCode != XtensaISD::CALL && OpCode != XtensaISD::CALLW) { Val = true; break; } @@ -1014,7 +1043,13 @@ SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op, SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const { unsigned sp = Xtensa::SP; - return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), sp, Op.getOperand(1)); + if (Subtarget.isWinABI()) { + SDValue NewSP = + DAG.getNode(XtensaISD::MOVSP, SDLoc(Op), MVT::i32, Op.getOperand(1)); + return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), sp, NewSP); + } else { + return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), sp, Op.getOperand(1)); + } } SDValue XtensaTargetLowering::LowerFRAMEADDR(SDValue Op, @@ -1050,7 +1085,12 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, unsigned SPReg = Xtensa::SP; SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT); SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value - Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain + if (Subtarget.isWinABI()) { + SDValue NewSP1 = DAG.getNode(XtensaISD::MOVSP, DL, MVT::i32, NewSP); + Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP1); // Output chain + } else { + Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain + } SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32); Chain = NewVal.getValue(1); diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 387f96b8c9e67..e6ec0a7fe4aa0 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -75,9 +75,13 @@ void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, .addReg(Reg1, RegState::Kill); } - BuildMI(MBB, I, DL, get(Xtensa::OR), SP) - .addReg(Reg, RegState::Kill) - .addReg(Reg, RegState::Kill); + if (STI.isWinABI()) { + BuildMI(MBB, I, DL, get(Xtensa::MOVSP), SP).addReg(Reg, RegState::Kill); + } else { + BuildMI(MBB, I, DL, get(Xtensa::OR), SP) + .addReg(Reg, RegState::Kill) + .addReg(Reg, RegState::Kill); + } } void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp index 198517a75451f..8f773458583ed 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -34,13 +34,19 @@ XtensaRegisterInfo::XtensaRegisterInfo(const XtensaSubtarget &STI) const uint16_t * XtensaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { - return CSR_Xtensa_SaveList; + if (Subtarget.isWinABI()) + return CSRWE_Xtensa_SaveList; + else + return CSR_Xtensa_SaveList; } const uint32_t * XtensaRegisterInfo::getCallPreservedMask(const MachineFunction &MF, CallingConv::ID) const { - return CSR_Xtensa_RegMask; + if (Subtarget.isWinABI()) + return CSRWE_Xtensa_RegMask; + else + return CSR_Xtensa_RegMask; } BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const { @@ -172,5 +178,6 @@ void XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); - return TFI->hasFP(MF) ? (Xtensa::A15) : Xtensa::SP; + return TFI->hasFP(MF) ? (Subtarget.isWinABI() ? Xtensa::A7 : Xtensa::A15) + : Xtensa::SP; } From 21fb40a19e9842656fda0e5151425e9fa9fba6d4 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:56 +0300 Subject: [PATCH 035/150] [Xtensa] Reserve an emergency spill slot for scavenger. Reserve an emergency spill slot for the register scavenger when Windowed Call ABI is used. --- llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp | 16 ++++++++++++++++ llvm/lib/Target/Xtensa/XtensaFrameLowering.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index b7c9cb161fdad..b8c6cadf700d8 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -360,3 +360,19 @@ void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF, int FI = MF.getFrameInfo().CreateStackObject(Size, Alignment, false); RS->addScavengingFrameIndex(FI); } + +void XtensaFrameLowering::processFunctionBeforeFrameFinalized( + MachineFunction &MF, RegScavenger *RS) const { + const XtensaSubtarget &STI = MF.getSubtarget(); + + // In WinABI mode add register scavenging slot + // FIXME: It may be posssible to add spill slot by more optimal way + if (STI.isWinABI() && (MF.getFrameInfo().estimateStackSize(MF) > 256)) { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const TargetRegisterClass &RC = Xtensa::ARRegClass; + const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); + unsigned Size = TRI.getSpillSize(RC); + Align Alignment = TRI.getSpillAlign(RC); + RS->addScavengingFrameIndex(MFI.CreateStackObject(Size, Alignment, false)); + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h index b112f069cd618..8eb44c4932660 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h @@ -44,6 +44,9 @@ class XtensaFrameLowering : public TargetFrameLowering { void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS) const override; }; } // namespace llvm From 456e445f077660afecdbf8ca94138d50152a0c94 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:57 +0300 Subject: [PATCH 036/150] [Xtensa] Implement Boolean feature operations --- .../Disassembler/XtensaDisassembler.cpp | 25 +++++-- llvm/lib/Target/Xtensa/Xtensa.td | 6 ++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 4 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 28 ++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 65 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 19 +++++- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 5 ++ 8 files changed, 148 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index ffd71ddb6a22d..ba2332f761b86 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -74,8 +74,25 @@ static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Success; } +static const unsigned BRDecoderTable[] = { + Xtensa::B0, Xtensa::B1, Xtensa::B2, Xtensa::B3, Xtensa::B4, Xtensa::B5, + Xtensa::B6, Xtensa::B7, Xtensa::B8, Xtensa::B9, Xtensa::B10, Xtensa::B11, + Xtensa::B12, Xtensa::B13, Xtensa::B14, Xtensa::B15}; + +static DecodeStatus DecodeBRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= array_lengthof(BRDecoderTable)) + return MCDisassembler::Fail; + + unsigned Reg = BRDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + static const unsigned SRDecoderTable[] = { - Xtensa::SAR, 3, Xtensa::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73}; + Xtensa::SAR, 3, Xtensa::BREG, 4, + Xtensa ::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73}; static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, @@ -231,8 +248,8 @@ static DecodeStatus decodeImm64n_4nOperand(MCInst &Inst, uint64_t Imm, } static DecodeStatus decodeEntry_Imm12OpValue(MCInst &Inst, uint64_t Imm, - int64_t Address, - const void *Decoder) { + int64_t Address, + const void *Decoder) { assert(isUInt<12>(Imm) && "Invalid immediate"); Inst.addOperand(MCOperand::createImm(Imm << 3)); return MCDisassembler::Success; @@ -367,4 +384,4 @@ DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size, Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI); Size = 3; return Result; -} \ No newline at end of file +} diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 29b2164b398df..209b97aa24fb3 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -26,6 +26,12 @@ def FeatureWindowed : SubtargetFeature<"windowed", "HasWindowed", "true" "Enable Xtensa Windowed Register option">; def HasWindowed : Predicate<"Subtarget->hasWindowed()">, AssemblerPredicate<(all_of FeatureWindowed)>; + +def FeatureBoolean : SubtargetFeature<"bool", "HasBoolean", "true", + "Enable Xtensa Boolean extension">; +def HasBoolean : Predicate<"Subtarget->hasBoolean()">, + AssemblerPredicate<(all_of FeatureBoolean)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 5901bcd4b1823..5de31cdeba04f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -191,6 +191,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); + + if (Subtarget.hasBoolean()) { + addRegisterClass(MVT::i1, &Xtensa::BRRegClass); + } } bool XtensaTargetLowering::isOffsetFoldingLegal( diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index e6ec0a7fe4aa0..abbd5afcc7128 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -234,6 +234,12 @@ bool XtensaInstrInfo::reverseBranchCondition( Cond[0].setImm(Xtensa::BLTZ); return false; + case Xtensa::BF: + Cond[0].setImm(Xtensa::BT); + return false; + case Xtensa::BT: + Cond[0].setImm(Xtensa::BF); + return false; default: llvm_unreachable("Invalid branch condition!"); } @@ -270,6 +276,10 @@ XtensaInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { case Xtensa::BGEZ: return MI.getOperand(1).getMBB(); + case Xtensa::BT: + case Xtensa::BF: + return MI.getOperand(1).getMBB(); + default: llvm_unreachable("Unknown branch opcode"); } @@ -305,6 +315,10 @@ bool XtensaInstrInfo::isBranchOffsetInRange(unsigned BranchOp, case Xtensa::BGEZ: BrOffset -= 4; return isIntN(12, BrOffset); + case Xtensa::BT: + case Xtensa::BF: + BrOffset -= 4; + return isIntN(8, BrOffset); default: llvm_unreachable("Unknown branch opcode"); } @@ -529,6 +543,10 @@ unsigned XtensaInstrInfo::InsertConstBranchAtInst( case Xtensa::BGEZ: MI = BuildMI(MBB, I, DL, get(BR_C)).addImm(offset).addReg(Cond[1].getReg()); break; + case Xtensa::BT: + case Xtensa::BF: + MI = BuildMI(MBB, I, DL, get(BR_C)).addImm(offset).addReg(Cond[1].getReg()); + break; default: llvm_unreachable("Invalid branch type!"); } @@ -589,6 +607,10 @@ unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, case Xtensa::BGEZ: MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB); break; + case Xtensa::BT: + case Xtensa::BF: + MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB); + break; default: llvm_unreachable("Invalid branch type!"); } @@ -637,6 +659,12 @@ bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI, Target = &MI->getOperand(1); return true; + case Xtensa::BT: + case Xtensa::BF: + Cond[0].setImm(OpCode); + Target = &MI->getOperand(1); + return true; + default: assert(!MI->getDesc().isBranch() && "Unknown branch opcode"); return false; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index cd65344318a1f..840406b452acf 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -834,3 +834,68 @@ def ROTW : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins imm8n_7:$imm), let s = 0x0; let t = imm{3-0}; } + +//===----------------------------------------------------------------------===// +// Boolean Instructions +//===----------------------------------------------------------------------===// + +def ALL4 : RRR_Inst<0x00, 0x00, 0x00, (outs BR:$t), (ins BR:$s), + "all4\t$t, $s", []>, Requires<[HasBoolean]> { + let r = 0x9; +} + +def ALL8 : RRR_Inst<0x00, 0x00, 0x00, (outs BR:$t), (ins BR:$s), + "all8\t$t, $s", []>, Requires<[HasBoolean]> { + let r = 0xB; +} + +def ANDB : RRR_Inst<0x00, 0x02, 0x00, (outs BR:$r), (ins BR:$s, BR:$t), + "andb\t$r, $s, $t", []>, Requires<[HasBoolean]>; +def ANDBC : RRR_Inst<0x00, 0x02, 0x01, (outs BR:$r), (ins BR:$s, BR:$t), + "andbc\t$r, $s, $t", []>, Requires<[HasBoolean]>; + +def ANY4 : RRR_Inst<0x00, 0x00, 0x00, (outs BR:$t), (ins BR:$s), + "any4\t$t, $s", []>, Requires<[HasBoolean]> { + let r = 0x8; +} + +def ANY8 : RRR_Inst<0x00, 0x00, 0x00, (outs BR:$t), (ins BR:$s), + "any8\t$t, $s", []>, Requires<[HasBoolean]> { + let r = 0xA; +} + +let isBranch = 1, isTerminator = 1, Predicates = [HasBoolean] in { + def BT : RRI8_Inst<0x06, (outs), (ins BR:$b, brtarget:$target), + "bt\t$b, $target", []> { + bits<8> target; + bits<4> b; + + let r = 0x1; + let s = b; + let t = 0x7; + let imm8 = target; + } + + def BF : RRI8_Inst<0x06, (outs), (ins BR:$b, brtarget:$target), + "bf\t$b, $target", []> { + bits<8> target; + bits<4> b; + + let r = 0x0; + let s = b; + let t = 0x7; + let imm8 = target; + } +} + +def MOVF : RRR_Inst<0x00, 0x03, 0x0C, (outs AR:$r), (ins AR:$s, BR:$t), + "movf\t$r, $s, $t", []>, Requires<[HasBoolean]>; +def MOVT : RRR_Inst<0x00, 0x03, 0x0D, (outs AR:$r), (ins AR:$s, BR:$t), + "movt\t$r, $s, $t", []>, Requires<[HasBoolean]>; + +def ORB : RRR_Inst<0x00, 0x02, 0x02, (outs BR:$r), (ins BR:$s, BR:$t), + "orb\t$r, $s, $t", []>, Requires<[HasBoolean]>; +def ORBC : RRR_Inst<0x00, 0x02, 0x03, (outs BR:$r), (ins BR:$s, BR:$t), + "orbc\t$r, $s, $t", []>, Requires<[HasBoolean]>; +def XORB : RRR_Inst<0x00, 0x02, 0x04, (outs BR:$r), (ins BR:$s, BR:$t), + "xorb\t$r, $s, $t", []>, Requires<[HasBoolean]>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 9939d19ef1907..5b87a83786ac4 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -75,8 +75,25 @@ class SRReg num, string n, list alt = []> : XtensaReg { // Shift Amount Register def SAR : SRReg<3, "sar", ["SAR","3"]>; +def BREG : SRReg<4, "br", ["BR", "4"]>; + def WINDOWBASE : SRReg<72, "windowbase", ["WINDOWBASE", "72"]>; def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>; def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR, - WINDOWBASE, WINDOWSTART)>; + BREG, WINDOWBASE, WINDOWSTART)>; + +//===----------------------------------------------------------------------===// +// Boolean registers +//===----------------------------------------------------------------------===// +class BReg num, string n> : XtensaReg { + let HWEncoding{3-0} = num; +} + +foreach i = 0-15 in { + def B#i : BReg, DwarfRegNum<[i]>; +} + +// Boolean register class +def BR : RegisterClass<"Xtensa", [i1], 0, (add B0, B1, +B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15)>; diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index fe47de0f95271..df8e248dbfdf7 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -34,6 +34,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasDensity = false; HasWindowed = false; + HasBoolean = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index aea0a9ed9b452..cf014f5371d1a 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -44,6 +44,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enabled Xtensa Windowed Register option bool HasWindowed; + // Enabled Xtensa Boolean extension + bool HasBoolean; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -65,6 +68,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasWindowed() const { return HasWindowed; } + bool hasBoolean() const { return HasBoolean; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; From ce861cfe7870fe038df06e9833d81f5fea65ef1d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:57 +0300 Subject: [PATCH 037/150] [Xtensa] Implement Floating-Point feature operations. Also implement User Registers class. --- .../Disassembler/XtensaDisassembler.cpp | 38 ++++ .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 2 + llvm/lib/Target/Xtensa/Xtensa.td | 5 + llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 10 + llvm/lib/Target/Xtensa/XtensaISelLowering.h | 15 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 3 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 198 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperators.td | 15 ++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 44 ++++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 5 + 11 files changed, 336 insertions(+) diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index ba2332f761b86..098111b170444 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -74,6 +74,22 @@ static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Success; } +static const unsigned FPRDecoderTable[] = { + Xtensa::F0, Xtensa::F1, Xtensa::F2, Xtensa::F3, Xtensa::F4, Xtensa::F5, + Xtensa::F6, Xtensa::F7, Xtensa::F8, Xtensa::F9, Xtensa::F10, Xtensa::F11, + Xtensa::F12, Xtensa::F13, Xtensa::F14, Xtensa::F15}; + +static DecodeStatus DecodeFPRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= array_lengthof(FPRDecoderTable)) + return MCDisassembler::Fail; + + unsigned Reg = FPRDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + static const unsigned BRDecoderTable[] = { Xtensa::B0, Xtensa::B1, Xtensa::B2, Xtensa::B3, Xtensa::B4, Xtensa::B5, Xtensa::B6, Xtensa::B7, Xtensa::B8, Xtensa::B9, Xtensa::B10, Xtensa::B11, @@ -111,6 +127,28 @@ static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Fail; } +static const unsigned URDecoderTable[] = {Xtensa::FCR, 232, Xtensa::FSR, 233}; + +static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + const llvm::MCSubtargetInfo STI = + ((const MCDisassembler *)Decoder)->getSubtargetInfo(); + + if (RegNo > 255) + return MCDisassembler::Fail; + + for (unsigned i = 0; i < array_lengthof(URDecoderTable); i += 2) { + if (URDecoderTable[i + 1] == RegNo) { + unsigned Reg = URDecoderTable[i]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; + } + } + + return MCDisassembler::Fail; +} + static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch, uint64_t Address, uint64_t Offset, uint64_t InstSize, MCInst &MI, diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index d5b61985d09da..379783761f588 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -276,6 +276,8 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, case Xtensa::L32I: case Xtensa::S32I_N: case Xtensa::L32I_N: + case Xtensa::S32F: + case Xtensa::L32F: if (Res & 0x3) { report_fatal_error("Unexpected operand value!"); } diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 209b97aa24fb3..f6a830c680490 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -22,6 +22,11 @@ def FeatureDensity : SubtargetFeature<"density", "HasDensity", "true", def HasDensity : Predicate<"Subtarget->hasDensity()">, AssemblerPredicate<(all_of FeatureDensity)>; +def FeatureSingleFloat : SubtargetFeature<"fp", "HasSingleFloat", "true", + "Enable Xtensa Single FP instructions">; +def HasSingleFloat : Predicate<"Subtarget->hasSingleFloat()">, + AssemblerPredicate<(all_of FeatureSingleFloat)>; + def FeatureWindowed : SubtargetFeature<"windowed", "HasWindowed", "true", "Enable Xtensa Windowed Register option">; def HasWindowed : Predicate<"Subtarget->hasWindowed()">, diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 5de31cdeba04f..202065dd751dc 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -1336,6 +1336,16 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(SELECT); OPCODE(SELECT_CC); OPCODE(BR_JT); + OPCODE(CMPUO); + OPCODE(CMPUEQ); + OPCODE(CMPULE); + OPCODE(CMPULT); + OPCODE(CMPOEQ); + OPCODE(CMPOLE); + OPCODE(CMPOLT); + OPCODE(MADD); + OPCODE(MSUB); + OPCODE(MOVS); OPCODE(MOVSP); OPCODE(SHL); OPCODE(SRA); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 562d59abf64d0..fe0cf6abd09bc 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -34,6 +34,21 @@ enum { // WinABI Call version CALLW, + // Floating point unordered compare conditions + CMPUEQ, + CMPULE, + CMPULT, + CMPUO, + // Floating point compare conditions + CMPOEQ, + CMPOLE, + CMPOLT, + // FP multipy-add/sub + MADD, + MSUB, + // FP move + MOVS, + MOVSP, // Wraps a TargetGlobalAddress that should be loaded using PC-relative diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index abbd5afcc7128..8dea2c7febdf0 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -128,6 +128,9 @@ void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, if (RC == &Xtensa::ARRegClass) { LoadOpcode = Xtensa::L32I; StoreOpcode = Xtensa::S32I; + } else if (RC == &Xtensa::FPRRegClass) { + LoadOpcode = Xtensa::L32F; + StoreOpcode = Xtensa::S32F; } else llvm_unreachable("Unsupported regclass to load or store"); } diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 840406b452acf..c2dcb49063ea6 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -899,3 +899,201 @@ def ORBC : RRR_Inst<0x00, 0x02, 0x03, (outs BR:$r), (ins BR:$s, BR:$t), "orbc\t$r, $s, $t", []>, Requires<[HasBoolean]>; def XORB : RRR_Inst<0x00, 0x02, 0x04, (outs BR:$r), (ins BR:$s, BR:$t), "xorb\t$r, $s, $t", []>, Requires<[HasBoolean]>; + +//===----------------------------------------------------------------------===// +// Floating-Point Instructions +//===----------------------------------------------------------------------===// + +class FPArith_RRR oper2, bits<4> oper1, string instrAsm, + SDPatternOperator opNode, bit isComm = 0> + : RRR_Inst<0x00, oper1, oper2, (outs FPR:$r), (ins FPR:$s, FPR:$t), + instrAsm#"\t$r, $s, $t", + [(set FPR:$r, (opNode FPR:$s, FPR:$t))]> { + let isCommutable = isComm; + let isReMaterializable = 0; + let Predicates = [HasSingleFloat]; +} + +def ADD_S : FPArith_RRR<0x00, 0x0A, "add.s", fadd, 1>; +def SUB_S : FPArith_RRR<0x01, 0x0A, "sub.s", fsub>; +def MUL_S : FPArith_RRR<0x02, 0x0A, "mul.s", fmul, 1>; + +def ABS_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "abs.s\t$r, $s", + [(set FPR:$r, (fabs FPR:$s))]> { + let t = 0x01; +} + +def NEG_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "neg.s\t$r, $s", + [(set FPR:$r, (fneg FPR:$s))]> { + let t = 0x06; +} + +def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s), + "trunc.s\t$r, $s, 0", + [(set AR:$r, (fp_to_sint FPR:$s))]> { + let t = 0x00; +} + +def UTRUNC_S : RRR_Inst<0x00, 0x0A, 0x0e, (outs AR:$r), (ins FPR:$s), + "utrunc.s\t$r, $s, 0", + [(set AR:$r, (fp_to_uint FPR:$s))]> { + let t = 0x00; +} + +def FLOAT_S : RRR_Inst<0x00, 0x0A, 0x0c, (outs FPR:$r), (ins AR:$s), + "float.s\t$r, $s, 0", + [(set FPR:$r, (sint_to_fp AR:$s))]> { + let t = 0x00; +} + +def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s), + "ufloat.s\t$r, $s, 0", + [(set FPR:$r, (uint_to_fp AR:$s))]> { + let t = 0x00; +} + +def RFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs AR:$r), (ins FPR:$s), + "rfr\t$r, $s", + [(set AR:$r, (bitconvert FPR:$s))]> { + let t = 0x04; +} + +def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s), + "wfr\t$r, $s", + [(set FPR:$r, (bitconvert AR:$s))]> { + let t = 0x05; +} + +// FP load instructions +let mayLoad = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in { + class LoadF_RRI8 oper, string instrAsm, SDPatternOperator opNode, + ComplexPattern addrOp,Operand memOp>: RRI8_Inst<0x03, (outs FPR:$t), (ins memOp:$addr), + instrAsm#"\t$t, $addr", + [(set FPR:$t, (opNode addrOp:$addr))]> { + bits<12> addr; + + let r = oper; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +def L32F : LoadF_RRI8<0x00, "lsi", load, addr_ish4, mem32>, Requires<[]>; + +// FP store instructions +let mayStore = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in { + class StoreF_RRI8 oper, string instrAsm, SDPatternOperator opNode, + ComplexPattern addrOp, Operand memOp>: RRI8_Inst<0x03, (outs), (ins FPR:$t, memOp:$addr), + instrAsm#"\t$t, $addr", + [(opNode FPR:$t, addrOp:$addr)]> { + bits<12> addr; + + let r = oper; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +def S32F : StoreF_RRI8<0x04, "ssi", store, addr_ish4, mem32>; + +// FP compare instructions +let isCompare = 1, Predicates = [HasSingleFloat] in { + class FCompare oper2, bits<4> oper1, string instrAsm, + SDPatternOperator opNode, bit isComm = 0> + : RRR_Inst<0x00, oper1, oper2, (outs BR:$b), (ins FPR:$s, FPR:$t), + instrAsm#"\t$b, $s, $t", + [(set BR:$b, (opNode FPR:$s, FPR:$t))]> { + let isCommutable = isComm; + let isReMaterializable = 0; + let Predicates = [HasSingleFloat]; + } +} + +def OEQ_S : FCompare<0x02, 0x0b, "oeq.s", Xtensa_cmpoeq, 1>; +def OLT_S : FCompare<0x04, 0x0b, "olt.s", Xtensa_cmpolt, 0>; +def OLE_S : FCompare<0x06, 0x0b, "ole.s", Xtensa_cmpole, 0>; + +def UEQ_S : FCompare<0x03, 0x0b, "ueq.s", Xtensa_cmpueq, 1>; +def ULT_S : FCompare<0x05, 0x0b, "ult.s", Xtensa_cmpult, 0>; +def ULE_S : FCompare<0x07, 0x0b, "ule.s", Xtensa_cmpule, 0>; +def UN_S : FCompare<0x01, 0x0b, "un.s", Xtensa_cmpuo, 1>; + +//FP complex operations +def MADD_S : RRR_Inst<0x00, 0x0A, 0x04, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t), + "madd.s\t$r, $s, $t", + [(set FPR:$r, (Xtensa_madd FPR:$a, FPR:$s, FPR:$t))]>, + Requires<[HasSingleFloat]> { + let isCommutable = 0; + let isReMaterializable = 0; + let Constraints = "$r = $a"; +} + +def MSUB_S : RRR_Inst<0x00, 0x0A, 0x05, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t), + "msub.s\t$r, $s, $t", + [(set FPR:$r, (Xtensa_msub FPR:$a, FPR:$s, FPR:$t))]>, + Requires<[HasSingleFloat]> { + let isCommutable = 0; + let isReMaterializable = 0; + let Constraints = "$r = $a"; +} + +//FP move operations +def MOV_S : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins FPR:$s), + "mov.s\t$r, $s", + [(set FPR:$r, (Xtensa_movs FPR:$s))]>, Requires<[HasSingleFloat]> +{ + let t = 0x00; +} + +def CONST_S : RRR_Inst<0x00, 0x0a, 0x0f, (outs FPR:$r), (ins uimm4:$imm), + "const.s\t$r, $imm", []>, Requires<[HasSingleFloat]> { + bits<4> imm; + + let t = 0x03; + let s = imm{3-0}; +} + +def DIV0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "div0.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x7; +} + +def MADDN_S : RRR_Inst<0x00, 0x0A, 0x06, (outs FPR:$r), (ins FPR:$s, FPR:$t), + "maddn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]> { + let isCommutable = 0; +} + +def MKDADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "mkdadj.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0D; +} + +def MKSADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "mksadj.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0C; +} + +def ADDEXP_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "addexp.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0E; +} + +def ADDEXPM_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "addexpm.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0F; +} + +def DIVN_S : RRR_Inst<0x00, 0x0A, 0x07, (outs FPR:$r), (ins FPR:$s, FPR:$t), + "divn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; + +def NEXP01_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "nexp01.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0B; +} + +def SQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "sqrt0.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x09; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index 41b2f9d72a64a..975d6820802d9 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -25,6 +25,9 @@ def SDT_XtensaSelectCC : SDTypeProfile<1, 5, SDTCisVT<5, i32>]>; def SDT_XtensaMOVSP : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>; +def SDT_XtensaCmp : SDTypeProfile<1, 2, [SDTCisVT<0, i1>, SDTCisVT<1, f32>, SDTCisVT<2, f32>]>; +def SDT_XtensaMADD : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisVT<0, f32>]>; +def SDT_XtensaMOVS : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, f32>]>; def SDT_XtensaBrJT : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; @@ -63,6 +66,18 @@ def Xtensa_select_cc: SDNode<"XtensaISD::SELECT_CC", SDT_XtensaSelectCC, def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP, [SDNPInGlue]>; +def Xtensa_cmpoeq : SDNode<"XtensaISD::CMPOEQ", SDT_XtensaCmp, [SDNPOutGlue]>; +def Xtensa_cmpolt : SDNode<"XtensaISD::CMPOLT", SDT_XtensaCmp, [SDNPOutGlue]>; +def Xtensa_cmpole : SDNode<"XtensaISD::CMPOLE", SDT_XtensaCmp, [SDNPOutGlue]>; +def Xtensa_cmpueq : SDNode<"XtensaISD::CMPUEQ", SDT_XtensaCmp, [SDNPOutGlue]>; +def Xtensa_cmpult : SDNode<"XtensaISD::CMPULT", SDT_XtensaCmp, [SDNPOutGlue]>; +def Xtensa_cmpule : SDNode<"XtensaISD::CMPULE", SDT_XtensaCmp, [SDNPOutGlue]>; +def Xtensa_cmpuo : SDNode<"XtensaISD::CMPUO", SDT_XtensaCmp, [SDNPOutGlue]>; + +def Xtensa_madd: SDNode<"XtensaISD::MADD", SDT_XtensaMADD, [SDNPInGlue]>; +def Xtensa_msub: SDNode<"XtensaISD::MSUB", SDT_XtensaMADD, [SDNPInGlue]>; +def Xtensa_movs: SDNode<"XtensaISD::MOVS", SDT_XtensaMOVS, [SDNPInGlue]>; + def Xtensa_shl: SDNode<"XtensaISD::SHL", SDT_XtensaSHL, [SDNPInGlue]>; def Xtensa_sra: SDNode<"XtensaISD::SRA", SDT_XtensaSRA, [SDNPInGlue]>; def Xtensa_srl: SDNode<"XtensaISD::SRL", SDT_XtensaSRL, [SDNPInGlue]>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 5b87a83786ac4..18341287347d2 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -83,6 +83,50 @@ def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>; def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR, BREG, WINDOWBASE, WINDOWSTART)>; +//===----------------------------------------------------------------------===// +// USER registers +//===----------------------------------------------------------------------===// +class URReg num, string n, list alt = []> : XtensaReg { + let HWEncoding{7-0} = num; + let AltNames = alt; +} + +def FCR : URReg<232, "fcr", ["FCR"]>; +def FSR : URReg<233, "fsr", ["FSR"]>; + +def UR : RegisterClass<"Xtensa", [i32], 32, (add FCR, FSR)>; + +//===----------------------------------------------------------------------===// +// Floating-Point registers +//===----------------------------------------------------------------------===// + +// Xtensa Floating-Point regs +class FPReg num, string n> : XtensaReg { + let HWEncoding{3-0} = num; +} + +def F0 : FPReg<0, "f0">, DwarfRegNum<[19]>; +def F1 : FPReg<1, "f1">, DwarfRegNum<[20]>; +def F2 : FPReg<2, "f2">, DwarfRegNum<[21]>; +def F3 : FPReg<3, "f3">, DwarfRegNum<[22]>; +def F4 : FPReg<4, "f4">, DwarfRegNum<[23]>; +def F5 : FPReg<5, "f5">, DwarfRegNum<[24]>; +def F6 : FPReg<6, "f6">, DwarfRegNum<[25]>; +def F7 : FPReg<7, "f7">, DwarfRegNum<[26]>; +def F8 : FPReg<8, "f8">, DwarfRegNum<[27]>; +def F9 : FPReg<9, "f9">, DwarfRegNum<[28]>; +def F10 : FPReg<10, "f10">, DwarfRegNum<[29]>; +def F11 : FPReg<11, "f11">, DwarfRegNum<[30]>; +def F12 : FPReg<12, "f12">, DwarfRegNum<[31]>; +def F13 : FPReg<13, "f13">, DwarfRegNum<[32]>; +def F14 : FPReg<14, "f14">, DwarfRegNum<[33]>; +def F15 : FPReg<15, "f15">, DwarfRegNum<[34]>; + +// Floating-Point register class with allocation order +def FPR : RegisterClass<"Xtensa", [f32], 32, (add + F8, F9, F10, F11, F12, F13, F14, F15, + F7, F6, F5, F4, F3, F2, F1, F0)>; + //===----------------------------------------------------------------------===// // Boolean registers //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index df8e248dbfdf7..a878477726da7 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -33,6 +33,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { } HasDensity = false; + HasSingleFloat = false; HasWindowed = false; HasBoolean = false; diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index cf014f5371d1a..3e2cbbee972fb 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -41,6 +41,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enabled Xtensa Density extension bool HasDensity; + // Enabled Xtensa Single FP instructions + bool HasSingleFloat; + // Enabled Xtensa Windowed Register option bool HasWindowed; @@ -66,6 +69,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasDensity() const { return HasDensity; } + bool hasSingleFloat() const { return HasSingleFloat; } + bool hasWindowed() const { return HasWindowed; } bool hasBoolean() const { return HasBoolean; } From 1a8ac61bc7279dd4a8dbd73c7302760b7cf88514 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:58 +0300 Subject: [PATCH 038/150] [Xtensa] Lowering Floating-Point Operations SELECT_CC/SETCC/BR_CC. Implement DAG Combine for BRCOND operation with f32 operands. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 352 +++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 7 + llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 17 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 16 + llvm/lib/Target/Xtensa/XtensaOperators.td | 9 + 5 files changed, 385 insertions(+), 16 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 202065dd751dc..ada2df227ef5f 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -59,6 +59,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, // Set up the register classes. addRegisterClass(MVT::i32, &Xtensa::ARRegClass); + if (Subtarget.hasSingleFloat()) { + addRegisterClass(MVT::f32, &Xtensa::FPRRegClass); + } + // Set up special registers. setStackPointerRegisterToSaveRestore(Xtensa::SP); @@ -94,16 +98,29 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::BR_CC, MVT::i32, Legal); setOperationAction(ISD::BR_CC, MVT::i64, Expand); + if (Subtarget.hasSingleFloat()) + setOperationAction(ISD::BR_CC, MVT::f32, Custom); + else + setOperationAction(ISD::BR_CC, MVT::f32, Expand); setOperationAction(ISD::SELECT, MVT::i32, Expand); setOperationAction(ISD::SELECT, MVT::i64, Expand); + setOperationAction(ISD::SELECT, MVT::f32, Expand); setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); setOperationAction(ISD::SELECT_CC, MVT::i64, Expand); + if (Subtarget.hasSingleFloat()) + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + else + setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); setOperationAction(ISD::SETCC, MVT::i32, Custom); // folds into brcond setOperationAction(ISD::SETCC, MVT::i64, Expand); + if (Subtarget.hasSingleFloat()) + setOperationAction(ISD::SETCC, MVT::f32, Custom); + else + setOperationAction(ISD::SETCC, MVT::f32, Expand); // Expand jump table branches as address arithmetic followed by an // indirect jump. @@ -175,6 +192,83 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand); + // Handle floating-point types. + for (unsigned I = MVT::FIRST_FP_VALUETYPE; I <= MVT::LAST_FP_VALUETYPE; ++I) { + MVT VT = MVT::SimpleValueType(I); + if (isTypeLegal(VT)) { + // We can use FI for FRINT. + // setOperationAction(ISD::FRINT, VT, Legal); + if (VT.getSizeInBits() == 32 && Subtarget.hasSingleFloat()) { + setOperationAction(ISD::FADD, VT, Legal); + setOperationAction(ISD::FSUB, VT, Legal); + setOperationAction(ISD::FMUL, VT, Legal); + setOperationAction(ISD::FDIV, VT, Expand); + } else { + setOperationAction(ISD::FADD, VT, Expand); + setOperationAction(ISD::FSUB, VT, Expand); + setOperationAction(ISD::FMUL, VT, Expand); + setOperationAction(ISD::FDIV, VT, Expand); + } + + // TODO: once implemented in InstrInfo uncomment + setOperationAction(ISD::FSQRT, VT, Expand); + + // No special instructions for these. + setOperationAction(ISD::FSIN, VT, Expand); + setOperationAction(ISD::FCOS, VT, Expand); + setOperationAction(ISD::FREM, VT, Expand); + setOperationAction(ISD::FABS, VT, Expand); + } + } + + // Handle floating-point types. + if (Subtarget.hasSingleFloat()) { + setOperationAction(ISD::FMA, MVT::f32, Legal); + setOperationAction(ISD::BITCAST, MVT::i32, Legal); + setOperationAction(ISD::BITCAST, MVT::f32, Legal); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal); + setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Legal); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + } else { + setOperationAction(ISD::FMA, MVT::f32, Expand); + setOperationAction(ISD::SETCC, MVT::f32, Expand); + setOperationAction(ISD::BITCAST, MVT::i32, Expand); + setOperationAction(ISD::BITCAST, MVT::f32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Expand); + } + setOperationAction(ISD::FMA, MVT::f64, Expand); + setOperationAction(ISD::SETCC, MVT::f64, Expand); + setOperationAction(ISD::BITCAST, MVT::i64, Expand); + setOperationAction(ISD::BITCAST, MVT::f64, Expand); + + if (Subtarget.hasSingleFloat()) { + setCondCodeAction(ISD::SETOGT, MVT::f32, Expand); + setCondCodeAction(ISD::SETOGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETONE, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGE, MVT::f32, Expand); + setCondCodeAction(ISD::SETUGT, MVT::f32, Expand); + + setTargetDAGCombine(ISD::BRCOND); + } + + // Needed so that we don't try to implement f128 constant loads using + // a load-and-extend of a f80 constant (in cases where the constant + // would fit in an f80). + for (MVT VT : MVT::fp_valuetypes()) + setLoadExtAction(ISD::EXTLOAD, VT, MVT::f80, Expand); + + // Floating-point truncation and stores need to be done separately. + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + // Implement custom stack allocations setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); // Implement custom stack save and restore @@ -289,6 +383,50 @@ void XtensaTargetLowering::LowerAsmOperandForConstraint( TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); } +//===----------------------------------------------------------------------===// +// DAG Combine functions +//===----------------------------------------------------------------------===// + +static SDValue PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const XtensaSubtarget &Subtarget) { + if (DCI.isBeforeLegalizeOps()) { + SDValue Chain = N->getOperand(0); + + if (N->getOperand(1).getOpcode() != ISD::SETCC) + return SDValue(); + + SDLoc DL(N); + SDValue SetCC = N->getOperand(1); + SDValue Dest = N->getOperand(2); + ISD::CondCode CC = cast(SetCC->getOperand(2))->get(); + SDValue LHS = SetCC->getOperand(0); + SDValue RHS = SetCC->getOperand(1); + + if (LHS.getValueType() != MVT::i32) + return SDValue(); + + return DAG.getNode(ISD::BR_CC, DL, MVT::isVoid, Chain, DAG.getCondCode(CC), + LHS, RHS, Dest); + } + return SDValue(); +} + +SDValue XtensaTargetLowering::PerformDAGCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + unsigned Opc = N->getOpcode(); + + switch (Opc) { + default: + break; + case ISD::BRCOND: + return PerformBRCONDCombine(N, DAG, DCI, Subtarget); + } + + return SDValue(); +} + //===----------------------------------------------------------------------===// // Calling conventions //===----------------------------------------------------------------------===// @@ -827,6 +965,90 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, DL, MVT::Other, RetOps); } +static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, ISD::CondCode CC, SDLoc dl, + SelectionDAG &DAG, int &br_code) { + // Minor optimization: if LHS is a constant, swap operands, then the + // constant can be folded into comparison. + if (LHS.getOpcode() == ISD::Constant) + std::swap(LHS, RHS); + int cmp_code = 0; + + switch (CC) { + default: + llvm_unreachable("Invalid condition!"); + break; + case ISD::SETUNE: + br_code = XtensaISD::BR_CC_F; + cmp_code = XtensaISD::CMPOEQ; + break; + case ISD::SETUO: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPUO; + break; + case ISD::SETO: + br_code = XtensaISD::BR_CC_F; + cmp_code = XtensaISD::CMPUO; + break; + case ISD::SETUEQ: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPUEQ; + break; + case ISD::SETULE: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPULE; + break; + case ISD::SETULT: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPULT; + break; + case ISD::SETEQ: + case ISD::SETOEQ: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPOEQ; + break; + case ISD::SETNE: + br_code = XtensaISD::BR_CC_F; + cmp_code = XtensaISD::CMPOEQ; + break; + case ISD::SETLE: + case ISD::SETOLE: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPOLE; + break; + case ISD::SETLT: + case ISD::SETOLT: + br_code = XtensaISD::BR_CC_T; + cmp_code = XtensaISD::CMPOLT; + break; + case ISD::SETGE: + br_code = XtensaISD::BR_CC_F; + cmp_code = XtensaISD::CMPOLT; + break; + case ISD::SETGT: + br_code = XtensaISD::BR_CC_F; + cmp_code = XtensaISD::CMPOLE; + break; + } + return DAG.getNode(cmp_code, dl, MVT::i1, LHS, RHS); +} + +SDValue XtensaTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + SDLoc DL(Op); + + if (LHS.getValueType() == MVT::f32) { + int br_code; + SDValue Flag = EmitCMP(LHS, RHS, CC, DL, DAG, br_code); + return DAG.getNode(br_code, DL, Op.getValueType(), Chain, Flag, Dest); + } else { + llvm_unreachable("invalid BR_CC to lower"); + } +} + SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -839,8 +1061,15 @@ SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op, SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); // Wrap select nodes - return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueV, FalseV, - TargetCC); + if (LHS.getValueType() == MVT::f32) + return DAG.getNode(XtensaISD::SELECT_CC_FP, DL, TrueV.getValueType(), LHS, + RHS, TrueV, FalseV, TargetCC); + else if (TrueV.getValueType() == MVT::f32) + return DAG.getNode(XtensaISD::SELECT_CC_FP, DL, TrueV.getValueType(), LHS, + RHS, TrueV, FalseV, TargetCC); + else + return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueV, FalseV, + TargetCC); } SDValue XtensaTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { @@ -873,8 +1102,15 @@ SDValue XtensaTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { SDValue TrueV = DAG.getConstant(1, DL, Op.getValueType()); SDValue FalseV = DAG.getConstant(0, DL, Op.getValueType()); - return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueV, FalseV, - TargetCC); + if (LHS.getValueType() == MVT::f32) + return DAG.getNode(XtensaISD::SELECT_CC_FP, DL, TrueV.getValueType(), LHS, + RHS, TrueV, FalseV, TargetCC); + else if (TrueV.getValueType() == MVT::f32) + return DAG.getNode(XtensaISD::SELECT_CC_FP, DL, TrueV.getValueType(), LHS, + RHS, TrueV, FalseV, TargetCC); + else + return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueV, FalseV, + TargetCC); } SDValue XtensaTargetLowering::LowerRETURNADDR(SDValue Op, @@ -1288,6 +1524,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerImmediateFP(Op, DAG); case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); case ISD::SETCC: return LowerSETCC(Op, DAG); case ISD::SELECT_CC: @@ -1335,6 +1573,9 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(PCREL_WRAPPER); OPCODE(SELECT); OPCODE(SELECT_CC); + OPCODE(SELECT_CC_FP); + OPCODE(BR_CC_T); + OPCODE(BR_CC_F); OPCODE(BR_JT); OPCODE(CMPUO); OPCODE(CMPUEQ); @@ -1401,6 +1642,66 @@ static int GetBranchKind(int Cond, bool &BrInv) { } } +static void GetFPBranchKind(int Cond, int &BrKind, int &CmpKind) { + + switch (Cond) { + default: + llvm_unreachable("Invalid condition!"); + break; + case ISD::SETUNE: + BrKind = Xtensa::BF; + CmpKind = Xtensa::OEQ_S; + break; + case ISD::SETUO: + BrKind = Xtensa::BT; + CmpKind = Xtensa::UN_S; + break; + case ISD::SETO: + BrKind = Xtensa::BF; + CmpKind = Xtensa::UN_S; + break; + case ISD::SETUEQ: + BrKind = Xtensa::BT; + CmpKind = Xtensa::UEQ_S; + break; + case ISD::SETULE: + BrKind = Xtensa::BT; + CmpKind = Xtensa::ULE_S; + break; + case ISD::SETULT: + BrKind = Xtensa::BT; + CmpKind = Xtensa::ULT_S; + break; + case ISD::SETEQ: + case ISD::SETOEQ: + BrKind = Xtensa::BT; + CmpKind = Xtensa::OEQ_S; + break; + case ISD::SETNE: + BrKind = Xtensa::BF; + CmpKind = Xtensa::OEQ_S; + break; + case ISD::SETLE: + case ISD::SETOLE: + BrKind = Xtensa::BT; + CmpKind = Xtensa::OLE_S; + break; + case ISD::SETLT: + case ISD::SETOLT: + BrKind = Xtensa::BT; + CmpKind = Xtensa::OLT_S; + break; + case ISD::SETGE: + BrKind = Xtensa::BF; + CmpKind = Xtensa::OLT_S; + break; + case ISD::SETGT: + BrKind = Xtensa::BF; + CmpKind = Xtensa::OLE_S; + break; + } +} + MachineBasicBlock * XtensaTargetLowering::emitSelectCC(MachineInstr &MI, MachineBasicBlock *BB) const { @@ -1443,19 +1744,35 @@ XtensaTargetLowering::emitSelectCC(MachineInstr &MI, BB->addSuccessor(copy0MBB); BB->addSuccessor(sinkMBB); - bool BrInv = false; - int BrKind = GetBranchKind(Cond.getImm(), BrInv); - if (BrInv) { - BuildMI(BB, DL, TII.get(BrKind)) - .addReg(RHS.getReg()) + if ((MI.getOpcode() == Xtensa::SELECT_CC_FP_FP) || + (MI.getOpcode() == Xtensa::SELECT_CC_FP_INT)) { + int BrKind = 0; + int CmpKind = 0; + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i1); + unsigned b = RegInfo.createVirtualRegister(RC); + GetFPBranchKind(Cond.getImm(), BrKind, CmpKind); + BuildMI(BB, DL, TII.get(CmpKind), b) .addReg(LHS.getReg()) - .addMBB(sinkMBB); + .addReg(RHS.getReg()); + BuildMI(BB, DL, TII.get(BrKind)).addReg(b).addMBB(sinkMBB); } else { - BuildMI(BB, DL, TII.get(BrKind)) - .addReg(LHS.getReg()) - .addReg(RHS.getReg()) - .addMBB(sinkMBB); + bool BrInv = false; + int BrKind = GetBranchKind(Cond.getImm(), BrInv); + if (BrInv) { + BuildMI(BB, DL, TII.get(BrKind)) + .addReg(RHS.getReg()) + .addReg(LHS.getReg()) + .addMBB(sinkMBB); + } else { + BuildMI(BB, DL, TII.get(BrKind)) + .addReg(LHS.getReg()) + .addReg(RHS.getReg()) + .addMBB(sinkMBB); + } } + // copy0MBB: // %FalseValue = ... // # fallthrough to sinkMBB @@ -1487,6 +1804,9 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( DebugLoc DL = MI.getDebugLoc(); switch (MI.getOpcode()) { + case Xtensa::SELECT_CC_FP_FP: + case Xtensa::SELECT_CC_FP_INT: + case Xtensa::SELECT_CC_INT_FP: case Xtensa::SELECT: return emitSelectCC(MI, MBB); @@ -1548,11 +1868,13 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( case Xtensa::S16I: case Xtensa::S32I: case Xtensa::S32I_N: + case Xtensa::S32F: case Xtensa::L8UI: case Xtensa::L16SI: case Xtensa::L16UI: case Xtensa::L32I: - case Xtensa::L32I_N: { + case Xtensa::L32I_N: + case Xtensa::L32F: { const MachineMemOperand &MMO = **MI.memoperands_begin(); if (MMO.isVolatile()) { BuildMI(*MBB, MI, DL, TII.get(Xtensa::MEMW)); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index fe0cf6abd09bc..b6534cf67ce44 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -25,6 +25,9 @@ namespace XtensaISD { enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, + BR_CC_T, + BR_CC_F, + BR_JT, // Calls a function. Operand 0 is the chain operand and operand 1 @@ -66,6 +69,7 @@ enum { // Operand 3 is the flag operand. SELECT, SELECT_CC, + SELECT_CC_FP, // Shift SHL, @@ -116,6 +120,8 @@ class XtensaTargetLowering : public TargetLowering { std::vector &Ops, SelectionDAG &DAG) const override; + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, @@ -150,6 +156,7 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 8dea2c7febdf0..a4d5882983a7f 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -88,13 +88,28 @@ void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, bool KillSrc) const { + unsigned Opcode; + // when we are copying a phys reg we want the bits for fp - if (Xtensa::ARRegClass.contains(DestReg, SrcReg)) + if (Xtensa::ARRegClass.contains(DestReg, SrcReg)) { BuildMI(MBB, MBBI, DL, get(Xtensa::OR), DestReg) .addReg(SrcReg, getKillRegState(KillSrc)) .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } else if (STI.hasSingleFloat() && Xtensa::FPRRegClass.contains(SrcReg) && + Xtensa::FPRRegClass.contains(DestReg)) + Opcode = Xtensa::MOV_S; + else if (STI.hasSingleFloat() && Xtensa::FPRRegClass.contains(SrcReg) && + Xtensa::ARRegClass.contains(DestReg)) + Opcode = Xtensa::RFR; + else if (STI.hasSingleFloat() && Xtensa::ARRegClass.contains(SrcReg) && + Xtensa::FPRRegClass.contains(DestReg)) + Opcode = Xtensa::WFR; else llvm_unreachable("Impossible reg-to-reg copy"); + + BuildMI(MBB, MBBI, DL, get(Opcode), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); } void XtensaInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index c2dcb49063ea6..002add6574f23 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -900,6 +900,9 @@ def ORBC : RRR_Inst<0x00, 0x02, 0x03, (outs BR:$r), (ins BR:$s, BR:$t), def XORB : RRR_Inst<0x00, 0x02, 0x04, (outs BR:$r), (ins BR:$s, BR:$t), "xorb\t$r, $s, $t", []>, Requires<[HasBoolean]>; +def : Pat<(Xtensa_brcc_t BR:$b, bb:$target), (BT BR:$b, bb:$target)>; +def : Pat<(Xtensa_brcc_f BR:$b, bb:$target), (BF BR:$b, bb:$target)>; + //===----------------------------------------------------------------------===// // Floating-Point Instructions //===----------------------------------------------------------------------===// @@ -1097,3 +1100,16 @@ def SQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "sqrt0.s\t$r, $s", []>, Requires<[HasSingleFloat]> { let t = 0x09; } + +// FP select operations +let usesCustomInserter = 1 in { + def SELECT_CC_FP_INT : Pseudo<(outs AR:$dst), (ins FPR:$lhs, FPR:$rhs, AR:$t, AR:$f, i32imm:$cond), + "!select_cc_fp_int $dst, $lhs, $rhs, $t, $f, $cond", + [(set AR:$dst, (Xtensa_select_cc_fp FPR:$lhs, FPR:$rhs, AR:$t, AR:$f, imm:$cond))]>; + def SELECT_CC_INT_FP : Pseudo<(outs FPR:$dst), (ins AR:$lhs, AR:$rhs, FPR:$t, FPR:$f, i32imm:$cond), + "!select_cc_int_fp $dst, $lhs, $rhs, $t, $f, $cond", + [(set FPR:$dst, (Xtensa_select_cc_fp AR:$lhs, AR:$rhs, FPR:$t, FPR:$f, imm:$cond))]>; + def SELECT_CC_FP_FP : Pseudo<(outs FPR:$dst), (ins FPR:$lhs, FPR:$rhs, FPR:$t, FPR:$f, i32imm:$cond), + "!select_cc_fp_fp $dst, $lhs, $rhs, $t, $f, $cond", + [(set FPR:$dst, (Xtensa_select_cc_fp FPR:$lhs, FPR:$rhs, FPR:$t, FPR:$f, imm:$cond))]>; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index 975d6820802d9..fcb82e400a39f 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -25,9 +25,11 @@ def SDT_XtensaSelectCC : SDTypeProfile<1, 5, SDTCisVT<5, i32>]>; def SDT_XtensaMOVSP : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>; +def SDT_XtensaBrCC : SDTypeProfile<0, 2, [SDTCisVT<0, i1>, SDTCisVT<1, OtherVT>]>; def SDT_XtensaCmp : SDTypeProfile<1, 2, [SDTCisVT<0, i1>, SDTCisVT<1, f32>, SDTCisVT<2, f32>]>; def SDT_XtensaMADD : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisVT<0, f32>]>; def SDT_XtensaMOVS : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, f32>]>; +def SDT_XtensaSelectCCFP : SDTypeProfile<1, 5, [SDTCisSameAs<0, 3>, SDTCisSameAs<1, 2>, SDTCisSameAs<3, 4>, SDTCisVT<5, i32>]>; def SDT_XtensaBrJT : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; @@ -62,10 +64,17 @@ def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, def Xtensa_select : SDNode<"XtensaISD::SELECT", SDTSelect>; def Xtensa_select_cc: SDNode<"XtensaISD::SELECT_CC", SDT_XtensaSelectCC, [SDNPInGlue]>; +def Xtensa_select_cc_fp: SDNode<"XtensaISD::SELECT_CC_FP", SDT_XtensaSelectCCFP, + [SDNPInGlue]>; def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP, [SDNPInGlue]>; +def Xtensa_brcc_t : SDNode<"XtensaISD::BR_CC_T", SDT_XtensaBrCC, + [SDNPHasChain, SDNPInGlue]>; +def Xtensa_brcc_f : SDNode<"XtensaISD::BR_CC_F", SDT_XtensaBrCC, + [SDNPHasChain, SDNPInGlue]>; + def Xtensa_cmpoeq : SDNode<"XtensaISD::CMPOEQ", SDT_XtensaCmp, [SDNPOutGlue]>; def Xtensa_cmpolt : SDNode<"XtensaISD::CMPOLT", SDT_XtensaCmp, [SDNPOutGlue]>; def Xtensa_cmpole : SDNode<"XtensaISD::CMPOLE", SDT_XtensaCmp, [SDNPOutGlue]>; From 803642d3605d00bea66566738378d505cf4e0dfd Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:58 +0300 Subject: [PATCH 039/150] [Xtensa] Implement DAG Combine for FADD and FSUB operations. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 72 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 3 + 2 files changed, 75 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index ada2df227ef5f..c1f225ff6a664 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -257,6 +257,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setCondCodeAction(ISD::SETUGE, MVT::f32, Expand); setCondCodeAction(ISD::SETUGT, MVT::f32, Expand); + setTargetDAGCombine(ISD::FADD); + setTargetDAGCombine(ISD::FSUB); setTargetDAGCombine(ISD::BRCOND); } @@ -291,6 +293,21 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, } } +bool XtensaTargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, + EVT VT) const { + if (!VT.isSimple()) + return false; + + switch (VT.getSimpleVT().SimpleTy) { + case MVT::f32: + return Subtarget.hasSingleFloat(); + default: + break; + } + + return false; +} + bool XtensaTargetLowering::isOffsetFoldingLegal( const GlobalAddressSDNode *GA) const { // The Xtensa target isn't yet aware of offsets. @@ -387,6 +404,57 @@ void XtensaTargetLowering::LowerAsmOperandForConstraint( // DAG Combine functions //===----------------------------------------------------------------------===// +static SDValue performMADD_MSUBCombine(SDNode *ROOTNode, SelectionDAG &CurDAG, + const XtensaSubtarget &Subtarget) { + if (ROOTNode->getOperand(0).getValueType() != MVT::f32) + return SDValue(); + + if (ROOTNode->getOperand(0).getOpcode() != ISD::FMUL && + ROOTNode->getOperand(1).getOpcode() != ISD::FMUL) + return SDValue(); + + SDValue Mult = ROOTNode->getOperand(0).getOpcode() == ISD::FMUL + ? ROOTNode->getOperand(0) + : ROOTNode->getOperand(1); + + SDValue AddOperand = ROOTNode->getOperand(0).getOpcode() == ISD::FMUL + ? ROOTNode->getOperand(1) + : ROOTNode->getOperand(0); + + if (!Mult.hasOneUse()) + return SDValue(); + + SDLoc DL(ROOTNode); + + bool IsAdd = ROOTNode->getOpcode() == ISD::FADD; + unsigned Opcode = IsAdd ? XtensaISD::MADD : XtensaISD::MSUB; + SDValue MAddOps[3] = {AddOperand, Mult->getOperand(0), Mult->getOperand(1)}; + EVT VTs[3] = {MVT::f32, MVT::f32, MVT::f32}; + SDValue MAdd = CurDAG.getNode(Opcode, DL, VTs, MAddOps); + + return MAdd; +} + +static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const XtensaSubtarget &Subtarget) { + if (DCI.isBeforeLegalizeOps()) { + if (Subtarget.hasSingleFloat() && N->getValueType(0) == MVT::f32) + return performMADD_MSUBCombine(N, DAG, Subtarget); + } + return SDValue(); +} + +static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const XtensaSubtarget &Subtarget) { + if (DCI.isBeforeLegalizeOps()) { + if (Subtarget.hasSingleFloat() && N->getValueType(0) == MVT::f32) + return performMADD_MSUBCombine(N, DAG, Subtarget); + } + return SDValue(); +} + static SDValue PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const XtensaSubtarget &Subtarget) { @@ -420,6 +488,10 @@ SDValue XtensaTargetLowering::PerformDAGCombine(SDNode *N, switch (Opc) { default: break; + case ISD::FADD: + return performADDCombine(N, DAG, DCI, Subtarget); + case ISD::FSUB: + return performSUBCombine(N, DAG, DCI, Subtarget); case ISD::BRCOND: return PerformBRCONDCombine(N, DAG, DCI, Subtarget); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index b6534cf67ce44..3f9929b9da2f4 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -99,6 +99,9 @@ class XtensaTargetLowering : public TargetLowering { return VT.changeVectorElementTypeToInteger(); } + bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, + EVT VT) const override; + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; From 23611dc64a5dd841bfd147bd0097028b31ad7c39 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:13:59 +0300 Subject: [PATCH 040/150] [Xtensa] Implement Loop, SEXT and NSA features. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 5 ++ .../Disassembler/XtensaDisassembler.cpp | 13 ++++- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 11 ++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 1 + .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 20 ++++++- llvm/lib/Target/Xtensa/Xtensa.td | 15 +++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 18 ++++-- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 56 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 8 +++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 8 ++- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 3 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 15 +++++ 12 files changed, 163 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 22fdf6ac652d5..4687f75efc429 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -250,6 +250,8 @@ struct XtensaOperand : public MCParsedAsmOperand { return false; } + bool isseimm7_22() const { return isImm(7, 22); } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -452,6 +454,9 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_Invalidentry_imm12: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [0, 32760]"); + case Match_Invalidseimm7_22: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [7, 22]"); } report_fatal_error("Unknown match type detected!"); diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index 098111b170444..f9c0208de297c 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -107,8 +107,9 @@ static DecodeStatus DecodeBRRegisterClass(MCInst &Inst, uint64_t RegNo, } static const unsigned SRDecoderTable[] = { - Xtensa::SAR, 3, Xtensa::BREG, 4, - Xtensa ::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73}; + Xtensa::LBEG, 0, Xtensa::LEND, 1, Xtensa::LCOUNT, 2, + Xtensa::SAR, 3, Xtensa::BREG, 4, Xtensa ::WINDOWBASE, 72, + Xtensa::WINDOWSTART, 73}; static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, @@ -301,6 +302,14 @@ static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeSeimm7_22Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm + 7)); + return MCDisassembler::Success; +} + static int64_t TableB4const[16] = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256}; static DecodeStatus decodeB4constOperand(MCInst &Inst, uint64_t Imm, diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index 489e4eba2d258..c402179368df1 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -411,3 +411,14 @@ void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum, } else printOperand(MI, OpNum, O); } + +void XtensaInstPrinter::printSeimm7_22_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 7 && Value <= 22) && + "Invalid argument, value must be in range <7,22>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index b4f75f0b9c016..62507780ee2a7 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -71,6 +71,7 @@ class XtensaInstPrinter : public MCInstPrinter { void printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printSeimm7_22_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 379783761f588..4870cd5361efa 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -134,6 +134,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + uint32_t getSeimm7_22OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // namespace @@ -284,7 +288,7 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, Res >>= 2; break; } - + switch (MI.getOpcode()) { case Xtensa::S32I_N: case Xtensa::L32I_N: @@ -550,4 +554,18 @@ XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo, return Res; } + +uint32_t +XtensaMCCodeEmitter::getSeimm7_22OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t res = static_cast(MO.getImm()); + + res -= 7; + assert(((res & 0xf) == res) && "Unexpected operand value!"); + + return res; +} + #include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index f6a830c680490..171600e8f3417 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -37,6 +37,21 @@ def FeatureBoolean : SubtargetFeature<"bool", "HasBoolean", "true", def HasBoolean : Predicate<"Subtarget->hasBoolean()">, AssemblerPredicate<(all_of FeatureBoolean)>; +def FeatureLoop : SubtargetFeature<"loop", "HasLoop", "true", + "Enable Xtensa Loop extension">; +def HasLoop : Predicate<"Subtarget->hasLoop()">, + AssemblerPredicate<(all_of FeatureLoop)>; + +def FeatureSEXT : SubtargetFeature<"sext", "HasSEXT", "true", + "Enable Xtensa Sign Extend option">; +def HasSEXT : Predicate<"Subtarget->hasSEXT()">, + AssemblerPredicate<(all_of FeatureSEXT)>; + +def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true", + "Enable Xtensa NSA option">; +def HasNSA : Predicate<"Subtarget->hasNSA()">, + AssemblerPredicate<(all_of FeatureNSA)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index c1f225ff6a664..419cb18a332da 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -1928,14 +1928,22 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( BuildMI(*MBB, MI, DL, TII.get(Xtensa::L8UI), R1).add(Op1).add(Op2); - unsigned R2 = MRI.createVirtualRegister(RC); - BuildMI(*MBB, MI, DL, TII.get(Xtensa::SLLI), R2).addReg(R1).addImm(24); - BuildMI(*MBB, MI, DL, TII.get(Xtensa::SRAI), R.getReg()) - .addReg(R2) - .addImm(24); + if (Subtarget.hasSEXT()) { + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SEXT), R.getReg()) + .addReg(R1) + .addImm(7); + } else { + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SLLI), R2).addReg(R1).addImm(24); + BuildMI(*MBB, MI, DL, TII.get(Xtensa::SRAI), R.getReg()) + .addReg(R2) + .addImm(24); + } + MI.eraseFromParent(); return MBB; } + case Xtensa::S8I: case Xtensa::S16I: case Xtensa::S32I: diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 002add6574f23..f465f50e78639 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1113,3 +1113,59 @@ let usesCustomInserter = 1 in { "!select_cc_fp_fp $dst, $lhs, $rhs, $t, $f, $cond", [(set FPR:$dst, (Xtensa_select_cc_fp FPR:$lhs, FPR:$rhs, FPR:$t, FPR:$f, imm:$cond))]>; } + +//===----------------------------------------------------------------------===// +// Loop Instructions +//===----------------------------------------------------------------------===// + +def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, mem8:$uimm8), + "loop\t$$s, $uimm8", []>, Requires<[HasLoop]> { + bits<8> uimm8; + + let r = 0x08; + let t = 0x07; + let imm8 = uimm8; +} + +def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, mem8:$uimm8), + "loopgtz\t$$s, $uimm8", []>, Requires<[HasLoop]> { + bits<8> uimm8; + + let r = 0x0A; + let t = 0x07; + let imm8 = uimm8; +} + +def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, mem8:$uimm8), + "loopnez\t$$s, $uimm8", []>, Requires<[HasLoop]> { + bits<8> uimm8; + + let r = 0x09; + let t = 0x07; + let imm8 = uimm8; +} + +//===----------------------------------------------------------------------===// +// SEXT Instructions +//===----------------------------------------------------------------------===// + +def SEXT : RRR_Inst<0x00, 0x03, 0x02, (outs AR:$r), (ins AR:$s, seimm7_22:$imm), + "sext\t$r, $s, $imm", []>, Requires<[HasSEXT]> { + bits<4> imm; + + let t = imm; +} + +//===----------------------------------------------------------------------===// +// NSA Instructions +//===----------------------------------------------------------------------===// + +def NSA : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), + "nsa\t$t, $s", []>, Requires<[HasNSA]> { + let r = 0xE; +} + +def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), + "nsau\t$t, $s", []>, Requires<[HasNSA]> { + let r = 0xF; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 47946596282ad..1ea3eeab0e363 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -167,6 +167,14 @@ def b4constu: Immediate; +def seimm7_22: Immediate= 7 && Imm <= 22; }], "Seimm7_22_AsmOperand"> { + let EncoderMethod = "getSeimm7_22OpValue"; + let DecoderMethod = "decodeSeimm7_22Operand"; +} + //===----------------------------------------------------------------------===// // Memory address operands //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 18341287347d2..d7fbdcff09b98 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -72,6 +72,10 @@ class SRReg num, string n, list alt = []> : XtensaReg { let AltNames = alt; } +def LBEG : SRReg<0, "lbeg", ["LBEG", "0"]>; +def LEND : SRReg<1, "lend", ["LEND", "1"]>; +def LCOUNT : SRReg<2, "lcount", ["LCOUNT", "2"]>; + // Shift Amount Register def SAR : SRReg<3, "sar", ["SAR","3"]>; @@ -80,8 +84,8 @@ def BREG : SRReg<4, "br", ["BR", "4"]>; def WINDOWBASE : SRReg<72, "windowbase", ["WINDOWBASE", "72"]>; def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>; -def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR, - BREG, WINDOWBASE, WINDOWSTART)>; +def SR : RegisterClass<"Xtensa", [i32], 32, (add LBEG, LEND, LCOUNT, + SAR, BREG, WINDOWBASE, WINDOWSTART)>; //===----------------------------------------------------------------------===// // USER registers diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index a878477726da7..d6cc451e0268a 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -36,6 +36,9 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasSingleFloat = false; HasWindowed = false; HasBoolean = false; + HasLoop = false; + HasSEXT = false; + HasNSA = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index 3e2cbbee972fb..ba619caffc0f5 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -50,6 +50,15 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enabled Xtensa Boolean extension bool HasBoolean; + // Enabled Xtensa Loop extension + bool HasLoop; + + // Enable Xtensa Sign Extend option + bool HasSEXT; + + // Enable Xtensa NSA option + bool HasNSA; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -75,6 +84,12 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasBoolean() const { return HasBoolean; } + bool hasLoop() const { return HasLoop; } + + bool hasSEXT() const { return HasSEXT; } + + bool hasNSA() const { return HasNSA; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; From 81aced351a5aebb41b77b684c23082c840008e15 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:32 +0300 Subject: [PATCH 041/150] [Xtensa] Implement Mul32, Mul32High and Div32 features. --- llvm/lib/Target/Xtensa/Xtensa.td | 15 ++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 30 ++++++++++++++----- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 17 +++++++++++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 3 ++ llvm/lib/Target/Xtensa/XtensaSubtarget.h | 15 ++++++++++ 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 171600e8f3417..b7351fcd774d2 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -52,6 +52,21 @@ def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true", def HasNSA : Predicate<"Subtarget->hasNSA()">, AssemblerPredicate<(all_of FeatureNSA)>; +def FeatureMul32 : SubtargetFeature<"mul32", "HasMul32", "true", + "Enable Xtensa Mul32 option">; +def HasMul32 : Predicate<"Subtarget->hasMul32()">, + AssemblerPredicate<(all_of FeatureMul32)>; + +def FeatureMul32High : SubtargetFeature<"mul32high", "HasMul32High", "true", + "Enable Xtensa Mul32High option">; +def HasMul32High : Predicate<"Subtarget->hasMul32High()">, + AssemblerPredicate<(all_of FeatureMul32High)>; + +def FeatureDiv32 : SubtargetFeature<"div32", "HasDiv32", "true", + "Enable Xtensa Div32 option">; +def HasDiv32 : Predicate<"Subtarget->hasDiv32()">, + AssemblerPredicate<(all_of FeatureDiv32)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 419cb18a332da..041ef1aafcaf3 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -140,17 +140,33 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, } } - setOperationAction(ISD::MUL, MVT::i32, Expand); - setOperationAction(ISD::MULHU, MVT::i32, Expand); - setOperationAction(ISD::MULHS, MVT::i32, Expand); + if (Subtarget.hasMul32()) + setOperationAction(ISD::MUL, MVT::i32, Legal); + else + setOperationAction(ISD::MUL, MVT::i32, Expand); + + if (Subtarget.hasMul32High()) { + setOperationAction(ISD::MULHU, MVT::i32, Legal); + setOperationAction(ISD::MULHS, MVT::i32, Legal); + } else { + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + } setOperationAction(ISD::MUL, MVT::i64, Expand); setOperationAction(ISD::MULHS, MVT::i64, Expand); setOperationAction(ISD::MULHU, MVT::i64, Expand); - setOperationAction(ISD::SDIV, MVT::i32, Expand); - setOperationAction(ISD::UDIV, MVT::i32, Expand); - setOperationAction(ISD::SREM, MVT::i32, Expand); - setOperationAction(ISD::UREM, MVT::i32, Expand); + if (Subtarget.hasDiv32()) { + setOperationAction(ISD::SDIV, MVT::i32, Legal); + setOperationAction(ISD::UDIV, MVT::i32, Legal); + setOperationAction(ISD::SREM, MVT::i32, Legal); + setOperationAction(ISD::UREM, MVT::i32, Legal); + } else { + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + } setOperationAction(ISD::SDIV, MVT::i64, Expand); setOperationAction(ISD::UDIV, MVT::i64, Expand); diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index f465f50e78639..b651db6fa4e2a 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1169,3 +1169,20 @@ def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), "nsau\t$t, $s", []>, Requires<[HasNSA]> { let r = 0xF; } + +//===----------------------------------------------------------------------===// +// Mul32 Instructions +//===----------------------------------------------------------------------===// + +def MULL : ArithLogic_RRR<0x08, 0x02, "mull", mul, 1>, Requires<[HasMul32]>; +def MULUH : ArithLogic_RRR<0x0A, 0x02, "muluh", mulhu, 1>, Requires<[HasMul32High]>; +def MULSH : ArithLogic_RRR<0x0B, 0x02, "mulsh", mulhs, 1>, Requires<[HasMul32High]>; + +//===----------------------------------------------------------------------===// +// Div32 Instructions +//===----------------------------------------------------------------------===// + +def QUOS : ArithLogic_RRR<0x0D, 0x02, "quos", sdiv>, Requires<[HasDiv32]>; +def QUOU : ArithLogic_RRR<0x0C, 0x02, "quou", udiv>, Requires<[HasDiv32]>; +def REMS : ArithLogic_RRR<0x0F, 0x02, "rems", srem>, Requires<[HasDiv32]>; +def REMU : ArithLogic_RRR<0x0E, 0x02, "remu", urem>, Requires<[HasDiv32]>; diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index d6cc451e0268a..03fd8cb99cb9f 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -39,6 +39,9 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasLoop = false; HasSEXT = false; HasNSA = false; + HasMul32 = false; + HasMul32High = false; + HasDiv32 = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index ba619caffc0f5..f129ddbdb893b 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -59,6 +59,15 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enable Xtensa NSA option bool HasNSA; + // Enable Xtensa Mul32 option + bool HasMul32; + + // Enable Xtensa Mul32High option + bool HasMul32High; + + // Enable Xtensa Div32 option + bool HasDiv32; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -90,6 +99,12 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasNSA() const { return HasNSA; } + bool hasMul32() const { return HasMul32; } + + bool hasMul32High() const { return HasMul32High; } + + bool hasDiv32() const { return HasDiv32; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; From 3ad1b650c05ac2c9076395adf7e23eefe9189cde Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:32 +0300 Subject: [PATCH 042/150] [Xtensa] Implement Mac16 feature and operations. --- .../Disassembler/XtensaDisassembler.cpp | 47 ++- llvm/lib/Target/Xtensa/Xtensa.td | 5 + llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td | 353 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 5 + llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 12 +- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 5 + llvm/test/MC/Xtensa/xtensa-valid-mac16.s | 234 ++++++++++++ 8 files changed, 658 insertions(+), 4 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-mac16.s diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index f9c0208de297c..f169175e53093 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -106,10 +106,51 @@ static DecodeStatus DecodeBRRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Success; } +static const unsigned MRDecoderTable[] = {Xtensa::M0, Xtensa::M1, Xtensa::M2, + Xtensa::M3}; + +static DecodeStatus DecodeMRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= array_lengthof(MRDecoderTable)) + return MCDisassembler::Fail; + + unsigned Reg = MRDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static const unsigned MR01DecoderTable[] = {Xtensa::M0, Xtensa::M1}; + +static DecodeStatus DecodeMR01RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 2) + return MCDisassembler::Fail; + + unsigned Reg = MR01DecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static const unsigned MR23DecoderTable[] = {Xtensa::M2, Xtensa::M3}; + +static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if ((RegNo < 2) || (RegNo > 3)) + return MCDisassembler::Fail; + + unsigned Reg = MR23DecoderTable[RegNo - 2]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + static const unsigned SRDecoderTable[] = { - Xtensa::LBEG, 0, Xtensa::LEND, 1, Xtensa::LCOUNT, 2, - Xtensa::SAR, 3, Xtensa::BREG, 4, Xtensa ::WINDOWBASE, 72, - Xtensa::WINDOWSTART, 73}; + Xtensa::LEND, 1, Xtensa::LCOUNT, 2, Xtensa::SAR, 3, + Xtensa::BREG, 4, Xtensa::ACCLO, 16, Xtensa::ACCHI, 17, + Xtensa::M0, 32, Xtensa::M1, 33, Xtensa::M2, 34, + Xtensa::M3, 35, Xtensa ::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73}; static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index b7351fcd774d2..b2cd3e5a08f1b 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -67,6 +67,11 @@ def FeatureDiv32 : SubtargetFeature<"div32", "HasDiv32", "true", def HasDiv32 : Predicate<"Subtarget->hasDiv32()">, AssemblerPredicate<(all_of FeatureDiv32)>; +def FeatureMAC16 : SubtargetFeature<"mac16", "HasMAC16", "true", + "Enable Xtensa MAC16 instructions">; +def HasMAC16 : Predicate<"Subtarget->hasMAC16()">, + AssemblerPredicate<(all_of FeatureMAC16)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td new file mode 100644 index 0000000000000..d80df46320643 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td @@ -0,0 +1,353 @@ +//===- XtensaDSPInstrInfo.td - Xtensa Target Description ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 describes the Xtensa DSP instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +// Multiply +class UMUL_AA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), + instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + let r = 0; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def UMUL_AA_LL : UMUL_AA<0x00, "umul.aa.ll">; +def UMUL_AA_HL : UMUL_AA<0x01, "umul.aa.hl">; +def UMUL_AA_LH : UMUL_AA<0x02, "umul.aa.lh">; +def UMUL_AA_HH : UMUL_AA<0x03, "umul.aa.hh">; + +class MUL_AA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), + instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + let r = 0; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MUL_AA_LL : MUL_AA<0x04, "mul.aa.ll">; +def MUL_AA_HL : MUL_AA<0x05, "mul.aa.hl">; +def MUL_AA_LH : MUL_AA<0x06, "mul.aa.lh">; +def MUL_AA_HH : MUL_AA<0x07, "mul.aa.hh">; + +class MUL_AD oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x03, (outs), (ins AR:$s, MR23:$y), + instrAsm#"\t$s, $y", []>, Requires<[HasMAC16]> { + bits<2> y; + + let r = 0; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MUL_AD_LL : MUL_AD<0x04, "mul.ad.ll">; +def MUL_AD_HL : MUL_AD<0x05, "mul.ad.hl">; +def MUL_AD_LH : MUL_AD<0x06, "mul.ad.lh">; +def MUL_AD_HH : MUL_AD<0x07, "mul.ad.hh">; + +class MUL_DA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x06, (outs), (ins MR01:$x, AR:$t), + instrAsm#"\t$x, $t", []>, Requires<[HasMAC16]> { + bits<2> x; + + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = 0; + let s = 0; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MUL_DA_LL : MUL_DA<0x04, "mul.da.ll">; +def MUL_DA_HL : MUL_DA<0x05, "mul.da.hl">; +def MUL_DA_LH : MUL_DA<0x06, "mul.da.lh">; +def MUL_DA_HH : MUL_DA<0x07, "mul.da.hh">; + +class MUL_DD oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x02, (outs), (ins MR01:$x, MR23:$y), + instrAsm#"\t$x, $y", []>, Requires<[HasMAC16]> { + bits<2> x; + bits<2> y; + + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = 0; + let s = 0; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MUL_DD_LL : MUL_DD<0x04, "mul.dd.ll">; +def MUL_DD_HL : MUL_DD<0x05, "mul.dd.hl">; +def MUL_DD_LH : MUL_DD<0x06, "mul.dd.lh">; +def MUL_DD_HH : MUL_DD<0x07, "mul.dd.hh">; + +class MULA_AA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), + instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + let r = 0; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_AA_LL : MULA_AA<0x08, "mula.aa.ll">; +def MULA_AA_HL : MULA_AA<0x09, "mula.aa.hl">; +def MULA_AA_LH : MULA_AA<0x0A, "mula.aa.lh">; +def MULA_AA_HH : MULA_AA<0x0B, "mula.aa.hh">; + +class MULA_AD oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x03, (outs), (ins AR:$s, MR23:$y), + instrAsm#"\t$s, $y", []>, Requires<[HasMAC16]> { + bits<2> y; + + let r = 0; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_AD_LL : MULA_AD<0x08, "mula.ad.ll">; +def MULA_AD_HL : MULA_AD<0x09, "mula.ad.hl">; +def MULA_AD_LH : MULA_AD<0x0A, "mula.ad.lh">; +def MULA_AD_HH : MULA_AD<0x0B, "mula.ad.hh">; + +class MULA_DA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x06, (outs), (ins MR01:$x, AR:$t), + instrAsm#"\t$x, $t", []>, Requires<[HasMAC16]> { + bits<2> x; + + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = 0; + let s = 0; + + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_DA_LL : MULA_DA<0x08, "mula.da.ll">; +def MULA_DA_HL : MULA_DA<0x09, "mula.da.hl">; +def MULA_DA_LH : MULA_DA<0x0A, "mula.da.lh">; +def MULA_DA_HH : MULA_DA<0x0B, "mula.da.hh">; + +class MULA_DD oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x02, (outs), (ins MR01:$x, MR23:$y), + instrAsm#"\t$x, $y", []>, Requires<[HasMAC16]> { + bits<2> x; + bits<2> y; + + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = 0; + let s = 0; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_DD_LL : MULA_DD<0x08, "mula.dd.ll">; +def MULA_DD_HL : MULA_DD<0x09, "mula.dd.hl">; +def MULA_DD_LH : MULA_DD<0x0A, "mula.dd.lh">; +def MULA_DD_HH : MULA_DD<0x0B, "mula.dd.hh">; + +class MULS_AA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), + instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + let r = 0; + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULS_AA_LL : MULS_AA<0x0C, "muls.aa.ll">; +def MULS_AA_HL : MULS_AA<0x0D, "muls.aa.hl">; +def MULS_AA_LH : MULS_AA<0x0E, "muls.aa.lh">; +def MULS_AA_HH : MULS_AA<0x0F, "muls.aa.hh">; + +class MULS_AD oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x03, (outs), (ins AR:$s, MR23:$y), + instrAsm#"\t$s, $y", []>, Requires<[HasMAC16]> { + bits<2> y; + + let r = 0; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULS_AD_LL : MULS_AD<0x0C, "muls.ad.ll">; +def MULS_AD_HL : MULS_AD<0x0D, "muls.ad.hl">; +def MULS_AD_LH : MULS_AD<0x0E, "muls.ad.lh">; +def MULS_AD_HH : MULS_AD<0x0F, "muls.ad.hh">; + +class MULS_DA oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x06, (outs), (ins MR01:$x, AR:$t), + instrAsm#"\t$x, $t", []>, Requires<[HasMAC16]> { + bits<2> x; + + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = 0; + let s = 0; + + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULS_DA_LL : MULS_DA<0x0C, "muls.da.ll">; +def MULS_DA_HL : MULS_DA<0x0D, "muls.da.hl">; +def MULS_DA_LH : MULS_DA<0x0E, "muls.da.lh">; +def MULS_DA_HH : MULS_DA<0x0F, "muls.da.hh">; + +class MULS_DD oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x02, (outs), (ins MR01:$x, MR23:$y), + instrAsm#"\t$x, $y", []>, Requires<[HasMAC16]> { + bits<2> x; + bits<2> y; + + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = 0; + let s = 0; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULS_DD_LL : MULS_DD<0x0C, "muls.dd.ll">; +def MULS_DD_HL : MULS_DD<0x0D, "muls.dd.hl">; +def MULS_DD_LH : MULS_DD<0x0E, "muls.dd.lh">; +def MULS_DD_HH : MULS_DD<0x0F, "muls.dd.hh">; + +//===----------------------------------------------------------------------===// +// Multiply-accumulate with load + +class MULA_DA_LDDEC oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x05, (outs MR:$w, AR:$d), (ins AR:$s, MR01:$x, AR:$t), + instrAsm#"\t $w, $s, $x, $t", []>, Requires<[HasMAC16]> { + bits<2> x; + bits<2> w; + + let Constraints = "$s = $d"; + let mayLoad = 1; + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = w{1-0}; + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_DA_LL_LDDEC : MULA_DA_LDDEC<0x08, "mula.da.ll.lddec">; +def MULA_DA_HL_LDDEC : MULA_DA_LDDEC<0x09, "mula.da.hl.lddec">; +def MULA_DA_LH_LDDEC : MULA_DA_LDDEC<0x0A, "mula.da.lh.lddec">; +def MULA_DA_HH_LDDEC : MULA_DA_LDDEC<0x0B, "mula.da.hh.lddec">; + +class MULA_DA_LDINC oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x04, (outs MR:$w, AR:$d), (ins AR:$s, MR:$x, AR:$t), + instrAsm#"\t $w, $s, $x, $t", []>, Requires<[HasMAC16]> { + bits<1> x; + bits<2> w; + + let Constraints = "$s = $d"; + let mayLoad = 1; + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = w{1-0}; + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_DA_LL_LDINC: MULA_DA_LDINC<0x08, "mula.da.ll.ldinc">; +def MULA_DA_HL_LDINC: MULA_DA_LDINC<0x09, "mula.da.hl.ldinc">; +def MULA_DA_LH_LDINC: MULA_DA_LDINC<0x0A, "mula.da.lh.ldinc">; +def MULA_DA_HH_LDINC: MULA_DA_LDINC<0x0B, "mula.da.hh.ldinc">; + +class MULA_DD_LDDEC oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x01, (outs MR:$w, AR:$d), (ins AR:$s, MR01:$x, MR23:$y), + instrAsm#"\t $w, $s, $x, $y", []>, Requires<[HasMAC16]> { + bits<2> x; + bits<2> y; + bits<2> w; + + let Constraints = "$s = $d"; + let mayLoad = 1; + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = w{1-0}; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_DD_LL_LDDEC : MULA_DD_LDDEC<0x08, "mula.dd.ll.lddec">; +def MULA_DD_HL_LDDEC : MULA_DD_LDDEC<0x09, "mula.dd.hl.lddec">; +def MULA_DD_LH_LDDEC : MULA_DD_LDDEC<0x0A, "mula.dd.lh.lddec">; +def MULA_DD_HH_LDDEC : MULA_DD_LDDEC<0x0B, "mula.dd.hh.lddec">; + +class MULA_DD_LDINC oper1, string instrAsm> + : RRR_Inst<0x04, oper1, 0x00, (outs MR:$w, AR:$d), (ins AR:$s, MR01:$x, MR23:$y), + instrAsm#"\t $w, $s, $x, $y", []>, Requires<[HasMAC16]> { + bits<2> x; + bits<2> y; + bits<2> w; + + let Constraints = "$s = $d"; + let mayLoad = 1; + let r{3} = 0; + let r{2} = x{0}; + let r{1-0} = w{1-0}; + let t{3} = 0; + let t{2} = y{0}; + let t{1-0} = 0; + let Uses = [ACCLO, ACCHI]; + let Defs = [M1, M2, ACCLO, ACCHI]; +} + +def MULA_DD_LL_LDINC : MULA_DD_LDINC<0x08, "mula.dd.ll.ldinc">; +def MULA_DD_HL_LDINC : MULA_DD_LDINC<0x09, "mula.dd.hl.ldinc">; +def MULA_DD_LH_LDINC : MULA_DD_LDINC<0x0A, "mula.dd.lh.ldinc">; +def MULA_DD_HH_LDINC : MULA_DD_LDINC<0x0B, "mula.dd.hh.ldinc">; + +def LDDEC : RRR_Inst<0x04, 0x00, 0x09, (outs MR:$w, AR:$d), (ins AR:$s), + "lddec\t $w, $s", []>, Requires<[HasMAC16]> { + bits<2> w; + + let Constraints = "$s = $d"; + let mayLoad = 1; + let r{3-2} = 0; + let r{1-0} = w{1-0}; + let t = 0x00; +} + +def LDINC : RRR_Inst<0x04, 0x00, 0x08, (outs MR:$w, AR:$d), (ins AR:$s), + "ldinc\t $w, $s", []>, Requires<[HasMAC16]> { + bits<2> w; + + let Constraints = "$s = $d"; + let mayLoad = 1; + let r{3-2} = 0; + let r{1-0} = w{1-0}; + let t = 0; +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index b651db6fa4e2a..774417f8b020c 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1186,3 +1186,8 @@ def QUOS : ArithLogic_RRR<0x0D, 0x02, "quos", sdiv>, Requires<[HasDiv32]>; def QUOU : ArithLogic_RRR<0x0C, 0x02, "quou", udiv>, Requires<[HasDiv32]>; def REMS : ArithLogic_RRR<0x0F, 0x02, "rems", srem>, Requires<[HasDiv32]>; def REMU : ArithLogic_RRR<0x0E, 0x02, "remu", urem>, Requires<[HasDiv32]>; + +//===----------------------------------------------------------------------===// +// DSP Instructions +//===----------------------------------------------------------------------===// +include "XtensaDSPInstrInfo.td" diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index d7fbdcff09b98..4e953f7bfe159 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -81,11 +81,21 @@ def SAR : SRReg<3, "sar", ["SAR","3"]>; def BREG : SRReg<4, "br", ["BR", "4"]>; +def ACCLO : SRReg<16, "acclo", ["ACCLO", "16"]>; +def ACCHI : SRReg<17, "acchi", ["ACCHI", "17"]>; +def M0 : SRReg<32, "m0", ["M0", "32"]>; +def M1 : SRReg<33, "m1", ["M1", "33"]>; +def M2 : SRReg<34, "m2", ["M2", "34"]>; +def M3 : SRReg<35, "m3", ["M3", "35"]>; def WINDOWBASE : SRReg<72, "windowbase", ["WINDOWBASE", "72"]>; def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>; +def MR01 : RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>; +def MR23 : RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>; +def MR : RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>; + def SR : RegisterClass<"Xtensa", [i32], 32, (add LBEG, LEND, LCOUNT, - SAR, BREG, WINDOWBASE, WINDOWSTART)>; + SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>; //===----------------------------------------------------------------------===// // USER registers diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index 03fd8cb99cb9f..b23346ea4335c 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -42,6 +42,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasMul32 = false; HasMul32High = false; HasDiv32 = false; + HasMAC16 = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index f129ddbdb893b..a4bfd2ae39567 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -68,6 +68,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enable Xtensa Div32 option bool HasDiv32; + // Enabled Xtensa MAC16 instructions + bool HasMAC16; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -105,6 +108,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasDiv32() const { return HasDiv32; } + bool hasMAC16() const { return HasMAC16; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; diff --git a/llvm/test/MC/Xtensa/xtensa-valid-mac16.s b/llvm/test/MC/Xtensa/xtensa-valid-mac16.s new file mode 100644 index 0000000000000..dee79da7755d9 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-mac16.s @@ -0,0 +1,234 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+mac16 -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: umul.aa.ll a2, a3 +# CHECK: encoding: [0x34,0x02,0x70] + umul.aa.ll a2, a3 +# CHECK-INST: umul.aa.lh a2, a3 +# CHECK: encoding: [0x34,0x02,0x72] + umul.aa.lh a2, a3 +# CHECK-INST: umul.aa.hl a2, a3 +# CHECK: encoding: [0x34,0x02,0x71] + umul.aa.hl a2, a3 +# CHECK-INST: umul.aa.hh a2, a3 +# CHECK: encoding: [0x34,0x02,0x73] + umul.aa.hh a2, a3 + +# CHECK-INST: mul.aa.ll a2, a3 +# CHECK: encoding: [0x34,0x02,0x74] + mul.aa.ll a2, a3 +# CHECK-INST: mul.aa.lh a2, a3 +# CHECK: encoding: [0x34,0x02,0x76] + mul.aa.lh a2, a3 +# CHECK-INST: mul.aa.hl a2, a3 +# CHECK: encoding: [0x34,0x02,0x75] + mul.aa.hl a2, a3 +# CHECK-INST: mul.aa.hh a2, a3 +# CHECK: encoding: [0x34,0x02,0x77] + mul.aa.hh a2, a3 + +# CHECK-INST: mul.ad.ll a2, m2 +# CHECK: encoding: [0x04,0x02,0x34] + mul.ad.ll a2, m2 +# CHECK-INST: mul.ad.lh a2, m2 +# CHECK: encoding: [0x04,0x02,0x36] + mul.ad.lh a2, m2 +# CHECK-INST: mul.ad.hl a2, m2 +# CHECK: encoding: [0x04,0x02,0x35] + mul.ad.hl a2, m2 +# CHECK-INST: mul.ad.hh a2, m2 +# CHECK: encoding: [0x04,0x02,0x37] + mul.ad.hh a2, m2 + +# CHECK-INST: mul.da.ll m1, a3 +# CHECK: encoding: [0x34,0x40,0x64] + mul.da.ll m1, a3 +# CHECK-INST: mul.da.lh m1, a3 +# CHECK: encoding: [0x34,0x40,0x66] + mul.da.lh m1, a3 +# CHECK-INST: mul.da.hl m1, a3 +# CHECK: encoding: [0x34,0x40,0x65] + mul.da.hl m1, a3 +# CHECK-INST: mul.da.hh m1, a3 +# CHECK: encoding: [0x34,0x40,0x67] + mul.da.hh m1, a3 + +# CHECK-INST: mul.dd.ll m1, m2 +# CHECK: encoding: [0x04,0x40,0x24] + mul.dd.ll m1, m2 +# CHECK-INST: mul.dd.lh m1, m2 +# CHECK: encoding: [0x04,0x40,0x26] + mul.dd.lh m1, m2 +# CHECK-INST: mul.dd.hl m1, m2 +# CHECK: encoding: [0x04,0x40,0x25] + mul.dd.hl m1, m2 +# CHECK-INST: mul.dd.hh m1, m2 +# CHECK: encoding: [0x04,0x40,0x27] + mul.dd.hh m1, m2 + +# CHECK-INST: mula.aa.ll a2, a3 +# CHECK: encoding: [0x34,0x02,0x78] + mula.aa.ll a2, a3 +# CHECK-INST: mula.aa.lh a2, a3 +# CHECK: encoding: [0x34,0x02,0x7a] + mula.aa.lh a2, a3 +# CHECK-INST: mula.aa.hl a2, a3 +# CHECK: encoding: [0x34,0x02,0x79] + mula.aa.hl a2, a3 +# CHECK-INST: mula.aa.hh a2, a3 +# CHECK: encoding: [0x34,0x02,0x7b] + mula.aa.hh a2, a3 + +# CHECK-INST: mula.ad.ll a2, m2 +# CHECK: encoding: [0x04,0x02,0x38] + mula.ad.ll a2, m2 +# CHECK-INST: mula.ad.lh a2, m2 +# CHECK: encoding: [0x04,0x02,0x3a] + mula.ad.lh a2, m2 +# CHECK-INST: mula.ad.hl a2, m2 +# CHECK: encoding: [0x04,0x02,0x39] + mula.ad.hl a2, m2 +# CHECK-INST: mula.ad.hh a2, m2 +# CHECK: encoding: [0x04,0x02,0x3b] + mula.ad.hh a2, m2 + +# CHECK-INST: mula.da.ll m1, a3 +# CHECK: encoding: [0x34,0x40,0x68] + mula.da.ll m1, a3 +# CHECK-INST: mula.da.lh m1, a3 +# CHECK: encoding: [0x34,0x40,0x6a] + mula.da.lh m1, a3 +# CHECK-INST: mula.da.hl m1, a3 +# CHECK: encoding: [0x34,0x40,0x69] + mula.da.hl m1, a3 +# CHECK-INST: mula.da.hh m1, a3 +# CHECK: encoding: [0x34,0x40,0x6b] + mula.da.hh m1, a3 + +# CHECK-INST: mula.dd.ll m1, m2 +# CHECK: encoding: [0x04,0x40,0x28] + mula.dd.ll m1, m2 +# CHECK-INST: mula.dd.lh m1, m2 +# CHECK: encoding: [0x04,0x40,0x2a] + mula.dd.lh m1, m2 +# CHECK-INST: mula.dd.hl m1, m2 +# CHECK: encoding: [0x04,0x40,0x29] + mula.dd.hl m1, m2 +# CHECK-INST: mula.dd.hh m1, m2 +# CHECK: encoding: [0x04,0x40,0x2b] + mula.dd.hh m1, m2 + +# CHECK-INST: muls.aa.ll a2, a3 +# CHECK: encoding: [0x34,0x02,0x7c] + muls.aa.ll a2, a3 +# CHECK-INST: muls.aa.lh a2, a3 +# CHECK: encoding: [0x34,0x02,0x7e] + muls.aa.lh a2, a3 +# CHECK-INST: muls.aa.hl a2, a3 +# CHECK: encoding: [0x34,0x02,0x7d] + muls.aa.hl a2, a3 +# CHECK-INST: muls.aa.hh a2, a3 +# CHECK: encoding: [0x34,0x02,0x7f] + muls.aa.hh a2, a3 + +# CHECK-INST: muls.ad.ll a2, m2 +# CHECK: encoding: [0x04,0x02,0x3c] + muls.ad.ll a2, m2 +# CHECK-INST: muls.ad.lh a2, m2 +# CHECK: encoding: [0x04,0x02,0x3e] + muls.ad.lh a2, m2 +# CHECK-INST: muls.ad.hl a2, m2 +# CHECK: encoding: [0x04,0x02,0x3d] + muls.ad.hl a2, m2 +# CHECK-INST: muls.ad.hh a2, m2 +# CHECK: encoding: [0x04,0x02,0x3f] + muls.ad.hh a2, m2 + +# CHECK-INST: muls.da.ll m1, a3 +# CHECK: encoding: [0x34,0x40,0x6c] + muls.da.ll m1, a3 +# CHECK-INST: muls.da.lh m1, a3 +# CHECK: encoding: [0x34,0x40,0x6e] + muls.da.lh m1, a3 +# CHECK-INST: muls.da.hl m1, a3 +# CHECK: encoding: [0x34,0x40,0x6d] + muls.da.hl m1, a3 +# CHECK-INST: muls.da.hh m1, a3 +# CHECK: encoding: [0x34,0x40,0x6f] + muls.da.hh m1, a3 + +# CHECK-INST: muls.dd.ll m1, m2 +# CHECK: encoding: [0x04,0x40,0x2c] + muls.dd.ll m1, m2 +# CHECK-INST: muls.dd.lh m1, m2 +# CHECK: encoding: [0x04,0x40,0x2e] + muls.dd.lh m1, m2 +# CHECK-INST: muls.dd.hl m1, m2 +# CHECK: encoding: [0x04,0x40,0x2d] + muls.dd.hl m1, m2 +# CHECK-INST: muls.dd.hh m1, m2 +# CHECK: encoding: [0x04,0x40,0x2f] + muls.dd.hh m1, m2 + +# CHECK-INST: mula.da.ll.lddec m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x58] + mula.da.ll.lddec m1, a8, m0, a3 +# CHECK-INST: mula.da.hl.lddec m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x59] + mula.da.hl.lddec m1, a8, m0, a3 +# CHECK-INST: mula.da.lh.lddec m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x5a] + mula.da.lh.lddec m1, a8, m0, a3 +# CHECK-INST: mula.da.hh.lddec m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x5b] + mula.da.hh.lddec m1, a8, m0, a3 + +# CHECK-INST: mula.dd.ll.lddec m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x18] + mula.dd.ll.lddec m1, a8, m0, m2 +# CHECK-INST: mula.dd.hl.lddec m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x19] + mula.dd.hl.lddec m1, a8, m0, m2 +# CHECK-INST: mula.dd.lh.lddec m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x1a] + mula.dd.lh.lddec m1, a8, m0, m2 +# CHECK-INST: mula.dd.hh.lddec m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x1b] + mula.dd.hh.lddec m1, a8, m0, m2 + +# CHECK-INST: mula.da.ll.ldinc m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x48] + mula.da.ll.ldinc m1, a8, m0, a3 +# CHECK-INST: mula.da.hl.ldinc m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x49] + mula.da.hl.ldinc m1, a8, m0, a3 +# CHECK-INST: mula.da.lh.ldinc m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x4a] + mula.da.lh.ldinc m1, a8, m0, a3 +# CHECK-INST: mula.da.hh.ldinc m1, a8, m0, a3 +# CHECK: encoding: [0x34,0x18,0x4b] + mula.da.hh.ldinc m1, a8, m0, a3 + +# CHECK-INST: mula.dd.ll.ldinc m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x08] + mula.dd.ll.ldinc m1, a8, m0, m2 +# CHECK-INST: mula.dd.hl.ldinc m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x09] + mula.dd.hl.ldinc m1, a8, m0, m2 +# CHECK-INST: mula.dd.lh.ldinc m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x0a] + mula.dd.lh.ldinc m1, a8, m0, m2 +# CHECK-INST: mula.dd.hh.ldinc m1, a8, m0, m2 +# CHECK: encoding: [0x04,0x18,0x0b] + mula.dd.hh.ldinc m1, a8, m0, m2 + +# CHECK-INST: lddec m0, a8 +# CHECK: encoding: [0x04,0x08,0x90] + lddec m0, a8 +# CHECK-INST: ldinc m0, a8 +# CHECK: encoding: [0x04,0x08,0x80] + ldinc m0, a8 + From e627138c78dc65545b45091412024b542057ec17 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:33 +0300 Subject: [PATCH 043/150] [Xtensa] Implement Xtensa features and operations. Implement Debug, DFPAccel, S32C1I, THREADPTR, Extended L32R, ATOMCTL, MEMCTL features. --- .../Disassembler/XtensaDisassembler.cpp | 21 ++++++-- .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 1 + llvm/lib/Target/Xtensa/Xtensa.td | 35 +++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 2 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 39 +++++++++++++++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 49 ++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 7 +++ llvm/lib/Target/Xtensa/XtensaSubtarget.h | 35 +++++++++++++ llvm/test/MC/Xtensa/xtensa-valid-dbg.s | 9 ++++ 9 files changed, 191 insertions(+), 7 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-dbg.s diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index f169175e53093..13e56a5b0a00d 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -147,10 +147,19 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo, } static const unsigned SRDecoderTable[] = { - Xtensa::LEND, 1, Xtensa::LCOUNT, 2, Xtensa::SAR, 3, - Xtensa::BREG, 4, Xtensa::ACCLO, 16, Xtensa::ACCHI, 17, - Xtensa::M0, 32, Xtensa::M1, 33, Xtensa::M2, 34, - Xtensa::M3, 35, Xtensa ::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73}; + Xtensa::LBEG, 0, Xtensa::LEND, 1, + Xtensa::LCOUNT, 2, Xtensa::SAR, 3, + Xtensa::BREG, 4, Xtensa::LITBASE, 5, + Xtensa::ACCLO, 16, Xtensa::ACCHI, 17, + Xtensa::M0, 32, Xtensa::M1, 33, + Xtensa::M2, 34, Xtensa::M3, 35, + Xtensa::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73, + Xtensa::IBREAKENABLE, 96, Xtensa::MEMCTL, 97, + Xtensa::ATOMCTL, 99, Xtensa::IBREAKA0, 128, + Xtensa::IBREAKA1, 129, Xtensa::DBREAKA0, 144, + Xtensa::DBREAKA1, 145, Xtensa::DBREAKC0, 160, + Xtensa::DBREAKC1, 161, Xtensa::DEBUGCAUSE, 233, + Xtensa::ICOUNT, 236, Xtensa::ICOUNTLEVEL, 237}; static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, @@ -169,7 +178,9 @@ static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Fail; } -static const unsigned URDecoderTable[] = {Xtensa::FCR, 232, Xtensa::FSR, 233}; +static const unsigned URDecoderTable[] = { + Xtensa::THREADPTR, 231, Xtensa::FCR, 232, Xtensa::FSR, 233, + Xtensa::F64R_LO, 234, Xtensa::F64R_HI, 235, Xtensa::F64S, 236}; static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 4870cd5361efa..c204e0866e449 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -282,6 +282,7 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, case Xtensa::L32I_N: case Xtensa::S32F: case Xtensa::L32F: + case Xtensa::S32C1I: if (Res & 0x3) { report_fatal_error("Unexpected operand value!"); } diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index b2cd3e5a08f1b..2830d3f44c676 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -72,6 +72,41 @@ def FeatureMAC16 : SubtargetFeature<"mac16", "HasMAC16", "true", def HasMAC16 : Predicate<"Subtarget->hasMAC16()">, AssemblerPredicate<(all_of FeatureMAC16)>; +def FeatureDFPAccel : SubtargetFeature<"dfpaccel", "HasDFPAccel", "true", + "Enable Xtensa Double Precision FP acceleration">; +def HasDFPAccel : Predicate<"Subtarget->hasDFPAccel()">, + AssemblerPredicate<(all_of FeatureDFPAccel)>; + +def FeatureS32C1I : SubtargetFeature<"s32c1i", "HasS32C1I", "true", + "Enable Xtensa S32C1I option">; +def HasS32C1I : Predicate<"Subtarget->hasS32C1I()">, + AssemblerPredicate<(all_of FeatureS32C1I)>; + +def FeatureTHREADPTR : SubtargetFeature<"threadptr", "HasTHREADPTR", "true", + "Enable Xtensa THREADPTR option">; +def HasTHREADPTR : Predicate<"Subtarget->hasTHREADPTR()">, + AssemblerPredicate<(all_of FeatureTHREADPTR)>; + +def FeatureExtendedL32R : SubtargetFeature<"extendedl32r", "HasExtendedL32R", "true", + "Enable Xtensa Extended L32R option">; +def HasExtendedL32R : Predicate<"Subtarget->hasExtendedL32R()">, + AssemblerPredicate<(all_of FeatureExtendedL32R)>; + +def FeatureATOMCTL : SubtargetFeature<"atomctl", "HasATOMCTL", "true", + "Enable Xtensa ATOMCTL option">; +def HasATOMCTL : Predicate<"Subtarget->hasATOMCTL()">, + AssemblerPredicate<(all_of FeatureATOMCTL)>; + +def FeatureMEMCTL : SubtargetFeature<"memctl", "HasMEMCTL", "true", + "Enable Xtensa MEMCTL option">; +def HasMEMCTL : Predicate<"Subtarget->hasMEMCTL()">, + AssemblerPredicate<(all_of FeatureMEMCTL)>; + +def FeatureDebug : SubtargetFeature<"debug", "HasDebug", "true", + "Enable Xtensa Debug option">; +def HasDebug : Predicate<"Subtarget->hasDebug()">, + AssemblerPredicate<(all_of FeatureDebug)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 041ef1aafcaf3..1029906a8b0fb 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -301,6 +301,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::VACOPY, MVT::Other, Custom); setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::TRAP, MVT::Other, Legal); + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 774417f8b020c..6e7c0bc79965c 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1187,6 +1187,45 @@ def QUOU : ArithLogic_RRR<0x0C, 0x02, "quou", udiv>, Requires<[HasDiv32]>; def REMS : ArithLogic_RRR<0x0F, 0x02, "rems", srem>, Requires<[HasDiv32]>; def REMU : ArithLogic_RRR<0x0E, 0x02, "remu", urem>, Requires<[HasDiv32]>; +//===----------------------------------------------------------------------===// +// S32C1I +//===----------------------------------------------------------------------===// + +let mayStore = 1, mayLoad = 1, Predicates = [HasS32C1I] in { + def S32C1I : RRI8_Inst<0x02, (outs AR:$a), (ins AR:$t, mem32:$addr), + "s32c1i\t$t, $addr", []> { + bits<12> addr; + + let r = 0x0e; + let Uses = [SCOMPARE1]; + let Constraints = "$a = $t"; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +//===----------------------------------------------------------------------===// +// Debug instructions +//===----------------------------------------------------------------------===// + +let isBarrier = 1, isTerminator = 1 in { + def BREAK : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins uimm4:$s, uimm4:$t), + "break\t$s, $t", []>, Requires<[HasDebug]> { + let r = 0x04; + } + + def BREAK_N : RRRN_Inst<0x0C, (outs), (ins uimm4:$imm), + "break.n\t$imm", []>, Requires<[HasDensity, HasDebug]> { + bits<4> imm; + + let r = 0xf; + let s = imm; + let t = 0x2; + } +} + +def : Pat<(trap), (BREAK (i32 1), (i32 15))>; + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 4e953f7bfe159..b5d371c2e315a 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -80,6 +80,10 @@ def LCOUNT : SRReg<2, "lcount", ["LCOUNT", "2"]>; def SAR : SRReg<3, "sar", ["SAR","3"]>; def BREG : SRReg<4, "br", ["BR", "4"]>; +def LITBASE : SRReg<5, "litbase", ["LITBASE", "5"]>; + +// Expected data value for S32C1I operation +def SCOMPARE1 : SRReg<12, "scompare1", ["SCOMPARE1", "12"]>; def ACCLO : SRReg<16, "acclo", ["ACCLO", "16"]>; def ACCHI : SRReg<17, "acchi", ["ACCHI", "17"]>; @@ -90,12 +94,46 @@ def M3 : SRReg<35, "m3", ["M3", "35"]>; def WINDOWBASE : SRReg<72, "windowbase", ["WINDOWBASE", "72"]>; def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>; +// Instuction breakpoint enable register +def IBREAKENABLE : SRReg<96, "ibreakenable", ["IBREAKENABLE", "96"]>; + +// Memory Control Register +def MEMCTL : SRReg<97, "memctl", ["MEMCTL", "97"]>; + +def ATOMCTL : SRReg<99, "atomctl", ["ATOMCTL", "99"]>; + +// Instuction break address register 0 +def IBREAKA0 : SRReg<128, "ibreaka0", ["IBREAKA0", "128"]>; + +// Instuction break address register 1 +def IBREAKA1 : SRReg<129, "ibreaka1", ["IBREAKA1", "129"]>; + +// Data break address register 0 +def DBREAKA0 : SRReg<144, "dbreaka0", ["DBREAKA0", "144"]>; + +// Data break address register 1 +def DBREAKA1 : SRReg<145, "dbreaka1", ["DBREAKA1", "145"]>; + +// Data breakpoint control register 0 +def DBREAKC0 : SRReg<160, "dbreakc0", ["DBREAKC0", "160"]>; + +// Data breakpoint control register 1 +def DBREAKC1 : SRReg<161, "dbreakc1", ["DBREAKC1", "161"]>; + +// Cause of last debug exception register +def DEBUGCAUSE : SRReg<233, "debugcause", ["DEBUGCAUSE", "233"]>; + +def ICOUNT : SRReg<236, "icount", ["ICOUNT", "236"]>; +def ICOUNTLEVEL : SRReg<237, "icountlevel", ["ICOUNTLEVEL", "237"]>; + def MR01 : RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>; def MR23 : RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>; def MR : RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>; def SR : RegisterClass<"Xtensa", [i32], 32, (add LBEG, LEND, LCOUNT, - SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>; + SAR, BREG, LITBASE, SCOMPARE1, ACCLO, ACCHI, MR, WINDOWBASE, WINDOWSTART, + IBREAKENABLE, MEMCTL, ATOMCTL, IBREAKA0, IBREAKA1, DBREAKA0, DBREAKA1, + DBREAKC0, DBREAKC1, DEBUGCAUSE, ICOUNT, ICOUNTLEVEL)>; //===----------------------------------------------------------------------===// // USER registers @@ -105,10 +143,17 @@ class URReg num, string n, list alt = []> : XtensaReg { let AltNames = alt; } +// Thread Pointer register +def THREADPTR : URReg<231, "threadptr", ["THREADPTR"]>; + def FCR : URReg<232, "fcr", ["FCR"]>; def FSR : URReg<233, "fsr", ["FSR"]>; +def F64R_LO : URReg<234, "f64r_lo", ["F64R_LO"]>; +def F64R_HI : URReg<235, "f64r_hi", ["F64R_HI"]>; +def F64S : URReg<236, "f64s", ["F64S"]>; -def UR : RegisterClass<"Xtensa", [i32], 32, (add FCR, FSR)>; +def UR : RegisterClass<"Xtensa", [i32], 32, (add THREADPTR, FCR, + FSR, F64R_LO, F64R_HI, F64S)>; //===----------------------------------------------------------------------===// // Floating-Point registers diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index b23346ea4335c..800c62d9cefc6 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -43,6 +43,13 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasMul32High = false; HasDiv32 = false; HasMAC16 = false; + HasDFPAccel = false; + HasS32C1I = false; + HasTHREADPTR = false; + HasExtendedL32R = false; + HasATOMCTL = false; + HasMEMCTL = false; + HasDebug = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index a4bfd2ae39567..eed24f28be153 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -71,6 +71,27 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enabled Xtensa MAC16 instructions bool HasMAC16; + // Enable Xtensa Xtensa Double Precision FP acceleration + bool HasDFPAccel; + + // Enable Xtensa S32C1I option + bool HasS32C1I; + + // Enable Xtensa THREADPTR option + bool HasTHREADPTR; + + // Enable Xtensa Extended L32R option + bool HasExtendedL32R; + + // Enable Xtensa ATOMCTL option + bool HasATOMCTL; + + // Enable Xtensa ATOMCTL option + bool HasMEMCTL; + + // Enable Xtensa Debug option + bool HasDebug; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -110,6 +131,20 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasMAC16() const { return HasMAC16; } + bool hasDFPAccel() const { return HasDFPAccel; } + + bool hasS32C1I() const { return HasS32C1I; } + + bool hasTHREADPTR() const { return HasTHREADPTR; } + + bool hasExtendedL32R() const { return HasExtendedL32R; } + + bool hasATOMCTL() const { return HasATOMCTL; } + + bool hasMEMCTL() const { return HasMEMCTL; } + + bool hasDebug() const { return HasDebug; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; diff --git a/llvm/test/MC/Xtensa/xtensa-valid-dbg.s b/llvm/test/MC/Xtensa/xtensa-valid-dbg.s new file mode 100644 index 0000000000000..9391c60e43f69 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-dbg.s @@ -0,0 +1,9 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+debug -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: break 1, 2 +# CHECK: encoding: [0x20,0x41,0x00] + break 1, 2 From a67a17b7f0400301e0b6c942ccd2bc5cd36a465f Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:33 +0300 Subject: [PATCH 044/150] [Xtensa] Implement Xtensa features and operations. Implement Exception, HighPriInterrupts, Coprocessor, Interrupt, RelocatableVector, TimerInt, PRID, RegionProtection and MiscSR features. Implement instructions for Exception, Interrupt and RegionProtection features with tests. --- .../Disassembler/XtensaDisassembler.cpp | 52 +++++++--- llvm/lib/Target/Xtensa/Xtensa.td | 46 +++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 77 +++++++++++++++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 94 ++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 9 ++ llvm/lib/Target/Xtensa/XtensaSubtarget.h | 45 +++++++++ llvm/test/MC/Xtensa/xtensa-valid-exc.s | 21 +++++ llvm/test/MC/Xtensa/xtensa-valid-int.s | 18 ++++ llvm/test/MC/Xtensa/xtensa-valid-regprotect.s | 14 +++ 9 files changed, 356 insertions(+), 20 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-exc.s create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-int.s create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-regprotect.s diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index 13e56a5b0a00d..cb4a506c7eb75 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -147,19 +147,40 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo, } static const unsigned SRDecoderTable[] = { - Xtensa::LBEG, 0, Xtensa::LEND, 1, - Xtensa::LCOUNT, 2, Xtensa::SAR, 3, - Xtensa::BREG, 4, Xtensa::LITBASE, 5, - Xtensa::ACCLO, 16, Xtensa::ACCHI, 17, - Xtensa::M0, 32, Xtensa::M1, 33, - Xtensa::M2, 34, Xtensa::M3, 35, - Xtensa::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73, - Xtensa::IBREAKENABLE, 96, Xtensa::MEMCTL, 97, - Xtensa::ATOMCTL, 99, Xtensa::IBREAKA0, 128, - Xtensa::IBREAKA1, 129, Xtensa::DBREAKA0, 144, - Xtensa::DBREAKA1, 145, Xtensa::DBREAKC0, 160, - Xtensa::DBREAKC1, 161, Xtensa::DEBUGCAUSE, 233, - Xtensa::ICOUNT, 236, Xtensa::ICOUNTLEVEL, 237}; + Xtensa::LBEG, 0, Xtensa::LEND, 1, + Xtensa::LCOUNT, 2, Xtensa::SAR, 3, + Xtensa::BREG, 4, Xtensa::LITBASE, 5, + Xtensa::SCOMPARE1, 12, Xtensa::ACCLO, 16, + Xtensa::ACCHI, 17, Xtensa::M0, 32, + Xtensa::M1, 33, Xtensa::M2, 34, + Xtensa::M3, 35, Xtensa::WINDOWBASE, 72, + Xtensa::WINDOWSTART, 73, Xtensa::IBREAKENABLE, 96, + Xtensa::MEMCTL, 97, Xtensa::ATOMCTL, 99, + Xtensa::DDR, 104, Xtensa::IBREAKA0, 128, + Xtensa::IBREAKA1, 129, Xtensa::DBREAKA0, 144, + Xtensa::DBREAKA1, 145, Xtensa::DBREAKC0, 160, + Xtensa::DBREAKC1, 161, Xtensa::CONFIGID0, 176, + Xtensa::EPC1, 177, Xtensa::EPC2, 178, + Xtensa::EPC3, 179, Xtensa::EPC4, 180, + Xtensa::EPC5, 181, Xtensa::EPC6, 182, + Xtensa::EPC7, 183, Xtensa::DEPC, 192, + Xtensa::EPS2, 194, Xtensa::EPS3, 195, + Xtensa::EPS4, 196, Xtensa::EPS5, 197, + Xtensa::EPS6, 198, Xtensa::EPS7, 199, + Xtensa::CONFIGID1, 208, Xtensa::EXCSAVE1, 209, + Xtensa::EXCSAVE2, 210, Xtensa::EXCSAVE3, 211, + Xtensa::EXCSAVE4, 212, Xtensa::EXCSAVE5, 213, + Xtensa::EXCSAVE6, 214, Xtensa::EXCSAVE7, 215, + Xtensa::CPENABLE, 224, Xtensa::INTSET, 226, + Xtensa::INTCLEAR, 227, Xtensa::INTENABLE, 228, + Xtensa::PS, 230, Xtensa::VECBASE, 231, + Xtensa::EXCCAUSE, 232, Xtensa::DEBUGCAUSE, 233, + Xtensa::CCOUNT, 234, Xtensa::PRID, 235, + Xtensa::ICOUNT, 236, Xtensa::ICOUNTLEVEL, 237, + Xtensa::EXCVADDR, 238, Xtensa::CCOMPARE0, 240, + Xtensa::CCOMPARE1, 241, Xtensa::CCOMPARE2, 242, + Xtensa::MISC0, 244, Xtensa::MISC1, 245, + Xtensa::MISC2, 246, Xtensa::MISC3, 247}; static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, @@ -179,8 +200,9 @@ static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, } static const unsigned URDecoderTable[] = { - Xtensa::THREADPTR, 231, Xtensa::FCR, 232, Xtensa::FSR, 233, - Xtensa::F64R_LO, 234, Xtensa::F64R_HI, 235, Xtensa::F64S, 236}; + Xtensa::EXPSTATE, 230, Xtensa::THREADPTR, 231, Xtensa::FCR, 232, + Xtensa::FSR, 233, Xtensa::F64R_LO, 234, Xtensa::F64R_HI, 235, + Xtensa::F64S, 236}; static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 2830d3f44c676..27137a2edf956 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -107,6 +107,52 @@ def FeatureDebug : SubtargetFeature<"debug", "HasDebug", "true", def HasDebug : Predicate<"Subtarget->hasDebug()">, AssemblerPredicate<(all_of FeatureDebug)>; +def FeatureException : SubtargetFeature<"exception", "HasException", "true", + "Enable Xtensa Exception option">; +def HasException : Predicate<"Subtarget->hasException()">, + AssemblerPredicate<(all_of FeatureException)>; + +def FeatureHighPriInterrupts : SubtargetFeature<"highpriinterrupts", + "HasHighPriInterrupts", "true", + "Enable Xtensa HighPriInterrupts option">; +def HasHighPriInterrupts : Predicate<"Subtarget->hasHighPriInterrupts()">, + AssemblerPredicate<(all_of FeatureHighPriInterrupts)>; + +def FeatureCoprocessor : SubtargetFeature<"coprocessor", "HasCoprocessor", "true", + "Enable Xtensa Coprocessor option">; +def HasCoprocessor : Predicate<"Subtarget->hasCoprocessor()">, + AssemblerPredicate<(all_of FeatureCoprocessor)>; + +def FeatureInterrupt : SubtargetFeature<"interrupt", "HasInterrupt", "true", + "Enable Xtensa Interrupt option">; +def HasInterrupt : Predicate<"Subtarget->hasInterrupt()">, + AssemblerPredicate<(all_of FeatureInterrupt)>; + +def FeatureRelocatableVector : SubtargetFeature<"rvector", "HasRelocatableVector", "true", + "Enable Xtensa Relocatable Vector option">; +def HasRelocatableVector : Predicate<"Subtarget->hasRelocatableVector()">, + AssemblerPredicate<(all_of FeatureRelocatableVector)>; + +def FeatureTimerInt : SubtargetFeature<"timerint", "HasTimerInt", "true", + "Enable Xtensa Timer Interrupt option">; +def HasTimerInt : Predicate<"Subtarget->hasTimerInt()">, + AssemblerPredicate<(all_of FeatureTimerInt)>; + +def FeaturePRID : SubtargetFeature<"prid", "HasPRID", "true", + "Enable Xtensa Processor ID option">; +def HasPRID : Predicate<"Subtarget->hasPRID()">, + AssemblerPredicate<(all_of FeaturePRID)>; + +def FeatureRegionProtection : SubtargetFeature<"regprotect", "HasRegionProtection", "true", + "Enable Xtensa Region Protection option">; +def HasRegionProtection : Predicate<"Subtarget->hasRegionProtection()">, + AssemblerPredicate<(all_of FeatureRegionProtection)>; + +def FeatureMiscSR : SubtargetFeature<"miscsr", "HasMiscSR", "true", + "Enable Xtensa Miscellaneous SR option">; +def HasMiscSR : Predicate<"Subtarget->hasMiscSR()">, + AssemblerPredicate<(all_of FeatureMiscSR)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 6e7c0bc79965c..c84fff473c841 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1226,6 +1226,83 @@ let isBarrier = 1, isTerminator = 1 in { def : Pat<(trap), (BREAK (i32 1), (i32 15))>; +//===----------------------------------------------------------------------===// +// Exception feature instructions +//===----------------------------------------------------------------------===// + +def EXCW : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "excw", []>, Requires<[HasException]> { + let r = 0x2; + let s = 0x0; + let t = 0x8; +} + +def RFDE : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "rfde", []>, Requires<[HasException]> { + let r = 0x3; + let s = 0x2; + let t = 0x0; +} + + +def RFE : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "rfe", []>, Requires<[HasException]> { + let r = 0x3; + let s = 0x0; + let t = 0x0; +} + +def SYSCALL : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), + "syscall", []>, Requires<[HasException]> { + let r = 0x5; + let s = 0x0; + let t = 0x0; +} + +//===----------------------------------------------------------------------===// +// Interrupt feature instructions +//===----------------------------------------------------------------------===// + +def RSIL : RRR_Inst<0x00, 0x00, 0x00, (outs AR:$t), (ins uimm4:$imm), + "rsil\t$t, $imm", []>, Requires<[HasInterrupt]> { + bits<4> imm; + + let r = 0x6; + let s = imm{3-0}; +} + +def WAITI : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins uimm4:$imm), + "waiti\t$imm", []>, Requires<[HasInterrupt]> { + bits<4> imm; + + let r = 0x7; + let s = imm{3-0}; + let t = 0; +} + +def RFI : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins uimm4:$imm), + "rfi\t$imm", []>, Requires<[HasInterrupt]> { + bits<4> imm; + + let r = 0x3; + let s = imm{3-0}; + let t = 0x1; +} + +//===----------------------------------------------------------------------===// +// Region Protection feature instructions +//===----------------------------------------------------------------------===// + +def WDTLB : RRR_Inst<0x00, 0x00, 0x05, (outs AR:$t), (ins AR:$s), + "wdtlb\t$t, $s", []>, Requires<[HasRegionProtection]> { + let r = 0xE; +} + +def WITLB : RRR_Inst<0x00, 0x00, 0x05, (outs AR:$t), (ins AR:$s), + "witlb\t$t, $s", []>, Requires<[HasRegionProtection]> { + let r = 0x6; +} + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index b5d371c2e315a..2fb153d065aca 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -102,6 +102,8 @@ def MEMCTL : SRReg<97, "memctl", ["MEMCTL", "97"]>; def ATOMCTL : SRReg<99, "atomctl", ["ATOMCTL", "99"]>; +def DDR : SRReg<104, "ddr", ["DDR", "104"]>; + // Instuction break address register 0 def IBREAKA0 : SRReg<128, "ibreaka0", ["IBREAKA0", "128"]>; @@ -120,20 +122,100 @@ def DBREAKC0 : SRReg<160, "dbreakc0", ["DBREAKC0", "160"]>; // Data breakpoint control register 1 def DBREAKC1 : SRReg<161, "dbreakc1", ["DBREAKC1", "161"]>; +def CONFIGID0 : SRReg<176, "configid0", ["CONFIGID0", "176"]>; + +// Exception PC1 +def EPC1 : SRReg<177, "epc1", ["EPC1", "177"]>; + +// Exception PC2 +def EPC2 : SRReg<178, "epc2", ["EPC2", "178"]>; + +// Exception PC3 +def EPC3 : SRReg<179, "epc3", ["EPC3", "179"]>; + +// Exception PC4 +def EPC4 : SRReg<180, "epc4", ["EPC4", "180"]>; + +// Exception PC5 +def EPC5 : SRReg<181, "epc5", ["EPC5", "181"]>; + +// Exception PC6 +def EPC6 : SRReg<182, "epc6", ["EPC6", "182"]>; + +// Exception PC7 +def EPC7 : SRReg<183, "epc7", ["EPC7", "183"]>; + +def DEPC : SRReg<192, "depc", ["DEPC", "192"]>; +def EPS2 : SRReg<194, "eps2", ["EPS2", "194"]>; +def EPS3 : SRReg<195, "eps3", ["EPS3", "195"]>; +def EPS4 : SRReg<196, "eps4", ["EPS4", "196"]>; +def EPS5 : SRReg<197, "eps5", ["EPS5", "197"]>; +def EPS6 : SRReg<198, "eps6", ["EPS6", "198"]>; +def EPS7 : SRReg<199, "eps7", ["EPS7", "199"]>; +def CONFIGID1 : SRReg<208, "configid1", ["CONFIGID1", "208"]>; +def EXCSAVE1 : SRReg<209, "excsave1", ["EXCSAVE1", "209"]>; +def EXCSAVE2 : SRReg<210, "excsave2", ["EXCSAVE2", "210"]>; +def EXCSAVE3 : SRReg<211, "excsave3", ["EXCSAVE3", "211"]>; +def EXCSAVE4 : SRReg<212, "excsave4", ["EXCSAVE4", "212"]>; +def EXCSAVE5 : SRReg<213, "excsave5", ["EXCSAVE5", "213"]>; +def EXCSAVE6 : SRReg<214, "excsave6", ["EXCSAVE6", "214"]>; +def EXCSAVE7 : SRReg<215, "excsave7", ["EXCSAVE7", "215"]>; +def CPENABLE : SRReg<224, "cpenable", ["CPENABLE", "224"]>; + +// Interrupt enable mask register +def INTSET : SRReg<226, "interrupt", ["INTERRUPT", "226"]>; + +def INTCLEAR : SRReg<227, "intclear", ["INTCLEAR", "227"]>; + +def INTENABLE : SRReg<228, "intenable", ["INTENABLE", "228"]>; + +// Processor State +def PS : SRReg<230, "ps", ["PS", "230"]>; + +// Vector base register +def VECBASE : SRReg<231, "vecbase", ["VECBASE", "231"]>; + +def EXCCAUSE : SRReg<232, "exccause", ["EXCCAUSE", "232"]>; + // Cause of last debug exception register def DEBUGCAUSE : SRReg<233, "debugcause", ["DEBUGCAUSE", "233"]>; +// Processor Clock Count Register +def CCOUNT : SRReg<234, "ccount", ["CCOUNT", "234"]>; + +// Processor ID Register +def PRID : SRReg<235, "prid", ["PRID", "235"]>; + def ICOUNT : SRReg<236, "icount", ["ICOUNT", "236"]>; def ICOUNTLEVEL : SRReg<237, "icountlevel", ["ICOUNTLEVEL", "237"]>; +def EXCVADDR : SRReg<238, "excvaddr", ["EXCVADDR", "238"]>; + +// Cycle number to interrupt register 0 +def CCOMPARE0 : SRReg<240, "ccompare0", ["CCOMPARE0", "240"]>; + +// Cycle number to interrupt register 1 +def CCOMPARE1 : SRReg<241, "ccompare1", ["CCOMPARE1", "241"]>; + +// Cycle number to interrupt register 2 +def CCOMPARE2 : SRReg<242, "ccompare2", ["CCOMPARE2", "242"]>; + +def MISC0 : SRReg<244, "misc0", ["MISC0", "244"]>; +def MISC1 : SRReg<245, "misc1", ["MISC1", "245"]>; +def MISC2 : SRReg<246, "misc2", ["MISC2", "246"]>; +def MISC3 : SRReg<247, "misc3", ["MISC3", "247"]>; def MR01 : RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>; def MR23 : RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>; def MR : RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>; -def SR : RegisterClass<"Xtensa", [i32], 32, (add LBEG, LEND, LCOUNT, - SAR, BREG, LITBASE, SCOMPARE1, ACCLO, ACCHI, MR, WINDOWBASE, WINDOWSTART, - IBREAKENABLE, MEMCTL, ATOMCTL, IBREAKA0, IBREAKA1, DBREAKA0, DBREAKA1, - DBREAKC0, DBREAKC1, DEBUGCAUSE, ICOUNT, ICOUNTLEVEL)>; +def SR : RegisterClass<"Xtensa", [i32], 32, (add + LBEG, LEND, LCOUNT, SAR, BREG, LITBASE, SCOMPARE1, ACCLO, ACCHI, MR, + WINDOWBASE, WINDOWSTART, IBREAKENABLE, MEMCTL, ATOMCTL, DDR, IBREAKA0, IBREAKA1, + DBREAKA0, DBREAKA1, DBREAKC0, DBREAKC1, CONFIGID0, EPC1, EPC2, EPC3, EPC4, EPC5, + EPC6, EPC7, DEPC, EPS2, EPS3, EPS4, EPS5, EPS6, EPS7, CONFIGID1, EXCSAVE1, EXCSAVE2, + EXCSAVE3, EXCSAVE4, EXCSAVE5, EXCSAVE6, EXCSAVE7, CPENABLE, INTSET, INTCLEAR, INTENABLE, PS, + VECBASE, EXCCAUSE, DEBUGCAUSE, CCOUNT, PRID, ICOUNT, ICOUNTLEVEL, EXCVADDR, CCOMPARE0, + CCOMPARE1, CCOMPARE2, MISC0, MISC1, MISC2, MISC3)>; //===----------------------------------------------------------------------===// // USER registers @@ -143,6 +225,8 @@ class URReg num, string n, list alt = []> : XtensaReg { let AltNames = alt; } +def EXPSTATE : URReg<230, "expstate", ["EXPSTATE"]>; + // Thread Pointer register def THREADPTR : URReg<231, "threadptr", ["THREADPTR"]>; @@ -152,7 +236,7 @@ def F64R_LO : URReg<234, "f64r_lo", ["F64R_LO"]>; def F64R_HI : URReg<235, "f64r_hi", ["F64R_HI"]>; def F64S : URReg<236, "f64s", ["F64S"]>; -def UR : RegisterClass<"Xtensa", [i32], 32, (add THREADPTR, FCR, +def UR : RegisterClass<"Xtensa", [i32], 32, (add EXPSTATE, THREADPTR, FCR, FSR, F64R_LO, F64R_HI, F64S)>; //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index 800c62d9cefc6..8c259dd33f2fa 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -50,6 +50,15 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasATOMCTL = false; HasMEMCTL = false; HasDebug = false; + HasException = false; + HasHighPriInterrupts = false; + HasCoprocessor = false; + HasInterrupt = false; + HasRelocatableVector = false; + HasTimerInt = false; + HasPRID = false; + HasRegionProtection = false; + HasMiscSR = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index eed24f28be153..8eb3281706cfe 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -92,6 +92,33 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enable Xtensa Debug option bool HasDebug; + // Enable Xtensa Exceptions option + bool HasException; + + // Enable Xtensa High Priority Interrupt option + bool HasHighPriInterrupts; + + // Enable Xtensa Coprocessor option + bool HasCoprocessor; + + // Enable Xtensa Interrupt option + bool HasInterrupt; + + // Enable Xtensa Relocatable Vector option + bool HasRelocatableVector; + + // Enable Xtensa Timer Interrupt option + bool HasTimerInt; + + // Enable Xtensa Processor ID option + bool HasPRID; + + // Enable Xtensa Region Protection option + bool HasRegionProtection; + + // Enable Xtensa Miscellaneous Special Reigsiters option + bool HasMiscSR; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -145,6 +172,24 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasDebug() const { return HasDebug; } + bool hasException() const { return HasException; } + + bool hasHighPriInterrupts() const { return HasHighPriInterrupts; } + + bool hasCoprocessor() const { return HasCoprocessor; } + + bool hasInterrupt() const { return HasInterrupt; } + + bool hasRelocatableVector() const { return HasRelocatableVector; } + + bool hasTimerInt() const { return HasTimerInt; } + + bool hasPRID() const { return HasPRID; } + + bool hasRegionProtection() const { return HasRegionProtection; } + + bool hasMiscSR() const { return HasMiscSR; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; diff --git a/llvm/test/MC/Xtensa/xtensa-valid-exc.s b/llvm/test/MC/Xtensa/xtensa-valid-exc.s new file mode 100644 index 0000000000000..4d1e9198bd9ad --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-exc.s @@ -0,0 +1,21 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+exception -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: excw +# CHECK: encoding: [0x80,0x20,0x00] + excw + +# CHECK-INST: rfde +# CHECK: encoding: [0x00,0x32,0x00] + rfde + +# CHECK-INST: rfe +# CHECK: encoding: [0x00,0x30,0x00] + rfe + +# CHECK-INST: syscall +# CHECK: encoding: [0x00,0x50,0x00] + syscall diff --git a/llvm/test/MC/Xtensa/xtensa-valid-int.s b/llvm/test/MC/Xtensa/xtensa-valid-int.s new file mode 100644 index 0000000000000..a24191ef4aa5a --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-int.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+interrupt -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# CHECK-INST: rfi 1 +# CHECK: encoding: [0x10,0x31,0x00] + rfi 1 + +# CHECK-INST: rsil a3, 1 +# CHECK: encoding: [0x30,0x61,0x00] + rsil a3, 1 + +# CHECK-INST: waiti 1 +# CHECK: encoding: [0x00,0x71,0x00] + waiti 1 \ No newline at end of file diff --git a/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s b/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s new file mode 100644 index 0000000000000..b3504eef1d557 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s @@ -0,0 +1,14 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+regprotect -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# CHECK-INST: wdtlb a3, a4 +# CHECK: encoding: [0x30,0xe4,0x50] + wdtlb a3, a4 + +# CHECK-INST: witlb a3, a4 +# CHECK: encoding: [0x30,0x64,0x50] + witlb a3, a4 From 3b363cd8c751766265e8d0b76faf00789c36e9f3 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:33 +0300 Subject: [PATCH 045/150] [Xtensa] Add the Xtensa target. --- clang/include/clang/Basic/TargetInfo.h | 5 +- clang/lib/AST/ASTContext.cpp | 47 +++++++++ clang/lib/Basic/CMakeLists.txt | 1 + clang/lib/Basic/Targets.cpp | 4 + clang/lib/Basic/Targets/Xtensa.cpp | 29 ++++++ clang/lib/Basic/Targets/Xtensa.h | 106 +++++++++++++++++++++ clang/lib/Driver/ToolChains/CommonArgs.cpp | 5 + clang/lib/Driver/ToolChains/Gnu.cpp | 6 ++ 8 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Basic/Targets/Xtensa.cpp create mode 100644 clang/lib/Basic/Targets/Xtensa.h diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index b4f3a69259fad..426e43dec1150 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -313,7 +313,10 @@ class TargetInfo : public virtual TransferrableTargetInfo, // void *__saved_reg_area_end_pointer; // void *__overflow_area_pointer; //} va_list; - HexagonBuiltinVaList + HexagonBuiltinVaList, + + // Tensilica Xtensa + XtensaABIBuiltinVaList }; protected: diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cfd7bf6045422..07631732eb5ca 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8968,6 +8968,51 @@ static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) { return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list"); } +static TypedefDecl * +CreateXtensaABIBuiltinVaListDecl(const ASTContext *Context) { + // typedef struct __va_list_tag { + RecordDecl *VaListTagDecl; + + VaListTagDecl = Context->buildImplicitRecord("__va_list_tag"); + VaListTagDecl->startDefinition(); + + const size_t NumFields = 3; + QualType FieldTypes[NumFields]; + const char *FieldNames[NumFields]; + + // int* __va_stk; + FieldTypes[0] = Context->getPointerType(Context->IntTy); + FieldNames[0] = "__va_stk"; + + // int* __va_reg; + FieldTypes[1] = Context->getPointerType(Context->IntTy); + FieldNames[1] = "__va_reg"; + + // int __va_ndx; + FieldTypes[2] = Context->IntTy; + FieldNames[2] = "__va_ndx"; + + // Create fields + for (unsigned i = 0; i < NumFields; ++i) { + FieldDecl *Field = FieldDecl::Create( + *Context, VaListTagDecl, SourceLocation(), SourceLocation(), + &Context->Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr, + /*BitWidth=*/nullptr, + /*Mutable=*/false, ICIS_NoInit); + Field->setAccess(AS_public); + VaListTagDecl->addDecl(Field); + } + VaListTagDecl->completeDefinition(); + Context->VaListTagDecl = VaListTagDecl; + QualType VaListTagType = Context->getRecordType(VaListTagDecl); + + // } __va_list_tag; + TypedefDecl *VaListTagTypedefDecl = + Context->buildImplicitTypedef(VaListTagType, "__builtin_va_list"); + + return VaListTagTypedefDecl; +} + static TypedefDecl *CreateVaListDecl(const ASTContext *Context, TargetInfo::BuiltinVaListKind Kind) { switch (Kind) { @@ -8989,6 +9034,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreateSystemZBuiltinVaListDecl(Context); case TargetInfo::HexagonBuiltinVaList: return CreateHexagonBuiltinVaListDecl(Context); + case TargetInfo::XtensaABIBuiltinVaList: + return CreateXtensaABIBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index 3e052c0cf9957..ca9dfea45b0f4 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -98,6 +98,7 @@ add_clang_library(clangBasic Targets/WebAssembly.cpp Targets/X86.cpp Targets/XCore.cpp + Targets/Xtensa.cpp TokenKinds.cpp TypeTraits.cpp Version.cpp diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 2d6ef998485ae..8d2d52f11e296 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -40,6 +40,7 @@ #include "Targets/WebAssembly.h" #include "Targets/X86.h" #include "Targets/XCore.h" +#include "Targets/Xtensa.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -670,6 +671,9 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, default: return new CSKYTargetInfo(Triple, Opts); } + + case llvm::Triple::xtensa : + return new XtensaTargetInfo(Triple, Opts); } } } // namespace targets diff --git a/clang/lib/Basic/Targets/Xtensa.cpp b/clang/lib/Basic/Targets/Xtensa.cpp new file mode 100644 index 0000000000000..270af0a05cfdc --- /dev/null +++ b/clang/lib/Basic/Targets/Xtensa.cpp @@ -0,0 +1,29 @@ +//===--- Xtensa.cpp - Implement Xtensa target feature support -------------===// +// +// The LLVM Compiler Infrastructure +// +// 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 implements Xtensa TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +void XtensaTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__Xtensa__"); + Builder.defineMacro("__xtensa__"); + Builder.defineMacro("__XTENSA__"); + Builder.defineMacro("__XTENSA_EL__"); +} diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h new file mode 100644 index 0000000000000..4a31e40eeb6ef --- /dev/null +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -0,0 +1,106 @@ +//===--- Xtensa.h - Declare Xtensa target feature support -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 declares Xtensa TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_XTENSA_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_XTENSA_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + std::string CPU; + +public: + XtensaTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + BigEndian = false; + NoAsmVariants = true; + LongLongAlign = 64; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 64; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + WCharType = UnsignedChar; + WIntType = UnsignedInt; + UseZeroLengthBitfieldAlignment = true; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + resetDataLayout("e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + + return TargetInfo::XtensaABIBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + // General register name + "a0", "sp", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", + "a11", "a12", "a13", "a14", "a15", + // Special register name + "sar"}; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'a': + Info.setAllowsRegister(); + return true; + } + return false; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + return (RegNo < 2) ? RegNo : -1; + } + + bool isValidCPUName(StringRef Name) const override { + return llvm::StringSwitch(Name).Case("generic", true).Default(false); + } + + bool setCPU(const std::string &Name) override { + CPU = Name; + return isValidCPUName(Name); + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_XTENSA_H diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 443725f7d8a8d..48d5437cbac38 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -462,6 +462,11 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, case llvm::Triple::wasm32: case llvm::Triple::wasm64: return std::string(getWebAssemblyTargetCPU(Args)); + + case llvm::Triple::xtensa: + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(); + return ""; } } diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index f203cae1d329f..868b7e1d2bcfd 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2304,6 +2304,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", "s390x-redhat-linux"}; + static const char *const XtensaLibDirs[] = {"/lib"}; + static const char *const XtensaTriples[] = {"xtensa-unknown-elf"}; using std::begin; using std::end; @@ -2571,6 +2573,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); break; + case llvm::Triple::xtensa: + LibDirs.append(begin(XtensaLibDirs), end(XtensaLibDirs)); + TripleAliases.append(begin(XtensaTriples), end(XtensaTriples)); + break; default: // By default, just rely on the standard lib directories and the original // triple. From e49f602b2e5b5730ae75d9990bbf5dceb1bd9779 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:34 +0300 Subject: [PATCH 046/150] [Xtensa] Implement Xtensa ABI lowering. --- clang/lib/CodeGen/TargetInfo.cpp | 223 +++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 36e10e4df4c19..7e70630489083 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -11535,6 +11535,227 @@ class CSKYTargetCodeGenInfo : public TargetCodeGenInfo { }; } // end anonymous namespace +//===----------------------------------------------------------------------===// +// Xtensa ABI Implementation +//===----------------------------------------------------------------------===// + +namespace { +class XtensaABIInfo : public DefaultABIInfo { +private: + static const int MaxNumArgGPRs = 6; + static const int MaxNumRetGPRs = 4; + +public: + XtensaABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + + // DefaultABIInfo's classifyReturnType and classifyArgumentType are + // non-virtual, but computeInfo is virtual, so we overload it. + void computeInfo(CGFunctionInfo &FI) const override; + + ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft) const; + + ABIArgInfo classifyReturnType(QualType RetTy) const; + + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; + + ABIArgInfo extendType(QualType Ty) const; +}; +} // end anonymous namespace + +void XtensaABIInfo::computeInfo(CGFunctionInfo &FI) const { + QualType RetTy = FI.getReturnType(); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(RetTy); + + int ArgGPRsLeft = MaxNumArgGPRs; + for (auto &ArgInfo : FI.arguments()) { + ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft); + } +} + +ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, + int &ArgGPRsLeft) const { + assert(ArgGPRsLeft <= MaxNumArgGPRs && "Arg GPR tracking underflow"); + Ty = useFirstFieldIfTransparentUnion(Ty); + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always passed indirectly. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { + if (ArgGPRsLeft) + ArgGPRsLeft -= 1; + return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == + CGCXXABI::RAA_DirectInMemory); + } + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + uint64_t Size = getContext().getTypeSize(Ty); + uint64_t NeededAlign = getContext().getTypeAlign(Ty); + bool MustUseStack = false; + int NeededArgGPRs = (Size + 31) / 32; + + if (NeededAlign == (2 * 32)) + NeededArgGPRs += (ArgGPRsLeft % 2); + + // Put on stack objects which are not fit to 6 registers, + // also on stack object which alignment more then 16 bytes and + // object with 16-byte alignment if it isn't the first argument. + if ((NeededArgGPRs > ArgGPRsLeft) || (NeededAlign > (4 * 32)) || + ((ArgGPRsLeft < 6) && (NeededAlign == (4 * 32)))) { + MustUseStack = true; + NeededArgGPRs = ArgGPRsLeft; + } + ArgGPRsLeft -= NeededArgGPRs; + + if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType() && !MustUseStack) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + // All integral types are promoted to XLen width, unless passed on the + // stack. + if (Size < 32 && Ty->isIntegralOrEnumerationType() && !MustUseStack) { + return extendType(Ty); + } + if (Size == 64) + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64)); + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 32)); + } + + // Aggregates which are <= 6*32 will be passed in registers if possible, + // so coerce to integers. + if ((Size <= (MaxNumArgGPRs * 32)) && (!MustUseStack)) { + if (Size <= 32) { + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 32)); + } else if (NeededAlign == (2 * 32)) { + return ABIArgInfo::getDirect(llvm::ArrayType::get( + llvm::IntegerType::get(getVMContext(), 64), NeededArgGPRs / 2)); + } else { + return ABIArgInfo::getDirect(llvm::ArrayType::get( + llvm::IntegerType::get(getVMContext(), 32), NeededArgGPRs)); + } + } +#undef MAX_STRUCT_IN_REGS_SIZE + return getNaturalAlignIndirect(Ty, /*ByVal=*/true); +} + +ABIArgInfo XtensaABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + int ArgGPRsLeft = MaxNumRetGPRs; + // The rules for return and argument types are the same, so defer to + // classifyArgumentType. + return classifyArgumentType(RetTy, ArgGPRsLeft); +} + +Address XtensaABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + // The va_list structure memory layout: + // struct __va_list_tag { + // int32_t *va_stk; + // int32_t *va_reg; + // int32_t va_ndx; + // }; + CGBuilderTy &Builder = CGF.Builder; + + Address OverflowAreaPtr = Builder.CreateStructGEP(VAListAddr, 0, "__va_stk"); + Address OverflowArea = Address(Builder.CreateLoad(OverflowAreaPtr, ""), + CGF.Int32Ty, CharUnits::fromQuantity(4)); + Address RegSaveAreaPtr = Builder.CreateStructGEP(VAListAddr, 1, "__va_reg"); + Address RegSaveArea = Address(Builder.CreateLoad(RegSaveAreaPtr, ""), + CGF.Int32Ty, CharUnits::fromQuantity(4)); + Address ARAreaPtr = Builder.CreateStructGEP(VAListAddr, 2, "__va_ndx"); + llvm::Value *ARIndex = Builder.CreateLoad(ARAreaPtr, ""); + + ARIndex = Builder.CreateLShr(ARIndex, Builder.getInt32(2)); + + unsigned Align = getContext().getTypeAlign(Ty) / 32; + unsigned Size = (getContext().getTypeSize(Ty) + 31) / 32; + + if (Align > 1) { + ARIndex = Builder.CreateAdd(ARIndex, Builder.getInt32(Align - 1)); + ARIndex = + Builder.CreateAnd(ARIndex, Builder.getInt32((uint32_t) ~(Align - 1))); + } + + llvm::Value *ARIndexNext = Builder.CreateAdd(ARIndex, Builder.getInt32(Size)); + Builder.CreateStore(Builder.CreateShl(ARIndexNext, Builder.getInt32(2)), + ARAreaPtr); + + const unsigned OverflowLimit = 6; + llvm::Value *CC = Builder.CreateICmpULE( + ARIndexNext, Builder.getInt32(OverflowLimit), "cond"); + + llvm::BasicBlock *UsingRegSaveArea = + CGF.createBasicBlock("using_regsavearea"); + llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow"); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + + Builder.CreateCondBr(CC, UsingRegSaveArea, UsingOverflow); + + llvm::Type *DirectTy = CGF.ConvertType(Ty); + + // Case 1: consume registers. + Address RegAddr = Address::invalid(); + { + CGF.EmitBlock(UsingRegSaveArea); + + CharUnits RegSize = CharUnits::fromQuantity(4); + RegSaveArea = + Address(Builder.CreateInBoundsGEP(CGF.Int32Ty, RegSaveArea.getPointer(), + ARIndex), + CGF.Int32Ty, RegSaveArea.getAlignment().alignmentOfArrayElement(RegSize)); + RegAddr = Builder.CreateElementBitCast(RegSaveArea, DirectTy); + CGF.EmitBranch(Cont); + } + + // Case 2: consume space in the overflow area. + Address MemAddr = Address::invalid(); + { + CGF.EmitBlock(UsingOverflow); + llvm::Value *CC1 = Builder.CreateICmpULE( + ARIndex, Builder.getInt32(OverflowLimit), "cond_overflow"); + + llvm::Value *ARIndexOff = Builder.CreateSelect( + CC1, Builder.CreateSub(Builder.getInt32(8), ARIndex), + Builder.getInt32(0)); + + llvm::Value *ARIndexCorr = Builder.CreateAdd(ARIndex, ARIndexOff); + llvm::Value *ARIndexNextCorr = Builder.CreateAdd(ARIndexNext, ARIndexOff); + Builder.CreateStore(Builder.CreateShl(ARIndexNextCorr, Builder.getInt32(2)), + ARAreaPtr); + + CharUnits RegSize = CharUnits::fromQuantity(4); + OverflowArea = + Address(Builder.CreateInBoundsGEP( + CGF.Int32Ty, OverflowArea.getPointer(), ARIndexCorr), + CGF.Int32Ty, OverflowArea.getAlignment().alignmentOfArrayElement(RegSize)); + MemAddr = Builder.CreateElementBitCast(OverflowArea, DirectTy); + CGF.EmitBranch(Cont); + } + + CGF.EmitBlock(Cont); + + // Merge the cases with a phi. + Address Result = + emitMergePHI(CGF, RegAddr, UsingRegSaveArea, MemAddr, UsingOverflow, ""); + + return Result; +} + +ABIArgInfo XtensaABIInfo::extendType(QualType Ty) const { + return ABIArgInfo::getExtend(Ty); +} + +namespace { +class XtensaTargetCodeGenInfo : public TargetCodeGenInfo { +public: + XtensaTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique(CGT)) {} +}; +} // namespace + //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// @@ -11763,6 +11984,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { : hasFP64 ? 64 : 32)); } + case llvm::Triple::xtensa: + return SetCGInfo(new XtensaTargetCodeGenInfo(Types)); } } From 2bb21f9e14c049893f566003be04f4ccac59f71a Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:34 +0300 Subject: [PATCH 047/150] [Xtensa] Add subtargets ESP32. ESP8266 and ESP32-S2. Make ESP32 default subtarget. --- llvm/lib/Target/Xtensa/Xtensa.td | 12 ++++++++++++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 27137a2edf956..2d031067e1832 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -161,6 +161,18 @@ class Proc Features> def : Proc<"generic", []>; +def : Proc<"esp32", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, + FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, + FeatureATOMCTL, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, + FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR]>; + +def : Proc<"esp8266", [FeatureDensity, FeatureNSA, FeatureMul32, FeatureExtendedL32R, FeatureDebug, FeatureException, FeatureHighPriInterrupts, + FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeatureRegionProtection, FeaturePRID]>; + +def : Proc<"esp32-s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureTHREADPTR, FeatureDiv32, + FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector, + FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR]>; + //===----------------------------------------------------------------------===// // Register File Description //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index 8c259dd33f2fa..106884d8a0311 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -29,7 +29,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { StringRef CPUName = CPU; if (CPUName.empty()) { // set default cpu name - CPUName = "generic"; + CPUName = "esp32"; } HasDensity = false; From 970ba6ee9dc3e9e895423962178e8973b71022b8 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:35 +0300 Subject: [PATCH 048/150] [Xtensa] Add esp32, esp8266 and esp32-s2 to valid cpu names. --- clang/lib/Basic/Targets/Xtensa.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index 4a31e40eeb6ef..188b2dc803ccd 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -93,7 +93,12 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { } bool isValidCPUName(StringRef Name) const override { - return llvm::StringSwitch(Name).Case("generic", true).Default(false); + return llvm::StringSwitch(Name) + .Case("esp32", true) + .Case("esp8266", true) + .Case("esp32-s2", true) + .Case("generic", true) + .Default(false); } bool setCPU(const std::string &Name) override { From 8ca87b99cc3e401a50fcfaef10545a292f50927d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:35 +0300 Subject: [PATCH 049/150] [Xtensa] Improve parsing of the SR and UR registers. Implement subtarget dependent SR and UR register parsing and disassembling, add tests. Implement User Registers read/write instructions and add tests. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 312 +++++++++++++++++- .../Disassembler/XtensaDisassembler.cpp | 180 +++++++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 35 ++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.td | 3 +- llvm/test/MC/Xtensa/xtensa-valid-ur.s | 19 ++ llvm/test/MC/Xtensa/xtensa-valid.s | 8 + 6 files changed, 540 insertions(+), 17 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-ur.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 4687f75efc429..f442ff0840c7a 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -51,10 +51,11 @@ class XtensaAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands, - bool AllowParens = false, bool SR = false); + bool AllowParens = false, bool SR = false, + bool UR = false); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); bool parseOperand(OperandVector &Operands, StringRef Mnemonic, - bool SR = false); + bool SR = false, bool UR = false); bool ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands); OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, @@ -62,6 +63,7 @@ class XtensaAsmParser : public MCTargetAsmParser { return MatchOperand_NoMatch; } OperandMatchResultTy parsePCRelTarget(OperandVector &Operands); + bool checkRegister(unsigned RegNo); public: enum XtensaMatchResultTy { @@ -76,6 +78,86 @@ class XtensaAsmParser : public MCTargetAsmParser { : MCTargetAsmParser(Options, STI, MII) { setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); } + + bool hasWindowed() const { + return getSTI().getFeatureBits()[Xtensa::FeatureWindowed]; + }; + + bool hasSingleFloat() const { + return getSTI().getFeatureBits()[Xtensa::FeatureSingleFloat]; + }; + + bool hasLoop() const { + return getSTI().getFeatureBits()[Xtensa::FeatureLoop]; + }; + + bool hasMAC16() const { + return getSTI().getFeatureBits()[Xtensa::FeatureMAC16]; + }; + + bool hasBoolean() const { + return getSTI().getFeatureBits()[Xtensa::FeatureBoolean]; + }; + + bool hasDFPAccel() const { + return getSTI().getFeatureBits()[Xtensa::FeatureDFPAccel]; + }; + + bool hasS32C1I() const { + return getSTI().getFeatureBits()[Xtensa::FeatureS32C1I]; + }; + + bool hasTHREADPTR() const { + return getSTI().getFeatureBits()[Xtensa::FeatureTHREADPTR]; + }; + + bool hasExtendedL32R() const { + return getSTI().getFeatureBits()[Xtensa::FeatureExtendedL32R]; + } + + bool hasATOMCTL() const { + return getSTI().getFeatureBits()[Xtensa::FeatureATOMCTL]; + } + + bool hasMEMCTL() const { + return getSTI().getFeatureBits()[Xtensa::FeatureMEMCTL]; + } + + bool hasDebug() const { + return getSTI().getFeatureBits()[Xtensa::FeatureDebug]; + } + + bool hasException() const { + return getSTI().getFeatureBits()[Xtensa::FeatureException]; + } + + bool hasHighPriInterrupts() const { + return getSTI().getFeatureBits()[Xtensa::FeatureHighPriInterrupts]; + } + + bool hasCoprocessor() const { + return getSTI().getFeatureBits()[Xtensa::FeatureCoprocessor]; + } + + bool hasInterrupt() const { + return getSTI().getFeatureBits()[Xtensa::FeatureInterrupt]; + } + + bool hasRelocatableVector() const { + return getSTI().getFeatureBits()[Xtensa::FeatureRelocatableVector]; + } + + bool hasTimerInt() const { + return getSTI().getFeatureBits()[Xtensa::FeatureTimerInt]; + } + + bool hasPRID() const { + return getSTI().getFeatureBits()[Xtensa::FeaturePRID]; + } + + bool hasMiscSR() const { + return getSTI().getFeatureBits()[Xtensa::FeatureMiscSR]; + } }; // Return true if Expr is in the range [MinValue, MaxValue]. @@ -503,17 +585,19 @@ bool XtensaAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, } OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, - bool AllowParens, bool SR) { + bool AllowParens, bool SR, + bool UR) { SMLoc FirstS = getLoc(); bool HadParens = false; AsmToken Buf[2]; - StringRef RegName; + std::string RegName = ""; + int64_t Num; // If this a parenthesised register name is allowed, parse it atomically if (AllowParens && getLexer().is(AsmToken::LParen)) { size_t ReadCount = getLexer().peekTokens(Buf); if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { - if ((Buf[0].getKind() == AsmToken::Integer) && (!SR)) + if ((Buf[0].getKind() == AsmToken::Integer) && (!SR) && (!UR)) return MatchOperand_NoMatch; HadParens = true; getParser().Lex(); // Eat '(' @@ -524,12 +608,35 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, default: return MatchOperand_NoMatch; case AsmToken::Integer: - if (!SR) + if ((!SR) && (!UR)) return MatchOperand_NoMatch; - RegName = StringRef(std::to_string(getLexer().getTok().getIntVal())); + + Num = getLexer().getTok().getIntVal(); + // Parse case when we expect UR operand as special case, + // because SR and UR registers may have the same number + // and such situation may lead to confilct + if (UR) { + if (Num == 0) + RegName = "GPIO_OUT"; + if (Num == 230) + RegName = "EXPSTATE"; + if (Num == 231) + RegName = "THREADPTR"; + if (Num == 232) + RegName = "FCR"; + if (Num == 233) + RegName = "FSR"; + if (Num == 234) + RegName = "F64R_LO"; + if (Num == 235) + RegName = "F64R_HI"; + if (Num == 236) + RegName = "F64S"; + } else + RegName = std::to_string(Num); break; case AsmToken::Identifier: - RegName = getLexer().getTok().getIdentifier(); + RegName = getLexer().getTok().getIdentifier().str(); break; } @@ -542,6 +649,11 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, getLexer().UnLex(Buf[0]); return MatchOperand_NoMatch; } + + if (!checkRegister(RegNo)) { + return MatchOperand_NoMatch; + } + if (HadParens) Operands.push_back(XtensaOperand::createToken("(", FirstS)); SMLoc S = getLoc(); @@ -600,7 +712,7 @@ XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) { /// from this information, adding to Operands. /// If operand was parsed, returns false, else true. bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, - bool SR) { + bool SR, bool UR) { // Check if the current operand has a custom associated parser, if so, try to // custom parse the operand, or fallback to the general approach. OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); @@ -614,7 +726,7 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, return true; // Attempt to parse token as register - if (parseRegister(Operands, true, SR) == MatchOperand_Success) + if (parseRegister(Operands, true, SR, UR) == MatchOperand_Success) return false; // Attempt to parse token as an immediate @@ -630,8 +742,13 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { + bool IsSR = Name.startswith("wsr") || Name.startswith("rsr") || + Name.startswith("xsr"); + bool IsUR = Name.startswith("wur") || Name.startswith("rur"); + if ((Name.startswith("wsr.") || Name.startswith("rsr.") || - Name.startswith("xsr.")) && + Name.startswith("xsr.") || Name.startswith("rur.") || + Name.startswith("wur.")) && (Name.size() > 4)) { // Parse case when instruction name is concatenated with SR register // name, like "wsr.sar a1" @@ -650,6 +767,11 @@ bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info, return true; } + if (!checkRegister(RegNo)) { + Error(NameLoc, "invalid register name"); + return true; + } + // Parse operand if (parseOperand(Operands, Name)) return true; @@ -674,7 +796,7 @@ bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info, getLexer().Lex(); // Parse second operand - if (parseOperand(Operands, Name, true)) + if (parseOperand(Operands, Name, IsSR, IsUR)) return true; } @@ -692,7 +814,8 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { if (Name.startswith("wsr") || Name.startswith("rsr") || - Name.startswith("xsr")) { + Name.startswith("xsr") || Name.startswith("rur") || + Name.startswith("wur")) { return ParseInstructionWithSR(Info, Name, NameLoc, Operands); } @@ -729,6 +852,169 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } +// Verify SR and UR +bool XtensaAsmParser::checkRegister(unsigned RegNo) { + StringRef CPU = getSTI().getCPU(); + unsigned NumIntLevels = 0; + unsigned NumTimers = 0; + unsigned NumMiscSR = 0; + bool IsESP32 = false; + bool IsESP32_S2 = false; + bool Res = true; + + // Assume that CPU is esp32 by default + if ((CPU == "esp32") || (CPU == "")) { + NumIntLevels = 6; + NumTimers = 3; + NumMiscSR = 4; + IsESP32 = true; + } else if (CPU == "esp32-s2") { + NumIntLevels = 6; + NumTimers = 3; + NumMiscSR = 4; + IsESP32_S2 = true; + } else if (CPU == "esp8266") { + NumIntLevels = 2; + NumTimers = 1; + } + + switch (RegNo) { + case Xtensa::LBEG: + case Xtensa::LEND: + case Xtensa::LCOUNT: + Res = hasLoop(); + break; + case Xtensa::BREG: + Res = hasBoolean(); + break; + case Xtensa::LITBASE: + Res = hasExtendedL32R(); + break; + case Xtensa::SCOMPARE1: + Res = hasS32C1I(); + break; + case Xtensa::ACCLO: + case Xtensa::ACCHI: + case Xtensa::M0: + case Xtensa::M1: + case Xtensa::M2: + case Xtensa::M3: + Res = hasMAC16(); + break; + case Xtensa::WINDOWBASE: + case Xtensa::WINDOWSTART: + Res = hasWindowed(); + break; + case Xtensa::IBREAKENABLE: + case Xtensa::IBREAKA0: + case Xtensa::IBREAKA1: + case Xtensa::DBREAKA0: + case Xtensa::DBREAKA1: + case Xtensa::DBREAKC0: + case Xtensa::DBREAKC1: + case Xtensa::DEBUGCAUSE: + case Xtensa::ICOUNT: + case Xtensa::ICOUNTLEVEL: + Res = hasDebug(); + break; + case Xtensa::ATOMCTL: + Res = hasATOMCTL(); + break; + case Xtensa::MEMCTL: + Res = hasMEMCTL(); + break; + case Xtensa::EPC1: + Res = hasException(); + break; + case Xtensa::EPC2: + case Xtensa::EPC3: + case Xtensa::EPC4: + case Xtensa::EPC5: + case Xtensa::EPC6: + case Xtensa::EPC7: + Res = hasHighPriInterrupts(); + Res = Res & (NumIntLevels >= (RegNo - Xtensa::EPC1)); + break; + case Xtensa::EPS2: + case Xtensa::EPS3: + case Xtensa::EPS4: + case Xtensa::EPS5: + case Xtensa::EPS6: + case Xtensa::EPS7: + Res = hasHighPriInterrupts(); + Res = Res & (NumIntLevels > (RegNo - Xtensa::EPS2)); + break; + case Xtensa::EXCSAVE1: + Res = hasException(); + break; + case Xtensa::EXCSAVE2: + case Xtensa::EXCSAVE3: + case Xtensa::EXCSAVE4: + case Xtensa::EXCSAVE5: + case Xtensa::EXCSAVE6: + case Xtensa::EXCSAVE7: + Res = hasHighPriInterrupts(); + Res = Res & (NumIntLevels >= (RegNo - Xtensa::EXCSAVE1)); + break; + case Xtensa::DEPC: + case Xtensa::EXCCAUSE: + case Xtensa::EXCVADDR: + Res = hasException(); + break; + case Xtensa::CPENABLE: + Res = hasCoprocessor(); + break; + case Xtensa::VECBASE: + Res = hasRelocatableVector(); + break; + case Xtensa::CCOUNT: + Res = hasTimerInt(); + Res &= (NumTimers > 0); + break; + case Xtensa::CCOMPARE0: + case Xtensa::CCOMPARE1: + case Xtensa::CCOMPARE2: + Res = hasTimerInt(); + Res &= (NumTimers > (RegNo - Xtensa::CCOMPARE0)); + break; + case Xtensa::PRID: + Res = hasPRID(); + break; + case Xtensa::INTSET: + case Xtensa::INTCLEAR: + case Xtensa::INTENABLE: + Res = hasInterrupt(); + break; + case Xtensa::MISC0: + case Xtensa::MISC1: + case Xtensa::MISC2: + case Xtensa::MISC3: + Res = hasMiscSR(); + Res &= (NumMiscSR > (RegNo - Xtensa::MISC0)); + break; + case Xtensa::THREADPTR: + Res = hasTHREADPTR(); + break; + case Xtensa::GPIO_OUT: + Res = IsESP32_S2; + break; + case Xtensa::EXPSTATE: + Res = IsESP32; + break; + case Xtensa::FCR: + case Xtensa::FSR: + Res = hasSingleFloat(); + break; + case Xtensa::F64R_LO: + case Xtensa::F64R_HI: + case Xtensa::F64S: + Res = hasDFPAccel(); + break; + } + + return Res; +} + // Force static initialization. extern "C" void LLVMInitializeXtensaAsmParser() { RegisterMCAsmParser X(TheXtensaTarget); diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index cb4a506c7eb75..c67a2e40b842d 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -146,6 +146,169 @@ static DecodeStatus DecodeMR23RegisterClass(MCInst &Inst, uint64_t RegNo, return MCDisassembler::Success; } +// Verify SR and UR +bool CheckRegister(unsigned RegNo, MCSubtargetInfo STI) { + StringRef CPU = STI.getCPU(); + unsigned NumIntLevels = 0; + unsigned NumTimers = 0; + unsigned NumMiscSR = 0; + bool IsESP32 = false; + bool IsESP32_S2 = false; + bool Res = true; + + // Assume that CPU is esp32 by default + if ((CPU == "esp32") || (CPU == "")) { + NumIntLevels = 6; + NumTimers = 3; + NumMiscSR = 4; + IsESP32 = true; + } else if (CPU == "esp32-s2") { + NumIntLevels = 6; + NumTimers = 3; + NumMiscSR = 4; + IsESP32_S2 = true; + } else if (CPU == "esp8266") { + NumIntLevels = 2; + NumTimers = 1; + } + + switch (RegNo) { + case Xtensa::LBEG: + case Xtensa::LEND: + case Xtensa::LCOUNT: + Res = STI.getFeatureBits()[Xtensa::FeatureLoop]; + break; + case Xtensa::BREG: + Res = STI.getFeatureBits()[Xtensa::FeatureBoolean]; + break; + case Xtensa::LITBASE: + Res = STI.getFeatureBits()[Xtensa::FeatureExtendedL32R]; + break; + case Xtensa::SCOMPARE1: + Res = STI.getFeatureBits()[Xtensa::FeatureS32C1I]; + break; + case Xtensa::ACCLO: + case Xtensa::ACCHI: + case Xtensa::M0: + case Xtensa::M1: + case Xtensa::M2: + case Xtensa::M3: + Res = STI.getFeatureBits()[Xtensa::FeatureMAC16]; + break; + case Xtensa::WINDOWBASE: + case Xtensa::WINDOWSTART: + Res = STI.getFeatureBits()[Xtensa::FeatureWindowed]; + break; + case Xtensa::IBREAKENABLE: + case Xtensa::IBREAKA0: + case Xtensa::IBREAKA1: + case Xtensa::DBREAKA0: + case Xtensa::DBREAKA1: + case Xtensa::DBREAKC0: + case Xtensa::DBREAKC1: + case Xtensa::DEBUGCAUSE: + case Xtensa::ICOUNT: + case Xtensa::ICOUNTLEVEL: + Res = STI.getFeatureBits()[Xtensa::FeatureDebug]; + break; + case Xtensa::ATOMCTL: + Res = STI.getFeatureBits()[Xtensa::FeatureATOMCTL]; + break; + case Xtensa::MEMCTL: + Res = STI.getFeatureBits()[Xtensa::FeatureMEMCTL]; + break; + case Xtensa::EPC1: + Res = STI.getFeatureBits()[Xtensa::FeatureException]; + break; + case Xtensa::EPC2: + case Xtensa::EPC3: + case Xtensa::EPC4: + case Xtensa::EPC5: + case Xtensa::EPC6: + case Xtensa::EPC7: + Res = STI.getFeatureBits()[Xtensa::FeatureHighPriInterrupts]; + Res = Res & (NumIntLevels >= (RegNo - Xtensa::EPC1)); + break; + case Xtensa::EPS2: + case Xtensa::EPS3: + case Xtensa::EPS4: + case Xtensa::EPS5: + case Xtensa::EPS6: + case Xtensa::EPS7: + Res = STI.getFeatureBits()[Xtensa::FeatureHighPriInterrupts]; + Res = Res & (NumIntLevels > (RegNo - Xtensa::EPS2)); + break; + case Xtensa::EXCSAVE1: + Res = STI.getFeatureBits()[Xtensa::FeatureException]; + break; + case Xtensa::EXCSAVE2: + case Xtensa::EXCSAVE3: + case Xtensa::EXCSAVE4: + case Xtensa::EXCSAVE5: + case Xtensa::EXCSAVE6: + case Xtensa::EXCSAVE7: + Res = STI.getFeatureBits()[Xtensa::FeatureHighPriInterrupts]; + Res = Res & (NumIntLevels >= (RegNo - Xtensa::EXCSAVE1)); + break; + case Xtensa::DEPC: + case Xtensa::EXCCAUSE: + case Xtensa::EXCVADDR: + Res = STI.getFeatureBits()[Xtensa::FeatureException]; + break; + case Xtensa::CPENABLE: + Res = STI.getFeatureBits()[Xtensa::FeatureCoprocessor]; + break; + case Xtensa::VECBASE: + Res = STI.getFeatureBits()[Xtensa::FeatureRelocatableVector]; + break; + case Xtensa::CCOUNT: + Res = STI.getFeatureBits()[Xtensa::FeatureTimerInt]; + Res &= (NumTimers > 0); + break; + case Xtensa::CCOMPARE0: + case Xtensa::CCOMPARE1: + case Xtensa::CCOMPARE2: + Res = STI.getFeatureBits()[Xtensa::FeatureTimerInt]; + Res &= (NumTimers > (RegNo - Xtensa::CCOMPARE0)); + break; + case Xtensa::PRID: + Res = STI.getFeatureBits()[Xtensa::FeaturePRID]; + break; + case Xtensa::INTSET: + case Xtensa::INTCLEAR: + case Xtensa::INTENABLE: + Res = STI.getFeatureBits()[Xtensa::FeatureInterrupt]; + break; + case Xtensa::MISC0: + case Xtensa::MISC1: + case Xtensa::MISC2: + case Xtensa::MISC3: + Res = STI.getFeatureBits()[Xtensa::FeatureMiscSR]; + Res &= (NumMiscSR > (RegNo - Xtensa::MISC0)); + break; + case Xtensa::THREADPTR: + Res = STI.getFeatureBits()[Xtensa::FeatureTHREADPTR]; + break; + case Xtensa::GPIO_OUT: + Res = IsESP32_S2; + break; + case Xtensa::EXPSTATE: + Res = IsESP32; + break; + case Xtensa::FCR: + case Xtensa::FSR: + Res = STI.getFeatureBits()[Xtensa::FeatureSingleFloat]; + break; + case Xtensa::F64R_LO: + case Xtensa::F64R_HI: + case Xtensa::F64S: + Res = STI.getFeatureBits()[Xtensa::FeatureDFPAccel]; + break; + } + + return Res; +} + static const unsigned SRDecoderTable[] = { Xtensa::LBEG, 0, Xtensa::LEND, 1, Xtensa::LCOUNT, 2, Xtensa::SAR, 3, @@ -185,12 +348,19 @@ static const unsigned SRDecoderTable[] = { static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, const void *Decoder) { + const llvm::MCSubtargetInfo STI = + ((const MCDisassembler *)Decoder)->getSubtargetInfo(); + if (RegNo > 255) return MCDisassembler::Fail; for (unsigned i = 0; i < array_lengthof(SRDecoderTable); i += 2) { if (SRDecoderTable[i + 1] == RegNo) { unsigned Reg = SRDecoderTable[i]; + + if (!CheckRegister(Reg, STI)) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::createReg(Reg)); return MCDisassembler::Success; } @@ -200,9 +370,9 @@ static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, } static const unsigned URDecoderTable[] = { - Xtensa::EXPSTATE, 230, Xtensa::THREADPTR, 231, Xtensa::FCR, 232, - Xtensa::FSR, 233, Xtensa::F64R_LO, 234, Xtensa::F64R_HI, 235, - Xtensa::F64S, 236}; + Xtensa::GPIO_OUT, 0, Xtensa::EXPSTATE, 230, Xtensa::THREADPTR, 231, + Xtensa::FCR, 232, Xtensa::FSR, 233, Xtensa::F64R_LO, 234, + Xtensa::F64R_HI, 235, Xtensa::F64S, 236}; static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, @@ -216,6 +386,10 @@ static DecodeStatus DecodeURRegisterClass(MCInst &Inst, uint64_t RegNo, for (unsigned i = 0; i < array_lengthof(URDecoderTable); i += 2) { if (URDecoderTable[i + 1] == RegNo) { unsigned Reg = URDecoderTable[i]; + + if (!CheckRegister(Reg, STI)) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::createReg(Reg)); return MCDisassembler::Success; } diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index c84fff473c841..eaca671134cae 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -607,6 +607,41 @@ def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr let Constraints = "$ard = $t, $srd = $sr"; } +//===----------------------------------------------------------------------===// +// User Registers read/write instructions +//===----------------------------------------------------------------------===// + +def WUR : RRR_Inst<0x00, 0x03, 0x0F, (outs UR:$ur), (ins AR:$t), + "wur\t$t, $ur", []> { + bits<8> ur; + + let r = ur{7-4}; + let s = ur{3-0}; +} + +def RUR : RRR_Inst<0x00, 0x03, 0x0E, (outs AR:$r), (ins UR:$ur), + "rur\t$r, $ur", []> { + bits<8> ur; + + let s = ur{7-4}; + let t = ur{3-0}; +} + +//===----------------------------------------------------------------------===// +// External Registers read/write instructions +//===----------------------------------------------------------------------===// + +def RER : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), + "rer\t$t, $s", []> { + let r = 0x6; +} + +def WER : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$t, AR:$s), + "wer\t$t, $s", []> { + let r = 0x7; + let hasSideEffects = 1; +} + //===----------------------------------------------------------------------===// // Stack allocation //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 2fb153d065aca..93e67af82fc86 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -225,6 +225,7 @@ class URReg num, string n, list alt = []> : XtensaReg { let AltNames = alt; } +def GPIO_OUT : URReg<0, "gpio_out", ["GPIO_OUT"]>; def EXPSTATE : URReg<230, "expstate", ["EXPSTATE"]>; // Thread Pointer register @@ -236,7 +237,7 @@ def F64R_LO : URReg<234, "f64r_lo", ["F64R_LO"]>; def F64R_HI : URReg<235, "f64r_hi", ["F64R_HI"]>; def F64S : URReg<236, "f64s", ["F64S"]>; -def UR : RegisterClass<"Xtensa", [i32], 32, (add EXPSTATE, THREADPTR, FCR, +def UR : RegisterClass<"Xtensa", [i32], 32, (add GPIO_OUT, EXPSTATE, THREADPTR, FCR, FSR, F64R_LO, F64R_HI, F64S)>; //===----------------------------------------------------------------------===// diff --git a/llvm/test/MC/Xtensa/xtensa-valid-ur.s b/llvm/test/MC/Xtensa/xtensa-valid-ur.s new file mode 100644 index 0000000000000..5bff7a6457f07 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-ur.s @@ -0,0 +1,19 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+threadptr -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: rur a3, threadptr +# CHECK: encoding: [0x70,0x3e,0xe3] + rur a3, threadptr +# CHECK-INST: rur a3, threadptr +# CHECK: encoding: [0x70,0x3e,0xe3] + rur.threadptr a3 + +# CHECK-INST: wur a3, threadptr +# CHECK: encoding: [0x30,0xe7,0xf3] + wur a3, threadptr +# CHECK-INST: wur a3, threadptr +# CHECK: encoding: [0x30,0xe7,0xf3] + wur.threadptr a3 diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s index a2d4fe5274ed5..7cde38de052f3 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -213,6 +213,10 @@ nop # CHECK: encoding: [0x60,0x45,0x20] or a4, a5, a6 +# CHECK-INST: rer a3, a4 +# CHECK: encoding: [0x30,0x64,0x40] +rer a3, a4 + # CHECK-INST: ret # CHECK: encoding: [0x80,0x00,0x00] ret @@ -299,6 +303,10 @@ subx4 a3, sp, a6 # CHECK: encoding: [0x70,0x41,0xf0] subx8 a4, sp, a7 +# CHECK-INST: wer a3, a4 +# CHECK: encoding: [0x30,0x74,0x40] +wer a3, a4 + # CHECK-INST: wsr a8, sar # CHECK: encoding: [0x80,0x03,0x13] wsr a8, sar From 6b07117c2299c5267c5532010f6dd5c6a3450951 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:15:36 +0300 Subject: [PATCH 050/150] [Xtensa] Emit literals Implement Xtensa specific streamer to support emit literals. --- .../Target/Xtensa/MCTargetDesc/CMakeLists.txt | 1 + .../MCTargetDesc/XtensaMCTargetDesc.cpp | 20 ++++ .../MCTargetDesc/XtensaTargetStreamer.cpp | 97 +++++++++++++++++++ .../MCTargetDesc/XtensaTargetStreamer.h | 53 ++++++++++ 4 files changed, 171 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt index 6841b44f9d569..dc12863394c7a 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_component_library(LLVMXtensaDesc XtensaMCCodeEmitter.cpp XtensaMCExpr.cpp XtensaMCTargetDesc.cpp + XtensaTargetStreamer.cpp LINK_COMPONENTS MC diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index 29bd805d86260..b9e964ffdffd6 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -10,6 +10,7 @@ #include "XtensaMCTargetDesc.h" #include "XtensaInstPrinter.h" #include "XtensaMCAsmInfo.h" +#include "XtensaTargetStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInstrInfo.h" @@ -62,6 +63,17 @@ createXtensaMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { return createXtensaMCSubtargetInfoImpl(TT, CPU, CPU, FS); } +static MCTargetStreamer * +createXtensaAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, bool isVerboseAsm) { + return new XtensaTargetAsmStreamer(S, OS); +} + +static MCTargetStreamer * +createXtensaObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + return new XtensaTargetELFStreamer(S); +} + extern "C" void LLVMInitializeXtensaTargetMC() { // Register the MCAsmInfo. TargetRegistry::RegisterMCAsmInfo(TheXtensaTarget, createXtensaMCAsmInfo); @@ -88,4 +100,12 @@ extern "C" void LLVMInitializeXtensaTargetMC() { // Register the MCAsmBackend. TargetRegistry::RegisterMCAsmBackend(TheXtensaTarget, createXtensaMCAsmBackend); + + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(TheXtensaTarget, + createXtensaAsmTargetStreamer); + + // Register the ELF target streamer. + TargetRegistry::RegisterObjectTargetStreamer( + TheXtensaTarget, createXtensaObjectTargetStreamer); } diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp new file mode 100644 index 0000000000000..645491d8f9711 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp @@ -0,0 +1,97 @@ +//===-- XtensaTargetStreamer.cpp - Xtensa Target Streamer Methods ---------===// +// +// The LLVM Compiler Infrastructure +// +// 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 Xtensa specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "XtensaTargetStreamer.h" +#include "XtensaInstPrinter.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +XtensaTargetStreamer::XtensaTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S) {} + +XtensaTargetAsmStreamer::XtensaTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : XtensaTargetStreamer(S), OS(OS) {} + +void XtensaTargetAsmStreamer::emitLiteral(std::string str) { OS << str; } + +XtensaTargetELFStreamer::XtensaTargetELFStreamer(MCStreamer &S) + : XtensaTargetStreamer(S) {} + +void XtensaTargetELFStreamer::emitLiteralLabel(MCSymbol *LblSym, SMLoc L) { + MCContext &Context = getStreamer().getContext(); + MCStreamer &OutStreamer = getStreamer(); + MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); + std::string CSectionName = CS->getName().str(); + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + SectionName = ".literal"; + SectionName += CSectionName.substr(Pos); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } + + MCSection *ConstSection = Context.getELFSection( + SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); + ConstSection->setAlignment(Align(4)); + + OutStreamer.pushSection(); + OutStreamer.switchSection(ConstSection); + OutStreamer.emitLabel(LblSym, L); + OutStreamer.popSection(); +} + +void XtensaTargetELFStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + SMLoc L) { + MCStreamer &OutStreamer = getStreamer(); + + OutStreamer.emitLabel(LblSym, L); + OutStreamer.emitValue(Value, 4, L); +} + +void XtensaTargetELFStreamer::emitLiteral(const MCExpr *Value, SMLoc L) { + MCContext &Context = getStreamer().getContext(); + MCStreamer &OutStreamer = getStreamer(); + MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); + std::string CSectionName = CS->getName().str(); + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + SectionName = ".literal"; + SectionName += CSectionName.substr(Pos); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } + + MCSection *ConstSection = Context.getELFSection( + SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); + + OutStreamer.pushSection(); + OutStreamer.switchSection(ConstSection); + OutStreamer.emitValue(Value, 4, L); + OutStreamer.popSection(); +} + +MCELFStreamer &XtensaTargetELFStreamer::getStreamer() { + return static_cast(Streamer); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h new file mode 100644 index 0000000000000..962da002a997d --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h @@ -0,0 +1,53 @@ +//===-- XtensaTargetStreamer.h - Xtensa Target Streamer --------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// 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_XTENSA_XTENSATARGETSTREAMER_H +#define LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H + +#include "XtensaConstantPoolValue.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/SMLoc.h" + +namespace llvm { +class formatted_raw_ostream; + +class XtensaTargetStreamer : public MCTargetStreamer { +public: + XtensaTargetStreamer(MCStreamer &S); + virtual void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) = 0; + virtual void emitLiteralLabel(MCSymbol *LblSym, SMLoc L) = 0; + virtual void emitLiteral(const MCExpr *Value, SMLoc L) = 0; + virtual void emitLiteral(std::string str) = 0; +}; + +class XtensaTargetAsmStreamer : public XtensaTargetStreamer { + formatted_raw_ostream &OS; + +public: + XtensaTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); + void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) override {} + void emitLiteralLabel(MCSymbol *LblSym, SMLoc L) override {} + void emitLiteral(const MCExpr *Value, SMLoc L) override {} + void emitLiteral(std::string str) override; +}; + +class XtensaTargetELFStreamer : public XtensaTargetStreamer { +public: + XtensaTargetELFStreamer(MCStreamer &S); + MCELFStreamer &getStreamer(); + void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) override; + void emitLiteralLabel(MCSymbol *LblSym, SMLoc L) override; + void emitLiteral(const MCExpr *Value, SMLoc L) override; + void emitLiteral(std::string str) override {} +}; +} // end namespace llvm + +#endif From 6ef8eb8b8ff832327f9251cb6693a1f4a190219a Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:56 +0300 Subject: [PATCH 051/150] [Xtensa] Improve assembler parsing. Improve CFA support. Implement special processing of MOVI and L32R instructions in assembler parser. The MOVI assembler expression now can have 32-bit immediate values, so also correct xtensa-invalid.s test. Also implement computation of CFA during XtensaMCAsmInfo creation. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 90 ++++++++++++++++++- .../MCTargetDesc/XtensaMCTargetDesc.cpp | 4 + llvm/test/MC/Xtensa/xtensa-invalid.s | 4 - 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index f442ff0840c7a..94933c4fb6202 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -8,7 +8,9 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/XtensaMCExpr.h" #include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "MCTargetDesc/XtensaTargetStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" @@ -33,6 +35,11 @@ class XtensaAsmParser : public MCTargetAsmParser { SMLoc getLoc() const { return getParser().getTok().getLoc(); } + XtensaTargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast(TS); + } + // Override MCTargetAsmParser. bool ParseDirective(AsmToken DirectiveID) override; bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; @@ -45,6 +52,9 @@ class XtensaAsmParser : public MCTargetAsmParser { unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; + bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + // Auto-generated instruction matching functions #define GET_ASSEMBLER_HEADER #include "XtensaGenAsmMatcher.inc" @@ -230,7 +240,13 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm12() const { return isImm(-2048, 2047); } - bool isImm12m() const { return isImm(-2048, 2047); } + // Convert MOVI to literal load, when immediate is not in range (-2048, 2047) + bool isImm12m() const { + //Process special case when operand is symbol + if ((Kind == Immediate) && (getImm()->getKind() == MCExpr::SymbolRef)) + return true; + return isImm(LONG_MIN, LONG_MAX); + } bool isOffset4m32() const { return isImm(0, 60) && @@ -443,6 +459,74 @@ static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, return Loc; } +bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { + Inst.setLoc(IDLoc); + const unsigned Opcode = Inst.getOpcode(); + + switch (Opcode) { + case Xtensa::L32R: { + const MCSymbolRefExpr *OpExpr = + (const MCSymbolRefExpr *)Inst.getOperand(1).getExpr(); + XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; + const MCExpr *NewOpExpr = XtensaMCExpr::create(OpExpr, Kind, getContext()); + Inst.getOperand(1).setExpr(NewOpExpr); + } break; + case Xtensa::MOVI: { + XtensaTargetStreamer &TS = this->getTargetStreamer(); + + //In the case of asm output, simply pass the representation of + //the MOVI instruction as is + if (TS.getStreamer().hasRawTextSupport()) + break; + + //Expand MOVI operand + if (!Inst.getOperand(1).isExpr()) { + uint64_t ImmOp64 = Inst.getOperand(1).getImm(); + int32_t Imm = ImmOp64; + if ((Imm < -2048) || (Imm > 2047)) { + XtensaTargetStreamer &TS = this->getTargetStreamer(); + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(Xtensa::L32R); + const MCExpr *Value = MCConstantExpr::create(ImmOp64, getContext()); + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *Expr = MCSymbolRefExpr::create( + Sym, MCSymbolRefExpr::VK_None, getContext()); + const MCExpr *OpExpr = XtensaMCExpr::create( + Expr, XtensaMCExpr::VK_Xtensa_None, getContext()); + TmpInst.addOperand(Inst.getOperand(0)); + MCOperand Op1 = MCOperand::createExpr(OpExpr); + TmpInst.addOperand(Op1); + TS.emitLiteralLabel(Sym, IDLoc); + TS.emitLiteral(Value, IDLoc); + Inst = TmpInst; + } + } else { + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(Xtensa::L32R); + const MCExpr *Value = Inst.getOperand(1).getExpr(); + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *Expr = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MCExpr *OpExpr = XtensaMCExpr::create( + Expr, XtensaMCExpr::VK_Xtensa_None, getContext()); + TmpInst.addOperand(Inst.getOperand(0)); + MCOperand Op1 = MCOperand::createExpr(OpExpr); + TmpInst.addOperand(Op1); + Inst = TmpInst; + TS.emitLiteralLabel(Sym, IDLoc); + TS.emitLiteral(Value, IDLoc); + } + } break; + default: + break; + } + return true; +} + bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -456,6 +540,7 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, default: break; case Match_Success: + processInstruction(Inst, IDLoc, Out, STI); Inst.setLoc(IDLoc); Out.emitInstruction(Inst, getSTI()); return false; @@ -491,9 +576,6 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidImm12: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-2048, 2047]"); - case Match_InvalidImm12m: - return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), - "expected immediate in range [-2048, 2047]"); case Match_InvalidImm1_16: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [1, 16]"); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index b9e964ffdffd6..3565d3bf1f927 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -10,6 +10,7 @@ #include "XtensaMCTargetDesc.h" #include "XtensaInstPrinter.h" #include "XtensaMCAsmInfo.h" +#include "llvm/MC/MCDwarf.h" #include "XtensaTargetStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" @@ -35,6 +36,9 @@ static MCAsmInfo *createXtensaMCAsmInfo(const MCRegisterInfo &MRI, const Triple &TT, const MCTargetOptions &Options) { MCAsmInfo *MAI = new XtensaMCAsmInfo(TT); + MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa( + nullptr, MRI.getDwarfRegNum(Xtensa::SP, true), 0); + MAI->addInitialFrameState(Inst); return MAI; } diff --git a/llvm/test/MC/Xtensa/xtensa-invalid.s b/llvm/test/MC/Xtensa/xtensa-invalid.s index 3cf16d44bd35c..88d94b3e2ca5f 100644 --- a/llvm/test/MC/Xtensa/xtensa-invalid.s +++ b/llvm/test/MC/Xtensa/xtensa-invalid.s @@ -4,10 +4,6 @@ LBL0: -# imm12m -movi a1, 3000 -# CHECK: error: expected immediate in range [-2048, 2047] - # imm8 addi a1, a2, 300 # CHECK: error: expected immediate in range [-128, 127] From ab2cfbb02d65d33224ee1d6729f3cff75e76b7dd Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:56 +0300 Subject: [PATCH 052/150] [Xtensa] Lowering Exception Selector and Pointer Registers. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 14 ++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 1029906a8b0fb..085b8513a3123 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -326,6 +326,20 @@ bool XtensaTargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, return false; } +/// If a physical register, this returns the register that receives the +/// exception address on entry to an EH pad. +Register XtensaTargetLowering::getExceptionPointerRegister( + const Constant *PersonalityFn) const { + return Xtensa::A2; +} + +/// If a physical register, this returns the register that receives the +/// exception typeid on entry to a landing pad. +Register XtensaTargetLowering::getExceptionSelectorRegister( + const Constant *PersonalityFn) const { + return Xtensa::A3; +} + bool XtensaTargetLowering::isOffsetFoldingLegal( const GlobalAddressSDNode *GA) const { // The Xtensa target isn't yet aware of offsets. diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 3f9929b9da2f4..222a07611334d 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -102,6 +102,15 @@ class XtensaTargetLowering : public TargetLowering { bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override; + /// If a physical register, this returns the register that receives the + /// exception address on entry to an EH pad. + Register + getExceptionPointerRegister(const Constant *PersonalityFn) const override; + /// If a physical register, this returns the register that receives the + /// exception typeid on entry to a landing pad. + Register + getExceptionSelectorRegister(const Constant *PersonalityFn) const override; + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; From 438ad201dd784cac411e2e2c41793cd974841d8a Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:56 +0300 Subject: [PATCH 053/150] [Xtensa] Lowering GLobalTLSAddress operation. --- .../MCTargetDesc/XtensaELFObjectWriter.cpp | 6 ++- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 44 ++++++++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 4 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 2 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 4 ++ 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp index 7788790ee66c2..439f0d7041de4 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp @@ -46,10 +46,14 @@ XtensaObjectWriter::~XtensaObjectWriter() {} unsigned XtensaObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); switch ((unsigned)Fixup.getKind()) { case FK_Data_4: - return ELF::R_XTENSA_32; + if (Modifier == MCSymbolRefExpr::VariantKind::VK_TPOFF) + return ELF::R_XTENSA_TLS_TPOFF; + else + return ELF::R_XTENSA_32; default: return ELF::R_XTENSA_SLOT0_OP; } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 085b8513a3123..f0d8c21113883 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -67,7 +67,7 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setStackPointerRegisterToSaveRestore(Xtensa::SP); setSchedulingPreference(Sched::RegPressure); - + setBooleanContents(ZeroOrOneBooleanContent); setBooleanVectorContents(ZeroOrOneBooleanContent); @@ -88,6 +88,7 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, // Handle the various types of symbolic address. setOperationAction(ISD::ConstantPool, PtrVT, Custom); setOperationAction(ISD::GlobalAddress, PtrVT, Custom); + setOperationAction(ISD::GlobalTLSAddress, PtrVT, Custom); setOperationAction(ISD::BlockAddress, PtrVT, Custom); setOperationAction(ISD::JumpTable, PtrVT, Custom); @@ -1305,6 +1306,44 @@ SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op, llvm_unreachable("invalid global addresses to lower"); } +SDValue XtensaTargetLowering::LowerGlobalTLSAddress(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDLoc DL(GA); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + if (DAG.getTarget().useEmulatedTLS()) + return LowerToTLSEmulatedModel(GA, DAG); + + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (!Subtarget.hasTHREADPTR()) { + llvm_unreachable("only emulated TLS supported"); + } + + if ((model == TLSModel::LocalExec) || (model == TLSModel::InitialExec)) { + auto PtrVt = getPointerTy(DAG.getDataLayout()); + + bool Priv = GV->isPrivateLinkage(GV->getLinkage()); + // Create a constant pool entry for the callee address + XtensaConstantPoolValue *CPV = XtensaConstantPoolSymbol::Create( + *DAG.getContext(), GV->getName().str().c_str() /* Sym */, + 0 /* XtensaCLabelIndex */, Priv, XtensaCP::TPOFF); + + // Get the address of the callee into a register + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4)); + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + + SDValue TPRegister = DAG.getRegister(Xtensa::THREADPTR, MVT::i32); + SDValue ThreadPointer = + DAG.getNode(XtensaISD::RUR, DL, MVT::i32, TPRegister); + return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadPointer, CPWrap); + } else + llvm_unreachable("only local-exec and initial-exec TLS mode supported"); + + return SDValue(); +} + SDValue XtensaTargetLowering::LowerBlockAddress(BlockAddressSDNode *Node, SelectionDAG &DAG) const { const BlockAddress *BA = Node->getBlockAddress(); @@ -1636,6 +1675,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerSELECT_CC(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: + return LowerGlobalTLSAddress(cast(Op), DAG); case ISD::BlockAddress: return LowerBlockAddress(cast(Op), DAG); case ISD::JumpTable: @@ -1692,6 +1733,7 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(MSUB); OPCODE(MOVS); OPCODE(MOVSP); + OPCODE(RUR); OPCODE(SHL); OPCODE(SRA); OPCODE(SRL); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 222a07611334d..a6da5a0296dba 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -63,6 +63,8 @@ enum { // WinABI Return RETW_FLAG, + RUR, + // Selects between operand 0 and operand 1. Operand 2 is the // mask of condition-code values for which operand 0 should be // chosen over operand 1; it has the same form as BR_CCMASK. @@ -164,6 +166,8 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; SDValue LowerImmediateFP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(GlobalAddressSDNode *Node, + SelectionDAG &DAG) const; SDValue LowerBlockAddress(BlockAddressSDNode *Node, SelectionDAG &DAG) const; SDValue LowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const; SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index eaca671134cae..8f8dfd2c8c4c8 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -620,7 +620,7 @@ def WUR : RRR_Inst<0x00, 0x03, 0x0F, (outs UR:$ur), (ins AR:$t), } def RUR : RRR_Inst<0x00, 0x03, 0x0E, (outs AR:$r), (ins UR:$ur), - "rur\t$r, $ur", []> { + "rur\t$r, $ur", [(set AR:$r, (Xtensa_rur UR:$ur))]> { bits<8> ur; let s = ur{7-4}; diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index fcb82e400a39f..3107137c9ad15 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -40,6 +40,7 @@ def SDT_XtensaSRC : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCi SDTCisVT<2, i32>]>; def SDT_XtensaSSL : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; def SDT_XtensaSSR : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; +def SDT_XtensaRUR : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; //===----------------------------------------------------------------------===// // Node definitions @@ -97,3 +98,6 @@ def Xtensa_ssr: SDNode<"XtensaISD::SSR", SDT_XtensaSSR, [SDNPOutGlue]>; def Xtensa_brjt: SDNode<"XtensaISD::BR_JT", SDT_XtensaBrJT, [SDNPHasChain]>; def Xtensa_callw: SDNode<"XtensaISD::CALLW", SDT_XtensaCall, [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; + +def Xtensa_rur: SDNode<"XtensaISD::RUR", SDT_XtensaRUR, + [SDNPInGlue]>; From 1e96c1ee1c28dc5eb05df5df888ab3af84cdddcf Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:57 +0300 Subject: [PATCH 054/150] [Xtensa] Lower ATOMIC_FENCE. Add Atomic Expand pass. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 14 ++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 8 ++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 14 ++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperators.td | 5 ++++- llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp | 3 +++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index f0d8c21113883..fa20931b1eee8 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -304,6 +304,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::TRAP, MVT::Other, Legal); + // to have the best chance and doing something good with fences custom lower + // them + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); @@ -1656,6 +1660,13 @@ SDValue XtensaTargetLowering::LowerShiftRightParts(SDValue Op, return DAG.getMergeValues(Ops, DL); } +SDValue XtensaTargetLowering::LowerATOMIC_FENCE(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Chain = Op.getOperand(0); + return DAG.getNode(XtensaISD::MEMW, DL, MVT::Other, Chain); +} + SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { @@ -1695,6 +1706,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerVASTART(Op, DAG); case ISD::VACOPY: return LowerVACOPY(Op, DAG); + case ISD::ATOMIC_FENCE: + return LowerATOMIC_FENCE(Op, DAG); case ISD::SHL_PARTS: return LowerShiftLeftParts(Op, DAG); case ISD::SRA_PARTS: @@ -1732,6 +1745,7 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(MADD); OPCODE(MSUB); OPCODE(MOVS); + OPCODE(MEMW); OPCODE(MOVSP); OPCODE(RUR); OPCODE(SHL); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index a6da5a0296dba..52c3bb4e589c2 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -52,6 +52,8 @@ enum { // FP move MOVS, + MEMW, + MOVSP, // Wraps a TargetGlobalAddress that should be loaded using PC-relative @@ -155,6 +157,10 @@ class XtensaTargetLowering : public TargetLowering { const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override; + bool shouldInsertFencesForAtomic(const Instruction *I) const override { + return true; + } + MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const override; @@ -188,6 +194,8 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; + SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const; + SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 8f8dfd2c8c4c8..44bb2c060683a 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -557,6 +557,8 @@ def EXTW : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), let t = 0xd; } +def : Pat<(Xtensa_mem_barrier), (MEMW)>; + //===----------------------------------------------------------------------===// // Processor control instructions //===----------------------------------------------------------------------===// @@ -1338,6 +1340,18 @@ def WITLB : RRR_Inst<0x00, 0x00, 0x05, (outs AR:$t), (ins AR:$s), let r = 0x6; } +//===----------------------------------------------------------------------===// +// Atomic patterns +//===----------------------------------------------------------------------===// + +def : Pat<(i32 (atomic_load_8 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; +def : Pat<(i32 (atomic_load_16 addr_ish2:$addr)), (L16UI addr_ish2:$addr)>; +def : Pat<(i32 (atomic_load_32 addr_ish4:$addr)), (L32I addr_ish4:$addr)>; + +def : Pat<(atomic_store_8 addr_ish1:$addr, AR:$t), (S8I AR:$t, addr_ish1:$addr)>; +def : Pat<(atomic_store_16 addr_ish2:$addr, AR:$t), (S16I AR:$t, addr_ish2:$addr)>; +def : Pat<(atomic_store_32 addr_ish4:$addr, AR:$t), (S32I AR:$t, addr_ish4:$addr)>; + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index 3107137c9ad15..e5f96e4465208 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -40,6 +40,7 @@ def SDT_XtensaSRC : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCi SDTCisVT<2, i32>]>; def SDT_XtensaSSL : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; def SDT_XtensaSSR : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; +def SDT_XtensaMEMBARRIER : SDTypeProfile<0, 0, []>; def SDT_XtensaRUR : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; //===----------------------------------------------------------------------===// @@ -98,6 +99,8 @@ def Xtensa_ssr: SDNode<"XtensaISD::SSR", SDT_XtensaSSR, [SDNPOutGlue]>; def Xtensa_brjt: SDNode<"XtensaISD::BR_JT", SDT_XtensaBrJT, [SDNPHasChain]>; def Xtensa_callw: SDNode<"XtensaISD::CALLW", SDT_XtensaCall, [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; +def Xtensa_mem_barrier: SDNode<"XtensaISD::MEMW", SDT_XtensaMEMBARRIER, + [SDNPHasChain, SDNPSideEffect]>; def Xtensa_rur: SDNode<"XtensaISD::RUR", SDT_XtensaRUR, - [SDNPInGlue]>; + [SDNPInGlue]>; diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index 8740b31216ec4..4f109f2a086fa 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -82,6 +82,7 @@ class XtensaPassConfig : public TargetPassConfig { return getTM(); } + void addIRPasses() override; bool addInstSelector() override; void addPreEmitPass() override; }; @@ -92,6 +93,8 @@ bool XtensaPassConfig::addInstSelector() { return false; } +void XtensaPassConfig::addIRPasses() { addPass(createAtomicExpandPass()); } + void XtensaPassConfig::addPreEmitPass() { addPass(createXtensaSizeReductionPass()); addPass(&BranchRelaxationPassID); From 01d46583f98f473e39a36582216fd4253a93bdd8 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:57 +0300 Subject: [PATCH 055/150] [Xtensa] Lower atomic_cmp_swap_(8/16/32) operations. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 173 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 2 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 12 ++ 3 files changed, 187 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index fa20931b1eee8..cc52241f4f423 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -308,6 +308,16 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, // them setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + if (!Subtarget.hasS32C1I()) { + for (unsigned I = MVT::FIRST_INTEGER_VALUETYPE; + I <= MVT::LAST_INTEGER_VALUETYPE; ++I) { + MVT VT = MVT::SimpleValueType(I); + if (isTypeLegal(VT)) { + setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand); + } + } + } + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); @@ -1956,6 +1966,143 @@ XtensaTargetLowering::emitSelectCC(MachineInstr &MI, return BB; } +// Emit instructions for atomic_cmp_swap node for 8/16 bit operands +MachineBasicBlock * +XtensaTargetLowering::emitAtomicCmpSwap(MachineInstr &MI, MachineBasicBlock *BB, + int isByteOperand) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + MachineBasicBlock *thisBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *BBLoop = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBExit = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, BBLoop); + F->insert(It, BBExit); + + // Transfer the remainder of BB and its successor edges to BBExit. + BBExit->splice(BBExit->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + BBExit->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(BBLoop); + + MachineOperand &Res = MI.getOperand(0); + MachineOperand &AtomValAddr = MI.getOperand(1); + MachineOperand &CmpVal = MI.getOperand(2); + MachineOperand &SwpVal = MI.getOperand(3); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + + unsigned R1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R1).addImm(3); + + unsigned ByteOffs = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::AND), ByteOffs) + .addReg(R1) + .addReg(AtomValAddr.getReg()); + + unsigned AddrAlign = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SUB), AddrAlign) + .addReg(AtomValAddr.getReg()) + .addReg(ByteOffs); + + unsigned BitOffs = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLLI), BitOffs) + .addReg(ByteOffs) + .addImm(3); + + unsigned Mask1 = MRI.createVirtualRegister(RC); + if (isByteOperand) { + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), Mask1).addImm(0xff); + } else { + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R2).addImm(1); + unsigned R3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLLI), R3).addReg(R2).addImm(16); + BuildMI(*BB, MI, DL, TII.get(Xtensa::ADDI), Mask1).addReg(R3).addImm(-1); + } + + BuildMI(*BB, MI, DL, TII.get(Xtensa::SSL)).addReg(BitOffs); + + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R2).addImm(-1); + + unsigned Mask2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), Mask2).addReg(Mask1); + + unsigned Mask3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::XOR), Mask3).addReg(Mask2).addReg(R2); + + unsigned R3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R3).addReg(AddrAlign).addImm(0); + + unsigned R4 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::AND), R4).addReg(R3).addReg(Mask3); + + unsigned Cmp1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), Cmp1).addReg(CmpVal.getReg()); + + unsigned Swp1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), Swp1).addReg(SwpVal.getReg()); + + BB = BBLoop; + + unsigned MaskPhi = MRI.createVirtualRegister(RC); + unsigned MaskLoop = MRI.createVirtualRegister(RC); + + BuildMI(*BB, BB->begin(), DL, TII.get(Xtensa::PHI), MaskPhi) + .addReg(MaskLoop) + .addMBB(BBLoop) + .addReg(R4) + .addMBB(thisBB); + + unsigned Cmp2 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::OR), Cmp2).addReg(Cmp1).addReg(MaskPhi); + + unsigned Swp2 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::OR), Swp2).addReg(Swp1).addReg(MaskPhi); + + BuildMI(BB, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1).addReg(Cmp2); + + unsigned Swp3 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::S32C1I), Swp3) + .addReg(Swp2) + .addReg(AddrAlign) + .addImm(0); + + BuildMI(BB, DL, TII.get(Xtensa::AND), MaskLoop).addReg(Swp3).addReg(Mask3); + + BuildMI(BB, DL, TII.get(Xtensa::BNE)) + .addReg(MaskLoop) + .addReg(MaskPhi) + .addMBB(BBLoop); + + BB->addSuccessor(BBLoop); + BB->addSuccessor(BBExit); + + BB = BBExit; + auto St = BBExit->begin(); + + unsigned R5 = MRI.createVirtualRegister(RC); + BuildMI(*BB, St, DL, TII.get(Xtensa::SSR)).addReg(BitOffs); + + BuildMI(*BB, St, DL, TII.get(Xtensa::SRL), R5).addReg(Swp3); + + BuildMI(*BB, St, DL, TII.get(Xtensa::AND), Res.getReg()) + .addReg(R5) + .addReg(Mask1); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); @@ -2032,6 +2179,32 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( return MBB; } + case Xtensa::ATOMIC_CMP_SWAP_8_P: { + return emitAtomicCmpSwap(MI, MBB, 1); + } + + case Xtensa::ATOMIC_CMP_SWAP_16_P: { + return emitAtomicCmpSwap(MI, MBB, 0); + } + + case Xtensa::ATOMIC_CMP_SWAP_32_P: { + MachineOperand &R = MI.getOperand(0); + MachineOperand &Addr = MI.getOperand(1); + MachineOperand &Cmp = MI.getOperand(2); + MachineOperand &Swap = MI.getOperand(3); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1) + .addReg(Cmp.getReg()); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::S32C1I), R.getReg()) + .addReg(Swap.getReg()) + .addReg(Addr.getReg()) + .addImm(0); + + MI.eraseFromParent(); + return MBB; + } + case Xtensa::S8I: case Xtensa::S16I: case Xtensa::S32I: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 52c3bb4e589c2..bba58bac8ae45 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -203,6 +203,8 @@ class XtensaTargetLowering : public TargetLowering { // Implement EmitInstrWithCustomInserter for individual operation types. MachineBasicBlock *emitSelectCC(MachineInstr &MI, MachineBasicBlock *BB) const; + MachineBasicBlock *emitAtomicCmpSwap(MachineInstr &MI, MachineBasicBlock *BB, + int isByteOperand) const; unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override { if (ConstraintCode == "R") diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 44bb2c060683a..0ea39ca4fd467 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1352,6 +1352,18 @@ def : Pat<(atomic_store_8 addr_ish1:$addr, AR:$t), (S8I AR:$t, addr_ish1:$addr) def : Pat<(atomic_store_16 addr_ish2:$addr, AR:$t), (S16I AR:$t, addr_ish2:$addr)>; def : Pat<(atomic_store_32 addr_ish4:$addr, AR:$t), (S32I AR:$t, addr_ish4:$addr)>; +let usesCustomInserter = 1, Predicates = [HasS32C1I] in { + def ATOMIC_CMP_SWAP_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$cmp, AR:$swap), + "!atomic_cmp_swap_8_p, $dst, $ptr, $cmp, $swap", + [(set AR:$dst, (atomic_cmp_swap_8 AR:$ptr, AR:$cmp, AR:$swap))]>; + def ATOMIC_CMP_SWAP_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$cmp, AR:$swap), + "!atomic_cmp_swap_16_p, $dst, $ptr, $cmp, $swap", + [(set AR:$dst, (atomic_cmp_swap_16 AR:$ptr, AR:$cmp, AR:$swap))]>; + def ATOMIC_CMP_SWAP_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$cmp, AR:$swap), + "!atomic_cmp_swap_32_p, $dst, $ptr, $cmp, $swap", + [(set AR:$dst, (atomic_cmp_swap_32 AR:$ptr, AR:$cmp, AR:$swap))]>; +} + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// From 1c1a40c23af9827d4c2b6ec52840b472adc6ec00 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:58 +0300 Subject: [PATCH 056/150] [Xtensa] Lower atomic_swap_(8/16/32) operations. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 275 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 4 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 10 + 3 files changed, 289 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index cc52241f4f423..14ea78af4a89d 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -314,6 +314,7 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, MVT VT = MVT::SimpleValueType(I); if (isTypeLegal(VT)) { setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand); + setOperationAction(ISD::ATOMIC_SWAP, VT, Expand); } } } @@ -2103,6 +2104,268 @@ XtensaTargetLowering::emitAtomicCmpSwap(MachineInstr &MI, MachineBasicBlock *BB, return BB; } +// Emit instructions for atomic_swap node for 8/16 bit operands +MachineBasicBlock * +XtensaTargetLowering::emitAtomicSwap(MachineInstr &MI, MachineBasicBlock *BB, + int isByteOperand) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + MachineFunction *F = BB->getParent(); + MachineBasicBlock *BBLoop1 = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBLoop2 = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBLoop3 = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBLoop4 = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBExit = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, BBLoop1); + F->insert(It, BBLoop2); + F->insert(It, BBLoop3); + F->insert(It, BBLoop4); + F->insert(It, BBExit); + + // Transfer the remainder of BB and its successor edges to BBExit. + BBExit->splice(BBExit->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + BBExit->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(BBLoop1); + BBLoop1->addSuccessor(BBLoop2); + BBLoop2->addSuccessor(BBLoop3); + BBLoop2->addSuccessor(BBLoop4); + BBLoop3->addSuccessor(BBLoop2); + BBLoop3->addSuccessor(BBLoop4); + BBLoop4->addSuccessor(BBLoop1); + BBLoop4->addSuccessor(BBExit); + + MachineOperand &Res = MI.getOperand(0); + MachineOperand &AtomValAddr = MI.getOperand(1); + MachineOperand &SwpVal = MI.getOperand(2); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + + unsigned R1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R1).addImm(3); + + unsigned ByteOffs = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::AND), ByteOffs) + .addReg(R1) + .addReg(AtomValAddr.getReg()); + + unsigned AddrAlign = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SUB), AddrAlign) + .addReg(AtomValAddr.getReg()) + .addReg(ByteOffs); + + unsigned BitOffs = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLLI), BitOffs) + .addReg(ByteOffs) + .addImm(3); + + unsigned Mask1 = MRI.createVirtualRegister(RC); + if (isByteOperand) { + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), Mask1).addImm(0xff); + } else { + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R2).addImm(1); + unsigned R3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLLI), R3).addReg(R2).addImm(16); + BuildMI(*BB, MI, DL, TII.get(Xtensa::ADDI), Mask1).addReg(R3).addImm(-1); + } + + BuildMI(*BB, MI, DL, TII.get(Xtensa::SSL)).addReg(BitOffs); + + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R2).addImm(-1); + + unsigned Mask2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), Mask2).addReg(Mask1); + + unsigned Mask3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::XOR), Mask3).addReg(Mask2).addReg(R2); + + unsigned R3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R3).addReg(AddrAlign).addImm(0); + + unsigned R4 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::AND), R4).addReg(R3).addReg(Mask3); + + unsigned SwpValShifted = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), SwpValShifted) + .addReg(SwpVal.getReg()); + + unsigned R5 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R5).addReg(AddrAlign).addImm(0); + + unsigned AtomVal = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::AND), AtomVal).addReg(R5).addReg(Mask2); + + unsigned AtomValPhi = MRI.createVirtualRegister(RC); + unsigned AtomValLoop = MRI.createVirtualRegister(RC); + + BuildMI(*BBLoop1, BBLoop1->begin(), DL, TII.get(Xtensa::PHI), AtomValPhi) + .addReg(AtomValLoop) + .addMBB(BBLoop4) + .addReg(AtomVal) + .addMBB(BB); + + BB = BBLoop1; + + BuildMI(BB, DL, TII.get(Xtensa::MEMW)); + + unsigned R6 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::L32I), R6).addReg(AddrAlign).addImm(0); + + unsigned R7 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), R7).addReg(R6).addReg(Mask3); + + unsigned MaskPhi = MRI.createVirtualRegister(RC); + unsigned MaskLoop = MRI.createVirtualRegister(RC); + + BuildMI(*BBLoop2, BBLoop2->begin(), DL, TII.get(Xtensa::PHI), MaskPhi) + .addReg(MaskLoop) + .addMBB(BBLoop3) + .addReg(R7) + .addMBB(BBLoop1); + + BB = BBLoop2; + + unsigned Swp1 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::OR), Swp1) + .addReg(SwpValShifted) + .addReg(MaskPhi); + + unsigned AtomVal1 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::OR), AtomVal1) + .addReg(AtomValPhi) + .addReg(MaskPhi); + + BuildMI(BB, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1).addReg(AtomVal1); + + unsigned Swp2 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::S32C1I), Swp2) + .addReg(Swp1) + .addReg(AddrAlign) + .addImm(0); + + BuildMI(BB, DL, TII.get(Xtensa::BEQ)) + .addReg(AtomVal1) + .addReg(Swp2) + .addMBB(BBLoop4); + + BB = BBLoop3; + + BuildMI(BB, DL, TII.get(Xtensa::AND), MaskLoop).addReg(Swp2).addReg(Mask3); + + BuildMI(BB, DL, TII.get(Xtensa::BNE)) + .addReg(MaskLoop) + .addReg(MaskPhi) + .addMBB(BBLoop2); + + BB = BBLoop4; + + BuildMI(BB, DL, TII.get(Xtensa::AND), AtomValLoop).addReg(Swp2).addReg(Mask2); + + BuildMI(BB, DL, TII.get(Xtensa::BNE)) + .addReg(AtomValLoop) + .addReg(AtomValPhi) + .addMBB(BBLoop1); + + BB = BBExit; + + auto St = BB->begin(); + + unsigned R8 = MRI.createVirtualRegister(RC); + + BuildMI(*BB, St, DL, TII.get(Xtensa::SSR)).addReg(BitOffs); + BuildMI(*BB, St, DL, TII.get(Xtensa::SLL), R8).addReg(AtomValLoop); + + if (isByteOperand) { + BuildMI(*BB, St, DL, TII.get(Xtensa::SEXT), Res.getReg()) + .addReg(R8) + .addImm(7); + } else { + BuildMI(*BB, St, DL, TII.get(Xtensa::SEXT), Res.getReg()) + .addReg(R8) + .addImm(15); + } + + MI.eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit instructions for atomic_swap node for 32 bit operands +MachineBasicBlock * +XtensaTargetLowering::emitAtomicSwap(MachineInstr &MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + MachineFunction *F = BB->getParent(); + MachineBasicBlock *BBLoop = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBExit = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, BBLoop); + F->insert(It, BBExit); + + // Transfer the remainder of BB and its successor edges to BBExit. + BBExit->splice(BBExit->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + BBExit->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(BBLoop); + BBLoop->addSuccessor(BBLoop); + BBLoop->addSuccessor(BBExit); + + MachineOperand &Res = MI.getOperand(0); + MachineOperand &AtomValAddr = MI.getOperand(1); + MachineOperand &SwpVal = MI.getOperand(2); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + + BuildMI(*BB, MI, DL, TII.get(Xtensa::MEMW)); + + unsigned AtomVal = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), AtomVal) + .addReg(AtomValAddr.getReg()) + .addImm(0); + + unsigned AtomValLoop = MRI.createVirtualRegister(RC); + + BuildMI(*BBLoop, BBLoop->begin(), DL, TII.get(Xtensa::PHI), Res.getReg()) + .addReg(AtomValLoop) + .addMBB(BBLoop) + .addReg(AtomVal) + .addMBB(BB); + + BB = BBLoop; + + BuildMI(BB, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1).addReg(Res.getReg()); + + BuildMI(BB, DL, TII.get(Xtensa::S32C1I), AtomValLoop) + .addReg(SwpVal.getReg()) + .addReg(AtomValAddr.getReg()) + .addImm(0); + + BuildMI(BB, DL, TII.get(Xtensa::BNE)) + .addReg(AtomValLoop) + .addReg(Res.getReg()) + .addMBB(BBLoop); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); @@ -2205,6 +2468,18 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( return MBB; } + case Xtensa::ATOMIC_SWAP_8_P: { + return emitAtomicSwap(MI, MBB, 1); + } + + case Xtensa::ATOMIC_SWAP_16_P: { + return emitAtomicSwap(MI, MBB, 0); + } + + case Xtensa::ATOMIC_SWAP_32_P: { + return emitAtomicSwap(MI, MBB); + } + case Xtensa::S8I: case Xtensa::S16I: case Xtensa::S32I: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index bba58bac8ae45..29588fd122867 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -203,8 +203,12 @@ class XtensaTargetLowering : public TargetLowering { // Implement EmitInstrWithCustomInserter for individual operation types. MachineBasicBlock *emitSelectCC(MachineInstr &MI, MachineBasicBlock *BB) const; + MachineBasicBlock *emitAtomicSwap(MachineInstr &MI, MachineBasicBlock *BB, + int isByteOperand) const; MachineBasicBlock *emitAtomicCmpSwap(MachineInstr &MI, MachineBasicBlock *BB, int isByteOperand) const; + MachineBasicBlock *emitAtomicSwap(MachineInstr &MI, + MachineBasicBlock *BB) const; unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override { if (ConstraintCode == "R") diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 0ea39ca4fd467..5a76565b52fb2 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1362,6 +1362,16 @@ let usesCustomInserter = 1, Predicates = [HasS32C1I] in { def ATOMIC_CMP_SWAP_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$cmp, AR:$swap), "!atomic_cmp_swap_32_p, $dst, $ptr, $cmp, $swap", [(set AR:$dst, (atomic_cmp_swap_32 AR:$ptr, AR:$cmp, AR:$swap))]>; + + def ATOMIC_SWAP_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$swap), + "!atomic_swap_8_p, $dst, $ptr, $swap", + [(set AR:$dst, (atomic_swap_8 AR:$ptr, AR:$swap))]>; + def ATOMIC_SWAP_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$swap), + "!atomic_swap_16_p, $dst, $ptr, $swap", + [(set AR:$dst, (atomic_swap_16 AR:$ptr, AR:$swap))]>; + def ATOMIC_SWAP_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$swap), + "!atomic_swap_32_p, $dst, $ptr, $swap", + [(set AR:$dst, (atomic_swap_32 AR:$ptr, AR:$swap))]>; } //===----------------------------------------------------------------------===// From 48964ccb9392364df612002c71260b9b42fc7c46 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:58 +0300 Subject: [PATCH 057/150] [Xtensa] Lower atomic operations. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 412 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 6 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 100 +++++ 3 files changed, 518 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 14ea78af4a89d..8e843189b87d0 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -315,6 +315,16 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, if (isTypeLegal(VT)) { setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand); setOperationAction(ISD::ATOMIC_SWAP, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_ADD, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_SUB, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_AND, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_OR, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_XOR, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand); } } } @@ -2366,6 +2376,345 @@ XtensaTargetLowering::emitAtomicSwap(MachineInstr &MI, return BB; } +MachineBasicBlock *XtensaTargetLowering::emitAtomicRMW(MachineInstr &MI, + MachineBasicBlock *BB, + unsigned Opcode, + bool inv, + bool minmax) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + MachineBasicBlock *ThisBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *BBLoop = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBExit = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, BBLoop); + F->insert(It, BBExit); + + // Transfer the remainder of BB and its successor edges to BB2. + BBExit->splice(BBExit->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + BBExit->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(BBLoop); + + MachineOperand &Res = MI.getOperand(0); + MachineOperand &AtomicValAddr = MI.getOperand(1); + MachineOperand &Val = MI.getOperand(2); + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + + unsigned R1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R1).add(AtomicValAddr).addImm(0); + + BB = BBLoop; + + unsigned AtomicValPhi = MRI.createVirtualRegister(RC); + unsigned AtomicValLoop = MRI.createVirtualRegister(RC); + + BuildMI(*BB, BB->begin(), DL, TII.get(Xtensa::PHI), AtomicValPhi) + .addReg(AtomicValLoop) + .addMBB(BBLoop) + .addReg(R1) + .addMBB(ThisBB); + + unsigned R2 = MRI.createVirtualRegister(RC); + + if (minmax) { + MachineBasicBlock *BBLoop1 = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, BBLoop1); + BB->addSuccessor(BBLoop1); + MachineBasicBlock *BBLoop2 = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, BBLoop2); + BB->addSuccessor(BBLoop2); + + BuildMI(BB, DL, TII.get(Opcode)) + .addReg(AtomicValPhi) + .addReg(Val.getReg()) + .addMBB(BBLoop1); + + unsigned R7 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), R7).addReg(Val.getReg()); + + BB = BBLoop1; + unsigned R8 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), R8).addReg(AtomicValPhi); + BB->addSuccessor(BBLoop2); + + BB = BBLoop2; + unsigned R9 = MRI.createVirtualRegister(RC); + + BuildMI(*BB, BB->begin(), DL, TII.get(Xtensa::PHI), R9) + .addReg(R7) + .addMBB(BBLoop) + .addReg(R8) + .addMBB(BBLoop1); + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), R2).addReg(R9); + } else { + BuildMI(BB, DL, TII.get(Opcode), R2) + .addReg(AtomicValPhi) + .addReg(Val.getReg()); + if (inv) { + unsigned Rtmp1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), Rtmp1).addImm(-1); + unsigned Rtmp2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::XOR), Rtmp2) + .addReg(R2) + .addReg(Rtmp1); + R2 = Rtmp2; + } + } + + unsigned R4 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1).addReg(AtomicValPhi); + BuildMI(BB, DL, TII.get(Xtensa::S32C1I), R4) + .addReg(R2) + .addReg(AtomicValAddr.getReg()) + .addImm(0); + + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), AtomicValLoop).addReg(R4); + + BuildMI(BB, DL, TII.get(Xtensa::BNE)) + .addReg(AtomicValPhi) + .addReg(R4) + .addMBB(BBLoop); + + BB->addSuccessor(BBLoop); + BB->addSuccessor(BBExit); + + BB = BBExit; + auto st = BBExit->begin(); + + BuildMI(*BB, st, DL, TII.get(Xtensa::MOV_N), Res.getReg()).addReg(R4); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + + return BB; +} + +MachineBasicBlock * +XtensaTargetLowering::emitAtomicRMW(MachineInstr &MI, MachineBasicBlock *BB, + bool isByteOperand, unsigned Opcode, + bool inv, bool minmax) const { + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = ++BB->getIterator(); + + MachineBasicBlock *ThisBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *BBLoop = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *BBExit = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, BBLoop); + F->insert(It, BBExit); + + // Transfer the remainder of BB and its successor edges to BB2. + BBExit->splice(BBExit->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + BBExit->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(BBLoop); + + MachineOperand &Res = MI.getOperand(0); + MachineOperand &AtomValAddr = MI.getOperand(1); + MachineOperand &Val = MI.getOperand(2); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + + unsigned R1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R1).addImm(3); + + unsigned ByteOffs = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::AND), ByteOffs) + .addReg(R1) + .addReg(AtomValAddr.getReg()); + + unsigned AddrAlign = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SUB), AddrAlign) + .addReg(AtomValAddr.getReg()) + .addReg(ByteOffs); + + unsigned BitOffs = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLLI), BitOffs) + .addReg(ByteOffs) + .addImm(3); + + unsigned Mask1 = MRI.createVirtualRegister(RC); + if (isByteOperand) { + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), Mask1).addImm(0xff); + } else { + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R2).addImm(1); + unsigned R3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLLI), R3).addReg(R2).addImm(16); + BuildMI(*BB, MI, DL, TII.get(Xtensa::ADDI), Mask1).addReg(R3).addImm(-1); + } + + BuildMI(*BB, MI, DL, TII.get(Xtensa::SSL)).addReg(BitOffs); + + unsigned R2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::MOVI), R2).addImm(-1); + + unsigned Mask2 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), Mask2).addReg(Mask1); + + unsigned Mask3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::XOR), Mask3).addReg(Mask2).addReg(R2); + + unsigned R3 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R3).addReg(AddrAlign).addImm(0); + + unsigned Val1 = MRI.createVirtualRegister(RC); + BuildMI(*BB, MI, DL, TII.get(Xtensa::SLL), Val1).addReg(Val.getReg()); + + BB = BBLoop; + + unsigned AtomicValPhi = MRI.createVirtualRegister(RC); + unsigned AtomicValLoop = MRI.createVirtualRegister(RC); + + BuildMI(*BB, BB->begin(), DL, TII.get(Xtensa::PHI), AtomicValPhi) + .addReg(AtomicValLoop) + .addMBB(BBLoop) + .addReg(R3) + .addMBB(ThisBB); + + unsigned Swp2; + + if (minmax) { + MachineBasicBlock *BBLoop1 = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, BBLoop1); + BB->addSuccessor(BBLoop1); + MachineBasicBlock *BBLoop2 = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, BBLoop2); + BB->addSuccessor(BBLoop2); + + unsigned R1 = MRI.createVirtualRegister(RC); + unsigned R2 = MRI.createVirtualRegister(RC); + unsigned R3 = MRI.createVirtualRegister(RC); + unsigned R4 = MRI.createVirtualRegister(RC); + + unsigned R5 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), R5) + .addReg(AtomicValPhi) + .addReg(Mask2); + + BuildMI(BB, DL, TII.get(Xtensa::SRL), R1).addReg(R5); + BuildMI(BB, DL, TII.get(Xtensa::SRL), R2).addReg(Val1); + + if ((Opcode == Xtensa::BLT) || (Opcode == Xtensa::BGE)) { + if (isByteOperand) { + BuildMI(BB, DL, TII.get(Xtensa::SEXT), R3).addReg(R1).addImm(7); + BuildMI(BB, DL, TII.get(Xtensa::SEXT), R4).addReg(R2).addImm(7); + } else { + BuildMI(BB, DL, TII.get(Xtensa::SEXT), R3).addReg(R1).addImm(15); + BuildMI(BB, DL, TII.get(Xtensa::SEXT), R4).addReg(R2).addImm(15); + } + } else { + R3 = R1; + R4 = R2; + } + + BuildMI(BB, DL, TII.get(Opcode)).addReg(R3).addReg(R4).addMBB(BBLoop1); + + unsigned R7 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), R7).addReg(Val1); + + BB = BBLoop1; + unsigned R8 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), R8).addReg(AtomicValPhi); + BB->addSuccessor(BBLoop2); + + BB = BBLoop2; + unsigned R9 = MRI.createVirtualRegister(RC); + + BuildMI(*BB, BB->begin(), DL, TII.get(Xtensa::PHI), R9) + .addReg(R7) + .addMBB(BBLoop) + .addReg(R8) + .addMBB(BBLoop1); + + unsigned R10 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), R10) + .addReg(AtomicValPhi) + .addReg(Mask3); + + unsigned R11 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), R11).addReg(R9).addReg(Mask2); + + Swp2 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::OR), Swp2).addReg(R10).addReg(R11); + } else { + unsigned R4 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), R4) + .addReg(AtomicValPhi) + .addReg(Mask2); + + unsigned Res1 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Opcode), Res1).addReg(R4).addReg(Val1); + + unsigned Swp1 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), Swp1).addReg(Res1).addReg(Mask2); + + unsigned R5 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::AND), R5) + .addReg(AtomicValPhi) + .addReg(Mask3); + + if (inv) { + unsigned Rtmp1 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::XOR), Rtmp1) + .addReg(AtomicValPhi) + .addReg(Mask2); + R5 = Rtmp1; + } + + Swp2 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::OR), Swp2).addReg(Swp1).addReg(R5); + } + + unsigned Swp3 = MRI.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1).addReg(AtomicValPhi); + BuildMI(BB, DL, TII.get(Xtensa::S32C1I), Swp3) + .addReg(Swp2) + .addReg(AddrAlign) + .addImm(0); + + BuildMI(BB, DL, TII.get(Xtensa::MOV_N), AtomicValLoop).addReg(Swp3); + + BuildMI(BB, DL, TII.get(Xtensa::BNE)) + .addReg(Swp3) + .addReg(AtomicValPhi) + .addMBB(BBLoop); + + BB->addSuccessor(BBLoop); + BB->addSuccessor(BBExit); + BB = BBExit; + auto St = BBExit->begin(); + + unsigned R6 = MRI.createVirtualRegister(RC); + + BuildMI(*BB, St, DL, TII.get(Xtensa::SSR)).addReg(BitOffs); + + BuildMI(*BB, St, DL, TII.get(Xtensa::SRL), R6).addReg(AtomicValLoop); + + BuildMI(*BB, St, DL, TII.get(Xtensa::AND), Res.getReg()) + .addReg(R6) + .addReg(Mask1); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + + return BB; +} + MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); @@ -2480,6 +2829,69 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( return emitAtomicSwap(MI, MBB); } + case Xtensa::ATOMIC_LOAD_ADD_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::ADD, false, false); + case Xtensa::ATOMIC_LOAD_SUB_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::SUB, false, false); + case Xtensa::ATOMIC_LOAD_OR_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::OR, false, false); + case Xtensa::ATOMIC_LOAD_XOR_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::XOR, false, false); + case Xtensa::ATOMIC_LOAD_AND_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::AND, false, false); + case Xtensa::ATOMIC_LOAD_NAND_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::AND, true, false); + case Xtensa::ATOMIC_LOAD_MIN_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::BGE, false, true); + case Xtensa::ATOMIC_LOAD_MAX_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::BLT, false, true); + case Xtensa::ATOMIC_LOAD_UMIN_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::BGEU, false, true); + case Xtensa::ATOMIC_LOAD_UMAX_8_P: + return emitAtomicRMW(MI, MBB, true, Xtensa::BLTU, false, true); + + case Xtensa::ATOMIC_LOAD_ADD_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::ADD, false, false); + case Xtensa::ATOMIC_LOAD_SUB_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::SUB, false, false); + case Xtensa::ATOMIC_LOAD_OR_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::OR, false, false); + case Xtensa::ATOMIC_LOAD_XOR_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::XOR, false, false); + case Xtensa::ATOMIC_LOAD_AND_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::AND, false, false); + case Xtensa::ATOMIC_LOAD_NAND_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::AND, true, false); + case Xtensa::ATOMIC_LOAD_MIN_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::BGE, false, true); + case Xtensa::ATOMIC_LOAD_MAX_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::BLT, false, true); + case Xtensa::ATOMIC_LOAD_UMIN_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::BGEU, false, true); + case Xtensa::ATOMIC_LOAD_UMAX_16_P: + return emitAtomicRMW(MI, MBB, false, Xtensa::BLTU, false, true); + + case Xtensa::ATOMIC_LOAD_ADD_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::ADD, false, false); + case Xtensa::ATOMIC_LOAD_SUB_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::SUB, false, false); + case Xtensa::ATOMIC_LOAD_OR_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::OR, false, false); + case Xtensa::ATOMIC_LOAD_XOR_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::XOR, false, false); + case Xtensa::ATOMIC_LOAD_AND_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::AND, false, false); + case Xtensa::ATOMIC_LOAD_NAND_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::AND, true, false); + case Xtensa::ATOMIC_LOAD_MIN_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::BGE, false, true); + case Xtensa::ATOMIC_LOAD_MAX_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::BLT, false, true); + case Xtensa::ATOMIC_LOAD_UMIN_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::BGEU, false, true); + case Xtensa::ATOMIC_LOAD_UMAX_32_P: + return emitAtomicRMW(MI, MBB, Xtensa::BLTU, false, true); + case Xtensa::S8I: case Xtensa::S16I: case Xtensa::S32I: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 29588fd122867..c1db77548308a 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -209,6 +209,12 @@ class XtensaTargetLowering : public TargetLowering { int isByteOperand) const; MachineBasicBlock *emitAtomicSwap(MachineInstr &MI, MachineBasicBlock *BB) const; + MachineBasicBlock *emitAtomicRMW(MachineInstr &MI, MachineBasicBlock *BB, + bool isByteOperand, unsigned Opcode, + bool inv, bool minmax) const; + MachineBasicBlock *emitAtomicRMW(MachineInstr &MI, MachineBasicBlock *BB, + unsigned Opcode, bool inv, + bool minmax) const; unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override { if (ConstraintCode == "R") diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 5a76565b52fb2..bfc3f773e9819 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1372,6 +1372,106 @@ let usesCustomInserter = 1, Predicates = [HasS32C1I] in { def ATOMIC_SWAP_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$swap), "!atomic_swap_32_p, $dst, $ptr, $swap", [(set AR:$dst, (atomic_swap_32 AR:$ptr, AR:$swap))]>; + + def ATOMIC_LOAD_ADD_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_add_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_add_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_ADD_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_add_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_add_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_ADD_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_add_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_add_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_SUB_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_sub_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_sub_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_SUB_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_sub_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_sub_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_SUB_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_sub_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_sub_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_AND_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_and_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_and_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_AND_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_and_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_and_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_AND_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_and_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_and_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_OR_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_or_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_or_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_OR_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_or_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_or_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_OR_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_or_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_or_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_XOR_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_xor_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_xor_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_XOR_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_xor_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_xor_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_XOR_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_xor_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_xor_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_NAND_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_nand_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_nand_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_NAND_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_nand_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_nand_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_NAND_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_nand_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_nand_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_MIN_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_min_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_min_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_MIN_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_min_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_min_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_MIN_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_min_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_min_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_MAX_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_max_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_max_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_MAX_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_max_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_max_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_MAX_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_max_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_max_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_UMIN_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_umin_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_umin_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_UMIN_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_umin_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_umin_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_UMIN_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_umin_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_umin_32 AR:$ptr, AR:$arg))]>; + + def ATOMIC_LOAD_UMAX_8_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_umax_8_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_umax_8 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_UMAX_16_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_umax_16_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_umax_16 AR:$ptr, AR:$arg))]>; + def ATOMIC_LOAD_UMAX_32_P : Pseudo<(outs AR:$dst), (ins AR:$ptr, AR:$arg), + "!atomic_load_umax_32_p, $dst, $ptr, $arg", + [(set AR:$dst, (atomic_load_umax_32 AR:$ptr, AR:$arg))]>; } //===----------------------------------------------------------------------===// From 07d2d1f83e27def0af529aac602f654e943847fd Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:59 +0300 Subject: [PATCH 058/150] [Xtensa] Implement Xtensa toolchain. --- clang/lib/Driver/CMakeLists.txt | 1 + clang/lib/Driver/Driver.cpp | 4 + clang/lib/Driver/ToolChains/Xtensa.cpp | 266 +++++++++++++++++++++++++ clang/lib/Driver/ToolChains/Xtensa.h | 94 +++++++++ 4 files changed, 365 insertions(+) create mode 100644 clang/lib/Driver/ToolChains/Xtensa.cpp create mode 100644 clang/lib/Driver/ToolChains/Xtensa.h diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 18c9b2d042f6c..05263ad676ccf 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -80,6 +80,7 @@ add_clang_library(clangDriver ToolChains/VEToolchain.cpp ToolChains/WebAssembly.cpp ToolChains/XCore.cpp + ToolChains/Xtensa.cpp ToolChains/PPCLinux.cpp ToolChains/PPCFreeBSD.cpp ToolChains/InterfaceStubs.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 3f29afd359718..a019143b7dbff 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -51,6 +51,7 @@ #include "ToolChains/VEToolchain.h" #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" +#include "ToolChains/Xtensa.h" #include "ToolChains/ZOS.h" #include "clang/Basic/TargetID.h" #include "clang/Basic/Version.h" @@ -6115,6 +6116,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::csky: TC = std::make_unique(*this, Target, Args); break; + case llvm::Triple::xtensa: + TC = std::make_unique(*this, Target, Args); + break; default: if (Target.getVendor() == llvm::Triple::Myriad) TC = std::make_unique(*this, Target, diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp new file mode 100644 index 0000000000000..003a10a0b9f63 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -0,0 +1,266 @@ +//===--- Xtensa.cpp - Xtensa ToolChain Implementations ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "CommonArgs.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Basic/Cuda.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Distro.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" +#include + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +XtensaGCCToolchainDetector::XtensaGCCToolchainDetector( + const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args) { + std::string InstalledDir; + InstalledDir = D.getInstalledDir(); + StringRef CPUName = XtensaToolChain::GetTargetCPUVersion(Args); + std::string Dir; + std::string ToolchainName; + std::string ToolchainDir; + + if (CPUName.equals("esp32")) + ToolchainName = "xtensa-esp32-elf"; + else if (CPUName.equals("esp32-s2")) + ToolchainName = "xtensa-esp32s2-elf"; + else if (CPUName.equals("esp8266")) + ToolchainName = "xtensa-lx106-elf"; + + Slash = llvm::sys::path::get_separator().str(); + + ToolchainDir = InstalledDir + Slash + ".."; + Dir = ToolchainDir + Slash + "lib" + Slash + "gcc" + Slash + ToolchainName + + Slash; + GCCLibAndIncVersion = ""; + + if (D.getVFS().exists(Dir)) { + std::error_code EC; + for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + auto GCCVersion = Generic_GCC::GCCVersion::Parse(VersionText); + if (GCCVersion.Major == -1) + continue; + GCCLibAndIncVersion = GCCVersion.Text; + } + if (GCCLibAndIncVersion == "") + llvm_unreachable("Unexpected Xtensa GCC toolchain version"); + + } else { + // Unable to find Xtensa GCC toolchain; + GCCToolchainName = ""; + return; + } + GCCToolchainDir = ToolchainDir; + GCCToolchainName = ToolchainName; +} + +/// Xtensa Toolchain +XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args), XtensaGCCToolchain(D, getTriple(), Args) { + for (auto *A : Args) { + std::string Str = A->getAsString(Args); + if (!Str.compare("-mlongcalls")) + A->claim(); + if (!Str.compare("-fno-tree-switch-conversion")) + A->claim(); + + // Currently don't use integrated assembler for assembler input files + if ((IsIntegratedAsm) && (Str.length() > 2)) { + std::string ExtSubStr = Str.substr(Str.length() - 2); + if (!ExtSubStr.compare(".s")) + IsIntegratedAsm = false; + if (!ExtSubStr.compare(".S")) + IsIntegratedAsm = false; + } + } + + // Currently don't use integrated assembler for assembler input files + if (IsIntegratedAsm) { + if (Args.getLastArgValue(options::OPT_x).equals("assembler")) + IsIntegratedAsm = false; + + if (Args.getLastArgValue(options::OPT_x).equals("assembler-with-cpp")) + IsIntegratedAsm = false; + } + + const std::string Slash = XtensaGCCToolchain.Slash; + std::string Libs = + XtensaGCCToolchain.GCCToolchainDir + Slash + "lib" + Slash + "gcc" + + Slash + XtensaGCCToolchain.GCCToolchainName + Slash + + XtensaGCCToolchain.GCCLibAndIncVersion; + getFilePaths().push_back(Libs); + + Libs = XtensaGCCToolchain.GCCToolchainDir + Slash + + XtensaGCCToolchain.GCCToolchainName + Slash + "lib"; + getFilePaths().push_back(Libs); +} + +Tool *XtensaToolChain::buildLinker() const { + return new tools::Xtensa::Linker(*this); +} + +Tool *XtensaToolChain::buildAssembler() const { + return new tools::Xtensa::Assembler(*this); +} + +void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + if (!XtensaGCCToolchain.IsValid()) + return; + + std::string Slash = XtensaGCCToolchain.Slash; + + std::string Path1 = getDriver().ResourceDir.c_str() + Slash + "include"; + std::string Path2 = XtensaGCCToolchain.GCCToolchainDir + Slash + + XtensaGCCToolchain.GCCToolchainName + Slash + + "sys-include"; + std::string Path3 = XtensaGCCToolchain.GCCToolchainDir + Slash + + XtensaGCCToolchain.GCCToolchainName + Slash + "include"; + + const StringRef Paths[] = {Path1, Path2, Path3}; + addSystemIncludes(DriverArgs, CC1Args, Paths); +} + +void XtensaToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (!XtensaGCCToolchain.IsValid()) + return; + + std::string Slash = XtensaGCCToolchain.Slash; + + std::string BaseDir = XtensaGCCToolchain.GCCToolchainDir + Slash + + XtensaGCCToolchain.GCCToolchainName + Slash + + "include" + Slash + "c++" + Slash + + XtensaGCCToolchain.GCCLibAndIncVersion; + std::string TargetDir = BaseDir + Slash + XtensaGCCToolchain.GCCToolchainName; + addLibStdCXXIncludePaths(BaseDir, "", "", DriverArgs, CC1Args); + addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); + TargetDir = BaseDir + Slash + "backward"; + addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); +} + +ToolChain::CXXStdlibType +XtensaToolChain::GetCXXStdlibType(const ArgList &Args) const { + Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); + if (!A) + return ToolChain::CST_Libstdcxx; + + StringRef Value = A->getValue(); + if (Value != "libstdc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); + + return ToolChain::CST_Libstdcxx; +} + +const StringRef XtensaToolChain::GetTargetCPUVersion(const ArgList &Args) { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + StringRef CPUName = A->getValue(); + return CPUName; + } + return "esp32"; +} + +void tools::Xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &TC = + static_cast(getToolChain()); + + if (!TC.XtensaGCCToolchain.IsValid()) + llvm_unreachable("Unable to find Xtensa GCC assembler"); + + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + CmdArgs.push_back("-c"); + + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + + if (Arg *A = Args.getLastArg(options::OPT_g_Group)) + if (!A->getOption().matches(options::OPT_g0)) + CmdArgs.push_back("-g"); + + if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, + false)) + CmdArgs.push_back("-fverbose-asm"); + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + std::string Slash = TC.XtensaGCCToolchain.Slash; + + const char *Asm = + Args.MakeArgString(getToolChain().getDriver().Dir + Slash + + TC.XtensaGCCToolchain.GCCToolchainName + "-as"); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileCurCP(), Asm, CmdArgs, Inputs)); +} + +void Xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &TC = + static_cast(getToolChain()); + std::string Slash = TC.XtensaGCCToolchain.Slash; + + if (!TC.XtensaGCCToolchain.IsValid()) + llvm_unreachable("Unable to find Xtensa GCC linker"); + + std::string Linker = getToolChain().getDriver().Dir + Slash + + TC.XtensaGCCToolchain.GCCToolchainName + "-ld"; + ArgStringList CmdArgs; + + Args.AddAllArgs(CmdArgs, options::OPT_L); + TC.AddFilePathLibArgs(Args, CmdArgs); + + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand( + std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Linker), CmdArgs, Inputs)); +} diff --git a/clang/lib/Driver/ToolChains/Xtensa.h b/clang/lib/Driver/ToolChains/Xtensa.h new file mode 100644 index 0000000000000..663dc63f6d279 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Xtensa.h @@ -0,0 +1,94 @@ +//===--- Xtensa.h - Xtensa Tool and ToolChain Implementations ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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_CLANG_LIB_DRIVER_TOOLCHAINS_Xtensa_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Xtensa_H + +#include "Gnu.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class XtensaGCCToolchainDetector { +public: + std::string GCCLibAndIncVersion; + std::string GCCToolchainName; + std::string GCCToolchainDir; + std::string Slash; + + XtensaGCCToolchainDetector(const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args); + + bool IsValid() const { return GCCToolchainName != ""; } +}; + +class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { +protected: + Tool *buildLinker() const override; + Tool *buildAssembler() const override; + +public: + XtensaToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + bool IsIntegratedAssemblerDefault() const override { + return (IsIntegratedAsm || (XtensaGCCToolchain.GCCToolchainName == "")); + } + + static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); + + XtensaGCCToolchainDetector XtensaGCCToolchain; + bool IsIntegratedAsm = true; +}; + +} // end namespace toolchains + +namespace tools { +namespace Xtensa { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) + : Tool("Xtensa::Linker", "xtensa-esp32-elf-ld", TC) {} + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) + : Tool("Xtensa::Assembler", "xtensa-esp32-elf-as", TC) {} + + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace Xtensa +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Xtensa_H From c93b1e9af7edce5ca0b5858c5aa560081354497d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:16:59 +0300 Subject: [PATCH 059/150] [Xtensa] Implement multilib support Use Multilib class functionality to choose between library variants, based on the command line args. --- clang/lib/Driver/ToolChains/Xtensa.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 003a10a0b9f63..a1f83801b5610 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -29,6 +29,8 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; +using tools::addMultilibFlag; + XtensaGCCToolchainDetector::XtensaGCCToolchainDetector( const Driver &D, const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args) { @@ -105,15 +107,28 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, IsIntegratedAsm = false; } + Multilibs.push_back(Multilib()); + + Multilibs.push_back( + Multilib("no-rtti", {}, {}, 1).flag("+fno-rtti").flag("-frtti")); + + Multilib::flags_list Flags; + addMultilibFlag( + Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, false), "frtti", + Flags); + + Multilibs.select(Flags, SelectedMultilib); + const std::string Slash = XtensaGCCToolchain.Slash; std::string Libs = XtensaGCCToolchain.GCCToolchainDir + Slash + "lib" + Slash + "gcc" + Slash + XtensaGCCToolchain.GCCToolchainName + Slash + - XtensaGCCToolchain.GCCLibAndIncVersion; + XtensaGCCToolchain.GCCLibAndIncVersion + SelectedMultilib.gccSuffix(); getFilePaths().push_back(Libs); Libs = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + "lib"; + XtensaGCCToolchain.GCCToolchainName + Slash + "lib" + + SelectedMultilib.gccSuffix(); getFilePaths().push_back(Libs); } From 37f3ffe985d164737aa117e4cf593a13cc2deb3a Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:18 +0300 Subject: [PATCH 060/150] [Xtensa] Implemented builtins for Xtensa MAC16 instructions. --- clang/include/clang/Basic/BuiltinsXtensa.def | 127 +++++++ clang/include/clang/Basic/TargetBuiltins.h | 10 + clang/include/clang/Sema/Sema.h | 1 + clang/lib/Basic/Targets/Xtensa.cpp | 11 + clang/lib/Basic/Targets/Xtensa.h | 2 +- clang/lib/Sema/SemaChecking.cpp | 79 +++++ llvm/include/llvm/IR/CMakeLists.txt | 1 + llvm/include/llvm/IR/Intrinsics.td | 1 + llvm/include/llvm/IR/IntrinsicsXtensa.td | 251 ++++++++++++++ llvm/lib/IR/Function.cpp | 1 + llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td | 175 ++++++++-- llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 257 +++++++++++++- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 262 ++++++++++++++ llvm/test/CodeGen/Xtensa/lit.local.cfg | 2 + llvm/test/CodeGen/Xtensa/mac16_intrinsics.ll | 319 ++++++++++++++++++ .../secondary/llvm/include/llvm/IR/BUILD.gn | 11 + 16 files changed, 1475 insertions(+), 35 deletions(-) create mode 100644 clang/include/clang/Basic/BuiltinsXtensa.def create mode 100644 llvm/include/llvm/IR/IntrinsicsXtensa.td create mode 100644 llvm/test/CodeGen/Xtensa/lit.local.cfg create mode 100644 llvm/test/CodeGen/Xtensa/mac16_intrinsics.ll diff --git a/clang/include/clang/Basic/BuiltinsXtensa.def b/clang/include/clang/Basic/BuiltinsXtensa.def new file mode 100644 index 0000000000000..47f75f1665b16 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsXtensa.def @@ -0,0 +1,127 @@ +//===-- BuiltinsXtensa.def - Xtensa Builtin function database ----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the Xtensa-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__builtin_xtensa_umul_aa_ll, "vUiUi", "n") +BUILTIN(__builtin_xtensa_umul_aa_lh, "vUiUi", "n") +BUILTIN(__builtin_xtensa_umul_aa_hl, "vUiUi", "n") +BUILTIN(__builtin_xtensa_umul_aa_hh, "vUiUi", "n") + +BUILTIN(__builtin_xtensa_mul_aa_ll, "vUiUi", "n") +BUILTIN(__builtin_xtensa_mul_aa_lh, "vUiUi", "n") +BUILTIN(__builtin_xtensa_mul_aa_hl, "vUiUi", "n") +BUILTIN(__builtin_xtensa_mul_aa_hh, "vUiUi", "n") + +BUILTIN(__builtin_xtensa_mul_ad_ll, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_mul_ad_lh, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_mul_ad_hl, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_mul_ad_hh, "vUiIUi", "n") + +BUILTIN(__builtin_xtensa_mul_da_ll, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_mul_da_lh, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_mul_da_hl, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_mul_da_hh, "vIUiUi", "n") + +BUILTIN(__builtin_xtensa_mul_dd_ll, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_mul_dd_lh, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_mul_dd_hl, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_mul_dd_hh, "vIUiIUi", "n") + +BUILTIN(__builtin_xtensa_mula_aa_ll, "vUiUi", "n") +BUILTIN(__builtin_xtensa_mula_aa_lh, "vUiUi", "n") +BUILTIN(__builtin_xtensa_mula_aa_hl, "vUiUi", "n") +BUILTIN(__builtin_xtensa_mula_aa_hh, "vUiUi", "n") + +BUILTIN(__builtin_xtensa_mula_ad_ll, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_ad_lh, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_ad_hl, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_ad_hh, "vUiIUi", "n") + +BUILTIN(__builtin_xtensa_mula_da_ll, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_mula_da_lh, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_mula_da_hl, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_mula_da_hh, "vIUiUi", "n") + +BUILTIN(__builtin_xtensa_mula_dd_ll, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_lh, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_hl, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_hh, "vIUiIUi", "n") + +BUILTIN(__builtin_xtensa_muls_aa_ll, "vUiUi", "n") +BUILTIN(__builtin_xtensa_muls_aa_lh, "vUiUi", "n") +BUILTIN(__builtin_xtensa_muls_aa_hl, "vUiUi", "n") +BUILTIN(__builtin_xtensa_muls_aa_hh, "vUiUi", "n") + +BUILTIN(__builtin_xtensa_muls_ad_ll, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_muls_ad_lh, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_muls_ad_hl, "vUiIUi", "n") +BUILTIN(__builtin_xtensa_muls_ad_hh, "vUiIUi", "n") + +BUILTIN(__builtin_xtensa_muls_da_ll, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_muls_da_lh, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_muls_da_hl, "vIUiUi", "n") +BUILTIN(__builtin_xtensa_muls_da_hh, "vIUiUi", "n") + +BUILTIN(__builtin_xtensa_muls_dd_ll, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_muls_dd_lh, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_muls_dd_hl, "vIUiIUi", "n") +BUILTIN(__builtin_xtensa_muls_dd_hh, "vIUiIUi", "n") + +BUILTIN(__builtin_xtensa_mula_da_ll_lddec, "vIUii**IUii", "n") +BUILTIN(__builtin_xtensa_mula_da_lh_lddec, "vIUii**IUii", "n") +BUILTIN(__builtin_xtensa_mula_da_hl_lddec, "vIUii**IUii", "n") +BUILTIN(__builtin_xtensa_mula_da_hh_lddec, "vIUii**IUii", "n") + +BUILTIN(__builtin_xtensa_mula_da_ll_ldinc, "vIUii**IUii", "n") +BUILTIN(__builtin_xtensa_mula_da_lh_ldinc, "vIUii**IUii", "n") +BUILTIN(__builtin_xtensa_mula_da_hl_ldinc, "vIUii**IUii", "n") +BUILTIN(__builtin_xtensa_mula_da_hh_ldinc, "vIUii**IUii", "n") + +BUILTIN(__builtin_xtensa_mula_dd_ll_lddec, "vIUii**IUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_lh_lddec, "vIUii**IUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_hl_lddec, "vIUii**IUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_hh_lddec, "vIUii**IUiIUi", "n") + +BUILTIN(__builtin_xtensa_mula_dd_ll_ldinc, "vIUii**IUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_lh_ldinc, "vIUii**IUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_hl_ldinc, "vIUii**IUiIUi", "n") +BUILTIN(__builtin_xtensa_mula_dd_hh_ldinc, "vIUii**IUiIUi", "n") + +// Load operations + +BUILTIN(__builtin_xtensa_ldinc, "vIUii**", "n") +BUILTIN(__builtin_xtensa_lddec, "vIUii**", "n") + +// WSR/RSR/XSR + +BUILTIN(__builtin_xtensa_wsr_acclo, "vUi", "n") +BUILTIN(__builtin_xtensa_rsr_acclo, "Ui", "n") +BUILTIN(__builtin_xtensa_xsr_acclo, "vUi*", "n") +BUILTIN(__builtin_xtensa_wsr_acchi, "vUi", "n") +BUILTIN(__builtin_xtensa_rsr_acchi, "Ui", "n") +BUILTIN(__builtin_xtensa_xsr_acchi, "vUi*", "n") +BUILTIN(__builtin_xtensa_wsr_m0, "vUi", "n") +BUILTIN(__builtin_xtensa_rsr_m0, "Ui", "n") +BUILTIN(__builtin_xtensa_xsr_m0, "vUi*", "n") +BUILTIN(__builtin_xtensa_wsr_m1, "vUi", "n") +BUILTIN(__builtin_xtensa_rsr_m1, "Ui", "n") +BUILTIN(__builtin_xtensa_xsr_m1, "vUi*", "n") +BUILTIN(__builtin_xtensa_wsr_m2, "vUi", "n") +BUILTIN(__builtin_xtensa_rsr_m2, "Ui", "n") +BUILTIN(__builtin_xtensa_xsr_m2, "vUi*", "n") +BUILTIN(__builtin_xtensa_wsr_m3, "vUi", "n") +BUILTIN(__builtin_xtensa_rsr_m3, "Ui", "n") +BUILTIN(__builtin_xtensa_xsr_m3, "vUi*", "n") + +#undef BUILTIN \ No newline at end of file diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index d8ad9858d8c80..c26637e36bac3 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -336,6 +336,16 @@ namespace clang { }; } + /// Xtensa builtins + namespace Xtensa { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsXtensa.def" + LastTSBuiltin + }; + } // namespace Xtensa + static constexpr uint64_t LargestBuiltinID = std::max( {ARM::LastTSBuiltin, AArch64::LastTSBuiltin, BPF::LastTSBuiltin, PPC::LastTSBuiltin, NVPTX::LastTSBuiltin, AMDGPU::LastTSBuiltin, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 681a76dfa56a6..cd8ffbfabf21b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13117,6 +13117,7 @@ class Sema final { bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum); bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); + bool CheckXtensaBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); diff --git a/clang/lib/Basic/Targets/Xtensa.cpp b/clang/lib/Basic/Targets/Xtensa.cpp index 270af0a05cfdc..2fb0474801b63 100644 --- a/clang/lib/Basic/Targets/Xtensa.cpp +++ b/clang/lib/Basic/Targets/Xtensa.cpp @@ -20,6 +20,12 @@ using namespace clang; using namespace clang::targets; +const Builtin::Info XtensaTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsXtensa.def" +}; + void XtensaTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__Xtensa__"); @@ -27,3 +33,8 @@ void XtensaTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__XTENSA__"); Builder.defineMacro("__XTENSA_EL__"); } + +ArrayRef XtensaTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Xtensa::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index 188b2dc803ccd..981edf5cb2809 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -53,7 +53,7 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - ArrayRef getTargetBuiltins() const override { return None; } + ArrayRef getTargetBuiltins() const override; BuiltinVaListKind getBuiltinVaListKind() const override { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index dae51d0690e6d..6b646dd02c0d2 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1981,6 +1981,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::riscv32: case llvm::Triple::riscv64: return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::xtensa: + return CheckXtensaBuiltinFunctionCall(BuiltinID, TheCall); } } @@ -4514,6 +4516,83 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, i, l, u); } +bool Sema::CheckXtensaBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + unsigned i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: + return false; + case Xtensa::BI__builtin_xtensa_mul_ad_ll: + case Xtensa::BI__builtin_xtensa_mul_ad_lh: + case Xtensa::BI__builtin_xtensa_mul_ad_hl: + case Xtensa::BI__builtin_xtensa_mul_ad_hh: + case Xtensa::BI__builtin_xtensa_mula_ad_ll: + case Xtensa::BI__builtin_xtensa_mula_ad_lh: + case Xtensa::BI__builtin_xtensa_mula_ad_hl: + case Xtensa::BI__builtin_xtensa_mula_ad_hh: + case Xtensa::BI__builtin_xtensa_muls_ad_ll: + case Xtensa::BI__builtin_xtensa_muls_ad_lh: + case Xtensa::BI__builtin_xtensa_muls_ad_hl: + case Xtensa::BI__builtin_xtensa_muls_ad_hh: + i = 1; + l = 2; + u = 3; + break; + case Xtensa::BI__builtin_xtensa_mul_da_ll: + case Xtensa::BI__builtin_xtensa_mul_da_lh: + case Xtensa::BI__builtin_xtensa_mul_da_hl: + case Xtensa::BI__builtin_xtensa_mul_da_hh: + case Xtensa::BI__builtin_xtensa_mula_da_ll: + case Xtensa::BI__builtin_xtensa_mula_da_lh: + case Xtensa::BI__builtin_xtensa_mula_da_hl: + case Xtensa::BI__builtin_xtensa_mula_da_hh: + case Xtensa::BI__builtin_xtensa_muls_da_ll: + case Xtensa::BI__builtin_xtensa_muls_da_lh: + case Xtensa::BI__builtin_xtensa_muls_da_hl: + case Xtensa::BI__builtin_xtensa_muls_da_hh: + i = 0; + l = 0; + u = 1; + break; + case Xtensa::BI__builtin_xtensa_mul_dd_ll: + case Xtensa::BI__builtin_xtensa_mul_dd_lh: + case Xtensa::BI__builtin_xtensa_mul_dd_hl: + case Xtensa::BI__builtin_xtensa_mul_dd_hh: + case Xtensa::BI__builtin_xtensa_mula_dd_ll: + case Xtensa::BI__builtin_xtensa_mula_dd_lh: + case Xtensa::BI__builtin_xtensa_mula_dd_hl: + case Xtensa::BI__builtin_xtensa_mula_dd_hh: + case Xtensa::BI__builtin_xtensa_muls_dd_ll: + case Xtensa::BI__builtin_xtensa_muls_dd_lh: + case Xtensa::BI__builtin_xtensa_muls_dd_hl: + case Xtensa::BI__builtin_xtensa_muls_dd_hh: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 1, 2, 3); + case Xtensa::BI__builtin_xtensa_mula_da_ll_lddec: + case Xtensa::BI__builtin_xtensa_mula_da_lh_lddec: + case Xtensa::BI__builtin_xtensa_mula_da_hl_lddec: + case Xtensa::BI__builtin_xtensa_mula_da_hh_lddec: + case Xtensa::BI__builtin_xtensa_mula_da_ll_ldinc: + case Xtensa::BI__builtin_xtensa_mula_da_lh_ldinc: + case Xtensa::BI__builtin_xtensa_mula_da_hl_ldinc: + case Xtensa::BI__builtin_xtensa_mula_da_hh_ldinc: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); + case Xtensa::BI__builtin_xtensa_mula_dd_ll_lddec: + case Xtensa::BI__builtin_xtensa_mula_dd_lh_lddec: + case Xtensa::BI__builtin_xtensa_mula_dd_hl_lddec: + case Xtensa::BI__builtin_xtensa_mula_dd_hh_lddec: + case Xtensa::BI__builtin_xtensa_mula_dd_ll_ldinc: + case Xtensa::BI__builtin_xtensa_mula_dd_lh_ldinc: + case Xtensa::BI__builtin_xtensa_mula_dd_hl_ldinc: + case Xtensa::BI__builtin_xtensa_mula_dd_hh_ldinc: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 3, 2, 3); + } + return SemaBuiltinConstantArgRange(TheCall, i, l, u); +} + /// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *). /// This checks that the target supports __builtin_cpu_supports and /// that the string argument is constant and valid. diff --git a/llvm/include/llvm/IR/CMakeLists.txt b/llvm/include/llvm/IR/CMakeLists.txt index 5151f9125b946..2ae6aa0cc23c0 100644 --- a/llvm/include/llvm/IR/CMakeLists.txt +++ b/llvm/include/llvm/IR/CMakeLists.txt @@ -20,5 +20,6 @@ tablegen(LLVM IntrinsicsS390.h -gen-intrinsic-enums -intrinsic-prefix=s390) tablegen(LLVM IntrinsicsWebAssembly.h -gen-intrinsic-enums -intrinsic-prefix=wasm) tablegen(LLVM IntrinsicsX86.h -gen-intrinsic-enums -intrinsic-prefix=x86) tablegen(LLVM IntrinsicsXCore.h -gen-intrinsic-enums -intrinsic-prefix=xcore) +tablegen(LLVM IntrinsicsXtensa.h -gen-intrinsic-enums -intrinsic-prefix=xtensa) tablegen(LLVM IntrinsicsVE.h -gen-intrinsic-enums -intrinsic-prefix=ve) add_public_tablegen_target(intrinsics_gen) diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index d46fa4fbf5b50..974674e2a286f 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -2053,3 +2053,4 @@ include "llvm/IR/IntrinsicsRISCV.td" include "llvm/IR/IntrinsicsSPIRV.td" include "llvm/IR/IntrinsicsVE.td" include "llvm/IR/IntrinsicsDirectX.td" +include "llvm/IR/IntrinsicsXtensa.td" diff --git a/llvm/include/llvm/IR/IntrinsicsXtensa.td b/llvm/include/llvm/IR/IntrinsicsXtensa.td new file mode 100644 index 0000000000000..d7d25609b5d56 --- /dev/null +++ b/llvm/include/llvm/IR/IntrinsicsXtensa.td @@ -0,0 +1,251 @@ +//===- IntrinsicsXtensa.td - Defines Xtensa intrinsics -----*- tablegen -*-===// +// +// 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 defines all of the Xtensa-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +let TargetPrefix = "xtensa" in { // All intrinsics start with "llvm.xtensa.". + +def int_xtensa_umul_aa_ll: ClangBuiltin<"__builtin_xtensa_umul_aa_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_umul_aa_hl: ClangBuiltin<"__builtin_xtensa_umul_aa_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_umul_aa_lh: ClangBuiltin<"__builtin_xtensa_umul_aa_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_umul_aa_hh: ClangBuiltin<"__builtin_xtensa_umul_aa_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; + +def int_xtensa_mul_aa_ll: ClangBuiltin<"__builtin_xtensa_mul_aa_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_mul_aa_hl: ClangBuiltin<"__builtin_xtensa_mul_aa_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_mul_aa_lh: ClangBuiltin<"__builtin_xtensa_mul_aa_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_mul_aa_hh: ClangBuiltin<"__builtin_xtensa_mul_aa_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; + +def int_xtensa_mul_ad_ll: ClangBuiltin<"__builtin_xtensa_mul_ad_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mul_ad_hl: ClangBuiltin<"__builtin_xtensa_mul_ad_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mul_ad_lh: ClangBuiltin<"__builtin_xtensa_mul_ad_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mul_ad_hh: ClangBuiltin<"__builtin_xtensa_mul_ad_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; + +def int_xtensa_mul_da_ll: ClangBuiltin<"__builtin_xtensa_mul_da_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mul_da_hl: ClangBuiltin<"__builtin_xtensa_mul_da_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mul_da_lh: ClangBuiltin<"__builtin_xtensa_mul_da_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mul_da_hh: ClangBuiltin<"__builtin_xtensa_mul_da_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; + +def int_xtensa_mul_dd_ll: ClangBuiltin<"__builtin_xtensa_mul_dd_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_mul_dd_hl: ClangBuiltin<"__builtin_xtensa_mul_dd_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_mul_dd_lh: ClangBuiltin<"__builtin_xtensa_mul_dd_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_mul_dd_hh: ClangBuiltin<"__builtin_xtensa_mul_dd_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; + +def int_xtensa_mula_aa_ll: ClangBuiltin<"__builtin_xtensa_mula_aa_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_mula_aa_hl: ClangBuiltin<"__builtin_xtensa_mula_aa_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_mula_aa_lh: ClangBuiltin<"__builtin_xtensa_mula_aa_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_mula_aa_hh: ClangBuiltin<"__builtin_xtensa_mula_aa_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; + +def int_xtensa_mula_ad_ll: ClangBuiltin<"__builtin_xtensa_mula_ad_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mula_ad_hl: ClangBuiltin<"__builtin_xtensa_mula_ad_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mula_ad_lh: ClangBuiltin<"__builtin_xtensa_mula_ad_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mula_ad_hh: ClangBuiltin<"__builtin_xtensa_mula_ad_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; + +def int_xtensa_mula_da_ll: ClangBuiltin<"__builtin_xtensa_mula_da_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mula_da_hl: ClangBuiltin<"__builtin_xtensa_mula_da_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mula_da_lh: ClangBuiltin<"__builtin_xtensa_mula_da_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_mula_da_hh: ClangBuiltin<"__builtin_xtensa_mula_da_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; + +def int_xtensa_mula_dd_ll: ClangBuiltin<"__builtin_xtensa_mula_dd_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_hl: ClangBuiltin<"__builtin_xtensa_mula_dd_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_lh: ClangBuiltin<"__builtin_xtensa_mula_dd_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_hh: ClangBuiltin<"__builtin_xtensa_mula_dd_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; + +def int_xtensa_muls_aa_ll: ClangBuiltin<"__builtin_xtensa_muls_aa_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_muls_aa_hl: ClangBuiltin<"__builtin_xtensa_muls_aa_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_muls_aa_lh: ClangBuiltin<"__builtin_xtensa_muls_aa_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; +def int_xtensa_muls_aa_hh: ClangBuiltin<"__builtin_xtensa_muls_aa_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; + +def int_xtensa_muls_ad_ll: ClangBuiltin<"__builtin_xtensa_muls_ad_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_muls_ad_hl: ClangBuiltin<"__builtin_xtensa_muls_ad_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_muls_ad_lh: ClangBuiltin<"__builtin_xtensa_muls_ad_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_muls_ad_hh: ClangBuiltin<"__builtin_xtensa_muls_ad_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; + +def int_xtensa_muls_da_ll: ClangBuiltin<"__builtin_xtensa_muls_da_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_muls_da_hl: ClangBuiltin<"__builtin_xtensa_muls_da_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_muls_da_lh: ClangBuiltin<"__builtin_xtensa_muls_da_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; +def int_xtensa_muls_da_hh: ClangBuiltin<"__builtin_xtensa_muls_da_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>]>; + +def int_xtensa_muls_dd_ll: ClangBuiltin<"__builtin_xtensa_muls_dd_ll">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_muls_dd_hl: ClangBuiltin<"__builtin_xtensa_muls_dd_hl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_muls_dd_lh: ClangBuiltin<"__builtin_xtensa_muls_dd_lh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; +def int_xtensa_muls_dd_hh: ClangBuiltin<"__builtin_xtensa_muls_dd_hh">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [ImmArg>, ImmArg>]>; + + +def int_xtensa_mula_da_ll_lddec: ClangBuiltin<"__builtin_xtensa_mula_da_ll_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; +def int_xtensa_mula_da_lh_lddec: ClangBuiltin<"__builtin_xtensa_mula_da_lh_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; +def int_xtensa_mula_da_hl_lddec: ClangBuiltin<"__builtin_xtensa_mula_da_hl_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; +def int_xtensa_mula_da_hh_lddec: ClangBuiltin<"__builtin_xtensa_mula_da_hh_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; + +def int_xtensa_mula_da_ll_ldinc: ClangBuiltin<"__builtin_xtensa_mula_da_ll_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; +def int_xtensa_mula_da_lh_ldinc: ClangBuiltin<"__builtin_xtensa_mula_da_lh_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; +def int_xtensa_mula_da_hl_ldinc: ClangBuiltin<"__builtin_xtensa_mula_da_hl_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; +def int_xtensa_mula_da_hh_ldinc: ClangBuiltin<"__builtin_xtensa_mula_da_hh_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>]>; + +def int_xtensa_mula_dd_ll_lddec: ClangBuiltin<"__builtin_xtensa_mula_dd_ll_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_lh_lddec: ClangBuiltin<"__builtin_xtensa_mula_dd_lh_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_hl_lddec: ClangBuiltin<"__builtin_xtensa_mula_dd_hl_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_hh_lddec: ClangBuiltin<"__builtin_xtensa_mula_dd_hh_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; + +def int_xtensa_mula_dd_ll_ldinc: ClangBuiltin<"__builtin_xtensa_mula_dd_ll_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_lh_ldinc: ClangBuiltin<"__builtin_xtensa_mula_dd_lh_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_hl_ldinc: ClangBuiltin<"__builtin_xtensa_mula_dd_hl_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; +def int_xtensa_mula_dd_hh_ldinc: ClangBuiltin<"__builtin_xtensa_mula_dd_hh_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], + [ImmArg>, ImmArg>, ImmArg>]>; + +//===----------------------------------------------------------------------===// +// Load operations + +def int_xtensa_lddec: ClangBuiltin<"__builtin_xtensa_lddec">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty], [ImmArg>]>; + +def int_xtensa_ldinc: ClangBuiltin<"__builtin_xtensa_ldinc">, + Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty], [ImmArg>]>; + +//===----------------------------------------------------------------------===// +// WSR/XSR/RSR + +def int_xtensa_wsr_acclo: ClangBuiltin<"__builtin_xtensa_wsr_acclo">, + Intrinsic<[], [llvm_i32_ty], []>; + +def int_xtensa_rsr_acclo: ClangBuiltin<"__builtin_xtensa_rsr_acclo">, + Intrinsic<[llvm_i32_ty], [], []>; + +def int_xtensa_xsr_acclo: ClangBuiltin<"__builtin_xtensa_xsr_acclo">, + Intrinsic<[], [llvm_ptr_ty], []>; + +def int_xtensa_wsr_acchi: ClangBuiltin<"__builtin_xtensa_wsr_acchi">, + Intrinsic<[], [llvm_i32_ty], []>; + +def int_xtensa_rsr_acchi: ClangBuiltin<"__builtin_xtensa_rsr_acchi">, + Intrinsic<[llvm_i32_ty], [], []>; + +def int_xtensa_xsr_acchi: ClangBuiltin<"__builtin_xtensa_xsr_acchi">, + Intrinsic<[], [llvm_ptr_ty], []>; + +def int_xtensa_wsr_m0: ClangBuiltin<"__builtin_xtensa_wsr_m0">, + Intrinsic<[], [llvm_i32_ty], []>; + +def int_xtensa_rsr_m0: ClangBuiltin<"__builtin_xtensa_rsr_m0">, + Intrinsic<[llvm_i32_ty]>; + +def int_xtensa_xsr_m0: ClangBuiltin<"__builtin_xtensa_xsr_m0">, + Intrinsic<[], [llvm_ptr_ty], []>; + +def int_xtensa_wsr_m1: ClangBuiltin<"__builtin_xtensa_wsr_m1">, + Intrinsic<[], [llvm_i32_ty], []>; + +def int_xtensa_rsr_m1: ClangBuiltin<"__builtin_xtensa_rsr_m1">, + Intrinsic<[llvm_i32_ty], [], []>; + +def int_xtensa_xsr_m1: ClangBuiltin<"__builtin_xtensa_xsr_m1">, + Intrinsic<[], [llvm_ptr_ty], []>; + +def int_xtensa_wsr_m2: ClangBuiltin<"__builtin_xtensa_wsr_m2">, + Intrinsic<[], [llvm_i32_ty], []>; + +def int_xtensa_rsr_m2: ClangBuiltin<"__builtin_xtensa_rsr_m2">, + Intrinsic<[llvm_i32_ty], [], []>; + +def int_xtensa_xsr_m2: ClangBuiltin<"__builtin_xtensa_xsr_m2">, + Intrinsic<[], [llvm_ptr_ty], []>; + +def int_xtensa_wsr_m3: ClangBuiltin<"__builtin_xtensa_wsr_m3">, + Intrinsic<[], [llvm_i32_ty], []>; + +def int_xtensa_rsr_m3: ClangBuiltin<"__builtin_xtensa_rsr_m3">, + Intrinsic<[llvm_i32_ty], [], []>; + +def int_xtensa_xsr_m3: ClangBuiltin<"__builtin_xtensa_xsr_m3">, + Intrinsic<[], [llvm_ptr_ty], []>; + +} diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index d4138133721e8..fb854dc17dea8 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -48,6 +48,7 @@ #include "llvm/IR/IntrinsicsWebAssembly.h" #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/IntrinsicsXCore.h" +#include "llvm/IR/IntrinsicsXtensa.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" diff --git a/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td index d80df46320643..aec66efd8d2f2 100644 --- a/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaDSPInstrInfo.td @@ -13,29 +13,31 @@ //===----------------------------------------------------------------------===// // Multiply -class UMUL_AA oper1, string instrAsm> +class UMUL_AA oper1, string instrAsm, SDPatternOperator opNode> : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), - instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + instrAsm#"\t$s, $t", + [(opNode AR:$s, AR:$t)]>, Requires<[HasMAC16]> { let r = 0; let Defs = [M1, M2, ACCLO, ACCHI]; } -def UMUL_AA_LL : UMUL_AA<0x00, "umul.aa.ll">; -def UMUL_AA_HL : UMUL_AA<0x01, "umul.aa.hl">; -def UMUL_AA_LH : UMUL_AA<0x02, "umul.aa.lh">; -def UMUL_AA_HH : UMUL_AA<0x03, "umul.aa.hh">; +def UMUL_AA_LL : UMUL_AA<0x00, "umul.aa.ll", int_xtensa_umul_aa_ll>; +def UMUL_AA_HL : UMUL_AA<0x01, "umul.aa.hl", int_xtensa_umul_aa_hl>; +def UMUL_AA_LH : UMUL_AA<0x02, "umul.aa.lh", int_xtensa_umul_aa_lh>; +def UMUL_AA_HH : UMUL_AA<0x03, "umul.aa.hh", int_xtensa_umul_aa_hh>; -class MUL_AA oper1, string instrAsm> +class MUL_AA oper1, string instrAsm, SDPatternOperator opNode> : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), - instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + instrAsm#"\t$s, $t", + [(opNode AR:$s, AR:$t)]>, Requires<[HasMAC16]> { let r = 0; let Defs = [M1, M2, ACCLO, ACCHI]; } -def MUL_AA_LL : MUL_AA<0x04, "mul.aa.ll">; -def MUL_AA_HL : MUL_AA<0x05, "mul.aa.hl">; -def MUL_AA_LH : MUL_AA<0x06, "mul.aa.lh">; -def MUL_AA_HH : MUL_AA<0x07, "mul.aa.hh">; +def MUL_AA_LL : MUL_AA<0x04, "mul.aa.ll", int_xtensa_mul_aa_ll>; +def MUL_AA_HL : MUL_AA<0x05, "mul.aa.hl", int_xtensa_mul_aa_hl>; +def MUL_AA_LH : MUL_AA<0x06, "mul.aa.lh", int_xtensa_mul_aa_lh>; +def MUL_AA_HH : MUL_AA<0x07, "mul.aa.hh", int_xtensa_mul_aa_hh>; class MUL_AD oper1, string instrAsm> : RRR_Inst<0x04, oper1, 0x03, (outs), (ins AR:$s, MR23:$y), @@ -92,17 +94,18 @@ def MUL_DD_HL : MUL_DD<0x05, "mul.dd.hl">; def MUL_DD_LH : MUL_DD<0x06, "mul.dd.lh">; def MUL_DD_HH : MUL_DD<0x07, "mul.dd.hh">; -class MULA_AA oper1, string instrAsm> +class MULA_AA oper1, string instrAsm, SDPatternOperator opNode> : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), - instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + instrAsm#"\t$s, $t", + [(opNode AR:$s, AR:$t)]>, Requires<[HasMAC16]> { let r = 0; let Defs = [M1, M2, ACCLO, ACCHI]; } -def MULA_AA_LL : MULA_AA<0x08, "mula.aa.ll">; -def MULA_AA_HL : MULA_AA<0x09, "mula.aa.hl">; -def MULA_AA_LH : MULA_AA<0x0A, "mula.aa.lh">; -def MULA_AA_HH : MULA_AA<0x0B, "mula.aa.hh">; +def MULA_AA_LL : MULA_AA<0x08, "mula.aa.ll", int_xtensa_mula_aa_ll>; +def MULA_AA_HL : MULA_AA<0x09, "mula.aa.hl", int_xtensa_mula_aa_hl>; +def MULA_AA_LH : MULA_AA<0x0A, "mula.aa.lh", int_xtensa_mula_aa_lh>; +def MULA_AA_HH : MULA_AA<0x0B, "mula.aa.hh", int_xtensa_mula_aa_hh>; class MULA_AD oper1, string instrAsm> : RRR_Inst<0x04, oper1, 0x03, (outs), (ins AR:$s, MR23:$y), @@ -165,18 +168,19 @@ def MULA_DD_HL : MULA_DD<0x09, "mula.dd.hl">; def MULA_DD_LH : MULA_DD<0x0A, "mula.dd.lh">; def MULA_DD_HH : MULA_DD<0x0B, "mula.dd.hh">; -class MULS_AA oper1, string instrAsm> +class MULS_AA oper1, string instrAsm, SDPatternOperator opNode> : RRR_Inst<0x04, oper1, 0x07, (outs), (ins AR:$s, AR:$t), - instrAsm#"\t$s, $t", []>, Requires<[HasMAC16]> { + instrAsm#"\t$s, $t", + [(opNode AR:$s, AR:$t)]>, Requires<[HasMAC16]> { let r = 0; let Uses = [ACCLO, ACCHI]; let Defs = [M1, M2, ACCLO, ACCHI]; } -def MULS_AA_LL : MULS_AA<0x0C, "muls.aa.ll">; -def MULS_AA_HL : MULS_AA<0x0D, "muls.aa.hl">; -def MULS_AA_LH : MULS_AA<0x0E, "muls.aa.lh">; -def MULS_AA_HH : MULS_AA<0x0F, "muls.aa.hh">; +def MULS_AA_LL : MULS_AA<0x0C, "muls.aa.ll", int_xtensa_muls_aa_ll>; +def MULS_AA_HL : MULS_AA<0x0D, "muls.aa.hl", int_xtensa_muls_aa_hl>; +def MULS_AA_LH : MULS_AA<0x0E, "muls.aa.lh", int_xtensa_muls_aa_lh>; +def MULS_AA_HH : MULS_AA<0x0F, "muls.aa.hh", int_xtensa_muls_aa_hh>; class MULS_AD oper1, string instrAsm> : RRR_Inst<0x04, oper1, 0x03, (outs), (ins AR:$s, MR23:$y), @@ -262,6 +266,21 @@ def MULA_DA_HL_LDDEC : MULA_DA_LDDEC<0x09, "mula.da.hl.lddec">; def MULA_DA_LH_LDDEC : MULA_DA_LDDEC<0x0A, "mula.da.lh.lddec">; def MULA_DA_HH_LDDEC : MULA_DA_LDDEC<0x0B, "mula.da.hh.lddec">; +let usesCustomInserter = 1, Predicates = [HasMAC16] in { + def MULA_DA_LL_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_ll_lddec_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_ll_lddec timm:$mw, AR:$s, timm:$mx, AR:$t)]>; + def MULA_DA_HL_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_hl_lddec_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_hl_lddec timm:$mw, AR:$s, timm:$mx, AR:$t)]>; + def MULA_DA_LH_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_lh_lddec_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_lh_lddec timm:$mw, AR:$s, timm:$mx, AR:$t)]>; + def MULA_DA_HH_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_hh_lddec_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_hh_lddec timm:$mw, AR:$s, timm:$mx, AR:$t)]>; +} + class MULA_DA_LDINC oper1, string instrAsm> : RRR_Inst<0x04, oper1, 0x04, (outs MR:$w, AR:$d), (ins AR:$s, MR:$x, AR:$t), instrAsm#"\t $w, $s, $x, $t", []>, Requires<[HasMAC16]> { @@ -277,10 +296,25 @@ class MULA_DA_LDINC oper1, string instrAsm> let Defs = [M1, M2, ACCLO, ACCHI]; } -def MULA_DA_LL_LDINC: MULA_DA_LDINC<0x08, "mula.da.ll.ldinc">; -def MULA_DA_HL_LDINC: MULA_DA_LDINC<0x09, "mula.da.hl.ldinc">; -def MULA_DA_LH_LDINC: MULA_DA_LDINC<0x0A, "mula.da.lh.ldinc">; -def MULA_DA_HH_LDINC: MULA_DA_LDINC<0x0B, "mula.da.hh.ldinc">; +def MULA_DA_LL_LDINC : MULA_DA_LDINC<0x08, "mula.da.ll.ldinc">; +def MULA_DA_HL_LDINC : MULA_DA_LDINC<0x09, "mula.da.hl.ldinc">; +def MULA_DA_LH_LDINC : MULA_DA_LDINC<0x0A, "mula.da.lh.ldinc">; +def MULA_DA_HH_LDINC : MULA_DA_LDINC<0x0B, "mula.da.hh.ldinc">; + +let usesCustomInserter = 1, Predicates = [HasMAC16] in { + def MULA_DA_LL_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_ll_ldinc_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_ll_ldinc timm:$mw, AR:$s, timm:$mx, AR:$t)]>; + def MULA_DA_HL_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_hl_ldinc_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_hl_ldinc timm:$mw, AR:$s, timm:$mx, AR:$t)]>; + def MULA_DA_LH_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_lh_ldinc_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_lh_ldinc timm:$mw, AR:$s, timm:$mx, AR:$t)]>; + def MULA_DA_HH_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, AR:$t), + "!xtensa_mula_da_hh_ldinc_p, $mw, $s, $mx, $t", + [(int_xtensa_mula_da_hh_ldinc timm:$mw, AR:$s, timm:$mx, AR:$t)]>; +} class MULA_DD_LDDEC oper1, string instrAsm> : RRR_Inst<0x04, oper1, 0x01, (outs MR:$w, AR:$d), (ins AR:$s, MR01:$x, MR23:$y), @@ -306,6 +340,21 @@ def MULA_DD_HL_LDDEC : MULA_DD_LDDEC<0x09, "mula.dd.hl.lddec">; def MULA_DD_LH_LDDEC : MULA_DD_LDDEC<0x0A, "mula.dd.lh.lddec">; def MULA_DD_HH_LDDEC : MULA_DD_LDDEC<0x0B, "mula.dd.hh.lddec">; +let usesCustomInserter = 1, Predicates = [HasMAC16] in { + def MULA_DD_LL_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_ll_lddec_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_ll_lddec timm:$mw, AR:$s, timm:$mx, timm:$my)]>; + def MULA_DD_HL_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_hl_lddec_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_hl_lddec timm:$mw, AR:$s, timm:$mx, timm:$my)]>; + def MULA_DD_LH_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_lh_lddec_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_lh_lddec timm:$mw, AR:$s, timm:$mx, timm:$my)]>; + def MULA_DD_HH_LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_hh_lddec_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_hh_lddec timm:$mw, AR:$s, timm:$mx, timm:$my)]>; +} + class MULA_DD_LDINC oper1, string instrAsm> : RRR_Inst<0x04, oper1, 0x00, (outs MR:$w, AR:$d), (ins AR:$s, MR01:$x, MR23:$y), instrAsm#"\t $w, $s, $x, $y", []>, Requires<[HasMAC16]> { @@ -330,6 +379,21 @@ def MULA_DD_HL_LDINC : MULA_DD_LDINC<0x09, "mula.dd.hl.ldinc">; def MULA_DD_LH_LDINC : MULA_DD_LDINC<0x0A, "mula.dd.lh.ldinc">; def MULA_DD_HH_LDINC : MULA_DD_LDINC<0x0B, "mula.dd.hh.ldinc">; +let usesCustomInserter = 1, Predicates = [HasMAC16] in { + def MULA_DD_LL_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_ll_ldinc_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_ll_ldinc timm:$mw, AR:$s, timm:$mx, timm:$my)]>; + def MULA_DD_HL_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_hl_ldinc_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_hl_ldinc timm:$mw, AR:$s, timm:$mx, timm:$my)]>; + def MULA_DD_LH_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_lh_ldinc_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_lh_ldinc timm:$mw, AR:$s, timm:$mx, timm:$my)]>; + def MULA_DD_HH_LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s, imm8:$mx, imm8:$my), + "!xtensa_mula_dd_hh_ldinc_p, $mw, $s, $mx, $my", + [(int_xtensa_mula_dd_hh_ldinc timm:$mw, AR:$s, timm:$mx, timm:$my)]>; +} + def LDDEC : RRR_Inst<0x04, 0x00, 0x09, (outs MR:$w, AR:$d), (ins AR:$s), "lddec\t $w, $s", []>, Requires<[HasMAC16]> { bits<2> w; @@ -351,3 +415,58 @@ def LDINC : RRR_Inst<0x04, 0x00, 0x08, (outs MR:$w, AR:$d), (ins AR:$s), let r{1-0} = w{1-0}; let t = 0; } + +let usesCustomInserter = 1, Predicates = [HasMAC16] in { + def LDDEC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s), + "!xtensa_lddec_p, $mw, $s", + [(int_xtensa_lddec timm:$mw, AR:$s)]>; + def LDINC_P : Pseudo<(outs), (ins imm8:$mw, AR:$s), + "!xtensa_ldinc_p, $mw, $s", + [(int_xtensa_ldinc timm:$mw, AR:$s)]>; +} + +def : Pat<(i32 (int_xtensa_rsr_acclo)), (RSR ACCLO)>; +def : Pat<(i32 (int_xtensa_rsr_acchi)), (RSR ACCHI)>; +def : Pat<(i32 (int_xtensa_rsr_m0)), (RSR M0)>; +def : Pat<(i32 (int_xtensa_rsr_m1)), (RSR M1)>; +def : Pat<(i32 (int_xtensa_rsr_m2)), (RSR M2)>; +def : Pat<(i32 (int_xtensa_rsr_m3)), (RSR M3)>; + +let usesCustomInserter = 1, Predicates = [HasMAC16] in { + def XSR_ACCLO_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_xsr_acclo_p, $s", + [(int_xtensa_xsr_acclo AR:$s)]>; + def XSR_ACCHI_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_xsr_acchi_p, $s", + [(int_xtensa_xsr_acchi AR:$s)]>; + def XSR_M0_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_xsr_m0_p, $s", + [(int_xtensa_xsr_m0 AR:$s)]>; + def XSR_M1_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_xsr_m1_p, $s", + [(int_xtensa_xsr_m1 AR:$s)]>; + def XSR_M2_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_xsr_m2_p, $s", + [(int_xtensa_xsr_m2 AR:$s)]>; + def XSR_M3_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_xsr_m3_p, $s", + [(int_xtensa_xsr_m3 AR:$s)]>; + def WSR_ACCLO_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_wsr_acclo_p, $s", + [(int_xtensa_wsr_acclo AR:$s)]>; + def WSR_ACCHI_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_wsr_acchi_p, $s", + [(int_xtensa_wsr_acchi AR:$s)]>; + def WSR_M0_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_wsr_m0_p, $s", + [(int_xtensa_wsr_m0 AR:$s)]>; + def WSR_M1_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_wsr_m1_p, $s", + [(int_xtensa_wsr_m1 AR:$s)]>; + def WSR_M2_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_wsr_m2_p, $s", + [(int_xtensa_wsr_m2 AR:$s)]>; + def WSR_M3_P : Pseudo<(outs), (ins AR:$s), + "!xtensa_wsr_m3_p, $s", + [(int_xtensa_wsr_m3 AR:$s)]>; +} diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp index fc4155ec54a1c..be95e9a2720a6 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp @@ -14,6 +14,7 @@ #include "Xtensa.h" #include "XtensaTargetMachine.h" +#include "llvm/IR/IntrinsicsXtensa.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" @@ -128,14 +129,258 @@ FunctionPass *llvm::createXtensaISelDag(XtensaTargetMachine &TM, } void XtensaDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); SDLoc DL(Node); - // Dump information about the Node being selected - LLVM_DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + const unsigned MRTable[] = {Xtensa::M0, Xtensa::M1, Xtensa::M2, Xtensa::M3}; - // If we have a custom node, we already have selected! - if (Node->isMachineOpcode()) { - LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); - return; + switch (Opcode) { + case ISD::INTRINSIC_VOID: { + unsigned IntNo = cast(Node->getOperand(1))->getZExtValue(); + switch (IntNo) { + default: + break; + case Intrinsic::xtensa_mul_da_ll: + case Intrinsic::xtensa_mul_da_lh: + case Intrinsic::xtensa_mul_da_hl: + case Intrinsic::xtensa_mul_da_hh: + case Intrinsic::xtensa_mula_da_ll: + case Intrinsic::xtensa_mula_da_lh: + case Intrinsic::xtensa_mula_da_hl: + case Intrinsic::xtensa_mula_da_hh: + case Intrinsic::xtensa_muls_da_ll: + case Intrinsic::xtensa_muls_da_lh: + case Intrinsic::xtensa_muls_da_hl: + case Intrinsic::xtensa_muls_da_hh: { + SDValue ChainIn = Node->getOperand(0); + SDValue ValueMX = Node->getOperand(2); + SDValue ValueT = Node->getOperand(3); + unsigned OpCode; + + switch (IntNo) { + case Intrinsic::xtensa_mul_da_ll: + OpCode = Xtensa::MUL_DA_LL; + break; + case Intrinsic::xtensa_mul_da_lh: + OpCode = Xtensa::MUL_DA_LH; + break; + case Intrinsic::xtensa_mul_da_hl: + OpCode = Xtensa::MUL_DA_HL; + break; + case Intrinsic::xtensa_mul_da_hh: + OpCode = Xtensa::MUL_DA_HH; + break; + case Intrinsic::xtensa_mula_da_ll: + OpCode = Xtensa::MULA_DA_LL; + break; + case Intrinsic::xtensa_mula_da_lh: + OpCode = Xtensa::MULA_DA_LH; + break; + case Intrinsic::xtensa_mula_da_hl: + OpCode = Xtensa::MULA_DA_HL; + break; + case Intrinsic::xtensa_mula_da_hh: + OpCode = Xtensa::MULA_DA_HH; + break; + case Intrinsic::xtensa_muls_da_ll: + OpCode = Xtensa::MULS_DA_LL; + break; + case Intrinsic::xtensa_muls_da_lh: + OpCode = Xtensa::MULS_DA_LH; + break; + case Intrinsic::xtensa_muls_da_hl: + OpCode = Xtensa::MULS_DA_HL; + break; + case Intrinsic::xtensa_muls_da_hh: + OpCode = Xtensa::MULS_DA_HH; + break; + } + + uint64_t MXVal = 4; + if (ValueMX.getOpcode() == ISD::TargetConstant) { + MXVal = cast(ValueMX)->getZExtValue(); + } + + assert( + (MXVal < 2) && + "Unexpected value of mul*_da* first argument, it must be m0 or m1"); + unsigned MXReg = MRTable[MXVal]; + + const EVT MULAResTys[] = {MVT::Other}; + SmallVector MULAOps; + MULAOps.push_back(CurDAG->getRegister(MXReg, MVT::i32)); + MULAOps.push_back(ValueT); + MULAOps.push_back(ChainIn); + + SDNode *MULA = CurDAG->getMachineNode(OpCode, DL, MULAResTys, MULAOps); + ReplaceNode(Node, MULA); + return; + } + case Intrinsic::xtensa_mul_ad_ll: + case Intrinsic::xtensa_mul_ad_lh: + case Intrinsic::xtensa_mul_ad_hl: + case Intrinsic::xtensa_mul_ad_hh: + case Intrinsic::xtensa_mula_ad_ll: + case Intrinsic::xtensa_mula_ad_lh: + case Intrinsic::xtensa_mula_ad_hl: + case Intrinsic::xtensa_mula_ad_hh: + case Intrinsic::xtensa_muls_ad_ll: + case Intrinsic::xtensa_muls_ad_lh: + case Intrinsic::xtensa_muls_ad_hl: + case Intrinsic::xtensa_muls_ad_hh: { + SDValue ChainIn = Node->getOperand(0); + SDValue ValueS = Node->getOperand(2); + SDValue ValueMY = Node->getOperand(3); + unsigned OpCode; + + switch (IntNo) { + case Intrinsic::xtensa_mul_ad_ll: + OpCode = Xtensa::MUL_AD_LL; + break; + case Intrinsic::xtensa_mul_ad_lh: + OpCode = Xtensa::MUL_AD_LH; + break; + case Intrinsic::xtensa_mul_ad_hl: + OpCode = Xtensa::MUL_AD_HL; + break; + case Intrinsic::xtensa_mul_ad_hh: + OpCode = Xtensa::MUL_AD_HH; + break; + case Intrinsic::xtensa_mula_ad_ll: + OpCode = Xtensa::MULA_AD_LL; + break; + case Intrinsic::xtensa_mula_ad_lh: + OpCode = Xtensa::MULA_AD_LH; + break; + case Intrinsic::xtensa_mula_ad_hl: + OpCode = Xtensa::MULA_AD_HL; + break; + case Intrinsic::xtensa_mula_ad_hh: + OpCode = Xtensa::MULA_AD_HH; + break; + case Intrinsic::xtensa_muls_ad_ll: + OpCode = Xtensa::MULS_AD_LL; + break; + case Intrinsic::xtensa_muls_ad_lh: + OpCode = Xtensa::MULS_AD_LH; + break; + case Intrinsic::xtensa_muls_ad_hl: + OpCode = Xtensa::MULS_AD_HL; + break; + case Intrinsic::xtensa_muls_ad_hh: + OpCode = Xtensa::MULS_AD_HH; + break; + } + + uint64_t MYVal = 4; + if (ValueMY.getOpcode() == ISD::TargetConstant) { + MYVal = cast(ValueMY)->getZExtValue(); + } + + assert( + ((MYVal > 1) && (MYVal < 4)) && + "Unexpected value of mul*_ad* second argument, it must be m2 or m3"); + unsigned MYReg = MRTable[MYVal]; + + const EVT MULAResTys[] = {MVT::Other}; + SmallVector MULAOps; + MULAOps.push_back(ValueS); + MULAOps.push_back(CurDAG->getRegister(MYReg, MVT::i32)); + MULAOps.push_back(ChainIn); + + SDNode *MULA = CurDAG->getMachineNode(OpCode, DL, MULAResTys, MULAOps); + ReplaceNode(Node, MULA); + return; + } + case Intrinsic::xtensa_mul_dd_ll: + case Intrinsic::xtensa_mul_dd_lh: + case Intrinsic::xtensa_mul_dd_hl: + case Intrinsic::xtensa_mul_dd_hh: + case Intrinsic::xtensa_mula_dd_ll: + case Intrinsic::xtensa_mula_dd_lh: + case Intrinsic::xtensa_mula_dd_hl: + case Intrinsic::xtensa_mula_dd_hh: + case Intrinsic::xtensa_muls_dd_ll: + case Intrinsic::xtensa_muls_dd_lh: + case Intrinsic::xtensa_muls_dd_hl: + case Intrinsic::xtensa_muls_dd_hh: { + SDValue ChainIn = Node->getOperand(0); + SDValue ValueMX = Node->getOperand(2); + SDValue ValueMY = Node->getOperand(3); + unsigned OpCode; + + switch (IntNo) { + case Intrinsic::xtensa_mul_dd_ll: + OpCode = Xtensa::MUL_DD_LL; + break; + case Intrinsic::xtensa_mul_dd_lh: + OpCode = Xtensa::MUL_DD_LH; + break; + case Intrinsic::xtensa_mul_dd_hl: + OpCode = Xtensa::MUL_DD_HL; + break; + case Intrinsic::xtensa_mul_dd_hh: + OpCode = Xtensa::MUL_DD_HH; + break; + case Intrinsic::xtensa_mula_dd_ll: + OpCode = Xtensa::MULA_DD_LL; + break; + case Intrinsic::xtensa_mula_dd_lh: + OpCode = Xtensa::MULA_DD_LH; + break; + case Intrinsic::xtensa_mula_dd_hl: + OpCode = Xtensa::MULA_DD_HL; + break; + case Intrinsic::xtensa_mula_dd_hh: + OpCode = Xtensa::MULA_DD_HH; + break; + case Intrinsic::xtensa_muls_dd_ll: + OpCode = Xtensa::MULS_DD_LL; + break; + case Intrinsic::xtensa_muls_dd_lh: + OpCode = Xtensa::MULS_DD_LH; + break; + case Intrinsic::xtensa_muls_dd_hl: + OpCode = Xtensa::MULS_DD_HL; + break; + case Intrinsic::xtensa_muls_dd_hh: + OpCode = Xtensa::MULS_DD_HH; + break; + } + uint64_t MXVal = 4; + if (ValueMX.getOpcode() == ISD::TargetConstant) { + MXVal = cast(ValueMX)->getZExtValue(); + } + + assert( + (MXVal < 2) && + "Unexpected value of mul*_dd* first argument, it must be m0 or m1"); + unsigned MXReg = MRTable[MXVal]; + + uint64_t MYVal = 4; + if (ValueMY.getOpcode() == ISD::TargetConstant) { + MYVal = cast(ValueMY)->getZExtValue(); + } + + assert( + ((MYVal > 1) && (MYVal < 4)) && + "Unexpected value of mul*_dd* second argument, it must be m2 or m3"); + unsigned MYReg = MRTable[MYVal]; + + const EVT MULAResTys[] = {MVT::Other}; + SmallVector MULAOps; + MULAOps.push_back(CurDAG->getRegister(MXReg, MVT::i32)); + MULAOps.push_back(CurDAG->getRegister(MYReg, MVT::i32)); + MULAOps.push_back(ChainIn); + + SDNode *MULA = CurDAG->getMachineNode(OpCode, DL, MULAResTys, MULAOps); + ReplaceNode(Node, MULA); + return; + } + } + break; + } + default: + break; } SelectCode(Node); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 8e843189b87d0..3904e128f44e7 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -2723,6 +2723,268 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( DebugLoc DL = MI.getDebugLoc(); switch (MI.getOpcode()) { + case Xtensa::MULA_DA_LL_LDDEC_P: + case Xtensa::MULA_DA_LH_LDDEC_P: + case Xtensa::MULA_DA_HL_LDDEC_P: + case Xtensa::MULA_DA_HH_LDDEC_P: + case Xtensa::MULA_DA_LL_LDINC_P: + case Xtensa::MULA_DA_LH_LDINC_P: + case Xtensa::MULA_DA_HL_LDINC_P: + case Xtensa::MULA_DA_HH_LDINC_P: { + MachineOperand &MW = MI.getOperand(0); + MachineOperand &S = MI.getOperand(1); + MachineOperand &MX = MI.getOperand(2); + MachineOperand &T = MI.getOperand(3); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned Reg1 = MRI.createVirtualRegister(RC); + unsigned Reg2 = MRI.createVirtualRegister(RC); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::L32I), Reg1) + .addReg(S.getReg()) + .addImm(0); + + unsigned Opc; + switch (MI.getOpcode()) { + case Xtensa::MULA_DA_LL_LDDEC_P: + Opc = Xtensa::MULA_DA_LL_LDDEC; + break; + case Xtensa::MULA_DA_LH_LDDEC_P: + Opc = Xtensa::MULA_DA_LH_LDDEC; + break; + case Xtensa::MULA_DA_HL_LDDEC_P: + Opc = Xtensa::MULA_DA_HL_LDDEC; + break; + case Xtensa::MULA_DA_HH_LDDEC_P: + Opc = Xtensa::MULA_DA_HH_LDDEC; + break; + case Xtensa::MULA_DA_LL_LDINC_P: + Opc = Xtensa::MULA_DA_LL_LDINC; + break; + case Xtensa::MULA_DA_LH_LDINC_P: + Opc = Xtensa::MULA_DA_LH_LDINC; + break; + case Xtensa::MULA_DA_HL_LDINC_P: + Opc = Xtensa::MULA_DA_HL_LDINC; + break; + case Xtensa::MULA_DA_HH_LDINC_P: + Opc = Xtensa::MULA_DA_HH_LDINC; + break; + } + + unsigned MWVal = MW.getImm(); + assert((MWVal < 4) && "Unexpected value of mula_da*ld* first argument, it " + "must be from m0..m3"); + unsigned MXVal = MX.getImm(); + assert((MXVal < 2) && "Unexpected value of mula_da*ld* third " + "argument, it must be m0 or m1"); + + BuildMI(*MBB, MI, DL, TII.get(Opc)) + .addReg(Xtensa::M0 + MWVal, RegState::Define) + .addReg(Reg2, RegState::Define) + .addReg(Reg1) + .addReg(Xtensa::M0 + MXVal) + .addReg(T.getReg()); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::S32I)) + .addReg(Reg2) + .addReg(S.getReg()) + .addImm(0); + + MI.eraseFromParent(); + return MBB; + } + case Xtensa::MULA_DD_LL_LDDEC_P: + case Xtensa::MULA_DD_LH_LDDEC_P: + case Xtensa::MULA_DD_HL_LDDEC_P: + case Xtensa::MULA_DD_HH_LDDEC_P: + case Xtensa::MULA_DD_LL_LDINC_P: + case Xtensa::MULA_DD_LH_LDINC_P: + case Xtensa::MULA_DD_HL_LDINC_P: + case Xtensa::MULA_DD_HH_LDINC_P: { + MachineOperand &MW = MI.getOperand(0); + MachineOperand &S = MI.getOperand(1); + MachineOperand &MX = MI.getOperand(2); + MachineOperand &MY = MI.getOperand(3); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned Reg1 = MRI.createVirtualRegister(RC); + unsigned Reg2 = MRI.createVirtualRegister(RC); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::L32I), Reg1) + .addReg(S.getReg()) + .addImm(0); + + unsigned Opc; + switch (MI.getOpcode()) { + case Xtensa::MULA_DD_LL_LDDEC_P: + Opc = Xtensa::MULA_DD_LL_LDDEC; + break; + case Xtensa::MULA_DD_LH_LDDEC_P: + Opc = Xtensa::MULA_DD_LH_LDDEC; + break; + case Xtensa::MULA_DD_HL_LDDEC_P: + Opc = Xtensa::MULA_DD_HL_LDDEC; + break; + case Xtensa::MULA_DD_HH_LDDEC_P: + Opc = Xtensa::MULA_DD_HH_LDDEC; + break; + case Xtensa::MULA_DD_LL_LDINC_P: + Opc = Xtensa::MULA_DD_LL_LDINC; + break; + case Xtensa::MULA_DD_LH_LDINC_P: + Opc = Xtensa::MULA_DD_LH_LDINC; + break; + case Xtensa::MULA_DD_HL_LDINC_P: + Opc = Xtensa::MULA_DD_HL_LDINC; + break; + case Xtensa::MULA_DD_HH_LDINC_P: + Opc = Xtensa::MULA_DD_HH_LDINC; + break; + } + + unsigned MWVal = MW.getImm(); + assert((MWVal < 4) && "Unexpected value of mula_dd*ld* first argument, " + "it must be from m0..m3"); + unsigned MXVal = MX.getImm(); + assert((MXVal < 2) && "Unexpected value of mula_dd*ld* third " + "argument, it must be m0 or m1"); + unsigned MYVal = MY.getImm(); + assert(((MYVal > 1) && (MYVal < 4)) && + "Unexpected value of mula_dd*ld* fourth " + "argument, it must be m2 or m3"); + + BuildMI(*MBB, MI, DL, TII.get(Opc)) + .addReg(Xtensa::M0 + MWVal, RegState::Define) + .addReg(Reg2, RegState::Define) + .addReg(Reg1) + .addReg(Xtensa::M0 + MXVal) + .addReg(Xtensa::M0 + MYVal); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::S32I)) + .addReg(Reg2) + .addReg(S.getReg()) + .addImm(0); + + MI.eraseFromParent(); + return MBB; + } + case Xtensa::XSR_ACCLO_P: + case Xtensa::XSR_ACCHI_P: + case Xtensa::XSR_M0_P: + case Xtensa::XSR_M1_P: + case Xtensa::XSR_M2_P: + case Xtensa::XSR_M3_P: { + MachineOperand &T = MI.getOperand(0); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned Reg1 = MRI.createVirtualRegister(RC); + unsigned Reg2 = MRI.createVirtualRegister(RC); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::L32I), Reg1) + .addReg(T.getReg()) + .addImm(0); + + unsigned SReg; + switch (MI.getOpcode()) { + case Xtensa::XSR_ACCLO_P: + SReg = Xtensa::ACCLO; + break; + case Xtensa::XSR_ACCHI_P: + SReg = Xtensa::ACCHI; + break; + case Xtensa::XSR_M0_P: + SReg = Xtensa::M0; + break; + case Xtensa::XSR_M1_P: + SReg = Xtensa::M1; + break; + case Xtensa::XSR_M2_P: + SReg = Xtensa::M2; + break; + case Xtensa::XSR_M3_P: + SReg = Xtensa::M3; + break; + } + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::XSR)) + .addReg(Reg2, RegState::Define) + .addReg(SReg, RegState::Define) + .addReg(Reg1) + .addReg(SReg); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::S32I)) + .addReg(Reg2) + .addReg(T.getReg()) + .addImm(0); + + MI.eraseFromParent(); + return MBB; + } + case Xtensa::WSR_ACCLO_P: + case Xtensa::WSR_ACCHI_P: + case Xtensa::WSR_M0_P: + case Xtensa::WSR_M1_P: + case Xtensa::WSR_M2_P: + case Xtensa::WSR_M3_P: { + MachineOperand &T = MI.getOperand(0); + + unsigned SReg; + switch (MI.getOpcode()) { + case Xtensa::WSR_ACCLO_P: + SReg = Xtensa::ACCLO; + break; + case Xtensa::WSR_ACCHI_P: + SReg = Xtensa::ACCHI; + break; + case Xtensa::WSR_M0_P: + SReg = Xtensa::M0; + break; + case Xtensa::WSR_M1_P: + SReg = Xtensa::M1; + break; + case Xtensa::WSR_M2_P: + SReg = Xtensa::M2; + break; + case Xtensa::WSR_M3_P: + SReg = Xtensa::M3; + break; + } + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::WSR)) + .addReg(SReg, RegState::Define) + .addReg(T.getReg()); + MI.eraseFromParent(); + return MBB; + } + case Xtensa::LDDEC_P: + case Xtensa::LDINC_P: { + MachineOperand &MW = MI.getOperand(0); + MachineOperand &S = MI.getOperand(1); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + unsigned Reg1 = MRI.createVirtualRegister(RC); + unsigned Reg2 = MRI.createVirtualRegister(RC); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::L32I), Reg1) + .addReg(S.getReg()) + .addImm(0); + + unsigned Opc = Xtensa::LDDEC; + + if (MI.getOpcode() == Xtensa::LDINC_P) + Opc = Xtensa::LDINC; + + BuildMI(*MBB, MI, DL, TII.get(Opc)) + .addReg(Xtensa::M0 + MW.getImm(), RegState::Define) + .addReg(Reg2, RegState::Define) + .addReg(Reg1); + + BuildMI(*MBB, MI, DL, TII.get(Xtensa::S32I)) + .addReg(Reg2) + .addReg(S.getReg()) + .addImm(0); + + MI.eraseFromParent(); + return MBB; + } + case Xtensa::SELECT_CC_FP_FP: case Xtensa::SELECT_CC_FP_INT: case Xtensa::SELECT_CC_INT_FP: diff --git a/llvm/test/CodeGen/Xtensa/lit.local.cfg b/llvm/test/CodeGen/Xtensa/lit.local.cfg new file mode 100644 index 0000000000000..9e0be9979305d --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'Xtensa' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/CodeGen/Xtensa/mac16_intrinsics.ll b/llvm/test/CodeGen/Xtensa/mac16_intrinsics.ll new file mode 100644 index 0000000000000..fd58c76872aff --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/mac16_intrinsics.ll @@ -0,0 +1,319 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s + +define void @test_xtensa_umul(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: test_xtensa_umul +; CHECK: umul.aa.ll a2, a3 + call void @llvm.xtensa.umul.aa.ll(i32 %a, i32 %b) +; CHECK: umul.aa.lh a2, a3 + call void @llvm.xtensa.umul.aa.lh(i32 %a, i32 %b) +; CHECK: umul.aa.hl a2, a3 + call void @llvm.xtensa.umul.aa.hl(i32 %a, i32 %b) +; CHECK: umul.aa.hh a2, a3 + call void @llvm.xtensa.umul.aa.hh(i32 %a, i32 %b) + ret void +} + +define void @test_xtensa_mul(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: test_xtensa_mul +; CHECK: mul.aa.ll a2, a3 + call void @llvm.xtensa.mul.aa.ll(i32 %a, i32 %b) +; CHECK: mul.aa.lh a2, a3 + call void @llvm.xtensa.mul.aa.lh(i32 %a, i32 %b) +; CHECK: mul.aa.hl a2, a3 + call void @llvm.xtensa.mul.aa.hl(i32 %a, i32 %b) +; CHECK: mul.aa.hh a2, a3 + call void @llvm.xtensa.mul.aa.hh(i32 %a, i32 %b) +; CHECK: mul.ad.ll a2, m2 + call void @llvm.xtensa.mul.ad.ll(i32 %a, i32 2) +; CHECK: mul.ad.lh a2, m2 + call void @llvm.xtensa.mul.ad.lh(i32 %a, i32 2) +; CHECK: mul.ad.hl a2, m2 + call void @llvm.xtensa.mul.ad.hl(i32 %a, i32 2) +; CHECK: mul.ad.hh a2, m2 + call void @llvm.xtensa.mul.ad.hh(i32 %a, i32 2) +; CHECK: mul.da.ll m1, a3 + call void @llvm.xtensa.mul.da.ll(i32 1, i32 %b) +; CHECK: mul.da.lh m1, a3 + call void @llvm.xtensa.mul.da.lh(i32 1, i32 %b) +; CHECK: mul.da.hl m1, a3 + call void @llvm.xtensa.mul.da.hl(i32 1, i32 %b) +; CHECK: mul.da.hh m1, a3 + call void @llvm.xtensa.mul.da.hh(i32 1, i32 %b) +; CHECK: mul.dd.ll m1, m2 + call void @llvm.xtensa.mul.dd.ll(i32 1, i32 2) +; CHECK: mul.dd.lh m1, m2 + call void @llvm.xtensa.mul.dd.lh(i32 1, i32 2) +; CHECK: mul.dd.hl m1, m2 + call void @llvm.xtensa.mul.dd.hl(i32 1, i32 2) +; CHECK: mul.dd.hh m1, m2 + call void @llvm.xtensa.mul.dd.hh(i32 1, i32 2) + ret void +} + +define void @test_xtensa_mula(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: test_xtensa_mula +; CHECK: mula.aa.ll a2, a3 + call void @llvm.xtensa.mula.aa.ll(i32 %a, i32 %b) +; CHECK: mula.aa.lh a2, a3 + call void @llvm.xtensa.mula.aa.lh(i32 %a, i32 %b) +; CHECK: mula.aa.hl a2, a3 + call void @llvm.xtensa.mula.aa.hl(i32 %a, i32 %b) +; CHECK: mula.aa.hh a2, a3 + call void @llvm.xtensa.mula.aa.hh(i32 %a, i32 %b) +; CHECK: mula.ad.ll a2, m2 + call void @llvm.xtensa.mula.ad.ll(i32 %a, i32 2) +; CHECK: mula.ad.lh a2, m2 + call void @llvm.xtensa.mula.ad.lh(i32 %a, i32 2) +; CHECK: mula.ad.hl a2, m2 + call void @llvm.xtensa.mula.ad.hl(i32 %a, i32 2) +; CHECK: mula.ad.hh a2, m2 + call void @llvm.xtensa.mula.ad.hh(i32 %a, i32 2) +; CHECK: mula.da.ll m1, a3 + call void @llvm.xtensa.mula.da.ll(i32 1, i32 %b) +; CHECK: mula.da.lh m1, a3 + call void @llvm.xtensa.mula.da.lh(i32 1, i32 %b) +; CHECK: mula.da.hl m1, a3 + call void @llvm.xtensa.mula.da.hl(i32 1, i32 %b) +; CHECK: mula.da.hh m1, a3 + call void @llvm.xtensa.mula.da.hh(i32 1, i32 %b) +; CHECK: mula.dd.ll m1, m2 + call void @llvm.xtensa.mula.dd.ll(i32 1, i32 2) +; CHECK: mula.dd.lh m1, m2 + call void @llvm.xtensa.mula.dd.lh(i32 1, i32 2) +; CHECK: mula.dd.hl m1, m2 + call void @llvm.xtensa.mula.dd.hl(i32 1, i32 2) +; CHECK: mula.dd.hh m1, m2 + call void @llvm.xtensa.mula.dd.hh(i32 1, i32 2) + ret void +} + +define void @test_xtensa_muls(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: test_xtensa_muls +; CHECK: muls.aa.ll a2, a3 + call void @llvm.xtensa.muls.aa.ll(i32 %a, i32 %b) +; CHECK: muls.aa.lh a2, a3 + call void @llvm.xtensa.muls.aa.lh(i32 %a, i32 %b) +; CHECK: muls.aa.hl a2, a3 + call void @llvm.xtensa.muls.aa.hl(i32 %a, i32 %b) +; CHECK: muls.aa.hh a2, a3 + call void @llvm.xtensa.muls.aa.hh(i32 %a, i32 %b) +; CHECK: muls.ad.ll a2, m2 + call void @llvm.xtensa.muls.ad.ll(i32 %a, i32 2) +; CHECK: muls.ad.lh a2, m2 + call void @llvm.xtensa.muls.ad.lh(i32 %a, i32 2) +; CHECK: muls.ad.hl a2, m2 + call void @llvm.xtensa.muls.ad.hl(i32 %a, i32 2) +; CHECK: muls.ad.hh a2, m2 + call void @llvm.xtensa.muls.ad.hh(i32 %a, i32 2) +; CHECK: muls.da.ll m1, a3 + call void @llvm.xtensa.muls.da.ll(i32 1, i32 %b) +; CHECK: muls.da.lh m1, a3 + call void @llvm.xtensa.muls.da.lh(i32 1, i32 %b) +; CHECK: muls.da.hl m1, a3 + call void @llvm.xtensa.muls.da.hl(i32 1, i32 %b) +; CHECK: muls.da.hh m1, a3 + call void @llvm.xtensa.muls.da.hh(i32 1, i32 %b) +; CHECK: muls.dd.ll m1, m2 + call void @llvm.xtensa.muls.dd.ll(i32 1, i32 2) +; CHECK: muls.dd.lh m1, m2 + call void @llvm.xtensa.muls.dd.lh(i32 1, i32 2) +; CHECK: muls.dd.hl m1, m2 + call void @llvm.xtensa.muls.dd.hl(i32 1, i32 2) +; CHECK: muls.dd.hh m1, m2 + call void @llvm.xtensa.muls.dd.hh(i32 1, i32 2) + ret void +} + +define void @test_xtensa_mula_ld(i32 %pa.coerce, i32 %b) nounwind { +; CHECK-LABEL: test_xtensa_mula_ld +entry: + %0 = inttoptr i32 %pa.coerce to i8* +; CHECK: mula.da.ll.lddec m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.ll.lddec(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.da.lh.lddec m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.lh.lddec(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.da.hl.lddec m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.hl.lddec(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.da.hh.lddec m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.hh.lddec(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.dd.ll.lddec m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.ll.lddec(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.dd.lh.lddec m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.lh.lddec(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.dd.hl.lddec m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.hl.lddec(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.dd.hh.lddec m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.hh.lddec(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.da.ll.ldinc m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.ll.ldinc(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.da.lh.ldinc m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.lh.ldinc(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.da.hl.ldinc m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.hl.ldinc(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.da.hh.ldinc m1, a{{[0-9]+}}, m0, a3 + call void @llvm.xtensa.mula.da.hh.ldinc(i32 1, i8* %0, i32 0, i32 %b) +; CHECK: mula.dd.ll.ldinc m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.ll.ldinc(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.dd.lh.ldinc m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.lh.ldinc(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.dd.hl.ldinc m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.hl.ldinc(i32 1, i8* %0, i32 0, i32 2) +; CHECK: mula.dd.hh.ldinc m1, a{{[0-9]+}}, m0, m2 + call void @llvm.xtensa.mula.dd.hh.ldinc(i32 1, i8* %0, i32 0, i32 2) + ret void +} + +define void @test_xtensa_ld(i32 %pa.coerce) nounwind { +; CHECK-LABEL: test_xtensa_ld +entry: + %0 = inttoptr i32 %pa.coerce to i8* +; CHECK: lddec m0, a{{[0-9]+}} + call void @llvm.xtensa.lddec(i32 0, i8* %0) +; CHECK: ldinc m0, a{{[0-9]+}} + call void @llvm.xtensa.ldinc(i32 0, i8* %0) + ret void +} + +define void @test_xtensa_wsr(i32 %a) { +; CHECK-LABEL: test_xtensa_wsr +; CHECK: wsr a2, acclo + call void @llvm.xtensa.wsr.acclo(i32 %a) +; CHECK: wsr a2, acchi + call void @llvm.xtensa.wsr.acchi(i32 %a) +; CHECK: wsr a2, m0 + call void @llvm.xtensa.wsr.m0(i32 %a) +; CHECK: wsr a2, m1 + call void @llvm.xtensa.wsr.m1(i32 %a) +; CHECK: wsr a2, m2 + call void @llvm.xtensa.wsr.m2(i32 %a) +; CHECK: wsr a2, m3 + call void @llvm.xtensa.wsr.m3(i32 %a) + ret void +} + +define void @test_xtensa_xsr(i32 %a.coerce) { +; CHECK-LABEL: test_xtensa_xsr +entry: + %0 = inttoptr i32 %a.coerce to i8* +; CHECK: xsr a{{[0-9]+}}, acclo + call void @llvm.xtensa.xsr.acclo(i8* %0) +; CHECK: xsr a{{[0-9]+}}, acchi + call void @llvm.xtensa.xsr.acchi(i8* %0) +; CHECK: xsr a{{[0-9]+}}, m0 + call void @llvm.xtensa.xsr.m0(i8* %0) +; CHECK: xsr a{{[0-9]+}}, m1 + call void @llvm.xtensa.xsr.m1(i8* %0) +; CHECK: xsr a{{[0-9]+}}, m2 + call void @llvm.xtensa.xsr.m2(i8* %0) +; CHECK: xsr a{{[0-9]+}}, m3 + call void @llvm.xtensa.xsr.m3(i8* %0) + ret void +} + +define void @test_xtensa_rsr() { +; CHECK-LABEL: test_xtensa_rsr +entry: +; CHECK: rsr a{{[0-9]+}}, acclo + %0 = call i32 @llvm.xtensa.rsr.acclo() +; CHECK: rsr a{{[0-9]+}}, acchi + %1 = call i32 @llvm.xtensa.rsr.acchi() +; CHECK: rsr a{{[0-9]+}}, m0 + %2 = call i32 @llvm.xtensa.rsr.m0() +; CHECK: rsr a{{[0-9]+}}, m1 + %3 = call i32 @llvm.xtensa.rsr.m1() +; CHECK: rsr a{{[0-9]+}}, m2 + %4 = call i32 @llvm.xtensa.rsr.m2() +; CHECK: rsr a{{[0-9]+}}, m3 + %5 = call i32 @llvm.xtensa.rsr.m3() + ret void +} + +declare void @llvm.xtensa.umul.aa.ll(i32, i32) nounwind +declare void @llvm.xtensa.umul.aa.lh(i32, i32) nounwind +declare void @llvm.xtensa.umul.aa.hl(i32, i32) nounwind +declare void @llvm.xtensa.umul.aa.hh(i32, i32) nounwind +declare void @llvm.xtensa.mul.aa.ll(i32, i32) nounwind +declare void @llvm.xtensa.mul.aa.lh(i32, i32) nounwind +declare void @llvm.xtensa.mul.aa.hl(i32, i32) nounwind +declare void @llvm.xtensa.mul.aa.hh(i32, i32) nounwind +declare void @llvm.xtensa.mul.ad.ll(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mul.ad.lh(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mul.ad.hl(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mul.ad.hh(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mul.da.ll(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mul.da.lh(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mul.da.hl(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mul.da.hh(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mul.dd.ll(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mul.dd.lh(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mul.dd.hl(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mul.dd.hh(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.aa.ll(i32, i32) nounwind +declare void @llvm.xtensa.mula.aa.lh(i32, i32) nounwind +declare void @llvm.xtensa.mula.aa.hl(i32, i32) nounwind +declare void @llvm.xtensa.mula.aa.hh(i32, i32) nounwind +declare void @llvm.xtensa.mula.ad.ll(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mula.ad.lh(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mula.ad.hl(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mula.ad.hh(i32, i32 immarg) nounwind +declare void @llvm.xtensa.mula.da.ll(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.lh(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.hl(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.hh(i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.dd.ll(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.lh(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.hl(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.hh(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.muls.aa.ll(i32, i32) nounwind +declare void @llvm.xtensa.muls.aa.lh(i32, i32) nounwind +declare void @llvm.xtensa.muls.aa.hl(i32, i32) nounwind +declare void @llvm.xtensa.muls.aa.hh(i32, i32) nounwind +declare void @llvm.xtensa.muls.ad.ll(i32, i32 immarg) nounwind +declare void @llvm.xtensa.muls.ad.lh(i32, i32 immarg) nounwind +declare void @llvm.xtensa.muls.ad.hl(i32, i32 immarg) nounwind +declare void @llvm.xtensa.muls.ad.hh(i32, i32 immarg) nounwind +declare void @llvm.xtensa.muls.da.ll(i32 immarg, i32) nounwind +declare void @llvm.xtensa.muls.da.lh(i32 immarg, i32) nounwind +declare void @llvm.xtensa.muls.da.hl(i32 immarg, i32) nounwind +declare void @llvm.xtensa.muls.da.hh(i32 immarg, i32) nounwind +declare void @llvm.xtensa.muls.dd.ll(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.muls.dd.lh(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.muls.dd.hl(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.muls.dd.hh(i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.da.ll.lddec(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.lh.lddec(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.hl.lddec(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.hh.lddec(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.dd.ll.lddec(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.lh.lddec(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.hl.lddec(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.hh.lddec(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.da.ll.ldinc(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.lh.ldinc(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.hl.ldinc(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.da.hh.ldinc(i32 immarg, i8*, i32 immarg, i32) nounwind +declare void @llvm.xtensa.mula.dd.ll.ldinc(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.lh.ldinc(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.hl.ldinc(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.mula.dd.hh.ldinc(i32 immarg, i8*, i32 immarg, i32 immarg) nounwind +declare void @llvm.xtensa.lddec(i32 immarg, i8*) nounwind +declare void @llvm.xtensa.ldinc(i32 immarg, i8*) nounwind +declare i32 @llvm.xtensa.rsr.acclo() nounwind +declare i32 @llvm.xtensa.rsr.acchi() nounwind +declare i32 @llvm.xtensa.rsr.m0() nounwind +declare i32 @llvm.xtensa.rsr.m1() nounwind +declare i32 @llvm.xtensa.rsr.m2() nounwind +declare i32 @llvm.xtensa.rsr.m3() nounwind +declare void @llvm.xtensa.xsr.acclo(i8*) nounwind +declare void @llvm.xtensa.xsr.acchi(i8*) nounwind +declare void @llvm.xtensa.xsr.m0(i8*) nounwind +declare void @llvm.xtensa.xsr.m1(i8*) nounwind +declare void @llvm.xtensa.xsr.m2(i8*) nounwind +declare void @llvm.xtensa.xsr.m3(i8*) nounwind +declare void @llvm.xtensa.wsr.acclo(i32) nounwind +declare void @llvm.xtensa.wsr.acchi(i32) nounwind +declare void @llvm.xtensa.wsr.m0(i32) nounwind +declare void @llvm.xtensa.wsr.m1(i32) nounwind +declare void @llvm.xtensa.wsr.m2(i32) nounwind +declare void @llvm.xtensa.wsr.m3(i32) nounwind + diff --git a/llvm/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn b/llvm/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn index ab051f43e6216..eeb55c23bf9a6 100644 --- a/llvm/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn @@ -177,6 +177,16 @@ tablegen("IntrinsicsXCore") { td_file = "Intrinsics.td" } +tablegen("IntrinsicsXtensa") { + visibility = [ ":public_tablegen" ] + output_name = "IntrinsicsXtensa.h" + args = [ + "-gen-intrinsic-enums", + "-intrinsic-prefix=xtensa", + ] + td_file = "Intrinsics.td" +} + # Groups all tablegen() calls that create .inc files that are included in # IR's public headers. //llvm/lib/IR has this as a public_dep, so targets # depending on //llvm/lib/IR don't need to depend on this. This exists @@ -207,5 +217,6 @@ group("public_tablegen") { ":IntrinsicsWebAssembly", ":IntrinsicsX86", ":IntrinsicsXCore", + ":IntrinsicsXtensa", ] } From dd218f64e2f7d1c76025bc5a7d40912ed7c87f6f Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:19 +0300 Subject: [PATCH 061/150] [Xtensa] Implement lowering llvm intrinsics fshr/fshl. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 27 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 1 + llvm/test/CodeGen/Xtensa/funnel-shift.ll | 24 +++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 llvm/test/CodeGen/Xtensa/funnel-shift.ll diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 3904e128f44e7..5eb67c13d4c82 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -188,6 +188,10 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); + // Funnel shifts + setOperationAction(ISD::FSHR, MVT::i32, Custom); + setOperationAction(ISD::FSHL, MVT::i32, Custom); + // Bit Manipulation setOperationAction(ISD::BSWAP, MVT::i32, Expand); setOperationAction(ISD::BSWAP, MVT::i64, Expand); @@ -1681,6 +1685,26 @@ SDValue XtensaTargetLowering::LowerShiftRightParts(SDValue Op, return DAG.getMergeValues(Ops, DL); } +SDValue XtensaTargetLowering::LowerFunnelShift(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Op0 = Op.getOperand(0); + SDValue Op1 = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + MVT VT = Op.getSimpleValueType(); + + bool IsFSHR = Op.getOpcode() == ISD::FSHR; + assert((VT == MVT::i32) && "Unexpected funnel shift type!"); + + if (!IsFSHR) { + Shamt = DAG.getNode(ISD::SUB, DL, MVT::i32, + DAG.getConstant(32, DL, MVT::i32), Shamt); + } + SDValue SetSAR = DAG.getNode(XtensaISD::SSR, DL, + MVT::Glue, Shamt); + return DAG.getNode(XtensaISD::SRC, DL, VT, Op0, Op1, SetSAR); +} + SDValue XtensaTargetLowering::LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -1735,6 +1759,9 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, return LowerShiftRightParts(Op, DAG, true); case ISD::SRL_PARTS: return LowerShiftRightParts(Op, DAG, false); + case ISD::FSHL: + case ISD::FSHR: + return LowerFunnelShift(Op, DAG); default: llvm_unreachable("Unexpected node to lower"); } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index c1db77548308a..d2b61cd4ed732 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -193,6 +193,7 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; + SDValue LowerFunnelShift(SDValue Op, SelectionDAG &DAG) const; SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/test/CodeGen/Xtensa/funnel-shift.ll b/llvm/test/CodeGen/Xtensa/funnel-shift.ll new file mode 100644 index 0000000000000..09bf081be3737 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/funnel-shift.ll @@ -0,0 +1,24 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s + +define dso_local i32 @test_fshr(i32 %value1, i32 %value2, i32 %shift) nounwind { +; CHECK-LABEL: @test_fshr +; CHECK: ssr a4 +; CHECK: src a2, a2, a3 +entry: + %0 = tail call i32 @llvm.fshr.i32(i32 %value1, i32 %value2, i32 %shift) + ret i32 %0 +} + +define dso_local i32 @test_fshl(i32 %value1, i32 %value2, i32 %shift) nounwind { +; CHECK-LABEL: @test_fshl +; CHECK: movi.n a8, 32 +; CHECK: sub a8, a8, a4 +; CHECK: ssr a8 +; CHECK: src a2, a2, a3 +entry: + %0 = tail call i32 @llvm.fshl.i32(i32 %value1, i32 %value2, i32 %shift) + ret i32 %0 +} + +declare i32 @llvm.fshr.i32(i32, i32, i32) nounwind +declare i32 @llvm.fshl.i32(i32, i32, i32) nounwind From 85185652a6d021c2768908cc5662bc8f0e6dfdae Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:19 +0300 Subject: [PATCH 062/150] [Xtensa] Correct visibility of the Xtensa backend initialize functions. Make backend initialize functions public and visible outside library. --- llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp | 2 +- llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp | 2 +- llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp | 2 +- llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 94933c4fb6202..dfdb351e7c34b 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -1098,6 +1098,6 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { } // Force static initialization. -extern "C" void LLVMInitializeXtensaAsmParser() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() { RegisterMCAsmParser X(TheXtensaTarget); } diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index 3565d3bf1f927..a1b410b6b611c 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -78,7 +78,7 @@ createXtensaObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { return new XtensaTargetELFStreamer(S); } -extern "C" void LLVMInitializeXtensaTargetMC() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTargetMC() { // Register the MCAsmInfo. TargetRegistry::RegisterMCAsmInfo(TheXtensaTarget, createXtensaMCAsmInfo); diff --git a/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp b/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp index 349dcafdd5d15..7fe1bc793119b 100644 --- a/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp +++ b/llvm/lib/Target/Xtensa/TargetInfo/XtensaTargetInfo.cpp @@ -14,7 +14,7 @@ using namespace llvm; namespace llvm { Target TheXtensaTarget; } -extern "C" void LLVMInitializeXtensaTargetInfo() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTargetInfo() { RegisterTarget X(TheXtensaTarget, "xtensa", "Xtensa 32", "XTENSA"); } diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index 4f109f2a086fa..f93fed88d9694 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -23,7 +23,7 @@ using namespace llvm; -extern "C" void LLVMInitializeXtensaTarget() { +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTarget() { // Register the target. RegisterTargetMachine A(TheXtensaTarget); } From e18ae023d3c3f0fda3edccc1223033c5a50fab28 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:20 +0300 Subject: [PATCH 063/150] [Xtensa][Not for upstream] Add functions needed to use as rust submodule. --- llvm/include/llvm/MC/MCSubtargetInfo.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h index e1f0a86141e36..1e529bf4fb31e 100644 --- a/llvm/include/llvm/MC/MCSubtargetInfo.h +++ b/llvm/include/llvm/MC/MCSubtargetInfo.h @@ -230,6 +230,14 @@ class MCSubtargetInfo { return Found != ProcDesc.end() && StringRef(Found->Key) == CPU; } + ArrayRef getCPUTable() const { + return ProcDesc; + } + + ArrayRef getFeatureTable() const { + return ProcFeatures; + } + virtual unsigned getHwMode() const { return 0; } /// Return the cache size in bytes for the given level of cache. From 7b04fb39417748a433d773cdfeb5e6ea1a1b407f Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:20 +0300 Subject: [PATCH 064/150] [Xtensa] Correct Call ABI for function return arguments. --- clang/lib/CodeGen/TargetInfo.cpp | 12 +++++++++--- clang/test/CodeGen/xtensa-abi.c | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/xtensa-abi.c diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 7e70630489083..b7d5fc8ea5cfa 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -11643,10 +11643,16 @@ ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, ABIArgInfo XtensaABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); + int ArgGPRsLeft = MaxNumRetGPRs; - // The rules for return and argument types are the same, so defer to - // classifyArgumentType. - return classifyArgumentType(RetTy, ArgGPRsLeft); + auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; + + // The rules for return and argument with type size more then 4 bytes + // are the same, so defer to classifyArgumentType. + if (RetSize > 1) + return classifyArgumentType(RetTy, ArgGPRsLeft); + + return DefaultABIInfo::classifyReturnType(RetTy); } Address XtensaABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, diff --git a/clang/test/CodeGen/xtensa-abi.c b/clang/test/CodeGen/xtensa-abi.c new file mode 100644 index 0000000000000..4ce59e8466c8b --- /dev/null +++ b/clang/test/CodeGen/xtensa-abi.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -no-opaque-pointers -triple xtensa -O0 -emit-llvm %s -o - | FileCheck %s + +#define __malloc_like __attribute__((__malloc__)) +char *bufalloc () __malloc_like ;//__result_use_check; +extern void* malloc (unsigned size); + +char *bufalloc () +{ + char* buf = malloc(1024); + + return buf; +} + +// CHECK: define dso_local noalias i8* @bufalloc() #0 { From 229b3524634669f47127ba820b3f20d316967892 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:20 +0300 Subject: [PATCH 065/150] [Xtensa] Implement rest part of FP instructions. Add FP instructions test, format FP instruction descriptions. --- .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 6 +- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 10 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 4 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 263 ++++++++++++------ llvm/test/MC/Xtensa/xtensa-valid-float.s | 178 ++++++++++++ 5 files changed, 366 insertions(+), 95 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-float.s diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index c204e0866e449..8d30edafb54aa 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -280,8 +280,10 @@ XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, case Xtensa::L32I: case Xtensa::S32I_N: case Xtensa::L32I_N: - case Xtensa::S32F: - case Xtensa::L32F: + case Xtensa::SSI: + case Xtensa::SSIP: + case Xtensa::LSI: + case Xtensa::LSIP: case Xtensa::S32C1I: if (Res & 0x3) { report_fatal_error("Unexpected operand value!"); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 5eb67c13d4c82..69eee03871eaf 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -3185,13 +3185,19 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( case Xtensa::S16I: case Xtensa::S32I: case Xtensa::S32I_N: - case Xtensa::S32F: + case Xtensa::SSI: + case Xtensa::SSIP: + case Xtensa::SSX: + case Xtensa::SSXP: case Xtensa::L8UI: case Xtensa::L16SI: case Xtensa::L16UI: case Xtensa::L32I: case Xtensa::L32I_N: - case Xtensa::L32F: { + case Xtensa::LSI: + case Xtensa::LSIP: + case Xtensa::LSX: + case Xtensa::LSXP: { const MachineMemOperand &MMO = **MI.memoperands_begin(); if (MMO.isVolatile()) { BuildMI(*MBB, MI, DL, TII.get(Xtensa::MEMW)); diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index a4d5882983a7f..bd962e3cfa854 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -144,8 +144,8 @@ void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, LoadOpcode = Xtensa::L32I; StoreOpcode = Xtensa::S32I; } else if (RC == &Xtensa::FPRRegClass) { - LoadOpcode = Xtensa::L32F; - StoreOpcode = Xtensa::S32F; + LoadOpcode = Xtensa::LSI; + StoreOpcode = Xtensa::SSI; } else llvm_unreachable("Unsupported regclass to load or store"); } diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index bfc3f773e9819..789fc7317620c 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -958,85 +958,63 @@ def ADD_S : FPArith_RRR<0x00, 0x0A, "add.s", fadd, 1>; def SUB_S : FPArith_RRR<0x01, 0x0A, "sub.s", fsub>; def MUL_S : FPArith_RRR<0x02, 0x0A, "mul.s", fmul, 1>; -def ABS_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), - "abs.s\t$r, $s", - [(set FPR:$r, (fabs FPR:$s))]> { - let t = 0x01; -} - -def NEG_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), - "neg.s\t$r, $s", - [(set FPR:$r, (fneg FPR:$s))]> { - let t = 0x06; -} +// FP load instructions +let mayLoad = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in { + def LSI : RRI8_Inst<0x03, (outs FPR:$t), (ins mem32:$addr), + "lsi\t$t, $addr", []> { + bits<12> addr; -def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s), - "trunc.s\t$r, $s, 0", - [(set AR:$r, (fp_to_sint FPR:$s))]> { - let t = 0x00; -} + let r = 0x00; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } -def UTRUNC_S : RRR_Inst<0x00, 0x0A, 0x0e, (outs AR:$r), (ins FPR:$s), - "utrunc.s\t$r, $s, 0", - [(set AR:$r, (fp_to_uint FPR:$s))]> { - let t = 0x00; -} + def LSIP : RRI8_Inst<0x03, (outs FPR:$t), (ins mem32:$addr), + "lsip\t$t, $addr", []> { + bits<12> addr; -def FLOAT_S : RRR_Inst<0x00, 0x0A, 0x0c, (outs FPR:$r), (ins AR:$s), - "float.s\t$r, $s, 0", - [(set FPR:$r, (sint_to_fp AR:$s))]> { - let t = 0x00; -} + let r = 0x08; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } -def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s), - "ufloat.s\t$r, $s, 0", - [(set FPR:$r, (uint_to_fp AR:$s))]> { - let t = 0x00; -} + def LSX : RRR_Inst<0x00, 0x08, 0x00, (outs), (ins FPR:$r, AR:$s, AR:$t), + "lsx\t$r, $s, $t", []>; -def RFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs AR:$r), (ins FPR:$s), - "rfr\t$r, $s", - [(set AR:$r, (bitconvert FPR:$s))]> { - let t = 0x04; + def LSXP : RRR_Inst<0x00, 0x08, 0x01, (outs), (ins FPR:$r, AR:$s, AR:$t), + "lsxp\t$r, $s, $t", []>; } -def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s), - "wfr\t$r, $s", - [(set FPR:$r, (bitconvert AR:$s))]> { - let t = 0x05; -} +def : Pat<(f32 (load addr_ish4:$addr)), (f32 (LSI mem32:$addr))>; -// FP load instructions -let mayLoad = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in { - class LoadF_RRI8 oper, string instrAsm, SDPatternOperator opNode, - ComplexPattern addrOp,Operand memOp>: RRI8_Inst<0x03, (outs FPR:$t), (ins memOp:$addr), - instrAsm#"\t$t, $addr", - [(set FPR:$t, (opNode addrOp:$addr))]> { +// FP store instructions +let mayStore = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in { + def SSI : RRI8_Inst<0x03, (outs), (ins FPR:$t, mem32:$addr), + "ssi\t$t, $addr", []> { bits<12> addr; - let r = oper; + let r = 0x04; let imm8{7-0} = addr{11-4}; let s{3-0} = addr{3-0}; } -} - -def L32F : LoadF_RRI8<0x00, "lsi", load, addr_ish4, mem32>, Requires<[]>; -// FP store instructions -let mayStore = 1, usesCustomInserter = 1, Predicates = [HasSingleFloat] in { - class StoreF_RRI8 oper, string instrAsm, SDPatternOperator opNode, - ComplexPattern addrOp, Operand memOp>: RRI8_Inst<0x03, (outs), (ins FPR:$t, memOp:$addr), - instrAsm#"\t$t, $addr", - [(opNode FPR:$t, addrOp:$addr)]> { + def SSIP : RRI8_Inst<0x03, (outs), (ins FPR:$t, mem32:$addr), + "ssip\t$t, $addr", []> { bits<12> addr; - let r = oper; + let r = 0x0C; let imm8{7-0} = addr{11-4}; let s{3-0} = addr{3-0}; } + + def SSX: RRR_Inst<0x00, 0x08, 0x04, (outs), (ins FPR:$r, AR:$s, AR:$t), + "ssx\t$r, $s, $t", []>; + + def SSXP: RRR_Inst<0x00, 0x08, 0x05, (outs), (ins FPR:$r, AR:$s, AR:$t), + "ssxp\t$r, $s, $t", []>; } -def S32F : StoreF_RRI8<0x04, "ssi", store, addr_ish4, mem32>; +def : Pat<(store FPR:$t, addr_ish4:$addr), (SSI FPR:$t, mem32:$addr)>; // FP compare instructions let isCompare = 1, Predicates = [HasSingleFloat] in { @@ -1060,31 +1038,27 @@ def ULT_S : FCompare<0x05, 0x0b, "ult.s", Xtensa_cmpult, 0>; def ULE_S : FCompare<0x07, 0x0b, "ule.s", Xtensa_cmpule, 0>; def UN_S : FCompare<0x01, 0x0b, "un.s", Xtensa_cmpuo, 1>; -//FP complex operations -def MADD_S : RRR_Inst<0x00, 0x0A, 0x04, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t), - "madd.s\t$r, $s, $t", - [(set FPR:$r, (Xtensa_madd FPR:$a, FPR:$s, FPR:$t))]>, - Requires<[HasSingleFloat]> { - let isCommutable = 0; - let isReMaterializable = 0; - let Constraints = "$r = $a"; +def ABS_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "abs.s\t$r, $s", + [(set FPR:$r, (fabs FPR:$s))]> { + let t = 0x01; } -def MSUB_S : RRR_Inst<0x00, 0x0A, 0x05, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t), - "msub.s\t$r, $s, $t", - [(set FPR:$r, (Xtensa_msub FPR:$a, FPR:$s, FPR:$t))]>, - Requires<[HasSingleFloat]> { - let isCommutable = 0; - let isReMaterializable = 0; - let Constraints = "$r = $a"; +def ADDEXP_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "addexp.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0E; } -//FP move operations -def MOV_S : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins FPR:$s), - "mov.s\t$r, $s", - [(set FPR:$r, (Xtensa_movs FPR:$s))]>, Requires<[HasSingleFloat]> -{ - let t = 0x00; +def ADDEXPM_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "addexpm.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0F; +} + +def CEIL_S : RRR_Inst<0x00, 0x0A, 0x0B, (outs AR:$r), (ins FPR:$s, uimm4:$imm), + "ceil.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { + bits<4> imm; + + let t = imm; } def CONST_S : RRR_Inst<0x00, 0x0a, 0x0f, (outs FPR:$r), (ins uimm4:$imm), @@ -1100,11 +1074,40 @@ def DIV0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), let t = 0x7; } +def DIVN_S : RRR_Inst<0x00, 0x0A, 0x07, (outs FPR:$r), (ins FPR:$s, FPR:$t), + "divn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; + +def FLOAT_S : RRR_Inst<0x00, 0x0A, 0x0c, (outs FPR:$r), (ins AR:$s, uimm4:$imm), + "float.s\t$r, $s, $imm", []> { + bits<4> imm; + + let t = imm; +} + +def : Pat<(f32 (sint_to_fp AR:$s)), (FLOAT_S AR:$s, 0)>; + +def FLOOR_S : RRR_Inst<0x00, 0x0A, 0x0A, (outs AR:$r), (ins FPR:$s, uimm4:$imm), + "floor.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { + bits<4> imm; + + let t = imm; +} + def MADDN_S : RRR_Inst<0x00, 0x0A, 0x06, (outs FPR:$r), (ins FPR:$s, FPR:$t), "maddn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]> { let isCommutable = 0; } +// FP multipy-add +def MADD_S : RRR_Inst<0x00, 0x0A, 0x04, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t), + "madd.s\t$r, $s, $t", + [(set FPR:$r, (Xtensa_madd FPR:$a, FPR:$s, FPR:$t))]>, + Requires<[HasSingleFloat]> { + let isCommutable = 0; + let isReMaterializable = 0; + let Constraints = "$r = $a"; +} + def MKDADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "mkdadj.s\t$r, $s", []>, Requires<[HasSingleFloat]> { let t = 0x0D; @@ -1115,29 +1118,112 @@ def MKSADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), let t = 0x0C; } -def ADDEXP_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), - "addexp.s\t$r, $s", []>, Requires<[HasSingleFloat]> { - let t = 0x0E; +// FP move instructions +def MOV_S : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins FPR:$s), + "mov.s\t$r, $s", + [(set FPR:$r, (Xtensa_movs FPR:$s))]>, Requires<[HasSingleFloat]> { + let t = 0x00; } -def ADDEXPM_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), - "addexpm.s\t$r, $s", []>, Requires<[HasSingleFloat]> { - let t = 0x0F; -} +def MOVEQZ_S : RRR_Inst<0x00, 0x0B, 0x08, (outs FPR:$r), (ins FPR:$s, AR:$t), + "moveqz.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; -def DIVN_S : RRR_Inst<0x00, 0x0A, 0x07, (outs FPR:$r), (ins FPR:$s, FPR:$t), - "divn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; +def MOVF_S : RRR_Inst<0x00, 0x0B, 0x0C, (outs FPR:$r), (ins FPR:$s, BR:$t), + "movf.s\t$r, $s, $t", []>, Requires<[HasBoolean, HasSingleFloat]>; + +def MOVGEZ_S : RRR_Inst<0x00, 0x0B, 0x0B, (outs FPR:$r), (ins FPR:$s, AR:$t), + "movgez.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; + +def MOVLTZ_S : RRR_Inst<0x00, 0x0B, 0x0A, (outs FPR:$r), (ins FPR:$s, AR:$t), + "movltz.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; + +def MOVNEZ_S : RRR_Inst<0x00, 0x0B, 0x09, (outs FPR:$r), (ins FPR:$s, AR:$t), + "movnez.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; + +def MOVT_S : RRR_Inst<0x00, 0x0B, 0x0D, (outs FPR:$r), (ins FPR:$s, BR:$t), + "movt.s\t$r, $s, $t", []>, Requires<[HasBoolean, HasSingleFloat]>; + +// FP multipy-sub +def MSUB_S : RRR_Inst<0x00, 0x0A, 0x05, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR:$t), + "msub.s\t$r, $s, $t", + [(set FPR:$r, (Xtensa_msub FPR:$a, FPR:$s, FPR:$t))]>, Requires<[HasSingleFloat]> { + let isCommutable = 0; + let isReMaterializable = 0; + let Constraints = "$r = $a"; +} def NEXP01_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "nexp01.s\t$r, $s", []>, Requires<[HasSingleFloat]> { let t = 0x0B; } +def NEG_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "neg.s\t$r, $s", + [(set FPR:$r, (fneg FPR:$s))]> { + let t = 0x06; +} + +def RECIP0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "recip0.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x08; +} + +def RFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs AR:$r), (ins FPR:$s), + "rfr\t$r, $s", + [(set AR:$r, (bitconvert FPR:$s))]> { + let t = 0x04; +} + +def ROUND_S : RRR_Inst<0x00, 0x0A, 0x08, (outs AR:$r), (ins FPR:$s, uimm4:$imm), + "round.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { + bits<4> imm; + + let t = imm; +} + +def RSQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), + "rsqrt0.s\t$r, $s", []>, Requires<[HasSingleFloat]> { + let t = 0x0A; +} + def SQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "sqrt0.s\t$r, $s", []>, Requires<[HasSingleFloat]> { let t = 0x09; } +def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s, uimm4:$imm), + "trunc.s\t$r, $s, $imm", []> { + bits<4> imm; + + let t = imm; +} + +def : Pat<(i32 (fp_to_sint FPR:$s)), (TRUNC_S FPR:$s, 0)>; + +def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s, uimm4:$imm), + "ufloat.s\t$r, $s, $imm", []> { + bits<4> imm; + + let t = imm; +} + +def : Pat<(f32 (uint_to_fp AR:$s)), (UFLOAT_S AR:$s, 0)>; + +def UTRUNC_S : RRR_Inst<0x00, 0x0A, 0x0e, (outs AR:$r), (ins FPR:$s, uimm4:$imm), + "utrunc.s\t$r, $s, $imm", []> { + bits<4> imm; + + let t = imm; +} + +def : Pat<(i32 (fp_to_uint FPR:$s)), (UTRUNC_S FPR:$s, 0)>; + +def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s), + "wfr\t$r, $s", + [(set FPR:$r, (bitconvert AR:$s))]> { + let t = 0x05; +} + // FP select operations let usesCustomInserter = 1 in { def SELECT_CC_FP_INT : Pseudo<(outs AR:$dst), (ins FPR:$lhs, FPR:$rhs, AR:$t, AR:$f, i32imm:$cond), @@ -1150,7 +1236,6 @@ let usesCustomInserter = 1 in { "!select_cc_fp_fp $dst, $lhs, $rhs, $t, $f, $cond", [(set FPR:$dst, (Xtensa_select_cc_fp FPR:$lhs, FPR:$rhs, FPR:$t, FPR:$f, imm:$cond))]>; } - //===----------------------------------------------------------------------===// // Loop Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/test/MC/Xtensa/xtensa-valid-float.s b/llvm/test/MC/Xtensa/xtensa-valid-float.s new file mode 100644 index 0000000000000..40405e93c5843 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-float.s @@ -0,0 +1,178 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+fp -mattr=+bool -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: abs.s f2, f3 +# CHECK: encoding: [0x10,0x23,0xfa] + abs.s f2, f3 +# CHECK-INST: add.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x0a] + add.s f2, f3, f4 +# CHECK-INST: addexp.s f2, f3 +# CHECK: encoding: [0xe0,0x23,0xfa] + addexp.s f2, f3 +# CHECK-INST: addexpm.s f2, f3 +# CHECK: encoding: [0xf0,0x23,0xfa] + addexpm.s f2, f3 + +# CHECK-INST: ceil.s a2, f3, 5 +# CHECK: encoding: [0x50,0x23,0xba] + ceil.s a2, f3, 5 +# CHECK-INST: const.s f3, 5 +# CHECK: encoding: [0x30,0x35,0xfa] + const.s f3, 5 + +# CHECK-INST: div0.s f2, f3 +# CHECK: encoding: [0x70,0x23,0xfa] + div0.s f2, f3 +# CHECK-INST: divn.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x7a] + divn.s f2, f3, f4 + +# CHECK-INST: float.s f2, a3, 5 +# CHECK: encoding: [0x50,0x23,0xca] + float.s f2, a3, 5 +# CHECK-INST: floor.s a2, f3, 5 +# CHECK: encoding: [0x50,0x23,0xaa] + floor.s a2, f3, 5 + +# CHECK-INST: lsi f2, a3, 8 +# CHECK: encoding: [0x23,0x03,0x02] + lsi f2, a3, 8 +# CHECK-INST: lsip f2, a3, 8 +# CHECK: encoding: [0x23,0x83,0x02] + lsip f2, a3, 8 +# CHECK-INST: lsx f2, a3, a4 +# CHECK: encoding: [0x40,0x23,0x08] + lsx f2, a3, a4 +# CHECK-INST: lsxp f2, a3, a4 +# CHECK: encoding: [0x40,0x23,0x18] + lsxp f2, a3, a4 + +# CHECK-INST: madd.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x4a] + madd.s f2, f3, f4 +# CHECK-INST: maddn.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x6a] + maddn.s f2, f3, f4 +# CHECK-INST: mkdadj.s f2, f3 +# CHECK: encoding: [0xd0,0x23,0xfa] + mkdadj.s f2, f3 +# CHECK-INST: mksadj.s f2, f3 +# CHECK: encoding: [0xc0,0x23,0xfa] + mksadj.s f2, f3 + +# CHECK-INST: mov.s f2, f3 +# CHECK: encoding: [0x00,0x23,0xfa] + mov.s f2, f3 + +# CHECK-INST: moveqz.s f2, f3, a4 +# CHECK: encoding: [0x40,0x23,0x8b] + moveqz.s f2, f3, a4 +# CHECK-INST: movf.s f2, f3, b0 +# CHECK: encoding: [0x00,0x23,0xcb] + movf.s f2, f3, b0 +# CHECK-INST: movgez.s f2, f3, a4 +# CHECK: encoding: [0x40,0x23,0xbb] + movgez.s f2, f3, a4 +# CHECK-INST: movltz.s f2, f3, a4 +# CHECK: encoding: [0x40,0x23,0xab] + movltz.s f2, f3, a4 +# CHECK-INST: movnez.s f2, f3, a4 +# CHECK: encoding: [0x40,0x23,0x9b] + movnez.s f2, f3, a4 +# CHECK-INST: movt.s f2, f3, b0 +# CHECK: encoding: [0x00,0x23,0xdb] + movt.s f2, f3, b0 + +# CHECK-INST: msub.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x5a] + msub.s f2, f3, f4 +# CHECK-INST: mul.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x2a] + mul.s f2, f3, f4 +# CHECK-INST: neg.s f2, f3 +# CHECK: encoding: [0x60,0x23,0xfa] + neg.s f2, f3 + +# CHECK-INST: nexp01.s f2, f3 +# CHECK: encoding: [0xb0,0x23,0xfa] + nexp01.s f2, f3 + +# CHECK-INST: oeq.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x2b] + oeq.s b0, f2, f3 +# CHECK-INST: ole.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x6b] + ole.s b0, f2, f3 +# CHECK-INST: olt.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x4b] + olt.s b0, f2, f3 + +# CHECK-INST: recip0.s f2, f3 +# CHECK: encoding: [0x80,0x23,0xfa] + recip0.s f2, f3 + +# CHECK-INST: rfr a2, f3 +# CHECK: encoding: [0x40,0x23,0xfa] + rfr a2, f3 + +# CHECK-INST: round.s a2, f3, 5 +# CHECK: encoding: [0x50,0x23,0x8a] + round.s a2, f3, 5 +# CHECK-INST: rsqrt0.s f2, f3 +# CHECK: encoding: [0xa0,0x23,0xfa] + rsqrt0.s f2, f3 +# CHECK-INST: sqrt0.s f2, f3 +# CHECK: encoding: [0x90,0x23,0xfa] + sqrt0.s f2, f3 + +# CHECK-INST: ssi f2, a3, 8 +# CHECK: encoding: [0x23,0x43,0x02] + ssi f2, a3, 8 +# CHECK-INST: ssip f2, a3, 8 +# CHECK: encoding: [0x23,0xc3,0x02] + ssip f2, a3, 8 +# CHECK-INST: ssx f2, a3, a4 +# CHECK: encoding: [0x40,0x23,0x48] + ssx f2, a3, a4 +# CHECK-INST: ssxp f2, a3, a4 +# CHECK: encoding: [0x40,0x23,0x58] + ssxp f2, a3, a4 + +# CHECK-INST: sub.s f2, f3, f4 +# CHECK: encoding: [0x40,0x23,0x1a] + sub.s f2, f3, f4 + +# CHECK-INST: trunc.s a2, f3, 5 +# CHECK: encoding: [0x50,0x23,0x9a] + trunc.s a2, f3, 5 + +# CHECK-INST: ueq.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x3b] + ueq.s b0, f2, f3 + +# CHECK-INST: ufloat.s f2, a3, 5 +# CHECK: encoding: [0x50,0x23,0xda] + ufloat.s f2, a3, 5 + +# CHECK-INST: ule.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x7b] + ule.s b0, f2, f3 +# CHECK-INST: ult.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x5b] + ult.s b0, f2, f3 +# CHECK-INST: un.s b0, f2, f3 +# CHECK: encoding: [0x30,0x02,0x1b] + un.s b0, f2, f3 + +# CHECK-INST: utrunc.s a2, f3, 5 +# CHECK: encoding: [0x50,0x23,0xea] + utrunc.s a2, f3, 5 + +# CHECK-INST: wfr f2, a3 +# CHECK: encoding: [0x50,0x23,0xfa] + wfr f2, a3 + From ffddcb8581dc3c3049a4209250c1abb2a156576d Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:21 +0300 Subject: [PATCH 066/150] [Xtensa] Correct lowering BR_CC with FP operands. Remove register class for boolean operands, because it is only suitable for FP compare operations and may lead to problems in other cases. Disable load width reduction, because for IRAM memory it may cause exceptions. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 106 +++++------------- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 12 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 12 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 9 +- llvm/test/CodeGen/Xtensa/xtensa-fcmp.ll | 18 +++ llvm/test/CodeGen/Xtensa/xtensa-icmp.ll | 17 +++ 6 files changed, 90 insertions(+), 84 deletions(-) create mode 100644 llvm/test/CodeGen/Xtensa/xtensa-fcmp.ll create mode 100644 llvm/test/CodeGen/Xtensa/xtensa-icmp.ll diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 69eee03871eaf..d6bf1ec3b1804 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -335,10 +335,6 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); - - if (Subtarget.hasBoolean()) { - addRegisterClass(MVT::i1, &Xtensa::BRRegClass); - } } bool XtensaTargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, @@ -1099,73 +1095,6 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, DL, MVT::Other, RetOps); } -static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, ISD::CondCode CC, SDLoc dl, - SelectionDAG &DAG, int &br_code) { - // Minor optimization: if LHS is a constant, swap operands, then the - // constant can be folded into comparison. - if (LHS.getOpcode() == ISD::Constant) - std::swap(LHS, RHS); - int cmp_code = 0; - - switch (CC) { - default: - llvm_unreachable("Invalid condition!"); - break; - case ISD::SETUNE: - br_code = XtensaISD::BR_CC_F; - cmp_code = XtensaISD::CMPOEQ; - break; - case ISD::SETUO: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPUO; - break; - case ISD::SETO: - br_code = XtensaISD::BR_CC_F; - cmp_code = XtensaISD::CMPUO; - break; - case ISD::SETUEQ: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPUEQ; - break; - case ISD::SETULE: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPULE; - break; - case ISD::SETULT: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPULT; - break; - case ISD::SETEQ: - case ISD::SETOEQ: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPOEQ; - break; - case ISD::SETNE: - br_code = XtensaISD::BR_CC_F; - cmp_code = XtensaISD::CMPOEQ; - break; - case ISD::SETLE: - case ISD::SETOLE: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPOLE; - break; - case ISD::SETLT: - case ISD::SETOLT: - br_code = XtensaISD::BR_CC_T; - cmp_code = XtensaISD::CMPOLT; - break; - case ISD::SETGE: - br_code = XtensaISD::BR_CC_F; - cmp_code = XtensaISD::CMPOLT; - break; - case ISD::SETGT: - br_code = XtensaISD::BR_CC_F; - cmp_code = XtensaISD::CMPOLE; - break; - } - return DAG.getNode(cmp_code, dl, MVT::i1, LHS, RHS); -} - SDValue XtensaTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); ISD::CondCode CC = cast(Op.getOperand(1))->get(); @@ -1175,9 +1104,9 @@ SDValue XtensaTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); if (LHS.getValueType() == MVT::f32) { - int br_code; - SDValue Flag = EmitCMP(LHS, RHS, CC, DL, DAG, br_code); - return DAG.getNode(br_code, DL, Op.getValueType(), Chain, Flag, Dest); + SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); + return DAG.getNode(XtensaISD::BR_CC_FP, DL, Op.getValueType(), Chain, + TargetCC, LHS, RHS, Dest); } else { llvm_unreachable("invalid BR_CC to lower"); } @@ -1780,8 +1709,9 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(SELECT); OPCODE(SELECT_CC); OPCODE(SELECT_CC_FP); - OPCODE(BR_CC_T); - OPCODE(BR_CC_F); + OPCODE(BR_T); + OPCODE(BR_F); + OPCODE(BR_CC_FP); OPCODE(BR_JT); OPCODE(CMPUO); OPCODE(CMPUEQ); @@ -1958,7 +1888,7 @@ XtensaTargetLowering::emitSelectCC(MachineInstr &MI, int CmpKind = 0; MachineFunction *MF = BB->getParent(); MachineRegisterInfo &RegInfo = MF->getRegInfo(); - const TargetRegisterClass *RC = getRegClassFor(MVT::i1); + const TargetRegisterClass *RC = &Xtensa::BRRegClass; unsigned b = RegInfo.createVirtualRegister(RC); GetFPBranchKind(Cond.getImm(), BrKind, CmpKind); BuildMI(BB, DL, TII.get(CmpKind), b) @@ -3012,6 +2942,28 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( return MBB; } + case Xtensa::BRCC_FP: { + MachineOperand &Cond = MI.getOperand(0); + MachineOperand &LHS = MI.getOperand(1); + MachineOperand &RHS = MI.getOperand(2); + MachineBasicBlock *TargetBB = MI.getOperand(3).getMBB(); + int BrKind = 0; + int CmpKind = 0; + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = &Xtensa::BRRegClass; + + unsigned RegB = RegInfo.createVirtualRegister(RC); + GetFPBranchKind(Cond.getImm(), BrKind, CmpKind); + BuildMI(*MBB, MI, DL, TII.get(CmpKind), RegB) + .addReg(LHS.getReg()) + .addReg(RHS.getReg()); + BuildMI(*MBB, MI, DL, TII.get(BrKind)).addReg(RegB).addMBB(TargetBB); + + MI.eraseFromParent(); + return MBB; + } + case Xtensa::SELECT_CC_FP_FP: case Xtensa::SELECT_CC_FP_INT: case Xtensa::SELECT_CC_INT_FP: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index d2b61cd4ed732..1ac46c19454fc 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -25,8 +25,11 @@ namespace XtensaISD { enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, - BR_CC_T, - BR_CC_F, + BR_T, + BR_F, + + //Conditional branch with FP operands + BR_CC_FP, BR_JT, @@ -161,6 +164,11 @@ class XtensaTargetLowering : public TargetLowering { return true; } + bool shouldReduceLoadWidth(SDNode *Load, ISD::LoadExtType ExtTy, + EVT NewVT) const override { + return false; + } + MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const override; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 789fc7317620c..2cd034ea4fb73 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -937,8 +937,8 @@ def ORBC : RRR_Inst<0x00, 0x02, 0x03, (outs BR:$r), (ins BR:$s, BR:$t), def XORB : RRR_Inst<0x00, 0x02, 0x04, (outs BR:$r), (ins BR:$s, BR:$t), "xorb\t$r, $s, $t", []>, Requires<[HasBoolean]>; -def : Pat<(Xtensa_brcc_t BR:$b, bb:$target), (BT BR:$b, bb:$target)>; -def : Pat<(Xtensa_brcc_f BR:$b, bb:$target), (BF BR:$b, bb:$target)>; +def : Pat<(Xtensa_br_t BR:$b, bb:$target), (BT BR:$b, bb:$target)>; +def : Pat<(Xtensa_br_f BR:$b, bb:$target), (BF BR:$b, bb:$target)>; //===----------------------------------------------------------------------===// // Floating-Point Instructions @@ -1236,6 +1236,14 @@ let usesCustomInserter = 1 in { "!select_cc_fp_fp $dst, $lhs, $rhs, $t, $f, $cond", [(set FPR:$dst, (Xtensa_select_cc_fp FPR:$lhs, FPR:$rhs, FPR:$t, FPR:$f, imm:$cond))]>; } + +// FP brcc pesudo operation +let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, isBarrier = 1 in { + def BRCC_FP : Pseudo<(outs), (ins i32imm:$cond, FPR:$lhs, FPR:$rhs, brtarget:$target), + "!brcc_fp $cond, $lhs, $rhs, $target", + [(Xtensa_brcc_fp imm:$cond, FPR:$lhs, FPR:$rhs, bb:$target)]>; +} + //===----------------------------------------------------------------------===// // Loop Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index e5f96e4465208..e53691159d425 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -25,7 +25,8 @@ def SDT_XtensaSelectCC : SDTypeProfile<1, 5, SDTCisVT<5, i32>]>; def SDT_XtensaMOVSP : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>; -def SDT_XtensaBrCC : SDTypeProfile<0, 2, [SDTCisVT<0, i1>, SDTCisVT<1, OtherVT>]>; +def SDT_XtensaBrBool : SDTypeProfile<0, 2, [SDTCisVT<0, i1>, SDTCisVT<1, OtherVT>]>; +def SDT_XtensaBrCCFP : SDTypeProfile<0, 4, [SDTCisVT<0, i32>, SDTCisVT<1, f32>, SDTCisVT<2, f32>, SDTCisVT<3, OtherVT>]>; def SDT_XtensaCmp : SDTypeProfile<1, 2, [SDTCisVT<0, i1>, SDTCisVT<1, f32>, SDTCisVT<2, f32>]>; def SDT_XtensaMADD : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisVT<0, f32>]>; def SDT_XtensaMOVS : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, f32>]>; @@ -72,9 +73,11 @@ def Xtensa_select_cc_fp: SDNode<"XtensaISD::SELECT_CC_FP", SDT_XtensaSelectCCFP, def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP, [SDNPInGlue]>; -def Xtensa_brcc_t : SDNode<"XtensaISD::BR_CC_T", SDT_XtensaBrCC, +def Xtensa_br_t : SDNode<"XtensaISD::BR_T", SDT_XtensaBrBool, [SDNPHasChain, SDNPInGlue]>; -def Xtensa_brcc_f : SDNode<"XtensaISD::BR_CC_F", SDT_XtensaBrCC, +def Xtensa_br_f : SDNode<"XtensaISD::BR_F", SDT_XtensaBrBool, + [SDNPHasChain, SDNPInGlue]>; +def Xtensa_brcc_fp : SDNode<"XtensaISD::BR_CC_FP", SDT_XtensaBrCCFP, [SDNPHasChain, SDNPInGlue]>; def Xtensa_cmpoeq : SDNode<"XtensaISD::CMPOEQ", SDT_XtensaCmp, [SDNPOutGlue]>; diff --git a/llvm/test/CodeGen/Xtensa/xtensa-fcmp.ll b/llvm/test/CodeGen/Xtensa/xtensa-fcmp.ll new file mode 100644 index 0000000000000..ffd4977a03c61 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/xtensa-fcmp.ll @@ -0,0 +1,18 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s + +define void @test_fcmp(i32 %x.coerce) { +; CHECK-LABEL: @test_fcmp +entry: + %0 = bitcast i32 %x.coerce to float + %cmp = fcmp oeq float %0, 0x7FF0000000000000 + br i1 %cmp, label %if.then, label %if.else +; CHECK: oeq.s b0, f9, f8 +; CHECK: bf b0, .LBB0_2 + +if.then: ; preds = %entry + unreachable + +if.else: ; preds = %entry + unreachable +} + diff --git a/llvm/test/CodeGen/Xtensa/xtensa-icmp.ll b/llvm/test/CodeGen/Xtensa/xtensa-icmp.ll new file mode 100644 index 0000000000000..684ff3b2b60b8 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/xtensa-icmp.ll @@ -0,0 +1,17 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s + +define i8 @test_bit(i8 %a) { +; CHECK-LABEL: @test_bit + %b = and i8 %a, 16 + %bool = icmp eq i8 %b, 0 + br i1 %bool, label %true, label %false +; CHECK: movi.n a8, 16 +; CHECK: and a8, a2, a8 +; CHECK: bnez a8, .LBB0_2 + +true: + ret i8 1 + +false: + ret i8 0 +} From 3760cb936581eaf5e0976f355e3e55490f67bcff Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:21 +0300 Subject: [PATCH 067/150] [Xtensa] Use ctors for Xtensa target by default --- llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 7 +++++- .../Target/Xtensa/XtensaTargetObjectFile.cpp | 23 +++++++++++++++++ .../Target/Xtensa/XtensaTargetObjectFile.h | 25 +++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaTargetObjectFile.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaTargetObjectFile.h diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 1a3ff0c5311fe..2d27fa78a9b81 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -27,6 +27,7 @@ add_llvm_target(XtensaCodeGen XtensaSizeReductionPass.cpp XtensaSubtarget.cpp XtensaTargetMachine.cpp + XtensaTargetObjectFile.cpp LINK_COMPONENTS AsmPrinter diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index f93fed88d9694..0dbaca3f77c97 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "XtensaTargetMachine.h" +#include "XtensaTargetObjectFile.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -43,6 +44,10 @@ static Reloc::Model getEffectiveRelocModel(bool JIT, return *RM; } +static std::unique_ptr createTLOF() { + return std::make_unique(); +} + XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, @@ -53,7 +58,7 @@ XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, IsLittle), TT, CPU, FS, Options, getEffectiveRelocModel(JIT, RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), - TLOF(std::make_unique()), + TLOF(createTLOF()), Subtarget(TT, std::string(CPU), std::string(FS), *this) { initAsmInfo(); } diff --git a/llvm/lib/Target/Xtensa/XtensaTargetObjectFile.cpp b/llvm/lib/Target/Xtensa/XtensaTargetObjectFile.cpp new file mode 100644 index 0000000000000..27da879ea860d --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaTargetObjectFile.cpp @@ -0,0 +1,23 @@ +//===-- llvm/Target/XtensaTargetObjectFile.cpp - Xtensa Object Info Impl --===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "XtensaTargetObjectFile.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// ELF Target +//===----------------------------------------------------------------------===// + +void XtensaElfTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(false); +} diff --git a/llvm/lib/Target/Xtensa/XtensaTargetObjectFile.h b/llvm/lib/Target/Xtensa/XtensaTargetObjectFile.h new file mode 100644 index 0000000000000..dae8f890459aa --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaTargetObjectFile.h @@ -0,0 +1,25 @@ +//===- llvm/Target/XtensaTargetObjectFile.h - Xtensa Object Info -*- 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_XTENSA_XTENSATARGETOBJECTFILE_H +#define LLVM_LIB_TARGET_XTENSA_XTENSATARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { + +class XtensaElfTargetObjectFile : public TargetLoweringObjectFileELF { +public: + XtensaElfTargetObjectFile() : TargetLoweringObjectFileELF() {} + + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_XTENSA_XTENSATARGETOBJECTFILE_H From f93cbe8ba136d3b23f0c85a33cf917dd4bd97e7f Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:22 +0300 Subject: [PATCH 068/150] [Xtensa] Implement Hardware Loop optimization pass --- llvm/lib/Target/Xtensa/CMakeLists.txt | 3 + .../Disassembler/XtensaDisassembler.cpp | 10 + .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp | 8 +- .../Xtensa/MCTargetDesc/XtensaFixupKinds.h | 1 + .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 15 + .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 3 +- .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 21 + llvm/lib/Target/Xtensa/Xtensa.h | 2 + llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 2 + llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp | 388 ++++++++++++++++++ .../lib/Target/Xtensa/XtensaHardwareLoops.cpp | 335 +++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 112 ++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 3 + llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 56 +++ llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 4 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 41 +- llvm/lib/Target/Xtensa/XtensaOperands.td | 9 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 6 + .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 22 + llvm/lib/Target/Xtensa/XtensaTargetMachine.h | 3 + .../Xtensa/XtensaTargetTransformInfo.cpp | 35 ++ .../Target/Xtensa/XtensaTargetTransformInfo.h | 51 +++ llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll | 31 ++ .../CodeGen/Xtensa/hwloop_unsuitable_loop.ll | 38 ++ 24 files changed, 1167 insertions(+), 32 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.h create mode 100644 llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll create mode 100644 llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 2d27fa78a9b81..6b035e8cb41df 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -17,7 +17,9 @@ add_public_tablegen_target(XtensaCommonTableGen) add_llvm_target(XtensaCodeGen XtensaAsmPrinter.cpp XtensaConstantPoolValue.cpp + XtensaFixupHWLoops.cpp XtensaFrameLowering.cpp + XtensaHardwareLoops.cpp XtensaInstrInfo.cpp XtensaISelDAGToDAG.cpp XtensaISelLowering.cpp @@ -28,6 +30,7 @@ add_llvm_target(XtensaCodeGen XtensaSubtarget.cpp XtensaTargetMachine.cpp XtensaTargetObjectFile.cpp + XtensaTargetTransformInfo.cpp LINK_COMPONENTS AsmPrinter diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index c67a2e40b842d..4bf83b328fb75 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -442,6 +442,16 @@ static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeLoopOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + + assert(isUInt<8>(Imm) && "Invalid immediate"); + if (!tryAddingSymbolicOperand(Imm + 4 + Address, true, Address, 0, 3, Inst, + Decoder)) + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp index 6f47c77f64c8f..4039804b1b583 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp @@ -69,7 +69,8 @@ XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, {"fixup_xtensa_l32r_16", 8, 16, MCFixupKindInfo::FKF_IsPCRel | - MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}; + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, + {"fixup_xtensa_loop_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}}; if (Kind < FirstTargetFixupKind) return MCAsmBackend::getFixupKindInfo(Kind); @@ -119,6 +120,11 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, if (Value & 0x3) Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); return (Value & 0xffffc) >> 2; + case Xtensa::fixup_xtensa_loop_8: + Value -= 4; + if (!isUInt<8>(Value)) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + return (Value & 0xff); case Xtensa::fixup_xtensa_l32r_16: unsigned Offset = Fixup.getOffset(); if (Offset & 0x3) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h index ebbfe0320afd4..1ef683a934b5b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h @@ -22,6 +22,7 @@ enum FixupKind { fixup_xtensa_jump_18, fixup_xtensa_call_18, fixup_xtensa_l32r_16, + fixup_xtensa_loop_8, fixup_xtensa_invalid, LastTargetFixupKind, NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index c402179368df1..90ac7f6a30e1c 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -113,6 +113,21 @@ void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum, llvm_unreachable("Invalid operand"); } +void XtensaInstPrinter::printLoopTarget(const MCInst *MI, int OpNum, + raw_ostream &OS) { + const MCOperand &MC = MI->getOperand(OpNum); + if (MI->getOperand(OpNum).isImm()) { + int64_t Val = MC.getImm() + 4; + OS << ". "; + if (Val > 0) + OS << '+'; + OS << Val; + } else if (MC.isExpr()) + MC.getExpr()->print(OS, &MAI, true); + else + llvm_unreachable("Invalid operand"); +} + void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &OS) { const MCOperand &MC = MI->getOperand(OpNum); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index 62507780ee2a7..73fb032414116 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -36,7 +36,7 @@ class XtensaInstPrinter : public MCInstPrinter { static void printOperand(const MCOperand &MO, raw_ostream &O); // Print an address - static void printAddress(unsigned Base, int64_t Disp, raw_ostream &O); + static void printAddress(unsigned Base, int64_t Disp, raw_ostream &O); // Override MCInstPrinter. void printRegName(raw_ostream &O, unsigned RegNo) const override; @@ -48,6 +48,7 @@ class XtensaInstPrinter : public MCInstPrinter { void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O); void printBranchTarget(const MCInst *MI, int OpNum, raw_ostream &O); + void printLoopTarget(const MCInst *MI, int OpNum, raw_ostream &O); void printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &O); void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printL32RTarget(const MCInst *MI, int OpNum, raw_ostream &O); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 8d30edafb54aa..96194d4e4aa7b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -67,6 +67,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -218,6 +222,23 @@ uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding( } } +uint32_t +XtensaMCCodeEmitter::getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNum); + if (MO.isImm()) + return static_cast(MO.getImm()); + + assert((MO.isExpr()) && "Unexpected operand value!"); + + const MCExpr *Expr = MO.getExpr(); + + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_loop_8), MI.getLoc())); + return 0; +} + uint32_t XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, diff --git a/llvm/lib/Target/Xtensa/Xtensa.h b/llvm/lib/Target/Xtensa/Xtensa.h index ee054d131f35d..2966e085634fb 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.h +++ b/llvm/lib/Target/Xtensa/Xtensa.h @@ -27,5 +27,7 @@ class FunctionPass; FunctionPass *createXtensaISelDag(XtensaTargetMachine &TM, CodeGenOpt::Level OptLevel); FunctionPass *createXtensaSizeReductionPass(); +FunctionPass *createXtensaHardwareLoops(); +FunctionPass *createXtensaFixupHwLoops(); } // namespace llvm #endif /* LLVM_LIB_TARGET_XTENSA_XTENSA_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 8c27af73945d2..14dcda39303e6 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -53,6 +53,8 @@ void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { MCInstBuilder(Xtensa::JX).addReg(MI->getOperand(0).getReg())); return; } + case Xtensa::LOOPEND: + return; } Lower.lower(MI, LoweredMI); EmitToStreamer(*OutStreamer, LoweredMI); diff --git a/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp b/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp new file mode 100644 index 0000000000000..dc712a9138058 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp @@ -0,0 +1,388 @@ +//===---- XtensaFixupHWLoops.cpp - Fixup HW loops -------------------------===// +// +// 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 +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "XtensaTargetMachine.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/Pass.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; + +namespace llvm { +FunctionPass *createXtensaFixupHwLoops(); +void initializeXtensaFixupHwLoopsPass(PassRegistry &); +} // namespace llvm + +namespace { +class XtensaFixupHwLoops : public MachineFunctionPass { + // BasicBlockInfo - Information about the offset and size of a single + // basic block. + struct BasicBlockInfo { + // Offset - Distance from the beginning of the function to the beginning + // of this basic block. + // + // The offset is always aligned as required by the basic block. + unsigned Offset = 0; + + // Size - Size of the basic block in bytes. If the block contains + // inline assembly, this is a worst case estimate. + // + // The size does not include any alignment padding whether from the + // beginning of the block, or from an aligned jump table at the end. + unsigned Size = 0; + + BasicBlockInfo() = default; + + // Compute the offset immediately following this block. \p MBB is the next + // block. + unsigned postOffset(const MachineBasicBlock &MBB) const { + const unsigned PO = Offset + Size; + const Align Alignment = MBB.getAlignment(); + if (Alignment == 1) + return PO; + + const Align ParentAlign = MBB.getParent()->getAlignment(); + if (Alignment <= ParentAlign) + return PO + offsetToAlignment(PO, Alignment); + + // The alignment of this MBB is larger than the function's alignment, so + // we can't tell whether or not it will insert nops. Assume that it will. + return PO + Alignment.value() + offsetToAlignment(PO, Alignment); + } + }; + + SmallVector BlockInfo; + SmallPtrSet AnalyzedMBBs; + + MachineFunction *MF; + MachineLoopInfo *MLI; + const TargetRegisterInfo *TRI; + const TargetInstrInfo *TII; + + bool processLoop(MachineLoop *L); + + bool fixupLoopInstrs(MachineLoop *L); + + void scanFunction(); + + uint64_t computeBlockSize(const MachineBasicBlock &MBB) const; + + void adjustBlockOffsets(MachineBasicBlock &Start); + +public: + static char ID; + + XtensaFixupHwLoops() : MachineFunctionPass(ID) { + initializeXtensaFixupHwLoopsPass(*PassRegistry::getPassRegistry()); + } + + bool runOnMachineFunction(MachineFunction &MF) override; + + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::NoVRegs); + } + + StringRef getPassName() const override { + return "Xtensa Hardware Loop Fixup"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); + } +}; + +char XtensaFixupHwLoops::ID = 0; +} // namespace + +INITIALIZE_PASS(XtensaFixupHwLoops, "hwloopsfixup", + "Xtensa Hardware Loops Fixup", false, false) + +FunctionPass *llvm::createXtensaFixupHwLoops() { + return new XtensaFixupHwLoops(); +} + +// Returns true if the instruction is a hardware loop instruction. +static bool isHardwareLoop(const MachineInstr &MI) { + return (MI.getOpcode() == Xtensa::LOOPSTART); +} + +bool XtensaFixupHwLoops::runOnMachineFunction(MachineFunction &mf) { + if (skipFunction(mf.getFunction())) + return false; + + MF = &mf; + MLI = &getAnalysis(); + const TargetSubtargetInfo &ST = mf.getSubtarget(); + TII = ST.getInstrInfo(); + TRI = ST.getRegisterInfo(); + + // Renumber all of the machine basic blocks in the function, guaranteeing that + // the numbers agree with the position of the block in the function. + mf.RenumberBlocks(); + + // Do the initial scan of the function, building up information about the + // sizes of each block. + scanFunction(); + + AnalyzedMBBs.clear(); + + bool Changed = false; + + for (auto &L : *MLI) + if (!L->getParentLoop()) { + Changed |= processLoop(L); + } + + return Changed; +} + +// Scan loop and find hardware loop pseudo instructions LOOPSTART and LOOPEND. +// Transform LOOPSTART to Xtensa instructions and remove LOOPEND. +bool XtensaFixupHwLoops::fixupLoopInstrs(MachineLoop *L) { + // const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + MachineBasicBlock &MBB = *(L->getHeader()); + bool Changed = false; + unsigned Num = MBB.getNumber(); + unsigned Offset = BlockInfo[Num].Offset; + MachineBasicBlock *LastBlock = nullptr; + unsigned LHOffset = Offset; + unsigned LastBlockOffset = 0; + + // Loop over all the instructions. + MachineBasicBlock::iterator MII = MBB.begin(); + MachineBasicBlock::iterator MIE = MBB.end(); + MachineInstr *PredI1 = nullptr; + MachineInstr *FirstMI = nullptr; + + for (auto MBI = L->block_begin(), MBIE = L->block_end(); MBI != MBIE; ++MBI) { + if (LastBlockOffset < BlockInfo[(*MBI)->getNumber()].Offset) { + LastBlockOffset = BlockInfo[(*MBI)->getNumber()].Offset; + LastBlock = (*MBI); + } + } + + while (MII != MIE) { + if (MII->isMetaInstruction()) { + ++MII; + continue; + } + + MachineInstr &MI = *MII; + + if (FirstMI == nullptr) + FirstMI = &MI; + + if (isHardwareLoop(*MII)) { + MachineBasicBlock *LoopEnd = nullptr; + + MII->getNextNode(); + + MachineBasicBlock::iterator NextMII = std::next(MII); + + // Check whether loop is empty and remove if true + if (NextMII != MIE) { + if ((*NextMII).getOpcode() == Xtensa::LOOPEND) { + MBB.erase(*NextMII); + MBB.erase(*MII); + MBB.removeSuccessor(&MBB, true); + return true; + } + } + + for (MachineBasicBlock::pred_iterator PI = MBB.pred_begin(), + PE = MBB.pred_end(); + PI != PE; ++PI) { + MachineBasicBlock *PMBB = *PI; + MachineBasicBlock::iterator PIB = PMBB->begin(); + MachineBasicBlock::iterator PII = PMBB->end(); + + do { + --PII; + if (PII->isMetaInstruction()) { + continue; + } + + if ((*PII).getOpcode() == Xtensa::LOOPEND) { + DebugLoc DL = PII->getDebugLoc(); + unsigned OffsetLE = BlockInfo[PMBB->getNumber()].Offset; + + // Check if loop end is placed before loop header + // In such case add special MBB after loop header and create jump + // from loop end to it + if (OffsetLE < LHOffset) { + LoopEnd = MF->CreateMachineBasicBlock(); + MF->insert(++LastBlock->getIterator(), LoopEnd); + LoopEnd->transferSuccessors(PMBB); + LoopEnd->splice(LoopEnd->end(), PMBB, PII, PMBB->end()); + + MachineBasicBlock::iterator LEI = LoopEnd->end(); + --LEI; + + // Expect jump instruction + assert((LEI->getOpcode() == Xtensa::J) && "Broken hardware loop"); + + // Create block and insert it before loop end address as + // target for jump instruction to avoid premature exit from loop + MachineBasicBlock *BlockForJump = MF->CreateMachineBasicBlock(); + MF->insert(LoopEnd->getIterator(), BlockForJump); + BlockForJump->addSuccessor(LoopEnd); + BuildMI(*BlockForJump, BlockForJump->end(), DL, + TII->get(Xtensa::NOP)); + BuildMI(*PMBB, PMBB->end(), DL, TII->get(Xtensa::J)) + .addMBB(BlockForJump); + PMBB->addSuccessor(BlockForJump); + + BuildMI(*LoopEnd, LoopEnd->begin(), DL, TII->get(Xtensa::LOOPEND)) + .addMBB(LoopEnd); + LoopEnd->addSuccessor(LoopEnd); + Changed = true; + break; + } + + if (PII != PIB) { + LoopEnd = MF->CreateMachineBasicBlock(); + MF->insert(++(PMBB->getIterator()), LoopEnd); + LoopEnd->transferSuccessors(PMBB); + LoopEnd->splice(LoopEnd->end(), PMBB, PII, PMBB->end()); + PMBB->addSuccessor(LoopEnd); + + BuildMI(*LoopEnd, LoopEnd->begin(), DL, TII->get(Xtensa::LOOPEND)) + .addMBB(LoopEnd); + LoopEnd->addSuccessor(LoopEnd); + } else { + BuildMI(*PMBB, PII, DL, TII->get(Xtensa::LOOPEND)).addMBB(PMBB); + PMBB->addSuccessor(PMBB); + BuildMI(*PMBB, PII, DL, TII->get(Xtensa::NOP)); + LoopEnd = PMBB; + } + + Changed = true; + break; + } + } while (PII != PIB); + if (Changed) + break; + } + + assert((Changed) && "Broken hardware loop"); + + if (MII != FirstMI) { + MBB.splice(FirstMI->getIterator(), &MBB, MII); + Offset = BlockInfo[Num].Offset; + switch (PredI1->getOpcode()) { + case Xtensa::L32I_N: + if (PredI1->getOperand(0).getReg() == MII->getOperand(0).getReg()) { + MBB.splice(MII, &MBB, PredI1); + Offset += 2; + } + break; + case Xtensa::L32I: + if (PredI1->getOperand(0).getReg() == MII->getOperand(0).getReg()) { + MBB.splice(MII, &MBB, PredI1); + Offset += 3; + } + break; + } + } + + DebugLoc DL = MII->getDebugLoc(); + + // Fixup Loop alignment + switch (Offset & 0x3) { + case 0x0: + BuildMI(MBB, MII, DL, TII->get(Xtensa::NOP)); + BuildMI(MBB, MII, DL, TII->get(Xtensa::NOP)); + break; + case 0x3: + BuildMI(MBB, MII, DL, TII->get(Xtensa::NOP)); + break; + } + + BuildMI(MBB, MII, DL, TII->get(Xtensa::LOOP)) + .addReg(MII->getOperand(0).getReg()) + .addMBB(LoopEnd); + MBB.erase(MII); + + MF->RenumberBlocks(); + scanFunction(); + AnalyzedMBBs.insert(&MBB); + return true; + } else { + Offset += TII->getInstSizeInBytes(MI); + PredI1 = &MI; + ++MII; + } + } + + return Changed; +} + +bool XtensaFixupHwLoops::processLoop(MachineLoop *L) { + bool Changed = false; + + // Process nested loops first. + for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) { + Changed |= processLoop(*I); + } + + if (Changed) + return true; + + return fixupLoopInstrs(L); +} + +// scanFunction - Do the initial scan of the function, building up +// information about each block. +void XtensaFixupHwLoops::scanFunction() { + BlockInfo.clear(); + BlockInfo.resize(MF->getNumBlockIDs()); + + // First thing, compute the size of all basic blocks, and see if the function + // has any inline assembly in it. If so, we have to be conservative about + // alignment assumptions, as we don't know for sure the size of any + // instructions in the inline assembly. + for (MachineBasicBlock &MBB : *MF) + BlockInfo[MBB.getNumber()].Size = computeBlockSize(MBB); + + // Compute block offsets and known bits. + adjustBlockOffsets(*MF->begin()); +} + +// computeBlockSize - Compute the size for MBB. +uint64_t +XtensaFixupHwLoops::computeBlockSize(const MachineBasicBlock &MBB) const { + uint64_t Size = 0; + for (const MachineInstr &MI : MBB) + if (MI.getOpcode() != Xtensa::LOOPEND) + Size += TII->getInstSizeInBytes(MI); + return Size; +} + +void XtensaFixupHwLoops::adjustBlockOffsets(MachineBasicBlock &Start) { + unsigned PrevNum = Start.getNumber(); + for (auto &MBB : make_range(MachineFunction::iterator(Start), MF->end())) { + unsigned Num = MBB.getNumber(); + if (!Num) // block zero is never changed from offset zero. + continue; + // Get the offset and known bits at the end of the layout predecessor. + // Include the alignment of the current block. + BlockInfo[Num].Offset = BlockInfo[PrevNum].postOffset(MBB); + + PrevNum = Num; + } +} + diff --git a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp new file mode 100644 index 0000000000000..f31d724ebb8f1 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp @@ -0,0 +1,335 @@ +//===- XtensaHardwareLoops.cpp - Idenify and generate hardware Loops ------===// +// +// The LLVM Compiler Infrastructure +// +// 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 contains implementation of the pass which optimizes loops . +// +//===----------------------------------------------------------------------===// + +#include "XtensaInstrInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-hwloops" +#define MAX_LOOP_SIZE 256 + +namespace llvm { + +FunctionPass *createXtensaHardwareLoops(); +void initializeXtensaHardwareLoopsPass(PassRegistry &); + +} // end namespace llvm + +namespace { + +struct XtensaHardwareLoops : public MachineFunctionPass { + MachineLoopInfo *MLI; + MachineRegisterInfo *MRI; + MachineDominatorTree *MDT; + const XtensaInstrInfo *TII; + const XtensaSubtarget *STI; + SmallPtrSet VisitedMBBs; + +public: + static char ID; + + XtensaHardwareLoops() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &MF) override; + + StringRef getPassName() const override { return "Xtensa Hardware Loops"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); + } + +private: + // Return true if the instruction is not valid within a hardware + // loop. + bool isInvalidLoopOperation(const MachineInstr *MI) const; + + // Return true if the loop contains an instruction that inhibits + // using the hardware loop. + bool containsInvalidInstruction(MachineLoop *L) const; + + // Given a loop, check if we can convert it to a hardware loop. + // If so, then perform the conversion and return true. + bool processLoop(MachineLoop *L); + + bool checkLoopSize(MachineLoop *L); + + bool checkLoopEndDisplacement(MachineFunction &MF, MachineBasicBlock *LH, MachineBasicBlock* LE); +}; + +char XtensaHardwareLoops::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS(XtensaHardwareLoops, "hwloops", "Xtensa Hardware Loops", false, + false) + +FunctionPass *llvm::createXtensaHardwareLoops() { + return new XtensaHardwareLoops(); +} + +bool XtensaHardwareLoops::runOnMachineFunction(MachineFunction &MF) { + LLVM_DEBUG(dbgs() << "********* Xtensa Hardware Loops *********\n"); + if (skipFunction(MF.getFunction())) + return false; + + bool Changed = false; + + MLI = &getAnalysis(); + MRI = &MF.getRegInfo(); + STI = &MF.getSubtarget(); + TII = STI->getInstrInfo(); + + if (!STI->hasLoop()) + return false; + + VisitedMBBs.clear(); + + for (auto &L : *MLI) + if (!L->getParentLoop()) { + Changed |= processLoop(L); + } + + return Changed; +} + +// Return true if the operation is invalid within hardware loop. +bool XtensaHardwareLoops::isInvalidLoopOperation(const MachineInstr *MI) const { + + // Call is not allowed because the callee may use a hardware loop + if (MI->getDesc().isCall()) + return true; + + if ((MI->getOpcode() == Xtensa::LOOP) || + (MI->getOpcode() == Xtensa::LOOPGTZ) || + (MI->getOpcode() == Xtensa::LOOPNEZ)) + return true; + + if (MI->isInlineAsm()) + return true; + + return false; +} + +// Return true if the loop contains an instruction that inhibits +// the use of the hardware loop instruction. +bool XtensaHardwareLoops::containsInvalidInstruction(MachineLoop *L) const { + LLVM_DEBUG(dbgs() << "\nhw_loop head, " + << printMBBReference(**L->block_begin())); + for (MachineBasicBlock *MBB : L->getBlocks()) { + for (MachineBasicBlock::iterator MII = MBB->begin(), E = MBB->end(); + MII != E; ++MII) { + const MachineInstr *MI = &*MII; + if (isInvalidLoopOperation(MI)) { + LLVM_DEBUG(dbgs() << "\nCannot convert to hw_loop due to:"; + MI->dump();); + return true; + } + } + } + return false; +} + +// Check if this loop is suitable for converting to a hardware loop +bool XtensaHardwareLoops::processLoop(MachineLoop *L) { + // This is just for sanity. + assert(L->getHeader() && "Loop without a header?"); + + bool Changed = false; + + // Process nested loops first. + for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) { + Changed |= processLoop(*I); + } + + if (Changed) + return true; + + using instr_iterator = MachineBasicBlock::instr_iterator; + MachineInstr *LII = nullptr; // LOOPINIT instruction + MachineInstr *LEI = nullptr; // LOOPEND instruction + MachineBasicBlock *LEMBB = nullptr; + MachineBasicBlock *PH = L->getLoopPreheader(); + MachineBasicBlock *LastMBB = L->getLoopLatch(); + + // Try to find LOOPEND instruction in the loop latch + for (auto MBI = L->block_begin(), MBIE = L->block_end(); MBI != MBIE; ++MBI) { + if (VisitedMBBs.count(*MBI)) + continue; + for (auto MII = (*MBI)->begin(), MIE = (*MBI)->end(); MII != MIE; ++MII) { + MachineInstr *LMI = &*MII; + if (LMI->getOpcode() == Xtensa::LOOPEND) { + LEI = LMI; + LEMBB = *MBI; + } + } + VisitedMBBs.insert(*MBI); + } + + if (LEI != nullptr) { + MachineBasicBlock *LH = L->getHeader(); + MachineBasicBlock::iterator LHI = LH->getFirstNonPHI(); + + if (!PH) { + llvm_unreachable("Hardware loop predecessor not found"); + return false; + } + + MachineBasicBlock *LIMBB = PH; + + // Try to find LOOPINIT instruction in predecessors chain + while ((LII == nullptr) && (LIMBB != nullptr) && + ((L->getParentLoop() == nullptr) || + (L->getParentLoop()->contains(LIMBB)))) { + for (instr_iterator I = LIMBB->instr_begin(), E = LIMBB->instr_end(); + I != E; ++I) { + MachineInstr *MI = &*I; + if (MI->getOpcode() == Xtensa::LOOPINIT) { + LII = MI; + break; + } + } + if (LII == nullptr) + LIMBB = *LIMBB->pred_begin(); + } + + if (LII == nullptr) { + llvm_unreachable("Hardware loop init instruction not found"); + return false; + } + + DebugLoc DL = LII->getDebugLoc(); + + // If loop is too large or have wrong configuration + // then restore branch instruction + // sub a, a, 1 + // bnez a, LH + if (!checkLoopSize(L) || containsInvalidInstruction(L) || + (LEMBB != LastMBB) || (!checkLoopEndDisplacement(*LH->getParent(), LH, LEMBB))) { + const MCInstrDesc &PD = TII->get(TargetOpcode::PHI); + MachineInstr *NewPN = LH->getParent()->CreateMachineInstr(PD, DL); + LH->insert(LH->begin(), NewPN); + Register PR = MRI->createVirtualRegister(&Xtensa::ARRegClass); + NewPN->addOperand(MachineOperand::CreateReg(PR, true)); + + MachineOperand MO = + MachineOperand::CreateReg(LII->getOperand(0).getReg(), false); + NewPN->addOperand(MO); + NewPN->addOperand(MachineOperand::CreateMBB(PH)); + + Register IndR = MRI->createVirtualRegister(&Xtensa::ARRegClass); + MO = MachineOperand::CreateReg(IndR, false); + NewPN->addOperand(MO); + NewPN->addOperand(MachineOperand::CreateMBB(LastMBB)); + + MachineInstrBuilder MIB = + BuildMI(*LEMBB, LEI, LEI->getDebugLoc(), TII->get(Xtensa::ADDI), IndR) + .addReg(PR) + .addImm(-1); + + MIB = BuildMI(*LEMBB, LEI, LEI->getDebugLoc(), TII->get(Xtensa::BNEZ)) + .addReg(IndR) + .addMBB(LEI->getOperand(0).getMBB()); + LEMBB->erase(LEI); + PH->erase(LII); + return false; + } + + //Place LOOPSTART instruction in loop header + BuildMI(*LH, LHI, DL, TII->get(Xtensa::LOOPSTART)) + .addReg(LII->getOperand(0).getReg()) + .addMBB(LastMBB); + PH->erase(LII); + return true; + } + + return false; +} + +bool XtensaHardwareLoops::checkLoopSize(MachineLoop *L) { + uint64_t LoopSize = 0; + + for (auto *MBB : L->getBlocks()) { + uint64_t BlockSize = 0; + for (const MachineInstr &MI : *MBB) { + uint64_t InstSize = TII->getInstSizeInBytes(MI); + if (MI.isPHI()) + InstSize = 3; + BlockSize += InstSize; + } + LoopSize += BlockSize; + } + + if (LoopSize > MAX_LOOP_SIZE) + return false; + + return true; +} + +bool XtensaHardwareLoops::checkLoopEndDisplacement(MachineFunction &MF, + MachineBasicBlock *LH, + MachineBasicBlock *LE) { + bool isLHVisited = false; + + if (LH == LE) + return true; + + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { + MachineBasicBlock *MBB = &*I; + if (MBB == LH) + isLHVisited = true; + else if (MBB == LE) { + if (isLHVisited) + return true; + else + return false; + } + } + llvm_unreachable("Wrong hardware loop"); +} + diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index d6bf1ec3b1804..42c9ff0285c83 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -513,29 +513,106 @@ static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, return SDValue(); } +static SDValue SearchLoopIntrinsic(SDValue N, ISD::CondCode &CC, int &Imm, + bool &Negate) { + switch (N->getOpcode()) { + default: + break; + case ISD::XOR: { + if (!isa(N.getOperand(1))) + return SDValue(); + if (!cast(N.getOperand(1))->isOne()) + return SDValue(); + Negate = !Negate; + return SearchLoopIntrinsic(N.getOperand(0), CC, Imm, Negate); + } + case ISD::SETCC: { + auto *Const = dyn_cast(N.getOperand(1)); + if (!Const) + return SDValue(); + if (Const->isNullValue()) + Imm = 0; + else if (Const->isOne()) + Imm = 1; + else + return SDValue(); + CC = cast(N.getOperand(2))->get(); + return SearchLoopIntrinsic(N->getOperand(0), CC, Imm, Negate); + } + case ISD::INTRINSIC_W_CHAIN: { + unsigned IntOp = cast(N.getOperand(1))->getZExtValue(); + if (IntOp != Intrinsic::loop_decrement) + return SDValue(); + return N; + } + } + return SDValue(); +} + static SDValue PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const XtensaSubtarget &Subtarget) { - if (DCI.isBeforeLegalizeOps()) { - SDValue Chain = N->getOperand(0); + SDValue Chain = N->getOperand(0); + SDLoc DL(N); + SDValue Cond = N->getOperand(1); + SDValue Dest = N->getOperand(2); + ISD::CondCode CC = ISD::SETEQ; + int Imm = 1; + bool Negate = false; + + SDValue Int = SearchLoopIntrinsic(Cond, CC, Imm, Negate); + if (Int) { + assert((N->hasOneUse() && N->use_begin()->getOpcode() == ISD::BR) && + "expected single br user"); + SDNode *Br = *N->use_begin(); + SDValue OtherTarget = Br->getOperand(1); + + if (Negate) + CC = ISD::getSetCCInverse(CC, /* Integer inverse */ MVT::i32); + + auto IsTrueIfZero = [](ISD::CondCode CC, int Imm) { + return (CC == ISD::SETEQ && Imm == 0) || (CC == ISD::SETNE && Imm == 1) || + (CC == ISD::SETLT && Imm == 1) || (CC == ISD::SETULT && Imm == 1); + }; + + auto IsFalseIfZero = [](ISD::CondCode CC, int Imm) { + return (CC == ISD::SETEQ && Imm == 1) || (CC == ISD::SETNE && Imm == 0) || + (CC == ISD::SETGT && Imm == 0) || + (CC == ISD::SETUGT && Imm == 0) || + (CC == ISD::SETGE && Imm == 1) || (CC == ISD::SETUGE && Imm == 1); + }; + + if (IsTrueIfZero(CC, Imm)) { + SDValue NewBrOps[] = {Br->getOperand(0), Dest}; + SDValue NewBr = DAG.getNode(ISD::BR, SDLoc(Br), MVT::Other, NewBrOps); + DAG.ReplaceAllUsesOfValueWith(SDValue(Br, 0), NewBr); + Dest = OtherTarget; + } else if (!IsFalseIfZero(CC, Imm)) { + llvm_unreachable("unsupported condition"); + } - if (N->getOperand(1).getOpcode() != ISD::SETCC) - return SDValue(); + // We now need to make the intrinsic dead (it cannot be instruction + // selected). + DAG.ReplaceAllUsesOfValueWith(Int.getValue(1), Int.getOperand(0)); + assert(Int.getNode()->hasOneUse() && + "Counter decrement has more than one use"); - SDLoc DL(N); - SDValue SetCC = N->getOperand(1); - SDValue Dest = N->getOperand(2); - ISD::CondCode CC = cast(SetCC->getOperand(2))->get(); - SDValue LHS = SetCC->getOperand(0); - SDValue RHS = SetCC->getOperand(1); + return DAG.getNode(XtensaISD::LOOPEND, DL, MVT::Other, N->getOperand(0), + Dest); + } - if (LHS.getValueType() != MVT::i32) - return SDValue(); + if (Cond.getOpcode() != ISD::SETCC) + return SDValue(); - return DAG.getNode(ISD::BR_CC, DL, MVT::isVoid, Chain, DAG.getCondCode(CC), - LHS, RHS, Dest); - } - return SDValue(); + CC = cast(Cond->getOperand(2))->get(); + SDValue LHS = Cond->getOperand(0); + SDValue RHS = Cond->getOperand(1); + + if (LHS.getValueType() != MVT::i32) + return SDValue(); + + return DAG.getNode(ISD::BR_CC, DL, MVT::isVoid, Chain, DAG.getCondCode(CC), + LHS, RHS, Dest); } SDValue XtensaTargetLowering::PerformDAGCombine(SDNode *N, @@ -1632,7 +1709,7 @@ SDValue XtensaTargetLowering::LowerFunnelShift(SDValue Op, SDValue SetSAR = DAG.getNode(XtensaISD::SSR, DL, MVT::Glue, Shamt); return DAG.getNode(XtensaISD::SRC, DL, VT, Op0, Op1, SetSAR); -} +} SDValue XtensaTargetLowering::LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const { @@ -1720,6 +1797,7 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(CMPOEQ); OPCODE(CMPOLE); OPCODE(CMPOLT); + OPCODE(LOOPEND); OPCODE(MADD); OPCODE(MSUB); OPCODE(MOVS); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 1ac46c19454fc..d638343c82bb8 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -49,6 +49,9 @@ enum { CMPOEQ, CMPOLE, CMPOLT, + + LOOPEND, + // FP multipy-add/sub MADD, MSUB, diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index bd962e3cfa854..a4f765c411637 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -258,6 +258,10 @@ bool XtensaInstrInfo::reverseBranchCondition( case Xtensa::BT: Cond[0].setImm(Xtensa::BF); return false; + + case Xtensa::LOOPEND: + return true; + default: llvm_unreachable("Invalid branch condition!"); } @@ -271,6 +275,7 @@ XtensaInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { case Xtensa::JX: return nullptr; case Xtensa::J: + case Xtensa::LOOPEND: return MI.getOperand(0).getMBB(); case Xtensa::BEQ: case Xtensa::BNE: @@ -311,6 +316,11 @@ bool XtensaInstrInfo::isBranchOffsetInRange(unsigned BranchOp, return isIntN(18, BrOffset); case Xtensa::JX: return true; + case Xtensa::LOOPEND: + BrOffset += 4; + BrOffset += 3 * 3; // 2*NOP + LOOP instrucions + assert((BrOffset <= 0) && "Wrong hardware loop"); + return true; case Xtensa::BR_JT: return true; case Xtensa::BEQ: @@ -629,6 +639,9 @@ unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, case Xtensa::BF: MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB); break; + case Xtensa::LOOPEND: + MI = BuildMI(MBB, I, DL, get(BR_C)).addMBB(TBB); + break; default: llvm_unreachable("Invalid branch type!"); } @@ -638,6 +651,48 @@ unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, return Count; } +bool XtensaInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg, + Register &SrcReg2, int64_t &Mask, + int64_t &Value) const { + unsigned Opc = MI.getOpcode(); + + switch (Opc) { + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + SrcReg = MI.getOperand(0).getReg(); + SrcReg2 = MI.getOperand(1).getReg(); + Value = 0; + Mask = 0; + return true; + + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + SrcReg = MI.getOperand(0).getReg(); + Value = MI.getOperand(1).getImm(); + Mask = ~0; + return true; + + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + SrcReg = MI.getOperand(0).getReg(); + Value = 0; + Mask = ~0; + return true; + } + + return false; +} + bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI, SmallVectorImpl &Cond, const MachineOperand *&Target) const { @@ -646,6 +701,7 @@ bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI, case Xtensa::J: case Xtensa::JX: case Xtensa::BR_JT: + case Xtensa::LOOPEND: Cond[0].setImm(OpCode); Target = &MI->getOperand(0); return true; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h index 25597d9b0a220..8b064613d8250 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -93,6 +93,10 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { int64_t offset, ArrayRef Cond, DebugLoc DL, int *BytesAdded) const; + bool analyzeCompare(const MachineInstr &MI, Register &SrcReg, + Register &SrcReg2, int64_t &CmpMask, + int64_t &CmpValue) const override; + // Return true if MI is a conditional or unconditional branch. // When returning true, set Cond to the mask of condition-code // values on which the instruction will branch, and set Target diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 2cd034ea4fb73..efb710a2145a3 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1248,31 +1248,48 @@ let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, isBarrier = 1 in { // Loop Instructions //===----------------------------------------------------------------------===// -def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, mem8:$uimm8), - "loop\t$$s, $uimm8", []>, Requires<[HasLoop]> { - bits<8> uimm8; +def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), + "loop\t$s, $target", []>, Requires<[HasLoop]> { + bits<8> target; let r = 0x08; let t = 0x07; - let imm8 = uimm8; + let imm8 = target; } -def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, mem8:$uimm8), - "loopgtz\t$$s, $uimm8", []>, Requires<[HasLoop]> { - bits<8> uimm8; +def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), + "loopgtz\t$s, $target", []>, Requires<[HasLoop]> { + bits<8> target; let r = 0x0A; let t = 0x07; - let imm8 = uimm8; + let imm8 = target; } -def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, mem8:$uimm8), - "loopnez\t$$s, $uimm8", []>, Requires<[HasLoop]> { - bits<8> uimm8; +def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), + "loopnez\t$s, $target", []>, Requires<[HasLoop]> { + bits<8> target; let r = 0x09; let t = 0x07; - let imm8 = uimm8; + let imm8 = target; +} + +let isTerminator = 1, isBarrier = 1, hasSideEffects = 1, Size = 3 in { + def LOOPINIT : Pseudo<(outs), (ins AR:$elts), + "!loopinit $elts", [(int_set_loop_iterations AR:$elts)]>; +} + +// LOOPSTART pseudo instruction reserves 9 bytes for LOOP operation and NOP operations for possible alignment. +let isTerminator = 1, isBarrier = 1, hasSideEffects = 1, Size = 9 in { + def LOOPSTART : Pseudo<(outs), (ins AR:$s, brtarget:$target), + "!loopstart $s, $target", []>; +} + +// LOOPEND pseudo instruction reserves 6 bytes for Jump and NOP operations. +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 0, Size = 6 in { + def LOOPEND : Pseudo<(outs), (ins brtarget:$target), + "!loopend $target", [(Xtensa_loopend bb:$target)]>; } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 1ea3eeab0e363..9957bf7bd1f47 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -49,7 +49,7 @@ def Imm64n_4n_AsmOperand: ImmAsmOperand<"Imm64n_4n">; def imm64n_4n: Immediate= -64 && Imm <= -4; }], "Imm64n_4n_AsmOperand"> { let EncoderMethod = "getImm64n_4nOpValue"; let DecoderMethod = "decodeImm64n_4nOperand"; -} +} // imm12 predicate - Immediate in the range [-2048,2047] def Imm12_AsmOperand : ImmAsmOperand<"Imm12">; @@ -238,6 +238,13 @@ def jumptarget : Operand { let ParserMatchClass = XtensaPCRelTargetAsmOperand; } +def ltarget : Operand { + let PrintMethod = "printLoopTarget"; + let EncoderMethod = "getLoopTargetEncoding"; + let DecoderMethod = "decodeLoopOperand"; + let ParserMatchClass = XtensaPCRelTargetAsmOperand; +} + def L32Rtarget: Operand { let PrintMethod = "printL32RTarget"; let EncoderMethod = "getL32RTargetEncoding"; diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index e53691159d425..a37dcd7c8a986 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -44,6 +44,8 @@ def SDT_XtensaSSR : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; def SDT_XtensaMEMBARRIER : SDTypeProfile<0, 0, []>; def SDT_XtensaRUR : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaLoopEnd : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>; + //===----------------------------------------------------------------------===// // Node definitions //===----------------------------------------------------------------------===// @@ -107,3 +109,7 @@ def Xtensa_mem_barrier: SDNode<"XtensaISD::MEMW", SDT_XtensaMEMBARRIER, def Xtensa_rur: SDNode<"XtensaISD::RUR", SDT_XtensaRUR, [SDNPInGlue]>; + +def Xtensa_loopend: SDNode<"XtensaISD::LOOPEND", SDT_XtensaLoopEnd, + [SDNPHasChain, SDNPInGlue]>; + diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index 0dbaca3f77c97..8aea549304b93 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -14,6 +14,7 @@ #include "XtensaTargetMachine.h" #include "XtensaTargetObjectFile.h" +#include "XtensaTargetTransformInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -76,6 +77,11 @@ XtensaTargetMachine::getSubtargetImpl(const Function &F) const { return &Subtarget; } +TargetTransformInfo +XtensaTargetMachine::getTargetTransformInfo(const Function &F) const { + return TargetTransformInfo(XtensaTTIImpl(this, F)); +} + namespace { /// Xtensa Code Generator Pass Configuration Options. class XtensaPassConfig : public TargetPassConfig { @@ -88,11 +94,21 @@ class XtensaPassConfig : public TargetPassConfig { } void addIRPasses() override; + bool addPreISel() override; bool addInstSelector() override; + void addPreRegAlloc() override; void addPreEmitPass() override; }; } // end anonymous namespace +bool XtensaPassConfig::addPreISel() { + if (TM->getOptLevel() != CodeGenOpt::None) { + addPass(createHardwareLoopsPass()); + } + + return false; +} + bool XtensaPassConfig::addInstSelector() { addPass(createXtensaISelDag(getXtensaTargetMachine(), getOptLevel())); return false; @@ -100,11 +116,17 @@ bool XtensaPassConfig::addInstSelector() { void XtensaPassConfig::addIRPasses() { addPass(createAtomicExpandPass()); } +void XtensaPassConfig::addPreRegAlloc() { + addPass(createXtensaHardwareLoops()); +} + void XtensaPassConfig::addPreEmitPass() { addPass(createXtensaSizeReductionPass()); + addPass(createXtensaFixupHwLoops()); addPass(&BranchRelaxationPassID); } TargetPassConfig *XtensaTargetMachine::createPassConfig(PassManagerBase &PM) { return new XtensaPassConfig(*this, PM); } + diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.h b/llvm/lib/Target/Xtensa/XtensaTargetMachine.h index db99df12c6249..bd4948b5ea56c 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.h +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.h @@ -38,6 +38,8 @@ class XtensaTargetMachine : public LLVMTargetMachine { Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT); + TargetTransformInfo getTargetTransformInfo(const Function &F) const override; + // Override TargetMachine. const XtensaSubtarget *getSubtargetImpl() const { return &Subtarget; } const XtensaSubtarget *getSubtargetImpl(const Function &F) const override; @@ -53,3 +55,4 @@ class XtensaTargetMachine : public LLVMTargetMachine { } // end namespace llvm #endif /* LLVM_LIB_TARGET_XTENSA_XTENSATARGETMACHINE_H */ + diff --git a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp new file mode 100644 index 0000000000000..7bdec70504772 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp @@ -0,0 +1,35 @@ +//===- XtensaTargetTransformInfo.cpp - Xtensa specific TTI ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "XtensaTargetTransformInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensatti" + +static cl::opt DisableLowOverheadLoops( + "disable-xtensa-hwloops", cl::Hidden, cl::init(false), + cl::desc("Disable the generation of hardware loops")); + +bool XtensaTTIImpl::isHardwareLoopProfitable(Loop *L, ScalarEvolution &SE, + AssumptionCache &AC, + TargetLibraryInfo *LibInfo, + HardwareLoopInfo &HWLoopInfo) { + if (DisableLowOverheadLoops) + return false; + + if (!ST->hasLoop()) + return false; + + LLVMContext &C = L->getHeader()->getContext(); + HWLoopInfo.CounterInReg = false; + HWLoopInfo.IsNestingLegal = false; + HWLoopInfo.CountType = Type::getInt32Ty(C); + HWLoopInfo.LoopDecrement = ConstantInt::get(HWLoopInfo.CountType, 1); + return true; +} diff --git a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.h b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.h new file mode 100644 index 0000000000000..81bfbacc0381e --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.h @@ -0,0 +1,51 @@ +//===- XtensaTargetTransformInfo.h - Xtensa specific TTI --------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file defines a TargetTransformInfo::Concept conforming object specific +/// to the Xtensa target machine. It uses the target's detailed information to +/// provide more precise answers to certain TTI queries, while letting the +/// target independent and default TTI implementations handle the rest. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSATARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_XTENSA_XTENSATARGETTRANSFORMINFO_H + +#include "XtensaSubtarget.h" +#include "XtensaTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/IR/Function.h" + +namespace llvm { + +class XtensaTTIImpl : public BasicTTIImplBase { + using BaseT = BasicTTIImplBase; + using TTI = TargetTransformInfo; + + friend BaseT; + + const XtensaSubtarget *ST; + const XtensaTargetLowering *TLI; + + const XtensaSubtarget *getST() const { return ST; } + const XtensaTargetLowering *getTLI() const { return TLI; } + +public: + explicit XtensaTTIImpl(const XtensaTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + bool isHardwareLoopProfitable(Loop *L, ScalarEvolution &SE, + AssumptionCache &AC, TargetLibraryInfo *LibInfo, + HardwareLoopInfo &HWLoopInfo); +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_XTENSA_XTENSATARGETTRANSFORMINFO_H diff --git a/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll b/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll new file mode 100644 index 0000000000000..1942d51136a21 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll @@ -0,0 +1,31 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s + + +; Function Attrs: norecurse nounwind optsize readnone +define i32 @test_hwloop(i32 %a, i32 %b, i32 %n) local_unnamed_addr #0 { +; CHECK-LABEL: @test_hwloop +entry: + %cmp7 = icmp sgt i32 %n, 0 + br i1 %cmp7, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.body, %entry + %a.addr.0.lcssa = phi i32 [ %a, %entry ], [ %a.addr.1, %for.body ] + ret i32 %a.addr.0.lcssa + +for.body: ; preds = %entry, %for.body + %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ] + %a.addr.08 = phi i32 [ %a.addr.1, %for.body ], [ %a, %entry ] + %cmp1 = icmp sgt i32 %a.addr.08, 0 + %mul = mul nsw i32 %a.addr.08, %b + %add = select i1 %cmp1, i32 %mul, i32 0 + %a.addr.1 = add nsw i32 %add, %a.addr.08 + %inc = add nuw nsw i32 %i.09, 1 + %cmp = icmp slt i32 %inc, %n + br i1 %cmp, label %for.body, label %for.cond.cleanup +; CHECK: loop a4, .LBB0_5 +; CHECK: bge a8, a2, .LBB0_2 +; CHECK: mull a9, a2, a3 +; CHECK: add.n a2, a9, a2 +; CHECK: .LBB0_5 +} + diff --git a/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll b/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll new file mode 100644 index 0000000000000..bed2d7937468d --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll @@ -0,0 +1,38 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s + +; Function Attrs: nounwind optsize +define i32 @test_hwloop(i32 %a, i32 %b, i32 %n) local_unnamed_addr #1 { +; CHECK-LABEL: @test_hwloop +entry: + %cmp7 = icmp sgt i32 %n, 0 + br i1 %cmp7, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.body, %entry + %a.addr.0.lcssa = phi i32 [ %a, %entry ], [ %a.addr.1, %for.body ] + ret i32 %a.addr.0.lcssa + +for.body: ; preds = %entry, %for.body + %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ] + %a.addr.08 = phi i32 [ %a.addr.1, %for.body ], [ %a, %entry ] + tail call void asm sideeffect "", ""() #2, !srcloc !2 + %cmp1 = icmp sgt i32 %a.addr.08, 0 + %mul = mul nsw i32 %a.addr.08, %b + %add = select i1 %cmp1, i32 %mul, i32 0 + %a.addr.1 = add nsw i32 %add, %a.addr.08 + %inc = add nuw nsw i32 %i.09, 1 + %cmp = icmp slt i32 %inc, %n + br i1 %cmp, label %for.body, label %for.cond.cleanup +; CHECK:.LBB0_2: +; CHECK: mov.n a9, a8 +; CHECK:.LBB0_3: +; CHECK: add.n a2, a9, a2 +; CHECK: #APP +; CHECK: #NO_APP +; CHECK: addi.n a4, a4, -1 +; CHECK: beqz a4, .LBB0_6 +; CHECK:.LBB0_4: +; CHECK: bge a8, a2, .LBB0_2 + +} + +!2 = !{i32 216} From f7ec8471e2a696d7448f6ac7f2286438f78f324e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:22 +0300 Subject: [PATCH 069/150] [Xtensa] Change using of Frame Pointer. Do not use Frame Pointer by default. Also improve storing function argument from a7 register to a8 register. Corrected funnel shift test. --- clang/lib/Driver/ToolChains/Clang.cpp | 1 + llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp | 9 ++++++--- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 2 ++ llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h | 4 ++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 3704ed8586682..1f9533dc4a47a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -536,6 +536,7 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, case llvm::Triple::amdgcn: case llvm::Triple::r600: case llvm::Triple::csky: + case llvm::Triple::xtensa: return !areOptimizationsEnabled(Args); default: break; diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index b8c6cadf700d8..5d651c145bb41 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -100,6 +100,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF, unsigned FP = RegInfo->getFrameRegister(MF); MachineModuleInfo &MMI = MF.getMMI(); const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + XtensaFunctionInfo *XtensaFI = MF.getInfo(); // First, compute final stack size. uint64_t StackSize = MFI.getStackSize(); @@ -133,9 +134,11 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF, // Store FP register in A8, because FP may be used to pass function // arguments - BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), Xtensa::A8) - .addReg(FP) - .addReg(FP); + if (XtensaFI->isSaveFrameRegister()) { + BuildMI(MBB, MBBI, dl, TII.get(Xtensa::OR), Xtensa::A8) + .addReg(FP) + .addReg(FP); + } // if framepointer enabled, set it to point to the stack pointer. if (hasFP(MF)) { diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 42c9ff0285c83..6935ceaa53a73 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -793,6 +793,7 @@ SDValue XtensaTargetLowering::LowerFormalArguments( // so load argument from A8 if (Subtarget.isWinABI() && (VA.getLocReg() == FrameReg)) { Reg = MF.addLiveIn(Xtensa::A8, RC); + XtensaFI->setSaveFrameRegister(); } else { Reg = MF.addLiveIn(VA.getLocReg(), RC); } @@ -887,6 +888,7 @@ SDValue XtensaTargetLowering::LowerFormalArguments( // so load argument from A8 if (ArgRegs[I] == FrameReg) { RegInfo.addLiveIn(Xtensa::A8, Reg); + XtensaFI->setSaveFrameRegister(); } else { RegInfo.addLiveIn(ArgRegs[I], Reg); } diff --git a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h index f84d48bb6b761..49adc260856ae 100644 --- a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h @@ -27,6 +27,7 @@ class XtensaFunctionInfo : public MachineFunctionInfo { unsigned VarArgsFirstGPR; int VarArgsStackOffset; unsigned VarArgsFrameIndex; + bool SaveFrameRegister = false; public: explicit XtensaFunctionInfo(MachineFunction &MF) @@ -45,6 +46,9 @@ class XtensaFunctionInfo : public MachineFunctionInfo { unsigned getVarArgsFrameIndex() const { return VarArgsFrameIndex; } void setVarArgsFrameIndex(unsigned FI) { VarArgsFrameIndex = FI; } + bool isSaveFrameRegister() const { return SaveFrameRegister; } + void setSaveFrameRegister() { SaveFrameRegister = true; } + // TODO: large frame size definition should be specified more precisely bool isLargeFrame() { return (MF.getFrameInfo().estimateStackSize(MF) > 512) ? true : false; From 2bedc725a144e53ce3f616da71bbda7923a36a42 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:23 +0300 Subject: [PATCH 070/150] esp/maint: Adds Github workfows --- .github/workflows/issue_comment.yml | 19 +++++++++++++++++++ .github/workflows/new_issues.yml | 19 +++++++++++++++++++ .github/workflows/new_prs.yml | 24 ++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 .github/workflows/issue_comment.yml create mode 100644 .github/workflows/new_issues.yml create mode 100644 .github/workflows/new_prs.yml diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml new file mode 100644 index 0000000000000..b5c80040fc9ff --- /dev/null +++ b/.github/workflows/issue_comment.yml @@ -0,0 +1,19 @@ +name: Sync issue comments to JIRA + +# This workflow will be triggered when new issue comment is created (including PR comments) +on: issue_comment + +jobs: + sync_issue_comments_to_jira: + name: Sync Issue Comments to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync issue comments to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: LLVM + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_issues.yml b/.github/workflows/new_issues.yml new file mode 100644 index 0000000000000..a6602d1c7aa1c --- /dev/null +++ b/.github/workflows/new_issues.yml @@ -0,0 +1,19 @@ +name: Sync issues to Jira + +# This workflow will be triggered when a new issue is opened +on: issues + +jobs: + sync_issues_to_jira: + name: Sync issues to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync GitHub issues to Jira project + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: LLVM + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_prs.yml b/.github/workflows/new_prs.yml new file mode 100644 index 0000000000000..199d58ef87b3f --- /dev/null +++ b/.github/workflows/new_prs.yml @@ -0,0 +1,24 @@ +name: Sync remain PRs to Jira + +# This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project +# Note that, PRs can also get synced when new PR comment is created +on: + schedule: + - cron: "0 * * * *" + +jobs: + sync_prs_to_jira: + name: Sync PRs to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync PRs to Jira project + uses: espressif/github-actions/sync_issues_to_jira@master + with: + cron_job: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: LLVM + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} From 3a18ef7956964b9ac78f7a946aa54c7641518f54 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:48 +0300 Subject: [PATCH 071/150] [Xtensa] Implement esp32 psram cache fixes. --- clang/include/clang/Driver/Options.td | 9 + clang/lib/Driver/ToolChains/Clang.cpp | 32 ++ clang/lib/Driver/ToolChains/Clang.h | 2 + clang/lib/Driver/ToolChains/Xtensa.cpp | 16 + llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + llvm/lib/Target/Xtensa/Xtensa.h | 1 + .../lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp | 353 ++++++++++++++++++ .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 1 + llvm/test/CodeGen/Xtensa/psram_memw.ll | 50 +++ llvm/test/CodeGen/Xtensa/psram_nops.ll | 60 +++ 10 files changed, 525 insertions(+) create mode 100644 llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp create mode 100644 llvm/test/CodeGen/Xtensa/psram_memw.ll create mode 100644 llvm/test/CodeGen/Xtensa/psram_nops.ll diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 3cab37b21aaf3..ab45940c4a2c5 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -184,6 +184,8 @@ def m_x86_Features_Group : OptionGroup<"">, Group, Flags<[CoreOption]>, DocName<"X86">; def m_riscv_Features_Group : OptionGroup<"">, Group, DocName<"RISCV">; +def m_xtensa_Features_Group : OptionGroup<"">, + Group, Flags<[CoreOption]>, DocName<"Xtensa">; def m_libc_Group : OptionGroup<"">, Group, Flags<[HelpHidden]>; @@ -4662,6 +4664,13 @@ def mno_retpoline_external_thunk : Flag<["-"], "mno-retpoline-external-thunk">, def mvzeroupper : Flag<["-"], "mvzeroupper">, Group; def mno_vzeroupper : Flag<["-"], "mno-vzeroupper">, Group; +// Xtensa feature flags +def malways_memw : Flag<["-"], "malways-memw">, Group; +def mfix_esp32_psram_cache_issue : Flag<["-"], "mfix-esp32-psram-cache-issue">, Group; +def mfix_esp32_psram_cache_strategy_EQ : Joined<["-"], "mfix-esp32-psram-cache-strategy=">, Group, + HelpText<" Psram cache fix strategies : memw, nops">, + Values<"memw, nops">; + // These are legacy user-facing driver-level option spellings. They are always // aliases for options that are spelled using the more common Unix / GNU flag // style of double-dash and equals-joined flags. diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 1f9533dc4a47a..a95be47dd5aef 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1845,6 +1845,10 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, case llvm::Triple::ve: AddVETargetArgs(Args, CmdArgs); break; + + case llvm::Triple::xtensa: + AddXtensaTargetArgs(Args, CmdArgs); + break; } } @@ -2395,6 +2399,34 @@ void Clang::AddVETargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("hard"); } +void Clang::AddXtensaTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + + if (Args.getLastArg(options::OPT_malways_memw) != nullptr) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-malways-memw"); + } + + if (Args.getLastArg(options::OPT_mfix_esp32_psram_cache_issue) != nullptr) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mfix-esp32-psram-cache-issue"); + + if (Arg *A = + Args.getLastArg(options::OPT_mfix_esp32_psram_cache_strategy_EQ)) { + StringRef Value = A->getValue(); + if (Value == "memw" || Value == "nops") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString("-mfix-esp32-psram-cache-strategy=" + Value)); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + } +} + void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, StringRef Target, const InputInfo &Output, const InputInfo &Input, const ArgList &Args) const { diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 5209c6687599b..4d73bed0c6c75 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -79,6 +79,8 @@ class LLVM_LIBRARY_VISIBILITY Clang : public Tool { llvm::opt::ArgStringList &CmdArgs) const; void AddVETargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddXtensaTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index a1f83801b5610..c3919ff8c8e93 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -107,16 +107,32 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, IsIntegratedAsm = false; } + bool IsESP32 = XtensaToolChain::GetTargetCPUVersion(Args).equals("esp32"); Multilibs.push_back(Multilib()); + if (IsESP32) + Multilibs.push_back(Multilib("esp32-psram", {}, {}, 2) + .flag("+mfix-esp32-psram-cache-issue")); Multilibs.push_back( Multilib("no-rtti", {}, {}, 1).flag("+fno-rtti").flag("-frtti")); + if (IsESP32) + Multilibs.push_back(Multilib("esp32-psram/no-rtti", {}, {}, 3) + .flag("+fno-rtti") + .flag("-frtti") + .flag("+mfix-esp32-psram-cache-issue")); + Multilib::flags_list Flags; addMultilibFlag( Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, false), "frtti", Flags); + if (IsESP32) + addMultilibFlag(Args.hasFlag(options::OPT_mfix_esp32_psram_cache_issue, + options::OPT_mfix_esp32_psram_cache_issue, + false), + "mfix-esp32-psram-cache-issue", Flags); + Multilibs.select(Flags, SelectedMultilib); const std::string Slash = XtensaGCCToolchain.Slash; diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 6b035e8cb41df..fccdde013bbc9 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -17,6 +17,7 @@ add_public_tablegen_target(XtensaCommonTableGen) add_llvm_target(XtensaCodeGen XtensaAsmPrinter.cpp XtensaConstantPoolValue.cpp + XtensaESP32PSRAMFix.cpp XtensaFixupHWLoops.cpp XtensaFrameLowering.cpp XtensaHardwareLoops.cpp diff --git a/llvm/lib/Target/Xtensa/Xtensa.h b/llvm/lib/Target/Xtensa/Xtensa.h index 2966e085634fb..f9b06c6e79fa5 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.h +++ b/llvm/lib/Target/Xtensa/Xtensa.h @@ -29,5 +29,6 @@ FunctionPass *createXtensaISelDag(XtensaTargetMachine &TM, FunctionPass *createXtensaSizeReductionPass(); FunctionPass *createXtensaHardwareLoops(); FunctionPass *createXtensaFixupHwLoops(); +FunctionPass *createXtensaPSRAMCacheFixPass(); } // namespace llvm #endif /* LLVM_LIB_TARGET_XTENSA_XTENSA_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp b/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp new file mode 100644 index 0000000000000..5f22c2ea0e20c --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp @@ -0,0 +1,353 @@ +//===- XtensaPSRAMFIx.cpp - Fixup PSRAM Cache issues --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "XtensaInstrInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen//MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-fix-esp32-psram-cache-pass" + +enum PSRAMFixChoice { + ESP32_PSRAM_FIX_MEMW, + ESP32_PSRAM_FIX_NOPS +}; + +static cl::opt AlwaysMembarrier("malways-memw", cl::init(false), + cl::Hidden); + +static cl::opt FixESP32PSRAMCacheIssue("mfix-esp32-psram-cache-issue", + cl::init(false), cl::Hidden); + +static cl::opt ESP32PSRAMFixStrat( + "mfix-esp32-psram-cache-strategy", cl::init(ESP32_PSRAM_FIX_MEMW), + cl::desc(""), + cl::values(clEnumValN(ESP32_PSRAM_FIX_MEMW, "memw", ""), + clEnumValN(ESP32_PSRAM_FIX_NOPS, "nops", ""))); + +STATISTIC(NumAdded, "Number of instructions added"); + +class createXtensaPSRAMCacheFix : public MachineFunctionPass { +public: + static char ID; + createXtensaPSRAMCacheFix() : MachineFunctionPass(ID) {} + + const XtensaSubtarget *Subtarget; + static const XtensaInstrInfo *XtensaII; + + bool runOnMachineFunction(MachineFunction &MF) override; + + llvm::StringRef getPassName() const override { + return "Xtensa fix PSRAM cache issue in the ESP32 chips"; + } + +private: + bool xtensaPSRAMCacheFixNopReorg(MachineFunction &MF); + /* + Alternative fix to xtensaPSRAMCacheFixNopReorg. Tries to solve the 32-bit + load/store inversion by explicitly inserting a memory barrier instead of nops. + Slower than nops, but faster than just adding memws everywhere. + */ + bool xtensaPSRAMCacheFixMemwReorg(MachineFunction &MF); + // Emits a memw before every load/store instruction. Hard-handed approach to + // get rid of any pipeline/memory issues... + bool xtensaInsertMemwReorg(MachineFunction &MF); +}; + +char createXtensaPSRAMCacheFix::ID = 0; +const XtensaInstrInfo *createXtensaPSRAMCacheFix::XtensaII; + +// Affected piece of pipeline is 5 entries long; the load/store itself fills +// one. +#define LOAD_STORE_OFF 4 + +bool createXtensaPSRAMCacheFix::xtensaPSRAMCacheFixNopReorg( + MachineFunction &MF) { + MachineFunction::iterator I = MF.begin(), E = MF.end(); + MachineInstr *LastHIQIStore = nullptr; + MachineInstr *StoreInsn = nullptr; + int InsnsSinceStore = 0; + bool Modified = false; + + for (; I != E; ++I) { + MachineBasicBlock &MBB = *I; + MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), + MIE = MBB.instr_end(); + MachineBasicBlock::instr_iterator NextMII; + + // Iterate through the instructions in the basic block + for (; MII != MIE; MII = NextMII) { + MachineInstr *MI = &*MII; + unsigned Opcode = MI->getOpcode(); + NextMII = std::next(MII); + + if (MI->isCall() || MI->isBranch() || MI->isReturn()) { + if (LastHIQIStore) { + DebugLoc dl = LastHIQIStore->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(*LastHIQIStore->getParent(), LastHIQIStore, dl, NewMCID); + LastHIQIStore = nullptr; + Modified = true; + NumAdded++; + } + if (!(MI->isBranch() && (MI->getOpcode() != Xtensa::J) && + (MI->getOpcode() != Xtensa::JX))) { + StoreInsn = nullptr; + } + continue; + } + + switch (Opcode) { + case Xtensa::LSI: + case Xtensa::L32I_N: + case Xtensa::L32I: + case Xtensa::L16SI: + case Xtensa::L16UI: + case Xtensa::L8UI: + if (StoreInsn) { + while (InsnsSinceStore++ < LOAD_STORE_OFF) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::NOP); + BuildMI(MBB, MII, dl, NewMCID); + Modified = true; + NumAdded++; + } + } + if (LastHIQIStore) { + DebugLoc dl = LastHIQIStore->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(*LastHIQIStore->getParent(), + std::next(LastHIQIStore->getIterator()), dl, NewMCID); + LastHIQIStore = nullptr; + Modified = true; + NumAdded++; + } + break; + case Xtensa::SSI: + case Xtensa::S32I_N: + case Xtensa::S32I: { + LastHIQIStore = nullptr; + InsnsSinceStore = 0; + StoreInsn = MI; + } break; + case Xtensa::S16I: + case Xtensa::S8I: { + LastHIQIStore = MI; + InsnsSinceStore = 0; + StoreInsn = MI; + } break; + default: + InsnsSinceStore++; + break; + } + } + } + return Modified; +} + +bool createXtensaPSRAMCacheFix::xtensaPSRAMCacheFixMemwReorg( + MachineFunction &MF) { + MachineFunction::iterator I = MF.begin(), E = MF.end(); + MachineInstr *LastHIQIStore = nullptr; + MachineInstr *StoreInsn = nullptr; + bool Modified = false; + + for (; I != E; ++I) { + MachineBasicBlock &MBB = *I; + + MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), + MIE = MBB.instr_end(); + MachineBasicBlock::instr_iterator NextMII; + + // Iterate through the instructions in the basic block + for (; MII != MIE; MII = NextMII) { + NextMII = std::next(MII); + MachineInstr *MI = &*MII; + unsigned Opcode = MI->getOpcode(); + + // Don't process bundled instructions or pseudo operations + if (MI->isBundle() || MI->isTransient()) + continue; + + if (MI->isCall() || MI->isBranch() || MI->isReturn()) { + if (StoreInsn) { + if (!(MI->isBranch() && (MI->getOpcode() != Xtensa::J) && + (MI->getOpcode() != Xtensa::JX))) { + DebugLoc dl = MI->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + MachineBasicBlock::instr_iterator BranchI = MI->getIterator(); + while (((*BranchI).isBranch() || (*BranchI).isCall() || + (*BranchI).isReturn()) && + (BranchI != MBB.instr_begin())) + BranchI = std::prev(BranchI); + + if (BranchI != MBB.instr_begin()) + BranchI = std::next(BranchI); + + BuildMI(MBB, BranchI, dl, NewMCID); + Modified = true; + StoreInsn = nullptr; + NumAdded++; + } + } + if (LastHIQIStore) { + DebugLoc dl = LastHIQIStore->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(*LastHIQIStore->getParent(), + std::next(LastHIQIStore->getIterator()), dl, NewMCID); + LastHIQIStore = nullptr; + Modified = true; + NumAdded++; + } + continue; + } + + switch (Opcode) { + case Xtensa::LSI: + case Xtensa::L32I_N: + case Xtensa::L32I: + case Xtensa::L16SI: + case Xtensa::L16UI: + case Xtensa::L8UI: + if (StoreInsn) { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile()) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(MBB, MII, dl, NewMCID); + Modified = true; + StoreInsn = nullptr; + NumAdded++; + } + } + if (LastHIQIStore) { + DebugLoc dl = LastHIQIStore->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(*LastHIQIStore->getParent(), + std::next(LastHIQIStore->getIterator()), dl, NewMCID); + LastHIQIStore = nullptr; + Modified = true; + NumAdded++; + } + break; + case Xtensa::SSI: + case Xtensa::S32I_N: + case Xtensa::S32I: { + LastHIQIStore = nullptr; + StoreInsn = MI; + } break; + case Xtensa::S16I: + case Xtensa::S8I: { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile()) { + LastHIQIStore = MI; + } + StoreInsn = MI; + } break; + } + } + } + return Modified; +} + +bool createXtensaPSRAMCacheFix::xtensaInsertMemwReorg(MachineFunction &MF) { + MachineFunction::iterator I = MF.begin(), E = MF.end(); + bool Modified = false; + bool HadMemw = false; + + for (; I != E; ++I) { + MachineBasicBlock &MBB = *I; + + MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), + MIE = MBB.instr_end(); + MachineBasicBlock::instr_iterator NextMII; + + // Iterate through the instructions in the basic block + for (; MII != MIE; MII = NextMII) { + NextMII = std::next(MII); + MachineInstr *MI = &*MII; + unsigned Opcode = MI->getOpcode(); + + // Don't process bundled instructions or pseudo operations + if (MI->isBundle() || MI->isTransient()) + continue; + + switch (Opcode) { + case Xtensa::LSI: + case Xtensa::L32I_N: + case Xtensa::L32I: + case Xtensa::L16SI: + case Xtensa::L16UI: + case Xtensa::L8UI: { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile() && (!HadMemw)) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(MBB, MII, dl, NewMCID); + Modified = true; + NumAdded++; + } + HadMemw = false; + } break; + case Xtensa::SSI: + case Xtensa::S32I_N: + case Xtensa::S32I: + case Xtensa::S16I: + case Xtensa::S8I: { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile()) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(MBB, NextMII, dl, NewMCID); + Modified = true; + NumAdded++; + } + HadMemw = true; + } break; + default: + HadMemw = false; + break; + } + } + } + return Modified; +} + +bool createXtensaPSRAMCacheFix::runOnMachineFunction(MachineFunction &MF) { + + Subtarget = &static_cast(MF.getSubtarget()); + XtensaII = static_cast(Subtarget->getInstrInfo()); + bool Modified = false; + + if (AlwaysMembarrier) + return xtensaInsertMemwReorg(MF); + + if (!FixESP32PSRAMCacheIssue) + return false; + + if (ESP32PSRAMFixStrat == ESP32_PSRAM_FIX_MEMW) { + Modified = xtensaPSRAMCacheFixMemwReorg(MF); + } else if (ESP32PSRAMFixStrat == ESP32_PSRAM_FIX_NOPS) { + Modified = xtensaPSRAMCacheFixNopReorg(MF); + } + + return Modified; +} + +FunctionPass *llvm::createXtensaPSRAMCacheFixPass() { + return new createXtensaPSRAMCacheFix(); +} + diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index 8aea549304b93..b8448e1401122 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -121,6 +121,7 @@ void XtensaPassConfig::addPreRegAlloc() { } void XtensaPassConfig::addPreEmitPass() { + addPass(createXtensaPSRAMCacheFixPass()); addPass(createXtensaSizeReductionPass()); addPass(createXtensaFixupHwLoops()); addPass(&BranchRelaxationPassID); diff --git a/llvm/test/CodeGen/Xtensa/psram_memw.ll b/llvm/test/CodeGen/Xtensa/psram_memw.ll new file mode 100644 index 0000000000000..f10417ec779e6 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/psram_memw.ll @@ -0,0 +1,50 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw %s -o - | FileCheck %s + +@a = dso_local local_unnamed_addr global i32 0, align 4 +@b = dso_local local_unnamed_addr global i32 0, align 4 + +; Function Attrs: nofree norecurse nounwind +define dso_local void @f(i32 %a1.coerce, i32 %a2.coerce, i32 %a3.coerce, i32 %a4.coerce, i32 %cond) local_unnamed_addr #0 { +entry: + %coerce.val.ip = inttoptr i32 %a1.coerce to i8* + %coerce.val.ip1 = inttoptr i32 %a2.coerce to i16* + %coerce.val.ip2 = inttoptr i32 %a3.coerce to i32* + %coerce.val.ip3 = inttoptr i32 %a4.coerce to i32* + %0 = load i32, i32* %coerce.val.ip2, align 4 + %conv = trunc i32 %0 to i8 + store i8 %conv, i8* %coerce.val.ip, align 1 + %tobool.not = icmp eq i32 %cond, 0 + br i1 %tobool.not, label %if.end, label %if.then +; CHECK: s8i a8, a2, 0 +; CHECK: memw + +if.then: ; preds = %entry + %1 = load i32, i32* %coerce.val.ip2, align 4 + %conv8 = trunc i32 %1 to i16 + store i16 %conv8, i16* %coerce.val.ip1, align 2 + %2 = load i32, i32* %coerce.val.ip3, align 4 + store i32 %2, i32* %coerce.val.ip2, align 4 + %conv10 = trunc i32 %2 to i8 + store i8 %conv10, i8* %coerce.val.ip, align 1 + br label %return +; CHECK: l32i.n a8, a4, 0 +; CHECK: s16i a8, a3, 0 +; CHECK: memw +; CHECK: memw +; CHECK: l32i.n a8, a5, 0 +; CHECK: s32i.n a8, a4, 0 +; CHECK: s8i a8, a2, 0 +; CHECK: memw + +if.end: ; preds = %entry + %3 = load i32, i32* %coerce.val.ip3, align 4 + %conv9 = trunc i32 %3 to i16 + store i16 %conv9, i16* %coerce.val.ip1, align 2 + br label %return +; CHECK: l32i.n a8, a5, 0 +; CHECK: s16i a8, a3, 0 +; CHECK: memw + +return: ; preds = %if.then, %if.end + ret void +} diff --git a/llvm/test/CodeGen/Xtensa/psram_nops.ll b/llvm/test/CodeGen/Xtensa/psram_nops.ll new file mode 100644 index 0000000000000..ece7d6f6432c4 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/psram_nops.ll @@ -0,0 +1,60 @@ +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=nops %s -o - | FileCheck %s + +@a = dso_local local_unnamed_addr global i32 0, align 4 +@b = dso_local local_unnamed_addr global i32 0, align 4 + +; Function Attrs: nofree norecurse nounwind +define dso_local void @f(i32 %a1.coerce, i32 %a2.coerce, i32 %a3.coerce, i32 %a4.coerce, i32 %cond) local_unnamed_addr #0 { +entry: + %coerce.val.ip = inttoptr i32 %a1.coerce to i8* + %coerce.val.ip1 = inttoptr i32 %a2.coerce to i16* + %coerce.val.ip2 = inttoptr i32 %a3.coerce to i32* + %coerce.val.ip3 = inttoptr i32 %a4.coerce to i32* + %0 = load i32, i32* %coerce.val.ip2, align 4 + %conv = trunc i32 %0 to i8 + store i8 %conv, i8* %coerce.val.ip, align 1 + %tobool.not = icmp eq i32 %cond, 0 + br i1 %tobool.not, label %if.end, label %if.then +; CHECK: l32i.n a8, a4, 0 +; CHECK: memw +; CHECK: s8i a8, a2, 0 + + +if.then: ; preds = %entry + %1 = load i32, i32* %coerce.val.ip2, align 4 + %conv8 = trunc i32 %1 to i16 + store i16 %conv8, i16* %coerce.val.ip1, align 2 + %2 = load i32, i32* %coerce.val.ip3, align 4 + store i32 %2, i32* %coerce.val.ip2, align 4 + %conv10 = trunc i32 %2 to i8 + store i8 %conv10, i8* %coerce.val.ip, align 1 + br label %return +; CHECK: nop +; CHECK: nop +; CHECK: nop +; CHECK: nop +; CHECK: l32i.n a8, a4, 0 +; CHECK: s16i a8, a3, 0 +; CHECK: memw +; CHECK: nop +; CHECK: nop +; CHECK: nop +; CHECK: nop +; CHECK: l32i.n a8, a5, 0 +; CHECK: s32i.n a8, a4, 0 +; CHECK: memw +; CHECK: s8i a8, a2, 0 + +if.end: ; preds = %entry + %3 = load i32, i32* %coerce.val.ip3, align 4 + %conv9 = trunc i32 %3 to i16 + store i16 %conv9, i16* %coerce.val.ip1, align 2 + br label %return +; CHECK: l32i.n a8, a5, 0 +; CHECK: memw +; CHECK: s16i a8, a3, 0 + + +return: ; preds = %if.then, %if.end + ret void +} From 38e38ed74a298fd626dd1ebd1688b5c1fed74c64 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:48 +0300 Subject: [PATCH 072/150] [Xtensa] Fix Hardware Loop optimization --- .../lib/Target/Xtensa/XtensaHardwareLoops.cpp | 133 ++++++++++++------ llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 1 - 2 files changed, 93 insertions(+), 41 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp index f31d724ebb8f1..a1a2432ded4c1 100644 --- a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp +++ b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp @@ -194,8 +194,10 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { MachineInstr *LII = nullptr; // LOOPINIT instruction MachineInstr *LEI = nullptr; // LOOPEND instruction MachineBasicBlock *LEMBB = nullptr; - MachineBasicBlock *PH = L->getLoopPreheader(); + MachineBasicBlock *LH = L->getHeader(); MachineBasicBlock *LastMBB = L->getLoopLatch(); + std::vector LoopInitInsts; + std::map LoopInitMap; // Try to find LOOPEND instruction in the loop latch for (auto MBI = L->block_begin(), MBIE = L->block_end(); MBI != MBIE; ++MBI) { @@ -207,40 +209,56 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { LEI = LMI; LEMBB = *MBI; } + // Collect LOOPINIT instructions inside the loop + if (LMI->getOpcode() == Xtensa::LOOPINIT) { + LoopInitInsts.push_back(LMI); + MachineBasicBlock *SB = LMI->getParent(); + while (!SB->isSuccessor(LH)) { + for (auto SBI : SB->successors()) { + if (!L->contains(SBI)) + continue; + SB = SBI; + break; + } + if (!L->contains(SB)) + llvm_unreachable("Wrong hardware loop"); + } + LoopInitMap[SB] = LMI; + } } VisitedMBBs.insert(*MBI); } if (LEI != nullptr) { - MachineBasicBlock *LH = L->getHeader(); MachineBasicBlock::iterator LHI = LH->getFirstNonPHI(); - - if (!PH) { - llvm_unreachable("Hardware loop predecessor not found"); - return false; - } - - MachineBasicBlock *LIMBB = PH; - - // Try to find LOOPINIT instruction in predecessors chain - while ((LII == nullptr) && (LIMBB != nullptr) && - ((L->getParentLoop() == nullptr) || - (L->getParentLoop()->contains(LIMBB)))) { - for (instr_iterator I = LIMBB->instr_begin(), E = LIMBB->instr_end(); - I != E; ++I) { - MachineInstr *MI = &*I; - if (MI->getOpcode() == Xtensa::LOOPINIT) { - LII = MI; - break; + MachineBasicBlock *LIMBB = nullptr; + + // Collect LOOPINIT instructions in predecessors from outter loop + for (auto PBI : LH->predecessors()) { + if (L->contains(PBI)) + continue; + LIMBB = PBI; + LII = nullptr; + // Try to find LOOPINIT instructions in predecessor + while ((LII == nullptr) && (LIMBB != nullptr) && + ((L->getParentLoop() == nullptr) || + (L->getParentLoop()->contains(LIMBB)))) { + for (instr_iterator I = LIMBB->instr_begin(), E = LIMBB->instr_end(); + I != E; ++I) { + MachineInstr *MI = &*I; + if (MI->getOpcode() == Xtensa::LOOPINIT) { + LII = MI; + break; + } } + if (LII == nullptr) + LIMBB = *LIMBB->pred_begin(); } - if (LII == nullptr) - LIMBB = *LIMBB->pred_begin(); - } - - if (LII == nullptr) { - llvm_unreachable("Hardware loop init instruction not found"); - return false; + if (LII == nullptr) { + llvm_unreachable("Hardware loop init instruction not found"); + return false; + } + LoopInitMap[PBI] = LII; } DebugLoc DL = LII->getDebugLoc(); @@ -250,22 +268,30 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { // sub a, a, 1 // bnez a, LH if (!checkLoopSize(L) || containsInvalidInstruction(L) || - (LEMBB != LastMBB) || (!checkLoopEndDisplacement(*LH->getParent(), LH, LEMBB))) { + (LEMBB != LastMBB) || + (!checkLoopEndDisplacement(*LH->getParent(), LH, LEMBB))) { const MCInstrDesc &PD = TII->get(TargetOpcode::PHI); MachineInstr *NewPN = LH->getParent()->CreateMachineInstr(PD, DL); LH->insert(LH->begin(), NewPN); Register PR = MRI->createVirtualRegister(&Xtensa::ARRegClass); NewPN->addOperand(MachineOperand::CreateReg(PR, true)); - MachineOperand MO = - MachineOperand::CreateReg(LII->getOperand(0).getReg(), false); - NewPN->addOperand(MO); - NewPN->addOperand(MachineOperand::CreateMBB(PH)); - Register IndR = MRI->createVirtualRegister(&Xtensa::ARRegClass); - MO = MachineOperand::CreateReg(IndR, false); - NewPN->addOperand(MO); - NewPN->addOperand(MachineOperand::CreateMBB(LastMBB)); + + for (auto PB : LH->predecessors()) { + + if (LoopInitMap.find(PB) != LoopInitMap.end()) { + MachineOperand MO = MachineOperand::CreateReg( + LoopInitMap[PB]->getOperand(0).getReg(), false); + NewPN->addOperand(MO); + NewPN->addOperand(MachineOperand::CreateMBB(PB)); + LoopInitMap[PB]->getParent()->erase(LoopInitMap[PB]); + } else { + MachineOperand MO = MachineOperand::CreateReg(IndR, false); + NewPN->addOperand(MO); + NewPN->addOperand(MachineOperand::CreateMBB(PB)); + } + } MachineInstrBuilder MIB = BuildMI(*LEMBB, LEI, LEI->getDebugLoc(), TII->get(Xtensa::ADDI), IndR) @@ -276,15 +302,42 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { .addReg(IndR) .addMBB(LEI->getOperand(0).getMBB()); LEMBB->erase(LEI); - PH->erase(LII); return false; } - //Place LOOPSTART instruction in loop header + // If several LOOPINIT instructions are dicovered then create PHI + // function + if (LoopInitMap.size() > 1) { + const MCInstrDesc &PD = TII->get(TargetOpcode::PHI); + MachineInstr *NewPN = LH->getParent()->CreateMachineInstr(PD, DL); + LH->insert(LH->begin(), NewPN); + Register PR = MRI->createVirtualRegister(&Xtensa::ARRegClass); + NewPN->addOperand(MachineOperand::CreateReg(PR, true)); + + for (auto PB : LH->predecessors()) { + + if (LoopInitMap.find(PB) != LoopInitMap.end()) { + MachineOperand MO = MachineOperand::CreateReg( + LoopInitMap[PB]->getOperand(0).getReg(), false); + NewPN->addOperand(MO); + NewPN->addOperand(MachineOperand::CreateMBB(PB)); + LoopInitMap[PB]->getParent()->erase(LoopInitMap[PB]); + } else { + MachineOperand MO = MachineOperand::CreateReg(PR, false); + NewPN->addOperand(MO); + NewPN->addOperand(MachineOperand::CreateMBB(PB)); + } + } + LII = NewPN; + } + BuildMI(*LH, LHI, DL, TII->get(Xtensa::LOOPSTART)) .addReg(LII->getOperand(0).getReg()) - .addMBB(LastMBB); - PH->erase(LII); + .addMBB(LEMBB); + + if (LII->getOpcode() == Xtensa::LOOPINIT) + LII->getParent()->erase(LII); + return true; } diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index a4f765c411637..b67b2343493d4 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -318,7 +318,6 @@ bool XtensaInstrInfo::isBranchOffsetInRange(unsigned BranchOp, return true; case Xtensa::LOOPEND: BrOffset += 4; - BrOffset += 3 * 3; // 2*NOP + LOOP instrucions assert((BrOffset <= 0) && "Wrong hardware loop"); return true; case Xtensa::BR_JT: From 901e26a3c434c35a47ea6d48b7c88fe551f017a1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:48 +0300 Subject: [PATCH 073/150] [Xtensa] Remove unnecessary MOVSP in epilogue. --- llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index 5d651c145bb41..6b4b43ee38729 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -247,8 +247,13 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, for (unsigned i = 0; i < MFI.getCalleeSavedInfo().size(); ++i) --I; if (STI.isWinABI()) { - // Insert instruction "movsp $sp, $fp" at this location. - BuildMI(MBB, I, dl, TII.get(Xtensa::MOVSP), SP).addReg(FP); + // In most architectures, we need to explicitly restore the stack pointer + // before returning. + // + // For Xtensa Windowed Register option, it is not needed to explicitly + // restore the stack pointer. Reason being is that on function return, + // the window of the caller (including the old stack pointer) gets + // restored anyways. } else { BuildMI(MBB, I, dl, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP); } From 6f0c454ed194fa4ad371ffcb8484e9804756ec15 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:49 +0300 Subject: [PATCH 074/150] [Xtensa] Support 'f' Inline Assembly Constraint This adds the 'f' inline assembly constraint, as supported by GCC. An 'f'-constrained operand is passed in a floating point register. This patch adds support in both the clang frontend, and LLVM itself. --- clang/lib/Basic/Targets/Xtensa.h | 1 + clang/test/CodeGen/xtensa-inline-asm.c | 13 +++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 13 ++++++++++- .../CodeGen/Xtensa/inline-asm-constraints.ll | 23 +++++++++++++++++++ .../test/CodeGen/Xtensa/inline-asm-invalid.ll | 8 +++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/xtensa-inline-asm.c create mode 100644 llvm/test/CodeGen/Xtensa/inline-asm-constraints.ll create mode 100644 llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index 981edf5cb2809..0c077dda2d979 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -82,6 +82,7 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { default: return false; case 'a': + case 'f': Info.setAllowsRegister(); return true; } diff --git a/clang/test/CodeGen/xtensa-inline-asm.c b/clang/test/CodeGen/xtensa-inline-asm.c new file mode 100644 index 0000000000000..9c7473eb98359 --- /dev/null +++ b/clang/test/CodeGen/xtensa-inline-asm.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -no-opaque-pointers -triple xtensa -O1 -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +// Test Xtensa specific inline assembly constraints. + +float f; +void test_f() { +// CHECK-LABEL: define dso_local void @test_f() local_unnamed_addr #0 { +// CHECK: [[FLT_ARG:%[a-zA-Z_0-9]+]] = load float, float* @f +// CHECK: call void asm sideeffect "", "f"(float [[FLT_ARG]]) + asm volatile ("" :: "f"(f)); +} + diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 6935ceaa53a73..e3938bb290911 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -391,6 +391,7 @@ XtensaTargetLowering::getConstraintType(StringRef Constraint) const { switch (Constraint[0]) { case 'a': case 'd': + case 'f': case 'r': return C_RegisterClass; @@ -411,6 +412,8 @@ XtensaTargetLowering::getSingleConstraintMatchWeight( if (CallOperandVal == NULL) return CW_Default; + Type *type = CallOperandVal->getType(); + // Look at the constraint type. switch (*constraint) { default: @@ -420,9 +423,14 @@ XtensaTargetLowering::getSingleConstraintMatchWeight( case 'a': case 'd': case 'r': - if (CallOperandVal->getType()->isIntegerTy()) + if (type->isIntegerTy()) + weight = CW_Register; + break; + case 'f': + if (type->isFloatingPointTy()) weight = CW_Register; break; + } return weight; } @@ -439,6 +447,9 @@ XtensaTargetLowering::getRegForInlineAsmConstraint( case 'd': // Data register (equivalent to 'r') case 'r': // General-purpose register return std::make_pair(0U, &Xtensa::ARRegClass); + case 'f': // Floating-point register + if (Subtarget.hasSingleFloat()) + return std::make_pair(0U, &Xtensa::FPRRegClass); } } return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); diff --git a/llvm/test/CodeGen/Xtensa/inline-asm-constraints.ll b/llvm/test/CodeGen/Xtensa/inline-asm-constraints.ll new file mode 100644 index 0000000000000..7dbb0f07debda --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/inline-asm-constraints.ll @@ -0,0 +1,23 @@ +; RUN: llc -mtriple=xtensa -mcpu=esp32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=Xtensa %s + + +@gf = external global float + +define float @constraint_f_float(float %a) nounwind { +; Xtensa-LABEL: constraint_f_float: +; Xtensa: # %bb.0: +; Xtensa-NEXT: entry a1, 32 +; Xtensa-NEXT: wfr f8, a2 +; Xtensa-NEXT: l32r a8, .LCPI0_0 +; Xtensa-NEXT: lsi f9, a8, 0 +; Xtensa-NEXT: #APP +; Xtensa-NEXT: add.s f8, f8, f9 +; Xtensa-NEXT: #NO_APP +; Xtensa-NEXT: rfr a2, f8 +; Xtensa-NEXT: retw + %1 = load float, float* @gf + %2 = tail call float asm "add.s $0, $1, $2", "=f,f,f"(float %a, float %1) + ret float %2 +} + diff --git a/llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll b/llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll new file mode 100644 index 0000000000000..260429d933446 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/inline-asm-invalid.ll @@ -0,0 +1,8 @@ +; RUN: not llc -mtriple=xtensa -mcpu=generic < %s 2>&1 | FileCheck %s + +define void @constraint_f() nounwind { +; CHECK: error: couldn't allocate input reg for constraint 'f' + tail call void asm "add.s f0, f1, $0", "f"(float 0.0) + ret void +} + From f85a0aee470ac892cb0701cb194c0da0ecd00ab3 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:49 +0300 Subject: [PATCH 075/150] [Xtensa] Correction of the PSRAM fix pass --- .../lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp | 58 +++++++++++-------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp b/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp index 5f22c2ea0e20c..0c4433ed00122 100644 --- a/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp +++ b/llvm/lib/Target/Xtensa/XtensaESP32PSRAMFix.cpp @@ -223,14 +223,16 @@ bool createXtensaPSRAMCacheFix::xtensaPSRAMCacheFixMemwReorg( case Xtensa::L16UI: case Xtensa::L8UI: if (StoreInsn) { - MachineMemOperand *MMO = *MII->memoperands_begin(); - if (!MMO->isVolatile()) { - DebugLoc dl = MII->getDebugLoc(); - const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); - BuildMI(MBB, MII, dl, NewMCID); - Modified = true; - StoreInsn = nullptr; - NumAdded++; + if (!MII->memoperands_empty()) { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile()) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(MBB, MII, dl, NewMCID); + Modified = true; + StoreInsn = nullptr; + NumAdded++; + } } } if (LastHIQIStore) { @@ -251,9 +253,11 @@ bool createXtensaPSRAMCacheFix::xtensaPSRAMCacheFixMemwReorg( } break; case Xtensa::S16I: case Xtensa::S8I: { - MachineMemOperand *MMO = *MII->memoperands_begin(); - if (!MMO->isVolatile()) { - LastHIQIStore = MI; + if (!MII->memoperands_empty()) { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile()) { + LastHIQIStore = MI; + } } StoreInsn = MI; } break; @@ -292,13 +296,15 @@ bool createXtensaPSRAMCacheFix::xtensaInsertMemwReorg(MachineFunction &MF) { case Xtensa::L16SI: case Xtensa::L16UI: case Xtensa::L8UI: { - MachineMemOperand *MMO = *MII->memoperands_begin(); - if (!MMO->isVolatile() && (!HadMemw)) { - DebugLoc dl = MII->getDebugLoc(); - const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); - BuildMI(MBB, MII, dl, NewMCID); - Modified = true; - NumAdded++; + if (!MII->memoperands_empty()) { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile() && (!HadMemw)) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(MBB, MII, dl, NewMCID); + Modified = true; + NumAdded++; + } } HadMemw = false; } break; @@ -307,13 +313,15 @@ bool createXtensaPSRAMCacheFix::xtensaInsertMemwReorg(MachineFunction &MF) { case Xtensa::S32I: case Xtensa::S16I: case Xtensa::S8I: { - MachineMemOperand *MMO = *MII->memoperands_begin(); - if (!MMO->isVolatile()) { - DebugLoc dl = MII->getDebugLoc(); - const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); - BuildMI(MBB, NextMII, dl, NewMCID); - Modified = true; - NumAdded++; + if (!MII->memoperands_empty()) { + MachineMemOperand *MMO = *MII->memoperands_begin(); + if (!MMO->isVolatile()) { + DebugLoc dl = MII->getDebugLoc(); + const MCInstrDesc &NewMCID = XtensaII->get(Xtensa::MEMW); + BuildMI(MBB, NextMII, dl, NewMCID); + Modified = true; + NumAdded++; + } } HadMemw = true; } break; From 1f7f3ecccb1d5652793a665224856daddf9a42ac Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:50 +0300 Subject: [PATCH 076/150] [Xtensa] Correction of the hardware loop instrinsics detection. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index e3938bb290911..96f0e61043c1c 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -280,6 +280,9 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setTargetDAGCombine(ISD::FADD); setTargetDAGCombine(ISD::FSUB); + } + + if (Subtarget.hasSingleFloat() || Subtarget.hasLoop()) { setTargetDAGCombine(ISD::BRCOND); } From bac7c45628c7ddc0aa2f763a27d3023a848e1e30 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:50 +0300 Subject: [PATCH 077/150] [Xtensa] Correction of the ESP32-S2 target. The ESP32-S2 chip includes Xtensa ISA extension which helps to work with GPIO, so we add instructions description and test. Add MEMCTL feature to ESP32-S2 target. Implement Xtensa illegal instructions with tests. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 5 ++ .../Disassembler/XtensaDisassembler.cpp | 8 +++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 11 ++++ .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 1 + .../MCTargetDesc/XtensaMCCodeEmitter.cpp | 17 ++++++ llvm/lib/Target/Xtensa/Xtensa.td | 9 ++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 55 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaOperands.td | 7 +++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 5 ++ llvm/test/MC/Xtensa/xtensa-esp32s2-valid.s | 21 +++++++ llvm/test/MC/Xtensa/xtensa-valid-density.s | 9 +++ llvm/test/MC/Xtensa/xtensa-valid.s | 4 ++ 13 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-esp32s2-valid.s create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-density.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index dfdb351e7c34b..19bff501e8293 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -350,6 +350,8 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isseimm7_22() const { return isImm(7, 22); } + bool isSelect_256() const { return isImm(0, 255); } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -621,6 +623,9 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_Invalidseimm7_22: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [7, 22]"); + case Match_InvalidSelect_256: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 255]"); } report_fatal_error("Unknown match type detected!"); diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index 4bf83b328fb75..cdd871b2a3c07 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -568,6 +568,14 @@ static DecodeStatus decodeSeimm7_22Operand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeSelect_256Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + static int64_t TableB4const[16] = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256}; static DecodeStatus decodeB4constOperand(MCInst &Inst, uint64_t Imm, diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index 90ac7f6a30e1c..65da1ec845f07 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -437,3 +437,14 @@ void XtensaInstPrinter::printSeimm7_22_AsmOperand(const MCInst *MI, int OpNum, } else printOperand(MI, OpNum, O); } + +void XtensaInstPrinter::printSelect_256_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 255) && + "Invalid argument, value must be in range [0,255]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index 73fb032414116..b1c6b063aa000 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -73,6 +73,7 @@ class XtensaInstPrinter : public MCInstPrinter { void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printSeimm7_22_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printSelect_256_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index 96194d4e4aa7b..35a016eff25cd 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -142,6 +142,11 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { uint32_t getSeimm7_22OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + uint32_t getSelect_256OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + }; } // namespace @@ -592,4 +597,16 @@ XtensaMCCodeEmitter::getSeimm7_22OpValue(const MCInst &MI, unsigned OpNo, return res; } +uint32_t +XtensaMCCodeEmitter::getSelect_256OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert(((Res >= 0) && (Res <= 255)) && "Unexpected operand value!"); + + return Res; +} + #include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 2d031067e1832..8af7cb6113243 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -153,6 +153,11 @@ def FeatureMiscSR : SubtargetFeature<"miscsr", "HasMiscSR", "true", def HasMiscSR : Predicate<"Subtarget->hasMiscSR()">, AssemblerPredicate<(all_of FeatureMiscSR)>; +def FeatureESP32S2Ops : SubtargetFeature<"esp32s2", "HasESP32S2Ops", "true", + "Support Xtensa esp32-s2 ISA extension">; +def HasESP32S2Ops : Predicate<"Subtarget->hasESP32S2Ops()">, + AssemblerPredicate<(all_of FeatureESP32S2Ops)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// @@ -170,8 +175,8 @@ def : Proc<"esp8266", [FeatureDensity, FeatureNSA, FeatureMul32, FeatureExtended FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeatureRegionProtection, FeaturePRID]>; def : Proc<"esp32-s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureTHREADPTR, FeatureDiv32, - FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector, - FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR]>; + FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, + FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, FeatureESP32S2Ops]>; //===----------------------------------------------------------------------===// // Register File Description diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index efb710a2145a3..aac6e1fae346e 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1450,6 +1450,27 @@ def WITLB : RRR_Inst<0x00, 0x00, 0x05, (outs AR:$t), (ins AR:$s), let r = 0x6; } +//===----------------------------------------------------------------------===// +// Illegal instructions +//===----------------------------------------------------------------------===// + +let isBarrier = 1, isTerminator = 1 in { + def ILL : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins), + "ill", []> { + let m = 0x0; + let n = 0x0; + let r = 0; + let s = 0; + } + + def ILL_N : RRRN_Inst<0x0C, (outs), (ins), + "ill.n", []>, Requires<[HasDensity]> { + let r = 0xf; + let s = 0x0; + let t = 0x6; + } +} + //===----------------------------------------------------------------------===// // Atomic patterns //===----------------------------------------------------------------------===// @@ -1584,6 +1605,40 @@ let usesCustomInserter = 1, Predicates = [HasS32C1I] in { [(set AR:$dst, (atomic_load_umax_32 AR:$ptr, AR:$arg))]>; } +//===----------------------------------------------------------------------===// +// Xtensa ESP32S2 Instructions +//===----------------------------------------------------------------------===// +let Predicates = [HasESP32S2Ops] in { + def WR_MASK_GPIO_OUT : RRR_Inst<0x0, 0x06, 0x0, (outs), (ins AR:$s, AR:$t), + "wr_mask_gpio_out\t$s, $t", []> { + let r = 0x2; + } + + def SET_BIT_GPIO_OUT : RRR_Inst<0x0, 0x06, 0x0, (outs), (ins select_256:$imm), + "set_bit_gpio_out\t$imm", []> { + bits<8> imm; + + let r = 0x1; + let s = imm{7-4}; + let t = imm{3-0}; + } + + def CLR_BIT_GPIO_OUT : RRR_Inst<0x0, 0x06, 0x0, (outs), (ins select_256:$imm), + "clr_bit_gpio_out\t$imm", []> { + bits<8> imm; + + let r = 0x0; + let s = imm{7-4}; + let t = imm{3-0}; + } + + def GET_GPIO_IN : RRR_Inst<0x0, 0x06, 0x0, (outs AR:$t), (ins), + "get_gpio_in\t$t", []> { + let r = 0x3; + let s = 0x0; + } +} + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 9957bf7bd1f47..620aeee000518 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -175,6 +175,13 @@ def seimm7_22: Immediate= 7 && Imm <= 22; }], "Seimm7_22_As let DecoderMethod = "decodeSeimm7_22Operand"; } +// select_256 predicate - Immediate in the range [0,255] +def Select_256_AsmOperand: ImmAsmOperand<"Select_256">; +def select_256: Immediate= 0 && Imm <= 255; }], "Select_256_AsmOperand"> { + let EncoderMethod = "getSelect_256OpValue"; + let DecoderMethod = "decodeSelect_256Operand"; +} + //===----------------------------------------------------------------------===// // Memory address operands //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index 106884d8a0311..2b90365eb870c 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -59,6 +59,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasPRID = false; HasRegionProtection = false; HasMiscSR = false; + HasESP32S2Ops = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index 8eb3281706cfe..24be0de4bf2ac 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -119,6 +119,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enable Xtensa Miscellaneous Special Reigsiters option bool HasMiscSR; + // Enable Xtensa esp32-s2 ISA extension + bool HasESP32S2Ops; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -190,6 +193,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasMiscSR() const { return HasMiscSR; } + bool hasESP32S2Ops() const { return HasESP32S2Ops; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; diff --git a/llvm/test/MC/Xtensa/xtensa-esp32s2-valid.s b/llvm/test/MC/Xtensa/xtensa-esp32s2-valid.s new file mode 100644 index 0000000000000..9c998e919c81e --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-esp32s2-valid.s @@ -0,0 +1,21 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+esp32s2 -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: clr_bit_gpio_out 52 +# CHECK: encoding: [0x40,0x03,0x06] +clr_bit_gpio_out 52 + +# CHECK-INST: get_gpio_in a2 +# CHECK: encoding: [0x20,0x30,0x06] +get_gpio_in a2 + +# CHECK-INST: set_bit_gpio_out 18 +# CHECK: encoding: [0x20,0x11,0x06] +set_bit_gpio_out 18 + +# CHECK-INST: wr_mask_gpio_out a3, a2 +# CHECK: encoding: [0x20,0x23,0x06] +wr_mask_gpio_out a3, a2 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-density.s b/llvm/test/MC/Xtensa/xtensa-valid-density.s new file mode 100644 index 0000000000000..fc5457ce82ddc --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-density.s @@ -0,0 +1,9 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+density -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: ill.n +# CHECK: encoding: [0x6c,0xf0] +ill.n diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s index 7cde38de052f3..490d2205990c1 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -152,6 +152,10 @@ extui a1, a2, 7, 8 # CHECK: encoding: [0xd0,0x20,0x00] extw +# CHECK-INST: ill +# CHECK: encoding: [0x00,0x00,0x00] +ill + # CHECK-INST: isync # CHECK: encoding: [0x00,0x20,0x00] isync From b5c3753800363c847db0e4173651b351ea6444fd Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:51 +0300 Subject: [PATCH 078/150] [Xtensa] Implement ESP32-S3 target. Implement support of the ESP32-S3 chip in clang and llvm. The ESP32-S3 chip includes Xtensa ISA extension which helps to work with GPIO, so we add instructions description and test. --- clang/lib/Basic/Targets/Xtensa.h | 1 + clang/lib/Driver/ToolChains/Xtensa.cpp | 2 ++ .../Xtensa/AsmParser/XtensaAsmParser.cpp | 8 ++++- llvm/lib/Target/Xtensa/Xtensa.td | 11 ++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 34 +++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 5 +++ llvm/test/MC/Xtensa/xtensa-esp32s3-valid.s | 21 ++++++++++++ 8 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-esp32s3-valid.s diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index 0c077dda2d979..126ad83219486 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -98,6 +98,7 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { .Case("esp32", true) .Case("esp8266", true) .Case("esp32-s2", true) + .Case("esp32-s3", true) .Case("generic", true) .Default(false); } diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index c3919ff8c8e93..4e7d72e821ecc 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -45,6 +45,8 @@ XtensaGCCToolchainDetector::XtensaGCCToolchainDetector( ToolchainName = "xtensa-esp32-elf"; else if (CPUName.equals("esp32-s2")) ToolchainName = "xtensa-esp32s2-elf"; + else if (CPUName.equals("esp32-s3")) + ToolchainName = "xtensa-esp32s3-elf"; else if (CPUName.equals("esp8266")) ToolchainName = "xtensa-lx106-elf"; diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 19bff501e8293..4a399e69b4195 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -947,6 +947,7 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { unsigned NumMiscSR = 0; bool IsESP32 = false; bool IsESP32_S2 = false; + bool IsESP32_S3 = false; bool Res = true; // Assume that CPU is esp32 by default @@ -960,6 +961,11 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { NumTimers = 3; NumMiscSR = 4; IsESP32_S2 = true; + } else if (CPU == "esp32-s3") { + NumIntLevels = 6; + NumTimers = 3; + NumMiscSR = 4; + IsESP32_S3 = true; } else if (CPU == "esp8266") { NumIntLevels = 2; NumTimers = 1; @@ -1083,7 +1089,7 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { Res = hasTHREADPTR(); break; case Xtensa::GPIO_OUT: - Res = IsESP32_S2; + Res = IsESP32_S2 || IsESP32_S3; break; case Xtensa::EXPSTATE: Res = IsESP32; diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 8af7cb6113243..6502087898526 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -158,6 +158,11 @@ def FeatureESP32S2Ops : SubtargetFeature<"esp32s2", "HasESP32S2Ops", "tru def HasESP32S2Ops : Predicate<"Subtarget->hasESP32S2Ops()">, AssemblerPredicate<(all_of FeatureESP32S2Ops)>; +def FeatureESP32S3Ops : SubtargetFeature<"esp32s3", "HasESP32S3Ops", "true", + "Support Xtensa esp32-s3 ISA extension">; +def HasESP32S3Ops : Predicate<"Subtarget->hasESP32S3Ops()">, + AssemblerPredicate<(all_of FeatureESP32S3Ops)>; + //===----------------------------------------------------------------------===// // Xtensa supported processors. //===----------------------------------------------------------------------===// @@ -178,6 +183,12 @@ def : Proc<"esp32-s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, FeatureESP32S2Ops]>; +def : Proc<"esp32-s3", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, + FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, + FeatureATOMCTL, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, + FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, + FeatureESP32S3Ops]>; + //===----------------------------------------------------------------------===// // Register File Description //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index aac6e1fae346e..1c2f934d3cef5 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1639,6 +1639,40 @@ let Predicates = [HasESP32S2Ops] in { } } +//===----------------------------------------------------------------------===// +// Xtensa ESP32S3 Instructions +//===----------------------------------------------------------------------===// +let Predicates = [HasESP32S3Ops] in { + def EE_WR_MASK_GPIO_OUT : RRR_Inst<0x04, 0x02, 0x07, (outs), (ins AR:$t, AR:$s), + "ee.wr_mask_gpio_out\t$t, $s", []> { + let r = 0x4; + } + + def EE_SET_BIT_GPIO_OUT : RRR_Inst<0x04, 0x05, 0x07, (outs), (ins select_256:$imm), + "ee.set_bit_gpio_out\t$imm", []> { + bits<8> imm; + + let r = 0x4; + let s = imm{7-4}; + let t = imm{3-0}; + } + + def EE_CLR_BIT_GPIO_OUT : RRR_Inst<0x04, 0x06, 0x07, (outs), (ins select_256:$imm), + "ee.clr_bit_gpio_out\t$imm", []> { + bits<8> imm; + + let r = 0x4; + let s = imm{7-4}; + let t = imm{3-0}; + } + + def EE_GET_GPIO_IN : RRR_Inst<0x04, 0x05, 0x06, (outs AR:$t), (ins), + "ee.get_gpio_in\t$t", []> { + let r = 0x0; + let s = 0x8; + } +} + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index 2b90365eb870c..c9b8e0bd0e8c2 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -60,6 +60,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasRegionProtection = false; HasMiscSR = false; HasESP32S2Ops = false; + HasESP32S3Ops = false; // Parse features string. ParseSubtargetFeatures(CPUName, CPUName, FS); diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index 24be0de4bf2ac..ee173686c2a20 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -122,6 +122,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enable Xtensa esp32-s2 ISA extension bool HasESP32S2Ops; + // Enable Xtensa esp32-s3 ISA extension + bool HasESP32S3Ops; + XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); public: @@ -195,6 +198,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasESP32S2Ops() const { return HasESP32S2Ops; } + bool hasESP32S3Ops() const { return HasESP32S3Ops; } + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; diff --git a/llvm/test/MC/Xtensa/xtensa-esp32s3-valid.s b/llvm/test/MC/Xtensa/xtensa-esp32s3-valid.s new file mode 100644 index 0000000000000..50037ea38df15 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-esp32s3-valid.s @@ -0,0 +1,21 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+esp32s3 -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# CHECK-INST: ee.clr_bit_gpio_out 52 +# CHECK: encoding: [0x44,0x43,0x76] +ee.clr_bit_gpio_out 52 + +# CHECK-INST: ee.get_gpio_in a2 +# CHECK: encoding: [0x24,0x08,0x65] +ee.get_gpio_in a2 + +# CHECK-INST: ee.set_bit_gpio_out 18 +# CHECK: encoding: [0x24,0x41,0x75] +ee.set_bit_gpio_out 18 + +# CHECK-INST: ee.wr_mask_gpio_out a3, a2 +# CHECK: encoding: [0x34,0x42,0x72] +ee.wr_mask_gpio_out a3, a2 From 3761fa7880bc897aed2a61335c8a81a64e160f98 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:51 +0300 Subject: [PATCH 079/150] [Xtensa] Define register type for CC Implement getRegisterTypeForCallingConv() method in XtensaTargetLowering --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 10 ++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 96f0e61043c1c..91b17bb5bacce 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -340,6 +340,16 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, computeRegisterProperties(STI.getRegisterInfo()); } +/// Return the register type for a given MVT +MVT XtensaTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context, + CallingConv::ID CC, + EVT VT) const { + if (VT.isFloatingPoint()) + return MVT::i32; + + return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT); +} + bool XtensaTargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const { if (!VT.isSimple()) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index d638343c82bb8..3e7d9dda62f53 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -102,6 +102,10 @@ class XtensaTargetLowering : public TargetLowering { return LHSTy.getSizeInBits() <= 32 ? MVT::i32 : MVT::i64; } + /// Return the register type for a given MVT + MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, + EVT VT) const override; + EVT getSetCCResultType(const DataLayout &, LLVMContext &, EVT VT) const override { if (!VT.isVector()) From 50226ad44fb925dc2cdb80d69883e99b6bafaa2a Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:32:51 +0300 Subject: [PATCH 080/150] [Xtensa] Correcting FP instructions and intrinsics. Correcting FP instruction descriptions. Implement lowering of the fma, powf and other FP intrinsics. Add test for base FP intrinsics. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 62 ++- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 30 +- llvm/test/CodeGen/Xtensa/float-intrinsics.ll | 363 ++++++++++++++++++ 3 files changed, 422 insertions(+), 33 deletions(-) create mode 100644 llvm/test/CodeGen/Xtensa/float-intrinsics.ll diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 91b17bb5bacce..83ca842ea1c4b 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -217,56 +217,76 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, for (unsigned I = MVT::FIRST_FP_VALUETYPE; I <= MVT::LAST_FP_VALUETYPE; ++I) { MVT VT = MVT::SimpleValueType(I); if (isTypeLegal(VT)) { - // We can use FI for FRINT. - // setOperationAction(ISD::FRINT, VT, Legal); if (VT.getSizeInBits() == 32 && Subtarget.hasSingleFloat()) { + setOperationAction(ISD::FABS, VT, Legal); setOperationAction(ISD::FADD, VT, Legal); - setOperationAction(ISD::FSUB, VT, Legal); + setOperationAction(ISD::FMA, VT, Legal); setOperationAction(ISD::FMUL, VT, Legal); - setOperationAction(ISD::FDIV, VT, Expand); + setOperationAction(ISD::FNEG, VT, Legal); + setOperationAction(ISD::FSUB, VT, Legal); } else { + setOperationAction(ISD::FABS, VT, Expand); setOperationAction(ISD::FADD, VT, Expand); - setOperationAction(ISD::FSUB, VT, Expand); + setOperationAction(ISD::FMA, VT, Expand); setOperationAction(ISD::FMUL, VT, Expand); - setOperationAction(ISD::FDIV, VT, Expand); + setOperationAction(ISD::FNEG, VT, Expand); + setOperationAction(ISD::FSUB, VT, Expand); } - // TODO: once implemented in InstrInfo uncomment - setOperationAction(ISD::FSQRT, VT, Expand); - // No special instructions for these. - setOperationAction(ISD::FSIN, VT, Expand); + setOperationAction(ISD::FCBRT, VT, Expand); + setOperationAction(ISD::FCEIL, VT, Expand); + setOperationAction(ISD::FCOPYSIGN, VT, Expand); setOperationAction(ISD::FCOS, VT, Expand); + setOperationAction(ISD::FDIV, VT, Expand); + setOperationAction(ISD::FEXP, VT, Expand); + setOperationAction(ISD::FEXP2, VT, Expand); + setOperationAction(ISD::FFLOOR, VT, Expand); + setOperationAction(ISD::FLOG, VT, Expand); + setOperationAction(ISD::FLOG2, VT, Expand); + setOperationAction(ISD::FLOG10, VT, Expand); + setOperationAction(ISD::FMAXIMUM, VT, Expand); + setOperationAction(ISD::FMINIMUM, VT, Expand); + setOperationAction(ISD::FMAXNUM, VT, Expand); + setOperationAction(ISD::FMINNUM, VT, Expand); + setOperationAction(ISD::FNEARBYINT, VT, Expand); + setOperationAction(ISD::FPOW, VT, Expand); + setOperationAction(ISD::FPOWI, VT, Expand); setOperationAction(ISD::FREM, VT, Expand); - setOperationAction(ISD::FABS, VT, Expand); + setOperationAction(ISD::FRINT, VT, Expand); + setOperationAction(ISD::FROUND, VT, Expand); + setOperationAction(ISD::FSIN, VT, Expand); + setOperationAction(ISD::FSINCOS, VT, Expand); + setOperationAction(ISD::FSQRT, VT, Expand); + setOperationAction(ISD::FTRUNC, VT, Expand); + setOperationAction(ISD::LLRINT, VT, Expand); + setOperationAction(ISD::LLROUND, VT, Expand); + setOperationAction(ISD::LRINT, VT, Expand); + setOperationAction(ISD::LROUND, VT, Expand); } } - // Handle floating-point types. if (Subtarget.hasSingleFloat()) { - setOperationAction(ISD::FMA, MVT::f32, Legal); setOperationAction(ISD::BITCAST, MVT::i32, Legal); setOperationAction(ISD::BITCAST, MVT::f32, Legal); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Legal); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal); - setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); } else { - setOperationAction(ISD::FMA, MVT::f32, Expand); - setOperationAction(ISD::SETCC, MVT::f32, Expand); setOperationAction(ISD::BITCAST, MVT::i32, Expand); setOperationAction(ISD::BITCAST, MVT::f32, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand); - setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); - setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand); - setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); - setOperationAction(ISD::FP_TO_SINT, MVT::i64, Expand); } - setOperationAction(ISD::FMA, MVT::f64, Expand); + + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Expand); + setOperationAction(ISD::SETCC, MVT::f64, Expand); setOperationAction(ISD::BITCAST, MVT::i64, Expand); setOperationAction(ISD::BITCAST, MVT::f64, Expand); diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 1c2f934d3cef5..945944a38769d 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1040,10 +1040,12 @@ def UN_S : FCompare<0x01, 0x0b, "un.s", Xtensa_cmpuo, 1>; def ABS_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "abs.s\t$r, $s", - [(set FPR:$r, (fabs FPR:$s))]> { + [(set FPR:$r, (fabs FPR:$s))]>, Requires<[HasSingleFloat]> { let t = 0x01; } +def : Pat<(fabs FPR:$s), (ABS_S $s)>; + def ADDEXP_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "addexp.s\t$r, $s", []>, Requires<[HasSingleFloat]> { let t = 0x0E; @@ -1078,7 +1080,7 @@ def DIVN_S : RRR_Inst<0x00, 0x0A, 0x07, (outs FPR:$r), (ins FPR:$s, FPR:$t), "divn.s\t$r, $s, $t", []>, Requires<[HasSingleFloat]>; def FLOAT_S : RRR_Inst<0x00, 0x0A, 0x0c, (outs FPR:$r), (ins AR:$s, uimm4:$imm), - "float.s\t$r, $s, $imm", []> { + "float.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { bits<4> imm; let t = imm; @@ -1108,6 +1110,10 @@ def MADD_S : RRR_Inst<0x00, 0x0A, 0x04, (outs FPR:$r), (ins FPR:$a, FPR:$s, FPR: let Constraints = "$r = $a"; } +// fmadd: r1 * r2 + r3 +def : Pat<(fma FPR:$r1, FPR:$r2, FPR:$r3), + (MADD_S $r3, $r1, $r2)>; + def MKDADJ_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "mkdadj.s\t$r, $s", []>, Requires<[HasSingleFloat]> { let t = 0x0D; @@ -1159,7 +1165,7 @@ def NEXP01_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), def NEG_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), "neg.s\t$r, $s", - [(set FPR:$r, (fneg FPR:$s))]> { + [(set FPR:$r, (fneg FPR:$s))]>, Requires<[HasSingleFloat]> { let t = 0x06; } @@ -1170,7 +1176,7 @@ def RECIP0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), def RFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs AR:$r), (ins FPR:$s), "rfr\t$r, $s", - [(set AR:$r, (bitconvert FPR:$s))]> { + [(set AR:$r, (bitconvert FPR:$s))]>, Requires<[HasSingleFloat]> { let t = 0x04; } @@ -1192,16 +1198,16 @@ def SQRT0_S : RRR_Inst<0x00, 0x0A, 0x0F, (outs FPR:$r), (ins FPR:$s), } def TRUNC_S : RRR_Inst<0x00, 0x0A, 0x09, (outs AR:$r), (ins FPR:$s, uimm4:$imm), - "trunc.s\t$r, $s, $imm", []> { + "trunc.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { bits<4> imm; let t = imm; } -def : Pat<(i32 (fp_to_sint FPR:$s)), (TRUNC_S FPR:$s, 0)>; +def : Pat<(i32 (any_fp_to_sint FPR:$s)), (TRUNC_S FPR:$s, 0)>; def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s, uimm4:$imm), - "ufloat.s\t$r, $s, $imm", []> { + "ufloat.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { bits<4> imm; let t = imm; @@ -1210,22 +1216,22 @@ def UFLOAT_S : RRR_Inst<0x00, 0x0A, 0x0D, (outs FPR:$r), (ins AR:$s, uimm4:$imm) def : Pat<(f32 (uint_to_fp AR:$s)), (UFLOAT_S AR:$s, 0)>; def UTRUNC_S : RRR_Inst<0x00, 0x0A, 0x0e, (outs AR:$r), (ins FPR:$s, uimm4:$imm), - "utrunc.s\t$r, $s, $imm", []> { + "utrunc.s\t$r, $s, $imm", []>, Requires<[HasSingleFloat]> { bits<4> imm; let t = imm; } -def : Pat<(i32 (fp_to_uint FPR:$s)), (UTRUNC_S FPR:$s, 0)>; +def : Pat<(i32 (any_fp_to_uint FPR:$s)), (UTRUNC_S FPR:$s, 0)>; def WFR : RRR_Inst<0x00, 0x0A, 0x0f, (outs FPR:$r), (ins AR:$s), "wfr\t$r, $s", - [(set FPR:$r, (bitconvert AR:$s))]> { + [(set FPR:$r, (bitconvert AR:$s))]>, Requires<[HasSingleFloat]> { let t = 0x05; } // FP select operations -let usesCustomInserter = 1 in { +let usesCustomInserter = 1, Predicates = [HasSingleFloat] in { def SELECT_CC_FP_INT : Pseudo<(outs AR:$dst), (ins FPR:$lhs, FPR:$rhs, AR:$t, AR:$f, i32imm:$cond), "!select_cc_fp_int $dst, $lhs, $rhs, $t, $f, $cond", [(set AR:$dst, (Xtensa_select_cc_fp FPR:$lhs, FPR:$rhs, AR:$t, AR:$f, imm:$cond))]>; @@ -1238,7 +1244,7 @@ let usesCustomInserter = 1 in { } // FP brcc pesudo operation -let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, isBarrier = 1 in { +let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, isBarrier = 1, Predicates = [HasSingleFloat] in { def BRCC_FP : Pseudo<(outs), (ins i32imm:$cond, FPR:$lhs, FPR:$rhs, brtarget:$target), "!brcc_fp $cond, $lhs, $rhs, $target", [(Xtensa_brcc_fp imm:$cond, FPR:$lhs, FPR:$rhs, bb:$target)]>; diff --git a/llvm/test/CodeGen/Xtensa/float-intrinsics.ll b/llvm/test/CodeGen/Xtensa/float-intrinsics.ll new file mode 100644 index 0000000000000..256a1dee2abf8 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/float-intrinsics.ll @@ -0,0 +1,363 @@ +; RUN: llc -mtriple=xtensa -mcpu=esp32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=XTENSA %s + +declare float @llvm.sqrt.f32(float) + +define float @sqrt_f32(float %a) nounwind { +; XTENSA: .literal .LCPI0_0, sqrtf +; XTENSA-LABEL: sqrt_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI0_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n +; + %1 = call float @llvm.sqrt.f32(float %a) + ret float %1 +} + +declare float @llvm.powi.f32(float, i32) + +define float @powi_f32(float %a, i32 %b) nounwind { +; XTENSA: .literal .LCPI1_0, __powisf2 +; XTENSA-LABEL: powi_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI1_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: mov.n a11, a3 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.powi.f32(float %a, i32 %b) + ret float %1 +} + +declare float @llvm.sin.f32(float) + +define float @sin_f32(float %a) nounwind { +; XTENSA: .literal .LCPI2_0, sinf +; XTENSA-LABEL: sin_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI2_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.sin.f32(float %a) + ret float %1 +} + +declare float @llvm.cos.f32(float) + +define float @cos_f32(float %a) nounwind { +; XTENSA: .literal .LCPI3_0, cosf +; XTENSA-LABEL: cos_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI3_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.cos.f32(float %a) + ret float %1 +} + +declare float @llvm.pow.f32(float, float) + +define float @pow_f32(float %a, float %b) nounwind { +; XTENSA: .literal .LCPI4_0, powf +; XTENSA-LABEL: pow_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI4_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: mov.n a11, a3 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + %1 = call float @llvm.pow.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.exp.f32(float) + +define float @exp_f32(float %a) nounwind { +; XTENSA: .literal .LCPI5_0, expf +; XTENSA-LABEL: exp_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI5_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + %1 = call float @llvm.exp.f32(float %a) + ret float %1 +} + +declare float @llvm.exp2.f32(float) + +define float @exp2_f32(float %a) nounwind { +; XTENSA: .literal .LCPI6_0, exp2 +; XTENSA-LABEL: exp2_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI6_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + %1 = call float @llvm.exp2.f32(float %a) + ret float %1 +} + +declare float @llvm.log.f32(float) + +define float @log_f32(float %a) nounwind { +; XTENSA: .literal .LCPI7_0, log +; XTENSA-LABEL: log_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI7_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + %1 = call float @llvm.log.f32(float %a) + ret float %1 +} + +declare float @llvm.log10.f32(float) + +define float @log10_f32(float %a) nounwind { +; XTENSA: .literal .LCPI8_0, log10 +; XTENSA-LABEL: log10_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI8_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + %1 = call float @llvm.log10.f32(float %a) + ret float %1 +} + +declare float @llvm.log2.f32(float) + +define float @log2_f32(float %a) nounwind { +; XTENSA: .literal .LCPI9_0, log2 +; XTENSA-LABEL: log2_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI9_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + %1 = call float @llvm.log2.f32(float %a) + ret float %1 +} + +declare float @llvm.fma.f32(float, float, float) + +define float @fma_f32(float %a, float %b, float %c) nounwind { +; XTENSA-LABEL: fma_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: wfr f8, a3 +; XTENSA-NEXT: wfr f9, a2 +; XTENSA-NEXT: wfr f10, a4 +; XTENSA-NEXT: madd.s f10, f9, f8 +; XTENSA-NEXT: rfr a2, f10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.fma.f32(float %a, float %b, float %c) + ret float %1 +} + +declare float @llvm.minnum.f32(float, float) + +define float @minnum_f32(float %a, float %b) nounwind { +; XTENSA: .literal .LCPI11_0, fminf +; XTENSA-LABEL: minnum_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI11_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: mov.n a11, a3 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.minnum.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.maxnum.f32(float, float) + +define float @maxnum_f32(float %a, float %b) nounwind { +; XTENSA: .literal .LCPI12_0, fmaxf +; XTENSA-LABEL: maxnum_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI12_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: mov.n a11, a3 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.maxnum.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.fabs.f32(float) + +define float @fabs_f32(float %a) nounwind { +; XTENSA: .literal .LCPI13_0, 2147483647 +; XTENSA-LABEL: fabs_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI13_0 +; XTENSA-NEXT: and a2, a2, a8 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.fabs.f32(float %a) + ret float %1 +} + +declare float @llvm.copysign.f32(float, float) + +define float @copysign_f32(float %a, float %b) nounwind { +; XTENSA: .literal .LCPI14_0, -2147483648 +; XTENSA: .literal .LCPI14_1, 2147483647 +; XTENSA-LABEL: copysign_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI14_0 +; XTENSA-NEXT: and a8, a3, a8 +; XTENSA-NEXT: l32r a9, .LCPI14_1 +; XTENSA-NEXT: and a9, a2, a9 +; XTENSA-NEXT: wfr f8, a9 +; XTENSA-NEXT: movi.n a9, 0 +; XTENSA-NEXT: beq a8, a9, .LBB14_2 +; XTENSA-NEXT: # %bb.1: +; XTENSA-NEXT: neg.s f8, f8 +; XTENSA-NEXT: .LBB14_2: +; XTENSA-NEXT: rfr a2, f8 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.copysign.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.floor.f32(float) + +define float @floor_f32(float %a) nounwind { +; XTENSA: .literal .LCPI15_0, floor +; XTENSA-LABEL: floor_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI15_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.floor.f32(float %a) + ret float %1 +} + +declare float @llvm.ceil.f32(float) + +define float @ceil_f32(float %a) nounwind { +; XTENSA: .literal .LCPI16_0, ceil +; XTENSA-LABEL: ceil_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI16_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.ceil.f32(float %a) + ret float %1 +} + +declare float @llvm.trunc.f32(float) + +define float @trunc_f32(float %a) nounwind { +; XTENSA: .literal .LCPI17_0, trunc +; XTENSA-LABEL: trunc_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI17_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.trunc.f32(float %a) + ret float %1 +} + +declare float @llvm.rint.f32(float) + +define float @rint_f32(float %a) nounwind { +; XTENSA: .literal .LCPI18_0, rint +; XTENSA-LABEL: rint_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI18_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.rint.f32(float %a) + ret float %1 +} + +declare float @llvm.nearbyint.f32(float) + +define float @nearbyint_f32(float %a) nounwind { +; XTENSA: .literal .LCPI19_0, nearbyint +; XTENSA-LABEL: nearbyint_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI19_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.nearbyint.f32(float %a) + ret float %1 +} + +declare float @llvm.round.f32(float) + +define float @round_f32(float %a) nounwind { +; XTENSA: .literal .LCPI20_0, round +; XTENSA-LABEL: round_f32: +; XTENSA: # %bb.0: +; XTENSA-NEXT: entry a1, 32 +; XTENSA-NEXT: l32r a8, .LCPI20_0 +; XTENSA-NEXT: mov.n a10, a2 +; XTENSA-NEXT: callx8 a8 +; XTENSA-NEXT: mov.n a2, a10 +; XTENSA-NEXT: retw.n + + %1 = call float @llvm.round.f32(float %a) + ret float %1 +} From fba1511835e3930644239d749e51c0c57ba09ec1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:20 +0300 Subject: [PATCH 081/150] [Xtensa] Implement MUL16 feature. --- llvm/lib/Target/Xtensa/Xtensa.td | 21 +++++++++++++-------- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 11 +++++++++++ llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 1 + llvm/lib/Target/Xtensa/XtensaSubtarget.h | 5 +++++ llvm/test/MC/Xtensa/xtensa-valid-mul16.s | 14 ++++++++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-valid-mul16.s diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index 6502087898526..b4256c4dc8145 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -52,6 +52,11 @@ def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true", def HasNSA : Predicate<"Subtarget->hasNSA()">, AssemblerPredicate<(all_of FeatureNSA)>; +def FeatureMul16 : SubtargetFeature<"mul16", "HasMul16", "true", + "Enable Xtensa Mul16 option">; +def HasMul16 : Predicate<"Subtarget->hasMul16()">, + AssemblerPredicate<(all_of FeatureMul16)>; + def FeatureMul32 : SubtargetFeature<"mul32", "HasMul32", "true", "Enable Xtensa Mul32 option">; def HasMul32 : Predicate<"Subtarget->hasMul32()">, @@ -171,20 +176,20 @@ class Proc Features> def : Proc<"generic", []>; -def : Proc<"esp32", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, - FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, +def : Proc<"esp32", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, FeatureSEXT, + FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, FeatureATOMCTL, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR]>; -def : Proc<"esp8266", [FeatureDensity, FeatureNSA, FeatureMul32, FeatureExtendedL32R, FeatureDebug, FeatureException, FeatureHighPriInterrupts, - FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeatureRegionProtection, FeaturePRID]>; +def : Proc<"esp8266", [FeatureDensity, FeatureNSA, FeatureMul16, FeatureMul32, FeatureExtendedL32R, FeatureDebug, FeatureException, + FeatureHighPriInterrupts, FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeatureRegionProtection, FeaturePRID]>; -def : Proc<"esp32-s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureTHREADPTR, FeatureDiv32, - FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, +def : Proc<"esp32-s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureTHREADPTR, + FeatureDiv32, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, FeatureESP32S2Ops]>; -def : Proc<"esp32-s3", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, - FeatureSEXT, FeatureNSA, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, +def : Proc<"esp32-s3", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, FeatureSEXT, + FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, FeatureATOMCTL, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, FeatureESP32S3Ops]>; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 945944a38769d..e7ad633aa7cbe 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1323,6 +1323,17 @@ def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), let r = 0xF; } +//===----------------------------------------------------------------------===// +// Mul16 Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasMul16] in { + def MUL16S : RRR_Inst<0x00, 0x01, 0x0D, (outs AR:$r), (ins AR:$s, AR:$t), + "mul16s\t$r, $s, $t", []>; + def MUL16U : RRR_Inst<0x00, 0x01, 0x0C, (outs AR:$r), (ins AR:$s, AR:$t), + "mul16u\t$r, $s, $t", []>; +} + //===----------------------------------------------------------------------===// // Mul32 Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index c9b8e0bd0e8c2..e164da998b5e7 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -39,6 +39,7 @@ XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HasLoop = false; HasSEXT = false; HasNSA = false; + HasMul16 = false; HasMul32 = false; HasMul32High = false; HasDiv32 = false; diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index ee173686c2a20..b4fac0b65eb19 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -59,6 +59,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { // Enable Xtensa NSA option bool HasNSA; + // Enable Xtensa Mul16 option + bool HasMul16; + // Enable Xtensa Mul32 option bool HasMul32; @@ -156,6 +159,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasNSA() const { return HasNSA; } + bool hasMul16() const { return HasMul16; } + bool hasMul32() const { return HasMul32; } bool hasMul32High() const { return HasMul32High; } diff --git a/llvm/test/MC/Xtensa/xtensa-valid-mul16.s b/llvm/test/MC/Xtensa/xtensa-valid-mul16.s new file mode 100644 index 0000000000000..4a6c525191f87 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-valid-mul16.s @@ -0,0 +1,14 @@ +# RUN: llvm-mc %s -triple=xtensa -mattr=+mul16 -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# CHECK-INST: mul16s a2, a3, a4 +# CHECK: encoding: [0x40,0x23,0xd1] + mul16s a2, a3, a4 + +# CHECK-INST: mul16u a2, a3, a4 +# CHECK: encoding: [0x40,0x23,0xc1] + mul16u a2, a3, a4 From 65cedc277962c44b07c56c083f4eae63c7f6fcfd Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:20 +0300 Subject: [PATCH 082/150] [Xtensa] Add a no-op -mlongcalls option for better compatibility Many projects targeting Xtensa architecture use GCC-specific -mlongcalls option. The current behavior of LLVM for Xtensa is equivalent to this option being set, so accept this option without changing the behavior. --- clang/include/clang/Driver/Options.td | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index ab45940c4a2c5..837e840980aff 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4670,6 +4670,7 @@ def mfix_esp32_psram_cache_issue : Flag<["-"], "mfix-esp32-psram-cache-issue">, def mfix_esp32_psram_cache_strategy_EQ : Joined<["-"], "mfix-esp32-psram-cache-strategy=">, Group, HelpText<" Psram cache fix strategies : memw, nops">, Values<"memw, nops">; +def mlongcalls : Flag<["-"], "mlongcalls">, Group; // These are legacy user-facing driver-level option spellings. They are always // aliases for options that are spelled using the more common Unix / GNU flag From 2a178e0b7c40eb70255cff248d8e18e182114f37 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:21 +0300 Subject: [PATCH 083/150] [Xtensa] Initialize MCSubtargetInfo with esp32. Initialize Xtensa MCSubtargetInfo with esp32 subtarget by default. --- llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index a1b410b6b611c..61abbc194e183 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -64,6 +64,8 @@ static MCRegisterInfo *createXtensaMCRegisterInfo(const Triple &TT) { static MCSubtargetInfo * createXtensaMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { + if (CPU.empty()) + CPU = "esp32"; return createXtensaMCSubtargetInfoImpl(TT, CPU, CPU, FS); } From 9511ee030dc2ad3ee30084584faa490f2d440426 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:21 +0300 Subject: [PATCH 084/150] [Xtensa] Correction of the Hardware Loop pass. Update loop counter via a phi instruction. This improvement fix case when loop have multiple enters. --- .../lib/Target/Xtensa/XtensaHardwareLoops.cpp | 182 ++++++++++++------ llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 62 +++++- llvm/lib/Target/Xtensa/XtensaISelLowering.h | 4 + llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 9 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 14 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 7 +- .../Xtensa/XtensaTargetTransformInfo.cpp | 2 +- 7 files changed, 201 insertions(+), 79 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp index a1a2432ded4c1..34dc193995594 100644 --- a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp +++ b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp @@ -67,6 +67,7 @@ struct XtensaHardwareLoops : public MachineFunctionPass { MachineRegisterInfo *MRI; MachineDominatorTree *MDT; const XtensaInstrInfo *TII; + const TargetRegisterInfo *TRI; const XtensaSubtarget *STI; SmallPtrSet VisitedMBBs; @@ -99,7 +100,10 @@ struct XtensaHardwareLoops : public MachineFunctionPass { bool checkLoopSize(MachineLoop *L); - bool checkLoopEndDisplacement(MachineFunction &MF, MachineBasicBlock *LH, MachineBasicBlock* LE); + bool checkLoopEndDisplacement(MachineFunction &MF, MachineBasicBlock *LH, + MachineBasicBlock *LE); + + void revertNonLoops(MachineFunction &M); }; char XtensaHardwareLoops::ID = 0; @@ -119,11 +123,11 @@ bool XtensaHardwareLoops::runOnMachineFunction(MachineFunction &MF) { return false; bool Changed = false; - MLI = &getAnalysis(); MRI = &MF.getRegInfo(); STI = &MF.getSubtarget(); TII = STI->getInstrInfo(); + TRI = STI->getRegisterInfo(); if (!STI->hasLoop()) return false; @@ -135,6 +139,8 @@ bool XtensaHardwareLoops::runOnMachineFunction(MachineFunction &MF) { Changed |= processLoop(L); } + revertNonLoops(MF); + return Changed; } @@ -191,27 +197,33 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { return true; using instr_iterator = MachineBasicBlock::instr_iterator; - MachineInstr *LII = nullptr; // LOOPINIT instruction - MachineInstr *LEI = nullptr; // LOOPEND instruction - MachineBasicBlock *LEMBB = nullptr; + MachineInstr *LII = nullptr; // LOOPINIT instruction + MachineInstr *LDECI = nullptr; // LOOPDEC instruction + MachineInstr *LBRI = nullptr; // LOOPBR instruction + MachineBasicBlock *LDECMBB = nullptr; + MachineBasicBlock *LBRMBB = nullptr; MachineBasicBlock *LH = L->getHeader(); MachineBasicBlock *LastMBB = L->getLoopLatch(); - std::vector LoopInitInsts; std::map LoopInitMap; - // Try to find LOOPEND instruction in the loop latch + // Try to find LOOPENDDEC instruction in the loop latch for (auto MBI = L->block_begin(), MBIE = L->block_end(); MBI != MBIE; ++MBI) { if (VisitedMBBs.count(*MBI)) continue; for (auto MII = (*MBI)->begin(), MIE = (*MBI)->end(); MII != MIE; ++MII) { MachineInstr *LMI = &*MII; - if (LMI->getOpcode() == Xtensa::LOOPEND) { - LEI = LMI; - LEMBB = *MBI; + if (LMI->getOpcode() == Xtensa::LOOPDEC) { + LDECI = LMI; + LDECMBB = *MBI; + } + + if (LMI->getOpcode() == Xtensa::LOOPBR) { + LBRI = LMI; + LBRMBB = *MBI; } + // Collect LOOPINIT instructions inside the loop if (LMI->getOpcode() == Xtensa::LOOPINIT) { - LoopInitInsts.push_back(LMI); MachineBasicBlock *SB = LMI->getParent(); while (!SB->isSuccessor(LH)) { for (auto SBI : SB->successors()) { @@ -229,10 +241,17 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { VisitedMBBs.insert(*MBI); } - if (LEI != nullptr) { - MachineBasicBlock::iterator LHI = LH->getFirstNonPHI(); + if ((LBRI != nullptr) && (LDECI != nullptr)) { MachineBasicBlock *LIMBB = nullptr; + for (const auto &Use : MRI->use_operands(LDECI->getOperand(0).getReg())) { + const MachineInstr *UseMI = Use.getParent(); + if ((UseMI != LBRI) && (UseMI->getOpcode() != TargetOpcode::PHI)) { + LLVM_DEBUG(dbgs() << "Xtensa Loops: Unable to remove LoopDec.\n"); + return false; + } + } + // Collect LOOPINIT instructions in predecessors from outter loop for (auto PBI : LH->predecessors()) { if (L->contains(PBI)) @@ -268,76 +287,72 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { // sub a, a, 1 // bnez a, LH if (!checkLoopSize(L) || containsInvalidInstruction(L) || - (LEMBB != LastMBB) || - (!checkLoopEndDisplacement(*LH->getParent(), LH, LEMBB))) { - const MCInstrDesc &PD = TII->get(TargetOpcode::PHI); - MachineInstr *NewPN = LH->getParent()->CreateMachineInstr(PD, DL); - LH->insert(LH->begin(), NewPN); - Register PR = MRI->createVirtualRegister(&Xtensa::ARRegClass); - NewPN->addOperand(MachineOperand::CreateReg(PR, true)); - - Register IndR = MRI->createVirtualRegister(&Xtensa::ARRegClass); + (LBRMBB != LastMBB) || + (!checkLoopEndDisplacement(*LH->getParent(), LH, LBRMBB))) { for (auto PB : LH->predecessors()) { - if (LoopInitMap.find(PB) != LoopInitMap.end()) { - MachineOperand MO = MachineOperand::CreateReg( - LoopInitMap[PB]->getOperand(0).getReg(), false); - NewPN->addOperand(MO); - NewPN->addOperand(MachineOperand::CreateMBB(PB)); + Register Elts = LoopInitMap[PB]->getOperand(1).getReg(); + Register Def = LoopInitMap[PB]->getOperand(0).getReg(); + + for (auto &Use : make_early_inc_range(MRI->use_operands(Def))) { + Use.setReg(Elts); + } LoopInitMap[PB]->getParent()->erase(LoopInitMap[PB]); - } else { - MachineOperand MO = MachineOperand::CreateReg(IndR, false); - NewPN->addOperand(MO); - NewPN->addOperand(MachineOperand::CreateMBB(PB)); } } - MachineInstrBuilder MIB = - BuildMI(*LEMBB, LEI, LEI->getDebugLoc(), TII->get(Xtensa::ADDI), IndR) - .addReg(PR) - .addImm(-1); - - MIB = BuildMI(*LEMBB, LEI, LEI->getDebugLoc(), TII->get(Xtensa::BNEZ)) - .addReg(IndR) - .addMBB(LEI->getOperand(0).getMBB()); - LEMBB->erase(LEI); + Register IndR = LDECI->getOperand(0).getReg(); + Register PR = LDECI->getOperand(1).getReg(); + + BuildMI(*LDECMBB, LDECI, LDECI->getDebugLoc(), TII->get(Xtensa::ADDI), + IndR) + .addReg(PR) + .addImm(-1); + BuildMI(*LBRMBB, LBRI, LBRI->getDebugLoc(), TII->get(Xtensa::BNEZ)) + .addReg(IndR) + .addMBB(LBRI->getOperand(1).getMBB()); + LDECMBB->erase(LDECI); + LBRMBB->erase(LBRI); return false; } - // If several LOOPINIT instructions are dicovered then create PHI - // function - if (LoopInitMap.size() > 1) { - const MCInstrDesc &PD = TII->get(TargetOpcode::PHI); - MachineInstr *NewPN = LH->getParent()->CreateMachineInstr(PD, DL); - LH->insert(LH->begin(), NewPN); - Register PR = MRI->createVirtualRegister(&Xtensa::ARRegClass); - NewPN->addOperand(MachineOperand::CreateReg(PR, true)); - - for (auto PB : LH->predecessors()) { + MachineInstr *PN = nullptr; - if (LoopInitMap.find(PB) != LoopInitMap.end()) { - MachineOperand MO = MachineOperand::CreateReg( - LoopInitMap[PB]->getOperand(0).getReg(), false); - NewPN->addOperand(MO); - NewPN->addOperand(MachineOperand::CreateMBB(PB)); - LoopInitMap[PB]->getParent()->erase(LoopInitMap[PB]); - } else { - MachineOperand MO = MachineOperand::CreateReg(PR, false); - NewPN->addOperand(MO); - NewPN->addOperand(MachineOperand::CreateMBB(PB)); - } + for (auto &Use : MRI->use_operands(LDECI->getOperand(0).getReg())) { + MachineInstr *UseMI = Use.getParent(); + if (UseMI->getOpcode() == TargetOpcode::PHI) { + PN = UseMI; } - LII = NewPN; } + assert(((PN != nullptr) && (PN->getParent() == LH)) && + "Expected PHI node successor of the LOOPEND instruction in loop " + "header"); + LII = PN; + + Register EltsDec = LDECI->getOperand(0).getReg(); + Register Elts = LDECI->getOperand(1).getReg(); + + for (MachineOperand &MO : PN->operands()) { + if (!MO.isReg() || MO.getReg() != EltsDec) + continue; + MO.substVirtReg(Elts, 0, *TRI); + } + LDECMBB->erase(LDECI); + + MachineBasicBlock::iterator LHI = LH->getFirstNonPHI(); + BuildMI(*LH, LHI, DL, TII->get(Xtensa::LOOPSTART)) .addReg(LII->getOperand(0).getReg()) - .addMBB(LEMBB); + .addMBB(LBRMBB); if (LII->getOpcode() == Xtensa::LOOPINIT) LII->getParent()->erase(LII); + BuildMI(*LBRMBB, LBRI, DL, TII->get(Xtensa::LOOPEND)).addMBB(LH); + LBRMBB->erase(LBRI); + return true; } @@ -386,3 +401,44 @@ bool XtensaHardwareLoops::checkLoopEndDisplacement(MachineFunction &MF, llvm_unreachable("Wrong hardware loop"); } +void XtensaHardwareLoops::revertNonLoops(MachineFunction &MF) { + for (MachineFunction::iterator I = MF.begin(); I != MF.end(); ++I) { + MachineBasicBlock &MBB = *I; + + for (MachineBasicBlock::iterator MII = MBB.begin(), E = MBB.end(); MII != E; + ++MII) { + MachineInstr *MI = &*MII; + if (MI->getOpcode() == Xtensa::LOOPINIT) { + MachineInstr *LI = MI; + MachineBasicBlock *LIMBB = LI->getParent(); + Register Elts = LI->getOperand(1).getReg(); + Register Def = LI->getOperand(0).getReg(); + for (auto &Use : make_early_inc_range(MRI->use_operands(Def))) { + Use.setReg(Elts); + } + --MII; + LIMBB->erase(LI); + } else if (MI->getOpcode() == Xtensa::LOOPDEC) { + MachineInstr *LEI = MI; + MachineBasicBlock *LEMBB = LEI->getParent(); + Register IndR = LEI->getOperand(0).getReg(); + Register PR = LEI->getOperand(1).getReg(); + + BuildMI(*LEMBB, LEI, LEI->getDebugLoc(), TII->get(Xtensa::ADDI), IndR) + .addReg(PR) + .addImm(-1); + --MII; + LEMBB->erase(LEI); + } else if (MI->getOpcode() == Xtensa::LOOPBR) { + MachineInstr *LBRI = MI; + MachineBasicBlock *LBRMBB = LBRI->getParent(); + + BuildMI(*LBRMBB, LBRI, LBRI->getDebugLoc(), TII->get(Xtensa::BNEZ)) + .addReg(LBRI->getOperand(0).getReg()) + .addMBB(LBRI->getOperand(1).getMBB()); + --MII; + LBRMBB->erase(LBRI); + } + } + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 83ca842ea1c4b..c97f6fb16ea9d 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -302,10 +302,14 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &tm, setTargetDAGCombine(ISD::FSUB); } - if (Subtarget.hasSingleFloat() || Subtarget.hasLoop()) { + if (Subtarget.hasSingleFloat()) { setTargetDAGCombine(ISD::BRCOND); } + if (Subtarget.hasLoop()) { + setTargetDAGCombine(ISD::BR_CC); + } + // Needed so that we don't try to implement f128 constant loads using // a load-and-extend of a f80 constant (in cases where the constant // would fit in an f80). @@ -585,7 +589,7 @@ static SDValue SearchLoopIntrinsic(SDValue N, ISD::CondCode &CC, int &Imm, } case ISD::INTRINSIC_W_CHAIN: { unsigned IntOp = cast(N.getOperand(1))->getZExtValue(); - if (IntOp != Intrinsic::loop_decrement) + if (IntOp != Intrinsic::loop_decrement_reg) return SDValue(); return N; } @@ -593,17 +597,28 @@ static SDValue SearchLoopIntrinsic(SDValue N, ISD::CondCode &CC, int &Imm, return SDValue(); } -static SDValue PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG, +static SDValue PerformHWLoopCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const XtensaSubtarget &Subtarget) { SDValue Chain = N->getOperand(0); SDLoc DL(N); - SDValue Cond = N->getOperand(1); - SDValue Dest = N->getOperand(2); + SDValue Cond; + SDValue Dest; ISD::CondCode CC = ISD::SETEQ; int Imm = 1; bool Negate = false; + assert(N->getOpcode() == ISD::BR_CC && "Expected BR_CC!"); + CC = cast(N->getOperand(1))->get(); + Cond = N->getOperand(2); + Dest = N->getOperand(4); + if (auto *Const = dyn_cast(N->getOperand(3))) { + if (!Const->isOne() && !Const->isNullValue()) + return SDValue(); + Imm = Const->getZExtValue(); + } else + return SDValue(); + SDValue Int = SearchLoopIntrinsic(Cond, CC, Imm, Negate); if (Int) { assert((N->hasOneUse() && N->use_begin()->getOpcode() == ISD::BR) && @@ -634,16 +649,39 @@ static SDValue PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG, } else if (!IsFalseIfZero(CC, Imm)) { llvm_unreachable("unsupported condition"); } + SDLoc dl(Int); + SDValue Elements = Int.getOperand(2); + SDValue Size = DAG.getTargetConstant( + cast(Int.getOperand(3))->getZExtValue(), dl, MVT::i32); + SDValue Args[] = { + Int.getOperand(0), + Elements, + Size, + }; + SDValue LoopDec = DAG.getNode(XtensaISD::LOOPDEC, dl, + DAG.getVTList(MVT::i32, MVT::Other), Args); // We now need to make the intrinsic dead (it cannot be instruction // selected). - DAG.ReplaceAllUsesOfValueWith(Int.getValue(1), Int.getOperand(0)); - assert(Int.getNode()->hasOneUse() && - "Counter decrement has more than one use"); + DAG.ReplaceAllUsesWith(Int.getNode(), LoopDec.getNode()); + + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + SDValue(LoopDec.getNode(), 1), Chain); - return DAG.getNode(XtensaISD::LOOPEND, DL, MVT::Other, N->getOperand(0), - Dest); + SDValue EndArgs[] = {Chain, SDValue(LoopDec.getNode(), 0), Dest}; + return DAG.getNode(XtensaISD::LOOPBR, dl, MVT::Other, EndArgs); } + return SDValue(); +} + +static SDValue PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const XtensaSubtarget &Subtarget) { + SDValue Chain = N->getOperand(0); + SDLoc DL(N); + SDValue Cond = N->getOperand(1); + SDValue Dest = N->getOperand(2); + ISD::CondCode CC = ISD::SETEQ; if (Cond.getOpcode() != ISD::SETCC) return SDValue(); @@ -671,6 +709,8 @@ SDValue XtensaTargetLowering::PerformDAGCombine(SDNode *N, return performADDCombine(N, DAG, DCI, Subtarget); case ISD::FSUB: return performSUBCombine(N, DAG, DCI, Subtarget); + case ISD::BR_CC: + return PerformHWLoopCombine(N, DAG, DCI, Subtarget); case ISD::BRCOND: return PerformBRCONDCombine(N, DAG, DCI, Subtarget); } @@ -1843,6 +1883,8 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(CMPOEQ); OPCODE(CMPOLE); OPCODE(CMPOLT); + OPCODE(LOOPBR); + OPCODE(LOOPDEC); OPCODE(LOOPEND); OPCODE(MADD); OPCODE(MSUB); diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 3e7d9dda62f53..eaa8a0776346d 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -50,6 +50,10 @@ enum { CMPOLE, CMPOLT, + // Branch at the end of the loop, uses result of the LOOPDEC + LOOPBR, + // Decrement loop counter + LOOPDEC, LOOPEND, // FP multipy-add/sub diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index b67b2343493d4..bc4c68eeaa5e5 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -260,6 +260,7 @@ bool XtensaInstrInfo::reverseBranchCondition( return false; case Xtensa::LOOPEND: + case Xtensa::LOOPBR: return true; default: @@ -297,6 +298,7 @@ XtensaInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { case Xtensa::BNEZ: case Xtensa::BLTZ: case Xtensa::BGEZ: + case Xtensa::LOOPBR: return MI.getOperand(1).getMBB(); case Xtensa::BT: @@ -317,6 +319,7 @@ bool XtensaInstrInfo::isBranchOffsetInRange(unsigned BranchOp, case Xtensa::JX: return true; case Xtensa::LOOPEND: + case Xtensa::LOOPBR: BrOffset += 4; assert((BrOffset <= 0) && "Wrong hardware loop"); return true; @@ -632,6 +635,7 @@ unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, case Xtensa::BNEZ: case Xtensa::BLTZ: case Xtensa::BGEZ: + case Xtensa::LOOPBR: MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB); break; case Xtensa::BT: @@ -639,7 +643,7 @@ unsigned XtensaInstrInfo::InsertBranchAtInst(MachineBasicBlock &MBB, MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB); break; case Xtensa::LOOPEND: - MI = BuildMI(MBB, I, DL, get(BR_C)).addMBB(TBB); + MI = BuildMI(MBB, I, DL, get(Xtensa::LOOPEND)).addMBB(TBB); break; default: llvm_unreachable("Invalid branch type!"); @@ -728,6 +732,7 @@ bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI, case Xtensa::BNEZ: case Xtensa::BLTZ: case Xtensa::BGEZ: + case Xtensa::LOOPBR: Cond[0].setImm(OpCode); Target = &MI->getOperand(1); return true; @@ -742,4 +747,4 @@ bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI, assert(!MI->getDesc().isBranch() && "Unknown branch opcode"); return false; } -} +} \ No newline at end of file diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index e7ad633aa7cbe..46468f0349860 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1282,8 +1282,8 @@ def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), } let isTerminator = 1, isBarrier = 1, hasSideEffects = 1, Size = 3 in { - def LOOPINIT : Pseudo<(outs), (ins AR:$elts), - "!loopinit $elts", [(int_set_loop_iterations AR:$elts)]>; + def LOOPINIT : Pseudo<(outs AR:$elts), (ins AR:$eltsin), + "!loopinit $elts, $eltsin", [(set AR:$elts, (int_start_loop_iterations AR:$eltsin))]>; } // LOOPSTART pseudo instruction reserves 9 bytes for LOOP operation and NOP operations for possible alignment. @@ -1298,6 +1298,16 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 0, Size = "!loopend $target", [(Xtensa_loopend bb:$target)]>; } +let isTerminator = 1, isBarrier = 1, hasSideEffects = 1, Size = 3 in { + def LOOPDEC : Pseudo<(outs AR:$eltsout), (ins AR:$eltsin), + "!loopdec $eltsout, $eltsin", [(set AR:$eltsout, (Xtensa_loopdec AR:$eltsin))]>; +} + +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 0, Size = 3 in { + def LOOPBR : Pseudo<(outs), (ins AR:$elts, brtarget:$target), + "!loopbr $elts, $target", [(Xtensa_loopbr AR:$elts, bb:$target)]>; +} + //===----------------------------------------------------------------------===// // SEXT Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index a37dcd7c8a986..cdc29be5deb3b 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -45,6 +45,8 @@ def SDT_XtensaMEMBARRIER : SDTypeProfile<0, 0, []>; def SDT_XtensaRUR : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_XtensaLoopEnd : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>; +def SDT_XtensaLoopDec : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>; +def SDT_XtensaLoopBr : SDTypeProfile<0, 2, [SDTCisVT<0, i32>, SDTCisVT<1, OtherVT>]>; //===----------------------------------------------------------------------===// // Node definitions @@ -112,4 +114,7 @@ def Xtensa_rur: SDNode<"XtensaISD::RUR", SDT_XtensaRUR, def Xtensa_loopend: SDNode<"XtensaISD::LOOPEND", SDT_XtensaLoopEnd, [SDNPHasChain, SDNPInGlue]>; - +def Xtensa_loopdec: SDNode<"XtensaISD::LOOPDEC", SDT_XtensaLoopDec, + [SDNPHasChain, SDNPInGlue]>; +def Xtensa_loopbr: SDNode<"XtensaISD::LOOPBR", SDT_XtensaLoopBr, + [SDNPHasChain, SDNPInGlue]>; diff --git a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp index 7bdec70504772..62ad8b6b00997 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp @@ -27,7 +27,7 @@ bool XtensaTTIImpl::isHardwareLoopProfitable(Loop *L, ScalarEvolution &SE, return false; LLVMContext &C = L->getHeader()->getContext(); - HWLoopInfo.CounterInReg = false; + HWLoopInfo.CounterInReg = true; HWLoopInfo.IsNestingLegal = false; HWLoopInfo.CountType = Type::getInt32Ty(C); HWLoopInfo.LoopDecrement = ConstantInt::get(HWLoopInfo.CountType, 1); From cfe4f2425708a5cf55ecf843aa776fed0b518745 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:22 +0300 Subject: [PATCH 085/150] [Xtensa] Fix atomic swap for 8/16 bit operands. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 2 +- llvm/test/CodeGen/Xtensa/atomicrmw.ll | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/Xtensa/atomicrmw.ll diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index c97f6fb16ea9d..e9ae9ddf3e1f5 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -2416,7 +2416,7 @@ XtensaTargetLowering::emitAtomicSwap(MachineInstr &MI, MachineBasicBlock *BB, unsigned R8 = MRI.createVirtualRegister(RC); BuildMI(*BB, St, DL, TII.get(Xtensa::SSR)).addReg(BitOffs); - BuildMI(*BB, St, DL, TII.get(Xtensa::SLL), R8).addReg(AtomValLoop); + BuildMI(*BB, St, DL, TII.get(Xtensa::SRL), R8).addReg(AtomValLoop); if (isByteOperand) { BuildMI(*BB, St, DL, TII.get(Xtensa::SEXT), Res.getReg()) diff --git a/llvm/test/CodeGen/Xtensa/atomicrmw.ll b/llvm/test/CodeGen/Xtensa/atomicrmw.ll new file mode 100644 index 0000000000000..f2b7526e33e84 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/atomicrmw.ll @@ -0,0 +1,103 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=xtensa -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CHECK-XTENSA %s + +define i8 @atomicrmw_xchg_i8_seq_cst(i8* %a, i8 %b) nounwind { +; CHECK-XTENSA-LABEL: atomicrmw_xchg_i8_seq_cst: +; CHECK-XTENSA: # %bb.0: +; CHECK-XTENSA-NEXT: entry a1, 32 +; CHECK-XTENSA-NEXT: memw +; CHECK-XTENSA-NEXT: movi.n a8, 3 +; CHECK-XTENSA-NEXT: and a8, a8, a2 +; CHECK-XTENSA-NEXT: sub a9, a2, a8 +; CHECK-XTENSA-NEXT: slli a8, a8, 3 +; CHECK-XTENSA-NEXT: movi a10, 255 +; CHECK-XTENSA-NEXT: ssl a8 +; CHECK-XTENSA-NEXT: movi.n a11, -1 +; CHECK-XTENSA-NEXT: sll a10, a10 +; CHECK-XTENSA-NEXT: xor a11, a10, a11 +; CHECK-XTENSA-NEXT: l32i.n a12, a9, 0 +; CHECK-XTENSA-NEXT: sll a12, a3 +; CHECK-XTENSA-NEXT: l32i.n a13, a9, 0 +; CHECK-XTENSA-NEXT: and a14, a13, a10 +; CHECK-XTENSA-NEXT: .LBB0_1: # =>This Loop Header: Depth=1 +; CHECK-XTENSA-NEXT: # Child Loop BB0_2 Depth 2 +; CHECK-XTENSA-NEXT: mov.n a13, a14 +; CHECK-XTENSA-NEXT: memw +; CHECK-XTENSA-NEXT: l32i.n a14, a9, 0 +; CHECK-XTENSA-NEXT: and a7, a14, a11 +; CHECK-XTENSA-NEXT: .LBB0_2: # Parent Loop BB0_1 Depth=1 +; CHECK-XTENSA-NEXT: # => This Inner Loop Header: Depth=2 +; CHECK-XTENSA-NEXT: mov.n a15, a7 +; CHECK-XTENSA-NEXT: or a14, a12, a15 +; CHECK-XTENSA-NEXT: or a7, a13, a15 +; CHECK-XTENSA-NEXT: wsr a7, scompare1 +; CHECK-XTENSA-NEXT: s32c1i a14, a9, 0 +; CHECK-XTENSA-NEXT: beq a7, a14, .LBB0_4 +; CHECK-XTENSA-NEXT: # %bb.3: # in Loop: Header=BB0_2 Depth=2 +; CHECK-XTENSA-NEXT: and a7, a14, a11 +; CHECK-XTENSA-NEXT: bne a7, a15, .LBB0_2 +; CHECK-XTENSA-NEXT: .LBB0_4: # in Loop: Header=BB0_1 Depth=1 +; CHECK-XTENSA-NEXT: and a14, a14, a10 +; CHECK-XTENSA-NEXT: bne a14, a13, .LBB0_1 +; CHECK-XTENSA-NEXT: # %bb.5: +; CHECK-XTENSA-NEXT: ssr a8 +; CHECK-XTENSA-NEXT: srl a8, a14 +; CHECK-XTENSA-NEXT: sext a2, a8, 7 +; CHECK-XTENSA-NEXT: memw +; CHECK-XTENSA-NEXT: retw.n + + %1 = atomicrmw xchg i8* %a, i8 %b seq_cst + ret i8 %1 +} + +define i16 @atomicrmw_xchg_i16_seq_cst(i16* %a, i16 %b) nounwind { +; CHECK-XTENSA-LABEL: atomicrmw_xchg_i16_seq_cst: +; CHECK-XTENSA: # %bb.0: +; CHECK-XTENSA-NEXT: entry a1, 32 +; CHECK-XTENSA-NEXT: memw +; CHECK-XTENSA-NEXT: movi.n a8, 3 +; CHECK-XTENSA-NEXT: and a8, a8, a2 +; CHECK-XTENSA-NEXT: sub a9, a2, a8 +; CHECK-XTENSA-NEXT: slli a8, a8, 3 +; CHECK-XTENSA-NEXT: movi.n a10, 1 +; CHECK-XTENSA-NEXT: slli a10, a10, 16 +; CHECK-XTENSA-NEXT: addi.n a10, a10, -1 +; CHECK-XTENSA-NEXT: ssl a8 +; CHECK-XTENSA-NEXT: movi.n a11, -1 +; CHECK-XTENSA-NEXT: sll a10, a10 +; CHECK-XTENSA-NEXT: xor a11, a10, a11 +; CHECK-XTENSA-NEXT: l32i.n a12, a9, 0 +; CHECK-XTENSA-NEXT: sll a12, a3 +; CHECK-XTENSA-NEXT: l32i.n a13, a9, 0 +; CHECK-XTENSA-NEXT: and a14, a13, a10 +; CHECK-XTENSA-NEXT: .LBB1_1: # =>This Loop Header: Depth=1 +; CHECK-XTENSA-NEXT: # Child Loop BB1_2 Depth 2 +; CHECK-XTENSA-NEXT: mov.n a13, a14 +; CHECK-XTENSA-NEXT: memw +; CHECK-XTENSA-NEXT: l32i.n a14, a9, 0 +; CHECK-XTENSA-NEXT: and a7, a14, a11 +; CHECK-XTENSA-NEXT: .LBB1_2: # Parent Loop BB1_1 Depth=1 +; CHECK-XTENSA-NEXT: # => This Inner Loop Header: Depth=2 +; CHECK-XTENSA-NEXT: mov.n a15, a7 +; CHECK-XTENSA-NEXT: or a14, a12, a15 +; CHECK-XTENSA-NEXT: or a7, a13, a15 +; CHECK-XTENSA-NEXT: wsr a7, scompare1 +; CHECK-XTENSA-NEXT: s32c1i a14, a9, 0 +; CHECK-XTENSA-NEXT: beq a7, a14, .LBB1_4 +; CHECK-XTENSA-NEXT: # %bb.3: # in Loop: Header=BB1_2 Depth=2 +; CHECK-XTENSA-NEXT: and a7, a14, a11 +; CHECK-XTENSA-NEXT: bne a7, a15, .LBB1_2 +; CHECK-XTENSA-NEXT: .LBB1_4: # in Loop: Header=BB1_1 Depth=1 +; CHECK-XTENSA-NEXT: and a14, a14, a10 +; CHECK-XTENSA-NEXT: bne a14, a13, .LBB1_1 +; CHECK-XTENSA-NEXT: # %bb.5: +; CHECK-XTENSA-NEXT: ssr a8 +; CHECK-XTENSA-NEXT: srl a8, a14 +; CHECK-XTENSA-NEXT: sext a2, a8, 15 +; CHECK-XTENSA-NEXT: memw +; CHECK-XTENSA-NEXT: retw.n + + %1 = atomicrmw xchg i16* %a, i16 %b seq_cst + ret i16 %1 +} From d5569e42188867629fa506aeb7a4f2730cb52943 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:22 +0300 Subject: [PATCH 086/150] [Xtensa] Initial porting compiler-rt library for Xtensa. --- compiler-rt/cmake/Modules/CompilerRTUtils.cmake | 2 ++ compiler-rt/cmake/base-config-ix.cmake | 2 ++ compiler-rt/cmake/builtin-config-ix.cmake | 3 ++- compiler-rt/lib/builtins/CMakeLists.txt | 2 ++ compiler-rt/lib/crt/crtbegin.c | 14 ++++++++++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake index 9b5e03a6607ba..325307c6f6621 100644 --- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake @@ -205,6 +205,8 @@ macro(detect_target_arch) add_default_target_arch(sparc) elseif(__WEBASSEMBLY32) add_default_target_arch(wasm32) + elseif(__XTENSA) + add_default_target_arch(xtensa) elseif(__WEBASSEMBLY64) add_default_target_arch(wasm64) elseif(__VE) diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake index 8a6219568b3f4..4d36a435d7f7e 100644 --- a/compiler-rt/cmake/base-config-ix.cmake +++ b/compiler-rt/cmake/base-config-ix.cmake @@ -246,6 +246,8 @@ macro(test_targets) test_target_arch(riscv64 "" "") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32") test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown") + elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "xtensa") + test_target_arch(xtensa "" "--target=xtensa") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64") test_target_arch(wasm64 "" "--target=wasm64-unknown-unknown") elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "ve") diff --git a/compiler-rt/cmake/builtin-config-ix.cmake b/compiler-rt/cmake/builtin-config-ix.cmake index 439abc713bad9..0c40e71d49333 100644 --- a/compiler-rt/cmake/builtin-config-ix.cmake +++ b/compiler-rt/cmake/builtin-config-ix.cmake @@ -60,6 +60,7 @@ set(SPARC sparc) set(SPARCV9 sparcv9) set(WASM32 wasm32) set(WASM64 wasm64) +set(XTENSA xtensa) set(VE ve) if(APPLE) @@ -72,7 +73,7 @@ set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${AVR} ${HEXAGON} ${MIPS32} ${MIPS64} ${PPC32} ${PPC64} ${RISCV32} ${RISCV64} ${SPARC} ${SPARCV9} - ${WASM32} ${WASM64} ${VE}) + ${WASM32} ${WASM64} ${VE} ${XTENSA}) include(CompilerRTUtils) include(CompilerRTDarwinUtils) diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index ec668e294d6d7..f4fcbcd4e5713 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -674,6 +674,8 @@ set(riscv64_SOURCES set(sparc_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES}) set(sparcv9_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES}) +set(xtensa_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES}) + set(wasm32_SOURCES ${GENERIC_TF_SOURCES} ${GENERIC_SOURCES} diff --git a/compiler-rt/lib/crt/crtbegin.c b/compiler-rt/lib/crt/crtbegin.c index 7b041ff00b6b6..20de68c4620c3 100644 --- a/compiler-rt/lib/crt/crtbegin.c +++ b/compiler-rt/lib/crt/crtbegin.c @@ -69,6 +69,13 @@ __asm__(".pushsection .init,\"ax\",@progbits\n\t" __asm__(".pushsection .init,\"ax\",@progbits\n\t" "call " __USER_LABEL_PREFIX__ "__do_init\n\t" ".popsection"); +#elif defined(__xtensa__) +__asm__(".pushsection .init.literal,\"ax\",@progbits\n\t" + ".popsection\n\t" + ".pushsection .init,\"ax\",@progbits\n\t" + "movi a8, __do_init\n\t" + "callx8 a8\n\t" + ".popsection"); #else #error "crtbegin without .init_fini array unimplemented for this architecture" #endif // CRT_HAS_INITFINI_ARRAY @@ -122,6 +129,13 @@ __asm__(".pushsection .fini,\"ax\",@progbits\n\t" __asm__(".pushsection .fini,\"ax\",@progbits\n\t" "call " __USER_LABEL_PREFIX__ "__do_fini\n\t" ".popsection"); +#elif defined(__xtensa__) +__asm__(".pushsection .fini.literal,\"ax\",@progbits\n\t" + ".popsection\n\t" + ".pushsection .fini,\"ax\",@progbits\n\t" + "movi a8, __do_fini\n\t" + "callx8 a8\n\t" + ".popsection"); #else #error "crtbegin without .init_fini array unimplemented for this architecture" #endif // CRT_HAS_INIT_FINI_ARRAY From cda3a6005a1ff235bf5734be23cf9c64fbdab95e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:23 +0300 Subject: [PATCH 087/150] [Xtensa] Add support of "-mcpu" option. Implement support of the "-mcpu" option. Support Xtensa features in clang. Add macros definintion in XtensaTargetInfo based on Xtensa features. --- clang/lib/Basic/Targets/Xtensa.cpp | 54 +++++++++++- clang/lib/Basic/Targets/Xtensa.h | 23 +++-- clang/lib/Driver/ToolChains/Clang.cpp | 4 + clang/lib/Driver/ToolChains/Xtensa.cpp | 41 +++++++-- clang/lib/Driver/ToolChains/Xtensa.h | 6 +- clang/test/Driver/xtensa-cpus.c | 36 ++++++++ clang/test/Misc/target-invalid-cpu-note.c | 4 + llvm/include/llvm/Support/TargetParser.h | 48 +++++++++++ .../llvm/Support/XtensaTargetParser.def | 83 +++++++++++++++++++ llvm/include/llvm/module.modulemap | 1 + llvm/lib/Support/TargetParser.cpp | 75 +++++++++++++++++ .../Xtensa/AsmParser/XtensaAsmParser.cpp | 14 ++-- .../Disassembler/XtensaDisassembler.cpp | 8 +- .../MCTargetDesc/XtensaMCTargetDesc.cpp | 4 + llvm/lib/Target/Xtensa/Xtensa.td | 18 ++-- .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 12 ++- 16 files changed, 394 insertions(+), 37 deletions(-) create mode 100644 clang/test/Driver/xtensa-cpus.c create mode 100644 llvm/include/llvm/Support/XtensaTargetParser.def diff --git a/clang/lib/Basic/Targets/Xtensa.cpp b/clang/lib/Basic/Targets/Xtensa.cpp index 2fb0474801b63..feeedd26f62ed 100644 --- a/clang/lib/Basic/Targets/Xtensa.cpp +++ b/clang/lib/Basic/Targets/Xtensa.cpp @@ -28,13 +28,65 @@ const Builtin::Info XtensaTargetInfo::BuiltinInfo[] = { void XtensaTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - Builder.defineMacro("__Xtensa__"); + Builder.defineMacro("__ELF__"); Builder.defineMacro("__xtensa__"); Builder.defineMacro("__XTENSA__"); Builder.defineMacro("__XTENSA_EL__"); + if (HasWindowed) + Builder.defineMacro("__XTENSA_WINDOWED_ABI__"); + else + Builder.defineMacro("__XTENSA_CALL0_ABI__"); + if (!HasFP) + Builder.defineMacro("__XTENSA_SOFT_FLOAT__"); } ArrayRef XtensaTargetInfo::getTargetBuiltins() const { return llvm::makeArrayRef(BuiltinInfo, clang::Xtensa::LastTSBuiltin - Builtin::FirstTSBuiltin); } + +void XtensaTargetInfo::fillValidCPUList( + SmallVectorImpl &Values) const { + llvm::Xtensa::fillValidCPUList(Values); +} + +bool XtensaTargetInfo::initFeatureMap( + llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector &FeaturesVec) const { + + // Assume that by default cpu is esp32 + if (CPU.empty()) + CPU = "esp32"; + + CPU = llvm::Xtensa::getBaseName(CPU); + + SmallVector CPUFeatures; + llvm::Xtensa::getCPUFeatures(CPU, CPUFeatures); + + for (auto Feature : CPUFeatures) + if (Feature[0] == '+') + Features[Feature.drop_front(1)] = true; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +/// Return true if has this feature, need to sync with handleTargetFeatures. +bool XtensaTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch(Feature) + .Case("fp", HasFP) + .Case("windowed", HasWindowed) + .Default(false); +} + +/// Perform initialization based on the user configured set of features. +bool XtensaTargetInfo::handleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+fp") + HasFP = true; + else if (Feature == "+windowed") + HasWindowed = true; + } + + return true; +} diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index 126ad83219486..dde374bea3e61 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -20,6 +20,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TargetParser.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/MacroBuilder.h" @@ -31,6 +32,8 @@ namespace targets { class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; std::string CPU; + bool HasFP = false; + bool HasWindowed = false; public: XtensaTargetInfo(const llvm::Triple &Triple, const TargetOptions &) @@ -94,19 +97,25 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { } bool isValidCPUName(StringRef Name) const override { - return llvm::StringSwitch(Name) - .Case("esp32", true) - .Case("esp8266", true) - .Case("esp32-s2", true) - .Case("esp32-s3", true) - .Case("generic", true) - .Default(false); + return llvm::Xtensa::parseCPUKind(Name) != llvm::Xtensa::CK_INVALID; } bool setCPU(const std::string &Name) override { CPU = Name; return isValidCPUName(Name); } + + void fillValidCPUList(SmallVectorImpl &Values) const override; + + bool + initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector &FeaturesVec) const override; + + bool hasFeature(StringRef Feature) const override; + + bool handleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) override; }; } // namespace targets } // namespace clang diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a95be47dd5aef..3c942922122ef 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -23,6 +23,7 @@ #include "Hexagon.h" #include "MSP430.h" #include "PS4CPU.h" +#include "Xtensa.h" #include "clang/Basic/CLWarnings.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" @@ -371,6 +372,9 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::csky: csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features); break; + case llvm::Triple::xtensa: + xtensa::getXtensaTargetFeatures(D, Args, Features); + break; } for (auto Feature : unifyTargetFeatures(Features)) { diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 4e7d72e821ecc..b758800286ff0 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -20,6 +20,7 @@ #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" #include @@ -43,9 +44,9 @@ XtensaGCCToolchainDetector::XtensaGCCToolchainDetector( if (CPUName.equals("esp32")) ToolchainName = "xtensa-esp32-elf"; - else if (CPUName.equals("esp32-s2")) + else if (CPUName.equals("esp32-s2") || CPUName.equals("esp32s2")) ToolchainName = "xtensa-esp32s2-elf"; - else if (CPUName.equals("esp32-s3")) + else if (CPUName.equals("esp32-s3") || CPUName.equals("esp32s3")) ToolchainName = "xtensa-esp32s3-elf"; else if (CPUName.equals("esp8266")) ToolchainName = "xtensa-lx106-elf"; @@ -151,11 +152,11 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, } Tool *XtensaToolChain::buildLinker() const { - return new tools::Xtensa::Linker(*this); + return new tools::xtensa::Linker(*this); } Tool *XtensaToolChain::buildAssembler() const { - return new tools::Xtensa::Assembler(*this); + return new tools::xtensa::Assembler(*this); } void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -220,7 +221,7 @@ const StringRef XtensaToolChain::GetTargetCPUVersion(const ArgList &Args) { return "esp32"; } -void tools::Xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, +void tools::xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -264,7 +265,7 @@ void tools::Xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, JA, *this, ResponseFileSupport::AtFileCurCP(), Asm, CmdArgs, Inputs)); } -void Xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, +void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -297,3 +298,31 @@ void Xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), CmdArgs, Inputs)); } + +// Get features by CPU name +static void getXtensaFeaturesFromMcpu(const Driver &D, + const llvm::opt::ArgList &Args, + const llvm::opt::Arg *A, StringRef Mcpu, + std::vector &Features) { + if (llvm::Xtensa::parseCPUKind(Mcpu) == llvm::Xtensa::CK_INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + } else { + SmallVector CPUFeatures; + llvm::Xtensa::getCPUFeatures(Mcpu, CPUFeatures); + for (auto &F : CPUFeatures) { + Features.push_back(F); + } + } +} + +// Xtensa target features. +void xtensa::getXtensaTargetFeatures(const Driver &D, const ArgList &Args, + std::vector &Features) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + getXtensaFeaturesFromMcpu(D, Args, A, A->getValue(), Features); + + // Now add any that the user explicitly requested on the command line, + // which may override the defaults. + handleTargetFeaturesGroup(Args, Features, + options::OPT_m_xtensa_Features_Group); +} diff --git a/clang/lib/Driver/ToolChains/Xtensa.h b/clang/lib/Driver/ToolChains/Xtensa.h index 663dc63f6d279..ce6781040c42d 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.h +++ b/clang/lib/Driver/ToolChains/Xtensa.h @@ -61,7 +61,7 @@ class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { } // end namespace toolchains namespace tools { -namespace Xtensa { +namespace xtensa { class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: Linker(const ToolChain &TC) @@ -86,7 +86,9 @@ class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { const char *LinkingOutput) const override; }; -} // end namespace Xtensa +void getXtensaTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector &Features); +} // end namespace xtensa } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/clang/test/Driver/xtensa-cpus.c b/clang/test/Driver/xtensa-cpus.c new file mode 100644 index 0000000000000..7a93f4cba4b0c --- /dev/null +++ b/clang/test/Driver/xtensa-cpus.c @@ -0,0 +1,36 @@ +// Check target CPUs are correctly passed. + +// RUN: %clang -target xtensa -### -c %s 2>&1 -mcpu=esp8266 | FileCheck -check-prefix=MCPU-ESP8266 %s +// MCPU-ESP8266: "-target-cpu" "esp8266" +// MCPU-ESP8266: "-target-feature" "+density" "-target-feature" "+nsa" "-target-feature" "+mul32" "-target-feature" "+extendedl32r" +// MCPU-ESP8266: "-target-feature" "+debug" "-target-feature" "+exception" "-target-feature" "+highpriinterrupts" +// MCPU-ESP8266: "-target-feature" "+interrupt" "-target-feature" "+rvector" "-target-feature" "+timerint" "-target-feature" "+prid" +// MCPU-ESP8266: "-target-feature" "+regprotect" + +// RUN: %clang -target xtensa -### -c %s 2>&1 -mcpu=esp32 | FileCheck -check-prefix=MCPU-ESP32 %s +// MCPU-ESP32: "-target-cpu" "esp32" +// MCPU-ESP32: "-target-feature" "+density" "-target-feature" "+fp" "-target-feature" "+windowed" "-target-feature" "+bool" +// MCPU-ESP32: "-target-feature" "+loop" "-target-feature" "+sext" "-target-feature" "+nsa" "-target-feature" "+mul32" +// MCPU-ESP32: "-target-feature" "+mul32high" "-target-feature" "+div32" "-target-feature" "+mac16" "-target-feature" "+dfpaccel" +// MCPU-ESP32: "-target-feature" "+s32c1i" "-target-feature" "+threadptr" "-target-feature" "+atomctl" "-target-feature" "+memctl" +// MCPU-ESP32: "-target-feature" "+debug" "-target-feature" "+exception" "-target-feature" "+highpriinterrupts" +// MCPU-ESP32: "-target-feature" "+coprocessor" "-target-feature" "+interrupt" "-target-feature" "+rvector" "-target-feature" "+timerint" +// MCPU-ESP32: "-target-feature" "+prid" "-target-feature" "+regprotect" "-target-feature" "+miscsr" + +// RUN: %clang -target xtensa -### -c %s 2>&1 -mcpu=esp32s2 | FileCheck -check-prefix=MCPU-ESP32S2 %s +// MCPU-ESP32S2: "-target-cpu" "esp32s2" +// MCPU-ESP32S2: "-target-feature" "+density" "-target-feature" "+windowed" "-target-feature" "+sext" "-target-feature" "+nsa" +// MCPU-ESP32S2: "-target-feature" "+mul32" "-target-feature" "+mul32high" "-target-feature" "+div32" "-target-feature" "+threadptr" +// MCPU-ESP32S2: "-target-feature" "+memctl" "-target-feature" "+debug" "-target-feature" "+exception" "-target-feature" "+highpriinterrupts" +// MCPU-ESP32S2: "-target-feature" "+coprocessor" "-target-feature" "+interrupt" "-target-feature" "+rvector" "-target-feature" "+timerint" +// MCPU-ESP32S2: "-target-feature" "+prid" "-target-feature" "+regprotect" "-target-feature" "+miscsr" "-target-feature" "+esp32s2" + +// RUN: %clang -target xtensa -### -c %s 2>&1 -mcpu=esp32s3 | FileCheck -check-prefix=MCPU-ESP32S3 %s +// MCPU-ESP32S3: "-target-cpu" "esp32s3" +// MCPU-ESP32S3: "-target-feature" "+density" "-target-feature" "+fp" "-target-feature" "+windowed" "-target-feature" "+bool" +// MCPU-ESP32S3: "-target-feature" "+loop" "-target-feature" "+sext" "-target-feature" "+nsa" "-target-feature" "+mul32" +// MCPU-ESP32S3: "-target-feature" "+mul32high" "-target-feature" "+div32" "-target-feature" "+mac16" "-target-feature" "+dfpaccel" +// MCPU-ESP32S3: "-target-feature" "+s32c1i" "-target-feature" "+threadptr" "-target-feature" "+atomctl" "-target-feature" "+memctl" +// MCPU-ESP32S3: "-target-feature" "+debug" "-target-feature" "+exception" "-target-feature" "+highpriinterrupts" +// MCPU-ESP32S3: "-target-feature" "+coprocessor" "-target-feature" "+interrupt" "-target-feature" "+rvector" "-target-feature" "+timerint" +// MCPU-ESP32S3: "-target-feature" "+prid" "-target-feature" "+regprotect" "-target-feature" "+miscsr" "-target-feature" "+esp32s3" diff --git a/clang/test/Misc/target-invalid-cpu-note.c b/clang/test/Misc/target-invalid-cpu-note.c index 95e24b840145b..67b0cfb195e3e 100644 --- a/clang/test/Misc/target-invalid-cpu-note.c +++ b/clang/test/Misc/target-invalid-cpu-note.c @@ -94,3 +94,7 @@ // RUN: not %clang_cc1 -triple riscv64 -tune-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix TUNE-RISCV64 // TUNE-RISCV64: error: unknown target CPU 'not-a-cpu' // TUNE-RISCV64-NEXT: note: valid target CPU values are: generic-rv64, rocket-rv64, sifive-7-rv64, sifive-s21, sifive-s51, sifive-s54, sifive-s76, sifive-u54, sifive-u74, generic, rocket, sifive-7-series{{$}} + +// RUN: not %clang_cc1 -triple xtensa -tune-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix TUNE-XTENSA +// TUNE-XTENSA: error: unknown target CPU 'not-a-cpu' +// TUNE-XTENSA: note: valid target CPU values are: generic, esp8266, esp32, esp32s2, esp32-s2, esp32s3, esp32-s3 diff --git a/llvm/include/llvm/Support/TargetParser.h b/llvm/include/llvm/Support/TargetParser.h index c3a6cceaee6be..86c1a1f34a095 100644 --- a/llvm/include/llvm/Support/TargetParser.h +++ b/llvm/include/llvm/Support/TargetParser.h @@ -192,6 +192,54 @@ bool parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, } // namespace ARM +namespace Xtensa { + +enum CPUKind : unsigned { +#define XTENSA_CPU(ENUM, NAME, FEATURES) CK_##ENUM, +#include "XtensaTargetParser.def" +}; + +enum FeatureKind : uint64_t { + FK_INVALID = 0, + FK_NONE = 1, + FK_FP = 1 << 1, + FK_WINDOWED = 1 << 2, + FK_BOOLEAN = 1 << 3, + FK_DENSITY = 1 << 4, + FK_LOOP = 1 << 5, + FK_SEXT = 1 << 6, + FK_NSA = 1 << 7, + FK_MUL32 = 1 << 8, + FK_MUL32HIGH = 1 << 9, + FK_DIV32 = 1 << 10, + FK_MAC16 = 1 << 11, + FK_DFPACCEL = 1 << 12, + FK_S32C1I = 1 << 13, + FK_THREADPTR = 1 << 14, + FK_EXTENDEDL32R = 1 << 15, + FK_ATOMCTL = 1 << 16, + FK_MEMCTL = 1 << 17, + FK_DEBUG = 1 << 18, + FK_EXCEPTION = 1 << 19, + FK_HIGHPRIINTERRUPTS = 1 << 20, + FK_COPROCESSOR = 1 << 21, + FK_INTERRUPT = 1 << 22, + FK_RVECTOR = 1 << 23, + FK_TIMERINT = 1 << 24, + FK_PRID = 1 << 25, + FK_REGPROTECT = 1 << 26, + FK_MISCSR = 1 << 27, + FK_ESP32S2OPS = 1 << 28, + FK_ESP32S3OPS = 1 << 29 +}; + +CPUKind parseCPUKind(StringRef CPU); +StringRef getBaseName(StringRef CPU); +void getCPUFeatures(StringRef CPU, SmallVectorImpl &Features); +void fillValidCPUList(SmallVectorImpl &Values); + +} // namespace Xtensa + } // namespace llvm #endif diff --git a/llvm/include/llvm/Support/XtensaTargetParser.def b/llvm/include/llvm/Support/XtensaTargetParser.def new file mode 100644 index 0000000000000..e46020700f2e2 --- /dev/null +++ b/llvm/include/llvm/Support/XtensaTargetParser.def @@ -0,0 +1,83 @@ +//===- XtensaTargetParser.def - Xtensa target parsing defines ---*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides defines to build up the Xtensa target parser's logic. +// +//===----------------------------------------------------------------------===// + +#ifndef XTENSA_FEATURE +#define XTENSA_FEATURE(ID, STR) +#endif + +XTENSA_FEATURE(FK_DENSITY, "density") +XTENSA_FEATURE(FK_FP, "fp") +XTENSA_FEATURE(FK_WINDOWED, "windowed") +XTENSA_FEATURE(FK_BOOLEAN, "bool") +XTENSA_FEATURE(FK_LOOP, "loop") +XTENSA_FEATURE(FK_SEXT, "sext") +XTENSA_FEATURE(FK_NSA, "nsa") +XTENSA_FEATURE(FK_MUL32, "mul32") +XTENSA_FEATURE(FK_MUL32HIGH, "mul32high") +XTENSA_FEATURE(FK_DIV32, "div32") +XTENSA_FEATURE(FK_MAC16, "mac16") +XTENSA_FEATURE(FK_DFPACCEL, "dfpaccel") +XTENSA_FEATURE(FK_S32C1I, "s32c1i") +XTENSA_FEATURE(FK_THREADPTR, "threadptr") +XTENSA_FEATURE(FK_EXTENDEDL32R, "extendedl32r") +XTENSA_FEATURE(FK_ATOMCTL, "atomctl") +XTENSA_FEATURE(FK_MEMCTL, "memctl") +XTENSA_FEATURE(FK_DEBUG, "debug") +XTENSA_FEATURE(FK_EXCEPTION, "exception") +XTENSA_FEATURE(FK_HIGHPRIINTERRUPTS, "highpriinterrupts") +XTENSA_FEATURE(FK_COPROCESSOR, "coprocessor") +XTENSA_FEATURE(FK_INTERRUPT, "interrupt") +XTENSA_FEATURE(FK_RVECTOR, "rvector") +XTENSA_FEATURE(FK_TIMERINT, "timerint") +XTENSA_FEATURE(FK_PRID, "prid") +XTENSA_FEATURE(FK_REGPROTECT, "regprotect") +XTENSA_FEATURE(FK_MISCSR, "miscsr") +XTENSA_FEATURE(FK_ESP32S2OPS, "esp32s2") +XTENSA_FEATURE(FK_ESP32S3OPS, "esp32s3") + +#undef XTENSA_FEATURE + +#ifndef XTENSA_CPU +#define XTENSA_CPU(ENUM, NAME, FEATURES) +#endif + +XTENSA_CPU(INVALID, {"invalid"}, FK_INVALID) +XTENSA_CPU(GENERIC, {"generic"}, FK_NONE) +XTENSA_CPU(ESP8266, {"esp8266"}, + (FK_DENSITY | FK_NSA | FK_MUL32 | FK_EXTENDEDL32R | FK_DEBUG | FK_EXCEPTION | FK_HIGHPRIINTERRUPTS | + FK_INTERRUPT | FK_RVECTOR | FK_TIMERINT | FK_REGPROTECT | FK_PRID)) +XTENSA_CPU(ESP32, {"esp32"}, + (FK_DENSITY | FK_FP | FK_LOOP | FK_MAC16 | FK_WINDOWED | FK_BOOLEAN | + FK_SEXT | FK_NSA | FK_MUL32 | FK_MUL32HIGH | FK_DFPACCEL | FK_S32C1I | FK_THREADPTR | FK_DIV32 | + FK_ATOMCTL | FK_MEMCTL | FK_DEBUG | FK_EXCEPTION | FK_HIGHPRIINTERRUPTS | FK_COPROCESSOR | + FK_INTERRUPT | FK_RVECTOR | FK_TIMERINT | FK_PRID | FK_REGPROTECT | FK_MISCSR)) +XTENSA_CPU(ESP32S2, {"esp32s2"}, + (FK_DENSITY | FK_WINDOWED | FK_SEXT | FK_NSA | FK_MUL32 | FK_MUL32HIGH | FK_THREADPTR | FK_DIV32 | + FK_MEMCTL | FK_DEBUG | FK_EXCEPTION | FK_HIGHPRIINTERRUPTS | FK_COPROCESSOR | FK_INTERRUPT | + FK_RVECTOR | FK_TIMERINT | FK_PRID | FK_REGPROTECT | FK_MISCSR | FK_ESP32S2OPS)) +XTENSA_CPU(ESP32S3, {"esp32s3"}, + (FK_DENSITY | FK_FP | FK_LOOP | FK_MAC16 | FK_WINDOWED | FK_BOOLEAN | + FK_SEXT | FK_NSA | FK_MUL32 | FK_MUL32HIGH | FK_DFPACCEL | FK_S32C1I | FK_THREADPTR | FK_DIV32 | + FK_ATOMCTL | FK_MEMCTL | FK_DEBUG | FK_EXCEPTION | FK_HIGHPRIINTERRUPTS | FK_COPROCESSOR | + FK_INTERRUPT | FK_RVECTOR | FK_TIMERINT | FK_PRID | FK_REGPROTECT | FK_MISCSR | + FK_ESP32S3OPS)) + +#undef XTENSA_CPU + +#ifndef XTENSA_CPU_ALIAS +#define XTENSA_CPU_ALIAS(NAME, ALTNMAME) +#endif + +XTENSA_CPU_ALIAS("esp32s2", "esp32-s2") +XTENSA_CPU_ALIAS("esp32s3", "esp32-s3") + +#undef XTENSA_CPU_ALIAS diff --git a/llvm/include/llvm/module.modulemap b/llvm/include/llvm/module.modulemap index 80e0954242d46..3e40c71acdbd0 100644 --- a/llvm/include/llvm/module.modulemap +++ b/llvm/include/llvm/module.modulemap @@ -419,6 +419,7 @@ module LLVM_Utils { textual header "Support/RISCVTargetParser.def" textual header "Support/TargetOpcodes.def" textual header "Support/X86TargetParser.def" + textual header "Support/XtensaTargetParser.def" } // This part of the module is usable from both C and C++ code. diff --git a/llvm/lib/Support/TargetParser.cpp b/llvm/lib/Support/TargetParser.cpp index e5590d458fedc..80d449590f996 100644 --- a/llvm/lib/Support/TargetParser.cpp +++ b/llvm/lib/Support/TargetParser.cpp @@ -342,6 +342,81 @@ bool getCPUFeaturesExceptStdExt(CPUKind Kind, } } // namespace RISCV + +namespace Xtensa { +struct CPUInfo { + StringLiteral Name; + CPUKind Kind; + uint64_t Features; +}; + +struct FeatureName { + uint64_t ID; + const char *NameCStr; + size_t NameLength; + + StringRef getName() const { return StringRef(NameCStr, NameLength); } +}; + +const FeatureName XtensaFeatureNames[] = { +#define XTENSA_FEATURE(ID, NAME) {ID, "+" NAME, sizeof(NAME)}, +#include "llvm/Support/XtensaTargetParser.def" +}; + +constexpr CPUInfo XtensaCPUInfo[] = { +#define XTENSA_CPU(ENUM, NAME, FEATURES) {NAME, CK_##ENUM, FEATURES}, +#include "llvm/Support/XtensaTargetParser.def" +}; + +StringRef getBaseName(StringRef CPU){ + return llvm::StringSwitch(CPU) +#define XTENSA_CPU_ALIAS(NAME, ANAME) .Case(ANAME, NAME) +#include "llvm/Support/XtensaTargetParser.def" + .Default(CPU); +} + +StringRef getAliasName(StringRef CPU){ + return llvm::StringSwitch(CPU) +#define XTENSA_CPU_ALIAS(NAME, ANAME) .Case(NAME, ANAME) +#include "llvm/Support/XtensaTargetParser.def" + .Default(CPU); +} + +CPUKind parseCPUKind(StringRef CPU) { + CPU = getBaseName(CPU); + return llvm::StringSwitch(CPU) +#define XTENSA_CPU(ENUM, NAME, FEATURES) .Case(NAME, CK_##ENUM) +#include "llvm/Support/XtensaTargetParser.def" + .Default(CK_INVALID); +} + +//Get all features for the CPU +void getCPUFeatures(StringRef CPU, SmallVectorImpl &Features) { + CPU = getBaseName(CPU); + auto I = llvm::find_if(XtensaCPUInfo, + [&](const CPUInfo &CI) { return CI.Name == CPU; }); + assert(I != std::end(XtensaCPUInfo) && "CPU not found!"); + uint64_t Bits = I->Features; + + for (const auto &F : XtensaFeatureNames) { + if ((Bits & F.ID) == F.ID) + Features.push_back(F.getName()); + } +} + +//Find all valid CPUs +void fillValidCPUList(SmallVectorImpl &Values) { + for (const auto &C : XtensaCPUInfo) { + if (C.Kind != CK_INVALID) { + Values.emplace_back(C.Name); + StringRef Name = getAliasName(C.Name); + if (Name != C.Name) + Values.emplace_back(Name); + } + } +} + +} // namespace Xtensa } // namespace llvm // Parse a branch protection specification, which has the form diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 4a399e69b4195..640d708f9f7f9 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -946,8 +946,8 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { unsigned NumTimers = 0; unsigned NumMiscSR = 0; bool IsESP32 = false; - bool IsESP32_S2 = false; - bool IsESP32_S3 = false; + bool IsESP32S2 = false; + bool IsESP32S3 = false; bool Res = true; // Assume that CPU is esp32 by default @@ -956,16 +956,16 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { NumTimers = 3; NumMiscSR = 4; IsESP32 = true; - } else if (CPU == "esp32-s2") { + } else if (CPU == "esp32s2") { NumIntLevels = 6; NumTimers = 3; NumMiscSR = 4; - IsESP32_S2 = true; - } else if (CPU == "esp32-s3") { + IsESP32S2 = true; + } else if (CPU == "esp32s3") { NumIntLevels = 6; NumTimers = 3; NumMiscSR = 4; - IsESP32_S3 = true; + IsESP32S3 = true; } else if (CPU == "esp8266") { NumIntLevels = 2; NumTimers = 1; @@ -1089,7 +1089,7 @@ bool XtensaAsmParser::checkRegister(unsigned RegNo) { Res = hasTHREADPTR(); break; case Xtensa::GPIO_OUT: - Res = IsESP32_S2 || IsESP32_S3; + Res = IsESP32S2 || IsESP32S3; break; case Xtensa::EXPSTATE: Res = IsESP32; diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index cdd871b2a3c07..686454ce793a6 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -153,7 +153,7 @@ bool CheckRegister(unsigned RegNo, MCSubtargetInfo STI) { unsigned NumTimers = 0; unsigned NumMiscSR = 0; bool IsESP32 = false; - bool IsESP32_S2 = false; + bool IsESP32S2 = false; bool Res = true; // Assume that CPU is esp32 by default @@ -162,11 +162,11 @@ bool CheckRegister(unsigned RegNo, MCSubtargetInfo STI) { NumTimers = 3; NumMiscSR = 4; IsESP32 = true; - } else if (CPU == "esp32-s2") { + } else if (CPU == "esp32s2") { NumIntLevels = 6; NumTimers = 3; NumMiscSR = 4; - IsESP32_S2 = true; + IsESP32S2 = true; } else if (CPU == "esp8266") { NumIntLevels = 2; NumTimers = 1; @@ -290,7 +290,7 @@ bool CheckRegister(unsigned RegNo, MCSubtargetInfo STI) { Res = STI.getFeatureBits()[Xtensa::FeatureTHREADPTR]; break; case Xtensa::GPIO_OUT: - Res = IsESP32_S2; + Res = IsESP32S2; break; case Xtensa::EXPSTATE: Res = IsESP32; diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index 61abbc194e183..5e80d8c19aa00 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -66,6 +66,10 @@ static MCSubtargetInfo * createXtensaMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { if (CPU.empty()) CPU = "esp32"; + else if (CPU == "esp32-s2") + CPU = "esp32s2"; + else if (CPU == "esp32-s3") + CPU = "esp32s3"; return createXtensaMCSubtargetInfoImpl(TT, CPU, CPU, FS); } diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index b4256c4dc8145..d230c631257fa 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -184,15 +184,15 @@ def : Proc<"esp32", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC def : Proc<"esp8266", [FeatureDensity, FeatureNSA, FeatureMul16, FeatureMul32, FeatureExtendedL32R, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeatureRegionProtection, FeaturePRID]>; -def : Proc<"esp32-s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureTHREADPTR, - FeatureDiv32, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, - FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, FeatureESP32S2Ops]>; - -def : Proc<"esp32-s3", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, FeatureSEXT, - FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, - FeatureATOMCTL, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, - FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, - FeatureESP32S3Ops]>; +def : Proc<"esp32s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureTHREADPTR, + FeatureDiv32, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, FeatureInterrupt, + FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, FeatureESP32S2Ops]>; + +def : Proc<"esp32s3", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC16, FeatureWindowed, FeatureBoolean, FeatureSEXT, + FeatureNSA, FeatureMul16, FeatureMul32, FeatureMul32High, FeatureDFPAccel, FeatureS32C1I, FeatureTHREADPTR, FeatureDiv32, + FeatureATOMCTL, FeatureMEMCTL, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureCoprocessor, + FeatureInterrupt, FeatureRelocatableVector, FeatureTimerInt, FeaturePRID, FeatureRegionProtection, FeatureMiscSR, + FeatureESP32S3Ops]>; //===----------------------------------------------------------------------===// // Register File Description diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index b8448e1401122..eb190ad853823 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -49,6 +49,16 @@ static std::unique_ptr createTLOF() { return std::make_unique(); } +static StringRef getCPUName(StringRef CPU) { + if (CPU.empty()) + CPU = "esp32"; + else if (CPU == "esp32-s2") + CPU = "esp32s2"; + else if (CPU == "esp32-s3") + CPU = "esp32s3"; + return CPU; +} + XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, @@ -70,7 +80,7 @@ XtensaTargetMachine::XtensaTargetMachine(const Target &T, const Triple &TT, Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT) - : XtensaTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {} + : XtensaTargetMachine(T, TT, getCPUName(CPU), FS, Options, RM, CM, OL, JIT, true) {} const XtensaSubtarget * XtensaTargetMachine::getSubtargetImpl(const Function &F) const { From 7f717202f164c3ba035e7a6a023d07df7bf11461 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:23 +0300 Subject: [PATCH 088/150] [Xtensa] Improve Xtensa multilib support in clang. Use GCCInstallationDetector in Xtensa toolchain instead of XtensaGCCToolchainDetector for initialization of the gcc environment. Add xtensa toolchain test tree with multilib subdirectories. --- clang/lib/Driver/ToolChains/Gnu.cpp | 42 ++++- clang/lib/Driver/ToolChains/Xtensa.cpp | 174 ++++++------------ clang/lib/Driver/ToolChains/Xtensa.h | 23 +-- .../bin/xtensa-esp32-elf-ld | 1 + .../lib/gcc/xtensa-esp32-elf/8.4.0/crtbegin.o | 0 .../lib/gcc/xtensa-esp32-elf/8.4.0/crtend.o | 0 .../8.4.0/esp32-psram/crtbegin.o | 0 .../8.4.0/esp32-psram/crtend.o | 0 .../8.4.0/esp32-psram/no-rtti/crtbegin.o | 0 .../8.4.0/esp32-psram/no-rtti/crtend.o | 0 .../xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o | 0 .../xtensa-esp32-elf/8.4.0/no-rtti/crtend.o | 0 .../xtensa-esp32-elf/lib/crt0.o | 0 .../xtensa-esp32-elf/lib/esp32-psram/crt0.o | 0 .../lib/esp32-psram/no-rtti/crt0.o | 0 .../xtensa-esp32-elf/lib/no-rtti/crt0.o | 0 clang/test/Driver/xtensa-toolchain.c | 42 +++++ 17 files changed, 146 insertions(+), 136 deletions(-) create mode 100755 clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/no-rtti/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/no-rtti/crt0.o create mode 100644 clang/test/Driver/xtensa-toolchain.c diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 868b7e1d2bcfd..79915c9d09f7d 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1761,6 +1761,42 @@ static void findRISCVMultilibs(const Driver &D, Result.Multilibs = RISCVMultilibs; } +static void findXtensaMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, StringRef Path, + const ArgList &Args, DetectedMultilibs &Result) { + + MultilibSet XtensaMultilibs = MultilibSet(); + bool IsESP32 = Args.getLastArgValue(options::OPT_mcpu_EQ, "esp32").equals("esp32"); + + XtensaMultilibs.push_back(Multilib()); + if (IsESP32) + XtensaMultilibs.push_back(Multilib("esp32-psram", {}, {}, 2) + .flag("+mfix-esp32-psram-cache-issue")); + + XtensaMultilibs.push_back( + Multilib("no-rtti", {}, {}, 1).flag("+fno-rtti").flag("-frtti")); + + if (IsESP32) + XtensaMultilibs.push_back(Multilib("esp32-psram/no-rtti", {}, {}, 3) + .flag("+fno-rtti") + .flag("-frtti") + .flag("+mfix-esp32-psram-cache-issue")); + + Multilib::flags_list Flags; + addMultilibFlag( + Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, false), "frtti", + Flags); + + if (IsESP32) + addMultilibFlag(Args.hasFlag(options::OPT_mfix_esp32_psram_cache_issue, + options::OPT_mfix_esp32_psram_cache_issue, + false), + "mfix-esp32-psram-cache-issue", Flags); + + if (XtensaMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = XtensaMultilibs; +} + static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -2305,7 +2341,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "s390x-suse-linux", "s390x-redhat-linux"}; static const char *const XtensaLibDirs[] = {"/lib"}; - static const char *const XtensaTriples[] = {"xtensa-unknown-elf"}; + static const char *const XtensaTriples[] = { + "xtensa-unknown-elf", "xtensa-esp32-elf", "xtensa-esp32s2-elf", + "xtensa-esp32s3-elf"}; using std::begin; using std::end; @@ -2615,6 +2653,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( findMSP430Multilibs(D, TargetTriple, Path, Args, Detected); } else if (TargetArch == llvm::Triple::avr) { // AVR has no multilibs. + } else if (TargetArch == llvm::Triple::xtensa) { + findXtensaMultilibs(D, TargetTriple, Path, Args, Detected); } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, NeedsBiarchSuffix, Detected)) { return false; diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index b758800286ff0..fd41d78eea5b0 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -10,7 +10,6 @@ #include "Xtensa.h" #include "CommonArgs.h" -#include "clang/Driver/InputInfo.h" #include "clang/Basic/Cuda.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" @@ -32,58 +31,26 @@ using namespace llvm::opt; using tools::addMultilibFlag; -XtensaGCCToolchainDetector::XtensaGCCToolchainDetector( - const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args) { - std::string InstalledDir; - InstalledDir = D.getInstalledDir(); - StringRef CPUName = XtensaToolChain::GetTargetCPUVersion(Args); - std::string Dir; - std::string ToolchainName; - std::string ToolchainDir; - - if (CPUName.equals("esp32")) - ToolchainName = "xtensa-esp32-elf"; - else if (CPUName.equals("esp32-s2") || CPUName.equals("esp32s2")) - ToolchainName = "xtensa-esp32s2-elf"; - else if (CPUName.equals("esp32-s3") || CPUName.equals("esp32s3")) - ToolchainName = "xtensa-esp32s3-elf"; - else if (CPUName.equals("esp8266")) - ToolchainName = "xtensa-lx106-elf"; - - Slash = llvm::sys::path::get_separator().str(); - - ToolchainDir = InstalledDir + Slash + ".."; - Dir = ToolchainDir + Slash + "lib" + Slash + "gcc" + Slash + ToolchainName + - Slash; - GCCLibAndIncVersion = ""; - - if (D.getVFS().exists(Dir)) { - std::error_code EC; - for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - auto GCCVersion = Generic_GCC::GCCVersion::Parse(VersionText); - if (GCCVersion.Major == -1) - continue; - GCCLibAndIncVersion = GCCVersion.Text; - } - if (GCCLibAndIncVersion == "") - llvm_unreachable("Unexpected Xtensa GCC toolchain version"); - - } else { - // Unable to find Xtensa GCC toolchain; - GCCToolchainName = ""; - return; - } - GCCToolchainDir = ToolchainDir; - GCCToolchainName = ToolchainName; -} - /// Xtensa Toolchain XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args), XtensaGCCToolchain(D, getTriple(), Args) { + : Generic_ELF(D, Triple, Args) { + + GCCInstallation.init(Triple, Args); + + if (!GCCInstallation.isValid()) { + llvm_unreachable("Unexpected Xtensa GCC toolchain version"); + } + + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilib = GCCInstallation.getMultilib(); + + GCCLibAndIncVersion = GCCInstallation.getVersion().Text; + GCCToolchainName = GCCInstallation.getTriple().str(); + SmallString<128> Path(GCCInstallation.getParentLibPath()); + llvm::sys::path::append(Path, ".."); + GCCToolchainDir = Path.c_str(); + for (auto *A : Args) { std::string Str = A->getAsString(Args); if (!Str.compare("-mlongcalls")) @@ -110,45 +77,18 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, IsIntegratedAsm = false; } - bool IsESP32 = XtensaToolChain::GetTargetCPUVersion(Args).equals("esp32"); - Multilibs.push_back(Multilib()); - if (IsESP32) - Multilibs.push_back(Multilib("esp32-psram", {}, {}, 2) - .flag("+mfix-esp32-psram-cache-issue")); - - Multilibs.push_back( - Multilib("no-rtti", {}, {}, 1).flag("+fno-rtti").flag("-frtti")); - - if (IsESP32) - Multilibs.push_back(Multilib("esp32-psram/no-rtti", {}, {}, 3) - .flag("+fno-rtti") - .flag("-frtti") - .flag("+mfix-esp32-psram-cache-issue")); - - Multilib::flags_list Flags; - addMultilibFlag( - Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, false), "frtti", - Flags); - - if (IsESP32) - addMultilibFlag(Args.hasFlag(options::OPT_mfix_esp32_psram_cache_issue, - options::OPT_mfix_esp32_psram_cache_issue, - false), - "mfix-esp32-psram-cache-issue", Flags); - - Multilibs.select(Flags, SelectedMultilib); - - const std::string Slash = XtensaGCCToolchain.Slash; - std::string Libs = - XtensaGCCToolchain.GCCToolchainDir + Slash + "lib" + Slash + "gcc" + - Slash + XtensaGCCToolchain.GCCToolchainName + Slash + - XtensaGCCToolchain.GCCLibAndIncVersion + SelectedMultilib.gccSuffix(); - getFilePaths().push_back(Libs); - - Libs = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + "lib" + - SelectedMultilib.gccSuffix(); - getFilePaths().push_back(Libs); + SmallString<128> Libs1(GCCToolchainDir); + llvm::sys::path::append(Libs1, "lib", "gcc", GCCToolchainName, + GCCLibAndIncVersion); + if (!SelectedMultilib.gccSuffix().empty()) + llvm::sys::path::append(Libs1, SelectedMultilib.gccSuffix()); + getFilePaths().push_back(Libs1.c_str()); + + SmallString<128> Libs2(GCCToolchainDir); + llvm::sys::path::append(Libs2, GCCToolchainName, "lib"); + if (!SelectedMultilib.gccSuffix().empty()) + llvm::sys::path::append(Libs2, SelectedMultilib.gccSuffix()); + getFilePaths().push_back(Libs2.c_str()); } Tool *XtensaToolChain::buildLinker() const { @@ -165,17 +105,15 @@ void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - if (!XtensaGCCToolchain.IsValid()) + if (!GCCInstallation.isValid()) return; - std::string Slash = XtensaGCCToolchain.Slash; - - std::string Path1 = getDriver().ResourceDir.c_str() + Slash + "include"; - std::string Path2 = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + - "sys-include"; - std::string Path3 = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + "include"; + SmallString<128> Path1(getDriver().ResourceDir); + llvm::sys::path::append(Path1, "include"); + SmallString<128> Path2(GCCToolchainDir); + llvm::sys::path::append(Path2, GCCToolchainName, "sys-include"); + SmallString<128> Path3(GCCToolchainDir); + llvm::sys::path::append(Path3, GCCToolchainName, "include"); const StringRef Paths[] = {Path1, Path2, Path3}; addSystemIncludes(DriverArgs, CC1Args, Paths); @@ -184,20 +122,20 @@ void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void XtensaToolChain::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - if (!XtensaGCCToolchain.IsValid()) + if (!GCCInstallation.isValid()) return; - std::string Slash = XtensaGCCToolchain.Slash; + SmallString<128> BaseDir(GCCToolchainDir); + llvm::sys::path::append(BaseDir, GCCToolchainName, "include", "c++", + GCCLibAndIncVersion); + SmallString<128> TargetDir(BaseDir); + llvm::sys::path::append(TargetDir, GCCToolchainName); + SmallString<128> TargetDirBackward(BaseDir); + llvm::sys::path::append(TargetDirBackward, "backward"); - std::string BaseDir = XtensaGCCToolchain.GCCToolchainDir + Slash + - XtensaGCCToolchain.GCCToolchainName + Slash + - "include" + Slash + "c++" + Slash + - XtensaGCCToolchain.GCCLibAndIncVersion; - std::string TargetDir = BaseDir + Slash + XtensaGCCToolchain.GCCToolchainName; addLibStdCXXIncludePaths(BaseDir, "", "", DriverArgs, CC1Args); addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); - TargetDir = BaseDir + Slash + "backward"; - addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); + addLibStdCXXIncludePaths(TargetDirBackward, "", "", DriverArgs, CC1Args); } ToolChain::CXXStdlibType @@ -229,7 +167,7 @@ void tools::xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const auto &TC = static_cast(getToolChain()); - if (!TC.XtensaGCCToolchain.IsValid()) + if (TC.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC assembler"); claimNoWarnArgs(Args); @@ -256,13 +194,13 @@ void tools::xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - std::string Slash = TC.XtensaGCCToolchain.Slash; + SmallString<128> Asm(TC.GCCToolchainDir); + llvm::sys::path::append(Asm, "bin", + TC.GCCToolchainName + "-" + getShortName()); - const char *Asm = - Args.MakeArgString(getToolChain().getDriver().Dir + Slash + - TC.XtensaGCCToolchain.GCCToolchainName + "-as"); - C.addCommand(std::make_unique( - JA, *this, ResponseFileSupport::AtFileCurCP(), Asm, CmdArgs, Inputs)); + C.addCommand( + std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Asm), CmdArgs, Inputs)); } void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -272,13 +210,13 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const auto &TC = static_cast(getToolChain()); - std::string Slash = TC.XtensaGCCToolchain.Slash; - if (!TC.XtensaGCCToolchain.IsValid()) + if (TC.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC linker"); - std::string Linker = getToolChain().getDriver().Dir + Slash + - TC.XtensaGCCToolchain.GCCToolchainName + "-ld"; + SmallString<128> Linker(TC.GCCToolchainDir); + llvm::sys::path::append(Linker, "bin", + TC.GCCToolchainName + "-" + getShortName()); ArgStringList CmdArgs; Args.AddAllArgs(CmdArgs, options::OPT_L); diff --git a/clang/lib/Driver/ToolChains/Xtensa.h b/clang/lib/Driver/ToolChains/Xtensa.h index ce6781040c42d..0457d23ff42ce 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.h +++ b/clang/lib/Driver/ToolChains/Xtensa.h @@ -20,19 +20,6 @@ namespace clang { namespace driver { namespace toolchains { -class XtensaGCCToolchainDetector { -public: - std::string GCCLibAndIncVersion; - std::string GCCToolchainName; - std::string GCCToolchainDir; - std::string Slash; - - XtensaGCCToolchainDetector(const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args); - - bool IsValid() const { return GCCToolchainName != ""; } -}; - class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { protected: Tool *buildLinker() const override; @@ -49,13 +36,15 @@ class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; bool IsIntegratedAssemblerDefault() const override { - return (IsIntegratedAsm || (XtensaGCCToolchain.GCCToolchainName == "")); + return (IsIntegratedAsm || (GCCToolchainName == "")); } static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); - XtensaGCCToolchainDetector XtensaGCCToolchain; bool IsIntegratedAsm = true; + std::string GCCLibAndIncVersion = ""; + std::string GCCToolchainName = ""; + std::string GCCToolchainDir = ""; }; } // end namespace toolchains @@ -65,7 +54,7 @@ namespace xtensa { class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: Linker(const ToolChain &TC) - : Tool("Xtensa::Linker", "xtensa-esp32-elf-ld", TC) {} + : Tool("Xtensa::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, @@ -77,7 +66,7 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: Assembler(const ToolChain &TC) - : Tool("Xtensa::Assembler", "xtensa-esp32-elf-as", TC) {} + : Tool("Xtensa::Assembler", "as", TC) {} bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld new file mode 100755 index 0000000000000..b23e55619b2ff --- /dev/null +++ b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32-elf-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/esp32-psram/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/esp32-psram/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/lib/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/xtensa-toolchain.c b/clang/test/Driver/xtensa-toolchain.c new file mode 100644 index 0000000000000..245e09902f0f8 --- /dev/null +++ b/clang/test/Driver/xtensa-toolchain.c @@ -0,0 +1,42 @@ +// A basic clang -cc1 command-line, and simple environment check. + +// RUN: %clang %s -### -no-canonical-prefixes -target xtensa \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=CC1 %s +// CC1: clang{{.*}} "-cc1" "-triple" "xtensa" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL %s + +// C-XTENSA-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" +// C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -frtti 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-RTTI %s + +// C-XTENSA-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0" +// C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM %s + +// C-XTENSA-BAREMETAL-PSRAM: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram/no-rtti" +// C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue -frtti 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM-RTTI %s + +// C-XTENSA-BAREMETAL-PSRAM-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram" +// C-XTENSA-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram" From 40266fb7c1ca5b51bd9df27b7ade4d84fa79bce1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:23 +0300 Subject: [PATCH 089/150] [Xtensa]: Add '--rtlib' option support for ESP Xtensa toolchain --- clang/lib/Driver/ToolChains/Xtensa.cpp | 62 ++++++++++++++++++++------ clang/lib/Driver/ToolChains/Xtensa.h | 2 + 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index fd41d78eea5b0..37e05f414934f 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -151,6 +151,11 @@ XtensaToolChain::GetCXXStdlibType(const ArgList &Args) const { return ToolChain::CST_Libstdcxx; } +ToolChain::UnwindLibType +XtensaToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + return ToolChain::UNW_None; +} + const StringRef XtensaToolChain::GetTargetCPUVersion(const ArgList &Args) { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { StringRef CPUName = A->getValue(); @@ -208,33 +213,62 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const auto &TC = - static_cast(getToolChain()); + ArgStringList CmdArgs; + bool WantCRTs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + const auto &ToolChain = + static_cast(getToolChain()); - if (TC.GCCToolchainName == "") + if (ToolChain.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC linker"); - SmallString<128> Linker(TC.GCCToolchainDir); + SmallString<128> Linker(ToolChain.GCCToolchainDir); llvm::sys::path::append(Linker, "bin", - TC.GCCToolchainName + "-" + getShortName()); - ArgStringList CmdArgs; + ToolChain.GCCToolchainName + "-" + getShortName()); - Args.AddAllArgs(CmdArgs, options::OPT_L); - TC.AddFilePathLibArgs(Args, CmdArgs); + const char *crtbegin, *crtend; + auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); + if (RuntimeLib == ToolChain::RLT_Libgcc) { + crtbegin = "crtbegin.o"; + crtend = "crtend.o"; + } else { + assert (RuntimeLib == ToolChain::RLT_CompilerRT); + crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", + ToolChain::FT_Object); + crtend = ToolChain.getCompilerRTArgString(Args, "crtend", + ToolChain::FT_Object); + } + if (WantCRTs) { + // TODO: The crt0.o is not used for esp targets, but maybe used in + // future for other vendors + //CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_u_Group}); + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + } - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - CmdArgs.push_back("-lgcc"); + if (WantCRTs) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand( - std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), - Args.MakeArgString(Linker), CmdArgs, Inputs)); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), + CmdArgs, Inputs)); } // Get features by CPU name diff --git a/clang/lib/Driver/ToolChains/Xtensa.h b/clang/lib/Driver/ToolChains/Xtensa.h index 0457d23ff42ce..d645b55b54765 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.h +++ b/clang/lib/Driver/ToolChains/Xtensa.h @@ -35,6 +35,8 @@ class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + bool IsIntegratedAssemblerDefault() const override { return (IsIntegratedAsm || (GCCToolchainName == "")); } From 921cc56af660658386584c10bb98d92a6a903d0e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:24 +0300 Subject: [PATCH 090/150] [Xtensa]: Add '-fuse-ld' option support to ESP Xtensa toolchain --- clang/lib/Driver/ToolChains/Xtensa.cpp | 11 ++++++++--- clang/test/Driver/xtensa-toolchain.c | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 37e05f414934f..13be071ee1cd8 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -214,6 +214,7 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; + SmallString<128> Linker; bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); const auto &ToolChain = @@ -222,9 +223,13 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (ToolChain.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC linker"); - SmallString<128> Linker(ToolChain.GCCToolchainDir); - llvm::sys::path::append(Linker, "bin", - ToolChain.GCCToolchainName + "-" + getShortName()); + if (Args.hasArg(options::OPT_fuse_ld_EQ)) { + Linker.assign(ToolChain.GetLinkerPath()); + } else { + Linker.assign(ToolChain.GCCToolchainDir); + llvm::sys::path::append(Linker, "bin", + ToolChain.GCCToolchainName + "-" + getShortName()); + } const char *crtbegin, *crtend; auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); diff --git a/clang/test/Driver/xtensa-toolchain.c b/clang/test/Driver/xtensa-toolchain.c index 245e09902f0f8..0570c1d0f0b57 100644 --- a/clang/test/Driver/xtensa-toolchain.c +++ b/clang/test/Driver/xtensa-toolchain.c @@ -5,7 +5,7 @@ // RUN: | FileCheck -check-prefix=CC1 %s // CC1: clang{{.*}} "-cc1" "-triple" "xtensa" -// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: %clang %s -### -no-canonical-prefixes \ // RUN: -target xtensa --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ // RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL %s @@ -14,7 +14,7 @@ // C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" // C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" -// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: %clang %s -### -no-canonical-prefixes \ // RUN: -target xtensa --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -frtti 2>&1 \ // RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-RTTI %s @@ -23,7 +23,7 @@ // C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0" // C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib" -// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: %clang %s -### -no-canonical-prefixes \ // RUN: -target xtensa --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue 2>&1 \ // RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM %s @@ -32,7 +32,7 @@ // C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram/no-rtti" // C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram/no-rtti" -// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: %clang %s -### -no-canonical-prefixes \ // RUN: -target xtensa --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue -frtti 2>&1 \ // RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM-RTTI %s From 445da291acd0eb27fd5136afd14cd1322a0b3e00 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:49 +0300 Subject: [PATCH 091/150] Xtensa] Use B0 register for FP cmp operations. The virtual bool registers allocation from BR class may cause situation when we need to spill such 1-bit registers, this would cause performance degradation due to load/store operations of the 32-bit BR register. The performance improvement from using virtual bool registers is not significant. So, just use only B0 register for FP compare operations. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index e9ae9ddf3e1f5..4b4dd1b3f50e8 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -2052,15 +2052,15 @@ XtensaTargetLowering::emitSelectCC(MachineInstr &MI, (MI.getOpcode() == Xtensa::SELECT_CC_FP_INT)) { int BrKind = 0; int CmpKind = 0; - MachineFunction *MF = BB->getParent(); - MachineRegisterInfo &RegInfo = MF->getRegInfo(); - const TargetRegisterClass *RC = &Xtensa::BRRegClass; - unsigned b = RegInfo.createVirtualRegister(RC); + unsigned b = Xtensa::B0; + GetFPBranchKind(Cond.getImm(), BrKind, CmpKind); BuildMI(BB, DL, TII.get(CmpKind), b) .addReg(LHS.getReg()) .addReg(RHS.getReg()); - BuildMI(BB, DL, TII.get(BrKind)).addReg(b).addMBB(sinkMBB); + BuildMI(BB, DL, TII.get(BrKind)) + .addReg(b, RegState::Kill) + .addMBB(sinkMBB); } else { bool BrInv = false; int BrKind = GetBranchKind(Cond.getImm(), BrInv); @@ -3115,16 +3115,15 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineBasicBlock *TargetBB = MI.getOperand(3).getMBB(); int BrKind = 0; int CmpKind = 0; - MachineFunction *MF = MBB->getParent(); - MachineRegisterInfo &RegInfo = MF->getRegInfo(); - const TargetRegisterClass *RC = &Xtensa::BRRegClass; + unsigned RegB = Xtensa::B0; - unsigned RegB = RegInfo.createVirtualRegister(RC); GetFPBranchKind(Cond.getImm(), BrKind, CmpKind); BuildMI(*MBB, MI, DL, TII.get(CmpKind), RegB) .addReg(LHS.getReg()) .addReg(RHS.getReg()); - BuildMI(*MBB, MI, DL, TII.get(BrKind)).addReg(RegB).addMBB(TargetBB); + BuildMI(*MBB, MI, DL, TII.get(BrKind)) + .addReg(RegB, RegState::Kill) + .addMBB(TargetBB); MI.eraseFromParent(); return MBB; From 141d20ad4a7fb3829d1b0af8be990f4f4a870bb1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:50 +0300 Subject: [PATCH 092/150] ci: add .gitlab-ci.yml to support CI/CD --- .gitlab-ci.yml | 195 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000..94f59533db5ad --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,195 @@ +stages: + - build + - private_deploy + - test + - public_deploy + +image: ${CI_DOCKER_REGISTRY}/llvm-build:3 + +variables: + + CONF_TARGET: "xtensa-esp32-elf" + XTENSA_CLANG_TOOLCHAIN: "${CONF_TARGET}-clang" + PLATFORM_NAME_LINUX: "linux-amd64" + PLATFORM_NAME_WIN: "win64" + PLATFORM_NAME_MACOS: "macos" + + XTENSA_CLANG_TOOLCHAIN_BRANCH: "esp-20220415-r14.0.0" + GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" + + ARCHIVE_TOOL_LINUX: "tar -cJf" + UNARCHIVE_TOOL_LINUX: "tar -xf" + ARCHIVE_EXT_LINUX: "tar.xz" + + ARCHIVE_TOOL_WIN: "zip -9 -r" + UNARCHIVE_TOOL_WIN: "unzip" + ARCHIVE_EXT_WIN: "zip" + + ARCHIVE_TOOL_MACOS: "tar -cJf" + UNARCHIVE_TOOL_MACOS: "tar -xf" + ARCHIVE_EXT_MACOS: "tar.xz" + + DIST_DIR: "dist" + +.use_ci_tools: &use_ci_tools | + curl -sSL ${CIT_LOADER_URL} -o cit_loader.sh && sh cit_loader.sh + source citools/import_functions + +.add_gitlab_key: &add_gitlab_key | + cit_add_ssh_key "${GITLAB_KEY}" + +before_script: + - *use_ci_tools + - *add_gitlab_key + +# Prepare release name/number +.get_release_name: &get_release_name | + # using annotated tags + REL_NUM=$(git describe --abbrev=7) + REL_SFX="llvm14_0_0" + REL_NAME=${CONF_TARGET}-${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} + ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} + echo "CONF_TARGET: $CONF_TARGET" + echo "PLATFORM_NAME: $PLATFORM_NAME" + echo "REL_NUM: $REL_NUM" + echo "REL_NAME: $REL_NAME" + echo "ARCHIVE_NAME: $ARCHIVE_NAME" + +# Get an existing crosstool-ng build for esp32 +.get_gcc_toolchain: &get_gcc_toolchain | + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} + ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} + mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + +.get_clang_toolchain_build_scripts: &get_clang_toolchain_build_scripts | + git clone -b ${XTENSA_CLANG_TOOLCHAIN_BRANCH} ${GITLAB_SSH_SERVER}/${XTENSA_CLANG_TOOLCHAIN_REPO} + cp -r xtensa-clang-toolchain/* . + +# LLVM Build System used the remote address to show detailed version info, we'll change it to the public repository +.fix_origin_remote_for_public: &fix_origin_remote_for_public | + git remote set-url origin "${GH_REPO_HTTPS}" + + # Pack the toolchain +.package_toolchain: &package_toolchain | + ${ARCHIVE_TOOL} ${ARCHIVE_NAME} ${XTENSA_CLANG_TOOLCHAIN}/ + mkdir -p ${DIST_DIR} + mv ${ARCHIVE_NAME} ${DIST_DIR}/ + echo "${ARCHIVE_NAME}" > ${DIST_DIR}/file_${PLATFORM_NAME}_${CONF_TARGET} + +.build_template: + stage: build + tags: [ "amd64", "build" ] + artifacts: + paths: + - ${DIST_DIR}/ + when: always + expire_in: 10 day + script: + - *get_release_name + - *get_gcc_toolchain + - *fix_origin_remote_for_public + - *get_clang_toolchain_build_scripts + - ${BUILD_TOOLCHAIN_CMD} "${XTENSA_CLANG_TOOLCHAIN}" + - *package_toolchain + +linux_amd64_build: + extends: .build_template + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + # a filename was moved here from the global 'variables:' because of GCC_REL_NAME value couldn't be expanded and substituted there + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux.sh" + +win64_build: + extends: .build_template + variables: + PLATFORM_NAME: "${PLATFORM_NAME_WIN}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" + ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-win64.zip" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" + +macos_amd64_build: + extends: .build_template + variables: + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-macos.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh" + +linux_amd64_testsuite: + stage: test + tags: [ "amd64", "build" ] + dependencies: + - linux_amd64_build + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + script: + - *get_release_name + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} + + # getting testsuit + - git clone -b feature/ci_llvm_multitarget --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + + # preparing testsuit + - export PATH=$PATH:${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/ + - cd llvm-xtensa-testsuite + + # qemu + - ./qemu_esp32_install.sh + + # run testsuite for esp32 + - ./run_esp32_tests.sh + +upload_to_http: + stage: private_deploy + when: manual + allow_failure: true + tags: [ "deploy", "shiny" ] + variables: + # force the fetch strategy to clean old archives up in dist/ dir + GIT_STRATEGY: fetch + before_script: + - *use_ci_tools + script: + - cit_add_ssh_key "${HTTP_UPLOAD_KEY}" + # List of archives + - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) + - cd ${DIST_DIR} + - scp ${FILES} ${HTTP_UPLOAD_DIR}/ct-ng/llvm-builds + # Show info + - echo -e "\nArchives were published there:\n\n$(for n in ${FILES}; do echo "${HTTP_PUBLIC_DIR}/ct-ng/llvm-builds/${n}"; done)\n" + +upload_to_github: + stage: public_deploy + when: manual + allow_failure: true + only: + - tags + tags: [ "amd64", "internet" ] + image: espressif/github-hub:2 + variables: + GIT_STRATEGY: fetch + GITHUB_TOKEN: "${GH_TOKEN}" + GITHUB_REPO: "${GH_REPO_HTTPS}" + TAG: "${CI_COMMIT_TAG}" + before_script: [] + script: + - ls -l dist*/ + - git remote add github ${GH_REPO_HTTPS} + - hub release show ${TAG} || { echo "Please create a release on GitHub with ${TAG} tag at first"; exit 1; } + # List of archives + - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) + - cd ${DIST_DIR} + - ls -l $FILES + # Upload archives + - for n in ${FILES}; do hub release edit -m "" -a "${n}" "${TAG}"; done From 692a0ab3191dd5cc4022245a954ccac030216186 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:50 +0300 Subject: [PATCH 093/150] [Xtensa] Fix inline asm Fix inline asm printing of the memory operands. --- .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 9 ------- .../Xtensa/MCTargetDesc/XtensaInstPrinter.h | 3 --- llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 27 +++++++++++-------- llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 1 - llvm/test/CodeGen/Xtensa/inline-asm.ll | 20 ++++++++++++++ 5 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 llvm/test/CodeGen/Xtensa/inline-asm.ll diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index 65da1ec845f07..df5d67501de74 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -26,15 +26,6 @@ using namespace llvm; #include "XtensaGenAsmWriter.inc" -void XtensaInstPrinter::printAddress(unsigned Base, int64_t Disp, - raw_ostream &O) { - O << Disp; - if (Base) { - O << '('; - O << getRegisterName(Base) << ')'; - } -} - static void printExpr(const MCExpr *Expr, raw_ostream &OS) { int Offset = 0; const MCSymbolRefExpr *SRE; diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index b1c6b063aa000..8530c2560968b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -35,9 +35,6 @@ class XtensaInstPrinter : public MCInstPrinter { // Print the given operand. static void printOperand(const MCOperand &MO, raw_ostream &O); - // Print an address - static void printAddress(unsigned Base, int64_t Disp, raw_ostream &O); - // Override MCInstPrinter. void printRegName(raw_ostream &O, unsigned RegNo) const override; void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 14dcda39303e6..7ce99f538091e 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -258,18 +258,23 @@ bool XtensaAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) { - XtensaInstPrinter::printAddress(MI->getOperand(OpNo).getReg(), - MI->getOperand(OpNo + 1).getImm(), OS); - return false; -} + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + + assert(OpNo + 1 < MI->getNumOperands() && "Insufficient operands"); + + const MachineOperand &Base = MI->getOperand(OpNo); + const MachineOperand &Offset = MI->getOperand(OpNo + 1); -void XtensaAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, - raw_ostream &OS) { - OS << '%' - << XtensaInstPrinter::getRegisterName(MI->getOperand(opNum).getReg()); - OS << "("; - OS << MI->getOperand(opNum + 1).getImm(); - OS << ")"; + assert(Base.isReg() && + "Unexpected base pointer for inline asm memory operand."); + assert(Offset.isImm() && "Unexpected offset for inline asm memory operand."); + + OS << XtensaInstPrinter::getRegisterName(Base.getReg()); + OS << ", "; + OS << Offset.getImm(); + + return false; } // Force static initialization. diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h index 50feaa0fcd2c0..e17059a2d4c3b 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -43,7 +43,6 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { const char *ExtraCode, raw_ostream &O) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override; - void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); }; } // end namespace llvm diff --git a/llvm/test/CodeGen/Xtensa/inline-asm.ll b/llvm/test/CodeGen/Xtensa/inline-asm.ll new file mode 100644 index 0000000000000..7a267d5145981 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/inline-asm.ll @@ -0,0 +1,20 @@ +; RUN: llc -mtriple=xtensa -mcpu=esp32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=Xtensa %s + + +define dso_local i32 @test_memptr(i32 noundef %0) local_unnamed_addr #0 { +; Xtensa-LABEL: test_memptr: +; Xtensa: # %bb.0: +; Xtensa-NEXT: entry a1, 32 +; Xtensa-NEXT: #APP +; Xtensa-NEXT: l32i a2, a2, 0 +; Xtensa-NEXT: #NO_APP +; Xtensa-NEXT: retw + %2 = inttoptr i32 %0 to i32* + %3 = call i32 asm sideeffect "l32i $0, $1", "=r,*m"(i32* elementtype(i32) %2) + ret i32 %3 +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind } + From 09fa5765de5e175c975dae0eb42ae88eaea0b2df Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:51 +0300 Subject: [PATCH 094/150] [Xtensa]: Fix handling of empty '-fuse-ld' option for ESP toolchain --- clang/lib/Driver/ToolChains/Xtensa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 13be071ee1cd8..4d2a74070f2d6 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -223,7 +223,7 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (ToolChain.GCCToolchainName == "") llvm_unreachable("Unable to find Xtensa GCC linker"); - if (Args.hasArg(options::OPT_fuse_ld_EQ)) { + if (!Args.getLastArgValue(options::OPT_fuse_ld_EQ).empty()) { Linker.assign(ToolChain.GetLinkerPath()); } else { Linker.assign(ToolChain.GCCToolchainDir); From d575002a41dbb47a0f0453787941b7b16b97aaaa Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:51 +0300 Subject: [PATCH 095/150] esp: Adds support for vendor 'Espressif' to target triple --- clang/lib/Driver/ToolChains/Gnu.cpp | 3 +- clang/lib/Driver/ToolChains/Xtensa.cpp | 14 ++- .../bin/xtensa-esp32s2-elf-ld | 1 + .../bin/xtensa-esp32s3-elf-ld | 1 + .../gcc/xtensa-esp32s2-elf/8.4.0/crtbegin.o | 0 .../lib/gcc/xtensa-esp32s2-elf/8.4.0/crtend.o | 0 .../8.4.0/no-rtti/crtbegin.o | 0 .../xtensa-esp32s2-elf/8.4.0/no-rtti/crtend.o | 0 .../gcc/xtensa-esp32s3-elf/8.4.0/crtbegin.o | 0 .../lib/gcc/xtensa-esp32s3-elf/8.4.0/crtend.o | 0 .../8.4.0/no-rtti/crtbegin.o | 0 .../xtensa-esp32s3-elf/8.4.0/no-rtti/crtend.o | 0 .../xtensa-esp32s2-elf/lib/crt0.o | 0 .../xtensa-esp32s2-elf/lib/no-rtti/crt0.o | 0 .../xtensa-esp32s3-elf/lib/crt0.o | 0 .../xtensa-esp32s3-elf/lib/no-rtti/crt0.o | 0 clang/test/Driver/xtensa-toolchain.c | 105 +++++++++++++----- llvm/include/llvm/ADT/Triple.h | 1 + llvm/lib/Support/Triple.cpp | 2 + 19 files changed, 97 insertions(+), 30 deletions(-) create mode 100755 clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s2-elf-ld create mode 100755 clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s3-elf-ld create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s2-elf/lib/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s2-elf/lib/no-rtti/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s3-elf/lib/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s3-elf/lib/no-rtti/crt0.o diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 79915c9d09f7d..731591a251236 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2342,8 +2342,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const XtensaLibDirs[] = {"/lib"}; static const char *const XtensaTriples[] = { - "xtensa-unknown-elf", "xtensa-esp32-elf", "xtensa-esp32s2-elf", - "xtensa-esp32s3-elf"}; + "xtensa-esp-elf", "xtensa-esp-unknown-elf"}; using std::begin; using std::end; diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 4d2a74070f2d6..efeb4bd8055c2 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -36,8 +36,20 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + std::vector ExtraAliases; + if (Triple.getVendor() == llvm::Triple::Espressif) { + std::string ESPCpuName = "esp32"; + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + ESPCpuName = A->getValue(); + } + ExtraAliases = {std::string("xtensa-") + ESPCpuName + "-elf"}; + if (Args.hasArg(options::OPT_v)) { + llvm::errs() << "Use GCC target extra alias: " << ExtraAliases[0] << "\n"; + } + } + + GCCInstallation.init(Triple, Args, ExtraAliases); if (!GCCInstallation.isValid()) { llvm_unreachable("Unexpected Xtensa GCC toolchain version"); } diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s2-elf-ld b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s2-elf-ld new file mode 100755 index 0000000000000..b23e55619b2ff --- /dev/null +++ b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s2-elf-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s3-elf-ld b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s3-elf-ld new file mode 100755 index 0000000000000..b23e55619b2ff --- /dev/null +++ b/clang/test/Driver/Inputs/multilib_xtensa_tree/bin/xtensa-esp32s3-elf-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s2-elf/lib/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s2-elf/lib/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s2-elf/lib/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s2-elf/lib/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s3-elf/lib/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s3-elf/lib/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s3-elf/lib/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32s3-elf/lib/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/xtensa-toolchain.c b/clang/test/Driver/xtensa-toolchain.c index 0570c1d0f0b57..aa753abcf6366 100644 --- a/clang/test/Driver/xtensa-toolchain.c +++ b/clang/test/Driver/xtensa-toolchain.c @@ -1,42 +1,93 @@ // A basic clang -cc1 command-line, and simple environment check. -// RUN: %clang %s -### -no-canonical-prefixes -target xtensa \ +// RUN: %clang %s -### -no-canonical-prefixes -target xtensa-esp-elf \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ -// RUN: | FileCheck -check-prefix=CC1 %s -// CC1: clang{{.*}} "-cc1" "-triple" "xtensa" +// RUN: | FileCheck -check-prefix=CC1-ESP-DEFAULT %s +// CC1-ESP-DEFAULT: clang{{.*}} "-cc1" "-triple" "xtensa-esp-unknown-elf" -// RUN: %clang %s -### -no-canonical-prefixes \ -// RUN: -target xtensa --rtlib=platform \ +// RUN: %clang %s -### -no-canonical-prefixes -target xtensa-esp-elf -mcpu=esp32\ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ -// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL %s +// RUN: | FileCheck -check-prefix=CC1-ESP32 %s +// CC1-ESP32: clang{{.*}} "-cc1" "-triple" "xtensa-esp-unknown-elf" {{.*}}"-target-cpu" "esp32" -// C-XTENSA-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" -// C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" -// C-XTENSA-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" +// RUN: %clang %s -### -no-canonical-prefixes -target xtensa-esp-elf -mcpu=esp32s2\ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=CC1-ESP32S2 %s +// CC1-ESP32S2: clang{{.*}} "-cc1" "-triple" "xtensa-esp-unknown-elf" {{.*}}"-target-cpu" "esp32s2" + +// RUN: %clang %s -### -no-canonical-prefixes -target xtensa-esp-elf -mcpu=esp32s3\ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=CC1-ESP32S3 %s +// CC1-ESP32S3: clang{{.*}} "-cc1" "-triple" "xtensa-esp-unknown-elf" {{.*}}"-target-cpu" "esp32s3" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32-BAREMETAL %s -// RUN: %clang %s -### -no-canonical-prefixes \ -// RUN: -target xtensa --rtlib=platform \ +// C-XTENSA-ESP32-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-ESP32-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" +// C-XTENSA-ESP32-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -frtti 2>&1 \ -// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-RTTI %s +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32-BAREMETAL-RTTI %s -// C-XTENSA-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" -// C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0" -// C-XTENSA-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib" +// C-XTENSA-ESP32-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-ESP32-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0" +// C-XTENSA-ESP32-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib" -// RUN: %clang %s -### -no-canonical-prefixes \ -// RUN: -target xtensa --rtlib=platform \ +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue 2>&1 \ -// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM %s +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32-BAREMETAL-PSRAM %s -// C-XTENSA-BAREMETAL-PSRAM: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" -// C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram/no-rtti" -// C-XTENSA-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram/no-rtti" +// C-XTENSA-ESP32-BAREMETAL-PSRAM: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-ESP32-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram/no-rtti" +// C-XTENSA-ESP32-BAREMETAL-PSRAM: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram/no-rtti" -// RUN: %clang %s -### -no-canonical-prefixes \ -// RUN: -target xtensa --rtlib=platform \ +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf --rtlib=platform \ // RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -mfix-esp32-psram-cache-issue -frtti 2>&1 \ -// RUN: | FileCheck -check-prefix=C-XTENSA-BAREMETAL-PSRAM-RTTI %s +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32-BAREMETAL-PSRAM-RTTI %s + +// C-XTENSA-ESP32-BAREMETAL-PSRAM-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-ESP32-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram" +// C-XTENSA-ESP32-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf -mcpu=esp32s2 --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32S2-BAREMETAL %s + +// C-XTENSA-ESP32S2-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32s2-elf-ld" +// C-XTENSA-ESP32S2-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32s2-elf{{/|\\\\}}8.4.0/no-rtti" +// C-XTENSA-ESP32S2-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32s2-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf -mcpu=esp32s2 --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -frtti 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32S2-BAREMETAL-RTTI %s + +// C-XTENSA-ESP32S2-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32s2-elf-ld" +// C-XTENSA-ESP32S2-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32s2-elf{{/|\\\\}}8.4.0" +// C-XTENSA-ESP32S2-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s2-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32s2-elf{{/|\\\\}}lib" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf -mcpu=esp32s3 --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32S3-BAREMETAL %s + +// C-XTENSA-ESP32S3-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32s3-elf-ld" +// C-XTENSA-ESP32S3-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32s3-elf{{/|\\\\}}8.4.0/no-rtti" +// C-XTENSA-ESP32S3-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32s3-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang %s -### -no-canonical-prefixes -fuse-ld= \ +// RUN: -target xtensa-esp-elf -mcpu=esp32s3 --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree -frtti 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32S3-BAREMETAL-RTTI %s -// C-XTENSA-BAREMETAL-PSRAM-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" -// C-XTENSA-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/esp32-psram" -// C-XTENSA-BAREMETAL-PSRAM-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/esp32-psram" +// C-XTENSA-ESP32S3-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32s3-elf-ld" +// C-XTENSA-ESP32S3-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32s3-elf{{/|\\\\}}8.4.0" +// C-XTENSA-ESP32S3-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32s3-elf{{/|\\\\}}lib" diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index 71c15b1a86ee6..67085cb99c533 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -177,6 +177,7 @@ class Triple { Mesa, SUSE, OpenEmbedded, + Espressif, LastVendorType = OpenEmbedded }; enum OSType { diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index 9377df8fee9f6..ef934c18d90c6 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -196,6 +196,7 @@ StringRef Triple::getVendorTypeName(VendorType Kind) { case PC: return "pc"; case SCEI: return "scei"; case SUSE: return "suse"; + case Espressif: return "esp"; } llvm_unreachable("Invalid VendorType!"); @@ -548,6 +549,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("mesa", Triple::Mesa) .Case("suse", Triple::SUSE) .Case("oe", Triple::OpenEmbedded) + .Case("esp", Triple::Espressif) .Default(Triple::UnknownVendor); } From ced3ce0c1360206014e151929b944ebf59618992 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:51 +0300 Subject: [PATCH 096/150] esp/riscv: Use GCC assembler for ESP RISCV chips --- clang/lib/Driver/ToolChains/RISCVToolchain.cpp | 1 + clang/lib/Driver/ToolChains/RISCVToolchain.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 3491de22d3719..27fc03fcf5ea5 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -8,6 +8,7 @@ #include "RISCVToolchain.h" #include "CommonArgs.h" +#include "Arch/RISCV.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h index 46b94bdb54e09..dd4437f0a465d 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -35,6 +35,12 @@ class LLVM_LIBRARY_VISIBILITY RISCVToolChain : public Generic_ELF { addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + bool IsIntegratedAssemblerDefault() const override { + if (GCCInstallation.getTriple().getVendor() == llvm::Triple::Espressif) + return false; + return Generic_ELF::IsIntegratedAssemblerDefault(); + } + protected: Tool *buildLinker() const override; From f04f1c1124175ca158871ba3303a6042ce6afbf3 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:52 +0300 Subject: [PATCH 097/150] esp/riscv: Adds support for 'riscv32-esp-elf' target triple --- clang/lib/Driver/ToolChains/Gnu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 731591a251236..71042fff5fbe3 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2322,7 +2322,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const RISCV32LibDirs[] = {"/lib32", "/lib"}; static const char *const RISCV32Triples[] = {"riscv32-unknown-linux-gnu", "riscv32-linux-gnu", - "riscv32-unknown-elf"}; + "riscv32-unknown-elf", + "riscv32-esp-elf", + "riscv32-esp-unknown-elf"}; static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", "riscv64-linux-gnu", From c62fa56f39cc0d9fb9f3024893ba41e9a2baba67 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:52 +0300 Subject: [PATCH 098/150] riscv: Add default multilib. Make '-print-multi-lib' output compatible with GCC --- clang/lib/Driver/ToolChains/Gnu.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 71042fff5fbe3..3335dd960ae67 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1687,6 +1687,10 @@ static void findRISCVBareMetalMultilibs(const Driver &D, {"rv64imafdc", "lp64d"}}; std::vector Ms; + + if (TargetTriple.getVendor() == llvm::Triple::Espressif) + Ms.emplace_back(Multilib({}, {}, {}, -1)); + for (auto Element : RISCVMultilibSet) { // multilib path rule is ${march}/${mabi} Ms.emplace_back( From b18e725ea04290ec41b8dcdbccb98691bf5d81ba Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:53 +0300 Subject: [PATCH 099/150] esp/riscv: Add multilib support for 'riscv32-esp-elf' GCC toolcahin --- clang/lib/Driver/ToolChains/Gnu.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 3335dd960ae67..a23f20e6e5132 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1683,6 +1683,7 @@ static void findRISCVBareMetalMultilibs(const Driver &D, // TODO: support MULTILIB_REUSE constexpr RiscvMultilib RISCVMultilibSet[] = { {"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"}, + {"rv32imc", "ilp32"}, {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, {"rv64imafdc", "lp64d"}}; @@ -1701,14 +1702,23 @@ static void findRISCVBareMetalMultilibs(const Driver &D, MultilibSet RISCVMultilibs = MultilibSet() .Either(ArrayRef(Ms)) - .FilterOut(NonExistent) + .FilterOut(NonExistent); + if (TargetTriple.getVendor() == llvm::Triple::Espressif) { + RISCVMultilibs + .setFilePathsCallback([](const Multilib &M) { + return std::vector( + {M.gccSuffix(), + "/../../../../riscv32-esp-elf/lib" + M.gccSuffix()}); + }); + } else { + RISCVMultilibs .setFilePathsCallback([](const Multilib &M) { return std::vector( {M.gccSuffix(), "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(), "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); }); - + } Multilib::flags_list Flags; llvm::StringSet<> Added_ABIs; From fa0df1887f84390628ec4e2d8b279b2caa7961a1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:33:53 +0300 Subject: [PATCH 100/150] esp/riscv: Add 'libnosys' to linker command line by default Necessary to avoid build failures when build system (e.g. cmake) tries to make simple compiler checks at configuration stage. --- clang/lib/Driver/ToolChains/RISCVToolchain.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 27fc03fcf5ea5..0c65e8df79ee7 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -8,7 +8,6 @@ #include "RISCVToolchain.h" #include "CommonArgs.h" -#include "Arch/RISCV.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" @@ -210,6 +209,9 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--start-group"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgloss"); + if (ToolChain.getTriple().getVendor() == llvm::Triple::Espressif) { + CmdArgs.push_back("-lnosys"); + } CmdArgs.push_back("--end-group"); AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } From ab24392190883697ad7289cc163b74bb8dca5be0 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:26 +0300 Subject: [PATCH 101/150] esp/riscv: Exclude 'crt0.o' from linking in 'freestanding' mode --- clang/lib/Driver/ToolChains/RISCVToolchain.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 0c65e8df79ee7..f71543ac7d303 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -184,7 +184,17 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (WantCRTs) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + /* Espressif toolcahin uses newlib. crt0.o from it refers to 'main' symbol. + In 'freestanding' mode 'main' is not marked as special symbol by clang, + so when compiling C++ program with 'clang++' 'main' gets mmangled + (if not decalred as 'extern "C"' ) and linker can not resolve it. + The problem can happen, for example, when cmake checks C++ compiler by buiding simple C++ code, + unfortunately 'main' function in that code is not decalred as 'extern "C"'. */ + bool Freestanding = + Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false); + if (!Freestanding || ToolChain.getTriple().getVendor() != llvm::Triple::Espressif) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + } CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } From 3a1c604a52305c1296248dd1823d3fb9735070d6 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:27 +0300 Subject: [PATCH 102/150] riscv: Add ESP toolchain tests --- .../bin/riscv32-esp-elf-as | 1 + .../bin/riscv32-esp-elf-ld | 1 + .../lib/gcc/riscv32-esp-elf/8.4.0/crtbegin.o | 0 .../lib/gcc/riscv32-esp-elf/8.4.0/crtend.o | 0 .../8.4.0/rv32i/ilp32/crtbegin.o | 0 .../8.4.0/rv32i/ilp32/crtend.o | 0 .../8.4.0/rv32imac/ilp32/crtbegin.o | 0 .../8.4.0/rv32imac/ilp32/crtend.o | 0 .../8.4.0/rv32imafc/ilp32f/crtbegin.o | 0 .../8.4.0/rv32imafc/ilp32f/crtend.o | 0 .../8.4.0/rv32imc/ilp32/crtbegin.o | 0 .../8.4.0/rv32imc/ilp32/crtend.o | 0 .../riscv32-esp-elf/include/c++/8.4.0/.keep | 0 .../riscv32-esp-elf/lib/crt0.o | 0 .../riscv32-esp-elf/lib/rv32i/ilp32/crt0.o | 0 .../riscv32-esp-elf/lib/rv32imac/ilp32/crt0.o | 0 .../lib/rv32imafc/ilp32f/crt0.o | 0 .../riscv32-esp-elf/lib/rv32imc/ilp32/crt0.o | 0 clang/test/Driver/riscv32-esp-toolchain.c | 306 ++++++++++++++++++ 19 files changed, 308 insertions(+) create mode 100755 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-as create mode 100755 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-ld create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/include/c++/8.4.0/.keep create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32i/ilp32/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imac/ilp32/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imafc/ilp32f/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imc/ilp32/crt0.o create mode 100644 clang/test/Driver/riscv32-esp-toolchain.c diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-as b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-as new file mode 100755 index 0000000000000..b23e55619b2ff --- /dev/null +++ b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-as @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-ld b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-ld new file mode 100755 index 0000000000000..b23e55619b2ff --- /dev/null +++ b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/bin/riscv32-esp-elf-ld @@ -0,0 +1 @@ +#!/bin/true diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/include/c++/8.4.0/.keep b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/include/c++/8.4.0/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32i/ilp32/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32i/ilp32/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imac/ilp32/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imac/ilp32/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imafc/ilp32f/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imafc/ilp32f/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imc/ilp32/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imc/ilp32/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/riscv32-esp-toolchain.c b/clang/test/Driver/riscv32-esp-toolchain.c new file mode 100644 index 0000000000000..5c34c0a3bf7a1 --- /dev/null +++ b/clang/test/Driver/riscv32-esp-toolchain.c @@ -0,0 +1,306 @@ +// A basic clang -cc1 command-line, and simple environment check. + +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk 2>&1 \ +// RUN: | FileCheck -check-prefix=CC1 %s +// CC1: clang{{.*}} "-cc1" "-triple" "riscv32-esp-unknown-elf" + +// Test interaction with -fuse-ld=lld, if lld is available. +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk -fuse-ld=lld 2>&1 \ +// RUN: | FileCheck -check-prefix=LLD %s +// LLD: {{(error: invalid linker name in argument '-fuse-ld=lld')|(ld.lld)}} + +// rv32imac is the default + +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -ffreestanding --rtlib=libgcc --ld-path=riscv32-esp-elf-ld \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk \ +// RUN: --sysroot=%S/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf 2>&1 \ +// RUN: | FileCheck -check-prefix=C-RV32IMAC-BAREMETAL-MULTI-ILP32 %s + +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "-mabi" "ilp32" "-march" "rv32imac" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "--sysroot={{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "-m" "elf32lriscv" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtbegin.o" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// C-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtend.o" + +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -ffreestanding --rtlib=libgcc --ld-path=riscv32-esp-elf-ld \ +// RUN: --sysroot= \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk 2>&1 \ +// RUN: | FileCheck -check-prefix=C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32 %s + +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-mabi" "ilp32" "-march" "rv32imac" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-m" "elf32lriscv" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtbegin.o" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv32-esp-elf/lib" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// C-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtend.o" + +// RUN: %clangxx %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -ffreestanding -stdlib=libstdc++ --rtlib=libgcc --ld-path=riscv32-esp-elf-ld \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk \ +// RUN: --sysroot=%S/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf 2>&1 \ +// RUN: | FileCheck -check-prefix=CXX-RV32IMAC-BAREMETAL-MULTI-ILP32 %s + +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "-internal-isystem" "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/include/c++{{/|\\\\}}8.4.0" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "-mabi" "ilp32" "-march" "rv32imac" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "--sysroot={{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "-m" "elf32lriscv" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtbegin.o" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "-lstdc++" "-lm" "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// CXX-RV32IMAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtend.o" + +// RUN: %clangxx %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -ffreestanding -stdlib=libstdc++ --rtlib=libgcc --ld-path=riscv32-esp-elf-ld \ +// RUN: --sysroot= \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk 2>&1 \ +// RUN: | FileCheck -check-prefix=CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32 %s + +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-internal-isystem" "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv32-esp-elf/include/c++{{/|\\\\}}8.4.0" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-mabi" "ilp32" "-march" "rv32imac" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-m" "elf32lriscv" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtbegin.o" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv32-esp-elf/lib" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-lstdc++" "-lm" "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtend.o" + +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -march=rv32i -mabi=ilp32 \ +// RUN: -ffreestanding --rtlib=libgcc --ld-path=riscv32-esp-elf-ld --sysroot= \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk 2>&1 \ +// RUN: | FileCheck -check-prefix=C-RV32I-BAREMETAL-MULTI-ILP32 %s + +// C-RV32I-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// C-RV32I-BAREMETAL-MULTI-ILP32: "-mabi" "ilp32" "-march" "rv32i" +// C-RV32I-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// C-RV32I-BAREMETAL-MULTI-ILP32: "-m" "elf32lriscv" +// C-RV32I-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32{{/|\\\\}}crtbegin.o" +// C-RV32I-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// C-RV32I-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv32-esp-elf/lib" +// C-RV32I-BAREMETAL-MULTI-ILP32: "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// C-RV32I-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32{{/|\\\\}}crtend.o" + +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -march=rv32imc -mabi=ilp32 \ +// RUN: -ffreestanding --rtlib=libgcc --ld-path=riscv32-esp-elf-ld --sysroot= \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk 2>&1 \ +// RUN: | FileCheck -check-prefix=C-RV32IMC-BAREMETAL-MULTI-ILP32 %s + +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "-mabi" "ilp32" "-march" "rv32imc" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "-m" "elf32lriscv" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32{{/|\\\\}}crtbegin.o" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv32-esp-elf/lib" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// C-RV32IMC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32{{/|\\\\}}crtend.o" + +// RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -march=rv32imafc -mabi=ilp32f \ +// RUN: -ffreestanding --rtlib=libgcc --ld-path=riscv32-esp-elf-ld --sysroot= \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk 2>&1 \ +// RUN: | FileCheck -check-prefix=C-RV32IMAFC-BAREMETAL-MULTI-ILP32F %s + +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "-mabi" "ilp32f" "-march" "rv32imafc" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "-m" "elf32lriscv" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f{{/|\\\\}}crtbegin.o" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv32-esp-elf/lib" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f{{/|\\\\}}crtend.o" + +// RUN: %clang -target riscv32-esp-elf %s -emit-llvm -S -o - | FileCheck %s + +typedef __builtin_va_list va_list; +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __WCHAR_TYPE__ wchar_t; +typedef __WINT_TYPE__ wint_t; + + +// Check Alignments + +// CHECK: @align_c = dso_local global i32 1 +int align_c = __alignof(char); + +// CHECK: @align_s = dso_local global i32 2 +int align_s = __alignof(short); + +// CHECK: @align_i = dso_local global i32 4 +int align_i = __alignof(int); + +// CHECK: @align_wc = dso_local global i32 4 +int align_wc = __alignof(wchar_t); + +// CHECK: @align_wi = dso_local global i32 4 +int align_wi = __alignof(wint_t); + +// CHECK: @align_l = dso_local global i32 4 +int align_l = __alignof(long); + +// CHECK: @align_ll = dso_local global i32 8 +int align_ll = __alignof(long long); + +// CHECK: @align_p = dso_local global i32 4 +int align_p = __alignof(void*); + +// CHECK: @align_f = dso_local global i32 4 +int align_f = __alignof(float); + +// CHECK: @align_d = dso_local global i32 8 +int align_d = __alignof(double); + +// CHECK: @align_ld = dso_local global i32 16 +int align_ld = __alignof(long double); + +// CHECK: @align_vl = dso_local global i32 4 +int align_vl = __alignof(va_list); + +// CHECK: @align_a_c = dso_local global i32 1 +int align_a_c = __alignof(_Atomic(char)); + +// CHECK: @align_a_s = dso_local global i32 2 +int align_a_s = __alignof(_Atomic(short)); + +// CHECK: @align_a_i = dso_local global i32 4 +int align_a_i = __alignof(_Atomic(int)); + +// CHECK: @align_a_wc = dso_local global i32 4 +int align_a_wc = __alignof(_Atomic(wchar_t)); + +// CHECK: @align_a_wi = dso_local global i32 4 +int align_a_wi = __alignof(_Atomic(wint_t)); + +// CHECK: @align_a_l = dso_local global i32 4 +int align_a_l = __alignof(_Atomic(long)); + +// CHECK: @align_a_ll = dso_local global i32 8 +int align_a_ll = __alignof(_Atomic(long long)); + +// CHECK: @align_a_p = dso_local global i32 4 +int align_a_p = __alignof(_Atomic(void*)); + +// CHECK: @align_a_f = dso_local global i32 4 +int align_a_f = __alignof(_Atomic(float)); + +// CHECK: @align_a_d = dso_local global i32 8 +int align_a_d = __alignof(_Atomic(double)); + +// CHECK: @align_a_ld = dso_local global i32 16 +int align_a_ld = __alignof(_Atomic(long double)); + +// CHECK: @align_a_s4 = dso_local global i32 4 +int align_a_s4 = __alignof(_Atomic(struct { char s[4]; })); + +// CHECK: @align_a_s8 = dso_local global i32 8 +int align_a_s8 = __alignof(_Atomic(struct { char s[8]; })); + +// CHECK: @align_a_s16 = dso_local global i32 16 +int align_a_s16 = __alignof(_Atomic(struct { char s[16]; })); + +// CHECK: @align_a_s32 = dso_local global i32 1 +int align_a_s32 = __alignof(_Atomic(struct { char s[32]; })); + + +// Check Sizes + +// CHECK: @size_a_c = dso_local global i32 1 +int size_a_c = sizeof(_Atomic(char)); + +// CHECK: @size_a_s = dso_local global i32 2 +int size_a_s = sizeof(_Atomic(short)); + +// CHECK: @size_a_i = dso_local global i32 4 +int size_a_i = sizeof(_Atomic(int)); + +// CHECK: @size_a_wc = dso_local global i32 4 +int size_a_wc = sizeof(_Atomic(wchar_t)); + +// CHECK: @size_a_wi = dso_local global i32 4 +int size_a_wi = sizeof(_Atomic(wint_t)); + +// CHECK: @size_a_l = dso_local global i32 4 +int size_a_l = sizeof(_Atomic(long)); + +// CHECK: @size_a_ll = dso_local global i32 8 +int size_a_ll = sizeof(_Atomic(long long)); + +// CHECK: @size_a_p = dso_local global i32 4 +int size_a_p = sizeof(_Atomic(void*)); + +// CHECK: @size_a_f = dso_local global i32 4 +int size_a_f = sizeof(_Atomic(float)); + +// CHECK: @size_a_d = dso_local global i32 8 +int size_a_d = sizeof(_Atomic(double)); + +// CHECK: @size_a_ld = dso_local global i32 16 +int size_a_ld = sizeof(_Atomic(long double)); + + +// Check types + +// CHECK: zeroext i8 @check_char() +char check_char() { return 0; } + +// CHECK: define dso_local signext i16 @check_short() +short check_short() { return 0; } + +// CHECK: define dso_local i32 @check_int() +int check_int() { return 0; } + +// CHECK: define dso_local i32 @check_wchar_t() +int check_wchar_t() { return 0; } + +// CHECK: define dso_local i32 @check_long() +long check_long() { return 0; } + +// CHECK: define dso_local i64 @check_longlong() +long long check_longlong() { return 0; } + +// CHECK: define dso_local zeroext i8 @check_uchar() +unsigned char check_uchar() { return 0; } + +// CHECK: define dso_local zeroext i16 @check_ushort() +unsigned short check_ushort() { return 0; } + +// CHECK: define dso_local i32 @check_uint() +unsigned int check_uint() { return 0; } + +// CHECK: define dso_local i32 @check_ulong() +unsigned long check_ulong() { return 0; } + +// CHECK: define dso_local i64 @check_ulonglong() +unsigned long long check_ulonglong() { return 0; } + +// CHECK: define dso_local i32 @check_size_t() +size_t check_size_t() { return 0; } + +// CHECK: define dso_local float @check_float() +float check_float() { return 0; } + +// CHECK: define dso_local double @check_double() +double check_double() { return 0; } + +// CHECK: define dso_local fp128 @check_longdouble() +long double check_longdouble() { return 0; } From bad58a079afa762c75254c118a4ada42b2606ca3 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:27 +0300 Subject: [PATCH 103/150] esp/ci: Adds Linux build --- .gitlab-ci.yml | 145 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 114 insertions(+), 31 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 94f59533db5ad..2a7be284f5b86 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,19 +4,26 @@ stages: - test - public_deploy -image: ${CI_DOCKER_REGISTRY}/llvm-build:3 +image: ${CI_DOCKER_REGISTRY}/llvm-build:4-e2c59838 variables: - CONF_TARGET: "xtensa-esp32-elf" - XTENSA_CLANG_TOOLCHAIN: "${CONF_TARGET}-clang" + # move all these to CI/CD settings + GCC_REL_NAME: "esp-2021r2-patch3" + GCC_REL_VER: "gcc8_4_0" + XTENSA_CLANG_TOOLCHAIN_REF: "build_newlib_and_toolchain" + NEWLIB_REPO: "newlib-cygwin" + NEWLIB_REF: "esp_based_on_3_3_0" + BINUTILS_REPO: "binutils-gdb" + BINUTILS_REF: "esp_based_on_binutils-2_35" + XTENSA_OVERLAYS_REPO: "xtensa-overlays" + XTENSA_OVERLAYS_REF: "master" + LLVM_GCC_TESTSUITE_REF: "feature/toolchain_build_script" + PLATFORM_NAME_LINUX: "linux-amd64" PLATFORM_NAME_WIN: "win64" PLATFORM_NAME_MACOS: "macos" - XTENSA_CLANG_TOOLCHAIN_BRANCH: "esp-20220415-r14.0.0" - GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" - ARCHIVE_TOOL_LINUX: "tar -cJf" UNARCHIVE_TOOL_LINUX: "tar -xf" ARCHIVE_EXT_LINUX: "tar.xz" @@ -30,6 +37,15 @@ variables: ARCHIVE_EXT_MACOS: "tar.xz" DIST_DIR: "dist" + DOWNLOADS_DIR: "_downloads" + +########################################################################### +#################### START OF TEMPORARY LEGACY CODE ####################### +# TODO: the code below is to be removed after migration to new build script + CONF_TARGET: "xtensa-esp32-elf" + XTENSA_CLANG_TOOLCHAIN: "${CONF_TARGET}-clang" +##################### END OF TEMPORARY LEGACY CODE ######################## +########################################################################### .use_ci_tools: &use_ci_tools | curl -sSL ${CIT_LOADER_URL} -o cit_loader.sh && sh cit_loader.sh @@ -47,36 +63,108 @@ before_script: # using annotated tags REL_NUM=$(git describe --abbrev=7) REL_SFX="llvm14_0_0" - REL_NAME=${CONF_TARGET}-${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} + REL_NAME=${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} - echo "CONF_TARGET: $CONF_TARGET" echo "PLATFORM_NAME: $PLATFORM_NAME" echo "REL_NUM: $REL_NUM" echo "REL_NAME: $REL_NAME" echo "ARCHIVE_NAME: $ARCHIVE_NAME" -# Get an existing crosstool-ng build for esp32 +# Get an existing crosstool-ng builds for all chips .get_gcc_toolchain: &get_gcc_toolchain | - wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} - ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} - mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + declare -a XTENSA_CPUS=("esp32" + "esp32s2" + "esp32s3") + for ((i = 0; i < ${#XTENSA_CPUS[@]}; i++)); do + XTENSA_CPU=${XTENSA_CPUS[$i]} + GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-linux-amd64.tar.gz + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} + ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} + done; + GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-linux-amd64.tar.gz + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} + ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} .get_clang_toolchain_build_scripts: &get_clang_toolchain_build_scripts | - git clone -b ${XTENSA_CLANG_TOOLCHAIN_BRANCH} ${GITLAB_SSH_SERVER}/${XTENSA_CLANG_TOOLCHAIN_REPO} + git clone -b ${XTENSA_CLANG_TOOLCHAIN_REF} ${GITLAB_SSH_SERVER}/${XTENSA_CLANG_TOOLCHAIN_REPO} cp -r xtensa-clang-toolchain/* . # LLVM Build System used the remote address to show detailed version info, we'll change it to the public repository .fix_origin_remote_for_public: &fix_origin_remote_for_public | git remote set-url origin "${GH_REPO_HTTPS}" - # Pack the toolchain +# Pack the toolchain .package_toolchain: &package_toolchain | + ${ARCHIVE_TOOL} ${ARCHIVE_NAME} esp-elf-clang/ + mkdir -p ${DISTRO_DIR} + mv ${ARCHIVE_NAME} ${DISTRO_DIR}/ + echo "${ARCHIVE_NAME}" > ${DISTRO_DIR}/file_${PLATFORM_NAME} + +.build_template: + stage: build + tags: [ "amd64", "build" ] + artifacts: + paths: + - ${DIST_DIR}/ + - _build_Release/tests.log + when: always + expire_in: 1 day + script: + - *get_release_name + - mkdir ${DOWNLOADS_DIR} + - pushd ${DOWNLOADS_DIR} + - export ESP_GCC_TOOLCHAIN_DIST_BASE=$PWD + - *get_gcc_toolchain + - git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git + - export NEWLIB_PATH=$PWD/${NEWLIB_REPO} + - git clone -b ${BINUTILS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${BINUTILS_REPO}.git + - export BINUTILS_PATH=$PWD/${BINUTILS_REPO} + - git clone -b ${XTENSA_OVERLAYS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${XTENSA_OVERLAYS_REPO}.git + - export XTENSA_OVERLAYS_PATH=$PWD/${XTENSA_OVERLAYS_REPO} + - popd + - *get_clang_toolchain_build_scripts + - *fix_origin_remote_for_public + - export ESP_GCC_TOOLCHAIN_REL_VER=${GCC_REL_NAME} + - export LLVM_PROJECT_PATH=$PWD + - export ESP_CLANG_BUILD_TYPE=Release + - export BUILD_PATH=$PWD/_build_$ESP_CLANG_BUILD_TYPE + - ./build_toolchain.sh 2>&1 > /dev/null + # Run tests as non-root user + # permission tests fail when run by root + - useradd -m test_runner + - chown -R test_runner $BUILD_PATH + - runuser -l test_runner -c 'cmake --build '$BUILD_PATH'/clang --target check-all 2>&1 > '$BUILD_PATH'/tests.log' + - export DISTRO_DIR=$PWD/$DIST_DIR + - pushd $BUILD_PATH + - *package_toolchain + - popd + +########################################################################### +#################### START OF TEMPORARY LEGACY CODE ####################### +# TODO: the code below is to be removed after migration to new build script +.get_release_name_old: &get_release_name_old | + # using annotated tags + REL_NUM=$(git describe --abbrev=7) + REL_SFX="llvm14_0_0" + REL_NAME=${CONF_TARGET}-${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} + ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} + echo "PLATFORM_NAME: $PLATFORM_NAME" + echo "REL_NUM: $REL_NUM" + echo "REL_NAME: $REL_NAME" + echo "ARCHIVE_NAME: $ARCHIVE_NAME" + +.get_gcc_toolchain_old: &get_gcc_toolchain_old | + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} + ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} + mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + +.package_toolchain_old: &package_toolchain_old | ${ARCHIVE_TOOL} ${ARCHIVE_NAME} ${XTENSA_CLANG_TOOLCHAIN}/ mkdir -p ${DIST_DIR} mv ${ARCHIVE_NAME} ${DIST_DIR}/ echo "${ARCHIVE_NAME}" > ${DIST_DIR}/file_${PLATFORM_NAME}_${CONF_TARGET} -.build_template: +.build_template_old: stage: build tags: [ "amd64", "build" ] artifacts: @@ -85,12 +173,14 @@ before_script: when: always expire_in: 10 day script: - - *get_release_name - - *get_gcc_toolchain + - *get_release_name_old + - *get_gcc_toolchain_old - *fix_origin_remote_for_public - *get_clang_toolchain_build_scripts - ${BUILD_TOOLCHAIN_CMD} "${XTENSA_CLANG_TOOLCHAIN}" - - *package_toolchain + - *package_toolchain_old +##################### END OF TEMPORARY LEGACY CODE ######################## +########################################################################### linux_amd64_build: extends: .build_template @@ -99,12 +189,9 @@ linux_amd64_build: ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - # a filename was moved here from the global 'variables:' because of GCC_REL_NAME value couldn't be expanded and substituted there - XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux.sh" win64_build: - extends: .build_template + extends: .build_template_old variables: PLATFORM_NAME: "${PLATFORM_NAME_WIN}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" @@ -114,7 +201,7 @@ win64_build: BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" macos_amd64_build: - extends: .build_template + extends: .build_template_old variables: PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" @@ -136,17 +223,13 @@ linux_amd64_testsuite: script: - *get_release_name - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} - - # getting testsuit - - git clone -b feature/ci_llvm_multitarget --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git - - # preparing testsuit - - export PATH=$PATH:${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/ + # getting testsuite + - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + # preparing testsuite + - export PATH=${PWD}/esp-elf-clang/bin:$PATH - cd llvm-xtensa-testsuite - # qemu - ./qemu_esp32_install.sh - # run testsuite for esp32 - ./run_esp32_tests.sh From 9512846248b86d3f9819fb4233f9a8e2b5b35426 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:28 +0300 Subject: [PATCH 104/150] esp/ci: Adds Mingw32 build --- .gitlab-ci.yml | 145 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 123 insertions(+), 22 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2a7be284f5b86..f2923ed513b84 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,20 +4,21 @@ stages: - test - public_deploy -image: ${CI_DOCKER_REGISTRY}/llvm-build:4-e2c59838 +image: ${CI_DOCKER_REGISTRY}/llvm-build:3 variables: # move all these to CI/CD settings GCC_REL_NAME: "esp-2021r2-patch3" GCC_REL_VER: "gcc8_4_0" - XTENSA_CLANG_TOOLCHAIN_REF: "build_newlib_and_toolchain" NEWLIB_REPO: "newlib-cygwin" NEWLIB_REF: "esp_based_on_3_3_0" BINUTILS_REPO: "binutils-gdb" BINUTILS_REF: "esp_based_on_binutils-2_35" XTENSA_OVERLAYS_REPO: "xtensa-overlays" XTENSA_OVERLAYS_REF: "master" + # TODO: update vars below to tags names after related branches are merged in those repos + XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_14.0.0_gcc_8.4.0" LLVM_GCC_TESTSUITE_REF: "feature/toolchain_build_script" PLATFORM_NAME_LINUX: "linux-amd64" @@ -27,16 +28,20 @@ variables: ARCHIVE_TOOL_LINUX: "tar -cJf" UNARCHIVE_TOOL_LINUX: "tar -xf" ARCHIVE_EXT_LINUX: "tar.xz" + GCC_ARCHIVE_EXT_LINUX: "tar.gz" ARCHIVE_TOOL_WIN: "zip -9 -r" UNARCHIVE_TOOL_WIN: "unzip" ARCHIVE_EXT_WIN: "zip" + GCC_ARCHIVE_EXT_WIN: "zip" ARCHIVE_TOOL_MACOS: "tar -cJf" UNARCHIVE_TOOL_MACOS: "tar -xf" ARCHIVE_EXT_MACOS: "tar.xz" + GCC_ARCHIVE_EXT_MACOS: "tar.gz" DIST_DIR: "dist" + BUILD_DIR: "_build" DOWNLOADS_DIR: "_downloads" ########################################################################### @@ -77,11 +82,11 @@ before_script: "esp32s3") for ((i = 0; i < ${#XTENSA_CPUS[@]}; i++)); do XTENSA_CPU=${XTENSA_CPUS[$i]} - GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-linux-amd64.tar.gz + GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${GCC_ARCHIVE_EXT} wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} done; - GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-linux-amd64.tar.gz + GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${GCC_ARCHIVE_EXT} wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} @@ -95,7 +100,7 @@ before_script: # Pack the toolchain .package_toolchain: &package_toolchain | - ${ARCHIVE_TOOL} ${ARCHIVE_NAME} esp-elf-clang/ + ${ARCHIVE_TOOL} ${ARCHIVE_NAME} esp-clang/ mkdir -p ${DISTRO_DIR} mv ${ARCHIVE_NAME} ${DISTRO_DIR}/ echo "${ARCHIVE_NAME}" > ${DISTRO_DIR}/file_${PLATFORM_NAME} @@ -106,9 +111,15 @@ before_script: artifacts: paths: - ${DIST_DIR}/ - - _build_Release/tests.log + - ${BUILD_DIR}/clang_tests.log + - ${BUILD_DIR}/clang_build.log when: always expire_in: 1 day + variables: + BUILD_TOOLCHAIN_CMD_ARGS: "" + # use separate dist dir for universal toolchain + # TODO: remove this var after switching to universal toolchain builds + DIST_DIR: "dist_new" script: - *get_release_name - mkdir ${DOWNLOADS_DIR} @@ -126,19 +137,99 @@ before_script: - *fix_origin_remote_for_public - export ESP_GCC_TOOLCHAIN_REL_VER=${GCC_REL_NAME} - export LLVM_PROJECT_PATH=$PWD - - export ESP_CLANG_BUILD_TYPE=Release - - export BUILD_PATH=$PWD/_build_$ESP_CLANG_BUILD_TYPE - - ./build_toolchain.sh 2>&1 > /dev/null - # Run tests as non-root user - # permission tests fail when run by root - - useradd -m test_runner - - chown -R test_runner $BUILD_PATH - - runuser -l test_runner -c 'cmake --build '$BUILD_PATH'/clang --target check-all 2>&1 > '$BUILD_PATH'/tests.log' + - export BUILD_PATH=$PWD/${BUILD_DIR} + - mkdir -p ${BUILD_PATH} + - export USE_PARALLEL_LINK_JOBS=2 + - ${BUILD_TOOLCHAIN_CMD} --llvm-path=${LLVM_PROJECT_PATH} --newlib-path=${NEWLIB_PATH} + --gcc-toolchains-path=${ESP_GCC_TOOLCHAIN_DIST_BASE} --binutils-path=${BINUTILS_PATH} + --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_TOOLCHAIN_CMD_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/clang_build.log + # Run unit tests for native build only. + # Run as non-root user because permission tests fail when run by root. + - export BUILD_HOST=$(gcc -dumpmachine) + - export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-Release-${CONF_HOST} + - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then + echo "Run unit tests for native build"; + useradd -m test_runner; + chown -R test_runner ${LLVM_BUILD_PATH}; + touch ${BUILD_PATH}/clang_tests.log; + chmod o+w ${BUILD_PATH}/clang_tests.log; + runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target check-all 2>&1 > '${BUILD_PATH}'/clang_tests.log'; + fi - export DISTRO_DIR=$PWD/$DIST_DIR - - pushd $BUILD_PATH + - pushd ${BUILD_PATH} - *package_toolchain - popd +build_x86_64-linux-gnu: + extends: .build_template + variables: + CONF_HOST: "x86_64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + GCC_ARCHIVE_EXT: "${GCC_ARCHIVE_EXT_LINUX}" + BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" + +build_x86_64-w64-mingw32: + extends: .build_template + needs: + - job: build_x86_64-linux-gnu + before_script: + - *use_ci_tools + - *add_gitlab_key + # get ARCHIVE_NAME for Linux release. Modify vars to make get_release_name working properly + - export PLATFORM_NAME_ORIG=${PLATFORM_NAME} + - export ARCHIVE_EXT_ORIG=${ARCHIVE_EXT} + - export PLATFORM_NAME=${PLATFORM_NAME_LINUX} + - export ARCHIVE_EXT=${ARCHIVE_EXT_LINUX} + - *get_release_name + # restore modified vars + - export PLATFORM_NAME=${PLATFORM_NAME_ORIG} + - export ARCHIVE_EXT=${ARCHIVE_EXT_ORIG} + # unpack Linux release to re-use it as native Clang for Windows build + - mkdir -p esp-clang-${PLATFORM_NAME_LINUX} + - ${UNARCHIVE_TOOL_LINUX} ${DIST_DIR}/${ARCHIVE_NAME} -C esp-clang-${PLATFORM_NAME_LINUX} + # we do not want to keep artifacts from 'x86_64-linux-gnu' job + - rm -rf ${DIST_DIR} + - rm -rf ${BUILD_DIR} + # add build command args speciifc for Windows build + - export BUILD_TOOLCHAIN_CMD_ARGS="--host=${CONF_HOST} --native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" + variables: + CONF_HOST: "x86_64-w64-mingw32" + PLATFORM_NAME: "${PLATFORM_NAME_WIN}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" + ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + GCC_ARCHIVE_EXT: "${GCC_ARCHIVE_EXT_WIN}" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" + +test_x86_64-linux-gnu: + stage: test + tags: [ "amd64", "build" ] + needs: + - job: build_x86_64-linux-gnu + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + # use separate dist dir for universal toolchain + # TODO: remove this var after switching to universal toolchain builds + DIST_DIR: "dist_new" + script: + - *get_release_name + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} + # getting testsuite + - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + # preparing testsuite + - export PATH=${PWD}/esp-clang/bin:$PATH + - cd llvm-xtensa-testsuite + # qemu + - ./qemu_esp32_install.sh + # run testsuite for esp32 + - ./run_esp32_tests.sh + ########################################################################### #################### START OF TEMPORARY LEGACY CODE ####################### # TODO: the code below is to be removed after migration to new build script @@ -172,6 +263,9 @@ before_script: - ${DIST_DIR}/ when: always expire_in: 10 day + variables: + XTENSA_CLANG_TOOLCHAIN_REF: "esp-20220415-r14.0.0" + GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" script: - *get_release_name_old - *get_gcc_toolchain_old @@ -179,16 +273,16 @@ before_script: - *get_clang_toolchain_build_scripts - ${BUILD_TOOLCHAIN_CMD} "${XTENSA_CLANG_TOOLCHAIN}" - *package_toolchain_old -##################### END OF TEMPORARY LEGACY CODE ######################## -########################################################################### linux_amd64_build: - extends: .build_template + extends: .build_template_old variables: PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux.sh" win64_build: extends: .build_template_old @@ -213,26 +307,33 @@ macos_amd64_build: linux_amd64_testsuite: stage: test tags: [ "amd64", "build" ] - dependencies: - - linux_amd64_build + needs: + - job: linux_amd64_build variables: PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" script: - - *get_release_name + - *get_release_name_old - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} + # getting testsuite - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + # preparing testsuite - - export PATH=${PWD}/esp-elf-clang/bin:$PATH + - export PATH=$PATH:${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/ - cd llvm-xtensa-testsuite + # qemu - ./qemu_esp32_install.sh + # run testsuite for esp32 - ./run_esp32_tests.sh +##################### END OF TEMPORARY LEGACY CODE ######################## +########################################################################### + upload_to_http: stage: private_deploy when: manual From a67842f5f11b3e5871dd7548a5849f1b117f1ca9 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:28 +0300 Subject: [PATCH 105/150] [Xtensa] Remove redundant target features --- clang/lib/Driver/ToolChains/Xtensa.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index efeb4bd8055c2..f86a0f014dcec 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -309,9 +309,4 @@ void xtensa::getXtensaTargetFeatures(const Driver &D, const ArgList &Args, std::vector &Features) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) getXtensaFeaturesFromMcpu(D, Args, A, A->getValue(), Features); - - // Now add any that the user explicitly requested on the command line, - // which may override the defaults. - handleTargetFeaturesGroup(Args, Features, - options::OPT_m_xtensa_Features_Group); } From 5420992d068da8b19bb1a65a3ec023dd1ceae1c4 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:29 +0300 Subject: [PATCH 106/150] esp/ci: Upgrade universal toolchain to 'gcc11_2_0-esp-2022r1-RC1' and newlib 4.1.0 --- .gitlab-ci.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f2923ed513b84..025a6c55d42d1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,10 +9,10 @@ image: ${CI_DOCKER_REGISTRY}/llvm-build:3 variables: # move all these to CI/CD settings - GCC_REL_NAME: "esp-2021r2-patch3" - GCC_REL_VER: "gcc8_4_0" + GCC_REL_NAME: "esp-2022r1-RC1" + GCC_REL_VER: "gcc11_2_0" NEWLIB_REPO: "newlib-cygwin" - NEWLIB_REF: "esp_based_on_3_3_0" + NEWLIB_REF: "esp_based_on_4_1_0" BINUTILS_REPO: "binutils-gdb" BINUTILS_REF: "esp_based_on_binutils-2_35" XTENSA_OVERLAYS_REPO: "xtensa-overlays" @@ -28,17 +28,14 @@ variables: ARCHIVE_TOOL_LINUX: "tar -cJf" UNARCHIVE_TOOL_LINUX: "tar -xf" ARCHIVE_EXT_LINUX: "tar.xz" - GCC_ARCHIVE_EXT_LINUX: "tar.gz" ARCHIVE_TOOL_WIN: "zip -9 -r" UNARCHIVE_TOOL_WIN: "unzip" ARCHIVE_EXT_WIN: "zip" - GCC_ARCHIVE_EXT_WIN: "zip" ARCHIVE_TOOL_MACOS: "tar -cJf" UNARCHIVE_TOOL_MACOS: "tar -xf" ARCHIVE_EXT_MACOS: "tar.xz" - GCC_ARCHIVE_EXT_MACOS: "tar.gz" DIST_DIR: "dist" BUILD_DIR: "_build" @@ -82,11 +79,11 @@ before_script: "esp32s3") for ((i = 0; i < ${#XTENSA_CPUS[@]}; i++)); do XTENSA_CPU=${XTENSA_CPUS[$i]} - GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${GCC_ARCHIVE_EXT} + GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${ARCHIVE_EXT} wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} done; - GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${GCC_ARCHIVE_EXT} + GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${ARCHIVE_EXT} wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} @@ -168,7 +165,6 @@ build_x86_64-linux-gnu: ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - GCC_ARCHIVE_EXT: "${GCC_ARCHIVE_EXT_LINUX}" BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" build_x86_64-w64-mingw32: @@ -201,7 +197,6 @@ build_x86_64-w64-mingw32: ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" - GCC_ARCHIVE_EXT: "${GCC_ARCHIVE_EXT_WIN}" BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" test_x86_64-linux-gnu: From 866465c213023006ff918196e481b79712df991e Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:29 +0300 Subject: [PATCH 107/150] esp/ci: Allow failure for universal toolchain builds --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 025a6c55d42d1..81bfcf25648bd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -105,6 +105,7 @@ before_script: .build_template: stage: build tags: [ "amd64", "build" ] + allow_failure: true artifacts: paths: - ${DIST_DIR}/ @@ -202,6 +203,7 @@ build_x86_64-w64-mingw32: test_x86_64-linux-gnu: stage: test tags: [ "amd64", "build" ] + allow_failure: true needs: - job: build_x86_64-linux-gnu variables: From cebbe2d71fa3e81fee8d76705ea02bca78684f53 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:29 +0300 Subject: [PATCH 108/150] [Xtensa] Implement support of the sysroot --- clang/lib/Driver/ToolChains/Xtensa.cpp | 211 +++++++++++------- clang/lib/Driver/ToolChains/Xtensa.h | 3 + .../xtensa-esp32-elf/include/c++/8.4.0/.keep | 0 clang/test/Driver/xtensa-toolchain.c | 32 +++ 4 files changed, 162 insertions(+), 84 deletions(-) create mode 100644 clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/include/c++/8.4.0/.keep diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index f86a0f014dcec..7d76c47b2d755 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -50,57 +50,80 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, } GCCInstallation.init(Triple, Args, ExtraAliases); - if (!GCCInstallation.isValid()) { - llvm_unreachable("Unexpected Xtensa GCC toolchain version"); - } - - Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); - - GCCLibAndIncVersion = GCCInstallation.getVersion().Text; - GCCToolchainName = GCCInstallation.getTriple().str(); - SmallString<128> Path(GCCInstallation.getParentLibPath()); - llvm::sys::path::append(Path, ".."); - GCCToolchainDir = Path.c_str(); - - for (auto *A : Args) { - std::string Str = A->getAsString(Args); - if (!Str.compare("-mlongcalls")) - A->claim(); - if (!Str.compare("-fno-tree-switch-conversion")) - A->claim(); + if (GCCInstallation.isValid()) { + for (auto *A : Args) { + std::string Str = A->getAsString(Args); + if (!Str.compare("-mlongcalls")) + A->claim(); + if (!Str.compare("-fno-tree-switch-conversion")) + A->claim(); + + // Currently don't use integrated assembler for assembler input files + if ((IsIntegratedAsm) && (Str.length() > 2)) { + std::string ExtSubStr = Str.substr(Str.length() - 2); + if (!ExtSubStr.compare(".s")) + IsIntegratedAsm = false; + if (!ExtSubStr.compare(".S")) + IsIntegratedAsm = false; + } + } // Currently don't use integrated assembler for assembler input files - if ((IsIntegratedAsm) && (Str.length() > 2)) { - std::string ExtSubStr = Str.substr(Str.length() - 2); - if (!ExtSubStr.compare(".s")) + if (IsIntegratedAsm) { + if (Args.getLastArgValue(options::OPT_x).equals("assembler")) IsIntegratedAsm = false; - if (!ExtSubStr.compare(".S")) + + if (Args.getLastArgValue(options::OPT_x).equals("assembler-with-cpp")) IsIntegratedAsm = false; } - } - // Currently don't use integrated assembler for assembler input files - if (IsIntegratedAsm) { - if (Args.getLastArgValue(options::OPT_x).equals("assembler")) - IsIntegratedAsm = false; - - if (Args.getLastArgValue(options::OPT_x).equals("assembler-with-cpp")) - IsIntegratedAsm = false; + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilib = GCCInstallation.getMultilib(); + + GCCLibAndIncVersion = GCCInstallation.getVersion().Text; + GCCToolchainName = GCCInstallation.getTriple().str(); + SmallString<128> Path(GCCInstallation.getParentLibPath()); + llvm::sys::path::append(Path, ".."); + GCCToolchainDir = Path.c_str(); + + SmallString<128> Libs1(GCCToolchainDir); + llvm::sys::path::append(Libs1, "lib", "gcc", GCCToolchainName, + GCCLibAndIncVersion); + if (!SelectedMultilib.gccSuffix().empty()) + llvm::sys::path::append(Libs1, SelectedMultilib.gccSuffix()); + getFilePaths().push_back(Libs1.c_str()); + + SmallString<128> Libs2(GCCToolchainDir); + llvm::sys::path::append(Libs2, GCCToolchainName, "lib"); + if (!SelectedMultilib.gccSuffix().empty()) + llvm::sys::path::append(Libs2, SelectedMultilib.gccSuffix()); + getFilePaths().push_back(Libs2.c_str()); + + ToolChain::path_list &PPaths = getProgramPaths(); + // Multilib cross-compiler GCC installations put ld in a triple-prefixed + // directory of the GCC installation parent dir. + StringRef ParentDir = llvm::sys::path::parent_path(GCCInstallation.getParentLibPath()); + + SmallString<128> PathTripleBin(ParentDir); + llvm::sys::path::append(PathTripleBin, GCCInstallation.getTriple().str()); + llvm::sys::path::append(PathTripleBin, "bin"); + PPaths.push_back(PathTripleBin.c_str()); + + SmallString<128> PathBin(ParentDir); + llvm::sys::path::append(PathBin, "bin"); + PPaths.push_back(PathBin.c_str()); + + if (!getDriver().SysRoot.empty()) { + SmallString<128> SysRoot(computeSysRoot()); + llvm::sys::path::append(SysRoot, "lib"); + getFilePaths().push_back(SysRoot.c_str()); + } + } else { + getProgramPaths().push_back(D.Dir); + SmallString<128> SysRoot(computeSysRoot()); + llvm::sys::path::append(SysRoot, "lib"); + getFilePaths().push_back(SysRoot.c_str()); } - - SmallString<128> Libs1(GCCToolchainDir); - llvm::sys::path::append(Libs1, "lib", "gcc", GCCToolchainName, - GCCLibAndIncVersion); - if (!SelectedMultilib.gccSuffix().empty()) - llvm::sys::path::append(Libs1, SelectedMultilib.gccSuffix()); - getFilePaths().push_back(Libs1.c_str()); - - SmallString<128> Libs2(GCCToolchainDir); - llvm::sys::path::append(Libs2, GCCToolchainName, "lib"); - if (!SelectedMultilib.gccSuffix().empty()) - llvm::sys::path::append(Libs2, SelectedMultilib.gccSuffix()); - getFilePaths().push_back(Libs2.c_str()); } Tool *XtensaToolChain::buildLinker() const { @@ -117,18 +140,25 @@ void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - if (!GCCInstallation.isValid()) - return; - - SmallString<128> Path1(getDriver().ResourceDir); - llvm::sys::path::append(Path1, "include"); - SmallString<128> Path2(GCCToolchainDir); - llvm::sys::path::append(Path2, GCCToolchainName, "sys-include"); - SmallString<128> Path3(GCCToolchainDir); - llvm::sys::path::append(Path3, GCCToolchainName, "include"); - - const StringRef Paths[] = {Path1, Path2, Path3}; - addSystemIncludes(DriverArgs, CC1Args, Paths); + if (!getDriver().SysRoot.empty()) { + SmallString<128> Dir(getDriver().SysRoot); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } else if (GCCInstallation.isValid()) { + SmallString<128> Path1(getDriver().ResourceDir); + llvm::sys::path::append(Path1, "include"); + SmallString<128> Path2(GCCToolchainDir); + llvm::sys::path::append(Path2, GCCToolchainName, "sys-include"); + SmallString<128> Path3(GCCToolchainDir); + llvm::sys::path::append(Path3, GCCToolchainName, "include"); + + const StringRef Paths[] = {Path1, Path2, Path3}; + addSystemIncludes(DriverArgs, CC1Args, Paths); + } else { + SmallString<128> Dir(computeSysRoot()); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } } void XtensaToolChain::addLibStdCxxIncludePaths( @@ -137,17 +167,32 @@ void XtensaToolChain::addLibStdCxxIncludePaths( if (!GCCInstallation.isValid()) return; - SmallString<128> BaseDir(GCCToolchainDir); - llvm::sys::path::append(BaseDir, GCCToolchainName, "include", "c++", - GCCLibAndIncVersion); - SmallString<128> TargetDir(BaseDir); - llvm::sys::path::append(TargetDir, GCCToolchainName); - SmallString<128> TargetDirBackward(BaseDir); - llvm::sys::path::append(TargetDirBackward, "backward"); - - addLibStdCXXIncludePaths(BaseDir, "", "", DriverArgs, CC1Args); - addLibStdCXXIncludePaths(TargetDir, "", "", DriverArgs, CC1Args); - addLibStdCXXIncludePaths(TargetDirBackward, "", "", DriverArgs, CC1Args); + const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text, + TripleStr, "", DriverArgs, CC1Args); +} + +std::string XtensaToolChain::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + SmallString<128> SysRootDir; + if (GCCInstallation.isValid()) { + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr); + } else { + // Use the triple as provided to the driver. Unlike the parsed triple + // this has not been normalized to always contain every field. + llvm::sys::path::append(SysRootDir, getDriver().Dir, "..", + getDriver().getTargetTriple()); + } + + if (!llvm::sys::fs::exists(SysRootDir)) + return std::string(); + + return std::string(SysRootDir.str()); } ToolChain::CXXStdlibType @@ -184,9 +229,6 @@ void tools::xtensa::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const auto &TC = static_cast(getToolChain()); - if (TC.GCCToolchainName == "") - llvm_unreachable("Unable to find Xtensa GCC assembler"); - claimNoWarnArgs(Args); ArgStringList CmdArgs; @@ -230,17 +272,18 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); const auto &ToolChain = - static_cast(getToolChain()); + static_cast(getToolChain()); + const Driver &D = ToolChain.getDriver(); - if (ToolChain.GCCToolchainName == "") - llvm_unreachable("Unable to find Xtensa GCC linker"); + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - if (!Args.getLastArgValue(options::OPT_fuse_ld_EQ).empty()) { - Linker.assign(ToolChain.GetLinkerPath()); - } else { + if (ToolChain.GCCToolchainName != "") { Linker.assign(ToolChain.GCCToolchainDir); llvm::sys::path::append(Linker, "bin", ToolChain.GCCToolchainName + "-" + getShortName()); + } else { + Linker.assign(ToolChain.GetLinkerPath()); } const char *crtbegin, *crtend; @@ -249,17 +292,17 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, crtbegin = "crtbegin.o"; crtend = "crtend.o"; } else { - assert (RuntimeLib == ToolChain::RLT_CompilerRT); + assert(RuntimeLib == ToolChain::RLT_CompilerRT); crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object); - crtend = ToolChain.getCompilerRTArgString(Args, "crtend", - ToolChain::FT_Object); + crtend = + ToolChain.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object); } if (WantCRTs) { // TODO: The crt0.o is not used for esp targets, but maybe used in // future for other vendors - //CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + // CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } @@ -270,7 +313,7 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_u_Group}); - + if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) @@ -283,9 +326,9 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique( - JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Linker), CmdArgs, Inputs)); } // Get features by CPU name diff --git a/clang/lib/Driver/ToolChains/Xtensa.h b/clang/lib/Driver/ToolChains/Xtensa.h index d645b55b54765..8f3ed74923ba8 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.h +++ b/clang/lib/Driver/ToolChains/Xtensa.h @@ -47,6 +47,9 @@ class LLVM_LIBRARY_VISIBILITY XtensaToolChain : public Generic_ELF { std::string GCCLibAndIncVersion = ""; std::string GCCToolchainName = ""; std::string GCCToolchainDir = ""; + +private: + std::string computeSysRoot() const override; }; } // end namespace toolchains diff --git a/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/include/c++/8.4.0/.keep b/clang/test/Driver/Inputs/multilib_xtensa_tree/xtensa-esp32-elf/include/c++/8.4.0/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/xtensa-toolchain.c b/clang/test/Driver/xtensa-toolchain.c index aa753abcf6366..7cf4f151de2fc 100644 --- a/clang/test/Driver/xtensa-toolchain.c +++ b/clang/test/Driver/xtensa-toolchain.c @@ -91,3 +91,35 @@ // C-XTENSA-ESP32S3-BAREMETAL-RTTI: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32s3-elf-ld" // C-XTENSA-ESP32S3-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32s3-elf{{/|\\\\}}8.4.0" // C-XTENSA-ESP32S3-BAREMETAL-RTTI: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32s3-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32s3-elf{{/|\\\\}}lib" + +// RUN: %clang %s -### -no-canonical-prefixes \ +// RUN: -target xtensa-esp-elf -mcpu=esp32 --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree \ +// RUN: --sysroot=%S/Inputs/multilib_xtensa_tree/xtensa-esp32-elf 2>&1 \ +// RUN: | FileCheck -check-prefix=C-XTENSA-ESP32-SYSROOT-BAREMETAL %s + +// C-XTENSA-ESP32-SYSROOT-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// C-XTENSA-ESP32-SYSROOT-BAREMETAL: "--sysroot={{.*}}/Inputs/multilib_xtensa_tree/xtensa-esp32-elf" +// C-XTENSA-ESP32-SYSROOT-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" +// C-XTENSA-ESP32-SYSROOT-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang++ %s -### -no-canonical-prefixes \ +// RUN: -target xtensa-esp-elf -mcpu=esp32 -stdlib=libstdc++ --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree 2>&1 \ +// RUN: | FileCheck -check-prefix=CXX-XTENSA-ESP32-BAREMETAL %s + +// CXX-XTENSA-ESP32-BAREMETAL: "-internal-isystem" "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf/include/c++{{/|\\\\}}8.4.0" +// CXX-XTENSA-ESP32-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// CXX-XTENSA-ESP32-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" +// CXX-XTENSA-ESP32-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" + +// RUN: %clang++ %s -### -no-canonical-prefixes \ +// RUN: -target xtensa-esp-elf -mcpu=esp32 -stdlib=libstdc++ --rtlib=platform \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_xtensa_tree \ +// RUN: --sysroot=%S/Inputs/multilib_xtensa_tree/xtensa-esp32-elf 2>&1 \ +// RUN: | FileCheck -check-prefix=CXX-XTENSA-ESP32-SYSROOT-BAREMETAL %s + +// CXX-XTENSA-ESP32-SYSROOT-BAREMETAL: "-internal-isystem" "{{.*}}Inputs/multilib_xtensa_tree/xtensa-esp32-elf/include/c++/8.4.0" +// CXX-XTENSA-ESP32-SYSROOT-BAREMETAL: "{{.*}}Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}xtensa-esp32-elf-ld" +// CXX-XTENSA-ESP32-SYSROOT-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}gcc{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}8.4.0/no-rtti" +// CXX-XTENSA-ESP32-SYSROOT-BAREMETAL: "-L{{.*}}/Inputs/multilib_xtensa_tree/lib/gcc/xtensa-esp32-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}xtensa-esp32-elf{{/|\\\\}}lib/no-rtti" From 15d66652eba7f4ff4540d287af70cf3f8b1e95a1 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:30 +0300 Subject: [PATCH 109/150] [Xtensa] Fix crtbegin/crtend implementation. Add Xtensa to the list of arcthitectures with crt support in compiler_rt. --- compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index a1da35b0ac4b5..43bd0fe449afb 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -16,6 +16,7 @@ set(SPARCV9 sparcv9) set(WASM32 wasm32) set(WASM64 wasm64) set(VE ve) +set(XTENSA xtensa) if(APPLE) set(ARM64 arm64) @@ -25,7 +26,7 @@ endif() set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64} ${RISCV64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} - ${HEXAGON} ${LOONGARCH64}) + ${HEXAGON} ${XTENSA} ${LOONGARCH64}) set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} ${LOONGARCH64}) From a0e6b8fe94cba74f963c435b2faf9b91f9d21083 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:30 +0300 Subject: [PATCH 110/150] [Xtensa] Build compiler-rt libs. Include compiler-rt libs to the esp32 clang toolchains. --- .gitlab-ci.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 81bfcf25648bd..7397e0c2d708c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -244,7 +244,14 @@ test_x86_64-linux-gnu: .get_gcc_toolchain_old: &get_gcc_toolchain_old | wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} - mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + if [[ "$XTENSA_GCC_TOOLCHAIN" == *"linux"* ]]; then + cp -r xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + else + mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz + tar -xf xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz + fi + export GCC_ESP32_LINUX_TOOLCHAIN="xtensa-esp32-elf" .package_toolchain_old: &package_toolchain_old | ${ARCHIVE_TOOL} ${ARCHIVE_NAME} ${XTENSA_CLANG_TOOLCHAIN}/ @@ -261,7 +268,7 @@ test_x86_64-linux-gnu: when: always expire_in: 10 day variables: - XTENSA_CLANG_TOOLCHAIN_REF: "esp-20220415-r14.0.0" + XTENSA_CLANG_TOOLCHAIN_REF: "esp-20220708-r14.0.0" GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" script: - *get_release_name_old @@ -328,6 +335,9 @@ linux_amd64_testsuite: # run testsuite for esp32 - ./run_esp32_tests.sh + # run testsuite for compiler_rt library + - ./run_esp32_crt_tests.sh ../$XTENSA_CLANG_TOOLCHAIN + ##################### END OF TEMPORARY LEGACY CODE ######################## ########################################################################### From 11a06e9df48b9b1475e0e545e84e7c5f3eb8f869 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:31 +0300 Subject: [PATCH 111/150] [Xtensa] Fix ill.n instruction econding --- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 2 +- llvm/test/MC/Xtensa/xtensa-valid-density.s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 46468f0349860..cfe36353b2dad 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1490,7 +1490,7 @@ let isBarrier = 1, isTerminator = 1 in { let s = 0; } - def ILL_N : RRRN_Inst<0x0C, (outs), (ins), + def ILL_N : RRRN_Inst<0x0D, (outs), (ins), "ill.n", []>, Requires<[HasDensity]> { let r = 0xf; let s = 0x0; diff --git a/llvm/test/MC/Xtensa/xtensa-valid-density.s b/llvm/test/MC/Xtensa/xtensa-valid-density.s index fc5457ce82ddc..f4315c61e8efd 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-density.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-density.s @@ -5,5 +5,5 @@ LBL0: # CHECK-INST: ill.n -# CHECK: encoding: [0x6c,0xf0] +# CHECK: encoding: [0x6d,0xf0] ill.n From 31997a798a51e7645ba7767d5ff714ddf096b113 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 31 Aug 2022 12:34:31 +0300 Subject: [PATCH 112/150] ci: add jobs for arm64 toolchains --- .gitlab-ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7397e0c2d708c..1912cea3e4c7c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,6 +21,7 @@ variables: XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_14.0.0_gcc_8.4.0" LLVM_GCC_TESTSUITE_REF: "feature/toolchain_build_script" + PLATFORM_NAME_LINUX_ARM64: "linux-arm64" PLATFORM_NAME_LINUX: "linux-amd64" PLATFORM_NAME_WIN: "win64" PLATFORM_NAME_MACOS: "macos" @@ -244,7 +245,7 @@ test_x86_64-linux-gnu: .get_gcc_toolchain_old: &get_gcc_toolchain_old | wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} - if [[ "$XTENSA_GCC_TOOLCHAIN" == *"linux"* ]]; then + if [[ "$XTENSA_GCC_TOOLCHAIN" == *"linux-amd64"* ]]; then cp -r xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} else mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} @@ -268,7 +269,7 @@ test_x86_64-linux-gnu: when: always expire_in: 10 day variables: - XTENSA_CLANG_TOOLCHAIN_REF: "esp-20220708-r14.0.0" + XTENSA_CLANG_TOOLCHAIN_REF: "esp-20220721-r14.0.0" GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" script: - *get_release_name_old @@ -288,6 +289,17 @@ linux_amd64_build: XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz" BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux.sh" +linux_arm64_build: + extends: .build_template_old + image: $CI_DOCKER_REGISTRY/llvm-build-cross-arm:1 + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-arm64.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux-arm64.sh" + win64_build: extends: .build_template_old variables: @@ -326,7 +338,7 @@ linux_amd64_testsuite: - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git # preparing testsuite - - export PATH=$PATH:${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/ + - export PATH=${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/:$PATH - cd llvm-xtensa-testsuite # qemu From 7415f502a64e7c9ed32a26aaa40d509502865a65 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 2 Sep 2022 02:31:07 +0300 Subject: [PATCH 113/150] [Xtensa] Fix asm parser include files. --- llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 640d708f9f7f9..601a0cdc2a68e 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -16,6 +16,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" From b65d8d1fac5cdb6960215f39581ce7ed4ae26590 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 2 Sep 2022 02:33:43 +0300 Subject: [PATCH 114/150] ci/cd: fix clang version in gitlab-ci.yml --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1912cea3e4c7c..6da427203109c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -65,7 +65,7 @@ before_script: .get_release_name: &get_release_name | # using annotated tags REL_NUM=$(git describe --abbrev=7) - REL_SFX="llvm14_0_0" + REL_SFX="llvm15_0_0" REL_NAME=${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} echo "PLATFORM_NAME: $PLATFORM_NAME" @@ -234,7 +234,7 @@ test_x86_64-linux-gnu: .get_release_name_old: &get_release_name_old | # using annotated tags REL_NUM=$(git describe --abbrev=7) - REL_SFX="llvm14_0_0" + REL_SFX="llvm15_0_0" REL_NAME=${CONF_TARGET}-${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} echo "PLATFORM_NAME: $PLATFORM_NAME" @@ -269,7 +269,7 @@ test_x86_64-linux-gnu: when: always expire_in: 10 day variables: - XTENSA_CLANG_TOOLCHAIN_REF: "esp-20220721-r14.0.0" + XTENSA_CLANG_TOOLCHAIN_REF: "release_esp32_clang_15.0.0_gcc_8.4.0" GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" script: - *get_release_name_old From 60565589c4e015a14fcda79c4434fdc89799d766 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Sun, 4 Sep 2022 17:39:30 +0300 Subject: [PATCH 115/150] [Xtensa] fix compiler-rt crt build script --- compiler-rt/cmake/crt-config-ix.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler-rt/cmake/crt-config-ix.cmake b/compiler-rt/cmake/crt-config-ix.cmake index 78d1a0de1c8a7..be90c090ba726 100644 --- a/compiler-rt/cmake/crt-config-ix.cmake +++ b/compiler-rt/cmake/crt-config-ix.cmake @@ -28,9 +28,10 @@ set(PPC64 powerpc64 powerpc64le) set(RISCV32 riscv32) set(RISCV64 riscv64) set(VE ve) +set(XTENSA xtensa) set(ALL_CRT_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} - ${PPC64} ${RISCV32} ${RISCV64} ${VE} ${HEXAGON}) + ${PPC64} ${RISCV32} ${RISCV64} ${VE} ${HEXAGON} ${XTENSA}) include(CompilerRTUtils) From 03bb3f877333731f1c2ac37e1c71d66ed7ce951c Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 9 Sep 2022 21:32:42 +0300 Subject: [PATCH 116/150] [Xtensa] Implement asm macro for bbci/bbsi. Add bbci.l macro for bbci instructon and bbsi.l for bbsi. --- llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 4 ++++ llvm/test/MC/Xtensa/xtensa-valid.s | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index cfe36353b2dad..1d02caf1cf210 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -433,6 +433,8 @@ def BBCI : RRI8_Inst<0x07, (outs), let imm8 = target; } +def : InstAlias<"bbci.l\t$s, $imm, $target", (BBCI AR:$s, uimm5:$imm, brtarget:$target)>; + def BBSI : RRI8_Inst<0x07, (outs), (ins AR:$s, uimm5:$imm, brtarget:$target), "bbsi\t$s, $imm, $target", []> { @@ -445,6 +447,8 @@ def BBSI : RRI8_Inst<0x07, (outs), let imm8 = target; } +def : InstAlias<"bbsi.l\t$s, $imm, $target", (BBSI AR:$s, uimm5:$imm, brtarget:$target)>; + def : Pat<(brcc SETGT, AR:$s, AR:$t, bb:$target), (BLT AR:$t, AR:$s, bb:$target)>; def : Pat<(brcc SETUGT, AR:$s, AR:$t, bb:$target), diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s index 490d2205990c1..e863718193622 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -51,12 +51,18 @@ bbci a3, 16, LBL0 # CHECK-INST: bbci a3, 16, LBL0 # CHECK: encoding: [0x07,0x73,A] bbci a3, (16), LBL0 +# CHECK-INST: bbci a3, 16, LBL0 +# CHECK: encoding: [0x07,0x73,A] +bbci.l a3, 16, LBL0 # CHECK-INST: bbs a12, a5, LBL0 # CHECK: encoding: [0x57,0xdc,A] bbs a12, a5, LBL0 # CHECK-INST: bbsi a3, 16, LBL0 # CHECK: encoding: [0x07,0xf3,A] bbsi a3, 16, LBL0 +# CHECK-INST: bbsi a3, 16, LBL0 +# CHECK: encoding: [0x07,0xf3,A] +bbsi.l a3, 16, LBL0 # CHECK-INST: bnall a7, a3, LBL0 # CHECK: encoding: [0x37,0xc7,A] bnall a7, a3, LBL0 From 192619b80d475203ec48e0ebfb3e9136df005198 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 9 Sep 2022 21:33:34 +0300 Subject: [PATCH 117/150] [Xtensa] Implement support of literal and region asm directives in asm parser. Implement support of the ".literal" and ".literal_postion" directives in asm parser. Implement support of the regions using ".begin" and ".end" directives, currently only "literal_prefix" region is supported. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 159 +++++++++++++++++- .../MCTargetDesc/XtensaTargetStreamer.cpp | 42 +++-- .../MCTargetDesc/XtensaTargetStreamer.h | 4 + llvm/test/MC/Xtensa/directive-literal.s | 23 +++ llvm/test/MC/Xtensa/directive-region.s | 25 +++ 5 files changed, 237 insertions(+), 16 deletions(-) create mode 100644 llvm/test/MC/Xtensa/directive-literal.s create mode 100644 llvm/test/MC/Xtensa/directive-region.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 601a0cdc2a68e..fe3d8f3d68103 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -23,6 +23,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Casting.h" @@ -33,6 +34,21 @@ using namespace llvm; struct XtensaOperand; class XtensaAsmParser : public MCTargetAsmParser { + // Xtensa GNU assembler supports region definitions using + // .begin and .end directives. Currently only .literal_prefix regions are + // supported. + struct RegionInfo { + public: + SMLoc Loc; + StringRef RegionDirectiveName; + StringRef LiteralPrefixName; + RegionInfo() = default; + RegionInfo( SMLoc L, StringRef DirectiveName, StringRef Name = "") + : Loc(L), RegionDirectiveName(DirectiveName), LiteralPrefixName(Name) {} + }; + + // Stack of active region definitions. + SmallVector RegionInProgress; SMLoc getLoc() const { return getParser().getTok().getLoc(); } @@ -75,6 +91,14 @@ class XtensaAsmParser : public MCTargetAsmParser { } OperandMatchResultTy parsePCRelTarget(OperandVector &Operands); bool checkRegister(unsigned RegNo); + bool parseLiteralDirective(SMLoc L); + bool parseBeginDirective(SMLoc L); + bool parseEndDirective(SMLoc L); + void onEndOfFile() override { + if (!RegionInProgress.empty()) { + Error(RegionInProgress.back().Loc, ".end of region is not found"); + } + } public: enum XtensaMatchResultTy { @@ -938,7 +962,140 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, return false; } -bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } +bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { + MCAsmParser &Parser = getParser(); + MCSymbol *Sym; + const MCExpr *Value; + SMLoc LiteralLoc = getLexer().getLoc(); + XtensaTargetStreamer &TS = this->getTargetStreamer(); + + if (Parser.parseExpression(Value)) + return true; + + const MCSymbolRefExpr *SE = dyn_cast(Value); + if (!SE) + return Error(LiteralLoc, "literal label must be a symbol"); + else { + Sym = getContext().getOrCreateSymbol(SE->getSymbol().getName()); + } + + if (Parser.parseToken(AsmToken::Comma, "expected comma")) + return true; + + SMLoc OpcodeLoc = getLexer().getLoc(); + if (parseOptionalToken(AsmToken::EndOfStatement)) + return Error(OpcodeLoc, "expected value"); + + if (Parser.parseExpression(Value)) + return true; + + TS.emitLiteralLabel(Sym, LiteralLoc); + TS.emitLiteral(Value, LiteralLoc); + + return false; +} + +bool XtensaAsmParser::parseBeginDirective(SMLoc L) { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + SMLoc BeginLoc = getLexer().getLoc(); + XtensaTargetStreamer &TS = this->getTargetStreamer(); + + if (Parser.parseExpression(Value)) + return true; + + const MCSymbolRefExpr *SE = dyn_cast(Value); + if (!SE) + return Error(BeginLoc, "region option must be a symbol"); + + StringRef RegionDirectiveName = SE->getSymbol().getName(); + + if (RegionDirectiveName == "literal_prefix") { + + SMLoc OpcodeLoc = getLexer().getLoc(); + if (parseOptionalToken(AsmToken::EndOfStatement)) + return Error(OpcodeLoc, "expected literal section name"); + + if (Parser.parseExpression(Value)) + return true; + + OpcodeLoc = getLexer().getLoc(); + SE = dyn_cast(Value); + if (!SE) + return Error(OpcodeLoc, "literal_prefix name must be a symbol"); + + StringRef LiteralPrefixName = SE->getSymbol().getName(); + TS.setLiteralSectionPrefix(LiteralPrefixName); + RegionInProgress.emplace_back(BeginLoc, RegionDirectiveName, LiteralPrefixName); + } else { + return Error(BeginLoc, "unsupported region directive"); + } + + return false; +} + +bool XtensaAsmParser::parseEndDirective(SMLoc L) { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + SMLoc EndLoc = getLexer().getLoc(); + XtensaTargetStreamer &TS = this->getTargetStreamer(); + + if (Parser.parseExpression(Value)) + return true; + + const MCSymbolRefExpr *SE = dyn_cast(Value); + if (!SE) + return Error(EndLoc, "region option must be a symbol"); + + StringRef RegionDirectiveName = SE->getSymbol().getName(); + + if (RegionInProgress.empty()) + return Error(EndLoc, ".end of the region without .begin"); + else { + RegionInfo Region = RegionInProgress.pop_back_val(); + + if (RegionInProgress.empty()) + TS.setLiteralSectionPrefix(""); + else + TS.setLiteralSectionPrefix(Region.LiteralPrefixName); + + if (RegionDirectiveName != Region.RegionDirectiveName) { + return Error(EndLoc, ".end directive differs from .begin directive"); + } + } + + // Error: does not match begin literal_prefix + return false; +} + +bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { + StringRef IDVal = DirectiveID.getString(); + SMLoc Loc = getLexer().getLoc(); + + if (IDVal == ".literal_position") { + // We currently push literals in literal section which name depends on name + // of the current section. + // So, assume that we may skip this directive. + return false; + } + + if (IDVal == ".literal") { + parseLiteralDirective(Loc); + return false; + } + + if (IDVal == ".begin") { + parseBeginDirective(Loc); + return false; + } + + if (IDVal == ".end") { + parseEndDirective(Loc); + return false; + } + + return true; +} // Verify SR and UR bool XtensaAsmParser::checkRegister(unsigned RegNo) { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp index 645491d8f9711..134193821c85b 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp @@ -38,16 +38,22 @@ XtensaTargetELFStreamer::XtensaTargetELFStreamer(MCStreamer &S) void XtensaTargetELFStreamer::emitLiteralLabel(MCSymbol *LblSym, SMLoc L) { MCContext &Context = getStreamer().getContext(); MCStreamer &OutStreamer = getStreamer(); - MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); - std::string CSectionName = CS->getName().str(); - std::size_t Pos = CSectionName.find(".text"); + StringRef LiteralSectionPrefix = getLiteralSectionPrefix(); std::string SectionName; - if (Pos != std::string::npos) { - SectionName = ".literal"; - SectionName += CSectionName.substr(Pos); + + if (LiteralSectionPrefix != "") { + SectionName = LiteralSectionPrefix.str() + ".literal"; } else { - SectionName = CSectionName; - SectionName += ".literal"; + MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); + std::string CSectionName = CS->getName().str(); + std::size_t Pos = CSectionName.find(".text"); + if (Pos != std::string::npos) { + SectionName = ".literal"; + SectionName += CSectionName.substr(Pos); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } } MCSection *ConstSection = Context.getELFSection( @@ -72,15 +78,21 @@ void XtensaTargetELFStreamer::emitLiteral(const MCExpr *Value, SMLoc L) { MCContext &Context = getStreamer().getContext(); MCStreamer &OutStreamer = getStreamer(); MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); - std::string CSectionName = CS->getName().str(); - std::size_t Pos = CSectionName.find(".text"); + StringRef LiteralSectionPrefix = getLiteralSectionPrefix(); std::string SectionName; - if (Pos != std::string::npos) { - SectionName = ".literal"; - SectionName += CSectionName.substr(Pos); + + if (LiteralSectionPrefix != "") { + SectionName = LiteralSectionPrefix.str() + ".literal"; } else { - SectionName = CSectionName; - SectionName += ".literal"; + std::string CSectionName = CS->getName().str(); + std::size_t Pos = CSectionName.find(".text"); + if (Pos != std::string::npos) { + SectionName = ".literal"; + SectionName += CSectionName.substr(Pos); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } } MCSection *ConstSection = Context.getELFSection( diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h index 962da002a997d..ef03578862a26 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h @@ -20,12 +20,16 @@ namespace llvm { class formatted_raw_ostream; class XtensaTargetStreamer : public MCTargetStreamer { + StringRef LiteralSectionPrefix = ""; + public: XtensaTargetStreamer(MCStreamer &S); virtual void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) = 0; virtual void emitLiteralLabel(MCSymbol *LblSym, SMLoc L) = 0; virtual void emitLiteral(const MCExpr *Value, SMLoc L) = 0; virtual void emitLiteral(std::string str) = 0; + void setLiteralSectionPrefix(StringRef Name) { LiteralSectionPrefix = Name; } + StringRef getLiteralSectionPrefix() { return LiteralSectionPrefix; } }; class XtensaTargetAsmStreamer : public XtensaTargetStreamer { diff --git a/llvm/test/MC/Xtensa/directive-literal.s b/llvm/test/MC/Xtensa/directive-literal.s new file mode 100644 index 0000000000000..cc2fccdb61c89 --- /dev/null +++ b/llvm/test/MC/Xtensa/directive-literal.s @@ -0,0 +1,23 @@ +# RUN: llvm-mc -triple xtensa-esp-elf -filetype obj -o - %s \ +# RUN: | llvm-readobj -S --sd - \ +# RUN: | FileCheck %s + + .text + .literal_position + .literal .LCPI0_0, 305419896 + .global test_literal + .p2align 2 + .type test_literal,@function +test_literal: +# %bb.0: + entry a1, 32 + mov.n a7, a1 + l32r a2, .LCPI0_0 + retw.n + +# CHECK: Section { +# CHECK: Name: .literal.text +# CHECK: SectionData ( +# CHECK: 0000: 78563412 +# CHECK: ) +# CHECK: } \ No newline at end of file diff --git a/llvm/test/MC/Xtensa/directive-region.s b/llvm/test/MC/Xtensa/directive-region.s new file mode 100644 index 0000000000000..ca62571c31221 --- /dev/null +++ b/llvm/test/MC/Xtensa/directive-region.s @@ -0,0 +1,25 @@ +# RUN: llvm-mc -triple xtensa-esp-elf -filetype obj -o - %s \ +# RUN: | llvm-readobj -S --sd - \ +# RUN: | FileCheck %s + + .text + .begin literal_prefix .ExceptionVector + .literal_position + .literal .LCPI0_0, 305419896 + .global test_literal + .p2align 2 + .type test_literal,@function +test_literal: +# %bb.0: + entry a1, 32 + mov.n a7, a1 + l32r a2, .LCPI0_0 + retw.n + .end literal_prefix + +# CHECK: Section { +# CHECK: Name: .ExceptionVector.literal +# CHECK: SectionData ( +# CHECK: 0000: 78563412 +# CHECK: ) +# CHECK: } \ No newline at end of file From 2c11321587b07f7fdfc02693003d67f87d91223c Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 9 Sep 2022 21:34:09 +0300 Subject: [PATCH 118/150] [Xtensa] Corrected asm parser. Expand addi operation immediate, to addmi + addi. Improved constants evalutaion. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 73 ++++++++++++++++--- .../Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp | 4 +- llvm/test/MC/Xtensa/xtensa-invalid.s | 10 +-- llvm/test/MC/Xtensa/xtensa-valid.s | 13 ++++ 4 files changed, 82 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index fe3d8f3d68103..263bb917bfa88 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -111,6 +111,10 @@ class XtensaAsmParser : public MCTargetAsmParser { XtensaAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI, MII) { + Parser.addAliasForDirective(".half", ".2byte"); + Parser.addAliasForDirective(".hword", ".2byte"); + Parser.addAliasForDirective(".word", ".4byte"); + Parser.addAliasForDirective(".dword", ".8byte"); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); } @@ -256,7 +260,10 @@ struct XtensaOperand : public MCParsedAsmOperand { return Kind == Immediate && inRange(getImm(), MinValue, MaxValue); } - bool isImm8() const { return isImm(-128, 127); } + bool isImm8() const { + //The addi instruction maybe expaned to addmi and addi. + return isImm((-32768 - 128), (32512 + 127)); + } bool isImm8_sh8() const { return isImm(-32768, 32512) && @@ -267,10 +274,10 @@ struct XtensaOperand : public MCParsedAsmOperand { // Convert MOVI to literal load, when immediate is not in range (-2048, 2047) bool isImm12m() const { - //Process special case when operand is symbol - if ((Kind == Immediate) && (getImm()->getKind() == MCExpr::SymbolRef)) + if (Kind == Immediate) return true; - return isImm(LONG_MIN, LONG_MAX); + + return false; } bool isOffset4m32() const { @@ -493,6 +500,40 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, const unsigned Opcode = Inst.getOpcode(); switch (Opcode) { + case Xtensa::ADDI: { + int64_t Imm = Inst.getOperand(2).getImm(); + // Expand 16-bit immediate in ADDI instruction: + // ADDI rd, rs, imm - > ADMI rd, rs, (imm & 0xff00); ADDI rd, rd, (imm & 0xff) + if ((Imm < -128) || (Imm > 127)) { + unsigned DReg = Inst.getOperand(0).getReg(); + unsigned SReg = Inst.getOperand(1).getReg(); + MCInst ADDMIInst; + MCInst ADDIInst; + int64_t ImmHi = Imm & (~((uint64_t)0xff)); + int64_t ImmLo = Imm & 0xff; + + if (ImmLo > 127) { + ImmHi += 0x100; + ImmLo = ImmLo - 0x100; + } + + ADDMIInst.setOpcode(Xtensa::ADDMI); + ADDMIInst.addOperand(MCOperand::createReg(DReg)); + ADDMIInst.addOperand(MCOperand::createReg(SReg)); + ADDMIInst.addOperand(MCOperand::createImm(ImmHi)); + ADDMIInst.setLoc(IDLoc); + + Out.emitInstruction(ADDMIInst, *STI); + + ADDIInst.setOpcode(Xtensa::ADDI); + ADDIInst.addOperand(MCOperand::createReg(DReg)); + ADDIInst.addOperand(MCOperand::createReg(DReg)); + ADDIInst.addOperand(MCOperand::createImm(ImmLo)); + ADDIInst.setLoc(IDLoc); + + Inst = ADDIInst; + } + } break; case Xtensa::L32R: { const MCSymbolRefExpr *OpExpr = (const MCSymbolRefExpr *)Inst.getOperand(1).getExpr(); @@ -589,7 +630,7 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, } case Match_InvalidImm8: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), - "expected immediate in range [-128, 127]"); + "expected immediate in range [-32896, 32639]"); case Match_InvalidImm8_sh8: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-32768, 32512], first 8 bits " @@ -704,6 +745,7 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, AsmToken Buf[2]; std::string RegName = ""; int64_t Num; + bool IsIdentifier = false; // If this a parenthesised register name is allowed, parse it atomically if (AllowParens && getLexer().is(AsmToken::LParen)) { @@ -720,10 +762,17 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, default: return MatchOperand_NoMatch; case AsmToken::Integer: + case AsmToken::LParen: if ((!SR) && (!UR)) return MatchOperand_NoMatch; + const MCExpr *Res; + + if (getParser().parseExpression(Res)) + return MatchOperand_ParseFail; + + if (!Res->evaluateAsAbsolute(Num)) + return MatchOperand_NoMatch; - Num = getLexer().getTok().getIntVal(); // Parse case when we expect UR operand as special case, // because SR and UR registers may have the same number // and such situation may lead to confilct @@ -748,6 +797,7 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, RegName = std::to_string(Num); break; case AsmToken::Identifier: + IsIdentifier = true; RegName = getLexer().getTok().getIdentifier().str(); break; } @@ -770,7 +820,10 @@ OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands, Operands.push_back(XtensaOperand::createToken("(", FirstS)); SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); - getLexer().Lex(); + + if (IsIdentifier) + getLexer().Lex(); + Operands.push_back(XtensaOperand::createReg(RegNo, S, E)); if (HadParens) { @@ -799,12 +852,8 @@ OperandMatchResultTy XtensaAsmParser::parseImmediate(OperandVector &Operands) { return MatchOperand_ParseFail; break; case AsmToken::Identifier: { - StringRef Identifier; - if (getParser().parseIdentifier(Identifier)) + if (getParser().parseExpression(Res)) return MatchOperand_ParseFail; - - MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); - Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); break; } case AsmToken::Percent: diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp index ce80722230bb2..53e92aba4e2ba 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCAsmInfo.cpp @@ -23,10 +23,12 @@ XtensaMCAsmInfo::XtensaMCAsmInfo(const Triple &TT) { PrivateGlobalPrefix = ".L"; CommentString = "#"; ZeroDirective = "\t.space\t"; + Data16bitsDirective = "\t.half\t"; + Data32bitsDirective = "\t.word\t"; Data64bitsDirective = "\t.quad\t"; GlobalDirective = "\t.global\t"; UsesELFSectionDirectiveForBSS = true; SupportsDebugInformation = true; ExceptionsType = ExceptionHandling::DwarfCFI; - AlignmentIsInBytes = false; + AlignmentIsInBytes = true; } diff --git a/llvm/test/MC/Xtensa/xtensa-invalid.s b/llvm/test/MC/Xtensa/xtensa-invalid.s index 88d94b3e2ca5f..e0c3ea43102d1 100644 --- a/llvm/test/MC/Xtensa/xtensa-invalid.s +++ b/llvm/test/MC/Xtensa/xtensa-invalid.s @@ -5,12 +5,12 @@ LBL0: # imm8 -addi a1, a2, 300 -# CHECK: error: expected immediate in range [-128, 127] +addi a1, a2, -33000 +# CHECK: error: expected immediate in range [-32896, 32639] # imm8 -addi a1, a2, -129 -# CHECK: error: expected immediate in range [-128, 127] +addi a1, a2, 34000 +# CHECK: error: expected immediate in range [-32896, 32639] # imm1_16 extui a1, a2, 5, 17 @@ -70,4 +70,4 @@ or r2, sp, a3 # CHECK: :[[@LINE]]:4: error: invalid operand for instruction # Invalid operand types and sp, a2, 10 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction -addi sp, a1, a2 # CHECK: :[[@LINE]]:14: error: expected immediate in range [-128, 127] +addi sp, a1, a2 # CHECK: :[[@LINE]]:14: error: expected immediate in range [-32896, 32639] diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s index e863718193622..3edf24e62b033 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ b/llvm/test/MC/Xtensa/xtensa-valid.s @@ -21,6 +21,16 @@ addi a8, sp, -128 # CHECK-INST: addi a8, a1, -12 # CHECK: encoding: [0x82,0xc1,0xf4] addi a8, a1, -12 +# CHECK-INST: addmi a8, a1, 256 +# CHECK: encoding: [0x82,0xd1,0x01] +# CHECK-INST: addi a8, a8, 0 +# CHECK: encoding: [0x82,0xc8,0x00] +addi a8, a1, 256 +# CHECK-INST: addmi a8, a1, -9984 +# CHECK: encoding: [0x82,0xd1,0xd9] +# CHECK-INST: addi a8, a8, -16 +# CHECK: encoding: [0x82,0xc8,0xf0] +addi a8, a1, -10000 # CHECK-INST: addmi a1, a2, 32512 # CHECK: encoding: [0x12,0xd2,0x7f] @@ -326,6 +336,9 @@ wsr.sar a8 # CHECK-INST: wsr a8, sar # CHECK: encoding: [0x80,0x03,0x13] wsr a8, 3 +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, (2 + 1) # CHECK-INST: xor a6, a4, a5 # CHECK: encoding: [0x50,0x64,0x30] From 648f07638c8aeb66022861d7680d2660dbc99a40 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 10 Aug 2022 12:49:53 +0300 Subject: [PATCH 119/150] riscv/gnu: Adds `no-rtti` multilib support --- clang/lib/Driver/ToolChains/Gnu.cpp | 45 +++++++++++++++---- .../8.4.0/rv32i/ilp32/no-rtti/crtbegin.o | 0 .../8.4.0/rv32i/ilp32/no-rtti/crtend.o | 0 .../8.4.0/rv32imac/ilp32/no-rtti/crtbegin.o | 0 .../8.4.0/rv32imac/ilp32/no-rtti/crtend.o | 0 .../8.4.0/rv32imafc/ilp32f/no-rtti/crtbegin.o | 0 .../8.4.0/rv32imafc/ilp32f/no-rtti/crtend.o | 0 .../8.4.0/rv32imc/ilp32/no-rtti/crtbegin.o | 0 .../8.4.0/rv32imc/ilp32/no-rtti/crtend.o | 0 .../lib/rv32i/ilp32/no-rtti/crt0.o | 0 .../lib/rv32imac/ilp32/no-rtti/crt0.o | 0 .../lib/rv32imafc/ilp32f/no-rtti/crt0.o | 0 .../lib/rv32imc/ilp32/no-rtti/crt0.o | 0 clang/test/Driver/riscv32-esp-toolchain.c | 19 ++++++++ 14 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/no-rtti/crtbegin.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/no-rtti/crtend.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32i/ilp32/no-rtti/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imac/ilp32/no-rtti/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imafc/ilp32f/no-rtti/crt0.o create mode 100644 clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imc/ilp32/no-rtti/crt0.o diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index a23f20e6e5132..7608b87cda31a 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1039,6 +1039,10 @@ static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } +static Multilib makeMultilib(StringRef commonSuffix, int Priority) { + return Multilib(commonSuffix, commonSuffix, commonSuffix, Priority); +} + static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { @@ -1688,16 +1692,33 @@ static void findRISCVBareMetalMultilibs(const Driver &D, {"rv64imafdc", "lp64d"}}; std::vector Ms; - - if (TargetTriple.getVendor() == llvm::Triple::Espressif) - Ms.emplace_back(Multilib({}, {}, {}, -1)); - + if (TargetTriple.getVendor() == llvm::Triple::Espressif) { + Ms.emplace_back(Multilib()); + Ms.emplace_back(makeMultilib("no-rtti", 1) + .flag("+fno-rtti") + .flag("-frtti")); + } for (auto Element : RISCVMultilibSet) { - // multilib path rule is ${march}/${mabi} - Ms.emplace_back( - makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) - .flag(Twine("+march=", Element.march).str()) - .flag(Twine("+mabi=", Element.mabi).str())); + if (TargetTriple.getVendor() == llvm::Triple::Espressif) { + // multilib path rule is ${march}/${mabi} + Ms.emplace_back( + makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str(), 2) + .flag(Twine("+march=", Element.march).str()) + .flag(Twine("+mabi=", Element.mabi).str())); + /* no-rtti version for every ${march}/${mabi} */ + Ms.emplace_back( + makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi) + "/no-rtti").str(), 3) + .flag(Twine("+march=", Element.march).str()) + .flag(Twine("+mabi=", Element.mabi).str()) + .flag("+fno-rtti") + .flag("-frtti")); + } else { + // multilib path rule is ${march}/${mabi} + Ms.emplace_back( + makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) + .flag(Twine("+march=", Element.march).str()) + .flag(Twine("+mabi=", Element.mabi).str())); + } } MultilibSet RISCVMultilibs = MultilibSet() @@ -1734,6 +1755,12 @@ static void findRISCVBareMetalMultilibs(const Driver &D, } } + if (TargetTriple.getVendor() == llvm::Triple::Espressif) { + addMultilibFlag( + Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, true), "frtti", + Flags); + } + if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) Result.Multilibs = RISCVMultilibs; } diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32i/ilp32/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imafc/ilp32f/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/no-rtti/crtbegin.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/no-rtti/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/no-rtti/crtend.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imc/ilp32/no-rtti/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32i/ilp32/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32i/ilp32/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imac/ilp32/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imac/ilp32/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imafc/ilp32f/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imafc/ilp32f/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imc/ilp32/no-rtti/crt0.o b/clang/test/Driver/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib/rv32imc/ilp32/no-rtti/crt0.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/riscv32-esp-toolchain.c b/clang/test/Driver/riscv32-esp-toolchain.c index 5c34c0a3bf7a1..5804abe4a724a 100644 --- a/clang/test/Driver/riscv32-esp-toolchain.c +++ b/clang/test/Driver/riscv32-esp-toolchain.c @@ -81,6 +81,25 @@ // CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "-lstdc++" "-lm" "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" // CXX-RV32IMAC-BAREMETAL-MULTI-NOSYSROOT-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32{{/|\\\\}}crtend.o" +// RUN: %clangxx %s -### -no-canonical-prefixes -target riscv32-esp-elf \ +// RUN: -ffreestanding -stdlib=libstdc++ --rtlib=libgcc --ld-path=riscv32-esp-elf-ld \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_esp_elf_sdk \ +// RUN: --sysroot=%S/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf \ +// RUN: -fno-rtti 2>&1 \ +// RUN: | FileCheck -check-prefix=CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32 %s + +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-internal-isystem" "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/include/c++{{/|\\\\}}8.4.0" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-as" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-mabi" "ilp32" "-march" "rv32imac" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "{{.*}}Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/../../..{{/|\\\\}}..{{/|\\\\}}bin{{/|\\\\}}riscv32-esp-elf-ld" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "--sysroot={{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-m" "elf32lriscv" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti{{/|\\\\}}crtbegin.o" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-lstdc++" "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti{{/|\\\\}}crtend.o" + // RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ // RUN: -march=rv32i -mabi=ilp32 \ // RUN: -ffreestanding --rtlib=libgcc --ld-path=riscv32-esp-elf-ld --sysroot= \ From b8f05a37d7035e9a656be571cb78718d2a4111bb Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 10 Aug 2022 12:52:10 +0300 Subject: [PATCH 120/150] [Xtensa] Guess GCC toolchain triplet from MCPU option --- clang/lib/Driver/ToolChains/Xtensa.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index 7d76c47b2d755..de73ba80b3f64 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -38,14 +38,23 @@ XtensaToolChain::XtensaToolChain(const Driver &D, const llvm::Triple &Triple, std::vector ExtraAliases; - if (Triple.getVendor() == llvm::Triple::Espressif) { - std::string ESPCpuName = "esp32"; - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - ESPCpuName = A->getValue(); - } - ExtraAliases = {std::string("xtensa-") + ESPCpuName + "-elf"}; - if (Args.hasArg(options::OPT_v)) { - llvm::errs() << "Use GCC target extra alias: " << ExtraAliases[0] << "\n"; + if (Triple.getVendor() == llvm::Triple::Espressif || + Triple.getVendor() == llvm::Triple::UnknownVendor) { + Arg *mcpuArg = Args.getLastArg(options::OPT_mcpu_EQ); + SmallString<128> CpuName; + if (mcpuArg) + CpuName = mcpuArg->getValue(); + else if (Triple.getVendor() == llvm::Triple::Espressif) + // 'esp32' is default for 'xtensa-esp-xxx' targets, + // for generic 'xtensa' target CPU should be always specified explicitly with '-mcpu' + CpuName = "esp32"; + if (CpuName.startswith("esp")) { + // ESP Xtensa GCC toolchain uses shorten triple "xtensa--elf", so add it as an alias + // to help Clang detect GCC installation properly + ExtraAliases = {std::string("xtensa-") + CpuName.c_str() + "-elf"}; + if (Args.hasArg(options::OPT_v)) { + llvm::errs() << "Use GCC target extra alias: " << ExtraAliases[0] << "\n"; + } } } From 789d4979c11840cd9d2626c89234ac51409c80c6 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Tue, 24 May 2022 16:24:02 +0300 Subject: [PATCH 121/150] esp/ci: Adds MacOS x86_64/ARM64 universal toolchain builds --- .gitlab-ci.yml | 70 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6da427203109c..5ce8137132c93 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ stages: - test - public_deploy -image: ${CI_DOCKER_REGISTRY}/llvm-build:3 +image: ${CI_DOCKER_REGISTRY}/llvm-build:4 variables: @@ -18,7 +18,7 @@ variables: XTENSA_OVERLAYS_REPO: "xtensa-overlays" XTENSA_OVERLAYS_REF: "master" # TODO: update vars below to tags names after related branches are merged in those repos - XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_14.0.0_gcc_8.4.0" + XTENSA_CLANG_TOOLCHAIN_REF: "build_macos_arm64" LLVM_GCC_TESTSUITE_REF: "feature/toolchain_build_script" PLATFORM_NAME_LINUX_ARM64: "linux-arm64" @@ -110,8 +110,10 @@ before_script: artifacts: paths: - ${DIST_DIR}/ + - newlib/ - ${BUILD_DIR}/clang_tests.log - ${BUILD_DIR}/clang_build.log + - ${BUILD_DIR}/newlib_build.log when: always expire_in: 1 day variables: @@ -125,8 +127,6 @@ before_script: - pushd ${DOWNLOADS_DIR} - export ESP_GCC_TOOLCHAIN_DIST_BASE=$PWD - *get_gcc_toolchain - - git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git - - export NEWLIB_PATH=$PWD/${NEWLIB_REPO} - git clone -b ${BINUTILS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${BINUTILS_REPO}.git - export BINUTILS_PATH=$PWD/${BINUTILS_REPO} - git clone -b ${XTENSA_OVERLAYS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${XTENSA_OVERLAYS_REPO}.git @@ -139,15 +139,38 @@ before_script: - export BUILD_PATH=$PWD/${BUILD_DIR} - mkdir -p ${BUILD_PATH} - export USE_PARALLEL_LINK_JOBS=2 - - ${BUILD_TOOLCHAIN_CMD} --llvm-path=${LLVM_PROJECT_PATH} --newlib-path=${NEWLIB_PATH} + # build Clang toolchain w/o newlib + - ${BUILD_TOOLCHAIN_CMD} --llvm-path=${LLVM_PROJECT_PATH} --gcc-toolchains-path=${ESP_GCC_TOOLCHAIN_DIST_BASE} --binutils-path=${BINUTILS_PATH} - --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_TOOLCHAIN_CMD_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/clang_build.log + --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} --host=${CONF_HOST} ${BUILD_TOOLCHAIN_CMD_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/clang_build.log + # use just built Clang to build newlib + - export PATH=${BUILD_PATH}/esp-clang/bin:$PATH + - export BUILD_HOST=$(gcc -dumpmachine) + - export NEWLIB_OVERLAY_DISTRO_PATH=$PWD/newlib; + # build newlib overlay using ESP native (Linux) clang toolchain only + # it will be re-used for cross-buit toolchains (win and mac). + # FIXME: it would be good to move newlib overlay build to separate job and have job sequence like + # clang_linux_wo_newlib -> newlib_overlay -> clang_linux_full(copy newlib) -> clang_linux_unittests + # but we need full native (Linux) toolchain to run unittests and unittests need clang build dir. + # clang build dir may occupy about 2GB, so it looks too heavy to pass it as artifact + - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then + export BUILD_NEWLIB_PATH=${BUILD_PATH}/newlib; + mkdir -p ${NEWLIB_OVERLAY_DISTRO_PATH}; + git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git; + export NEWLIB_PATH=$PWD/${NEWLIB_REPO}; + ./build-toolchain.sh --newlib-path=${NEWLIB_PATH} --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_NEWLIB_PATH} 2>&1 > ${BUILD_PATH}/newlib_build.log; + pushd ${BUILD_NEWLIB_PATH}; + ${ARCHIVE_TOOL_LINUX} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_LINUX} esp-clang/; + popd; + fi + - ${UNARCHIVE_TOOL_LINUX} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_LINUX} -C ${BUILD_PATH} + # strip binutils afer newlib is built + - STRIP_BINUTILS=YES ./build-toolchain.sh --host=${CONF_HOST} ${BUILD_PATH} # Run unit tests for native build only. # Run as non-root user because permission tests fail when run by root. - - export BUILD_HOST=$(gcc -dumpmachine) - - export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-Release-${CONF_HOST} - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then - echo "Run unit tests for native build"; + export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-Release-${CONF_HOST}; + echo "Run unit tests for native build ib ${LLVM_BUILD_PATH}"; useradd -m test_runner; chown -R test_runner ${LLVM_BUILD_PATH}; touch ${BUILD_PATH}/clang_tests.log; @@ -169,7 +192,7 @@ build_x86_64-linux-gnu: ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" -build_x86_64-w64-mingw32: +.build_x86_64-w64-mingw32: extends: .build_template needs: - job: build_x86_64-linux-gnu @@ -192,7 +215,7 @@ build_x86_64-w64-mingw32: - rm -rf ${DIST_DIR} - rm -rf ${BUILD_DIR} # add build command args speciifc for Windows build - - export BUILD_TOOLCHAIN_CMD_ARGS="--host=${CONF_HOST} --native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" + - export BUILD_TOOLCHAIN_CMD_ARGS="--native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" variables: CONF_HOST: "x86_64-w64-mingw32" PLATFORM_NAME: "${PLATFORM_NAME_WIN}" @@ -201,7 +224,30 @@ build_x86_64-w64-mingw32: ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" -test_x86_64-linux-gnu: +.build_apple-darwin_template: + extends: .build_template + needs: + - job: build_x86_64-linux-gnu + variables: + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + GCC_ARCHIVE_EXT: "${GCC_ARCHIVE_EXT_MACOS}" + +build_x86_64-apple-darwin: + extends: .build_apple-darwin_template + variables: + CONF_HOST: "x86_64-apple-darwin21.1" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh --host-arch=x86_64" + +build_aarch64-apple-darwin: + extends: .build_apple-darwin_template + variables: + CONF_HOST: "aarch64-apple-darwin21.1" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh --host-arch=aarch64" + +.test_x86_64-linux-gnu: stage: test tags: [ "amd64", "build" ] allow_failure: true From 694867ec37144e13c92beddd47c23effd74b427d Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 17 Aug 2022 20:10:51 +0300 Subject: [PATCH 122/150] esp/ci: Adds minimal distro with libraries/headres only --- .gitlab-ci.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5ce8137132c93..6f616b8865638 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,8 @@ image: ${CI_DOCKER_REGISTRY}/llvm-build:4 variables: # move all these to CI/CD settings + REL_SFX: "llvm14_0_0" + CLANG_VER: "14.0.0" GCC_REL_NAME: "esp-2022r1-RC1" GCC_REL_VER: "gcc11_2_0" NEWLIB_REPO: "newlib-cygwin" @@ -65,9 +67,9 @@ before_script: .get_release_name: &get_release_name | # using annotated tags REL_NUM=$(git describe --abbrev=7) - REL_SFX="llvm15_0_0" REL_NAME=${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} + LIBS_ARCHIVE_NAME=libs_${REL_NAME}.${ARCHIVE_EXT} echo "PLATFORM_NAME: $PLATFORM_NAME" echo "REL_NUM: $REL_NUM" echo "REL_NAME: $REL_NAME" @@ -103,6 +105,13 @@ before_script: mv ${ARCHIVE_NAME} ${DISTRO_DIR}/ echo "${ARCHIVE_NAME}" > ${DISTRO_DIR}/file_${PLATFORM_NAME} +# Pack libs to be used for Rust, Go etc. +.package_libs: &package_libs | + ${ARCHIVE_TOOL} ${LIBS_ARCHIVE_NAME} esp-clang/lib/libclang* esp-clang/lib/clang/${CLANG_VER}/include + mkdir -p ${DISTRO_DIR} + mv ${LIBS_ARCHIVE_NAME} ${DISTRO_DIR}/ + echo "${LIBS_ARCHIVE_NAME}" > ${DISTRO_DIR}/file_lib${PLATFORM_NAME} + .build_template: stage: build tags: [ "amd64", "build" ] @@ -115,7 +124,7 @@ before_script: - ${BUILD_DIR}/clang_build.log - ${BUILD_DIR}/newlib_build.log when: always - expire_in: 1 day + expire_in: 3 day variables: BUILD_TOOLCHAIN_CMD_ARGS: "" # use separate dist dir for universal toolchain @@ -180,6 +189,7 @@ before_script: - export DISTRO_DIR=$PWD/$DIST_DIR - pushd ${BUILD_PATH} - *package_toolchain + - *package_libs - popd build_x86_64-linux-gnu: From 986b71e9c01bac7d7c111fc0bf01c632efd86f46 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 10 Aug 2022 12:53:58 +0300 Subject: [PATCH 123/150] esp/ci: Upgrade GCC toolchain to `esp-2022r1` --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6f616b8865638..70f206d102ea9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,12 +11,12 @@ variables: # move all these to CI/CD settings REL_SFX: "llvm14_0_0" CLANG_VER: "14.0.0" - GCC_REL_NAME: "esp-2022r1-RC1" + GCC_REL_NAME: "esp-2022r1" GCC_REL_VER: "gcc11_2_0" NEWLIB_REPO: "newlib-cygwin" - NEWLIB_REF: "esp_based_on_4_1_0" + NEWLIB_REF: "esp-2022r1" BINUTILS_REPO: "binutils-gdb" - BINUTILS_REF: "esp_based_on_binutils-2_35" + BINUTILS_REF: "esp-2022r1-binutils" XTENSA_OVERLAYS_REPO: "xtensa-overlays" XTENSA_OVERLAYS_REF: "master" # TODO: update vars below to tags names after related branches are merged in those repos From 63b6e4499f11f10cf62ba1e1024342927bcf40a0 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 17 Aug 2022 20:05:57 +0300 Subject: [PATCH 124/150] esp/ci: Move newlib build to separate job --- .gitlab-ci.yml | 248 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 180 insertions(+), 68 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 70f206d102ea9..f3fadafed1fcd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,6 @@ stages: - build + - pack - private_deploy - test - public_deploy @@ -19,14 +20,16 @@ variables: BINUTILS_REF: "esp-2022r1-binutils" XTENSA_OVERLAYS_REPO: "xtensa-overlays" XTENSA_OVERLAYS_REF: "master" - # TODO: update vars below to tags names after related branches are merged in those repos + LLVM_GCC_TESTSUITE_REF: "release_universal_clang_toolchain" + # TODO: update var below to tags names after related branches are merged in those repos + # XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_toolchain" XTENSA_CLANG_TOOLCHAIN_REF: "build_macos_arm64" - LLVM_GCC_TESTSUITE_REF: "feature/toolchain_build_script" PLATFORM_NAME_LINUX_ARM64: "linux-arm64" PLATFORM_NAME_LINUX: "linux-amd64" PLATFORM_NAME_WIN: "win64" PLATFORM_NAME_MACOS: "macos" + PLATFORM_NAME_MACOS_ARM64: "macos-arm64" ARCHIVE_TOOL_LINUX: "tar -cJf" UNARCHIVE_TOOL_LINUX: "tar -xf" @@ -40,6 +43,11 @@ variables: UNARCHIVE_TOOL_MACOS: "tar -xf" ARCHIVE_EXT_MACOS: "tar.xz" + ARCHIVE_TOOL_NEWLIB: ${ARCHIVE_TOOL_LINUX} + UNARCHIVE_TOOL_NEWLIB: ${UNARCHIVE_TOOL_LINUX} + ARCHIVE_EXT_NEWLIB: ${ARCHIVE_EXT_LINUX} + + DIST_NEW_DIR: "_dist_new" DIST_DIR: "dist" BUILD_DIR: "_build" DOWNLOADS_DIR: "_downloads" @@ -110,7 +118,19 @@ before_script: ${ARCHIVE_TOOL} ${LIBS_ARCHIVE_NAME} esp-clang/lib/libclang* esp-clang/lib/clang/${CLANG_VER}/include mkdir -p ${DISTRO_DIR} mv ${LIBS_ARCHIVE_NAME} ${DISTRO_DIR}/ - echo "${LIBS_ARCHIVE_NAME}" > ${DISTRO_DIR}/file_lib${PLATFORM_NAME} + echo "${LIBS_ARCHIVE_NAME}" > ${DISTRO_DIR}/file_libs-${PLATFORM_NAME} + +.get_binutils: &get_binutils | + git clone -b ${BINUTILS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${BINUTILS_REPO}.git + BINUTILS_PATH=$PWD/${BINUTILS_REPO} + +.get_xtensa_overlays: &get_xtensa_overlays | + git clone -b ${XTENSA_OVERLAYS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${XTENSA_OVERLAYS_REPO}.git + XTENSA_OVERLAYS_PATH=$PWD/${XTENSA_OVERLAYS_REPO} + +.get_newlib: &get_newlib | + git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git + NEWLIB_PATH=$PWD/${NEWLIB_REPO} .build_template: stage: build @@ -119,77 +139,49 @@ before_script: artifacts: paths: - ${DIST_DIR}/ - - newlib/ - - ${BUILD_DIR}/clang_tests.log - - ${BUILD_DIR}/clang_build.log - - ${BUILD_DIR}/newlib_build.log + - ${BUILD_DIR}/tests.log + - ${BUILD_DIR}/build.log when: always - expire_in: 3 day + expire_in: 1 day variables: - BUILD_TOOLCHAIN_CMD_ARGS: "" + BUILD_TOOLCHAIN_CMD_EXTRA_ARGS: "" # use separate dist dir for universal toolchain # TODO: remove this var after switching to universal toolchain builds - DIST_DIR: "dist_new" + DIST_DIR: ${DIST_NEW_DIR} script: - *get_release_name - mkdir ${DOWNLOADS_DIR} - pushd ${DOWNLOADS_DIR} - - export ESP_GCC_TOOLCHAIN_DIST_BASE=$PWD + - ESP_GCC_TOOLCHAIN_DIST_BASE=$PWD - *get_gcc_toolchain - - git clone -b ${BINUTILS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${BINUTILS_REPO}.git - - export BINUTILS_PATH=$PWD/${BINUTILS_REPO} - - git clone -b ${XTENSA_OVERLAYS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${XTENSA_OVERLAYS_REPO}.git - - export XTENSA_OVERLAYS_PATH=$PWD/${XTENSA_OVERLAYS_REPO} + - *get_binutils + - *get_xtensa_overlays - popd - *get_clang_toolchain_build_scripts - *fix_origin_remote_for_public - - export ESP_GCC_TOOLCHAIN_REL_VER=${GCC_REL_NAME} - - export LLVM_PROJECT_PATH=$PWD - - export BUILD_PATH=$PWD/${BUILD_DIR} + - LLVM_PROJECT_PATH=$PWD + - BUILD_PATH=$PWD/${BUILD_DIR} - mkdir -p ${BUILD_PATH} - export USE_PARALLEL_LINK_JOBS=2 # build Clang toolchain w/o newlib - ${BUILD_TOOLCHAIN_CMD} --llvm-path=${LLVM_PROJECT_PATH} --gcc-toolchains-path=${ESP_GCC_TOOLCHAIN_DIST_BASE} --binutils-path=${BINUTILS_PATH} - --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} --host=${CONF_HOST} ${BUILD_TOOLCHAIN_CMD_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/clang_build.log - # use just built Clang to build newlib - - export PATH=${BUILD_PATH}/esp-clang/bin:$PATH - - export BUILD_HOST=$(gcc -dumpmachine) - - export NEWLIB_OVERLAY_DISTRO_PATH=$PWD/newlib; - # build newlib overlay using ESP native (Linux) clang toolchain only - # it will be re-used for cross-buit toolchains (win and mac). - # FIXME: it would be good to move newlib overlay build to separate job and have job sequence like - # clang_linux_wo_newlib -> newlib_overlay -> clang_linux_full(copy newlib) -> clang_linux_unittests - # but we need full native (Linux) toolchain to run unittests and unittests need clang build dir. - # clang build dir may occupy about 2GB, so it looks too heavy to pass it as artifact - - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then - export BUILD_NEWLIB_PATH=${BUILD_PATH}/newlib; - mkdir -p ${NEWLIB_OVERLAY_DISTRO_PATH}; - git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git; - export NEWLIB_PATH=$PWD/${NEWLIB_REPO}; - ./build-toolchain.sh --newlib-path=${NEWLIB_PATH} --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_NEWLIB_PATH} 2>&1 > ${BUILD_PATH}/newlib_build.log; - pushd ${BUILD_NEWLIB_PATH}; - ${ARCHIVE_TOOL_LINUX} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_LINUX} esp-clang/; - popd; - fi - - ${UNARCHIVE_TOOL_LINUX} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_LINUX} -C ${BUILD_PATH} - # strip binutils afer newlib is built - - STRIP_BINUTILS=YES ./build-toolchain.sh --host=${CONF_HOST} ${BUILD_PATH} - # Run unit tests for native build only. + --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} --host=${CONF_HOST} ${BUILD_TOOLCHAIN_CMD_EXTRA_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/build.log + - BUILD_HOST=$(gcc -dumpmachine) + # Do not run unit tests for cross-builds. # Run as non-root user because permission tests fail when run by root. - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-Release-${CONF_HOST}; - echo "Run unit tests for native build ib ${LLVM_BUILD_PATH}"; + echo "Run unit tests for native build in ${LLVM_BUILD_PATH}"; useradd -m test_runner; chown -R test_runner ${LLVM_BUILD_PATH}; - touch ${BUILD_PATH}/clang_tests.log; - chmod o+w ${BUILD_PATH}/clang_tests.log; - runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target check-all 2>&1 > '${BUILD_PATH}'/clang_tests.log'; + touch ${BUILD_PATH}/tests.log; + chmod o+w ${BUILD_PATH}/tests.log; + runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target check-all 2>&1 > '${BUILD_PATH}'/tests.log'; fi - export DISTRO_DIR=$PWD/$DIST_DIR - pushd ${BUILD_PATH} - *package_toolchain - - *package_libs - popd build_x86_64-linux-gnu: @@ -202,67 +194,187 @@ build_x86_64-linux-gnu: ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" -.build_x86_64-w64-mingw32: +build_x86_64-w64-mingw32: extends: .build_template needs: + # needs native toolchain and newlib from this job - job: build_x86_64-linux-gnu before_script: - *use_ci_tools - *add_gitlab_key # get ARCHIVE_NAME for Linux release. Modify vars to make get_release_name working properly - - export PLATFORM_NAME_ORIG=${PLATFORM_NAME} - - export ARCHIVE_EXT_ORIG=${ARCHIVE_EXT} - - export PLATFORM_NAME=${PLATFORM_NAME_LINUX} - - export ARCHIVE_EXT=${ARCHIVE_EXT_LINUX} - - *get_release_name - # restore modified vars - - export PLATFORM_NAME=${PLATFORM_NAME_ORIG} - - export ARCHIVE_EXT=${ARCHIVE_EXT_ORIG} - # unpack Linux release to re-use it as native Clang for Windows build + - CLANG_LINUX_ARCHIVE=$(cat ${DIST_DIR}/file_${PLATFORM_NAME_LINUX}) + # unpack x86_64-linux-gnu toolchain to re-use it as native Clang for Windows build - mkdir -p esp-clang-${PLATFORM_NAME_LINUX} - - ${UNARCHIVE_TOOL_LINUX} ${DIST_DIR}/${ARCHIVE_NAME} -C esp-clang-${PLATFORM_NAME_LINUX} + - ${UNARCHIVE_TOOL_LINUX} ${DIST_DIR}/${CLANG_LINUX_ARCHIVE} -C esp-clang-${PLATFORM_NAME_LINUX} # we do not want to keep artifacts from 'x86_64-linux-gnu' job - rm -rf ${DIST_DIR} - rm -rf ${BUILD_DIR} # add build command args speciifc for Windows build - - export BUILD_TOOLCHAIN_CMD_ARGS="--native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" + - export BUILD_TOOLCHAIN_CMD_EXTRA_ARGS="--native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" variables: CONF_HOST: "x86_64-w64-mingw32" PLATFORM_NAME: "${PLATFORM_NAME_WIN}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" + # Use Linux compressor to minimize artifact size. + # Toolchain is not fully stripped yet, so may exceed max artifact size. + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" .build_apple-darwin_template: extends: .build_template - needs: - - job: build_x86_64-linux-gnu variables: - PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" - GCC_ARCHIVE_EXT: "${GCC_ARCHIVE_EXT_MACOS}" build_x86_64-apple-darwin: extends: .build_apple-darwin_template variables: CONF_HOST: "x86_64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh --host-arch=x86_64" build_aarch64-apple-darwin: extends: .build_apple-darwin_template variables: CONF_HOST: "aarch64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh --host-arch=aarch64" -.test_x86_64-linux-gnu: - stage: test +build_newlib: + stage: build + tags: [ "amd64", "build" ] + needs: + # needs native toolchainfrom this job + - job: build_x86_64-linux-gnu + artifacts: + paths: + - ${DIST_DIR}/ + - ${BUILD_DIR}/build.log + when: always + expire_in: 1 day + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + # use separate dist dir for universal toolchain + # TODO: remove this var after switching to universal toolchain builds + DIST_DIR: ${DIST_NEW_DIR} + script: + # get ARCHIVE_NAME for Linux release. + - CLANG_ARCHIVE=$PWD/${DIST_DIR}/$(cat ${DIST_DIR}/file_${PLATFORM_NAME_LINUX}) + - mkdir -p ${DOWNLOADS_DIR} + - pushd ${DOWNLOADS_DIR} + - *get_xtensa_overlays + - *get_newlib + # unpack clang + - ${UNARCHIVE_TOOL} ${CLANG_ARCHIVE} + - export PATH=$PWD/esp-clang/bin:$PATH + - popd + - rm -rf $PWD/${DIST_DIR} + - *get_clang_toolchain_build_scripts + # build newlib overlay using ESP native (Linux) clang toolchain only + # it will be re-used for cross-buit toolchains (win and mac). + - NEWLIB_OVERLAY_DISTRO_PATH=$PWD/${DIST_DIR} + - mkdir -p ${NEWLIB_OVERLAY_DISTRO_PATH} + - BUILD_PATH=$PWD/${BUILD_DIR} + - mkdir -p ${BUILD_PATH} + - ./build-toolchain.sh --newlib-path=${NEWLIB_PATH} --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/build.log + - pushd ${BUILD_PATH} + - ${ARCHIVE_TOOL_NEWLIB} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_NEWLIB} esp-clang/ + - popd + +.pack_template: + stage: pack tags: [ "amd64", "build" ] allow_failure: true + artifacts: + paths: + - ${DIST_DIR}/ + when: always + expire_in: 3 day + variables: + # use separate dist dir for universal toolchain + # TODO: remove this var after switching to universal toolchain builds + DIST_DIR: ${DIST_NEW_DIR} + script: + - *get_release_name + - export BUILD_PATH=$PWD/${BUILD_DIR} + - mkdir -p ${BUILD_PATH} + # unpack clang + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} -C ${BUILD_PATH} + # unpack newlib + - ${UNARCHIVE_TOOL_NEWLIB} ${DIST_DIR}/esp-clang-newlib-overlay.${ARCHIVE_EXT_NEWLIB} -C ${BUILD_PATH} + - rm -rf ${DIST_DIR} + - *get_clang_toolchain_build_scripts + # strip binutils afer newlib is built + - STRIP_BINUTILS=YES ./build-toolchain.sh --host=${CONF_HOST} ${BUILD_PATH} + - DISTRO_DIR=$PWD/${DIST_DIR} + - pushd ${BUILD_PATH} + - *package_toolchain + - *package_libs + - popd + +pack_x86_64-linux-gnu: + extends: .pack_template needs: - job: build_x86_64-linux-gnu + - job: build_newlib + variables: + CONF_HOST: "x86_64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + +pack_x86_64-w64-mingw32: + extends: .pack_template + needs: + - job: build_x86_64-w64-mingw32 + - job: build_newlib + variables: + CONF_HOST: "x86_64-w64-mingw32" + PLATFORM_NAME: "${PLATFORM_NAME_WIN}" + # use Linux compressor to save space. + # upon release archive will be re-packed into zip format for uploading to GH + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + +.pack_apple-darwin_template: + extends: .pack_template + variables: + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + +pack_x86_64-apple-darwin: + extends: .pack_apple-darwin_template + needs: + - job: build_x86_64-apple-darwin + - job: build_newlib + variables: + CONF_HOST: "x86_64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + +pack_aarch64-apple-darwin: + extends: .pack_apple-darwin_template + needs: + - job: build_aarch64-apple-darwin + - job: build_newlib + variables: + CONF_HOST: "aarch64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" + +test_x86_64-linux-gnu: + stage: test + tags: [ "amd64", "build" ] + allow_failure: true + needs: + - job: pack_x86_64-linux-gnu variables: PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" @@ -270,7 +382,7 @@ build_aarch64-apple-darwin: ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" # use separate dist dir for universal toolchain # TODO: remove this var after switching to universal toolchain builds - DIST_DIR: "dist_new" + DIST_DIR: ${DIST_NEW_DIR} script: - *get_release_name - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} From e95d783d2a30cfbdf4694a7dd3903166861f638c Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 17 Aug 2022 22:04:41 +0300 Subject: [PATCH 125/150] esp/ci: Adds Linux ARM/ARM64 universal toolchain builds --- .gitignore | 3 +++ .gitlab-ci.yml | 69 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 20c4f52cd3786..0e13e97841618 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ # Nested build directory /build* +/*/build-* +/_build +/_dist #==============================================================================# # Explicit files to ignore (only matches one). diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3fadafed1fcd..6b57687583bf1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,10 +23,12 @@ variables: LLVM_GCC_TESTSUITE_REF: "release_universal_clang_toolchain" # TODO: update var below to tags names after related branches are merged in those repos # XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_toolchain" - XTENSA_CLANG_TOOLCHAIN_REF: "build_macos_arm64" + XTENSA_CLANG_TOOLCHAIN_REF: "universal_toolchain/build_linux_arm64" - PLATFORM_NAME_LINUX_ARM64: "linux-arm64" + CROSS_ARM_IMAGE: $CI_DOCKER_REGISTRY/llvm-build-cross-arm:1 PLATFORM_NAME_LINUX: "linux-amd64" + PLATFORM_NAME_LINUX_ARMHF: "linux-armhf" + PLATFORM_NAME_LINUX_ARM64: "linux-arm64" PLATFORM_NAME_WIN: "win64" PLATFORM_NAME_MACOS: "macos" PLATFORM_NAME_MACOS_ARM64: "macos-arm64" @@ -171,7 +173,7 @@ before_script: # Do not run unit tests for cross-builds. # Run as non-root user because permission tests fail when run by root. - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then - export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-Release-${CONF_HOST}; + export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-${CONF_HOST}-Release; echo "Run unit tests for native build in ${LLVM_BUILD_PATH}"; useradd -m test_runner; chown -R test_runner ${LLVM_BUILD_PATH}; @@ -184,16 +186,34 @@ before_script: - *package_toolchain - popd -build_x86_64-linux-gnu: +.build_linux-gnu_template: extends: .build_template variables: - CONF_HOST: "x86_64-linux-gnu" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" +build_x86_64-linux-gnu: + extends: .build_linux-gnu_template + variables: + CONF_HOST: "x86_64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + +build_arm-linux-gnueabihf: + extends: .build_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + variables: + CONF_HOST: "arm-linux-gnueabihf" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARMHF}" + +build_aarch64-linux-gnu: + extends: .build_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + variables: + CONF_HOST: "aarch64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" + build_x86_64-w64-mingw32: extends: .build_template needs: @@ -228,20 +248,19 @@ build_x86_64-w64-mingw32: ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" build_x86_64-apple-darwin: extends: .build_apple-darwin_template variables: CONF_HOST: "x86_64-apple-darwin21.1" PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh --host-arch=x86_64" build_aarch64-apple-darwin: extends: .build_apple-darwin_template variables: CONF_HOST: "aarch64-apple-darwin21.1" PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh --host-arch=aarch64" build_newlib: stage: build @@ -318,17 +337,41 @@ build_newlib: - *package_libs - popd -pack_x86_64-linux-gnu: +.pack_linux-gnu_template: extends: .pack_template + variables: + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + +pack_x86_64-linux-gnu: + extends: .pack_linux-gnu_template needs: - job: build_x86_64-linux-gnu - job: build_newlib variables: CONF_HOST: "x86_64-linux-gnu" PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + +pack_arm-linux-gnueabihf: + extends: .pack_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + needs: + - job: build_arm-linux-gnueabihf + - job: build_newlib + variables: + CONF_HOST: "arm-linux-gnueabihf" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARMHF}" + +pack_aarch64-linux-gnu: + extends: .pack_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + needs: + - job: build_aarch64-linux-gnu + - job: build_newlib + variables: + CONF_HOST: "aarch64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" pack_x86_64-w64-mingw32: extends: .pack_template @@ -459,7 +502,7 @@ linux_amd64_build: linux_arm64_build: extends: .build_template_old - image: $CI_DOCKER_REGISTRY/llvm-build-cross-arm:1 + image: ${CROSS_ARM_IMAGE} variables: PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" From d1b0c8863957fcb023d6149cd95b270352618583 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Thu, 18 Aug 2022 18:52:17 +0300 Subject: [PATCH 126/150] riscv/esp: Fixes riscv32-esp toolchain tests --- clang/test/Driver/riscv32-esp-toolchain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Driver/riscv32-esp-toolchain.c b/clang/test/Driver/riscv32-esp-toolchain.c index 5804abe4a724a..34ef6871f30f0 100644 --- a/clang/test/Driver/riscv32-esp-toolchain.c +++ b/clang/test/Driver/riscv32-esp-toolchain.c @@ -97,7 +97,7 @@ // CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti{{/|\\\\}}crtbegin.o" // CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0" // CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-L{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/riscv32-esp-elf/lib" -// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-lstdc++" "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" +// CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "-lstdc++" "-lm" "--start-group" "-lc" "-lgloss" "-lnosys" "--end-group" "-lgcc" // CXX-RV32IMAC-BAREMETAL-MULTI-NORTTI-ILP32: "{{.*}}/Inputs/multilib_riscv_esp_elf_sdk/lib/gcc/riscv32-esp-elf/8.4.0/rv32imac/ilp32/no-rtti{{/|\\\\}}crtend.o" // RUN: %clang %s -### -no-canonical-prefixes -target riscv32-esp-elf \ From d9ff0ed780eab22db36b661438ce0554a01c73fe Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 24 Aug 2022 10:53:30 +0300 Subject: [PATCH 127/150] esp/ci: Upgrade Clang ver to 15 --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6b57687583bf1..8a41a9dfc1694 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,8 +10,8 @@ image: ${CI_DOCKER_REGISTRY}/llvm-build:4 variables: # move all these to CI/CD settings - REL_SFX: "llvm14_0_0" - CLANG_VER: "14.0.0" + REL_SFX: "llvm15_0_0" + CLANG_VER: "15.0.0" GCC_REL_NAME: "esp-2022r1" GCC_REL_VER: "gcc11_2_0" NEWLIB_REPO: "newlib-cygwin" From ab29eaacb0e6a04424436196dc5722c7c57bf802 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Tue, 30 Aug 2022 13:29:15 +0300 Subject: [PATCH 128/150] esp/ci: Adds support to switch between legacy and universal toolchain release pipelines --- .gitlab-ci.yml | 578 +++---------------------------- .legacy-release.yml | 164 +++++++++ .universal-toolchain-release.yml | 409 ++++++++++++++++++++++ 3 files changed, 613 insertions(+), 538 deletions(-) create mode 100644 .legacy-release.yml create mode 100644 .universal-toolchain-release.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8a41a9dfc1694..d4a2c816f97ef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ image: ${CI_DOCKER_REGISTRY}/llvm-build:4 variables: # move all these to CI/CD settings - REL_SFX: "llvm15_0_0" + REL_SFX: "llvm" CLANG_VER: "15.0.0" GCC_REL_NAME: "esp-2022r1" GCC_REL_VER: "gcc11_2_0" @@ -21,9 +21,7 @@ variables: XTENSA_OVERLAYS_REPO: "xtensa-overlays" XTENSA_OVERLAYS_REF: "master" LLVM_GCC_TESTSUITE_REF: "release_universal_clang_toolchain" - # TODO: update var below to tags names after related branches are merged in those repos - # XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_toolchain" - XTENSA_CLANG_TOOLCHAIN_REF: "universal_toolchain/build_linux_arm64" + XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_toolchain" CROSS_ARM_IMAGE: $CI_DOCKER_REGISTRY/llvm-build-cross-arm:1 PLATFORM_NAME_LINUX: "linux-amd64" @@ -40,6 +38,10 @@ variables: ARCHIVE_TOOL_WIN: "zip -9 -r" UNARCHIVE_TOOL_WIN: "unzip" ARCHIVE_EXT_WIN: "zip" + # Use Linux xz compressor to minimize Windows build artifact size. + # Upon release archive will be re-packed into zip format for uploading to GH. + ARCHIVE_TOOL_WIN_INT: ${ARCHIVE_TOOL_LINUX} + UNARCHIVE_TOOL_WIN_INT: ${UNARCHIVE_TOOL_LINUX} ARCHIVE_TOOL_MACOS: "tar -cJf" UNARCHIVE_TOOL_MACOS: "tar -xf" @@ -49,10 +51,13 @@ variables: UNARCHIVE_TOOL_NEWLIB: ${UNARCHIVE_TOOL_LINUX} ARCHIVE_EXT_NEWLIB: ${ARCHIVE_EXT_LINUX} - DIST_NEW_DIR: "_dist_new" + LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + DIST_DIR: "dist" - BUILD_DIR: "_build" - DOWNLOADS_DIR: "_downloads" + BUILD_DIR: "build" + DOWNLOADS_DIR: "downloads" ########################################################################### #################### START OF TEMPORARY LEGACY CODE ####################### @@ -62,548 +67,45 @@ variables: ##################### END OF TEMPORARY LEGACY CODE ######################## ########################################################################### -.use_ci_tools: &use_ci_tools | +.use_ci_tools_snippet: &use_ci_tools_snippet | curl -sSL ${CIT_LOADER_URL} -o cit_loader.sh && sh cit_loader.sh source citools/import_functions -.add_gitlab_key: &add_gitlab_key | - cit_add_ssh_key "${GITLAB_KEY}" - -before_script: - - *use_ci_tools - - *add_gitlab_key - -# Prepare release name/number -.get_release_name: &get_release_name | - # using annotated tags - REL_NUM=$(git describe --abbrev=7) - REL_NAME=${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} - ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} - LIBS_ARCHIVE_NAME=libs_${REL_NAME}.${ARCHIVE_EXT} - echo "PLATFORM_NAME: $PLATFORM_NAME" - echo "REL_NUM: $REL_NUM" - echo "REL_NAME: $REL_NAME" - echo "ARCHIVE_NAME: $ARCHIVE_NAME" - -# Get an existing crosstool-ng builds for all chips -.get_gcc_toolchain: &get_gcc_toolchain | - declare -a XTENSA_CPUS=("esp32" - "esp32s2" - "esp32s3") - for ((i = 0; i < ${#XTENSA_CPUS[@]}; i++)); do - XTENSA_CPU=${XTENSA_CPUS[$i]} - GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${ARCHIVE_EXT} - wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} - ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} - done; - GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${ARCHIVE_EXT} - wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} - ${UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} - -.get_clang_toolchain_build_scripts: &get_clang_toolchain_build_scripts | - git clone -b ${XTENSA_CLANG_TOOLCHAIN_REF} ${GITLAB_SSH_SERVER}/${XTENSA_CLANG_TOOLCHAIN_REPO} - cp -r xtensa-clang-toolchain/* . - -# LLVM Build System used the remote address to show detailed version info, we'll change it to the public repository -.fix_origin_remote_for_public: &fix_origin_remote_for_public | - git remote set-url origin "${GH_REPO_HTTPS}" - -# Pack the toolchain -.package_toolchain: &package_toolchain | - ${ARCHIVE_TOOL} ${ARCHIVE_NAME} esp-clang/ - mkdir -p ${DISTRO_DIR} - mv ${ARCHIVE_NAME} ${DISTRO_DIR}/ - echo "${ARCHIVE_NAME}" > ${DISTRO_DIR}/file_${PLATFORM_NAME} - -# Pack libs to be used for Rust, Go etc. -.package_libs: &package_libs | - ${ARCHIVE_TOOL} ${LIBS_ARCHIVE_NAME} esp-clang/lib/libclang* esp-clang/lib/clang/${CLANG_VER}/include - mkdir -p ${DISTRO_DIR} - mv ${LIBS_ARCHIVE_NAME} ${DISTRO_DIR}/ - echo "${LIBS_ARCHIVE_NAME}" > ${DISTRO_DIR}/file_libs-${PLATFORM_NAME} - -.get_binutils: &get_binutils | - git clone -b ${BINUTILS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${BINUTILS_REPO}.git - BINUTILS_PATH=$PWD/${BINUTILS_REPO} - -.get_xtensa_overlays: &get_xtensa_overlays | - git clone -b ${XTENSA_OVERLAYS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${XTENSA_OVERLAYS_REPO}.git - XTENSA_OVERLAYS_PATH=$PWD/${XTENSA_OVERLAYS_REPO} - -.get_newlib: &get_newlib | - git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git - NEWLIB_PATH=$PWD/${NEWLIB_REPO} - -.build_template: - stage: build - tags: [ "amd64", "build" ] - allow_failure: true - artifacts: - paths: - - ${DIST_DIR}/ - - ${BUILD_DIR}/tests.log - - ${BUILD_DIR}/build.log - when: always - expire_in: 1 day - variables: - BUILD_TOOLCHAIN_CMD_EXTRA_ARGS: "" - # use separate dist dir for universal toolchain - # TODO: remove this var after switching to universal toolchain builds - DIST_DIR: ${DIST_NEW_DIR} - script: - - *get_release_name - - mkdir ${DOWNLOADS_DIR} - - pushd ${DOWNLOADS_DIR} - - ESP_GCC_TOOLCHAIN_DIST_BASE=$PWD - - *get_gcc_toolchain - - *get_binutils - - *get_xtensa_overlays - - popd - - *get_clang_toolchain_build_scripts - - *fix_origin_remote_for_public - - LLVM_PROJECT_PATH=$PWD - - BUILD_PATH=$PWD/${BUILD_DIR} - - mkdir -p ${BUILD_PATH} - - export USE_PARALLEL_LINK_JOBS=2 - # build Clang toolchain w/o newlib - - ${BUILD_TOOLCHAIN_CMD} --llvm-path=${LLVM_PROJECT_PATH} - --gcc-toolchains-path=${ESP_GCC_TOOLCHAIN_DIST_BASE} --binutils-path=${BINUTILS_PATH} - --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} --host=${CONF_HOST} ${BUILD_TOOLCHAIN_CMD_EXTRA_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/build.log - - BUILD_HOST=$(gcc -dumpmachine) - # Do not run unit tests for cross-builds. - # Run as non-root user because permission tests fail when run by root. - - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then - export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-${CONF_HOST}-Release; - echo "Run unit tests for native build in ${LLVM_BUILD_PATH}"; - useradd -m test_runner; - chown -R test_runner ${LLVM_BUILD_PATH}; - touch ${BUILD_PATH}/tests.log; - chmod o+w ${BUILD_PATH}/tests.log; - runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target check-all 2>&1 > '${BUILD_PATH}'/tests.log'; - fi - - export DISTRO_DIR=$PWD/$DIST_DIR - - pushd ${BUILD_PATH} - - *package_toolchain - - popd - -.build_linux-gnu_template: - extends: .build_template - variables: - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" - -build_x86_64-linux-gnu: - extends: .build_linux-gnu_template - variables: - CONF_HOST: "x86_64-linux-gnu" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - -build_arm-linux-gnueabihf: - extends: .build_linux-gnu_template - image: ${CROSS_ARM_IMAGE} - variables: - CONF_HOST: "arm-linux-gnueabihf" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARMHF}" - -build_aarch64-linux-gnu: - extends: .build_linux-gnu_template - image: ${CROSS_ARM_IMAGE} - variables: - CONF_HOST: "aarch64-linux-gnu" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" - -build_x86_64-w64-mingw32: - extends: .build_template - needs: - # needs native toolchain and newlib from this job - - job: build_x86_64-linux-gnu - before_script: - - *use_ci_tools - - *add_gitlab_key - # get ARCHIVE_NAME for Linux release. Modify vars to make get_release_name working properly - - CLANG_LINUX_ARCHIVE=$(cat ${DIST_DIR}/file_${PLATFORM_NAME_LINUX}) - # unpack x86_64-linux-gnu toolchain to re-use it as native Clang for Windows build - - mkdir -p esp-clang-${PLATFORM_NAME_LINUX} - - ${UNARCHIVE_TOOL_LINUX} ${DIST_DIR}/${CLANG_LINUX_ARCHIVE} -C esp-clang-${PLATFORM_NAME_LINUX} - # we do not want to keep artifacts from 'x86_64-linux-gnu' job - - rm -rf ${DIST_DIR} - - rm -rf ${BUILD_DIR} - # add build command args speciifc for Windows build - - export BUILD_TOOLCHAIN_CMD_EXTRA_ARGS="--native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" - variables: - CONF_HOST: "x86_64-w64-mingw32" - PLATFORM_NAME: "${PLATFORM_NAME_WIN}" - # Use Linux compressor to minimize artifact size. - # Toolchain is not fully stripped yet, so may exceed max artifact size. - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" - ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" - -.build_apple-darwin_template: - extends: .build_template - variables: - ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" - ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" - BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" - -build_x86_64-apple-darwin: - extends: .build_apple-darwin_template - variables: - CONF_HOST: "x86_64-apple-darwin21.1" - PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" - -build_aarch64-apple-darwin: - extends: .build_apple-darwin_template - variables: - CONF_HOST: "aarch64-apple-darwin21.1" - PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" - -build_newlib: - stage: build - tags: [ "amd64", "build" ] - needs: - # needs native toolchainfrom this job - - job: build_x86_64-linux-gnu - artifacts: - paths: - - ${DIST_DIR}/ - - ${BUILD_DIR}/build.log - when: always - expire_in: 1 day - variables: - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - # use separate dist dir for universal toolchain - # TODO: remove this var after switching to universal toolchain builds - DIST_DIR: ${DIST_NEW_DIR} - script: - # get ARCHIVE_NAME for Linux release. - - CLANG_ARCHIVE=$PWD/${DIST_DIR}/$(cat ${DIST_DIR}/file_${PLATFORM_NAME_LINUX}) - - mkdir -p ${DOWNLOADS_DIR} - - pushd ${DOWNLOADS_DIR} - - *get_xtensa_overlays - - *get_newlib - # unpack clang - - ${UNARCHIVE_TOOL} ${CLANG_ARCHIVE} - - export PATH=$PWD/esp-clang/bin:$PATH - - popd - - rm -rf $PWD/${DIST_DIR} - - *get_clang_toolchain_build_scripts - # build newlib overlay using ESP native (Linux) clang toolchain only - # it will be re-used for cross-buit toolchains (win and mac). - - NEWLIB_OVERLAY_DISTRO_PATH=$PWD/${DIST_DIR} - - mkdir -p ${NEWLIB_OVERLAY_DISTRO_PATH} - - BUILD_PATH=$PWD/${BUILD_DIR} - - mkdir -p ${BUILD_PATH} - - ./build-toolchain.sh --newlib-path=${NEWLIB_PATH} --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/build.log - - pushd ${BUILD_PATH} - - ${ARCHIVE_TOOL_NEWLIB} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_NEWLIB} esp-clang/ - - popd - -.pack_template: - stage: pack - tags: [ "amd64", "build" ] - allow_failure: true - artifacts: - paths: - - ${DIST_DIR}/ - when: always - expire_in: 3 day - variables: - # use separate dist dir for universal toolchain - # TODO: remove this var after switching to universal toolchain builds - DIST_DIR: ${DIST_NEW_DIR} - script: - - *get_release_name - - export BUILD_PATH=$PWD/${BUILD_DIR} - - mkdir -p ${BUILD_PATH} - # unpack clang - - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} -C ${BUILD_PATH} - # unpack newlib - - ${UNARCHIVE_TOOL_NEWLIB} ${DIST_DIR}/esp-clang-newlib-overlay.${ARCHIVE_EXT_NEWLIB} -C ${BUILD_PATH} - - rm -rf ${DIST_DIR} - - *get_clang_toolchain_build_scripts - # strip binutils afer newlib is built - - STRIP_BINUTILS=YES ./build-toolchain.sh --host=${CONF_HOST} ${BUILD_PATH} - - DISTRO_DIR=$PWD/${DIST_DIR} - - pushd ${BUILD_PATH} - - *package_toolchain - - *package_libs - - popd - -.pack_linux-gnu_template: - extends: .pack_template - variables: - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - -pack_x86_64-linux-gnu: - extends: .pack_linux-gnu_template - needs: - - job: build_x86_64-linux-gnu - - job: build_newlib - variables: - CONF_HOST: "x86_64-linux-gnu" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - -pack_arm-linux-gnueabihf: - extends: .pack_linux-gnu_template - image: ${CROSS_ARM_IMAGE} - needs: - - job: build_arm-linux-gnueabihf - - job: build_newlib - variables: - CONF_HOST: "arm-linux-gnueabihf" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARMHF}" - -pack_aarch64-linux-gnu: - extends: .pack_linux-gnu_template - image: ${CROSS_ARM_IMAGE} - needs: - - job: build_aarch64-linux-gnu - - job: build_newlib - variables: - CONF_HOST: "aarch64-linux-gnu" - PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" - -pack_x86_64-w64-mingw32: - extends: .pack_template - needs: - - job: build_x86_64-w64-mingw32 - - job: build_newlib - variables: - CONF_HOST: "x86_64-w64-mingw32" - PLATFORM_NAME: "${PLATFORM_NAME_WIN}" - # use Linux compressor to save space. - # upon release archive will be re-packed into zip format for uploading to GH - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" - -.pack_apple-darwin_template: - extends: .pack_template - variables: - ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" - ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" - -pack_x86_64-apple-darwin: - extends: .pack_apple-darwin_template - needs: - - job: build_x86_64-apple-darwin - - job: build_newlib - variables: - CONF_HOST: "x86_64-apple-darwin21.1" - PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" - -pack_aarch64-apple-darwin: - extends: .pack_apple-darwin_template - needs: - - job: build_aarch64-apple-darwin - - job: build_newlib - variables: - CONF_HOST: "aarch64-apple-darwin21.1" - PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" - -test_x86_64-linux-gnu: - stage: test - tags: [ "amd64", "build" ] - allow_failure: true - needs: - - job: pack_x86_64-linux-gnu - variables: - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - # use separate dist dir for universal toolchain - # TODO: remove this var after switching to universal toolchain builds - DIST_DIR: ${DIST_NEW_DIR} +.use_ci_tools: script: - - *get_release_name - - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} - # getting testsuite - - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git - # preparing testsuite - - export PATH=${PWD}/esp-clang/bin:$PATH - - cd llvm-xtensa-testsuite - # qemu - - ./qemu_esp32_install.sh - # run testsuite for esp32 - - ./run_esp32_tests.sh - -########################################################################### -#################### START OF TEMPORARY LEGACY CODE ####################### -# TODO: the code below is to be removed after migration to new build script -.get_release_name_old: &get_release_name_old | - # using annotated tags - REL_NUM=$(git describe --abbrev=7) - REL_SFX="llvm15_0_0" - REL_NAME=${CONF_TARGET}-${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} - ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} - echo "PLATFORM_NAME: $PLATFORM_NAME" - echo "REL_NUM: $REL_NUM" - echo "REL_NAME: $REL_NAME" - echo "ARCHIVE_NAME: $ARCHIVE_NAME" - -.get_gcc_toolchain_old: &get_gcc_toolchain_old | - wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} - ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} - if [[ "$XTENSA_GCC_TOOLCHAIN" == *"linux-amd64"* ]]; then - cp -r xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} - else - mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} - wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz - tar -xf xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz - fi - export GCC_ESP32_LINUX_TOOLCHAIN="xtensa-esp32-elf" + - *use_ci_tools_snippet -.package_toolchain_old: &package_toolchain_old | - ${ARCHIVE_TOOL} ${ARCHIVE_NAME} ${XTENSA_CLANG_TOOLCHAIN}/ - mkdir -p ${DIST_DIR} - mv ${ARCHIVE_NAME} ${DIST_DIR}/ - echo "${ARCHIVE_NAME}" > ${DIST_DIR}/file_${PLATFORM_NAME}_${CONF_TARGET} +.add_gitlab_key_snippet: &add_gitlab_key_snippet | + cit_add_ssh_key "${GITLAB_KEY}" -.build_template_old: - stage: build - tags: [ "amd64", "build" ] - artifacts: - paths: - - ${DIST_DIR}/ - when: always - expire_in: 10 day - variables: - XTENSA_CLANG_TOOLCHAIN_REF: "release_esp32_clang_15.0.0_gcc_8.4.0" - GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" +.add_gitlab_key: script: - - *get_release_name_old - - *get_gcc_toolchain_old - - *fix_origin_remote_for_public - - *get_clang_toolchain_build_scripts - - ${BUILD_TOOLCHAIN_CMD} "${XTENSA_CLANG_TOOLCHAIN}" - - *package_toolchain_old - -linux_amd64_build: - extends: .build_template_old - variables: - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux.sh" + - *add_gitlab_key_snippet -linux_arm64_build: - extends: .build_template_old - image: ${CROSS_ARM_IMAGE} - variables: - PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-arm64.tar.gz" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux-arm64.sh" - -win64_build: - extends: .build_template_old - variables: - PLATFORM_NAME: "${PLATFORM_NAME_WIN}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" - ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" - XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-win64.zip" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" - -macos_amd64_build: - extends: .build_template_old - variables: - PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" - ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" - XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-macos.tar.gz" - BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh" +# LLVM Build System used the remote address to show detailed version info, we'll change it to the public repository +.fix_origin_remote_for_public_snippet: &fix_origin_remote_for_public_snippet | + git remote set-url origin "${GH_REPO_HTTPS}" -linux_amd64_testsuite: - stage: test - tags: [ "amd64", "build" ] - needs: - - job: linux_amd64_build - variables: - PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" +.fix_origin_remote_for_public: script: - - *get_release_name_old - - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} - - # getting testsuite - - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git - - # preparing testsuite - - export PATH=${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/:$PATH - - cd llvm-xtensa-testsuite - - # qemu - - ./qemu_esp32_install.sh - - # run testsuite for esp32 - - ./run_esp32_tests.sh + - *fix_origin_remote_for_public_snippet - # run testsuite for compiler_rt library - - ./run_esp32_crt_tests.sh ../$XTENSA_CLANG_TOOLCHAIN - -##################### END OF TEMPORARY LEGACY CODE ######################## -########################################################################### +.get_clang_toolchain_build_scripts_snippet: &get_clang_toolchain_build_scripts_snippet | + git clone -b ${XTENSA_CLANG_TOOLCHAIN_REF} ${GITLAB_SSH_SERVER}/${XTENSA_CLANG_TOOLCHAIN_REPO} + cp -r xtensa-clang-toolchain/* . -upload_to_http: - stage: private_deploy - when: manual - allow_failure: true - tags: [ "deploy", "shiny" ] - variables: - # force the fetch strategy to clean old archives up in dist/ dir - GIT_STRATEGY: fetch - before_script: - - *use_ci_tools +.get_clang_toolchain_build_scripts: script: - - cit_add_ssh_key "${HTTP_UPLOAD_KEY}" - # List of archives - - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) - - cd ${DIST_DIR} - - scp ${FILES} ${HTTP_UPLOAD_DIR}/ct-ng/llvm-builds - # Show info - - echo -e "\nArchives were published there:\n\n$(for n in ${FILES}; do echo "${HTTP_PUBLIC_DIR}/ct-ng/llvm-builds/${n}"; done)\n" + - *get_clang_toolchain_build_scripts_snippet -upload_to_github: - stage: public_deploy - when: manual - allow_failure: true - only: - - tags - tags: [ "amd64", "internet" ] - image: espressif/github-hub:2 - variables: - GIT_STRATEGY: fetch - GITHUB_TOKEN: "${GH_TOKEN}" - GITHUB_REPO: "${GH_REPO_HTTPS}" - TAG: "${CI_COMMIT_TAG}" - before_script: [] - script: - - ls -l dist*/ - - git remote add github ${GH_REPO_HTTPS} - - hub release show ${TAG} || { echo "Please create a release on GitHub with ${TAG} tag at first"; exit 1; } - # List of archives - - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) - - cd ${DIST_DIR} - - ls -l $FILES - # Upload archives - - for n in ${FILES}; do hub release edit -m "" -a "${n}" "${TAG}"; done +before_script: + - !reference [.use_ci_tools, script] + - !reference [.add_gitlab_key, script] + +include: + - local: .universal-toolchain-release.yml + rules: + - if: $ESP_CLANG_LEGACY_RELEASE != "true" + - local: .legacy-release.yml + rules: + - if: $ESP_CLANG_LEGACY_RELEASE == "true" diff --git a/.legacy-release.yml b/.legacy-release.yml new file mode 100644 index 0000000000000..c46195f3fe475 --- /dev/null +++ b/.legacy-release.yml @@ -0,0 +1,164 @@ + +.get_release_name_legacy: &get_release_name_legacy | + # using annotated tags + REL_NUM=$(git describe --abbrev=7) + REL_SFX="llvm15_0_0" + REL_NAME=${CONF_TARGET}-${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} + ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} + echo "PLATFORM_NAME: $PLATFORM_NAME" + echo "REL_NUM: $REL_NUM" + echo "REL_NAME: $REL_NAME" + echo "ARCHIVE_NAME: $ARCHIVE_NAME" + +.get_gcc_toolchain_legacy: &get_gcc_toolchain_legacy | + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/${XTENSA_GCC_TOOLCHAIN} + ${UNARCHIVE_TOOL} ${XTENSA_GCC_TOOLCHAIN} + if [[ "$XTENSA_GCC_TOOLCHAIN" == *"linux-amd64"* ]]; then + cp -r xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + else + mv xtensa-esp32-elf ${XTENSA_CLANG_TOOLCHAIN} + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz + tar -xf xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz + fi + export GCC_ESP32_LINUX_TOOLCHAIN="xtensa-esp32-elf" + +.package_toolchain_legacy: &package_toolchain_legacy | + ${ARCHIVE_TOOL} ${ARCHIVE_NAME} ${XTENSA_CLANG_TOOLCHAIN}/ + mkdir -p ${DIST_DIR} + mv ${ARCHIVE_NAME} ${DIST_DIR}/ + echo "${ARCHIVE_NAME}" > ${DIST_DIR}/file_${PLATFORM_NAME}_${CONF_TARGET} + +.build_template_legacy: + stage: build + tags: [ "amd64", "build" ] + artifacts: + paths: + - ${DIST_DIR}/ + when: always + expire_in: 10 day + variables: + XTENSA_CLANG_TOOLCHAIN_REF: "release_esp32_clang_15.0.0_gcc_8.4.0" + GCC_REL_NAME: "gcc8_4_0-esp-2021r2-patch3" + script: + - *get_release_name_legacy + - *get_gcc_toolchain_legacy + - !reference [.fix_origin_remote_for_public, script] + - !reference [.get_clang_toolchain_build_scripts, script] + - ${BUILD_TOOLCHAIN_CMD} "${XTENSA_CLANG_TOOLCHAIN}" + - *package_toolchain_legacy + +linux_amd64_build: + extends: .build_template_legacy + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-amd64.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux.sh" + +linux_arm64_build: + extends: .build_template_legacy + image: ${CROSS_ARM_IMAGE} + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-linux-arm64.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-linux-arm64.sh" + +win64_build: + extends: .build_template_legacy + variables: + PLATFORM_NAME: "${PLATFORM_NAME_WIN}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" + ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-win64.zip" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" + +macos_amd64_build: + extends: .build_template_legacy + variables: + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + XTENSA_GCC_TOOLCHAIN: "xtensa-esp32-elf-${GCC_REL_NAME}-macos.tar.gz" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-macos.sh" + +linux_amd64_testsuite: + stage: test + tags: [ "amd64", "build" ] + needs: + - job: linux_amd64_build + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + LLVM_GCC_TESTSUITE_REF: "feature/ci_llvm_multitarget_crt_tests" + script: + - *get_release_name_legacy + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} + + # getting testsuite + - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + + # preparing testsuite + - export PATH=${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/:$PATH + - cd llvm-xtensa-testsuite + + # qemu + - ./qemu_esp32_install.sh + + # run testsuite for esp32 + - ./run_esp32_tests.sh + + # run testsuite for compiler_rt library + - ./run_esp32_crt_tests.sh ../$XTENSA_CLANG_TOOLCHAIN + +upload_to_http_legacy: + stage: private_deploy + when: manual + allow_failure: true + tags: [ "deploy", "shiny" ] + variables: + # force the fetch strategy to clean old archives up in dist/ dir + GIT_STRATEGY: fetch + before_script: + - !reference [.use_ci_tools, script] + script: + - cit_add_ssh_key "${HTTP_UPLOAD_KEY}" + # List of archives + - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) + - cd ${DIST_DIR} + - scp ${FILES} ${HTTP_UPLOAD_DIR}/ct-ng/llvm-builds + # Show info + - echo -e "\nArchives were published there:\n\n$(for n in ${FILES}; do echo "${HTTP_PUBLIC_DIR}/ct-ng/llvm-builds/${n}"; done)\n" + +upload_to_github_legacy: + stage: public_deploy + when: manual + allow_failure: true + only: + - tags + tags: [ "amd64", "internet" ] + image: espressif/github-hub:2 + variables: + GIT_STRATEGY: fetch + GITHUB_TOKEN: "${GH_TOKEN}" + GITHUB_REPO: "${GH_REPO_HTTPS}" + TAG: "${CI_COMMIT_TAG}" + before_script: [] + script: + - ls -l dist*/ + - git remote add github ${GH_REPO_HTTPS} + - hub release show ${TAG} || { echo "Please create a release on GitHub with ${TAG} tag at first"; exit 1; } + # List of archives + - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) + - cd ${DIST_DIR} + - ls -l $FILES + # Upload archives + - for n in ${FILES}; do hub release edit -m "" -a "${n}" "${TAG}"; done diff --git a/.universal-toolchain-release.yml b/.universal-toolchain-release.yml new file mode 100644 index 0000000000000..baf00964c2439 --- /dev/null +++ b/.universal-toolchain-release.yml @@ -0,0 +1,409 @@ + +# Prepare release name/number +.get_release_name: &get_release_name | + # using annotated tags + REL_NUM=$(git describe --abbrev=7) + REL_NAME=${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} + ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} + LIBS_ARCHIVE_NAME=libs_${REL_NAME}.${LIBS_ARCHIVE_EXT} + echo "PLATFORM_NAME: $PLATFORM_NAME" + echo "REL_NUM: $REL_NUM" + echo "REL_NAME: $REL_NAME" + echo "ARCHIVE_NAME: $ARCHIVE_NAME" + +# Get an existing crosstool-ng builds for all chips +.get_gcc_toolchain: &get_gcc_toolchain | + declare -a XTENSA_CPUS=("esp32" + "esp32s2" + "esp32s3") + for ((i = 0; i < ${#XTENSA_CPUS[@]}; i++)); do + XTENSA_CPU=${XTENSA_CPUS[$i]} + GCC_TOOLCHAIN_ARCH=xtensa-${XTENSA_CPU}-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${GCC_ARCHIVE_EXT} + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} + ${GCC_UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} + done; + GCC_TOOLCHAIN_ARCH=riscv32-esp-elf-${GCC_REL_VER}-${GCC_REL_NAME}-${PLATFORM_NAME}.${GCC_ARCHIVE_EXT} + wget --no-verbose https://dl.espressif.com/github_assets/espressif/crosstool-NG/releases/download/${GCC_REL_NAME}/${GCC_TOOLCHAIN_ARCH} + ${GCC_UNARCHIVE_TOOL} ${GCC_TOOLCHAIN_ARCH} + +# Pack the toolchain +.package_toolchain: &package_toolchain | + ${ARCHIVE_TOOL} ${ARCHIVE_NAME} esp-clang/ + mkdir -p ${DISTRO_DIR} + mv ${ARCHIVE_NAME} ${DISTRO_DIR}/ + echo "${ARCHIVE_NAME}" > ${DISTRO_DIR}/file_${PLATFORM_NAME} + +# Pack libs to be used for Rust, Go etc. +.package_libs: &package_libs | + ${LIBS_ARCHIVE_TOOL} ${LIBS_ARCHIVE_NAME} esp-clang/lib/libclang* esp-clang/lib/clang/${CLANG_VER}/include + mkdir -p ${DISTRO_DIR} + mv ${LIBS_ARCHIVE_NAME} ${DISTRO_DIR}/ + echo "${LIBS_ARCHIVE_NAME}" > ${DISTRO_DIR}/file_libs-${PLATFORM_NAME} + +.get_binutils: &get_binutils | + git clone -b ${BINUTILS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${BINUTILS_REPO}.git + BINUTILS_PATH=$PWD/${BINUTILS_REPO} + +.get_xtensa_overlays: &get_xtensa_overlays | + git clone -b ${XTENSA_OVERLAYS_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${XTENSA_OVERLAYS_REPO}.git + XTENSA_OVERLAYS_PATH=$PWD/${XTENSA_OVERLAYS_REPO} + +.get_newlib: &get_newlib | + git clone -b ${NEWLIB_REF} --single-branch ${GITLAB_SSH_SERVER}/idf/${NEWLIB_REPO}.git + NEWLIB_PATH=$PWD/${NEWLIB_REPO} + +.build_template: + stage: build + tags: [ "amd64", "build" ] + artifacts: + paths: + - ${DIST_DIR}/ + - ${BUILD_DIR}/tests.log + - ${BUILD_DIR}/build.log + when: always + expire_in: 1 day + variables: + BUILD_TOOLCHAIN_CMD_EXTRA_ARGS: "" + script: + - *get_release_name + - mkdir ${DOWNLOADS_DIR} + - pushd ${DOWNLOADS_DIR} + - ESP_GCC_TOOLCHAIN_DIST_BASE=$PWD + - *get_gcc_toolchain + - *get_binutils + - *get_xtensa_overlays + - popd + - !reference [.get_clang_toolchain_build_scripts, script] + - !reference [.fix_origin_remote_for_public, script] + - LLVM_PROJECT_PATH=$PWD + - BUILD_PATH=$PWD/${BUILD_DIR} + - mkdir -p ${BUILD_PATH} + - export USE_PARALLEL_LINK_JOBS=2 + # build Clang toolchain w/o newlib + - ${BUILD_TOOLCHAIN_CMD} --llvm-path=${LLVM_PROJECT_PATH} + --gcc-toolchains-path=${ESP_GCC_TOOLCHAIN_DIST_BASE} --binutils-path=${BINUTILS_PATH} + --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} --host=${CONF_HOST} ${BUILD_TOOLCHAIN_CMD_EXTRA_ARGS} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/build.log + - BUILD_HOST=$(gcc -dumpmachine) + # Do not run unit tests for cross-builds. + # Run as non-root user because permission tests fail when run by root. + - if [ "${CONF_HOST}" == "${BUILD_HOST}" ]; then + export LLVM_BUILD_PATH=${LLVM_PROJECT_PATH}/llvm/build-${CONF_HOST}-Release; + echo "Run unit tests for native build in ${LLVM_BUILD_PATH}"; + useradd -m test_runner; + chown -R test_runner ${LLVM_BUILD_PATH}; + touch ${BUILD_PATH}/tests.log; + chmod o+w ${BUILD_PATH}/tests.log; + runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target check-all 2>&1 > '${BUILD_PATH}'/tests.log'; + fi + - export DISTRO_DIR=$PWD/$DIST_DIR + - pushd ${BUILD_PATH} + - *package_toolchain + - popd + +.build_linux-gnu_template: + extends: .build_template + variables: + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + GCC_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + GCC_ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" + +build_x86_64-linux-gnu: + extends: .build_linux-gnu_template + variables: + CONF_HOST: "x86_64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + +build_arm-linux-gnueabihf: + extends: .build_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + variables: + CONF_HOST: "arm-linux-gnueabihf" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARMHF}" + +build_aarch64-linux-gnu: + extends: .build_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + variables: + CONF_HOST: "aarch64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" + +build_x86_64-w64-mingw32: + extends: .build_template + needs: + # needs native toolchain and newlib from this job + - job: build_x86_64-linux-gnu + before_script: + - !reference [.use_ci_tools, script] + - !reference [.add_gitlab_key, script] + # get ARCHIVE_NAME for Linux release. Modify vars to make get_release_name working properly + - CLANG_LINUX_ARCHIVE=$(cat ${DIST_DIR}/file_${PLATFORM_NAME_LINUX}) + # unpack x86_64-linux-gnu toolchain to re-use it as native Clang for Windows build + - mkdir -p esp-clang-${PLATFORM_NAME_LINUX} + - ${UNARCHIVE_TOOL_LINUX} ${DIST_DIR}/${CLANG_LINUX_ARCHIVE} -C esp-clang-${PLATFORM_NAME_LINUX} + # we do not want to keep artifacts from 'x86_64-linux-gnu' job + - rm -rf ${DIST_DIR} + - rm -rf ${BUILD_DIR} + # add build command args speciifc for Windows build + - export BUILD_TOOLCHAIN_CMD_EXTRA_ARGS="--native-esp-clang-path=$PWD/esp-clang-${PLATFORM_NAME_LINUX}" + variables: + CONF_HOST: "x86_64-w64-mingw32" + PLATFORM_NAME: "${PLATFORM_NAME_WIN}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + GCC_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" + GCC_ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + BUILD_TOOLCHAIN_CMD: "./build-toolchain-win.sh" + +.build_apple-darwin_template: + extends: .build_template + variables: + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + GCC_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + GCC_ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + BUILD_TOOLCHAIN_CMD: "./build-toolchain.sh" + +build_x86_64-apple-darwin: + extends: .build_apple-darwin_template + variables: + CONF_HOST: "x86_64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + +build_aarch64-apple-darwin: + extends: .build_apple-darwin_template + variables: + CONF_HOST: "aarch64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" + +build_newlib: + stage: build + tags: [ "amd64", "build" ] + needs: + # needs native toolchainfrom this job + - job: build_x86_64-linux-gnu + artifacts: + paths: + - ${DIST_DIR}/ + - ${BUILD_DIR}/build.log + when: always + expire_in: 1 day + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + script: + # get ARCHIVE_NAME for Linux release. + - CLANG_ARCHIVE=$PWD/${DIST_DIR}/$(cat ${DIST_DIR}/file_${PLATFORM_NAME_LINUX}) + - mkdir -p ${DOWNLOADS_DIR} + - pushd ${DOWNLOADS_DIR} + - *get_xtensa_overlays + - *get_newlib + # unpack clang + - ${UNARCHIVE_TOOL} ${CLANG_ARCHIVE} + - export PATH=$PWD/esp-clang/bin:$PATH + - popd + - rm -rf $PWD/${DIST_DIR} + - !reference [.get_clang_toolchain_build_scripts, script] + # build newlib overlay using ESP native (Linux) clang toolchain only + # it will be re-used for cross-buit toolchains (win and mac). + - NEWLIB_OVERLAY_DISTRO_PATH=$PWD/${DIST_DIR} + - mkdir -p ${NEWLIB_OVERLAY_DISTRO_PATH} + - BUILD_PATH=$PWD/${BUILD_DIR} + - mkdir -p ${BUILD_PATH} + - ./build-toolchain.sh --newlib-path=${NEWLIB_PATH} --xtensa-overlays-path=${XTENSA_OVERLAYS_PATH} ${BUILD_PATH} 2>&1 > ${BUILD_PATH}/build.log + - pushd ${BUILD_PATH} + - ${ARCHIVE_TOOL_NEWLIB} ${NEWLIB_OVERLAY_DISTRO_PATH}/esp-clang-newlib-overlay.${ARCHIVE_EXT_NEWLIB} esp-clang/ + - popd + +.pack_template: + stage: pack + tags: [ "amd64", "build" ] + artifacts: + paths: + - ${DIST_DIR}/ + when: always + expire_in: 3 day + script: + - *get_release_name + - export BUILD_PATH=$PWD/${BUILD_DIR} + - mkdir -p ${BUILD_PATH} + # unpack clang + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} -C ${BUILD_PATH} + # unpack newlib + - ${UNARCHIVE_TOOL_NEWLIB} ${DIST_DIR}/esp-clang-newlib-overlay.${ARCHIVE_EXT_NEWLIB} -C ${BUILD_PATH} + - rm -rf ${DIST_DIR} + - !reference [.get_clang_toolchain_build_scripts, script] + # strip binutils afer newlib is built + - STRIP_BINUTILS=YES ./build-toolchain.sh --host=${CONF_HOST} ${BUILD_PATH} + - DISTRO_DIR=$PWD/${DIST_DIR} + - pushd ${BUILD_PATH} + - *package_toolchain + - *package_libs + - popd + +.pack_linux-gnu_template: + extends: .pack_template + variables: + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + +pack_x86_64-linux-gnu: + extends: .pack_linux-gnu_template + needs: + - job: build_x86_64-linux-gnu + - job: build_newlib + variables: + CONF_HOST: "x86_64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + +pack_arm-linux-gnueabihf: + extends: .pack_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + needs: + - job: build_arm-linux-gnueabihf + - job: build_newlib + variables: + CONF_HOST: "arm-linux-gnueabihf" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARMHF}" + +pack_aarch64-linux-gnu: + extends: .pack_linux-gnu_template + image: ${CROSS_ARM_IMAGE} + needs: + - job: build_aarch64-linux-gnu + - job: build_newlib + variables: + CONF_HOST: "aarch64-linux-gnu" + PLATFORM_NAME: "${PLATFORM_NAME_LINUX_ARM64}" + +pack_x86_64-w64-mingw32: + extends: .pack_template + needs: + - job: build_x86_64-w64-mingw32 + - job: build_newlib + variables: + CONF_HOST: "x86_64-w64-mingw32" + PLATFORM_NAME: "${PLATFORM_NAME_WIN}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" + LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" + LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + +.pack_apple-darwin_template: + extends: .pack_template + variables: + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + +pack_x86_64-apple-darwin: + extends: .pack_apple-darwin_template + needs: + - job: build_x86_64-apple-darwin + - job: build_newlib + variables: + CONF_HOST: "x86_64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + +pack_aarch64-apple-darwin: + extends: .pack_apple-darwin_template + needs: + - job: build_aarch64-apple-darwin + - job: build_newlib + variables: + CONF_HOST: "aarch64-apple-darwin21.1" + PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" + +test_x86_64-linux-gnu: + stage: test + tags: [ "amd64", "build" ] + needs: + - job: pack_x86_64-linux-gnu + variables: + PLATFORM_NAME: "${PLATFORM_NAME_LINUX}" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" + ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" + script: + - *get_release_name + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} + # getting testsuite + - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + # preparing testsuite + - export PATH=${PWD}/esp-clang/bin:$PATH + - cd llvm-xtensa-testsuite + # qemu + - ./qemu_esp32_install.sh + # run testsuite for esp32 + - ./run_esp32_tests.sh + +upload_to_http: + stage: private_deploy + when: manual + allow_failure: true + tags: [ "deploy", "shiny" ] + variables: + # force the fetch strategy to clean old archives up in dist/ dir + GIT_STRATEGY: fetch + needs: + - job: pack_x86_64-linux-gnu + - job: pack_arm-linux-gnueabihf + - job: pack_aarch64-linux-gnu + - job: pack_x86_64-w64-mingw32 + - job: pack_x86_64-apple-darwin + - job: pack_aarch64-apple-darwin + before_script: + - !reference [.use_ci_tools, script] + script: + - cit_add_ssh_key "${HTTP_UPLOAD_KEY}" + # List of archives + - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) + - cd ${DIST_DIR} + - ls -l $FILES + - scp ${FILES} ${HTTP_UPLOAD_DIR}/ct-ng/llvm-builds + # Show info + - echo -e "\nArchives were published there:\n\n$(for n in ${FILES}; do echo "${HTTP_PUBLIC_DIR}/ct-ng/llvm-builds/${n}"; done)\n" + +upload_to_github: + stage: public_deploy + when: manual + allow_failure: true + only: + - tags + tags: [ "amd64", "internet" ] + image: espressif/github-hub:2 + variables: + GIT_STRATEGY: fetch + GITHUB_TOKEN: "${GH_TOKEN}" + GITHUB_REPO: "${GH_REPO_HTTPS}" + TAG: "${CI_COMMIT_TAG}" + needs: + - job: pack_x86_64-linux-gnu + - job: pack_arm-linux-gnueabihf + - job: pack_aarch64-linux-gnu + - job: pack_x86_64-w64-mingw32 + - job: pack_x86_64-apple-darwin + - job: pack_aarch64-apple-darwin + before_script: [] + script: + - ls -l dist*/ + - git remote add github ${GH_REPO_HTTPS} + - hub release show ${TAG} || { echo "Please create a release on GitHub with ${TAG} tag at first"; exit 1; } + # List of archives + - FILES=$(find ${DIST_DIR} -name file_\* -exec cat {} \+) + - cd ${DIST_DIR} + - ls -l $FILES + # Upload archives + - for n in ${FILES}; do hub release edit -m "" -a "${n}" "${TAG}"; done From 9840a973b862b082a2b06718cf61d84e43833415 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Tue, 13 Sep 2022 13:43:36 +0300 Subject: [PATCH 129/150] esp/ci: Adds MacOS binaries signing stage --- .gitlab-ci.yml | 1 + .universal-toolchain-release.yml | 59 +++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d4a2c816f97ef..e152a1c90a6e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ stages: - build - pack + - sign - private_deploy - test - public_deploy diff --git a/.universal-toolchain-release.yml b/.universal-toolchain-release.yml index baf00964c2439..3f15eb9637a31 100644 --- a/.universal-toolchain-release.yml +++ b/.universal-toolchain-release.yml @@ -349,6 +349,57 @@ test_x86_64-linux-gnu: # run testsuite for esp32 - ./run_esp32_tests.sh +.macos_codesign: &macos_codesign + stage: sign + tags: [ "darwin", "amd64" ] + resource_group: macos_codesign + artifacts: + paths: + - ${DIST_DIR}/ + when: always + expire_in: 3 day + variables: + KEYCHAIN_NAME: "llvm.keychain" + ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" + UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" + ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" + script: + - *get_release_name + - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} + - rm -rf ${DIST_DIR} + - TOOLCHAIN_PATH=$PWD/esp-clang + - echo $MACOS_CERTIFICATE | base64 --decode > $PWD/certificate.p12 + - security create-keychain -p $KEYCHAIN_PWD $KEYCHAIN_NAME || true + - security import $PWD/certificate.p12 -k $KEYCHAIN_NAME -P $MACOS_CERTIFICATE_PWD -T /usr/bin/codesign + - security set-key-partition-list -S apple-tool:,apple:,codesign -s -k $KEYCHAIN_PWD $KEYCHAIN_NAME + - security list-keychains -d user -s ~/Library/Keychains/$KEYCHAIN_NAME + - security find-identity -v -p codesigning + - security unlock-keychain -p $KEYCHAIN_PWD $KEYCHAIN_NAME + - /usr/bin/codesign -v --force --options runtime -s $IDENTITY_ID $TOOLCHAIN_PATH/bin/* $TOOLCHAIN_PATH/lib/*.dylib + - security delete-keychain $KEYCHAIN_NAME + - codesign -dvv $TOOLCHAIN_PATH/bin/* + - DISTRO_DIR=$PWD/${DIST_DIR} + - *package_toolchain + - *package_libs + after_script: + - security find-identity -v + - security delete-keychain $KEYCHAIN_NAME + - security find-identity -v + +sign_x86_64-apple-darwin: + extends: .macos_codesign + needs: + - pack_x86_64-apple-darwin + variables: + PLATFORM_NAME: "${PLATFORM_NAME_MACOS}" + +sign_aarch64-apple-darwin: + extends: .macos_codesign + needs: + - pack_aarch64-apple-darwin + variables: + PLATFORM_NAME: "${PLATFORM_NAME_MACOS_ARM64}" + upload_to_http: stage: private_deploy when: manual @@ -362,8 +413,8 @@ upload_to_http: - job: pack_arm-linux-gnueabihf - job: pack_aarch64-linux-gnu - job: pack_x86_64-w64-mingw32 - - job: pack_x86_64-apple-darwin - - job: pack_aarch64-apple-darwin + - job: sign_x86_64-apple-darwin + - job: sign_aarch64-apple-darwin before_script: - !reference [.use_ci_tools, script] script: @@ -394,8 +445,8 @@ upload_to_github: - job: pack_arm-linux-gnueabihf - job: pack_aarch64-linux-gnu - job: pack_x86_64-w64-mingw32 - - job: pack_x86_64-apple-darwin - - job: pack_aarch64-apple-darwin + - job: sign_x86_64-apple-darwin + - job: sign_aarch64-apple-darwin before_script: [] script: - ls -l dist*/ From 34236f65202841d93f0273d6d06fafd65c2c709d Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Mon, 12 Sep 2022 18:07:08 +0100 Subject: [PATCH 130/150] [Xtensa] Xtensa ABI 128bit arg alignment - Forces 128bit arguments to have 128bit alignment as per the Xtensa ABI in LLVM & Clang. - Adds a check in the Xtensa calling convention to ensure 128bit aligned arguments are always passed as the first argument _or_ passed via the stack. --- clang/lib/Basic/Targets/Xtensa.h | 2 +- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 9 +++++++-- llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/lib/Basic/Targets/Xtensa.h b/clang/lib/Basic/Targets/Xtensa.h index dde374bea3e61..b243a91c679e4 100644 --- a/clang/lib/Basic/Targets/Xtensa.h +++ b/clang/lib/Basic/Targets/Xtensa.h @@ -50,7 +50,7 @@ class LLVM_LIBRARY_VISIBILITY XtensaTargetInfo : public TargetInfo { WIntType = UnsignedInt; UseZeroLengthBitfieldAlignment = true; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; - resetDataLayout("e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32"); + resetDataLayout("e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32"); } void getTargetDefines(const LangOptions &Opts, diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 4b4dd1b3f50e8..f0b1af9263fb1 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -755,14 +755,19 @@ static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT, unsigned Reg; Align OrigAlign = ArgFlags.getNonZeroOrigAlign(); - bool isI64 = (ValVT == MVT::i32 && OrigAlign == Align(8)); + bool needs64BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(8)); + bool needs128BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(16)); if (ValVT == MVT::i32 || ValVT == MVT::f32) { Reg = State.AllocateReg(IntRegs); // If this is the first part of an i64 arg, // the allocated register must be either A2, A4 or A6. - if (isI64 && (Reg == Xtensa::A3 || Reg == Xtensa::A5 || Reg == Xtensa::A7)) + if (needs64BitAlign && (Reg == Xtensa::A3 || Reg == Xtensa::A5 || Reg == Xtensa::A7)) Reg = State.AllocateReg(IntRegs); + // arguments with 16byte alignment must be passed in the first register or passed via stack + if (needs128BitAlign && Reg != Xtensa::A2) + while ( (Reg = State.AllocateReg(IntRegs)) ) { + } LocVT = MVT::i32; } else if (ValVT == MVT::f64) { // Allocate int register and shadow next int register. diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index eb190ad853823..9e39f1d502e6f 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -33,7 +33,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTarget() { static std::string computeDataLayout(const Triple &TT, StringRef CPU, const TargetOptions &Options, bool IsLittle) { - std::string Ret = "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32"; + std::string Ret = "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32"; return Ret; } From a9754a18bb91b263ba2ae6b8b7d4d1b72b65a8c7 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Tue, 30 Aug 2022 10:41:44 +0300 Subject: [PATCH 131/150] [Xtensa] Fix Call ABI for 16 byte alignment. --- clang/lib/CodeGen/TargetInfo.cpp | 7 ++++--- clang/test/CodeGen/xtensa-abi.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index b7d5fc8ea5cfa..2d714df600fb8 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -11618,9 +11618,8 @@ ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, if (Size < 32 && Ty->isIntegralOrEnumerationType() && !MustUseStack) { return extendType(Ty); } - if (Size == 64) - return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64)); - return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 32)); + // Assume that type has 32, 64 or 128 bits + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } // Aggregates which are <= 6*32 will be passed in registers if possible, @@ -11631,6 +11630,8 @@ ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, } else if (NeededAlign == (2 * 32)) { return ABIArgInfo::getDirect(llvm::ArrayType::get( llvm::IntegerType::get(getVMContext(), 64), NeededArgGPRs / 2)); + } else if (NeededAlign == (4 * 32)) { + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 128)); } else { return ABIArgInfo::getDirect(llvm::ArrayType::get( llvm::IntegerType::get(getVMContext(), 32), NeededArgGPRs)); diff --git a/clang/test/CodeGen/xtensa-abi.c b/clang/test/CodeGen/xtensa-abi.c index 4ce59e8466c8b..d50a45bcde489 100644 --- a/clang/test/CodeGen/xtensa-abi.c +++ b/clang/test/CodeGen/xtensa-abi.c @@ -12,3 +12,17 @@ char *bufalloc () } // CHECK: define dso_local noalias i8* @bufalloc() #0 { + +struct S16 { int a[4]; } __attribute__ ((aligned (16))); + +void callee_struct_a16b_1(struct S16 a) {} + +// CHECK: define dso_local void @callee_struct_a16b_1(i128 %a.coerce) + +void callee_struct_a16b_2(struct S16 a, int b) {} + +// CHECK: define dso_local void @callee_struct_a16b_2(i128 %a.coerce, i32 noundef %b) + +void callee_struct_a16b_3(int a, struct S16 b) {} + +// CHECK: define dso_local void @callee_struct_a16b_3(i32 noundef %a, %struct.S16* noundef byval(%struct.S16) align 16 %b) From 0af6dae007d2128c97a0b5c64e00c18d76bb68a8 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 16 Sep 2022 20:21:43 +0300 Subject: [PATCH 132/150] [Xtensa] Add IR test for 16byte alignment. --- .../test/CodeGen/Xtensa/calling-conv-call8.ll | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 llvm/test/CodeGen/Xtensa/calling-conv-call8.ll diff --git a/llvm/test/CodeGen/Xtensa/calling-conv-call8.ll b/llvm/test/CodeGen/Xtensa/calling-conv-call8.ll new file mode 100644 index 0000000000000..5d82100679384 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/calling-conv-call8.ll @@ -0,0 +1,172 @@ +; RUN: llc -mtriple=xtensa -mcpu=esp32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=XTENSA-STRUCT16 %s +; RUN: llc -mtriple=xtensa -mcpu=esp32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=XTENSA-I128 %s + +%struct.S = type { [4 x i32] } + +@v = dso_local global i32 0, align 4 + +define dso_local void @caller_struct_a128b_1([4 x i32] %0) { + +; XTENSA-STRUCT16-LABEL: caller_struct_a128b_1: +; XTENSA-STRUCT16-NEXT: .cfi_startproc +; XTENSA-STRUCT16: # %bb.0: +; XTENSA-STRUCT16-NEXT: entry a1, 32 +; XTENSA-STRUCT16-NEXT: .cfi_def_cfa_offset 32 +; XTENSA-STRUCT16-NEXT: l32r a8, .LCPI0_0 +; XTENSA-STRUCT16-NEXT: mov.n a10, a2 +; XTENSA-STRUCT16-NEXT: mov.n a11, a3 +; XTENSA-STRUCT16-NEXT: mov.n a12, a4 +; XTENSA-STRUCT16-NEXT: mov.n a13, a5 +; XTENSA-STRUCT16-NEXT: callx8 a8 +; XTENSA-STRUCT16-NEXT: retw.n + + call void @callee_struct_a128b_1([4 x i32] %0) + ret void +} + +declare dso_local void @callee_struct_a128b_1([4 x i32]) + +define dso_local void @caller_struct_a128b_2([4 x i32] %0) { +; XTENSA-STRUCT16-LABEL: caller_struct_a128b_2: +; XTENSA-STRUCT16: .cfi_startproc +; XTENSA-STRUCT16-NEXT: # %bb.0: +; XTENSA-STRUCT16-NEXT: entry a1, 32 +; XTENSA-STRUCT16-NEXT: .cfi_def_cfa_offset 32 +; XTENSA-STRUCT16-NEXT: l32r a8, .LCPI1_0 +; XTENSA-STRUCT16-NEXT: l32i.n a14, a8, 0 +; XTENSA-STRUCT16-NEXT: l32r a8, .LCPI1_1 +; XTENSA-STRUCT16-NEXT: mov.n a10, a2 +; XTENSA-STRUCT16-NEXT: mov.n a11, a3 +; XTENSA-STRUCT16-NEXT: mov.n a12, a4 +; XTENSA-STRUCT16-NEXT: mov.n a13, a5 +; XTENSA-STRUCT16-NEXT: callx8 a8 +; XTENSA-STRUCT16-NEXT: retw.n + + %2 = load i32, i32* @v, align 4 + call void @callee_struct_a128b_2([4 x i32] %0, i32 noundef %2) + ret void +} + +declare dso_local void @callee_struct_a128b_2([4 x i32], i32 noundef) + +define dso_local void @caller_struct_a128b_3([4 x i32] %0) { +; XTENSA-STRUCT16-LABEL: caller_struct_a128b_3: +; XTENSA-STRUCT16: .cfi_startproc +; XTENSA-STRUCT16-NEXT: # %bb.0: +; XTENSA-STRUCT16-NEXT: entry a1, 64 +; XTENSA-STRUCT16-NEXT: .cfi_def_cfa_offset 64 +; XTENSA-STRUCT16-NEXT: s32i.n a5, a1, 28 +; XTENSA-STRUCT16-NEXT: s32i.n a4, a1, 24 +; XTENSA-STRUCT16-NEXT: s32i.n a3, a1, 20 +; XTENSA-STRUCT16-NEXT: s32i.n a2, a1, 16 +; XTENSA-STRUCT16-NEXT: l32r a8, .LCPI2_0 +; XTENSA-STRUCT16-NEXT: l32i.n a10, a8, 0 +; XTENSA-STRUCT16-NEXT: l32i.n a8, a1, 28 +; XTENSA-STRUCT16-NEXT: s32i.n a8, a1, 12 +; XTENSA-STRUCT16-NEXT: l32i.n a8, a1, 24 +; XTENSA-STRUCT16-NEXT: s32i.n a8, a1, 8 +; XTENSA-STRUCT16-NEXT: l32i.n a8, a1, 20 +; XTENSA-STRUCT16-NEXT: s32i.n a8, a1, 4 +; XTENSA-STRUCT16-NEXT: l32i.n a8, a1, 16 +; XTENSA-STRUCT16-NEXT: s32i.n a8, a1, 0 +; XTENSA-STRUCT16-NEXT: l32r a8, .LCPI2_1 +; XTENSA-STRUCT16-NEXT: callx8 a8 +; XTENSA-STRUCT16-NEXT: retw.n + + %2 = alloca %struct.S, align 16 + %3 = extractvalue [4 x i32] %0, 0 + %4 = getelementptr inbounds %struct.S, %struct.S* %2, i32 0, i32 0, i32 0 + store i32 %3, i32* %4, align 16 + %5 = extractvalue [4 x i32] %0, 1 + %6 = getelementptr inbounds %struct.S, %struct.S* %2, i32 0, i32 0, i32 1 + store i32 %5, i32* %6, align 4 + %7 = extractvalue [4 x i32] %0, 2 + %8 = getelementptr inbounds %struct.S, %struct.S* %2, i32 0, i32 0, i32 2 + store i32 %7, i32* %8, align 8 + %9 = extractvalue [4 x i32] %0, 3 + %10 = getelementptr inbounds %struct.S, %struct.S* %2, i32 0, i32 0, i32 3 + store i32 %9, i32* %10, align 4 + %11 = load i32, i32* @v, align 4 + call void @callee_struct_a128b_3(i32 noundef %11, %struct.S* noundef nonnull byval(%struct.S) align 16 %2) + ret void +} + +declare dso_local void @callee_struct_a128b_3(i32 noundef, %struct.S* noundef byval(%struct.S) align 16) + +define dso_local void @caller_i128b_1(i128 noundef %0) { +; XTENSA-I128-LABEL: caller_i128b_1: +; XTENSA-I128: .cfi_startproc +; XTENSA-I128-NEXT: # %bb.0: +; XTENSA-I128-NEXT: entry a1, 32 +; XTENSA-I128-NEXT: .cfi_def_cfa_offset 32 +; XTENSA-I128-NEXT: l32r a8, .LCPI3_0 +; XTENSA-I128-NEXT: mov.n a10, a2 +; XTENSA-I128-NEXT: mov.n a11, a3 +; XTENSA-I128-NEXT: mov.n a12, a4 +; XTENSA-I128-NEXT: mov.n a13, a5 +; XTENSA-I128-NEXT: callx8 a8 +; XTENSA-I128-NEXT: retw.n + + call void @callee_i128b_1(i128 noundef %0) + ret void +} + +declare dso_local void @callee_i128b_1(i128 noundef) + +define dso_local void @caller_i128b_2(i128 noundef %0) { +; XTENSA-I128-LABEL: caller_i128b_2: +; XTENSA-I128: .cfi_startproc +; XTENSA-I128-NEXT: # %bb.0: +; XTENSA-I128-NEXT: entry a1, 32 +; XTENSA-I128-NEXT: .cfi_def_cfa_offset 32 +; XTENSA-I128-NEXT: l32r a8, .LCPI4_0 +; XTENSA-I128-NEXT: l32i.n a14, a8, 0 +; XTENSA-I128-NEXT: l32r a8, .LCPI4_1 +; XTENSA-I128-NEXT: mov.n a10, a2 +; XTENSA-I128-NEXT: mov.n a11, a3 +; XTENSA-I128-NEXT: mov.n a12, a4 +; XTENSA-I128-NEXT: mov.n a13, a5 +; XTENSA-I128-NEXT: callx8 a8 +; XTENSA-I128-NEXT: retw.n + + %2 = load i32, i32* @v, align 4 + call void @callee_i128b_2(i128 noundef %0, i32 noundef %2) + ret void +} + +declare dso_local void @callee_i128b_2(i128 noundef, i32 noundef) + +define dso_local void @caller_i128b_3(i128 noundef %0) { +; XTENSA-I128-LABEL: caller_i128b_3: +; XTENSA-I128: .cfi_startproc +; XTENSA-I128-NEXT: # %bb.0: +; XTENSA-I128-NEXT: entry a1, 64 +; XTENSA-I128-NEXT: .cfi_def_cfa_offset 64 +; XTENSA-I128-NEXT: s32i.n a5, a1, 28 +; XTENSA-I128-NEXT: s32i.n a4, a1, 24 +; XTENSA-I128-NEXT: s32i.n a3, a1, 20 +; XTENSA-I128-NEXT: s32i.n a2, a1, 16 +; XTENSA-I128-NEXT: l32r a8, .LCPI5_0 +; XTENSA-I128-NEXT: l32i.n a10, a8, 0 +; XTENSA-I128-NEXT: l32i.n a8, a1, 28 +; XTENSA-I128-NEXT: s32i.n a8, a1, 12 +; XTENSA-I128-NEXT: l32i.n a8, a1, 24 +; XTENSA-I128-NEXT: s32i.n a8, a1, 8 +; XTENSA-I128-NEXT: l32i.n a8, a1, 20 +; XTENSA-I128-NEXT: s32i.n a8, a1, 4 +; XTENSA-I128-NEXT: l32i.n a8, a1, 16 +; XTENSA-I128-NEXT: s32i.n a8, a1, 0 +; XTENSA-I128-NEXT: l32r a8, .LCPI5_1 +; XTENSA-I128-NEXT: callx8 a8 +; XTENSA-I128-NEXT: retw.n + + %2 = alloca i128, align 16 + %3 = load i32, i32* @v, align 4 + store i128 %0, i128* %2, align 16 + call void @callee_i128b_3(i32 noundef %3, i128* noundef nonnull byval(i128) align 16 %2) + ret void +} + +declare dso_local void @callee_i128b_3(i32 noundef, i128* noundef byval(i128) align 16) From 28b26ff95250371c59cf7a231acab8ef3191dc8b Mon Sep 17 00:00:00 2001 From: "stefan.stipanovic" Date: Thu, 29 Sep 2022 14:03:38 +0200 Subject: [PATCH 133/150] esp/ci: Run LLD tests. Output test logs in lld-tests.log --- .universal-toolchain-release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.universal-toolchain-release.yml b/.universal-toolchain-release.yml index 3f15eb9637a31..5292918a32a97 100644 --- a/.universal-toolchain-release.yml +++ b/.universal-toolchain-release.yml @@ -58,6 +58,7 @@ artifacts: paths: - ${DIST_DIR}/ + - ${BUILD_DIR}/lld-tests.log - ${BUILD_DIR}/tests.log - ${BUILD_DIR}/build.log when: always @@ -94,6 +95,9 @@ touch ${BUILD_PATH}/tests.log; chmod o+w ${BUILD_PATH}/tests.log; runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target check-all 2>&1 > '${BUILD_PATH}'/tests.log'; + touch ${BUILD_PATH}/lld-tests.log; + chmod o+w ${BUILD_PATH}/lld-tests.log; + runuser -l test_runner -c 'cmake --build '${LLVM_BUILD_PATH}' --target lld-test 2>&1 > '${BUILD_PATH}'/lld-tests.log'; fi - export DISTRO_DIR=$PWD/$DIST_DIR - pushd ${BUILD_PATH} From 4a51f8f8e0642dff0c125b79a9e484b6243e52c5 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 30 Sep 2022 17:55:08 +0300 Subject: [PATCH 134/150] [Xtensa] Fix atomic rmw operation. Fix register liveness in emitAtomicRMW function. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index f0b1af9263fb1..fb8f44dde598e 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -2538,7 +2538,9 @@ MachineBasicBlock *XtensaTargetLowering::emitAtomicRMW(MachineInstr &MI, const TargetRegisterClass *RC = getRegClassFor(MVT::i32); unsigned R1 = MRI.createVirtualRegister(RC); - BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R1).add(AtomicValAddr).addImm(0); + BuildMI(*BB, MI, DL, TII.get(Xtensa::L32I), R1) + .addReg(AtomicValAddr.getReg()) + .addImm(0); BB = BBLoop; @@ -2602,7 +2604,7 @@ MachineBasicBlock *XtensaTargetLowering::emitAtomicRMW(MachineInstr &MI, BuildMI(BB, DL, TII.get(Xtensa::WSR), Xtensa::SCOMPARE1).addReg(AtomicValPhi); BuildMI(BB, DL, TII.get(Xtensa::S32C1I), R4) .addReg(R2) - .addReg(AtomicValAddr.getReg()) + .addReg(AtomicValAddr.getReg(), getKillRegState(AtomicValAddr.isDead())) .addImm(0); BuildMI(BB, DL, TII.get(Xtensa::MOV_N), AtomicValLoop).addReg(R4); From 32e64117af37618a5c8085753119c2541443a613 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 30 Sep 2022 18:12:36 +0300 Subject: [PATCH 135/150] [Xtensa] Fix Hardware Loop pass. If block with LOOPEND instruction has smaller offset then loop heeader block then try to find appropriate place for LOOPEND instruction after loop header --- llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp b/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp index dc712a9138058..3089d7ee59fbf 100644 --- a/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp @@ -153,8 +153,8 @@ bool XtensaFixupHwLoops::runOnMachineFunction(MachineFunction &mf) { // Scan loop and find hardware loop pseudo instructions LOOPSTART and LOOPEND. // Transform LOOPSTART to Xtensa instructions and remove LOOPEND. bool XtensaFixupHwLoops::fixupLoopInstrs(MachineLoop *L) { - // const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); MachineBasicBlock &MBB = *(L->getHeader()); + const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo(); bool Changed = false; unsigned Num = MBB.getNumber(); unsigned Offset = BlockInfo[Num].Offset; @@ -168,10 +168,17 @@ bool XtensaFixupHwLoops::fixupLoopInstrs(MachineLoop *L) { MachineInstr *PredI1 = nullptr; MachineInstr *FirstMI = nullptr; + // Find appropriate place for the LOOPEND block for (auto MBI = L->block_begin(), MBIE = L->block_end(); MBI != MBIE; ++MBI) { - if (LastBlockOffset < BlockInfo[(*MBI)->getNumber()].Offset) { - LastBlockOffset = BlockInfo[(*MBI)->getNumber()].Offset; - LastBlock = (*MBI); + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + SmallVector Cond; + if (!TII->analyzeBranch(*(*MBI), TBB, FBB, Cond)) { + if (FBB && TBB) { + if (LastBlockOffset < BlockInfo[(*MBI)->getNumber()].Offset) { + LastBlockOffset = BlockInfo[(*MBI)->getNumber()].Offset; + LastBlock = (*MBI); + } + } } } @@ -220,12 +227,43 @@ bool XtensaFixupHwLoops::fixupLoopInstrs(MachineLoop *L) { DebugLoc DL = PII->getDebugLoc(); unsigned OffsetLE = BlockInfo[PMBB->getNumber()].Offset; - // Check if loop end is placed before loop header - // In such case add special MBB after loop header and create jump - // from loop end to it + // In most cases we expect that blocks in loop are ordered by such manner that block + // with LOOPSTART instruction preceeds block with LOOPEND instruction. + // But in some cases after transformations loop block which contains LOOPEND instruction + // maybe placed before LOOPSTART block during code generaion. We must handle such situation + // because "loop" instruction placed instead of LOOPSTART must have positive offset in the target + // field to the LOOPEND block. + // So, in such situation we add new LOOPEND block after the LOOPSTART block and create jump from old + // LOOPEND block to the new LOOPEND block adn set new LOOPEND block then as target for "loop" instruction if (OffsetLE < LHOffset) { LoopEnd = MF->CreateMachineBasicBlock(); - MF->insert(++LastBlock->getIterator(), LoopEnd); + + // If last block in the loop is whithin 256 byte offset from loop instruction + // then just place LOOPEND block after the last block. + if ((LastBlockOffset - LHOffset) < 256) { + //Insert after appropriate block + MF->insert(++LastBlock->getIterator(), LoopEnd); + } else { + // If loop is to large for hardware loop instructuin offset then + // place LoopEnd block just after loop header + MF->insert(++MBB.getIterator(), LoopEnd); + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + SmallVector Cond; + if (!TII->analyzeBranch(MBB, TBB, FBB, Cond)) { + if (!FBB) { + // LH block just falls through to its succ + for (auto I = MBB.succ_begin(), E = MBB.succ_end(); I != E; + ++I) { + MachineBasicBlock *Succ = *I; + if (Succ != TBB) { + BuildMI(MBB, MBB.end(), DL, TII->get(Xtensa::J)) + .addMBB(Succ); + } + } + } + } + } + LoopEnd->transferSuccessors(PMBB); LoopEnd->splice(LoopEnd->end(), PMBB, PII, PMBB->end()); From ce430fd8a19ca9bb7cc734d505e021d9b2584b34 Mon Sep 17 00:00:00 2001 From: Ayke Van Laethem Date: Wed, 19 Oct 2022 18:46:56 +0200 Subject: [PATCH 136/150] [Xtensa] Add LLD linker support Closes #11 --- lld/ELF/Arch/Xtensa.cpp | 173 ++++++++++++++++++ lld/ELF/CMakeLists.txt | 1 + lld/ELF/InputFiles.cpp | 2 + lld/ELF/Target.cpp | 2 + lld/ELF/Target.h | 1 + lld/test/ELF/xtensa-reloc.s | 17 ++ lld/test/lit.cfg.py | 3 +- .../llvm/BinaryFormat/ELFRelocs/Xtensa.def | 6 + 8 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 lld/ELF/Arch/Xtensa.cpp create mode 100644 lld/test/ELF/xtensa-reloc.s diff --git a/lld/ELF/Arch/Xtensa.cpp b/lld/ELF/Arch/Xtensa.cpp new file mode 100644 index 0000000000000..31603068b8df7 --- /dev/null +++ b/lld/ELF/Arch/Xtensa.cpp @@ -0,0 +1,173 @@ +//===- Xtensa.cpp ---------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include +#include +#include + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { + +class Xtensa final : public TargetInfo { +public: + Xtensa(); + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; +}; + +} // namespace + +Xtensa::Xtensa() {} + +RelExpr Xtensa::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_XTENSA_32: + return R_ABS; + case R_XTENSA_SLOT0_OP: + // This relocation is used for various instructions, with varying ways to + // calculate the relocation value. This is unlike most ELF architectures, + // and is arguably bad design (see the comment on R_386_GOT32 in X86.cpp). + // But that's what compilers emit, so it needs to be supported. + // + // We work around this by returning R_PC here and calculating the PC address + // in Xtensa::relocate based on the relative value. That's ugly. A better + // solution would be to look at the instruction here and emit various + // Xtensa-specific RelTypes, but that has another problem: the RelExpr enum + // is at its maximum size of 64. This will need to be fixed eventually, but + // for now hack around it and return R_PC. + return R_PC; + case R_XTENSA_ASM_EXPAND: + // This relocation appears to be emitted by the GNU Xtensa compiler as a + // linker relaxation hint. For example, for the following code: + // + // .section .foo + // .align 4 + // foo: + // nop + // nop + // call0 bar + // .align 4 + // bar: + // + // The call0 instruction is compiled to a l32r and callx0 instruction. + // The LLVM Xtensa backend does not emit this relocation. + // Because it's a relaxation hint, this relocation can be ignored for now + // until linker relaxations are implemented. + return R_NONE; + case R_XTENSA_PDIFF8: + case R_XTENSA_PDIFF16: + case R_XTENSA_PDIFF32: + case R_XTENSA_NDIFF8: + case R_XTENSA_NDIFF16: + case R_XTENSA_NDIFF32: + // > Xtensa relocations to mark the difference of two local symbols. + // > These are only needed to support linker relaxation and can be ignored + // > when not relaxing. + // Source: + // https://github.com/espressif/binutils-gdb/commit/30ce8e47fad9b057b6d7af9e1d43061126d34d20: + // Because we don't do linker relaxation, we can ignore these relocations. + return R_NONE; + default: + error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + + ") against symbol " + toString(s)); + return R_NONE; + } +} + +static inline bool isRRI8Branch(uint8_t *loc) { + if ((loc[0] & 0x0f) == 0b0111) { + // instructions: ball, bany, bbc, bbci, bbs, bbsi, beq, bge, bgeu, blt, + // bltu, bnall, bne, bnone + return true; + } + if ((loc[0] & 0b11'1111) == 0b10'0110) { + // instructions: beqi, bgei, bnei, blti + return true; + } + if ((loc[0] & 0b1011'1111) == 0b1011'0110) { + // instructions: bgeui, bltui + return true; + } + // some other instruction + return false; +} + +void Xtensa::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + switch (rel.type) { + case R_XTENSA_32: + write32le(loc, val); + break; + case R_XTENSA_SLOT0_OP: { + // HACK: calculate the instruction location based on the PC-relative + // relocation value. + uint64_t dest = rel.sym->getVA(rel.addend); + uint64_t p = dest - val; + + // This relocation is used for various instructions. + // Look at the instruction to determine how to do the relocation. + uint8_t opcode = loc[0] & 0x0f; + if (opcode == 0b0001) { // RI16 format: l32r + uint64_t val = dest - ((p + 3) & (uint64_t)0xfffffffc); + checkInt(loc, static_cast(val) >> 2, 16, rel); + checkAlignment(loc, val, 4, rel); + write16le(loc + 1, static_cast(val) >> 2); + } else if (opcode == 0b0101) { // call0, call4, call8, call12 (CALL format) + uint64_t val = dest - ((p + 4) & (uint64_t)0xfffffffc); + checkInt(loc, static_cast(val) >> 2, 18, rel); + checkAlignment(loc, val, 4, rel); + const int64_t target = static_cast(val) >> 2; + loc[0] = (loc[0] & 0b0011'1111) | ((target & 0b0000'0011) << 6); + loc[1] = target >> 2; + loc[2] = target >> 10; + } else if ((loc[0] & 0x3f) == 0b00'0110) { // j (CALL format) + uint64_t val = dest - p + 4; + checkInt(loc, static_cast(val), 18, rel); + loc[0] = (loc[0] & 0b0011'1111) | ((val & 0b0000'0011) << 6); + loc[1] = val >> 2; + loc[2] = val >> 10; + } else if (isRRI8Branch(loc)) { // RRI8 format (various branch instructions) + uint64_t v = val - 4; + checkInt(loc, static_cast(v), 8, rel); + loc[2] = v & 0xff; + } else if ((loc[0] & 0b1000'1111) == 0b1000'1100) { // RI16 format: beqz.n, bnez.n + uint64_t v = val - 4; + checkUInt(loc, v, 6, rel); + loc[0] = (loc[0] & 0xcf) | (v & 0x30); + loc[1] = (loc[1] & 0x0f) | ((v & 0x0f) << 4); + } else if ((loc[0] & 0b0011'1111) == 0b0001'0110) { // BRI12 format: beqz, bgez, bltz, bnez + uint64_t v = val - 4; + checkInt(loc, static_cast(v), 12, rel); + loc[1] = ((loc[1] & 0x0f)) | ((v & 0x0f) << 4); + loc[2] = (v >> 4) & 0xff; + } else { + error(getErrorLocation(loc) + + "unknown opcode for relocation: " + std::to_string(loc[0])); + } + break; + } + default: + llvm_unreachable("unknown relocation"); + } +} + +TargetInfo *elf::getXtensaTargetInfo() { + static Xtensa target; + return ⌖ +} diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index b37035d3e7429..44498e296c73e 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -22,6 +22,7 @@ add_lld_library(lldELF Arch/SPARCV9.cpp Arch/X86.cpp Arch/X86_64.cpp + Arch/Xtensa.cpp ARMErrataFix.cpp CallGraphSort.cpp DWARF.cpp diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 927dc272b5326..5e8a0b6d3c2ac 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1538,6 +1538,8 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) { return t.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; + case Triple::xtensa: + return EM_XTENSA; default: error(path + ": could not infer e_machine from bitcode target triple " + t.str()); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 7bc5121eabe4a..b7f05930ce800 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -87,6 +87,8 @@ TargetInfo *elf::getTarget() { return getSPARCV9TargetInfo(); case EM_X86_64: return getX86_64TargetInfo(); + case EM_XTENSA: + return getXtensaTargetInfo(); } llvm_unreachable("unknown target machine"); } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 14b1f53c6a819..347c676bd7def 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -187,6 +187,7 @@ TargetInfo *getRISCVTargetInfo(); TargetInfo *getSPARCV9TargetInfo(); TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); +TargetInfo *getXtensaTargetInfo(); template TargetInfo *getMipsTargetInfo(); struct ErrorPlace { diff --git a/lld/test/ELF/xtensa-reloc.s b/lld/test/ELF/xtensa-reloc.s new file mode 100644 index 0000000000000..7007756aa2a89 --- /dev/null +++ b/lld/test/ELF/xtensa-reloc.s @@ -0,0 +1,17 @@ +# REQUIRES: xtensa +# RUN: llvm-mc -filetype=obj -triple=xtensa -mcpu=esp32 %s -o %t.o +# RUN: ld.lld %t.o --defsym=a=0x2000 --section-start=.CALL=0x1000 --defsym=b=40 -o %t +# RUN: llvm-objdump -d --print-imm-hex %t | FileCheck %s + +.section .CALL,"ax",@progbits +# CHECK-LABEL: section .CALL: +# CHECK: call0 . +4096 +# CHECK-NEXT: call0 . +4096 +# CHECK-NEXT: call0 . +4092 +# CHECK-NEXT: call0 . +4088 +# CHECK-NEXT: call0 . -4068 + call0 a + call0 a + call0 a + call0 a + call0 b diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py index 96a1d652573fe..45c9e014a649d 100644 --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -74,7 +74,8 @@ 'RISCV': 'riscv', 'Sparc': 'sparc', 'WebAssembly': 'wasm', - 'X86': 'x86'}), + 'X86': 'x86', + 'Xtensa': 'xtensa'}), ('--assertion-mode', {'ON': 'asserts'}), ]) diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def index 51df120bb9ada..204e20f54301f 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/Xtensa.def @@ -57,3 +57,9 @@ ELF_RELOC(R_XTENSA_TLS_TPOFF, 53) ELF_RELOC(R_XTENSA_TLS_FUNC, 54) ELF_RELOC(R_XTENSA_TLS_ARG, 55) ELF_RELOC(R_XTENSA_TLS_CALL, 56) +ELF_RELOC(R_XTENSA_PDIFF8, 57) +ELF_RELOC(R_XTENSA_PDIFF16, 58) +ELF_RELOC(R_XTENSA_PDIFF32, 59) +ELF_RELOC(R_XTENSA_NDIFF8, 60) +ELF_RELOC(R_XTENSA_NDIFF16, 61) +ELF_RELOC(R_XTENSA_NDIFF32, 62) From 0e22873b5b35e0cde509148ccff965dc5851eeb5 Mon Sep 17 00:00:00 2001 From: "stefan.stipanovic" Date: Tue, 1 Nov 2022 16:40:19 +0100 Subject: [PATCH 137/150] [Xtensa][LLD] add more tests --- lld/test/ELF/xtensa-reloc.s | 44 +++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/lld/test/ELF/xtensa-reloc.s b/lld/test/ELF/xtensa-reloc.s index 7007756aa2a89..611e671e7646f 100644 --- a/lld/test/ELF/xtensa-reloc.s +++ b/lld/test/ELF/xtensa-reloc.s @@ -1,17 +1,57 @@ # REQUIRES: xtensa # RUN: llvm-mc -filetype=obj -triple=xtensa -mcpu=esp32 %s -o %t.o -# RUN: ld.lld %t.o --defsym=a=0x2000 --section-start=.CALL=0x1000 --defsym=b=40 -o %t +# RUN: ld.lld %t.o --defsym=a=0x2000 --section-start=.CALL=0x1000 --defsym=b=0x40 --defsym=c=0x140 --section-start=.BRANCH=0x5000 --defsym=d=0x5010 --section-start=.BR12=0x100 -o %t # RUN: llvm-objdump -d --print-imm-hex %t | FileCheck %s +.section .BR12,"ax",@progbits +# CHECK-LABEL:section .BR12 +# CHECK: beqz a2, . +64 +# CHECK-NEXT: bnez a3, . +61 +# CHECK-NEXT: bgez a4, . +58 +# CHECK-NEXT: bltz a5, . +55 + beqz a2, c + bnez a3, c + bgez a4, c + bltz a5, c + .section .CALL,"ax",@progbits # CHECK-LABEL: section .CALL: # CHECK: call0 . +4096 # CHECK-NEXT: call0 . +4096 # CHECK-NEXT: call0 . +4092 # CHECK-NEXT: call0 . +4088 -# CHECK-NEXT: call0 . -4068 +# CHECK-NEXT: j . +4092 +# CHECK-NEXT: j . +4089 +# CHECK-NEXT: j . +4086 +# CHECK-NEXT: j . -4045 +# CHECK-NEXT: j . -3792 +# CHECK-NEXT: call0 . -4056 +# CHECK-NEXT: call0 . -3804 +# CHECK-NEXT: l32r a3, . -4065 +# CHECK-NEXT: callx0 a3 +# CHECK-NEXT: l32r a4, . -3815 +# CHECK-NEXT: callx0 a4 call0 a call0 a call0 a call0 a + j a + j a + j a + j b + j c call0 b + call0 c + l32r a3, b + callx0 a3 + l32r a4, c + callx0 a4 + +.section .BRANCH,"ax",@progbits +# CHECK-LABEL: section .BRANCH: +# CHECK: beq a3, a4, . +16 +# CHECK-NEXT: ball a3, a4, . +13 +# CHECK-NEXT: blt a3, a4, . +10 + beq a3, a4, d + ball a3, a4, d + blt a3, a4, d From 1fa390603d270bda2978e0947acdf5c1c1c774f6 Mon Sep 17 00:00:00 2001 From: "stefan.stipanovic" Date: Tue, 1 Nov 2022 16:41:03 +0100 Subject: [PATCH 138/150] [Xtensa][LLD] Fix J formula --- lld/ELF/Arch/Xtensa.cpp | 10 +++++----- lld/test/ELF/xtensa-reloc.s | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lld/ELF/Arch/Xtensa.cpp b/lld/ELF/Arch/Xtensa.cpp index 31603068b8df7..f6d75fde7ac29 100644 --- a/lld/ELF/Arch/Xtensa.cpp +++ b/lld/ELF/Arch/Xtensa.cpp @@ -137,11 +137,11 @@ void Xtensa::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { loc[1] = target >> 2; loc[2] = target >> 10; } else if ((loc[0] & 0x3f) == 0b00'0110) { // j (CALL format) - uint64_t val = dest - p + 4; - checkInt(loc, static_cast(val), 18, rel); - loc[0] = (loc[0] & 0b0011'1111) | ((val & 0b0000'0011) << 6); - loc[1] = val >> 2; - loc[2] = val >> 10; + uint64_t valJ = val - 4; + checkInt(loc, static_cast(valJ), 18, rel); + loc[0] = (loc[0] & 0b0011'1111) | ((valJ & 0b0000'0011) << 6); + loc[1] = valJ >> 2; + loc[2] = valJ >> 10; } else if (isRRI8Branch(loc)) { // RRI8 format (various branch instructions) uint64_t v = val - 4; checkInt(loc, static_cast(v), 8, rel); diff --git a/lld/test/ELF/xtensa-reloc.s b/lld/test/ELF/xtensa-reloc.s index 611e671e7646f..e14151ae4a814 100644 --- a/lld/test/ELF/xtensa-reloc.s +++ b/lld/test/ELF/xtensa-reloc.s @@ -20,11 +20,11 @@ # CHECK-NEXT: call0 . +4096 # CHECK-NEXT: call0 . +4092 # CHECK-NEXT: call0 . +4088 -# CHECK-NEXT: j . +4092 -# CHECK-NEXT: j . +4089 -# CHECK-NEXT: j . +4086 -# CHECK-NEXT: j . -4045 -# CHECK-NEXT: j . -3792 +# CHECK-NEXT: j . +4084 +# CHECK-NEXT: j . +4081 +# CHECK-NEXT: j . +4078 +# CHECK-NEXT: j . -4053 +# CHECK-NEXT: j . -3800 # CHECK-NEXT: call0 . -4056 # CHECK-NEXT: call0 . -3804 # CHECK-NEXT: l32r a3, . -4065 From e520bb14d2c7fa5620d3d1665f7a8395b8aa8bb5 Mon Sep 17 00:00:00 2001 From: "stefan.stipanovic" Date: Fri, 28 Oct 2022 12:10:43 +0200 Subject: [PATCH 139/150] [Xtensa] Adding new invalid tests and changing test structure as requested in https://reviews.llvm.org/D64833. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 5 - llvm/test/MC/Xtensa/xtensa-arith.s | 85 +++++ llvm/test/MC/Xtensa/xtensa-branch.s | 171 +++++++++ llvm/test/MC/Xtensa/xtensa-call-jump.s | 35 ++ llvm/test/MC/Xtensa/xtensa-invalid.s | 43 ++- llvm/test/MC/Xtensa/xtensa-memorder.s | 16 + llvm/test/MC/Xtensa/xtensa-memory.s | 45 +++ llvm/test/MC/Xtensa/xtensa-move.s | 31 ++ .../test/MC/Xtensa/xtensa-processor-control.s | 86 +++++ llvm/test/MC/Xtensa/xtensa-shift.s | 66 ++++ llvm/test/MC/Xtensa/xtensa-valid-density.s | 21 ++ llvm/test/MC/Xtensa/xtensa-valid-float.s | 7 +- llvm/test/MC/Xtensa/xtensa-valid-int.s | 5 +- llvm/test/MC/Xtensa/xtensa-valid-mac16.s | 7 +- llvm/test/MC/Xtensa/xtensa-valid-mul16.s | 2 +- llvm/test/MC/Xtensa/xtensa-valid-regprotect.s | 2 +- llvm/test/MC/Xtensa/xtensa-valid-ur.s | 1 + llvm/test/MC/Xtensa/xtensa-valid.s | 355 ------------------ 18 files changed, 604 insertions(+), 379 deletions(-) create mode 100644 llvm/test/MC/Xtensa/xtensa-arith.s create mode 100644 llvm/test/MC/Xtensa/xtensa-branch.s create mode 100644 llvm/test/MC/Xtensa/xtensa-call-jump.s create mode 100644 llvm/test/MC/Xtensa/xtensa-memorder.s create mode 100644 llvm/test/MC/Xtensa/xtensa-memory.s create mode 100644 llvm/test/MC/Xtensa/xtensa-move.s create mode 100644 llvm/test/MC/Xtensa/xtensa-processor-control.s create mode 100644 llvm/test/MC/Xtensa/xtensa-shift.s delete mode 100644 llvm/test/MC/Xtensa/xtensa-valid.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 263bb917bfa88..c0672d1cbd752 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -544,11 +544,6 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, case Xtensa::MOVI: { XtensaTargetStreamer &TS = this->getTargetStreamer(); - //In the case of asm output, simply pass the representation of - //the MOVI instruction as is - if (TS.getStreamer().hasRawTextSupport()) - break; - //Expand MOVI operand if (!Inst.getOperand(1).isExpr()) { uint64_t ImmOp64 = Inst.getOperand(1).getImm(); diff --git a/llvm/test/MC/Xtensa/xtensa-arith.s b/llvm/test/MC/Xtensa/xtensa-arith.s new file mode 100644 index 0000000000000..927cab3615a58 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-arith.s @@ -0,0 +1,85 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 +LBL0: + +# Instruction format RRR +# CHECK-INST: abs a5, a6 +# CHECK: encoding: [0x60,0x51,0x60] +abs a5, a6 + +# Instruction format RRR +# CHECK-INST: add a3, a9, a4 +# CHECK: encoding: [0x40,0x39,0x80] +add a3, a9, a4 + +# Instruction format RRR +# CHECK-INST: add a15, a9, a1 +# CHECK: encoding: [0x10,0xf9,0x80] +add a15, a9, sp + +# Instruction format RRI8 +# CHECK-INST: addi a8, a1, -128 +# CHECK: encoding: [0x82,0xc1,0x80] +addi a8, sp, -128 + +# Instruction format RRI8 +# CHECK-INST: addi a8, a1, -12 +# CHECK: encoding: [0x82,0xc1,0xf4] +addi a8, a1, -12 + +# Instruction format RRI8 +# CHECK-INST: addmi a1, a2, 32512 +# CHECK: encoding: [0x12,0xd2,0x7f] +addmi a1, a2, 32512 + +# Instruction format RRR +# CHECK-INST: addx2 a2, a1, a5 +# CHECK: encoding: [0x50,0x21,0x90] +addx2 a2, sp, a5 + +# Instruction format RRR +# CHECK-INST: addx4 a3, a1, a6 +# CHECK: encoding: [0x60,0x31,0xa0] +addx4 a3, sp, a6 + +# Instruction format RRR +# CHECK-INST: addx8 a4, a1, a7 +# CHECK: encoding: [0x70,0x41,0xb0] +addx8 a4, sp, a7 + +# Instruction format RRR +# CHECK-INST: neg a1, a3 +# CHECK: encoding: [0x30,0x10,0x60] +neg a1, a3 + +# Instruction format RRR +# CHECK-INST: or a4, a5, a6 +# CHECK: encoding: [0x60,0x45,0x20] +or a4, a5, a6 + +# Instruction format RRR +# CHECK-INST: sub a8, a2, a1 +# CHECK: encoding: [0x10,0x82,0xc0] +sub a8, a2, a1 + +# Instruction format RRR +# CHECK-INST: subx2 a2, a1, a5 +# CHECK: encoding: [0x50,0x21,0xd0] +subx2 a2, sp, a5 + +# Instruction format RRR +# CHECK-INST: subx4 a3, a1, a6 +# CHECK: encoding: [0x60,0x31,0xe0] +subx4 a3, sp, a6 + +# Instruction format RRR +# CHECK-INST: subx8 a4, a1, a7 +# CHECK: encoding: [0x70,0x41,0xf0] +subx8 a4, sp, a7 + +# Instruction format RRR +# CHECK-INST: xor a6, a4, a5 +# CHECK: encoding: [0x50,0x64,0x30] +xor a6, a4, a5 diff --git a/llvm/test/MC/Xtensa/xtensa-branch.s b/llvm/test/MC/Xtensa/xtensa-branch.s new file mode 100644 index 0000000000000..eec16985d5566 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-branch.s @@ -0,0 +1,171 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRI8 +# CHECK-INST: ball a1, a3, LBL0 +# CHECK: encoding: [0x37,0x41,A] +ball a1, a3, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bany a8, a13, LBL0 +# CHECK: encoding: [0xd7,0x88,A] +bany a8, a13, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbc a8, a7, LBL0 +# CHECK: encoding: [0x77,0x58,A] +bbc a8, a7, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbci a3, 16, LBL0 +# CHECK: encoding: [0x07,0x73,A] +bbci a3, 16, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbci a3, 16, LBL0 +# CHECK: encoding: [0x07,0x73,A] +bbci a3, (16), LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbci a3, 16, LBL0 +# CHECK: encoding: [0x07,0x73,A] +bbci.l a3, 16, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbs a12, a5, LBL0 +# CHECK: encoding: [0x57,0xdc,A] +bbs a12, a5, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbsi a3, 16, LBL0 +# CHECK: encoding: [0x07,0xf3,A] +bbsi a3, 16, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bbsi a3, 16, LBL0 +# CHECK: encoding: [0x07,0xf3,A] +bbsi.l a3, 16, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bnall a7, a3, LBL0 +# CHECK: encoding: [0x37,0xc7,A] +bnall a7, a3, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bnone a2, a4, LBL0 +# CHECK: encoding: [0x47,0x02,A] +bnone a2, a4, LBL0 + +# Instruction format RRI8 +# CHECK-INST: beq a1, a2, LBL0 +# CHECK: encoding: [0x27,0x11,A] +beq a1, a2, LBL0 + +# Instruction format RRI8 +# CHECK-INST: beq a11, a5, LBL0 +# CHECK: encoding: [0x57,0x1b,A] +beq a11, a5, LBL0 + +# Instruction format BRI8 +# CHECK-INST: beqi a1, 256, LBL0 +# CHECK: encoding: [0x26,0xf1,A] +beqi a1, 256, LBL0 + +# Instruction format RRI8 +# CHECK-INST: beqi a11, -1, LBL0 +# CHECK: encoding: [0x26,0x0b,A] +beqi a11, -1, LBL0 + +# Instruction format BRI12 +# CHECK-INST: beqz a8, LBL0 +# CHECK: encoding: [0x16,0bAAAA1000,A] +beqz a8, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bge a14, a2, LBL0 +# CHECK: encoding: [0x27,0xae,A] +bge a14, a2, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bgei a11, -1, LBL0 +# CHECK: encoding: [0xe6,0x0b,A] +bgei a11, -1, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bgei a11, 128, LBL0 +# CHECK: encoding: [0xe6,0xeb,A] +bgei a11, 128, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bgeu a14, a2, LBL0 +# CHECK: encoding: [0x27,0xbe,A] +bgeu a14, a2, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bgeu a13, a1, LBL0 +# CHECK: encoding: [0x17,0xbd,A] +bgeu a13, a1, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bgeui a9, 32768, LBL0 +# CHECK: encoding: [0xf6,0x09,A] +bgeui a9, 32768, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bgeui a7, 65536, LBL0 +# CHECK: encoding: [0xf6,0x17,A] +bgeui a7, 65536, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bgeui a7, 64, LBL0 +# CHECK: encoding: [0xf6,0xd7,A] +bgeui a7, 64, LBL0 + +# Instruction format BRI12 +# CHECK-INST: bgez a8, LBL0 +# CHECK: encoding: [0xd6,0bAAAA1000,A] +bgez a8, LBL0 + +# Instruction format RRI8 +# CHECK-INST: blt a14, a2, LBL0 +# CHECK: encoding: [0x27,0x2e,A] +blt a14, a2, LBL0 + +# Instruction format BRI8 +# CHECK-INST: blti a12, -1, LBL0 +# CHECK: encoding: [0xa6,0x0c,A] +blti a12, -1, LBL0 + +# Instruction format BRI8 +# CHECK-INST: blti a0, 32, LBL0 +# CHECK: encoding: [0xa6,0xc0,A] +blti a0, 32, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bltui a7, 16, LBL0 +# CHECK: encoding: [0xb6,0xb7,A] +bltui a7, 16, LBL0 + +# Instruction format BRI12 +# CHECK-INST: bltz a6, LBL0 +# CHECK: encoding: [0x96,0bAAAA0110,A] +bltz a6, LBL0 + +# Instruction format RRI8 +# CHECK-INST: bne a3, a4, LBL0 +# CHECK: encoding: [0x47,0x93,A] +bne a3, a4, LBL0 + +# Instruction format BRI8 +# CHECK-INST: bnei a5, 12, LBL0 +# CHECK: encoding: [0x66,0xa5,A] +bnei a5, 12, LBL0 + +# Instruction format BRI12 +# CHECK-INST: bnez a5, LBL0 +# CHECK: encoding: [0x56,0bAAAA0101,A] +bnez a5, LBL0 diff --git a/llvm/test/MC/Xtensa/xtensa-call-jump.s b/llvm/test/MC/Xtensa/xtensa-call-jump.s new file mode 100644 index 0000000000000..5b4c95d64b633 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-call-jump.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format CALL +# CHECK-INST: call0 LBL0 +# CHECK: encoding: [0bAA000101,A,A] +call0 LBL0 + +# Instruction format CALLX +# CHECK-INST: callx0 a1 +# CHECK: encoding: [0xc0,0x01,0x00] +callx0 a1 + +# Instruction format CALL +# CHECK-INST: j LBL0 +# CHECK: encoding: [0bAA000110,A,A] +j LBL0 + +# Instruction format CALLX +# CHECK-INST: jx a2 +# CHECK: encoding: [0xa0,0x02,0x00] +jx a2 + +# CHECK-INST: ill +# CHECK: encoding: [0x00,0x00,0x00] +ill + +# Instruction format CALLX +# CHECK-INST: ret +# CHECK: encoding: [0x80,0x00,0x00] +ret diff --git a/llvm/test/MC/Xtensa/xtensa-invalid.s b/llvm/test/MC/Xtensa/xtensa-invalid.s index e0c3ea43102d1..f5ad98d29a81e 100644 --- a/llvm/test/MC/Xtensa/xtensa-invalid.s +++ b/llvm/test/MC/Xtensa/xtensa-invalid.s @@ -1,15 +1,15 @@ # RUN: not llvm-mc -triple xtensa < %s 2>&1 | FileCheck %s -# Out of range immediates - LBL0: +# Out of range immediates + # imm8 -addi a1, a2, -33000 +addi a1, a2, 33000 # CHECK: error: expected immediate in range [-32896, 32639] # imm8 -addi a1, a2, 34000 +addi a1, a2, -33000 # CHECK: error: expected immediate in range [-32896, 32639] # imm1_16 @@ -63,11 +63,36 @@ addi a1, a2, 4, 4 # CHECK: :[[@LINE]]:17: error: invalid operand for instruction # Invalid mnemonics aaa a10, a12 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic -# Invalid register names -addi a101, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction -wsr.uregister a2 # CHECK: :[[@LINE]]:1: error: invalid register name -or r2, sp, a3 # CHECK: :[[@LINE]]:4: error: invalid operand for instruction - # Invalid operand types and sp, a2, 10 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction addi sp, a1, a2 # CHECK: :[[@LINE]]:14: error: expected immediate in range [-32896, 32639] + +# Check invalid register names for different formats +# Instruction format RRR +or r2, sp, a3 # CHECK: :[[@LINE]]:4: error: invalid operand for instruction +and a1, r10, a3 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction +sub a1, sp, a100 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction +# Instruction format RRI8 +addi a101, sp, 10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +addi a1, r10, 10 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +# Instruction format RSR +wsr.uregister a2 # CHECK: :[[@LINE]]:1: error: invalid register name +wsr a2, uregister # CHECK: :[[@LINE]]:9: error: invalid operand for instruction +# Instruction format BRI12 +beqz b1, LBL0 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +# Instruction format BRI8 +bltui r7, 16, LBL0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +# Instruction format CALLX +callx0 r10 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction + +# Check invalid operands order for different formats +# Instruction format RRI8 +addi a1, 10, a2 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +# Instruction format RSR +wsr sar, a2 # CHECK: :[[@LINE]]:5: error: invalid operand for instruction +# Instruction format BRI12 +beqz LBL0, a2 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +# Instruction format BRI8 +bltui 16, a7, LBL0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +bltui a7, LBL0, 16 # CHECK: :[[@LINE]]:20: error: unknown operand + diff --git a/llvm/test/MC/Xtensa/xtensa-memorder.s b/llvm/test/MC/Xtensa/xtensa-memorder.s new file mode 100644 index 0000000000000..bf1ebac159b2d --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-memorder.s @@ -0,0 +1,16 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRR +# CHECK-INST: extw +# CHECK: encoding: [0xd0,0x20,0x00] +extw + +# Instruction format RRR +# CHECK-INST: memw +# CHECK: encoding: [0xc0,0x20,0x00] +memw diff --git a/llvm/test/MC/Xtensa/xtensa-memory.s b/llvm/test/MC/Xtensa/xtensa-memory.s new file mode 100644 index 0000000000000..889e156c95916 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-memory.s @@ -0,0 +1,45 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRI8 +# CHECK-INST: l8ui a2, a1, 3 +# CHECK: encoding: [0x22,0x01,0x03] +l8ui a2, sp, 3 + +# Instruction format RRI8 +# CHECK-INST: l16si a3, a1, 4 +# CHECK: encoding: [0x32,0x91,0x02] +l16si a3, sp, 4 + +# Instruction format RRI8 +# CHECK-INST: l16ui a4, a1, 6 +# CHECK: encoding: [0x42,0x11,0x03] +l16ui a4, sp, 6 + +# Instruction format RRI8 +# CHECK-INST: l32i a5, a1, 8 +# CHECK: encoding: [0x52,0x21,0x02] +l32i a5, sp, 8 + +# CHECK-INST: l32r a6, LBL0 +# CHECK: encoding: [0x61,A,A] +l32r a6, LBL0 + +# Instruction format RRI8 +# CHECK-INST: s8i a2, a1, 3 +# CHECK: encoding: [0x22,0x41,0x03] +s8i a2, sp, 3 + +# Instruction format RRI8 +# CHECK-INST: s16i a3, a1, 4 +# CHECK: encoding: [0x32,0x51,0x02] +s16i a3, sp, 4 + +# Instruction format RRI8 +# CHECK-INST: s32i a5, a1, 8 +# CHECK: encoding: [0x52,0x61,0x02] +s32i a5, sp, 8 diff --git a/llvm/test/MC/Xtensa/xtensa-move.s b/llvm/test/MC/Xtensa/xtensa-move.s new file mode 100644 index 0000000000000..87616599709c3 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-move.s @@ -0,0 +1,31 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRR +# CHECK-INST: moveqz a2, a3, a4 +# CHECK: encoding: [0x40,0x23,0x83] +moveqz a2, a3, a4 + +# Instruction format RRR +# CHECK-INST: movgez a3, a11, a12 +# CHECK: encoding: [0xc0,0x3b,0xb3] +movgez a3, a11, a12 + +# Instruction format RRI8 +# CHECK-INST: movi a1, -2048 +# CHECK: encoding: [0x12,0xa8,0x00] +movi a1, -2048 + +# Instruction format RRR +# CHECK-INST: movltz a7, a8, a9 +# CHECK: encoding: [0x90,0x78,0xa3] +movltz a7, a8, a9 + +# Instruction format RRR +# CHECK-INST: movnez a10, a11, a12 +# CHECK: encoding: [0xc0,0xab,0x93] +movnez a10, a11, a12 diff --git a/llvm/test/MC/Xtensa/xtensa-processor-control.s b/llvm/test/MC/Xtensa/xtensa-processor-control.s new file mode 100644 index 0000000000000..72e08f2e36697 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-processor-control.s @@ -0,0 +1,86 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRR +# CHECK-INST: dsync +# CHECK: encoding: [0x30,0x20,0x00] +dsync + +# Instruction format RRR +# CHECK-INST: esync +# CHECK: encoding: [0x20,0x20,0x00] +esync + +# Instruction format RRR +# CHECK-INST: isync +# CHECK: encoding: [0x00,0x20,0x00] +isync + +# Instruction format RRR +# CHECK-INST: nop +# CHECK: encoding: [0xf0,0x20,0x00] +nop + +# Instruction format RSR +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr a8, sar + +# Instruction format RSR +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr.sar a8 + +# Instruction format RSR +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr a8, 3 + +# Instruction format RRR +# CHECK-INST: rer a3, a4 +# CHECK: encoding: [0x30,0x64,0x40] +rer a3, a4 + +# Instruction format RRR +# CHECK-INST: rsync +# CHECK: encoding: [0x10,0x20,0x00] +rsync + +# Instruction format RRR +# CHECK-INST: wer a3, a4 +# CHECK: encoding: [0x30,0x74,0x40] +wer a3, a4 + +# Instruction format RSR +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, sar + +# Instruction format RSR +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr.sar a8 + +# Instruction format RSR +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, 3 + +# Instruction format RRR +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr a8, sar + +# Instruction format RRR +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr.sar a8 + +# Instruction format RRR +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr a8, 3 diff --git a/llvm/test/MC/Xtensa/xtensa-shift.s b/llvm/test/MC/Xtensa/xtensa-shift.s new file mode 100644 index 0000000000000..3f9c980ff5554 --- /dev/null +++ b/llvm/test/MC/Xtensa/xtensa-shift.s @@ -0,0 +1,66 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRR +# CHECK-INST: extui a1, a2, 7, 8 +# CHECK: encoding: [0x20,0x17,0x74] +extui a1, a2, 7, 8 + +# Instruction format RRR +# CHECK-INST: sll a10, a11 +# CHECK: encoding: [0x00,0xab,0xa1] +sll a10, a11 + +# Instruction format RRR +# CHECK-INST: slli a5, a1, 15 +# CHECK: encoding: [0x10,0x51,0x11] +slli a5, a1, 15 + +# Instruction format RRR +# CHECK-INST: sra a12, a3 +# CHECK: encoding: [0x30,0xc0,0xb1] +sra a12, a3 + +# Instruction format RRR +# CHECK-INST: srai a8, a5, 0 +# CHECK: encoding: [0x50,0x80,0x21] +srai a8, a5, 0 + +# Instruction format RRR +# CHECK-INST: src a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x81] +src a3, a4, a5 + +# Instruction format RRR +# CHECK-INST: srl a6, a7 +# CHECK: encoding: [0x70,0x60,0x91] +srl a6, a7 + +# Instruction format RRR +# CHECK-INST: srli a3, a4, 8 +# CHECK: encoding: [0x40,0x38,0x41] +srli a3, a4, 8 + +# Instruction format RRR +# CHECK-INST: ssa8l a14 +# CHECK: encoding: [0x00,0x2e,0x40] +ssa8l a14 + +# Instruction format RRR +# CHECK-INST: ssai 31 +# CHECK: encoding: [0x10,0x4f,0x40] +ssai 31 + +# Instruction format RRR +# CHECK-INST: ssl a0 +# CHECK: encoding: [0x00,0x10,0x40] +ssl a0 + +# Instruction format RRR +# CHECK-INST: ssr a2 +# CHECK: encoding: [0x00,0x02,0x40] +ssr a2 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-density.s b/llvm/test/MC/Xtensa/xtensa-valid-density.s index f4315c61e8efd..860597dd62627 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-density.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-density.s @@ -4,6 +4,27 @@ .align 4 LBL0: +# Instruction format RRRN # CHECK-INST: ill.n # CHECK: encoding: [0x6d,0xf0] ill.n + +# Instruction format RRRN +# CHECK-INST: add.n a3, a9, a4 +# CHECK: encoding: [0x4a,0x39] +add.n a3, a9, a4 + +# Instruction format RRRN +# CHECK-INST: addi.n a8, a1, 12 +# CHECK: encoding: [0xcb,0x81] +addi.n a8, a1, 12 + +# Instruction format RRRN +# CHECK-INST: l32i.n a5, a1, 8 +# CHECK: encoding: [0x58,0x21] +l32i.n a5, sp, 8 + +# Instruction format RRRN +# CHECK-INSt: s32i.n a5, a1, 56 +# CHECK: encoding: [0x59,0xe1] +s32i.n a5, sp, 56 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-float.s b/llvm/test/MC/Xtensa/xtensa-valid-float.s index 40405e93c5843..08fe0abad999e 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-float.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-float.s @@ -4,6 +4,7 @@ .align 4 LBL0: +# Instruction format RRR # CHECK-INST: abs.s f2, f3 # CHECK: encoding: [0x10,0x23,0xfa] abs.s f2, f3 @@ -145,10 +146,10 @@ LBL0: # CHECK-INST: sub.s f2, f3, f4 # CHECK: encoding: [0x40,0x23,0x1a] sub.s f2, f3, f4 - + # CHECK-INST: trunc.s a2, f3, 5 # CHECK: encoding: [0x50,0x23,0x9a] - trunc.s a2, f3, 5 + trunc.s a2, f3, 5 # CHECK-INST: ueq.s b0, f2, f3 # CHECK: encoding: [0x30,0x02,0x3b] @@ -170,7 +171,7 @@ LBL0: # CHECK-INST: utrunc.s a2, f3, 5 # CHECK: encoding: [0x50,0x23,0xea] - utrunc.s a2, f3, 5 + utrunc.s a2, f3, 5 # CHECK-INST: wfr f2, a3 # CHECK: encoding: [0x50,0x23,0xfa] diff --git a/llvm/test/MC/Xtensa/xtensa-valid-int.s b/llvm/test/MC/Xtensa/xtensa-valid-int.s index a24191ef4aa5a..08309d299f7b3 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-int.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-int.s @@ -5,6 +5,7 @@ .align 4 LBL0: +# Instruction format RRR # CHECK-INST: rfi 1 # CHECK: encoding: [0x10,0x31,0x00] rfi 1 @@ -12,7 +13,7 @@ LBL0: # CHECK-INST: rsil a3, 1 # CHECK: encoding: [0x30,0x61,0x00] rsil a3, 1 - + # CHECK-INST: waiti 1 # CHECK: encoding: [0x00,0x71,0x00] - waiti 1 \ No newline at end of file + waiti 1 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-mac16.s b/llvm/test/MC/Xtensa/xtensa-valid-mac16.s index dee79da7755d9..2c5170b75652c 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-mac16.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-mac16.s @@ -4,6 +4,7 @@ .align 4 LBL0: +# Instruction format RRR # CHECK-INST: umul.aa.ll a2, a3 # CHECK: encoding: [0x34,0x02,0x70] umul.aa.ll a2, a3 @@ -29,7 +30,7 @@ LBL0: # CHECK-INST: mul.aa.hh a2, a3 # CHECK: encoding: [0x34,0x02,0x77] mul.aa.hh a2, a3 - + # CHECK-INST: mul.ad.ll a2, m2 # CHECK: encoding: [0x04,0x02,0x34] mul.ad.ll a2, m2 @@ -42,7 +43,7 @@ LBL0: # CHECK-INST: mul.ad.hh a2, m2 # CHECK: encoding: [0x04,0x02,0x37] mul.ad.hh a2, m2 - + # CHECK-INST: mul.da.ll m1, a3 # CHECK: encoding: [0x34,0x40,0x64] mul.da.ll m1, a3 @@ -55,7 +56,7 @@ LBL0: # CHECK-INST: mul.da.hh m1, a3 # CHECK: encoding: [0x34,0x40,0x67] mul.da.hh m1, a3 - + # CHECK-INST: mul.dd.ll m1, m2 # CHECK: encoding: [0x04,0x40,0x24] mul.dd.ll m1, m2 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-mul16.s b/llvm/test/MC/Xtensa/xtensa-valid-mul16.s index 4a6c525191f87..472e1ddb533da 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-mul16.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-mul16.s @@ -1,10 +1,10 @@ # RUN: llvm-mc %s -triple=xtensa -mattr=+mul16 -show-encoding \ # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s - .align 4 LBL0: +# Instruction format RRR # CHECK-INST: mul16s a2, a3, a4 # CHECK: encoding: [0x40,0x23,0xd1] mul16s a2, a3, a4 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s b/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s index b3504eef1d557..cd1535498d648 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-regprotect.s @@ -1,10 +1,10 @@ # RUN: llvm-mc %s -triple=xtensa -mattr=+regprotect -show-encoding \ # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s - .align 4 LBL0: +# Instruction format RRR # CHECK-INST: wdtlb a3, a4 # CHECK: encoding: [0x30,0xe4,0x50] wdtlb a3, a4 diff --git a/llvm/test/MC/Xtensa/xtensa-valid-ur.s b/llvm/test/MC/Xtensa/xtensa-valid-ur.s index 5bff7a6457f07..81dca2f18acd5 100644 --- a/llvm/test/MC/Xtensa/xtensa-valid-ur.s +++ b/llvm/test/MC/Xtensa/xtensa-valid-ur.s @@ -4,6 +4,7 @@ .align 4 LBL0: +# Instruction format RSR # CHECK-INST: rur a3, threadptr # CHECK: encoding: [0x70,0x3e,0xe3] rur a3, threadptr diff --git a/llvm/test/MC/Xtensa/xtensa-valid.s b/llvm/test/MC/Xtensa/xtensa-valid.s deleted file mode 100644 index 3edf24e62b033..0000000000000 --- a/llvm/test/MC/Xtensa/xtensa-valid.s +++ /dev/null @@ -1,355 +0,0 @@ -# RUN: llvm-mc %s -triple=xtensa -show-encoding \ -# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s - -.align 4 -LBL0: - -# CHECK-INST: abs a5, a6 -# CHECK: encoding: [0x60,0x51,0x60] -abs a5, a6 - -# CHECK-INST: add a3, a9, a4 -# CHECK: encoding: [0x40,0x39,0x80] -add a3, a9, a4 -# CHECK-INST: add a15, a9, a1 -# CHECK: encoding: [0x10,0xf9,0x80] -add a15, a9, sp - -# CHECK-INST: addi a8, a1, -128 -# CHECK: encoding: [0x82,0xc1,0x80] -addi a8, sp, -128 -# CHECK-INST: addi a8, a1, -12 -# CHECK: encoding: [0x82,0xc1,0xf4] -addi a8, a1, -12 -# CHECK-INST: addmi a8, a1, 256 -# CHECK: encoding: [0x82,0xd1,0x01] -# CHECK-INST: addi a8, a8, 0 -# CHECK: encoding: [0x82,0xc8,0x00] -addi a8, a1, 256 -# CHECK-INST: addmi a8, a1, -9984 -# CHECK: encoding: [0x82,0xd1,0xd9] -# CHECK-INST: addi a8, a8, -16 -# CHECK: encoding: [0x82,0xc8,0xf0] -addi a8, a1, -10000 - -# CHECK-INST: addmi a1, a2, 32512 -# CHECK: encoding: [0x12,0xd2,0x7f] -addmi a1, a2, 32512 - -# CHECK-INST: addx2 a2, a1, a5 -# CHECK: encoding: [0x50,0x21,0x90] -addx2 a2, sp, a5 -# CHECK-INST: addx4 a3, a1, a6 -# CHECK: encoding: [0x60,0x31,0xa0] -addx4 a3, sp, a6 -# CHECK-INST: addx8 a4, a1, a7 -# CHECK: encoding: [0x70,0x41,0xb0] -addx8 a4, sp, a7 - -# CHECK-INST: ball a1, a3, LBL0 -# CHECK: encoding: [0x37,0x41,A] -ball a1, a3, LBL0 -# CHECK-INST: bany a8, a13, LBL0 -# CHECK: encoding: [0xd7,0x88,A] -bany a8, a13, LBL0 -# CHECK-INST: bbc a8, a7, LBL0 -# CHECK: encoding: [0x77,0x58,A] -bbc a8, a7, LBL0 -# CHECK-INST: bbci a3, 16, LBL0 -# CHECK: encoding: [0x07,0x73,A] -bbci a3, 16, LBL0 -# CHECK-INST: bbci a3, 16, LBL0 -# CHECK: encoding: [0x07,0x73,A] -bbci a3, (16), LBL0 -# CHECK-INST: bbci a3, 16, LBL0 -# CHECK: encoding: [0x07,0x73,A] -bbci.l a3, 16, LBL0 -# CHECK-INST: bbs a12, a5, LBL0 -# CHECK: encoding: [0x57,0xdc,A] -bbs a12, a5, LBL0 -# CHECK-INST: bbsi a3, 16, LBL0 -# CHECK: encoding: [0x07,0xf3,A] -bbsi a3, 16, LBL0 -# CHECK-INST: bbsi a3, 16, LBL0 -# CHECK: encoding: [0x07,0xf3,A] -bbsi.l a3, 16, LBL0 -# CHECK-INST: bnall a7, a3, LBL0 -# CHECK: encoding: [0x37,0xc7,A] -bnall a7, a3, LBL0 -# CHECK-INST: bnone a2, a4, LBL0 -# CHECK: encoding: [0x47,0x02,A] -bnone a2, a4, LBL0 - -# CHECK-INST: beq a1, a2, LBL0 -# CHECK: encoding: [0x27,0x11,A] -beq a1, a2, LBL0 -# CHECK-INST: beq a11, a5, LBL0 -# CHECK: encoding: [0x57,0x1b,A] -beq a11, a5, LBL0 -# CHECK-INST: beqi a1, 256, LBL0 -# CHECK: encoding: [0x26,0xf1,A] -beqi a1, 256, LBL0 -# CHECK-INST: beqi a11, -1, LBL0 -# CHECK: encoding: [0x26,0x0b,A] -beqi a11, -1, LBL0 -# CHECK-INST: beqz a8, LBL0 -# CHECK: encoding: [0x16,0bAAAA1000,A] -beqz a8, LBL0 -# CHECK-INST: bge a14, a2, LBL0 -# CHECK: encoding: [0x27,0xae,A] -bge a14, a2, LBL0 -# CHECK-INST: bgei a11, -1, LBL0 -# CHECK: encoding: [0xe6,0x0b,A] -bgei a11, -1, LBL0 -# CHECK-INST: bgei a11, 128, LBL0 -# CHECK: encoding: [0xe6,0xeb,A] -bgei a11, 128, LBL0 -# CHECK-INST: bgeu a14, a2, LBL0 -# CHECK: encoding: [0x27,0xbe,A] -bgeu a14, a2, LBL0 -# CHECK-INST: bgeui a9, 32768, LBL0 -# CHECK: encoding: [0xf6,0x09,A] -bgeui a9, 32768, LBL0 -# CHECK-INST: bgeui a7, 65536, LBL0 -# CHECK: encoding: [0xf6,0x17,A] -bgeui a7, 65536, LBL0 -# CHECK-INST: bgeui a7, 64, LBL0 -# CHECK: encoding: [0xf6,0xd7,A] -bgeui a7, 64, LBL0 -# CHECK-INST: bgez a8, LBL0 -# CHECK: encoding: [0xd6,0bAAAA1000,A] -bgez a8, LBL0 -# CHECK-INST: blt a14, a2, LBL0 -# CHECK: encoding: [0x27,0x2e,A] -blt a14, a2, LBL0 -# CHECK-INST: blti a12, -1, LBL0 -# CHECK: encoding: [0xa6,0x0c,A] -blti a12, -1, LBL0 -# CHECK-INST: blti a0, 32, LBL0 -# CHECK: encoding: [0xa6,0xc0,A] -blti a0, 32, LBL0 -# CHECK-INST: bgeu a13, a1, LBL0 -# CHECK: encoding: [0x17,0xbd,A] -bgeu a13, a1, LBL0 -# CHECK-INST: bltui a7, 16, LBL0 -# CHECK: encoding: [0xb6,0xb7,A] -bltui a7, 16, LBL0 -# CHECK-INST: bltz a6, LBL0 -# CHECK: encoding: [0x96,0bAAAA0110,A] -bltz a6, LBL0 -# CHECK-INST: bne a3, a4, LBL0 -# CHECK: encoding: [0x47,0x93,A] -bne a3, a4, LBL0 -# CHECK-INST: bnei a5, 12, LBL0 -# CHECK: encoding: [0x66,0xa5,A] -bnei a5, 12, LBL0 -# CHECK-INST: bnez a5, LBL0 -# CHECK: encoding: [0x56,0bAAAA0101,A] -bnez a5, LBL0 - -# CHECK-INST: call0 LBL0 -# CHECK: encoding: [0bAA000101,A,A] -call0 LBL0 -# CHECK-INST: callx0 a1 -# CHECK: encoding: [0xc0,0x01,0x00] -callx0 a1 -# CHECK-INST: dsync -# CHECK: encoding: [0x30,0x20,0x00] -dsync -# CHECK-INST: esync -# CHECK: encoding: [0x20,0x20,0x00] -esync - -# CHECK-INST: extui a1, a2, 7, 8 -# CHECK: encoding: [0x20,0x17,0x74] -extui a1, a2, 7, 8 - -# CHECK-INST: extw -# CHECK: encoding: [0xd0,0x20,0x00] -extw - -# CHECK-INST: ill -# CHECK: encoding: [0x00,0x00,0x00] -ill - -# CHECK-INST: isync -# CHECK: encoding: [0x00,0x20,0x00] -isync - -# CHECK-INST: j LBL0 -# CHECK: encoding: [0bAA000110,A,A] -j LBL0 -# CHECK-INST: jx a2 -# CHECK: encoding: [0xa0,0x02,0x00] -jx a2 - -# CHECK-INST: l8ui a2, a1, 3 -# CHECK: encoding: [0x22,0x01,0x03] -l8ui a2, sp, 3 -# CHECK-INST: l16si a3, a1, 4 -# CHECK: encoding: [0x32,0x91,0x02] -l16si a3, sp, 4 -# CHECK-INST: l16ui a4, a1, 6 -# CHECK: encoding: [0x42,0x11,0x03] -l16ui a4, sp, 6 -# CHECK-INST: l32i a5, a1, 8 -# CHECK: encoding: [0x52,0x21,0x02] -l32i a5, sp, 8 -# CHECK-INST: l32r a6, LBL0 -# CHECK: encoding: [0x61,A,A] -l32r a6, LBL0 - -# CHECK-INST: memw -# CHECK: encoding: [0xc0,0x20,0x00] -memw - -# CHECK-INST: moveqz a2, a3, a4 -# CHECK: encoding: [0x40,0x23,0x83] -moveqz a2,a3,a4 -# CHECK-INST: movgez a3, a11, a12 -# CHECK: encoding: [0xc0,0x3b,0xb3] -movgez a3,a11,a12 - -# CHECK-INST: movi a1, -2048 -# CHECK: encoding: [0x12,0xa8,0x00] -movi a1, -2048 - -# CHECK-INST: movltz a7, a8, a9 -# CHECK: encoding: [0x90,0x78,0xa3] -movltz a7, a8, a9 -# CHECK-INST: movnez a10, a11, a12 -# CHECK: encoding: [0xc0,0xab,0x93] -movnez a10,a11, a12 - -# CHECK-INST: neg a1, a3 -# CHECK: encoding: [0x30,0x10,0x60] -neg a1, a3 - -# CHECK-INST: nop -# CHECK: encoding: [0xf0,0x20,0x00] -nop - -# CHECK-INST: or a4, a5, a6 -# CHECK: encoding: [0x60,0x45,0x20] -or a4, a5, a6 - -# CHECK-INST: rer a3, a4 -# CHECK: encoding: [0x30,0x64,0x40] -rer a3, a4 - -# CHECK-INST: ret -# CHECK: encoding: [0x80,0x00,0x00] -ret - -# CHECK-INST: rsr a8, sar -# CHECK: encoding: [0x80,0x03,0x03] -rsr a8, sar -# CHECK-INST: rsr a8, sar -# CHECK: encoding: [0x80,0x03,0x03] -rsr.sar a8 -# CHECK-INST: rsr a8, sar -# CHECK: encoding: [0x80,0x03,0x03] -rsr a8, 3 - - -# CHECK-INST: rsync -# CHECK: encoding: [0x10,0x20,0x00] -rsync - -# CHECK-INST: s8i a2, a1, 3 -# CHECK: encoding: [0x22,0x41,0x03] -s8i a2, sp, 3 -# CHECK-INST: s16i a3, a1, 4 -# CHECK: encoding: [0x32,0x51,0x02] -s16i a3, sp, 4 -# CHECK-INST: s32i a5, a1, 8 -# CHECK: encoding: [0x52,0x61,0x02] -s32i a5, sp, 8 - -# CHECK-INST: sll a10, a11 -# CHECK: encoding: [0x00,0xab,0xa1] -sll a10, a11 - -# CHECK-INST: slli a5, a1, 15 -# CHECK: encoding: [0x10,0x51,0x11] -slli a5, a1, 15 - -# CHECK-INST: sra a12, a3 -# CHECK: encoding: [0x30,0xc0,0xb1] -sra a12, a3 - -# CHECK-INST: srai a8, a5, 0 -# CHECK: encoding: [0x50,0x80,0x21] -srai a8, a5, 0 - -# CHECK-INST: src a3, a4, a5 -# CHECK: encoding: [0x50,0x34,0x81] -src a3, a4, a5 - -# CHECK-INST: srl a6, a7 -# CHECK: encoding: [0x70,0x60,0x91] -srl a6, a7 - -# CHECK-INST: srli a3, a4, 8 -# CHECK: encoding: [0x40,0x38,0x41] -srli a3, a4, 8 - -# CHECK-INST: ssa8l a14 -# CHECK: encoding: [0x00,0x2e,0x40] -ssa8l a14 - -# CHECK-INST: ssai 31 -# CHECK: encoding: [0x10,0x4f,0x40] -ssai 31 - -# CHECK-INST: ssl a0 -# CHECK: encoding: [0x00,0x10,0x40] -ssl a0 - -# CHECK-INST: ssr a2 -# CHECK: encoding: [0x00,0x02,0x40] -ssr a2 - -# CHECK-INST: sub a8, a2, a1 -# CHECK: encoding: [0x10,0x82,0xc0] -sub a8, a2, a1 -# CHECK-INST: subx2 a2, a1, a5 -# CHECK: encoding: [0x50,0x21,0xd0] -subx2 a2, sp, a5 -# CHECK-INST: subx4 a3, a1, a6 -# CHECK: encoding: [0x60,0x31,0xe0] -subx4 a3, sp, a6 -# CHECK-INST: subx8 a4, a1, a7 -# CHECK: encoding: [0x70,0x41,0xf0] -subx8 a4, sp, a7 - -# CHECK-INST: wer a3, a4 -# CHECK: encoding: [0x30,0x74,0x40] -wer a3, a4 - -# CHECK-INST: wsr a8, sar -# CHECK: encoding: [0x80,0x03,0x13] -wsr a8, sar -# CHECK-INST: wsr a8, sar -# CHECK: encoding: [0x80,0x03,0x13] -wsr.sar a8 -# CHECK-INST: wsr a8, sar -# CHECK: encoding: [0x80,0x03,0x13] -wsr a8, 3 -# CHECK-INST: wsr a8, sar -# CHECK: encoding: [0x80,0x03,0x13] -wsr a8, (2 + 1) - -# CHECK-INST: xor a6, a4, a5 -# CHECK: encoding: [0x50,0x64,0x30] -xor a6, a4, a5 - -# CHECK-INST: xsr a8, sar -# CHECK: encoding: [0x80,0x03,0x61] -xsr a8, sar -# CHECK-INST: xsr a8, sar -# CHECK: encoding: [0x80,0x03,0x61 -xsr.sar a8 -# CHECK-INST: xsr a8, sar -# CHECK: encoding: [0x80,0x03,0x61 -xsr a8, 3 From d8fe3d00188bce34f6ade8d69316bf2869fd47c4 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 9 Sep 2022 01:27:38 +0300 Subject: [PATCH 140/150] [Xtensa] Add emit constant pool option. --- clang/include/clang/Driver/Options.td | 1 + clang/lib/Driver/ToolChains/Clang.cpp | 5 ++++ llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 32 ++++++++++++++------- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 8 ++++++ llvm/lib/Target/Xtensa/XtensaSubtarget.h | 2 ++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 837e840980aff..fba9db466fe94 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4671,6 +4671,7 @@ def mfix_esp32_psram_cache_strategy_EQ : Joined<["-"], "mfix-esp32-psram-cache-s HelpText<" Psram cache fix strategies : memw, nops">, Values<"memw, nops">; def mlongcalls : Flag<["-"], "mlongcalls">, Group; +def mtext_section_literals : Flag<["-"], "mtext-section-literals">, Group; // These are legacy user-facing driver-level option spellings. They are always // aliases for options that are spelled using the more common Unix / GNU flag diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 3c942922122ef..970c56c152cda 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2429,6 +2429,11 @@ void Clang::AddXtensaTargetArgs(const ArgList &Args, } } } + + if (Args.getLastArg(options::OPT_mtext_section_literals) != nullptr) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mtext-section-literals"); + } } void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 7ce99f538091e..983332aceac7f 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "XtensaAsmPrinter.h" +#include "XtensaSubtarget.h" #include "MCTargetDesc/XtensaInstPrinter.h" #include "XtensaConstantPoolValue.h" #include "XtensaMCInstLower.h" @@ -68,6 +69,8 @@ void XtensaAsmPrinter::emitConstantPool() { const Function &F = MF->getFunction(); const MachineConstantPool *MCP = MF->getConstantPool(); const std::vector &CP = MCP->getConstants(); + const XtensaSubtarget *Subtarget = &MF->getSubtarget(); + if (CP.empty()) return; @@ -83,18 +86,23 @@ void XtensaAsmPrinter::emitConstantPool() { MCSectionELF *CS = (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); std::string CSectionName = CS->getName().str(); - std::size_t Pos = CSectionName.find(".text"); std::string SectionName; - if (Pos != std::string::npos) { - if (Pos > 0) - SectionName = CSectionName.substr(0, Pos + 5); - else - SectionName = ""; - SectionName += ".literal"; - SectionName += CSectionName.substr(Pos + 5); + + if (Subtarget->useTextSectionLiterals()) { + SectionName = CSectionName; } else { - SectionName = CSectionName; - SectionName += ".literal"; + std::size_t Pos = CSectionName.find(".text"); + if (Pos != std::string::npos) { + if (Pos > 0) + SectionName = CSectionName.substr(0, Pos + 5); + else + SectionName = ""; + SectionName += ".literal"; + SectionName += CSectionName.substr(Pos + 5); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } } MCSectionELF *S = @@ -150,6 +158,8 @@ void XtensaAsmPrinter::emitConstantPool() { OutStreamer->emitRawText(StringRef(str)); } else { + OutStreamer->emitCodeAlignment( + 4, OutStreamer->getContext().getSubtargetInfo()); OutStreamer->emitLabel(LblSym); emitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); } @@ -213,6 +223,8 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue( const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); uint64_t Size = getDataLayout().getTypeAllocSize(ACPV->getType()); + OutStreamer->emitCodeAlignment( + 4, OutStreamer->getContext().getSubtargetInfo()); OutStreamer->emitLabel(LblSym); OutStreamer->emitValue(Expr, Size); } diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index e164da998b5e7..0fd2a25826117 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -24,6 +24,14 @@ using namespace llvm; +static cl::opt TextSectionLiterals("mtext-section-literals", + cl::init(false), cl::Hidden); + +bool XtensaSubtarget::useTextSectionLiterals() const +{ + return TextSectionLiterals; +} + XtensaSubtarget & XtensaSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { StringRef CPUName = CPU; diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index b4fac0b65eb19..a6647b5209613 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -205,6 +205,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { bool hasESP32S3Ops() const { return HasESP32S3Ops; } + bool useTextSectionLiterals() const; + // Automatically generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); }; From 9b553d70a5eec86148c33d166a5af943d8b87f30 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Tue, 1 Nov 2022 17:36:34 +0300 Subject: [PATCH 141/150] [Xtensa] Add support of the mcmodel option. For large mcmodel always emit contsant pool just before code. --- llvm/lib/Target/Xtensa/XtensaSubtarget.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp index 0fd2a25826117..311b757d55be1 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp @@ -29,6 +29,11 @@ static cl::opt TextSectionLiterals("mtext-section-literals", bool XtensaSubtarget::useTextSectionLiterals() const { + // If code model is large then always place literals in + // test section. + if (TLInfo.getTargetMachine().getCodeModel() == CodeModel::Large) + return true; + return TextSectionLiterals; } From 7c941f49ad7141567dae396918abbd237ce5d083 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 16 Nov 2022 22:19:21 +0300 Subject: [PATCH 142/150] [Xtensa] Fix lowering funnel shift left. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 12 ++++++++---- llvm/test/CodeGen/Xtensa/funnel-shift.ll | 4 +--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index fb8f44dde598e..4613728d7de30 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -1793,12 +1793,16 @@ SDValue XtensaTargetLowering::LowerFunnelShift(SDValue Op, bool IsFSHR = Op.getOpcode() == ISD::FSHR; assert((VT == MVT::i32) && "Unexpected funnel shift type!"); + SDValue SetSAR; + if (!IsFSHR) { - Shamt = DAG.getNode(ISD::SUB, DL, MVT::i32, - DAG.getConstant(32, DL, MVT::i32), Shamt); + SetSAR = DAG.getNode(XtensaISD::SSL, DL, + MVT::Glue, Shamt); + } else { + SetSAR = DAG.getNode(XtensaISD::SSR, DL, + MVT::Glue, Shamt); } - SDValue SetSAR = DAG.getNode(XtensaISD::SSR, DL, - MVT::Glue, Shamt); + return DAG.getNode(XtensaISD::SRC, DL, VT, Op0, Op1, SetSAR); } diff --git a/llvm/test/CodeGen/Xtensa/funnel-shift.ll b/llvm/test/CodeGen/Xtensa/funnel-shift.ll index 09bf081be3737..61eed40e72b9f 100644 --- a/llvm/test/CodeGen/Xtensa/funnel-shift.ll +++ b/llvm/test/CodeGen/Xtensa/funnel-shift.ll @@ -11,9 +11,7 @@ entry: define dso_local i32 @test_fshl(i32 %value1, i32 %value2, i32 %shift) nounwind { ; CHECK-LABEL: @test_fshl -; CHECK: movi.n a8, 32 -; CHECK: sub a8, a8, a4 -; CHECK: ssr a8 +; CHECK: ssl a4 ; CHECK: src a2, a2, a3 entry: %0 = tail call i32 @llvm.fshl.i32(i32 %value1, i32 %value2, i32 %shift) From 17496a82f0ae23b64c13ab78e875569d16780544 Mon Sep 17 00:00:00 2001 From: "stefan.stipanovic" Date: Thu, 17 Nov 2022 12:45:43 +0100 Subject: [PATCH 143/150] [Xtensa] Make it possible to use -fuse-ld when GCC toolchain is detected --- clang/lib/Driver/ToolChains/Xtensa.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Xtensa.cpp b/clang/lib/Driver/ToolChains/Xtensa.cpp index de73ba80b3f64..fb5611749cdfe 100644 --- a/clang/lib/Driver/ToolChains/Xtensa.cpp +++ b/clang/lib/Driver/ToolChains/Xtensa.cpp @@ -287,12 +287,18 @@ void xtensa::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + bool LinkerIsLLD; + std::string LinkerPath = ToolChain.GetLinkerPath(&LinkerIsLLD); if (ToolChain.GCCToolchainName != "") { - Linker.assign(ToolChain.GCCToolchainDir); - llvm::sys::path::append(Linker, "bin", - ToolChain.GCCToolchainName + "-" + getShortName()); + if (!LinkerIsLLD) { + Linker.assign(ToolChain.GCCToolchainDir); + llvm::sys::path::append( + Linker, "bin", ToolChain.GCCToolchainName + "-" + getShortName()); + } else { + Linker.assign(LinkerPath); + } } else { - Linker.assign(ToolChain.GetLinkerPath()); + Linker.assign(LinkerPath); } const char *crtbegin, *crtend; From d4f9df654cae3d6821d704dcf8cf423eb2634486 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Thu, 24 Nov 2022 22:59:36 +0300 Subject: [PATCH 144/150] esp/ci: Fixes Windows release archives --- .gitlab-ci.yml | 19 ++++++------------- .legacy-release.yml | 4 ++-- .universal-toolchain-release.yml | 24 ++++++++---------------- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e152a1c90a6e9..dbe33f2bd2c31 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,14 +15,11 @@ variables: CLANG_VER: "15.0.0" GCC_REL_NAME: "esp-2022r1" GCC_REL_VER: "gcc11_2_0" - NEWLIB_REPO: "newlib-cygwin" NEWLIB_REF: "esp-2022r1" - BINUTILS_REPO: "binutils-gdb" BINUTILS_REF: "esp-2022r1-binutils" - XTENSA_OVERLAYS_REPO: "xtensa-overlays" XTENSA_OVERLAYS_REF: "master" - LLVM_GCC_TESTSUITE_REF: "release_universal_clang_toolchain" - XTENSA_CLANG_TOOLCHAIN_REF: "release_universal_clang_toolchain" + LLVM_GCC_TESTSUITE_REF: "esp-15.0.0-20221201" + XTENSA_CLANG_TOOLCHAIN_REF: "esp-15.0.0-20221201" CROSS_ARM_IMAGE: $CI_DOCKER_REGISTRY/llvm-build-cross-arm:1 PLATFORM_NAME_LINUX: "linux-amd64" @@ -39,10 +36,10 @@ variables: ARCHIVE_TOOL_WIN: "zip -9 -r" UNARCHIVE_TOOL_WIN: "unzip" ARCHIVE_EXT_WIN: "zip" - # Use Linux xz compressor to minimize Windows build artifact size. - # Upon release archive will be re-packed into zip format for uploading to GH. - ARCHIVE_TOOL_WIN_INT: ${ARCHIVE_TOOL_LINUX} - UNARCHIVE_TOOL_WIN_INT: ${UNARCHIVE_TOOL_LINUX} + + PACK_ARCHIVE_TOOL_WIN: "tar -h -cJf" + PACK_UNARCHIVE_TOOL_WIN: "${UNARCHIVE_TOOL_LINUX}" + PACK_ARCHIVE_EXT_WIN: "${ARCHIVE_EXT_LINUX}" ARCHIVE_TOOL_MACOS: "tar -cJf" UNARCHIVE_TOOL_MACOS: "tar -xf" @@ -52,10 +49,6 @@ variables: UNARCHIVE_TOOL_NEWLIB: ${UNARCHIVE_TOOL_LINUX} ARCHIVE_EXT_NEWLIB: ${ARCHIVE_EXT_LINUX} - LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - DIST_DIR: "dist" BUILD_DIR: "build" DOWNLOADS_DIR: "downloads" diff --git a/.legacy-release.yml b/.legacy-release.yml index c46195f3fe475..2042369e9049d 100644 --- a/.legacy-release.yml +++ b/.legacy-release.yml @@ -104,11 +104,11 @@ linux_amd64_testsuite: - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} # getting testsuite - - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/${LLVM_TESTSUITE_REPO}.git # preparing testsuite - export PATH=${PWD}/${XTENSA_CLANG_TOOLCHAIN}/bin/:$PATH - - cd llvm-xtensa-testsuite + - cd ${LLVM_TESTSUITE_REPO} # qemu - ./qemu_esp32_install.sh diff --git a/.universal-toolchain-release.yml b/.universal-toolchain-release.yml index 5292918a32a97..27eebaf98e6c7 100644 --- a/.universal-toolchain-release.yml +++ b/.universal-toolchain-release.yml @@ -5,7 +5,7 @@ REL_NUM=$(git describe --abbrev=7) REL_NAME=${REL_SFX}-${REL_NUM}-${PLATFORM_NAME} ARCHIVE_NAME=${REL_NAME}.${ARCHIVE_EXT} - LIBS_ARCHIVE_NAME=libs_${REL_NAME}.${LIBS_ARCHIVE_EXT} + LIBS_ARCHIVE_NAME=libs_${REL_NAME}.${ARCHIVE_EXT} echo "PLATFORM_NAME: $PLATFORM_NAME" echo "REL_NUM: $REL_NUM" echo "REL_NAME: $REL_NAME" @@ -35,7 +35,7 @@ # Pack libs to be used for Rust, Go etc. .package_libs: &package_libs | - ${LIBS_ARCHIVE_TOOL} ${LIBS_ARCHIVE_NAME} esp-clang/lib/libclang* esp-clang/lib/clang/${CLANG_VER}/include + eval ${ARCHIVE_TOOL} ${LIBS_ARCHIVE_NAME} esp-clang/lib/clang/${CLANG_VER}/include esp-clang/lib/lib{clang,LLVM}* ${LIBS_PACK_EXTRA_PATHS:-} mkdir -p ${DISTRO_DIR} mv ${LIBS_ARCHIVE_NAME} ${DISTRO_DIR}/ echo "${LIBS_ARCHIVE_NAME}" > ${DISTRO_DIR}/file_libs-${PLATFORM_NAME} @@ -254,9 +254,6 @@ build_newlib: ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" pack_x86_64-linux-gnu: extends: .pack_linux-gnu_template @@ -295,12 +292,10 @@ pack_x86_64-w64-mingw32: variables: CONF_HOST: "x86_64-w64-mingw32" PLATFORM_NAME: "${PLATFORM_NAME_WIN}" - ARCHIVE_TOOL: "${ARCHIVE_TOOL_LINUX}" - UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_LINUX}" - ARCHIVE_EXT: "${ARCHIVE_EXT_LINUX}" - LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_WIN}" - LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_WIN}" - LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_WIN}" + ARCHIVE_TOOL: "${PACK_ARCHIVE_TOOL_WIN}" + UNARCHIVE_TOOL: "${PACK_UNARCHIVE_TOOL_WIN}" + ARCHIVE_EXT: "${PACK_ARCHIVE_EXT_WIN}" + LIBS_PACK_EXTRA_PATHS: esp-clang/bin/lib{c++,clang,LLVM,unwind}* .pack_apple-darwin_template: extends: .pack_template @@ -308,9 +303,6 @@ pack_x86_64-w64-mingw32: ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" - LIBS_ARCHIVE_TOOL: "${ARCHIVE_TOOL_MACOS}" - LIBS_UNARCHIVE_TOOL: "${UNARCHIVE_TOOL_MACOS}" - LIBS_ARCHIVE_EXT: "${ARCHIVE_EXT_MACOS}" pack_x86_64-apple-darwin: extends: .pack_apple-darwin_template @@ -344,10 +336,10 @@ test_x86_64-linux-gnu: - *get_release_name - ${UNARCHIVE_TOOL} ${DIST_DIR}/${ARCHIVE_NAME} # getting testsuite - - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/llvm-xtensa-testsuite.git + - git clone -b ${LLVM_GCC_TESTSUITE_REF} --depth 1 $GITLAB_SSH_SERVER/idf/${LLVM_TESTSUITE_REPO}.git # preparing testsuite - export PATH=${PWD}/esp-clang/bin:$PATH - - cd llvm-xtensa-testsuite + - cd ${LLVM_TESTSUITE_REPO} # qemu - ./qemu_esp32_install.sh # run testsuite for esp32 From 23786128aea96880a5752f6bd1c22aab27622ccf Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Tue, 29 Nov 2022 13:11:44 +0300 Subject: [PATCH 145/150] esp/ci: Check for OOM failures after build --- .universal-toolchain-release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.universal-toolchain-release.yml b/.universal-toolchain-release.yml index 27eebaf98e6c7..75a41258aead0 100644 --- a/.universal-toolchain-release.yml +++ b/.universal-toolchain-release.yml @@ -65,6 +65,14 @@ expire_in: 1 day variables: BUILD_TOOLCHAIN_CMD_EXTRA_ARGS: "" + after_script: + # help to identify that build failed due to OOM + - > + if [ $CI_JOB_STATUS == 'failed' ]; then + [ ! -f "${BUILD_DIR}/build.log" ] || grep -i "internal compiler error\|Killed" ${BUILD_DIR}/build.log || true + [ ! -f "${BUILD_DIR}/tests.log" ] || grep -i "internal compiler error\|Killed" ${BUILD_DIR}/tests.log || true + [ ! -f "${BUILD_DIR}/lld-tests.log" ] || grep -i "internal compiler error\|Killed" ${BUILD_DIR}/lld-tests.log || true + fi script: - *get_release_name - mkdir ${DOWNLOADS_DIR} From a07cafda9140cbd9e37235c1522b42674221d2a4 Mon Sep 17 00:00:00 2001 From: Stefan Stipanovic Date: Mon, 23 Jan 2023 15:02:22 +0100 Subject: [PATCH 146/150] [LLD][Xtensa] Cover DIFF{8, 16, 32} relocations. --- lld/ELF/Arch/Xtensa.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lld/ELF/Arch/Xtensa.cpp b/lld/ELF/Arch/Xtensa.cpp index f6d75fde7ac29..10d6c3b52d1dc 100644 --- a/lld/ELF/Arch/Xtensa.cpp +++ b/lld/ELF/Arch/Xtensa.cpp @@ -71,6 +71,9 @@ RelExpr Xtensa::getRelExpr(RelType type, const Symbol &s, // Because it's a relaxation hint, this relocation can be ignored for now // until linker relaxations are implemented. return R_NONE; + case R_XTENSA_DIFF8: + case R_XTENSA_DIFF16: + case R_XTENSA_DIFF32: case R_XTENSA_PDIFF8: case R_XTENSA_PDIFF16: case R_XTENSA_PDIFF32: From f389074e0045a2fb705b5524cb1c937723cb10bc Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 16 Mar 2023 11:22:07 +0300 Subject: [PATCH 147/150] [Xtensa] Fixup hwloop pass Create block and insert it before loop end address as target for jump/branch instruction to avoid premature exit from loop. --- llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp | 44 ++++++++++++++++--- .../lib/Target/Xtensa/XtensaHardwareLoops.cpp | 2 +- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp b/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp index 3089d7ee59fbf..6250aa938f83c 100644 --- a/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFixupHWLoops.cpp @@ -290,7 +290,6 @@ bool XtensaFixupHwLoops::fixupLoopInstrs(MachineLoop *L) { Changed = true; break; } - if (PII != PIB) { LoopEnd = MF->CreateMachineBasicBlock(); MF->insert(++(PMBB->getIterator()), LoopEnd); @@ -302,10 +301,45 @@ bool XtensaFixupHwLoops::fixupLoopInstrs(MachineLoop *L) { .addMBB(LoopEnd); LoopEnd->addSuccessor(LoopEnd); } else { - BuildMI(*PMBB, PII, DL, TII->get(Xtensa::LOOPEND)).addMBB(PMBB); - PMBB->addSuccessor(PMBB); - BuildMI(*PMBB, PII, DL, TII->get(Xtensa::NOP)); - LoopEnd = PMBB; + bool NeedBlockForJump = false; + // Check for branches to the loop end basic block from + // predecessors + for (auto I = PMBB->pred_begin(), E = PMBB->pred_end(); I != E; + ++I) { + MachineBasicBlock *PLEMBB = *I; + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + SmallVector Cond; + if (!TII->analyzeBranch(*PLEMBB, TBB, FBB, Cond)) { + if (TBB == PMBB) { + NeedBlockForJump = true; + break; + } + } else { + NeedBlockForJump = true; + break; + } + } + // Create block and insert it before loop end address as + // target for jump/branch instruction to avoid premature exit from + // loop + if (NeedBlockForJump) { + LoopEnd = MF->CreateMachineBasicBlock(); + MF->insert(++(PMBB->getIterator()), LoopEnd); + LoopEnd->transferSuccessors(PMBB); + LoopEnd->splice(LoopEnd->end(), PMBB, PII, PMBB->end()); + PMBB->addSuccessor(LoopEnd); + BuildMI(*PMBB, PMBB->end(), DL, TII->get(Xtensa::NOP)); + + BuildMI(*LoopEnd, LoopEnd->begin(), DL, + TII->get(Xtensa::LOOPEND)) + .addMBB(LoopEnd); + LoopEnd->addSuccessor(LoopEnd); + } else { + BuildMI(*PMBB, PII, DL, TII->get(Xtensa::LOOPEND)).addMBB(PMBB); + PMBB->addSuccessor(PMBB); + BuildMI(*PMBB, PII, DL, TII->get(Xtensa::NOP)); + LoopEnd = PMBB; + } } Changed = true; diff --git a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp index 34dc193995594..f77a98486ec3f 100644 --- a/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp +++ b/llvm/lib/Target/Xtensa/XtensaHardwareLoops.cpp @@ -360,7 +360,7 @@ bool XtensaHardwareLoops::processLoop(MachineLoop *L) { } bool XtensaHardwareLoops::checkLoopSize(MachineLoop *L) { - uint64_t LoopSize = 0; + uint64_t LoopSize = 3; //Reserve space for possible NOP for (auto *MBB : L->getBlocks()) { uint64_t BlockSize = 0; From a3ce6353dafd60542593f028a92f33f7e4e2e064 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 16 Feb 2023 03:08:38 +0300 Subject: [PATCH 148/150] [Xtensa] Implement constant islands pass The constant islands pass is always executed for large code model. Also currently is disabled support of the hardware loops for large code model, need to add support for hwloops in constant islands pass in future. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + llvm/lib/Target/Xtensa/Xtensa.h | 1 + llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 171 +- llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 5 + .../Target/Xtensa/XtensaConstantIsland.cpp | 1471 +++++++++++++++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 20 + .../lib/Target/Xtensa/XtensaTargetMachine.cpp | 1 + .../Xtensa/XtensaTargetTransformInfo.cpp | 6 + 8 files changed, 1609 insertions(+), 67 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaConstantIsland.cpp diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index fccdde013bbc9..873de70425a73 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -17,6 +17,7 @@ add_public_tablegen_target(XtensaCommonTableGen) add_llvm_target(XtensaCodeGen XtensaAsmPrinter.cpp XtensaConstantPoolValue.cpp + XtensaConstantIsland.cpp XtensaESP32PSRAMFix.cpp XtensaFixupHWLoops.cpp XtensaFrameLowering.cpp diff --git a/llvm/lib/Target/Xtensa/Xtensa.h b/llvm/lib/Target/Xtensa/Xtensa.h index f9b06c6e79fa5..5f7c7292a51bc 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.h +++ b/llvm/lib/Target/Xtensa/Xtensa.h @@ -30,5 +30,6 @@ FunctionPass *createXtensaSizeReductionPass(); FunctionPass *createXtensaHardwareLoops(); FunctionPass *createXtensaFixupHwLoops(); FunctionPass *createXtensaPSRAMCacheFixPass(); +FunctionPass *createXtensaConstantIslandPass(); } // namespace llvm #endif /* LLVM_LIB_TARGET_XTENSA_XTENSA_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 983332aceac7f..75a830208453f 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -14,10 +14,10 @@ //===----------------------------------------------------------------------===// #include "XtensaAsmPrinter.h" -#include "XtensaSubtarget.h" #include "MCTargetDesc/XtensaInstPrinter.h" #include "XtensaConstantPoolValue.h" #include "XtensaMCInstLower.h" +#include "XtensaSubtarget.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" @@ -46,6 +46,38 @@ void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { XtensaMCInstLower Lower(MF->getContext(), *this); MCInst LoweredMI; unsigned Opc = MI->getOpcode(); + const MachineConstantPool *MCP = MF->getConstantPool(); + + // If we just ended a constant pool, mark it as such. + if (InConstantPool && Opc != Xtensa::CONSTPOOL_ENTRY) { + OutStreamer->emitDataRegion(MCDR_DataRegionEnd); + InConstantPool = false; + } + + if (Opc == Xtensa::CONSTPOOL_ENTRY) { + // CONSTPOOL_ENTRY - This instruction represents a floating + // constant pool in the function. The first operand is the ID# + // for this instruction, the second is the index into the + // MachineConstantPool that this is, the third is the size in + // bytes of this constant pool entry. + // The required alignment is specified on the basic block holding this MI. + // + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + // If this is the first entry of the pool, mark it. + if (!InConstantPool) { + if (OutStreamer->hasRawTextSupport()) { + OutStreamer->emitRawText(StringRef("\t.literal_position\n")); + } + OutStreamer->emitDataRegion(MCDR_DataRegion); + InConstantPool = true; + } + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + + emitMachineConstantPoolEntry(MCPE, LabelId); + return; + } switch (Opc) { case Xtensa::BR_JT: { @@ -61,6 +93,63 @@ void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, LoweredMI); } +/// Emit single constant pool entry to asm or obj file. +/// Use i argument to define entry label. +void XtensaAsmPrinter::emitMachineConstantPoolEntry( + const MachineConstantPoolEntry &CPE, int i) { + if (CPE.isMachineConstantPoolEntry()) { + XtensaConstantPoolValue *ACPV = + static_cast(CPE.Val.MachineCPVal); + ACPV->setLabelId(i); + emitMachineConstantPoolValue(CPE.Val.MachineCPVal); + } else { + MCSymbol *LblSym = GetCPISymbol(i); + // TODO find a better way to check whether we emit data to .s file + if (OutStreamer->hasRawTextSupport()) { + std::string str("\t.literal "); + str += LblSym->getName(); + str += ", "; + const Constant *C = CPE.Val.ConstVal; + + Type *Ty = C->getType(); + if (const auto *CFP = dyn_cast(C)) { + str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); + } else if (const auto *CI = dyn_cast(C)) { + str += toString(CI->getValue(), 10, true); + } else if (isa(Ty)) { + const MCExpr *ME = lowerConstant(C); + const MCSymbolRefExpr &SRE = cast(*ME); + const MCSymbol &Sym = SRE.getSymbol(); + str += Sym.getName(); + } else { + unsigned NumElements; + if (isa(Ty)) + NumElements = (cast(Ty))->getNumElements(); + else + NumElements = Ty->getArrayNumElements(); + + for (unsigned I = 0; I < NumElements; I++) { + const Constant *CAE = C->getAggregateElement(I); + if (I > 0) + str += ", "; + if (const auto *CFP = dyn_cast(CAE)) { + str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); + } else if (const auto *CI = dyn_cast(CAE)) { + str += toString(CI->getValue(), 10, true); + } + } + } + + OutStreamer->emitRawText(StringRef(str)); + } else { + OutStreamer->emitCodeAlignment( + 4, OutStreamer->getContext().getSubtargetInfo()); + OutStreamer->emitLabel(LblSym); + emitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); + } + } +} + /// EmitConstantPool - Print to the current output stream assembly /// representations of the constants in the constant pool MCP. This is /// used to print out constants which have been "spilled to memory" by @@ -71,6 +160,9 @@ void XtensaAsmPrinter::emitConstantPool() { const std::vector &CP = MCP->getConstants(); const XtensaSubtarget *Subtarget = &MF->getSubtarget(); + if (Subtarget->useTextSectionLiterals()) + return; + if (CP.empty()) return; @@ -87,22 +179,17 @@ void XtensaAsmPrinter::emitConstantPool() { (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); std::string CSectionName = CS->getName().str(); std::string SectionName; - - if (Subtarget->useTextSectionLiterals()) { - SectionName = CSectionName; + std::size_t Pos = CSectionName.find(".text"); + if (Pos != std::string::npos) { + if (Pos > 0) + SectionName = CSectionName.substr(0, Pos + 5); + else + SectionName = ""; + SectionName += ".literal"; + SectionName += CSectionName.substr(Pos + 5); } else { - std::size_t Pos = CSectionName.find(".text"); - if (Pos != std::string::npos) { - if (Pos > 0) - SectionName = CSectionName.substr(0, Pos + 5); - else - SectionName = ""; - SectionName += ".literal"; - SectionName += CSectionName.substr(Pos + 5); - } else { - SectionName = CSectionName; - SectionName += ".literal"; - } + SectionName = CSectionName; + SectionName += ".literal"; } MCSectionELF *S = @@ -113,57 +200,7 @@ void XtensaAsmPrinter::emitConstantPool() { } } - if (CPE.isMachineConstantPoolEntry()) { - XtensaConstantPoolValue *ACPV = - static_cast(CPE.Val.MachineCPVal); - ACPV->setLabelId(i); - emitMachineConstantPoolValue(CPE.Val.MachineCPVal); - } else { - MCSymbol *LblSym = GetCPISymbol(i); - // TODO find a better way to check whether we emit data to .s file - if (OutStreamer->hasRawTextSupport()) { - std::string str("\t.literal "); - str += LblSym->getName(); - str += ", "; - const Constant *C = CPE.Val.ConstVal; - - Type *Ty = C->getType(); - if (const auto *CFP = dyn_cast(C)) { - str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); - } else if (const auto *CI = dyn_cast(C)) { - str += toString(CI->getValue(), 10, true); - } else if (isa(Ty)) { - const MCExpr *ME = lowerConstant(C); - const MCSymbolRefExpr &SRE = cast(*ME); - const MCSymbol &Sym = SRE.getSymbol(); - str += Sym.getName(); - } else { - unsigned NumElements; - if (isa(Ty)) - NumElements = (cast(Ty))->getNumElements(); - else - NumElements = Ty->getArrayNumElements(); - - for (unsigned I = 0; I < NumElements; I++) { - const Constant *CAE = C->getAggregateElement(I); - if (I > 0) - str += ", "; - if (const auto *CFP = dyn_cast(CAE)) { - str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); - } else if (const auto *CI = dyn_cast(CAE)) { - str += toString(CI->getValue(), 10, true); - } - } - } - - OutStreamer->emitRawText(StringRef(str)); - } else { - OutStreamer->emitCodeAlignment( - 4, OutStreamer->getContext().getSubtargetInfo()); - OutStreamer->emitLabel(LblSym); - emitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); - } - } + emitMachineConstantPoolEntry(CPE, i); } } diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h index e17059a2d4c3b..dbf092f671237 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -17,6 +17,7 @@ #include "XtensaTargetMachine.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Support/Compiler.h" namespace llvm { @@ -28,6 +29,9 @@ class raw_ostream; class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { const MCSubtargetInfo *STI; + /// InConstantPool - Maintain state when emitting a sequence of constant + /// pool entries so we can properly mark them as data regions. + bool InConstantPool = false; public: explicit XtensaAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) @@ -37,6 +41,7 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { StringRef getPassName() const override { return "Xtensa Assembly Printer"; } void emitInstruction(const MachineInstr *MI) override; void emitConstantPool() override; + void emitMachineConstantPoolEntry(const MachineConstantPoolEntry &CPE, int i); void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, diff --git a/llvm/lib/Target/Xtensa/XtensaConstantIsland.cpp b/llvm/lib/Target/Xtensa/XtensaConstantIsland.cpp new file mode 100644 index 0000000000000..cc010a02522ab --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaConstantIsland.cpp @@ -0,0 +1,1471 @@ +//===- XtensaConstantIslandPass.cpp - Emit Pc Relative loads +//----------------===// +// +// 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 pass is used to make Pc relative loads of constants. +// +// Loading constants inline is expensive on Xtensa and it's in general better +// to place the constant nearby in code space and then it can be loaded with a +// simple l32r instruction. +// +// The constants can be not just numbers but addresses of functions and labels. +// This can be particularly helpful in static relocation mode for embedded +// non-linux targets. +// +//===----------------------------------------------------------------------===// + +#include "Xtensa.h" +#include "XtensaConstantPoolValue.h" +#include "XtensaMachineFunctionInfo.h" +#include "XtensaSubtarget.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/LivePhysRegs.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "xtensa-constant-islands" + +STATISTIC(NumCPEs, "Number of constpool entries"); +STATISTIC(NumSplit, "Number of uncond branches inserted"); +STATISTIC(NumCBrFixed, "Number of cond branches fixed"); +STATISTIC(NumUBrFixed, "Number of uncond branches fixed"); + +// FIXME: This option should be removed once it has received sufficient testing. +static cl::opt + AlignConstantIslands("xtensa-align-constant-islands", cl::Hidden, + cl::init(true), + cl::desc("Align constant islands in code")); + +// Rather than do make check tests with huge amounts of code, we force +// the test to use this amount. +static cl::opt ConstantIslandsSmallOffset( + "xtensa-constant-islands-small-offset", cl::init(0), + cl::desc("Make small offsets be this amount for testing purposes"), + cl::Hidden); + +#define MAX_CP_ITERATIONS 30 +#define MAX_BR_ITERATIONS 30 + +// TODO +// This defines for L32R and J instruction displacemnt for +// testing purposes only +#define MAX_DISP_L32R 262144 +#define BITS_JUMP 18 + +static unsigned int branchTargetOperand(MachineInstr *MI) { + switch (MI->getOpcode()) { + case Xtensa::J: + return 0; + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + return 2; + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + return 1; + case Xtensa::BT: + case Xtensa::BF: + return 1; + } + llvm_unreachable("Unknown branch type"); +} + +namespace { + +using Iter = MachineBasicBlock::iterator; +using ReverseIter = MachineBasicBlock::reverse_iterator; + +/// XtensaConstantIslands - Due to limited PC-relative displacements, Xtensa +/// requires constant pool entries to be scattered among the instructions +/// inside a function. To do this, it completely ignores the normal LLVM +/// constant pool; instead, it places constants wherever it feels like with +/// special instructions. +/// +/// The terminology used in this pass includes: +/// Islands - Clumps of constants placed in the function. +/// Water - Potential places where an island could be formed. +/// CPE - A constant pool entry that has been placed somewhere, which +/// tracks a list of users. + +class XtensaConstantIslands : public MachineFunctionPass { + /// BasicBlockInfo - Information about the offset and size of a single + /// basic block. + struct BasicBlockInfo { + /// Offset - Distance from the beginning of the function to the beginning + /// of this basic block. + /// + /// Offsets are computed assuming worst case padding before an aligned + /// block. This means that subtracting basic block offsets always gives a + /// conservative estimate of the real distance which may be smaller. + /// + /// Because worst case padding is used, the computed offset of an aligned + /// block may not actually be aligned. + unsigned Offset = 0; + + /// Size - Size of the basic block in bytes. If the block contains + /// inline assembly, this is a worst case estimate. + /// + /// The size does not include any alignment padding whether from the + /// beginning of the block, or from an aligned jump table at the end. + unsigned Size = 0; + + BasicBlockInfo() = default; + + unsigned postOffset() const { return Offset + Size; } + }; + + std::vector BBInfo; + + /// WaterList - A sorted list of basic blocks where islands could be placed + /// (i.e. blocks that don't fall through to the following block, due + /// to a return, unreachable, or unconditional branch). + std::vector WaterList; + + /// NewWaterList - The subset of WaterList that was created since the + /// previous iteration by inserting unconditional branches. + SmallSet NewWaterList; + + using water_iterator = std::vector::iterator; + + /// CPUser - One user of a constant pool, keeping the machine instruction + /// pointer, the constant pool being referenced, and the max displacement + /// allowed from the instruction to the CP. The LowWaterMark records the + /// lowest basic block where a new CPEntry can be placed. To ensure this + /// pass terminates, the CP entries are initially placed at the second block + /// of the function and then move monotonically to higher addresses. The + /// exception to this rule is when the current CP entry for a particular + /// CPUser is out of range, but there is another CP entry for the same + /// constant value in range. We want to use the existing in-range CP + /// entry, but if it later moves out of range, the search for new water + /// should resume where it left off. The LowWaterMark is used to record + /// that point. + struct CPUser { + MachineInstr *MI; + MachineInstr *CPEMI; + MachineBasicBlock *LowWaterMark; + + private: + unsigned MaxDisp; + + public: + CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp) + : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp) { + LowWaterMark = CPEMI->getParent(); + } + + /// getMaxDisp - Returns the maximum displacement supported by MI. + unsigned getMaxDisp() const { + unsigned xMaxDisp = + ConstantIslandsSmallOffset ? ConstantIslandsSmallOffset : MaxDisp; + return xMaxDisp; + } + + void setMaxDisp(unsigned val) { MaxDisp = val; } + }; + + /// CPUsers - Keep track of all of the machine instructions that use various + /// constant pools and their max displacement. + std::vector CPUsers; + + /// CPEntry - One per constant pool entry, keeping the machine instruction + /// pointer, the constpool index, and the number of CPUser's which + /// reference this entry. + struct CPEntry { + MachineInstr *CPEMI; + unsigned CPI; + unsigned RefCount; + + CPEntry(MachineInstr *cpemi, unsigned cpi, unsigned rc = 0) + : CPEMI(cpemi), CPI(cpi), RefCount(rc) {} + }; + + /// CPEntries - Keep track of all of the constant pool entry machine + /// instructions. For each original constpool index (i.e. those that + /// existed upon entry to this pass), it keeps a vector of entries. + /// Original elements are cloned as we go along; the clones are + /// put in the vector of the original element, but have distinct CPIs. + std::vector> CPEntries; + + /// ImmBranch - One per immediate branch, keeping the machine instruction + /// pointer, conditional or unconditional, the max displacement, + /// and (if isCond is true) the corresponding unconditional branch + /// opcode. + struct ImmBranch { + MachineInstr *MI; + unsigned MaxDisp : 31; + bool isCond : 1; + int UncondBr; + + ImmBranch(MachineInstr *mi, unsigned maxdisp, bool cond, int ubr) + : MI(mi), MaxDisp(maxdisp), isCond(cond), UncondBr(ubr) {} + }; + + /// ImmBranches - Keep track of all the immediate branch instructions. + /// + std::vector ImmBranches; + + const XtensaSubtarget *STI = nullptr; + const XtensaInstrInfo *TII; + const TargetRegisterInfo *TRI; + XtensaFunctionInfo *MFI; + MachineFunction *MF = nullptr; + MachineConstantPool *MCP = nullptr; + MachineBasicBlock *InitConstantMBB = nullptr; + std::unique_ptr RS; + LivePhysRegs LiveRegs; + + unsigned PICLabelUId; + bool PrescannedForConstants = false; + + void initPICLabelUId(unsigned UId) { PICLabelUId = UId; } + + unsigned createPICLabelUId() { return PICLabelUId++; } + +public: + static char ID; + + XtensaConstantIslands() : MachineFunctionPass(ID) {} + + StringRef getPassName() const override { return "Xtensa Constant Islands"; } + + bool runOnMachineFunction(MachineFunction &F) override; + + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::NoVRegs); + } + + void doInitialPlacement(std::vector &CPEMIs); + CPEntry *findConstPoolEntry(unsigned CPI, const MachineInstr *CPEMI); + Align getCPEAlign(const MachineInstr &CPEMI); + void initializeFunctionInfo(const std::vector &CPEMIs); + unsigned getOffsetOf(MachineInstr *MI) const; + unsigned getUserOffset(CPUser &) const; + void dumpBBs(); + + bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset, + unsigned Disp); + + void computeBlockSize(MachineBasicBlock *MBB); + MachineBasicBlock *splitBlockBeforeInstr(MachineInstr &MI); + void updateForInsertedWaterBlock(MachineBasicBlock *NewBB); + void adjustBBOffsetsAfter(MachineBasicBlock *BB); + bool decrementCPEReferenceCount(unsigned CPI, MachineInstr *CPEMI); + int findInRangeCPEntry(CPUser &U, unsigned UserOffset); + bool findAvailableWater(CPUser &U, unsigned UserOffset, + water_iterator &WaterIter); + void createNewWater(unsigned CPUserIndex, unsigned UserOffset, + MachineBasicBlock *&NewMBB); + bool handleConstantPoolUser(unsigned CPUserIndex); + void removeDeadCPEMI(MachineInstr *CPEMI); + bool removeUnusedCPEntries(); + bool isCPEntryInRange(MachineInstr *MI, unsigned UserOffset, + MachineInstr *CPEMI, unsigned Disp, + bool DoDump = false); + bool isWaterInRange(unsigned UserOffset, MachineBasicBlock *Water, CPUser &U, + unsigned &Growth); + bool isBBInRange(MachineInstr *MI, MachineBasicBlock *BB, unsigned Disp); + bool fixupImmediateBr(ImmBranch &Br); + bool fixupConditionalBr(ImmBranch &Br); + bool fixupUnconditionalBr(ImmBranch &Br); + void removeEntryJump(); +}; + +} // end anonymous namespace + +char XtensaConstantIslands::ID = 0; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +/// print block size and offset information - debugging +LLVM_DUMP_METHOD void XtensaConstantIslands::dumpBBs() { + for (unsigned J = 0, E = BBInfo.size(); J != E; ++J) { + const BasicBlockInfo &BBI = BBInfo[J]; + dbgs() << format("%08x %bb.%u\t", BBI.Offset, J) + << format(" size=%#x\n", BBI.Size); + } +} +#endif + +bool XtensaConstantIslands::runOnMachineFunction(MachineFunction &mf) { + MF = &mf; + MCP = mf.getConstantPool(); + STI = &mf.getSubtarget(); + LLVM_DEBUG(dbgs() << "constant island machine function " + << "\n"); + TII = (const XtensaInstrInfo *)STI->getInstrInfo(); + MFI = MF->getInfo(); + + TRI = STI->getRegisterInfo(); + + if (!STI->useTextSectionLiterals()) + return false; + + if (TRI->trackLivenessAfterRegAlloc(*MF)) + RS.reset(new RegScavenger()); + + LLVM_DEBUG(dbgs() << "constant island processing " + << "\n"); + + // Renumber all of the machine basic blocks in the function, guaranteeing that + // the numbers agree with the position of the block in the function. + MF->RenumberBlocks(); + + bool MadeChange = false; + + // Perform the initial placement of the constant pool entries. To start with, + // we put them all at the end of the function. + std::vector CPEMIs; + doInitialPlacement(CPEMIs); + + // Renumber all of the machine basic blocks in the function, guaranteeing + // that the numbers agree with the position of the block in the function. + MF->RenumberBlocks(); + + /// The next UID to take is the first unused one. + initPICLabelUId(CPEMIs.size()); + + // Do the initial scan of the function, building up information about the + // sizes of each block, the location of all the water, and finding all of the + // constant pool users. + initializeFunctionInfo(CPEMIs); + CPEMIs.clear(); + LLVM_DEBUG(dumpBBs()); + + /// Remove dead constant pool entries. + MadeChange |= removeUnusedCPEntries(); + + // Iteratively place constant pool entries and fix up branches until there + // is no change. + unsigned NoCPIters = 0, NoBRIters = 0; + (void)NoBRIters; + while (true) { + LLVM_DEBUG(dbgs() << "Beginning CP iteration #" << NoCPIters << '\n'); + bool CPChange = false; + for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) { + CPChange |= handleConstantPoolUser(i); + } + if (CPChange && ++NoCPIters > MAX_CP_ITERATIONS) + report_fatal_error("Constant Island pass failed to converge!"); + LLVM_DEBUG(dumpBBs()); + + // Clear NewWaterList now. If we split a block for branches, it should + // appear as "new water" for the next iteration of constant pool placement. + NewWaterList.clear(); + + LLVM_DEBUG(dbgs() << "Beginning BR iteration #" << NoBRIters << '\n'); + bool BRChange = false; + for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) + BRChange |= fixupImmediateBr(ImmBranches[i]); + if (BRChange && ++NoBRIters > MAX_BR_ITERATIONS) + report_fatal_error("Branch Fix Up pass failed to converge!"); + LLVM_DEBUG(dumpBBs()); + + if (!CPChange && !BRChange) + break; + + MadeChange = true; + } + removeEntryJump(); + LLVM_DEBUG(dbgs() << '\n'; dumpBBs()); + BBInfo.clear(); + WaterList.clear(); + CPUsers.clear(); + CPEntries.clear(); + ImmBranches.clear(); + return MadeChange; +} + +/// BBHasFallthrough - Return true if the specified basic block can fallthrough +/// into the block immediately after it. +static bool BBHasFallthrough(MachineBasicBlock *MBB) { + // Get the next machine basic block in the function. + MachineFunction::iterator MBBI = MBB->getIterator(); + // Can't fall off end of function. + if (std::next(MBBI) == MBB->getParent()->end()) + return false; + + MachineBasicBlock *NextBB = &*std::next(MBBI); + return llvm::is_contained(MBB->successors(), NextBB); +} + +/// doInitialPlacement - Perform the initial placement of the constant pool +/// entries. To start with, we put them all at the end of the function. +void XtensaConstantIslands::doInitialPlacement( + std::vector &CPEMIs) { + // Create the basic block to hold the CPE's. + MachineBasicBlock *BB = MF->CreateMachineBasicBlock(); + + // TODO + MachineBasicBlock *Entry = &MF->front(); + MachineBasicBlock *NewEntry = MF->CreateMachineBasicBlock(); + + MF->insert(Entry->getIterator(), NewEntry); + BuildMI(NewEntry, DebugLoc(), TII->get(Xtensa::J)).addMBB(Entry); + NewEntry->addSuccessor(Entry); + NewEntry->setAlignment(Entry->getAlignment()); + + // Copy live-in information to new block. + for (const MachineBasicBlock::RegisterMaskPair &RegMaskPair : + Entry->liveins()) + NewEntry->addLiveIn(RegMaskPair); + + // MachineConstantPool measures alignment in bytes. We measure in log2(bytes). + const Align MaxAlign = MCP->getConstantPoolAlign(); + + BB->setAlignment(AlignConstantIslands ? MaxAlign : Align(4)); + + MF->insert(Entry->getIterator(), BB); + + // The function needs to be as aligned as the basic blocks. The linker may + // move functions around based on their alignment. + MF->ensureAlignment(BB->getAlignment()); + + // Order the entries in BB by descending alignment. That ensures correct + // alignment of all entries as long as BB is sufficiently aligned. Keep + // track of the insertion point for each alignment. We are going to bucket + // sort the entries as they are created. + SmallVector InsPoint(Log2(MaxAlign) + 1, + BB->end()); + + // Add all of the constants from the constant pool to the end block, use an + // identity mapping of CPI's to CPE's. + const std::vector &CPs = MCP->getConstants(); + + const DataLayout &TD = MF->getDataLayout(); + for (unsigned i = 0, e = CPs.size(); i != e; ++i) { + unsigned Size = CPs[i].getSizeInBytes(TD); + assert(Size >= 4 && "Too small constant pool entry"); + Align Alignment = CPs[i].getAlign(); + // Verify that all constant pool entries are a multiple of their alignment. + // If not, we would have to pad them out so that instructions stay aligned. + assert(isAligned(Alignment, Size) && "CP Entry not multiple of 4 bytes!"); + + // Insert CONSTPOOL_ENTRY before entries with a smaller alignment. + unsigned LogAlign = Log2(Alignment); + MachineBasicBlock::iterator InsAt = InsPoint[LogAlign]; + + MachineInstr *CPEMI = + BuildMI(*BB, InsAt, DebugLoc(), TII->get(Xtensa::CONSTPOOL_ENTRY)) + .addImm(i) + .addConstantPoolIndex(i) + .addImm(Size); + + CPEMIs.push_back(CPEMI); + + // Ensure that future entries with higher alignment get inserted before + // CPEMI. This is bucket sort with iterators. + for (unsigned a = LogAlign + 1; a <= Log2(MaxAlign); ++a) + if (InsPoint[a] == InsAt) + InsPoint[a] = CPEMI; + // Add a new CPEntry, but no corresponding CPUser yet. + CPEntries.emplace_back(1, CPEntry(CPEMI, i)); + ++NumCPEs; + LLVM_DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = " + << Size << ", align = " << Alignment.value() << '\n'); + } + InitConstantMBB = BB; + LLVM_DEBUG(BB->dump()); +} + +/// findConstPoolEntry - Given the constpool index and CONSTPOOL_ENTRY MI, +/// look up the corresponding CPEntry. +XtensaConstantIslands::CPEntry * +XtensaConstantIslands::findConstPoolEntry(unsigned CPI, + const MachineInstr *CPEMI) { + std::vector &CPEs = CPEntries[CPI]; + // Number of entries per constpool index should be small, just do a + // linear search. + for (CPEntry &CPE : CPEs) { + if (CPE.CPEMI == CPEMI) + return &CPE; + } + return nullptr; +} + +/// getCPEAlign - Returns the required alignment of the constant pool entry +/// represented by CPEMI. Alignment is measured in log2(bytes) units. +Align XtensaConstantIslands::getCPEAlign(const MachineInstr &CPEMI) { + assert(CPEMI.getOpcode() == Xtensa::CONSTPOOL_ENTRY); + + // Everything is 4-byte aligned unless AlignConstantIslands is set. + if (!AlignConstantIslands) + return Align(4); + + unsigned CPI = CPEMI.getOperand(1).getIndex(); + assert(CPI < MCP->getConstants().size() && "Invalid constant pool index."); + return MCP->getConstants()[CPI].getAlign(); +} + +/// initializeFunctionInfo - Do the initial scan of the function, building up +/// information about the sizes of each block, the location of all the water, +/// and finding all of the constant pool users. +void XtensaConstantIslands::initializeFunctionInfo( + const std::vector &CPEMIs) { + BBInfo.clear(); + BBInfo.resize(MF->getNumBlockIDs()); + + // First thing, compute the size of all basic blocks, and see if the function + // has any inline assembly in it. If so, we have to be conservative about + // alignment assumptions, as we don't know for sure the size of any + // instructions in the inline assembly. + for (MachineBasicBlock &MBB : *MF) + computeBlockSize(&MBB); + + // Compute block offsets. + adjustBBOffsetsAfter(&MF->front()); + + // Now go back through the instructions and build up our data structures. + for (MachineBasicBlock &MBB : *MF) { + // If this block doesn't fall through into the next MBB, then this is + // 'water' that a constant pool island could be placed. + if (!BBHasFallthrough(&MBB)) + WaterList.push_back(&MBB); + for (MachineInstr &MI : MBB) { + if (MI.isDebugInstr()) + continue; + + int Opc = MI.getOpcode(); + if (MI.isBranch()) { + bool isCond = false; + unsigned Bits = 0; + unsigned Scale = 1; + int UOpc = Xtensa::J; + switch (Opc) { + default: + continue; // Ignore other branches for now + case Xtensa::J: + Bits = BITS_JUMP; + Scale = 1; + isCond = false; + break; + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + Bits = 8; + Scale = 1; + isCond = true; + break; + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + Bits = 12; + Scale = 1; + isCond = true; + break; + case Xtensa::BT: + case Xtensa::BF: + Bits = 8; + Scale = 1; + isCond = true; + break; + } + // Record this immediate branch. + unsigned MaxOffs = ((1 << (Bits - 1)) - 1) * Scale - 4; + ImmBranches.push_back(ImmBranch(&MI, MaxOffs, isCond, UOpc)); + } + + if (Opc == Xtensa::CONSTPOOL_ENTRY) + continue; + + // Scan the instructions for constant pool operands. + for (const MachineOperand &MO : MI.operands()) + if (MO.isCPI()) { + // We found one. The addressing mode tells us the max displacement + // from the PC that this instruction permits. + unsigned CPI = MO.getIndex(); + MachineInstr *CPEMI = CPEMIs[CPI]; + + switch (Opc) { + default: + llvm_unreachable("Unknown addressing mode for CP reference!"); + case Xtensa::L32R: + CPUsers.push_back(CPUser(&MI, CPEMI, MAX_DISP_L32R)); + break; + } + + // Increment corresponding CPEntry reference count. + CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); + assert(CPE && "Cannot find a corresponding CPEntry!"); + CPE->RefCount++; + + // Instructions can only use one CP entry, don't bother scanning the + // rest of the operands. + break; + } + } + } +} + +/// computeBlockSize - Compute the size and some alignment information for MBB. +/// This function updates BBInfo directly. +void XtensaConstantIslands::computeBlockSize(MachineBasicBlock *MBB) { + BasicBlockInfo &BBI = BBInfo[MBB->getNumber()]; + BBI.Size = 0; + + for (const MachineInstr &MI : *MBB) { + if (MI.getOpcode() == Xtensa::CONSTPOOL_ENTRY) { + BBI.Size += 4; + } else { + BBI.Size += TII->getInstSizeInBytes(MI); + } + } +} + +/// getOffsetOf - Return the current offset of the specified machine instruction +/// from the start of the function. This offset changes as stuff is moved +/// around inside the function. +unsigned XtensaConstantIslands::getOffsetOf(MachineInstr *MI) const { + MachineBasicBlock *MBB = MI->getParent(); + + // The offset is composed of two things: the sum of the sizes of all MBB's + // before this instruction's block, and the offset from the start of the block + // it is in. + unsigned Offset = BBInfo[MBB->getNumber()].Offset; + + // Sum instructions before MI in MBB. + for (MachineBasicBlock::iterator I = MBB->begin(); &*I != MI; ++I) { + assert(I != MBB->end() && "Didn't find MI in its own basic block?"); + Offset += TII->getInstSizeInBytes(*I); + } + return Offset; +} + +/// CompareMBBNumbers - Little predicate function to sort the WaterList by MBB +/// ID. +static bool CompareMBBNumbers(const MachineBasicBlock *LHS, + const MachineBasicBlock *RHS) { + return LHS->getNumber() < RHS->getNumber(); +} + +/// updateForInsertedWaterBlock - When a block is newly inserted into the +/// machine function, it upsets all of the block numbers. Renumber the blocks +/// and update the arrays that parallel this numbering. +void XtensaConstantIslands::updateForInsertedWaterBlock( + MachineBasicBlock *NewBB) { + // Renumber the MBB's to keep them consecutive. + NewBB->getParent()->RenumberBlocks(NewBB); + + // Insert an entry into BBInfo to align it properly with the (newly + // renumbered) block numbers. + BBInfo.insert(BBInfo.begin() + NewBB->getNumber(), BasicBlockInfo()); + + // Next, update WaterList. Specifically, we need to add NewMBB as having + // available water after it. + water_iterator IP = llvm::lower_bound(WaterList, NewBB, CompareMBBNumbers); + WaterList.insert(IP, NewBB); +} + +unsigned XtensaConstantIslands::getUserOffset(CPUser &U) const { + return getOffsetOf(U.MI); +} + +/// Split the basic block containing MI into two blocks, which are joined by +/// an unconditional branch. Update data structures and renumber blocks to +/// account for this change and returns the newly created block. +MachineBasicBlock * +XtensaConstantIslands::splitBlockBeforeInstr(MachineInstr &MI) { + MachineBasicBlock *OrigBB = MI.getParent(); + + // Collect liveness information at MI. + LivePhysRegs LRs(*MF->getSubtarget().getRegisterInfo()); + LRs.addLiveOuts(*OrigBB); + auto LivenessEnd = ++MachineBasicBlock::iterator(MI).getReverse(); + for (MachineInstr &LiveMI : make_range(OrigBB->rbegin(), LivenessEnd)) + LRs.stepBackward(LiveMI); + + // Create a new MBB for the code after the OrigBB. + MachineBasicBlock *NewBB = + MF->CreateMachineBasicBlock(OrigBB->getBasicBlock()); + MachineFunction::iterator MBBI = ++OrigBB->getIterator(); + MF->insert(MBBI, NewBB); + + // Splice the instructions starting with MI over to NewBB. + NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end()); + + // Add an unconditional branch from OrigBB to NewBB. + // Note the new unconditional branch is not being recorded. + // There doesn't seem to be meaningful DebugInfo available; this doesn't + // correspond to anything in the source. + BuildMI(OrigBB, DebugLoc(), TII->get(Xtensa::J)).addMBB(NewBB); + ++NumSplit; + + // Update the CFG. All succs of OrigBB are now succs of NewBB. + NewBB->transferSuccessors(OrigBB); + + // OrigBB branches to NewBB. + OrigBB->addSuccessor(NewBB); + + // Update live-in information in the new block. + MachineRegisterInfo &MRI = MF->getRegInfo(); + for (MCPhysReg L : LRs) + if (!MRI.isReserved(L)) + NewBB->addLiveIn(L); + + // Update internal data structures to account for the newly inserted MBB. + // This is almost the same as updateForInsertedWaterBlock, except that + // the Water goes after OrigBB, not NewBB. + MF->RenumberBlocks(NewBB); + + // Insert an entry into BBInfo to align it properly with the (newly + // renumbered) block numbers. + BBInfo.insert(BBInfo.begin() + NewBB->getNumber(), BasicBlockInfo()); + + // Next, update WaterList. Specifically, we need to add OrigMBB as having + // available water after it (but not if it's already there, which happens + // when splitting before a conditional branch that is followed by an + // unconditional branch - in that case we want to insert NewBB). + water_iterator IP = llvm::lower_bound(WaterList, OrigBB, CompareMBBNumbers); + MachineBasicBlock *WaterBB = *IP; + if (WaterBB == OrigBB) + WaterList.insert(std::next(IP), NewBB); + else + WaterList.insert(IP, OrigBB); + NewWaterList.insert(OrigBB); + + // Figure out how large the OrigBB is. As the first half of the original + // block, it cannot contain a tablejump. The size includes + // the new jump we added. (It should be possible to do this without + // recounting everything, but it's very confusing, and this is rarely + // executed.) + computeBlockSize(OrigBB); + + // Figure out how large the NewMBB is. As the second half of the original + // block, it may contain a tablejump. + computeBlockSize(NewBB); + + // All BBOffsets following these blocks must be modified. + adjustBBOffsetsAfter(OrigBB); + +#if 0 + //TODO + // Need to fix live-in lists if we track liveness. + if (TRI->trackLivenessAfterRegAlloc(*MF)) + computeAndAddLiveIns(LiveRegs, *NewBB); +#endif + return NewBB; +} + +/// isOffsetInRange - Checks whether UserOffset (the location of a constant pool +/// reference) is within MaxDisp of TrialOffset (a proposed location of a +/// constant pool entry). +bool XtensaConstantIslands::isOffsetInRange(unsigned UserOffset, + unsigned TrialOffset, + unsigned MaxDisp) { + UserOffset = (UserOffset + 3) & (~0x3); + if ((UserOffset >= TrialOffset) && (UserOffset - TrialOffset <= MaxDisp)) { + return true; + } + return false; +} + +/// isWaterInRange - Returns true if a CPE placed after the specified +/// Water (a basic block) will be in range for the specific MI. +/// +/// Compute how much the function will grow by inserting a CPE after Water. +bool XtensaConstantIslands::isWaterInRange(unsigned UserOffset, + MachineBasicBlock *Water, CPUser &U, + unsigned &Growth) { + unsigned CPEOffset = BBInfo[Water->getNumber()].postOffset(); + unsigned NextBlockOffset; + Align NextBlockAlignment; + MachineFunction::const_iterator NextBlock = ++Water->getIterator(); + if (NextBlock == MF->end()) { + NextBlockOffset = BBInfo[Water->getNumber()].postOffset(); + NextBlockAlignment = Align(1); + } else { + NextBlockOffset = BBInfo[NextBlock->getNumber()].Offset; + NextBlockAlignment = NextBlock->getAlignment(); + } + unsigned Size = U.CPEMI->getOperand(2).getImm(); + unsigned CPEEnd = CPEOffset + Size; + + // The CPE may be able to hide in the alignment padding before the next + // block. It may also cause more padding to be required if it is more aligned + // that the next block. + if (CPEEnd > NextBlockOffset) { + Growth = CPEEnd - NextBlockOffset; + // Compute the padding that would go at the end of the CPE to align the next + // block. + Growth += offsetToAlignment(CPEEnd, NextBlockAlignment); + + // If the CPE is to be inserted before the instruction, that will raise + // the offset of the instruction. Also account for unknown alignment padding + // in blocks between CPE and the user. + if (CPEOffset < UserOffset) + UserOffset += Growth; + } else + // CPE fits in existing padding. + Growth = 0; + + return isOffsetInRange(UserOffset, CPEOffset, U.getMaxDisp()); +} + +/// isCPEntryInRange - Returns true if the distance between specific MI and +/// specific ConstPool entry instruction can fit in MI's displacement field. +bool XtensaConstantIslands::isCPEntryInRange(MachineInstr *MI, + unsigned UserOffset, + MachineInstr *CPEMI, + unsigned MaxDisp, bool DoDump) { + unsigned CPEOffset = getOffsetOf(CPEMI); + + if (DoDump) { + LLVM_DEBUG({ + unsigned Block = MI->getParent()->getNumber(); + const BasicBlockInfo &BBI = BBInfo[Block]; + dbgs() << "User of CPE#" << CPEMI->getOperand(0).getImm() + << " max delta=" << MaxDisp + << format(" insn address=%#x", UserOffset) << " in " + << printMBBReference(*MI->getParent()) << ": " + << format("%#x-%x\t", BBI.Offset, BBI.postOffset()) << *MI + << format("CPE address=%#x offset=%+d: ", CPEOffset, + int(CPEOffset - UserOffset)); + }); + } + + return isOffsetInRange(UserOffset, CPEOffset, MaxDisp); +} + +#ifndef NDEBUG +/// BBIsJumpedOver - Return true of the specified basic block's only predecessor +/// unconditionally branches to its only successor. +static bool BBIsJumpedOver(MachineBasicBlock *MBB) { + if (MBB->pred_size() != 1 || MBB->succ_size() != 1) + return false; + MachineBasicBlock *Succ = *MBB->succ_begin(); + MachineBasicBlock *Pred = *MBB->pred_begin(); + MachineInstr *PredMI = &Pred->back(); + + if (PredMI->getOpcode() == Xtensa::J) + return PredMI->getOperand(0).getMBB() == Succ; + return false; +} +#endif + +void XtensaConstantIslands::adjustBBOffsetsAfter(MachineBasicBlock *BB) { + unsigned BBNum = BB->getNumber(); + for (unsigned i = BBNum + 1, e = MF->getNumBlockIDs(); i < e; ++i) { + // Get the offset and known bits at the end of the layout predecessor. + // Include the alignment of the current block. + unsigned Offset = BBInfo[i - 1].Offset + BBInfo[i - 1].Size; + Align BlockAlignment = MF->getBlockNumbered(i)->getAlignment(); + BBInfo[i].Offset = Offset + offsetToAlignment(Offset, BlockAlignment); + } +} + +/// decrementCPEReferenceCount - find the constant pool entry with index CPI +/// and instruction CPEMI, and decrement its refcount. If the refcount +/// becomes 0 remove the entry and instruction. Returns true if we removed +/// the entry, false if we didn't. +bool XtensaConstantIslands::decrementCPEReferenceCount(unsigned CPI, + MachineInstr *CPEMI) { + // Find the old entry. Eliminate it if it is no longer used. + CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); + assert(CPE && "Unexpected!"); + if (--CPE->RefCount == 0) { + removeDeadCPEMI(CPEMI); + CPE->CPEMI = nullptr; + --NumCPEs; + return true; + } + return false; +} + +/// LookForCPEntryInRange - see if the currently referenced CPE is in range; +/// if not, see if an in-range clone of the CPE is in range, and if so, +/// change the data structures so the user references the clone. Returns: +/// 0 = no existing entry found +/// 1 = entry found, and there were no code insertions or deletions +/// 2 = entry found, and there were code insertions or deletions +int XtensaConstantIslands::findInRangeCPEntry(CPUser &U, unsigned UserOffset) { + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + + // Check to see if the CPE is already in-range. + if (isCPEntryInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp())) { + LLVM_DEBUG(dbgs() << "In range\n"); + return 1; + } + + // No. Look for previously created clones of the CPE that are in range. + unsigned CPI = CPEMI->getOperand(1).getIndex(); + std::vector &CPEs = CPEntries[CPI]; + for (CPEntry &CPE : CPEs) { + // We already tried this one + if (CPE.CPEMI == CPEMI) + continue; + // Removing CPEs can leave empty entries, skip + if (CPE.CPEMI == nullptr) + continue; + if (isCPEntryInRange(UserMI, UserOffset, CPE.CPEMI, U.getMaxDisp())) { + LLVM_DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#" << CPE.CPI + << "\n"); + // Point the CPUser node to the replacement + U.CPEMI = CPE.CPEMI; + // Change the CPI in the instruction operand to refer to the clone. + for (MachineOperand &MO : UserMI->operands()) + if (MO.isCPI()) { + MO.setIndex(CPE.CPI); + break; + } + // Adjust the refcount of the clone... + CPE.RefCount++; + // ...and the original. If we didn't remove the old entry, none of the + // addresses changed, so we don't need another pass. + return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1; + } + } + return 0; +} + +/// getUnconditionalBrDisp - Returns the maximum displacement that can fit in +/// the specific unconditional branch instruction. +static inline unsigned getUnconditionalBrDisp(int Opc) { + // Currently only J instruction is used + return (1 << (BITS_JUMP - 1)); +} + +/// findAvailableWater - Look for an existing entry in the WaterList in which +/// we can place the CPE referenced from U so it's within range of U's MI. +/// Returns true if found, false if not. If it returns true, WaterIter +/// is set to the WaterList entry. +/// To ensure that this pass +/// terminates, the CPE location for a particular CPUser is only allowed to +/// move to a lower address, so search backward from the end of the list and +/// prefer the first water that is in range. +bool XtensaConstantIslands::findAvailableWater(CPUser &U, unsigned UserOffset, + water_iterator &WaterIter) { + if (WaterList.empty()) + return false; + + unsigned BestGrowth = ~0u; + for (water_iterator IP = std::prev(WaterList.end()), B = WaterList.begin();; + --IP) { + MachineBasicBlock *WaterBB = *IP; + // Check if water is in range and is either at a higher address than the + // current "low water mark" or a new water block that was created since + // the previous iteration by inserting an unconditional branch. In the + // latter case, we want to allow resetting the low water mark back to + // this new water since we haven't seen it before. Inserting branches + // should be relatively uncommon and when it does happen, we want to be + // sure to take advantage of it for all the CPEs near that block, so that + // we don't insert more branches than necessary. + unsigned Growth; + if (isWaterInRange(UserOffset, WaterBB, U, Growth) && + (WaterBB->getNumber() > U.LowWaterMark->getNumber() || + NewWaterList.count(WaterBB)) && + Growth < BestGrowth) { + // This is the least amount of required padding seen so far. + BestGrowth = Growth; + WaterIter = IP; + LLVM_DEBUG(dbgs() << "Found water after " << printMBBReference(*WaterBB) + << " Growth=" << Growth << '\n'); + + // Keep looking unless it is perfect. + if (BestGrowth == 0) + return true; + } + if (IP == B) + break; + } + return BestGrowth != ~0u; +} + +/// createNewWater - No existing WaterList entry will work for +/// CPUsers[CPUserIndex], so create a place to put the CPE. The end of the +/// block is used if in range, and the conditional branch munged so control +/// flow is correct. Otherwise the block is split to create a hole with an +/// unconditional branch around it. In either case NewMBB is set to a +/// block following which the new island can be inserted (the WaterList +/// is not adjusted). +void XtensaConstantIslands::createNewWater(unsigned CPUserIndex, + unsigned UserOffset, + MachineBasicBlock *&NewMBB) { + CPUser &U = CPUsers[CPUserIndex]; + MachineInstr *UserMI = U.MI; + MachineBasicBlock *UserMBB = UserMI->getParent(); + NewMBB = splitBlockBeforeInstr(*UserMI); +} + +/// handleConstantPoolUser - Analyze the specified user, checking to see if it +/// is out-of-range. If so, pick up the constant pool value and move it some +/// place in-range. Return true if we changed any addresses (thus must run +/// another pass of branch lengthening), false otherwise. +bool XtensaConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { + CPUser &U = CPUsers[CPUserIndex]; + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + unsigned CPI = CPEMI->getOperand(1).getIndex(); + unsigned Size = CPEMI->getOperand(2).getImm(); + // Compute this only once, it's expensive. + unsigned UserOffset = getUserOffset(U); + + // See if the current entry is within range, or there is a clone of it + // in range. + int result = findInRangeCPEntry(U, UserOffset); + if (result == 1) + return false; + else if (result == 2) + return true; + + // Look for water where we can place this CPE. + MachineBasicBlock *NewIsland = MF->CreateMachineBasicBlock(); + MachineBasicBlock *NewMBB; + water_iterator IP; + if (findAvailableWater(U, UserOffset, IP)) { + LLVM_DEBUG(dbgs() << "Found water in range\n"); + MachineBasicBlock *WaterBB = *IP; + + // If the original WaterList entry was "new water" on this iteration, + // propagate that to the new island. This is just keeping NewWaterList + // updated to match the WaterList, which will be updated below. + if (NewWaterList.erase(WaterBB)) + NewWaterList.insert(NewIsland); + + // The new CPE goes before the following block (NewMBB). + NewMBB = &*++WaterBB->getIterator(); + } else { + // No water found. + LLVM_DEBUG(dbgs() << "No water found\n"); + createNewWater(CPUserIndex, UserOffset, NewMBB); + + // splitBlockBeforeInstr adds to WaterList, which is important when it is + // called while handling branches so that the water will be seen on the + // next iteration for constant pools, but in this context, we don't want + // it. Check for this so it will be removed from the WaterList. + // Also remove any entry from NewWaterList. + MachineBasicBlock *WaterBB = &*--NewMBB->getIterator(); + IP = llvm::find(WaterList, WaterBB); + if (IP != WaterList.end()) + NewWaterList.erase(WaterBB); + + // We are adding new water. Update NewWaterList. + NewWaterList.insert(NewIsland); + } + + // Remove the original WaterList entry; we want subsequent insertions in + // this vicinity to go after the one we're about to insert. This + // considerably reduces the number of times we have to move the same CPE + // more than once and is also important to ensure the algorithm terminates. + if (IP != WaterList.end()) + WaterList.erase(IP); + + // Okay, we know we can put an island before NewMBB now, do it! + MF->insert(NewMBB->getIterator(), NewIsland); + + // Update internal data structures to account for the newly inserted MBB. + updateForInsertedWaterBlock(NewIsland); + + // Decrement the old entry, and remove it if refcount becomes 0. + decrementCPEReferenceCount(CPI, CPEMI); + + // No existing clone of this CPE is within range. + // We will be generating a new clone. Get a UID for it. + unsigned ID = createPICLabelUId(); + + // Now that we have an island to add the CPE to, clone the original CPE and + // add it to the island. + U.LowWaterMark = NewIsland; + U.CPEMI = BuildMI(NewIsland, DebugLoc(), TII->get(Xtensa::CONSTPOOL_ENTRY)) + .addImm(ID) + .addConstantPoolIndex(CPI) + .addImm(Size); + CPEntries[CPI].push_back(CPEntry(U.CPEMI, ID, 1)); + ++NumCPEs; + + // Mark the basic block as aligned as required by the const-pool entry. + NewIsland->setAlignment(getCPEAlign(*U.CPEMI)); + + // Increase the size of the island block to account for the new entry. + BBInfo[NewIsland->getNumber()].Size += Size; + adjustBBOffsetsAfter(&*--NewIsland->getIterator()); + + // Finally, change the CPI in the instruction operand to be ID. + for (MachineOperand &MO : UserMI->operands()) + if (MO.isCPI()) { + MO.setIndex(ID); + break; + } + + LLVM_DEBUG( + dbgs() << " Moved CPE to #" << ID << " CPI=" << CPI + << format(" offset=%#x\n", BBInfo[NewIsland->getNumber()].Offset)); + + return true; +} + +/// removeDeadCPEMI - Remove a dead constant pool entry instruction. Update +/// sizes and offsets of impacted basic blocks. +void XtensaConstantIslands::removeDeadCPEMI(MachineInstr *CPEMI) { + MachineBasicBlock *CPEBB = CPEMI->getParent(); + unsigned Size = CPEMI->getOperand(2).getImm(); + CPEMI->eraseFromParent(); + BBInfo[CPEBB->getNumber()].Size -= Size; + // All succeeding offsets have the current size value added in, fix this. + if (CPEBB->empty()) { + BBInfo[CPEBB->getNumber()].Size = 0; + + // This block no longer needs to be aligned. + CPEBB->setAlignment(Align(1)); + } else { + // Entries are sorted by descending alignment, so realign from the front. + CPEBB->setAlignment(getCPEAlign(*CPEBB->begin())); + } + + adjustBBOffsetsAfter(CPEBB); + // An island has only one predecessor BB and one successor BB. Check if + // this BB's predecessor jumps directly to this BB's successor. This + // shouldn't happen currently. + assert(!BBIsJumpedOver(CPEBB) && "How did this happen?"); + // FIXME: remove the empty blocks after all the work is done? +} + +/// removeUnusedCPEntries - Remove constant pool entries whose refcounts +/// are zero. +bool XtensaConstantIslands::removeUnusedCPEntries() { + unsigned MadeChange = false; + for (std::vector &CPEs : CPEntries) { + for (CPEntry &CPE : CPEs) { + if (CPE.RefCount == 0 && CPE.CPEMI) { + removeDeadCPEMI(CPE.CPEMI); + CPE.CPEMI = nullptr; + MadeChange = true; + } + } + } + return MadeChange; +} + +/// isBBInRange - Returns true if the distance between specific MI and +/// specific BB can fit in MI's displacement field. +bool XtensaConstantIslands::isBBInRange(MachineInstr *MI, + MachineBasicBlock *DestBB, + unsigned MaxDisp) { + unsigned PCAdj = 4; + unsigned BrOffset = getOffsetOf(MI) + PCAdj; + unsigned DestOffset = BBInfo[DestBB->getNumber()].Offset; + + LLVM_DEBUG(dbgs() << "Branch of destination " << printMBBReference(*DestBB) + << " from " << printMBBReference(*MI->getParent()) + << " max delta=" << MaxDisp << " from " << getOffsetOf(MI) + << " to " << DestOffset << " offset " + << int(DestOffset - BrOffset) << "\t" << *MI); + if (BrOffset <= DestOffset) { + // Branch before the Dest. + if (DestOffset - BrOffset < MaxDisp) + return true; + } else { + if (BrOffset - DestOffset <= MaxDisp) + return true; + } + return false; +} + +/// fixupImmediateBr - Fix up an immediate branch whose destination is too far +/// away to fit in its displacement field. +bool XtensaConstantIslands::fixupImmediateBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + + if (MI->getOpcode() == Xtensa::JX) + return false; + + // TOOO: currently we don't fix J in start block + if (MI->getParent()->getNumber() == 0) + return false; + + unsigned TargetOperand = branchTargetOperand(MI); + MachineBasicBlock *DestBB = MI->getOperand(TargetOperand).getMBB(); + + // Check to see if the DestBB is already in-range. + if (isBBInRange(MI, DestBB, Br.MaxDisp)) + return false; + + if (!Br.isCond) + return fixupUnconditionalBr(Br); + return fixupConditionalBr(Br); +} + +/// fixupUnconditionalBr - Fix up an unconditional branch whose destination is +/// too far away to fit in its displacement field. If the LR register has been +/// spilled in the epilogue, then we can use BL to implement a far jump. +/// Otherwise, add an intermediate branch instruction to a branch. +/// fixupUnconditionalBr - Fix up an unconditional branch whose destination is +/// too far away to fit in its displacement field. If the LR register has been +/// spilled in the epilogue, then we can use BSR to implement a far jump. +/// Otherwise, add an intermediate branch instruction to a branch. +bool XtensaConstantIslands::fixupUnconditionalBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *MBB = MI->getParent(); + MachineBasicBlock *DestBB = TII->getBranchDestBlock(*MI); + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineConstantPool *ConstantPool = MF->getConstantPool(); + + XtensaConstantPoolValue *C = + XtensaConstantPoolMBB::Create(MF->getFunction().getContext(), DestBB, 0); + unsigned CPSize = ConstantPool->getConstants().size(); + unsigned Idx = ConstantPool->getConstantPoolIndex(C, Align(4)); + Register DestReg = MRI.createVirtualRegister(&Xtensa::ARRegClass); + + MachineInstr *CPEMI = nullptr; + // Add a new CPEntry, but no corresponding CPUser yet. + unsigned ID = Idx; + if (CPSize == Idx) { + ID = createPICLabelUId(); + CPEMI = + BuildMI(InitConstantMBB, DebugLoc(), TII->get(Xtensa::CONSTPOOL_ENTRY)) + .addImm(ID) + .addConstantPoolIndex(Idx) + .addImm(4); + CPEntries.emplace_back(1, CPEntry(CPEMI, Idx, 1)); + ++NumCPEs; + BBInfo[InitConstantMBB->getNumber()].Size += 4; + adjustBBOffsetsAfter(InitConstantMBB); + } else { + std::vector &CPEs = CPEntries[Idx]; + for (CPEntry &CPE : CPEs) { + if ((CPE.CPEMI != nullptr) && + isCPEntryInRange(MI, MAX_DISP_L32R, CPE.CPEMI, MAX_DISP_L32R, true)) { + CPEMI = CPE.CPEMI; + CPE.RefCount++; + } + } + if (CPEMI == nullptr) { + ID = createPICLabelUId(); + CPEMI = BuildMI(InitConstantMBB, DebugLoc(), + TII->get(Xtensa::CONSTPOOL_ENTRY)) + .addImm(ID) + .addConstantPoolIndex(Idx) + .addImm(4); + CPEntries[Idx].push_back(CPEntry(CPEMI, ID, 1)); + ++NumCPEs; + BBInfo[InitConstantMBB->getNumber()].Size += 4; + adjustBBOffsetsAfter(InitConstantMBB); + } else { + ID = CPEMI->getOperand(0).getImm(); + } + } + MachineInstr *L32R = + BuildMI(*MBB, MI, DebugLoc(), TII->get(Xtensa::L32R), DestReg) + .addConstantPoolIndex(ID); + + MI->setDesc(TII->get(Xtensa::JX)); + MI->removeOperand(0); + MI->addOperand(MachineOperand::CreateReg(DestReg, true)); + + RegScavenger RS; + RS.enterBasicBlockEnd(*MBB); + unsigned Scav = RS.scavengeRegisterBackwards(Xtensa::ARRegClass, + L32R->getIterator(), false, 0); + MRI.replaceRegWith(DestReg, Scav); + MRI.clearVirtRegs(); + RS.setRegUsed(Scav); + CPUsers.push_back(CPUser(L32R, CPEMI, MAX_DISP_L32R)); + BBInfo[MBB->getNumber()].Size += 3; + adjustBBOffsetsAfter(MBB); + ++NumUBrFixed; + + LLVM_DEBUG(dbgs() << " Changed B to long jump " << *MI); + return true; +} + +// TODO +/// fixupConditionalBr - Fix up a conditional branch whose destination is too +/// far away to fit in its displacement field. It is converted to an inverse +/// conditional branch + an unconditional branch to the destination. +bool XtensaConstantIslands::fixupConditionalBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *DestBB = TII->getBranchDestBlock(*MI); + + SmallVector Cond; + Cond.push_back(MachineOperand::CreateImm(MI->getOpcode())); + Cond.push_back(MI->getOperand(0)); + TII->reverseBranchCondition(Cond); + // Add an unconditional branch to the destination and invert the branch + // condition to jump over it: + // bteqz L1 + // => + // bnez L2 + // b L1 + // L2: + + // If the branch is at the end of its MBB and that has a fall-through block, + // direct the updated conditional branch to the fall-through block. Otherwise, + // split the MBB before the next instruction. + MachineBasicBlock *MBB = MI->getParent(); + MachineInstr *BMI = &MBB->back(); + bool NeedSplit = (BMI != MI) || !BBHasFallthrough(MBB); + + ++NumCBrFixed; + if (BMI != MI) { + if (std::next(MachineBasicBlock::iterator(MI)) == std::prev(MBB->end()) && + BMI->isUnconditionalBranch()) { + // Last MI in the BB is an unconditional branch. Can we simply invert the + // condition and swap destinations: + // beqz L1 + // b L2 + // => + // bnez L2 + // b L1 + MachineBasicBlock *NewDest = TII->getBranchDestBlock(*BMI); + if (isBBInRange(MI, NewDest, Br.MaxDisp)) { + LLVM_DEBUG( + dbgs() << " Invert Bcc condition and swap its destination with " + << *BMI); + BMI->getOperand(BMI->getNumExplicitOperands() - 1).setMBB(DestBB); + MI->getOperand(MI->getNumExplicitOperands() - 1).setMBB(NewDest); + + MI->setDesc(TII->get(Cond[0].getImm())); + return true; + } + } + } + + if (NeedSplit) { + splitBlockBeforeInstr(*MI); + // No need for the branch to the next block. We're adding an unconditional + // branch to the destination. + int Delta = TII->getInstSizeInBytes(MBB->back()); + BBInfo[MBB->getNumber()].Size -= Delta; + MBB->back().eraseFromParent(); + + // The conditional successor will be swapped between the BBs after this, so + // update CFG. + MBB->addSuccessor(DestBB); + std::next(MBB->getIterator())->removeSuccessor(DestBB); + } + MachineBasicBlock *NextBB = &*++MBB->getIterator(); + + LLVM_DEBUG(dbgs() << " Insert B to " << printMBBReference(*DestBB) + << " also invert condition and change dest. to " + << printMBBReference(*NextBB) << "\n"); + + // Insert a new conditional branch and a new unconditional branch. + // Also update the ImmBranch as well as adding a new entry for the new branch. + switch (MI->getOpcode()) { + case Xtensa::BEQ: + case Xtensa::BNE: + case Xtensa::BLT: + case Xtensa::BLTU: + case Xtensa::BGE: + case Xtensa::BGEU: + BuildMI(MBB, DebugLoc(), TII->get(Cond[0].getImm())) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addMBB(NextBB); + break; + case Xtensa::BEQI: + case Xtensa::BNEI: + case Xtensa::BLTI: + case Xtensa::BLTUI: + case Xtensa::BGEI: + case Xtensa::BGEUI: + BuildMI(MBB, DebugLoc(), TII->get(Cond[0].getImm())) + .addReg(MI->getOperand(0).getReg()) + .addImm(MI->getOperand(1).getImm()) + .addMBB(NextBB); + break; + case Xtensa::BEQZ: + case Xtensa::BNEZ: + case Xtensa::BLTZ: + case Xtensa::BGEZ: + BuildMI(MBB, DebugLoc(), TII->get(Cond[0].getImm())) + .addReg(MI->getOperand(0).getReg()) + .addMBB(NextBB); + break; + case Xtensa::BT: + case Xtensa::BF: + BuildMI(MBB, DebugLoc(), TII->get(Cond[0].getImm())) + .addReg(MI->getOperand(0).getReg()) + .addMBB(NextBB); + break; + } + + Br.MI = &MBB->back(); + BBInfo[MBB->getNumber()].Size += TII->getInstSizeInBytes(MBB->back()); + BuildMI(MBB, DebugLoc(), TII->get(Br.UncondBr)).addMBB(DestBB); + BBInfo[MBB->getNumber()].Size += TII->getInstSizeInBytes(MBB->back()); + unsigned MaxDisp = getUnconditionalBrDisp(Br.UncondBr); + ImmBranches.push_back(ImmBranch(&MBB->back(), MaxDisp, false, Br.UncondBr)); + + // Remove the old conditional branch. It may or may not still be in MBB. + BBInfo[MI->getParent()->getNumber()].Size -= TII->getInstSizeInBytes(*MI); + MI->eraseFromParent(); + adjustBBOffsetsAfter(MBB); + return true; +} + +// Check first constant island. If it is empty, then we can remove first block, +// which contains jump instruction to the third block and first constant +// insland. +void XtensaConstantIslands::removeEntryJump() { + MachineFunction *MF = InitConstantMBB->getParent(); + MachineBasicBlock *Entry = &MF->front(); + if (InitConstantMBB->empty()) { + Entry->removeSuccessor(Entry->getSingleSuccessor()); + MF->remove(Entry); + MF->remove(InitConstantMBB); + MF->RenumberBlocks(); + } +} + +/// Returns a pass that converts branches to long branches. +FunctionPass *llvm::createXtensaConstantIslandPass() { + return new XtensaConstantIslands(); +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 1d02caf1cf210..8f60abfea0e4b 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -1636,6 +1636,26 @@ let usesCustomInserter = 1, Predicates = [HasS32C1I] in { [(set AR:$dst, (atomic_load_umax_32 AR:$ptr, AR:$arg))]>; } +//===----------------------------------------------------------------------===// +// Xtensa CONSTPOOL_ENTRY +//===----------------------------------------------------------------------===// + +// An operand for the CONSTPOOL_ENTRY pseudo-instruction. +def cpinst_operand : Operand { + // let PrintMethod = "printCPInstOperand"; +} + +// CONSTPOOL_ENTRY - This instruction represents a floating constant pool in +// the function. The first operand is the ID# for this instruction, the second +// is the index into the MachineConstantPool that this is, the third is the +// size in bytes of this constant pool entry. +// +let hasSideEffects = 0, isNotDuplicable = 1 in +def CONSTPOOL_ENTRY : +Pseudo<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, + i32imm:$size), "foo", []>; + + //===----------------------------------------------------------------------===// // Xtensa ESP32S2 Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp index 9e39f1d502e6f..dd8003a429f5d 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetMachine.cpp @@ -135,6 +135,7 @@ void XtensaPassConfig::addPreEmitPass() { addPass(createXtensaSizeReductionPass()); addPass(createXtensaFixupHwLoops()); addPass(&BranchRelaxationPassID); + addPass(createXtensaConstantIslandPass()); } TargetPassConfig *XtensaTargetMachine::createPassConfig(PassManagerBase &PM) { diff --git a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp index 62ad8b6b00997..2be6c2d394f60 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp @@ -20,6 +20,12 @@ bool XtensaTTIImpl::isHardwareLoopProfitable(Loop *L, ScalarEvolution &SE, AssumptionCache &AC, TargetLibraryInfo *LibInfo, HardwareLoopInfo &HWLoopInfo) { + // Disable hw loops when literals are placed in text section. + // TODO: Implement support of hw loops in ConstantIslands pass + if (ST->useTextSectionLiterals()) { + return false; + } + if (DisableLowOverheadLoops) return false; From 2989ff7e8db51484c27c8d255c8b6125dada43d0 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 23 Feb 2023 01:31:53 +0300 Subject: [PATCH 149/150] [Xtensa] Disable hardware loops by default. Disable hwloop by default and fix hwloop tests. --- llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp | 2 +- llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll | 2 +- llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp index 2be6c2d394f60..4accacb20f2ad 100644 --- a/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaTargetTransformInfo.cpp @@ -13,7 +13,7 @@ using namespace llvm; #define DEBUG_TYPE "xtensatti" static cl::opt DisableLowOverheadLoops( - "disable-xtensa-hwloops", cl::Hidden, cl::init(false), + "disable-xtensa-hwloops", cl::Hidden, cl::init(true), cl::desc("Disable the generation of hardware loops")); bool XtensaTTIImpl::isHardwareLoopProfitable(Loop *L, ScalarEvolution &SE, diff --git a/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll b/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll index 1942d51136a21..ba188d61b5c8e 100644 --- a/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll +++ b/llvm/test/CodeGen/Xtensa/hwloop_inner_loop.ll @@ -1,4 +1,4 @@ -; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 -disable-xtensa-hwloops=false %s -o - | FileCheck %s ; Function Attrs: norecurse nounwind optsize readnone diff --git a/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll b/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll index bed2d7937468d..c8cf121eb4107 100644 --- a/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll +++ b/llvm/test/CodeGen/Xtensa/hwloop_unsuitable_loop.ll @@ -1,4 +1,4 @@ -; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 %s -o - | FileCheck %s +; RUN: llc -O1 -mtriple=xtensa -mcpu=esp32 -disable-xtensa-hwloops=false %s -o - | FileCheck %s ; Function Attrs: nounwind optsize define i32 @test_hwloop(i32 %a, i32 %b, i32 %n) local_unnamed_addr #1 { From 1e28f73ab9cb70f289f3eb25bb7875ba8694da0c Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 9 Mar 2023 10:30:04 +0300 Subject: [PATCH 150/150] [Xtensa] Improve fixup error messages in asm backend. Add different diagnotstics messages for different branch relocations fixups. --- ...-fixup-error-messages-in-asm-backend.patch | 68 +++++++++++++++++++ .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp | 14 ++-- llvm/test/MC/Xtensa/fixups-diagnostics.s | 4 +- 3 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 0001-Xtensa-Improve-fixup-error-messages-in-asm-backend.patch diff --git a/0001-Xtensa-Improve-fixup-error-messages-in-asm-backend.patch b/0001-Xtensa-Improve-fixup-error-messages-in-asm-backend.patch new file mode 100644 index 0000000000000..a7b3a23890e40 --- /dev/null +++ b/0001-Xtensa-Improve-fixup-error-messages-in-asm-backend.patch @@ -0,0 +1,68 @@ +From c8f321e8f88802dd427bc9772da171d5c889a77d Mon Sep 17 00:00:00 2001 +From: Andrei Safronov +Date: Thu, 9 Mar 2023 10:30:04 +0300 +Subject: [PATCH] [Xtensa] Improve fixup error messages in asm backend. + +--- + .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp +index 4039804b1b58..6981c82e768f 100644 +--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp ++++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp +@@ -93,7 +93,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + case Xtensa::fixup_xtensa_branch_6: { + Value -= 4; + if (!isInt<6>(Value)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "branch 6-bit fixup value out is of range"); + unsigned Hi2 = (Value >> 4) & 0x3; + unsigned Lo4 = Value & 0xf; + return (Hi2 << 4) | (Lo4 << 12); +@@ -101,36 +101,36 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + case Xtensa::fixup_xtensa_branch_8: + Value -= 4; + if (!isInt<8>(Value)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "branch 8-bit fixup value out of range"); + return (Value & 0xff); + case Xtensa::fixup_xtensa_branch_12: + Value -= 4; + if (!isInt<12>(Value)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "branch 12-bit fixup value out of range"); + return (Value & 0xfff); + case Xtensa::fixup_xtensa_jump_18: + Value -= 4; + if (!isInt<18>(Value)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "jump fixup value out of range"); + return (Value & 0x3ffff); + case Xtensa::fixup_xtensa_call_18: + Value -= 4; + if (!isInt<20>(Value)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "call fixup value out of range"); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); + return (Value & 0xffffc) >> 2; + case Xtensa::fixup_xtensa_loop_8: + Value -= 4; + if (!isUInt<8>(Value)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "loop fixup value out of range"); + return (Value & 0xff); + case Xtensa::fixup_xtensa_l32r_16: + unsigned Offset = Fixup.getOffset(); + if (Offset & 0x3) + Value -= 4; + if (!isInt<18>(Value) && (Value & 0x20000)) +- Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); ++ Ctx.reportError(Fixup.getLoc(), "l32r fixup value out of range"); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); + return (Value & 0x3fffc) >> 2; +-- +2.25.1 + diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp index 4039804b1b583..6981c82e768f5 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp @@ -93,7 +93,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, case Xtensa::fixup_xtensa_branch_6: { Value -= 4; if (!isInt<6>(Value)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "branch 6-bit fixup value out is of range"); unsigned Hi2 = (Value >> 4) & 0x3; unsigned Lo4 = Value & 0xf; return (Hi2 << 4) | (Lo4 << 12); @@ -101,36 +101,36 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, case Xtensa::fixup_xtensa_branch_8: Value -= 4; if (!isInt<8>(Value)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "branch 8-bit fixup value out of range"); return (Value & 0xff); case Xtensa::fixup_xtensa_branch_12: Value -= 4; if (!isInt<12>(Value)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "branch 12-bit fixup value out of range"); return (Value & 0xfff); case Xtensa::fixup_xtensa_jump_18: Value -= 4; if (!isInt<18>(Value)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "jump fixup value out of range"); return (Value & 0x3ffff); case Xtensa::fixup_xtensa_call_18: Value -= 4; if (!isInt<20>(Value)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "call fixup value out of range"); if (Value & 0x3) Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); return (Value & 0xffffc) >> 2; case Xtensa::fixup_xtensa_loop_8: Value -= 4; if (!isUInt<8>(Value)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "loop fixup value out of range"); return (Value & 0xff); case Xtensa::fixup_xtensa_l32r_16: unsigned Offset = Fixup.getOffset(); if (Offset & 0x3) Value -= 4; if (!isInt<18>(Value) && (Value & 0x20000)) - Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + Ctx.reportError(Fixup.getLoc(), "l32r fixup value out of range"); if (Value & 0x3) Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); return (Value & 0x3fffc) >> 2; diff --git a/llvm/test/MC/Xtensa/fixups-diagnostics.s b/llvm/test/MC/Xtensa/fixups-diagnostics.s index e0eac900552ce..d0d7b4d0f8857 100644 --- a/llvm/test/MC/Xtensa/fixups-diagnostics.s +++ b/llvm/test/MC/Xtensa/fixups-diagnostics.s @@ -2,9 +2,9 @@ .align 4 - beq a0, a1, LBL1 # CHECK: :[[@LINE]]:3: error: fixup value out of range + beq a0, a1, LBL1 # CHECK: :[[@LINE]]:3: error: branch 8-bit fixup value out of range LBL0: - beqz a0, LBL2 # CHECK: :[[@LINE]]:3: error: fixup value out of range + beqz a0, LBL2 # CHECK: :[[@LINE]]:3: error: branch 12-bit fixup value out of range call0 LBL0 # CHECK: :[[@LINE]]:3: error: fixup value must be 4-byte aligned