Skip to content

Commit 5050da7

Browse files
authored
[RISCV] Add initial assembler/MC layer support for big-endian (#146534)
This patch adds basic assembler and MC layer infrastructure for RISC-V big-endian targets (riscv32be/riscv64be): - Register big-endian targets in RISCVTargetMachine - Add big-endian data layout strings - Implement endianness-aware fixup application in assembler backend - Add byte swapping for data fixups on BE cores - Update MC layer components (AsmInfo, MCTargetDesc, Disassembler, AsmParser) This provides the foundation for BE support but does not yet include: - Codegen patterns for BE - Load/store instruction handling - BE-specific subtarget features
1 parent a2f542b commit 5050da7

File tree

15 files changed

+307
-23
lines changed

15 files changed

+307
-23
lines changed

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2340,6 +2340,9 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
23402340

23412341
getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
23422342

2343+
// RISC-V instructions are always little-endian, even on BE systems.
2344+
bool ForceLE = getContext().getTargetTriple().isRISCV();
2345+
23432346
// If we are showing fixups, create symbolic markers in the encoded
23442347
// representation. We do this by making a per-bit map to the fixup item index,
23452348
// then trying to display it as nicely as possible.
@@ -2394,7 +2397,10 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
23942397
unsigned Bit = (Code[i] >> j) & 1;
23952398

23962399
unsigned FixupBit;
2397-
if (MAI->isLittleEndian())
2400+
// RISC-V instructions are always little-endian.
2401+
// The FixupMap is indexed by actual bit positions in the LE
2402+
// instruction.
2403+
if (MAI->isLittleEndian() || ForceLE)
23982404
FixupBit = i * 8 + j;
23992405
else
24002406
FixupBit = i * 8 + (7-j);

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4065,4 +4065,6 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
40654065
LLVMInitializeRISCVAsmParser() {
40664066
RegisterMCAsmParser<RISCVAsmParser> X(getTheRISCV32Target());
40674067
RegisterMCAsmParser<RISCVAsmParser> Y(getTheRISCV64Target());
4068+
RegisterMCAsmParser<RISCVAsmParser> A(getTheRISCV32beTarget());
4069+
RegisterMCAsmParser<RISCVAsmParser> B(getTheRISCV64beTarget());
40684070
}

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ LLVMInitializeRISCVDisassembler() {
7474
createRISCVDisassembler);
7575
TargetRegistry::RegisterMCDisassembler(getTheRISCV64Target(),
7676
createRISCVDisassembler);
77+
TargetRegistry::RegisterMCDisassembler(getTheRISCV32beTarget(),
78+
createRISCVDisassembler);
79+
TargetRegistry::RegisterMCDisassembler(getTheRISCV64beTarget(),
80+
createRISCVDisassembler);
7781
}
7882

7983
static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ static cl::opt<bool>
3838
"bytes of NOPs even in norvc code"));
3939

4040
RISCVAsmBackend::RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI,
41-
bool Is64Bit, const MCTargetOptions &Options)
42-
: MCAsmBackend(llvm::endianness::little), STI(STI), OSABI(OSABI),
43-
Is64Bit(Is64Bit), TargetOptions(Options) {
41+
bool Is64Bit, bool IsLittleEndian,
42+
const MCTargetOptions &Options)
43+
: MCAsmBackend(IsLittleEndian ? llvm::endianness::little
44+
: llvm::endianness::big),
45+
STI(STI), OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options) {
4446
RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits());
4547
}
4648

@@ -374,7 +376,7 @@ bool RISCVAsmBackend::relaxDwarfLineAddr(MCFragment &F,
374376
} else {
375377
PCBytes = 2;
376378
OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc);
377-
support::endian::write<uint16_t>(OS, 0, llvm::endianness::little);
379+
support::endian::write<uint16_t>(OS, 0, Endian);
378380
}
379381
auto Offset = OS.tell() - PCBytes;
380382

@@ -428,15 +430,15 @@ bool RISCVAsmBackend::relaxDwarfCFA(MCFragment &F, bool &WasRelaxed) const {
428430
AddFixups(0, {ELF::R_RISCV_SET6, ELF::R_RISCV_SUB6});
429431
} else if (isUInt<8>(Value)) {
430432
OS << uint8_t(dwarf::DW_CFA_advance_loc1);
431-
support::endian::write<uint8_t>(OS, 0, llvm::endianness::little);
433+
support::endian::write<uint8_t>(OS, 0, Endian);
432434
AddFixups(1, {ELF::R_RISCV_SET8, ELF::R_RISCV_SUB8});
433435
} else if (isUInt<16>(Value)) {
434436
OS << uint8_t(dwarf::DW_CFA_advance_loc2);
435-
support::endian::write<uint16_t>(OS, 0, llvm::endianness::little);
437+
support::endian::write<uint16_t>(OS, 0, Endian);
436438
AddFixups(1, {ELF::R_RISCV_SET16, ELF::R_RISCV_SUB16});
437439
} else if (isUInt<32>(Value)) {
438440
OS << uint8_t(dwarf::DW_CFA_advance_loc4);
439-
support::endian::write<uint32_t>(OS, 0, llvm::endianness::little);
441+
support::endian::write<uint32_t>(OS, 0, Endian);
440442
AddFixups(1, {ELF::R_RISCV_SET32, ELF::R_RISCV_SUB32});
441443
} else {
442444
llvm_unreachable("unsupported CFA encoding");
@@ -909,6 +911,22 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup,
909911
return false;
910912
}
911913

914+
// Data fixups should be swapped for big endian cores.
915+
// Instruction fixups should not be swapped as RISC-V instructions
916+
// are always little-endian.
917+
static bool isDataFixup(unsigned Kind) {
918+
switch (Kind) {
919+
default:
920+
return false;
921+
922+
case FK_Data_1:
923+
case FK_Data_2:
924+
case FK_Data_4:
925+
case FK_Data_8:
926+
return true;
927+
}
928+
}
929+
912930
void RISCVAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
913931
const MCValue &Target, uint8_t *Data,
914932
uint64_t Value, bool IsResolved) {
@@ -932,8 +950,11 @@ void RISCVAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
932950

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

@@ -948,5 +969,6 @@ MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
948969
const MCTargetOptions &Options) {
949970
const Triple &TT = STI.getTargetTriple();
950971
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
951-
return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
972+
return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), TT.isLittleEndian(),
973+
Options);
952974
}

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class RISCVAsmBackend : public MCAsmBackend {
3535

3636
public:
3737
RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
38-
const MCTargetOptions &Options);
38+
bool IsLittleEndian, const MCTargetOptions &Options);
3939
~RISCVAsmBackend() override = default;
4040

4141
std::optional<bool> evaluateFixup(const MCFragment &, MCFixup &, MCValue &,

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ using namespace llvm;
2121
void RISCVMCAsmInfo::anchor() {}
2222

2323
RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) {
24+
IsLittleEndian = TT.isLittleEndian();
2425
CodePointerSize = CalleeSaveStackSlotSize = TT.isArch64Bit() ? 8 : 4;
2526
CommentString = "#";
2627
AlignmentIsInBytes = false;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ static MCInstrAnalysis *createRISCVInstrAnalysis(const MCInstrInfo *Info) {
376376

377377
extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
378378
LLVMInitializeRISCVTargetMC() {
379-
for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) {
379+
for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target(),
380+
&getTheRISCV32beTarget(), &getTheRISCV64beTarget()}) {
380381
TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo);
381382
TargetRegistry::RegisterMCObjectFileInfo(*T, createRISCVMCObjectFileInfo);
382383
TargetRegistry::RegisterMCInstrInfo(*T, createRISCVMCInstrInfo);

llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
611611
LLVMInitializeRISCVAsmPrinter() {
612612
RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
613613
RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
614+
RegisterAsmPrinter<RISCVAsmPrinter> A(getTheRISCV32beTarget());
615+
RegisterAsmPrinter<RISCVAsmPrinter> B(getTheRISCV64beTarget());
614616
}
615617

616618
void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ static cl::opt<bool>
106106
extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
107107
RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
108108
RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
109+
RegisterTargetMachine<RISCVTargetMachine> A(getTheRISCV32beTarget());
110+
RegisterTargetMachine<RISCVTargetMachine> B(getTheRISCV64beTarget());
109111
auto *PR = PassRegistry::getPassRegistry();
110112
initializeGlobalISel(*PR);
111113
initializeRISCVO0PreLegalizerCombinerPass(*PR);
@@ -139,21 +141,37 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
139141
initializeRISCVAsmPrinterPass(*PR);
140142
}
141143

142-
static StringRef computeDataLayout(const Triple &TT,
143-
const TargetOptions &Options) {
144-
StringRef ABIName = Options.MCOptions.getABIName();
145-
if (TT.isArch64Bit()) {
146-
if (ABIName == "lp64e")
147-
return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64";
144+
static std::string computeDataLayout(const Triple &TT,
145+
const TargetOptions &Opts) {
146+
std::string Ret;
147+
148+
if (TT.isLittleEndian())
149+
Ret += "e";
150+
else
151+
Ret += "E";
152+
153+
Ret += "-m:e";
148154

149-
return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128";
155+
// Pointer and integer sizes.
156+
if (TT.isArch64Bit()) {
157+
Ret += "-p:64:64-i64:64-i128:128";
158+
Ret += "-n32:64";
159+
} else {
160+
assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");
161+
Ret += "-p:32:32-i64:64";
162+
Ret += "-n32";
150163
}
151-
assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");
152164

153-
if (ABIName == "ilp32e")
154-
return "e-m:e-p:32:32-i64:64-n32-S32";
165+
// Stack alignment based on ABI.
166+
StringRef ABI = Opts.MCOptions.getABIName();
167+
if (ABI == "ilp32e")
168+
Ret += "-S32";
169+
else if (ABI == "lp64e")
170+
Ret += "-S64";
171+
else
172+
Ret += "-S128";
155173

156-
return "e-m:e-p:32:32-i64:64-n32-S128";
174+
return Ret;
157175
}
158176

159177
static Reloc::Model getEffectiveRelocModel(const Triple &TT,

llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,24 @@ Target &llvm::getTheRISCV64Target() {
2121
return TheRISCV64Target;
2222
}
2323

24+
Target &llvm::getTheRISCV32beTarget() {
25+
static Target TheRISCV32beTarget;
26+
return TheRISCV32beTarget;
27+
}
28+
29+
Target &llvm::getTheRISCV64beTarget() {
30+
static Target TheRISCV64beTarget;
31+
return TheRISCV64beTarget;
32+
}
33+
2434
extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
2535
LLVMInitializeRISCVTargetInfo() {
2636
RegisterTarget<Triple::riscv32, /*HasJIT=*/true> X(
2737
getTheRISCV32Target(), "riscv32", "32-bit RISC-V", "RISCV");
2838
RegisterTarget<Triple::riscv64, /*HasJIT=*/true> Y(
2939
getTheRISCV64Target(), "riscv64", "64-bit RISC-V", "RISCV");
40+
RegisterTarget<Triple::riscv32be> A(getTheRISCV32beTarget(), "riscv32be",
41+
"32-bit big endian RISC-V", "RISCV");
42+
RegisterTarget<Triple::riscv64be> B(getTheRISCV64beTarget(), "riscv64be",
43+
"64-bit big endian RISC-V", "RISCV");
3044
}

0 commit comments

Comments
 (0)