diff --git a/lld/test/ELF/riscv-relax-align-rvc.s b/lld/test/ELF/riscv-relax-align-rvc.s deleted file mode 100644 index 8980e18ea876b..0000000000000 --- a/lld/test/ELF/riscv-relax-align-rvc.s +++ /dev/null @@ -1,88 +0,0 @@ -# REQUIRES: riscv - -# RUN: rm -rf %t && mkdir %t && cd %t - -# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c,+relax %s -o 32.o -# RUN: ld.lld -Ttext=0x10000 32.o -o 32 -# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 32 | FileCheck %s -## R_RISCV_ALIGN is handled regarldess of --no-relax. -# RUN: ld.lld -Ttext=0x10000 --no-relax 32.o -o 32.norelax -# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 32.norelax | FileCheck %s - -# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s -o 64.o -# RUN: ld.lld -Ttext=0x10000 64.o -o 64 -# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 64 | FileCheck %s -# RUN: ld.lld -Ttext=0x10000 --no-relax 64.o -o 64.norelax -# RUN: llvm-objdump -td --no-show-raw-insn -M no-aliases 64.norelax | FileCheck %s - -# CHECK-DAG: 00010002 l .text {{0*}}1e a -# CHECK-DAG: 00010010 l .text {{0*}}22 b -# CHECK-DAG: 00010012 l .text {{0*}}1e c -# CHECK-DAG: 00010020 l .text {{0*}}16 d -# CHECK-DAG: 00010000 g .text {{0*}}36 _start - -# CHECK: <_start>: -# CHECK-NEXT: c.addi a0, 0x1 -# CHECK-EMPTY: -# CHECK-NEXT: : -# CHECK-NEXT: c.nop -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-EMPTY: -# CHECK-NEXT: : -# CHECK-NEXT: 10010: c.addi a0, 0x2 -# CHECK-EMPTY: -# CHECK-NEXT: : -# CHECK-NEXT: c.addi a0, 0x3 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-EMPTY: -# CHECK-NEXT: : -# CHECK-NEXT: 10020: c.addi a0, 0x4 -# CHECK-NEXT: c.addi a0, 0x5 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: addi zero, zero, 0x0 -# CHECK-NEXT: 10030: c.addi a0, 0x6 -# CHECK-NEXT: c.addi a0, 0x7 -# CHECK-NEXT: c.addi a0, 0x8 -# CHECK-EMPTY: - -# CHECK: <.text2>: -# CHECK-NEXT: addi a0, a1, 0x1 -# CHECK-NEXT: c.addi a0, 0x1 -# CHECK-NEXT: c.nop -# CHECK-NEXT: c.addi a0, 0x2 - -.global _start -_start: - c.addi a0, 0x1 -a: -.balign 16 -b: - c.addi a0, 0x2 -c: - c.addi a0, 0x3 -.balign 32 -.size a, . - a -d: - c.addi a0, 0x4 - c.addi a0, 0x5 -.balign 16 -.size c, . - c - c.addi a0, 0x6 -.size b, . - b - c.addi a0, 0x7 -.balign 4 - c.addi a0, 0x8 -.size d, . - d -.size _start, . - _start - -.section .text2,"ax" -.balign 16 - addi a0, a1, 0x1 - c.addi a0, 0x1 -.balign 8 - c.addi a0, 0x2 diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index d71c42c0a5fc1..beaf02f0f50f7 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -3177,6 +3177,17 @@ bool RISCVAsmParser::parseDirectiveOption() { if (Parser.parseEOL()) return true; + auto &Streamer = getTargetStreamer().getStreamer(); + auto *Assembler = Streamer.getAssemblerPtr(); + auto *Section = Streamer.getCurrentSectionOnly(); + // Update RVCEver status only if any instruction emitted. + if (Section->hasInstructions() && Assembler != nullptr && + getSTI().hasFeature(RISCV::FeatureStdExtZca)) { + RISCVAsmBackend &MAB = + static_cast(Assembler->getBackend()); + MAB.setRVCEver(Section); + } + getTargetStreamer().emitDirectiveOptionNoRVC(); clearFeatureBits(RISCV::FeatureStdExtC, "c"); clearFeatureBits(RISCV::FeatureStdExtZca, "zca"); @@ -3214,6 +3225,17 @@ bool RISCVAsmParser::parseDirectiveOption() { if (Parser.parseEOL()) return true; + auto &Streamer = getTargetStreamer().getStreamer(); + auto *Assembler = Streamer.getAssemblerPtr(); + auto *Section = Streamer.getCurrentSectionOnly(); + // Update RelaxEver status only if any instruction emitted. + if (Assembler != nullptr && Section->hasInstructions() && + getSTI().hasFeature(RISCV::FeatureRelax)) { + RISCVAsmBackend &MAB = + static_cast(Assembler->getBackend()); + MAB.setRelaxEver(Section); + } + getTargetStreamer().emitDirectiveOptionNoRelax(); clearFeatureBits(RISCV::FeatureRelax, "relax"); return false; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 82e3b5ceb4ef6..5583a2d73a23b 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -309,9 +309,12 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) { // Use default handling unless linker relaxation is enabled and the alignment // is larger than the nop size. const MCSubtargetInfo *STI = F.getSubtargetInfo(); - if (!STI->hasFeature(RISCV::FeatureRelax)) + if (!STI->hasFeature(RISCV::FeatureRelax) && !hasRelaxEver(F.getParent())) return false; - unsigned MinNopLen = STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4; + unsigned MinNopLen = + hasRVCEver(F.getParent()) || STI->hasFeature(RISCV::FeatureStdExtZca) + ? 2 + : 4; if (F.getAlignment() <= MinNopLen) return false; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h index d97d63204e7e4..74140056cbdfe 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -12,8 +12,10 @@ #include "MCTargetDesc/RISCVBaseInfo.h" #include "MCTargetDesc/RISCVFixupKinds.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCSubtargetInfo.h" namespace llvm { @@ -33,11 +35,23 @@ class RISCVAsmBackend : public MCAsmBackend { StringMap VendorSymbols; + SmallPtrSet RelaxEverSections; + SmallPtrSet RVCEverSections; + public: RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit, const MCTargetOptions &Options); ~RISCVAsmBackend() override = default; + void setRVCEver(const MCSection *Sec) { RVCEverSections.insert(Sec); } + bool hasRVCEver(const MCSection *Sec) const { + return RVCEverSections.contains(Sec); + } + void setRelaxEver(const MCSection *Sec) { RelaxEverSections.insert(Sec); } + bool hasRelaxEver(const MCSection *Sec) const { + return RelaxEverSections.contains(Sec); + } + std::optional evaluateFixup(const MCFragment &, MCFixup &, MCValue &, uint64_t &) override; bool addReloc(const MCFragment &, const MCFixup &, const MCValue &, diff --git a/llvm/test/MC/RISCV/align-option-norelax-norvc.s b/llvm/test/MC/RISCV/align-option-norelax-norvc.s new file mode 100644 index 0000000000000..acb724d443e7f --- /dev/null +++ b/llvm/test/MC/RISCV/align-option-norelax-norvc.s @@ -0,0 +1,34 @@ +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax,+c,+m %s -o - | \ +# RUN: llvm-objdump -dr --mattr=+c,+m - | FileCheck %s + + .text + .option relax + .balign 4 + .global _start + .type _start, @function +# This R_RISCV_ALIGN for .balign 4 +# CHECK: R_RISCV_ALIGN *ABS*+0x2 +_start: + lui a0, %hi(foo) + addi a0, a0, %lo(foo) + mul a0, a1, a4 + .option push + + .option norelax + .option norvc +# This R_RISCV_ALIGN for .balign 8, we should emit that even +# norelax is set, because the code before this point might relax, +# and size may changed, so that we need to align this again at linker +# time. +# Also padding pad should be +6 rather than +4 here, because we have enabled +# RVC before, and linker may relax instructions to RVC instructions, +# That will cause 4 byte padding might not be enough to fix the alignment. +# CHECK: R_RISCV_ALIGN *ABS*+0x6 + .balign 8 +SHOULD_ALIGN_8_HERE: + .word 0x12345678 + + .option pop + +foo: + ret diff --git a/llvm/test/MC/RISCV/align-option-norelax.s b/llvm/test/MC/RISCV/align-option-norelax.s new file mode 100644 index 0000000000000..61ed47091b4d3 --- /dev/null +++ b/llvm/test/MC/RISCV/align-option-norelax.s @@ -0,0 +1,30 @@ +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax,+c,+m %s -o - | \ +# RUN: llvm-objdump -dr --mattr=+c,+m - | FileCheck %s + + .text + .option relax + .balign 4 + .global _start + .type _start, @function +# This R_RISCV_ALIGN for .balign 4 +# CHECK: R_RISCV_ALIGN *ABS*+0x2 +_start: + lui a0, %hi(foo) + addi a0, a0, %lo(foo) + mul a0, a1, a4 + .option push + + .option norelax +# This R_RISCV_ALIGN for .balign 8, we should emit that even +# norelax is set, because the code before this point might relax, +# and size may changed, so that we need to align this again at linker +# time. +# CHECK: R_RISCV_ALIGN *ABS*+0x6 + .balign 8 +SHOULD_ALIGN_8_HERE: + .word 0x12345678 + + .option pop + +foo: + ret