Skip to content

[RISCV] Add initial assembler/MC layer support for big-endian #146534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llvm/cmake/config.guess
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ EOF
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-gnu
exit ;;
riscv32:Linux:*:* | riscv64:Linux:*:*)
riscv32:Linux:*:* | riscv64:Linux:*:* | riscv32be:Linux:*:* | riscv64be:Linux:*:*)
LIBC=gnu
eval $set_cc_for_build
# Do not check for __GLIBC__ because uclibc defines it too
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx,
break;
case Triple::riscv32:
case Triple::riscv64:
case Triple::riscv32be:
case Triple::riscv64be:
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata4;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4053,4 +4053,6 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeRISCVAsmParser() {
RegisterMCAsmParser<RISCVAsmParser> X(getTheRISCV32Target());
RegisterMCAsmParser<RISCVAsmParser> Y(getTheRISCV64Target());
RegisterMCAsmParser<RISCVAsmParser> A(getTheRISCV32beTarget());
RegisterMCAsmParser<RISCVAsmParser> B(getTheRISCV64beTarget());
}
4 changes: 4 additions & 0 deletions llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ LLVMInitializeRISCVDisassembler() {
createRISCVDisassembler);
TargetRegistry::RegisterMCDisassembler(getTheRISCV64Target(),
createRISCVDisassembler);
TargetRegistry::RegisterMCDisassembler(getTheRISCV32beTarget(),
createRISCVDisassembler);
TargetRegistry::RegisterMCDisassembler(getTheRISCV64beTarget(),
createRISCVDisassembler);
}

static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
Expand Down
59 changes: 50 additions & 9 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ static cl::opt<bool> ULEB128Reloc(
cl::desc("Emit R_RISCV_SET_ULEB128/E_RISCV_SUB_ULEB128 if appropriate"));

RISCVAsmBackend::RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI,
bool Is64Bit, const MCTargetOptions &Options)
: MCAsmBackend(llvm::endianness::little), STI(STI), OSABI(OSABI),
Is64Bit(Is64Bit), TargetOptions(Options) {
bool Is64Bit, bool IsLittleEndian,
const MCTargetOptions &Options)
: MCAsmBackend(IsLittleEndian ? llvm::endianness::little
: llvm::endianness::big),
STI(STI), OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options) {
RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits());
}

Expand Down Expand Up @@ -361,7 +363,7 @@ bool RISCVAsmBackend::relaxDwarfLineAddr(MCFragment &F,
} else {
PCBytes = 2;
OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc);
support::endian::write<uint16_t>(OS, 0, llvm::endianness::little);
support::endian::write<uint16_t>(OS, 0, Endian);
}
auto Offset = OS.tell() - PCBytes;

Expand Down Expand Up @@ -415,15 +417,15 @@ bool RISCVAsmBackend::relaxDwarfCFA(MCFragment &F, bool &WasRelaxed) const {
AddFixups(0, {ELF::R_RISCV_SET6, ELF::R_RISCV_SUB6});
} else if (isUInt<8>(Value)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc1);
support::endian::write<uint8_t>(OS, 0, llvm::endianness::little);
support::endian::write<uint8_t>(OS, 0, Endian);
AddFixups(1, {ELF::R_RISCV_SET8, ELF::R_RISCV_SUB8});
} else if (isUInt<16>(Value)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc2);
support::endian::write<uint16_t>(OS, 0, llvm::endianness::little);
support::endian::write<uint16_t>(OS, 0, Endian);
AddFixups(1, {ELF::R_RISCV_SET16, ELF::R_RISCV_SUB16});
} else if (isUInt<32>(Value)) {
OS << uint8_t(dwarf::DW_CFA_advance_loc4);
support::endian::write<uint32_t>(OS, 0, llvm::endianness::little);
support::endian::write<uint32_t>(OS, 0, Endian);
AddFixups(1, {ELF::R_RISCV_SET32, ELF::R_RISCV_SUB32});
} else {
llvm_unreachable("unsupported CFA encoding");
Expand Down Expand Up @@ -869,6 +871,41 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup,
return false;
}

// Data should be swapped for big endian cores.
static bool isDataFixup(unsigned Kind) {
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 true;

case RISCV::fixup_riscv_hi20:
case RISCV::fixup_riscv_lo12_i:
case RISCV::fixup_riscv_lo12_s:
case RISCV::fixup_riscv_pcrel_hi20:
case RISCV::fixup_riscv_pcrel_lo12_i:
case RISCV::fixup_riscv_pcrel_lo12_s:
case RISCV::fixup_riscv_jal:
case RISCV::fixup_riscv_branch:
case RISCV::fixup_riscv_call:
case RISCV::fixup_riscv_call_plt:
case RISCV::fixup_riscv_rvc_jump:
case RISCV::fixup_riscv_rvc_branch:
case RISCV::fixup_riscv_12_i:
case RISCV::fixup_riscv_rvc_imm:
case RISCV::fixup_riscv_qc_e_branch:
case RISCV::fixup_riscv_qc_e_32:
case RISCV::fixup_riscv_qc_abs20_u:
case RISCV::fixup_riscv_qc_e_call_plt:
case RISCV::fixup_riscv_nds_branch_10:
return false;
}
}

void RISCVAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
const MCValue &Target, uint8_t *Data,
uint64_t Value, bool IsResolved) {
Expand All @@ -892,8 +929,11 @@ void RISCVAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,

// For each byte of the fragment that the fixup touches, mask in the
// bits from the fixup value.
// For big endian cores, data fixup should be swapped.
bool SwapValue = Endian == llvm::endianness::big && isDataFixup(Kind);
for (unsigned i = 0; i != NumBytes; ++i) {
Data[i] |= uint8_t((Value >> (i * 8)) & 0xff);
unsigned Idx = SwapValue ? (NumBytes - 1 - i) : i;
Data[Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
}
}

Expand All @@ -908,5 +948,6 @@ MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
const MCTargetOptions &Options) {
const Triple &TT = STI.getTargetTriple();
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), TT.isLittleEndian(),
Options);
}
2 changes: 1 addition & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class RISCVAsmBackend : public MCAsmBackend {

public:
RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
const MCTargetOptions &Options);
bool IsLittleEndian, const MCTargetOptions &Options);
~RISCVAsmBackend() override = default;

std::optional<bool> evaluateFixup(const MCFragment &, MCFixup &, MCValue &,
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ using namespace llvm;
void RISCVMCAsmInfo::anchor() {}

RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) {
IsLittleEndian = TT.isLittleEndian();
CodePointerSize = CalleeSaveStackSlotSize = TT.isArch64Bit() ? 8 : 4;
CommentString = "#";
AlignmentIsInBytes = false;
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ static MCInstrAnalysis *createRISCVInstrAnalysis(const MCInstrInfo *Info) {

extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeRISCVTargetMC() {
for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) {
for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target(),
&getTheRISCV32beTarget(), &getTheRISCV64beTarget()}) {
TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo);
TargetRegistry::RegisterMCObjectFileInfo(*T, createRISCVMCObjectFileInfo);
TargetRegistry::RegisterMCInstrInfo(*T, createRISCVMCInstrInfo);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,8 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeRISCVAsmPrinter() {
RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
RegisterAsmPrinter<RISCVAsmPrinter> A(getTheRISCV32beTarget());
RegisterAsmPrinter<RISCVAsmPrinter> B(getTheRISCV64beTarget());
}

void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
Expand Down
36 changes: 25 additions & 11 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ static cl::opt<bool>
extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
RegisterTargetMachine<RISCVTargetMachine> A(getTheRISCV32beTarget());
RegisterTargetMachine<RISCVTargetMachine> B(getTheRISCV64beTarget());
auto *PR = PassRegistry::getPassRegistry();
initializeGlobalISel(*PR);
initializeRISCVO0PreLegalizerCombinerPass(*PR);
Expand Down Expand Up @@ -150,21 +152,33 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
initializeRISCVAsmPrinterPass(*PR);
}

static StringRef computeDataLayout(const Triple &TT,
const TargetOptions &Options) {
StringRef ABIName = Options.MCOptions.getABIName();
if (TT.isArch64Bit()) {
if (ABIName == "lp64e")
return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64";
static std::string computeDataLayout(const Triple &TT,
const TargetOptions &Opts) {
std::string Endianness = TT.isLittleEndian() ? "e" : "E";

std::string PointerAndIntegerLayout;
std::string NativeIntegerWidths;

return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
if (TT.isArch64Bit()) {
PointerAndIntegerLayout = "p:64:64-i64:64-i128:128";
NativeIntegerWidths = "n32:64";
} else {
assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");
PointerAndIntegerLayout = "p:32:32-i64:64";
NativeIntegerWidths = "n32";
}
assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");

if (ABIName == "ilp32e")
return "e-m:e-p:32:32-i64:64-n32-S32";
StringRef ABI = Opts.MCOptions.getABIName();
std::string StackAlignment;

if (TT.isArch64Bit()) {
StackAlignment = (ABI == "lp64e") ? "S64" : "S128";
} else {
StackAlignment = (ABI == "ilp32e") ? "S32" : "S128";
}

return "e-m:e-p:32:32-i64:64-n32-S128";
return Endianness + "-m:e-" + PointerAndIntegerLayout + "-" +
NativeIntegerWidths + "-" + StackAlignment;
}

static Reloc::Model getEffectiveRelocModel(const Triple &TT,
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,24 @@ Target &llvm::getTheRISCV64Target() {
return TheRISCV64Target;
}

Target &llvm::getTheRISCV32beTarget() {
static Target TheRISCV32beTarget;
return TheRISCV32beTarget;
}

Target &llvm::getTheRISCV64beTarget() {
static Target TheRISCV64beTarget;
return TheRISCV64beTarget;
}

extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeRISCVTargetInfo() {
RegisterTarget<Triple::riscv32, /*HasJIT=*/true> X(
getTheRISCV32Target(), "riscv32", "32-bit RISC-V", "RISCV");
RegisterTarget<Triple::riscv64, /*HasJIT=*/true> Y(
getTheRISCV64Target(), "riscv64", "64-bit RISC-V", "RISCV");
RegisterTarget<Triple::riscv32be> A(getTheRISCV32beTarget(), "riscv32be",
"32-bit big endian RISC-V", "RISCV");
RegisterTarget<Triple::riscv64be> B(getTheRISCV64beTarget(), "riscv64be",
"64-bit big endian RISC-V", "RISCV");
}
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class Target;

Target &getTheRISCV32Target();
Target &getTheRISCV64Target();
Target &getTheRISCV32beTarget();
Target &getTheRISCV64beTarget();

} // namespace llvm

Expand Down
29 changes: 29 additions & 0 deletions llvm/test/MC/Disassembler/RISCV/bigendian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# RUN: llvm-mc --disassemble %s -triple=riscv32be -mattr=+c 2>&1 | FileCheck %s
# RUN: llvm-mc --disassemble %s -triple=riscv64be -mattr=+c 2>&1 | FileCheck %s

# Test basic disassembly for big-endian RISC-V
# Instructions are always little-endian encoded in RISC-V

[0x13,0x05,0x45,0x06]
# CHECK: addi a0, a0, 100

[0xb7,0x52,0x34,0x12]
# CHECK: lui t0, 74565

[0x03,0x26,0x05,0x00]
# CHECK: lw a2, 0(a0)

[0x23,0x22,0xc5,0x00]
# CHECK: sw a2, 4(a0)

[0xef,0x00,0x00,0x00]
# CHECK: jal 0

[0x63,0x00,0xb5,0x00]
# CHECK: beq a0, a1, 0

[0x01,0x00]
# CHECK: nop

[0x05,0x05]
# CHECK: addi a0, a0, 1
36 changes: 36 additions & 0 deletions llvm/test/MC/RISCV/bigendian-data-directives.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# RUN: llvm-mc -filetype=obj -triple=riscv32be %s -o %t.32be.o
# RUN: llvm-objdump -s %t.32be.o | FileCheck -check-prefix=RV32BE %s
# RUN: llvm-mc -filetype=obj -triple=riscv64be %s -o %t.64be.o
# RUN: llvm-objdump -s %t.64be.o | FileCheck -check-prefix=RV64BE %s
# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32le.o
# RUN: llvm-objdump -s %t.32le.o | FileCheck -check-prefix=RV32LE %s
# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64le.o
# RUN: llvm-objdump -s %t.64le.o | FileCheck -check-prefix=RV64LE %s

# Test that data directives are properly byte-swapped on big-endian RISC-V

.data

byte_data:
.byte 0x11
.byte 0x22
.half 0x3344
.word 0x55667788
.long 0x99aabbcc
.quad 0x1122334455667788

# RV32BE: Contents of section .data:
# RV32BE-NEXT: 0000 11223344 55667788 99aabbcc 11223344
# RV32BE-NEXT: 0010 55667788

# RV64BE: Contents of section .data:
# RV64BE-NEXT: 0000 11223344 55667788 99aabbcc 11223344
# RV64BE-NEXT: 0010 55667788

# RV32LE: Contents of section .data:
# RV32LE-NEXT: 0000 11224433 88776655 ccbbaa99 88776655
# RV32LE-NEXT: 0010 44332211

# RV64LE: Contents of section .data:
# RV64LE-NEXT: 0000 11224433 88776655 ccbbaa99 88776655
# RV64LE-NEXT: 0010 44332211
60 changes: 60 additions & 0 deletions llvm/test/MC/RISCV/bigendian-fixups.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# RUN: llvm-mc -filetype=obj -triple=riscv32be < %s \
# RUN: | llvm-objdump --no-print-imm-hex -M no-aliases -d - \
# RUN: | FileCheck -check-prefix=CHECK-INSTR %s
# RUN: llvm-mc -filetype=obj -triple=riscv32be %s \
# RUN: | llvm-readobj -r - | FileCheck %s -check-prefix=CHECK-REL
# RUN: llvm-mc -filetype=obj -triple=riscv64be < %s \
# RUN: | llvm-objdump --no-print-imm-hex -M no-aliases -d - \
# RUN: | FileCheck -check-prefix=CHECK-INSTR %s
# RUN: llvm-mc -filetype=obj -triple=riscv64be %s \
# RUN: | llvm-readobj -r - | FileCheck %s -check-prefix=CHECK-REL

# Test that fixups work correctly on big-endian RISC-V targets

.LBB0:
lui t1, %hi(val)
# CHECK-INSTR: lui t1, 74565

lw a0, %lo(val)(t1)
# CHECK-INSTR: lw a0, 1656(t1)
addi a1, t1, %lo(val)
# CHECK-INSTR: addi a1, t1, 1656
sw a0, %lo(val)(t1)
# CHECK-INSTR: sw a0, 1656(t1)

1:
auipc t1, %pcrel_hi(.LBB0)
# CHECK-INSTR: auipc t1, 0
addi t1, t1, %pcrel_lo(1b)
# CHECK-INSTR: addi t1, t1, -16
sw t1, %pcrel_lo(1b)(t1)
# CHECK-INSTR: sw t1, -16(t1)

jal zero, .LBB0
# CHECK-INSTR: jal zero, 0x0
jal zero, .LBB2
# CHECK-INSTR: jal zero, 0x50d14
beq a0, a1, .LBB0
# CHECK-INSTR: beq a0, a1, 0x0
blt a0, a1, .LBB1
# CHECK-INSTR: blt a0, a1, 0x47c

.fill 1104

.LBB1:

.fill 329876
addi zero, zero, 0
.LBB2:

.set val, 0x12345678

# CHECK-REL-NOT: R_RISCV

# Test data fixups
.data
.align 3
data_label:
.word val
.long val
.quad val
Loading