SMLoc getLoc() const { return getParser().getTok().getLoc(); }
bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); }
+ bool isRV32E() const { return getSTI().hasFeature(RISCV::FeatureRV32E); }
RISCVTargetStreamer &getTargetStreamer() {
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
// Attempts to match Name as a register (either using the default name or
// alternative ABI names), setting RegNo to the matching register. Upon
-// failure, returns true and sets RegNo to 0.
-static bool matchRegisterNameHelper(unsigned &RegNo, StringRef Name) {
+// failure, returns true and sets RegNo to 0. If IsRV32E then registers
+// x16-x31 will be rejected.
+static bool matchRegisterNameHelper(bool IsRV32E, unsigned &RegNo,
+ StringRef Name) {
RegNo = MatchRegisterName(Name);
if (RegNo == 0)
RegNo = MatchRegisterAltName(Name);
+ if (IsRV32E && RegNo >= RISCV::X16 && RegNo <= RISCV::X31)
+ RegNo = 0;
return RegNo == 0;
}
RegNo = 0;
StringRef Name = getLexer().getTok().getIdentifier();
- if (matchRegisterNameHelper(RegNo, Name))
+ if (matchRegisterNameHelper(isRV32E(), RegNo, Name))
return Error(StartLoc, "invalid register name");
getParser().Lex(); // Eat identifier token.
case AsmToken::Identifier:
StringRef Name = getLexer().getTok().getIdentifier();
unsigned RegNo;
- matchRegisterNameHelper(RegNo, Name);
+ matchRegisterNameHelper(isRV32E(), RegNo, Name);
if (RegNo == 0) {
if (HadParens)
static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
- if (RegNo > array_lengthof(GPRDecoderTable))
+ const FeatureBitset &FeatureBits =
+ static_cast<const MCDisassembler *>(Decoder)
+ ->getSubtargetInfo()
+ .getFeatureBits();
+ bool IsRV32E = FeatureBits[RISCV::FeatureRV32E];
+
+ if (RegNo > array_lengthof(GPRDecoderTable) || (IsRV32E && RegNo > 15))
return MCDisassembler::Fail;
// We must define our own mapping from RegNo to register identifier.
TargetOptions(Options) {
TargetABI = RISCVABI::computeTargetABI(
STI.getTargetTriple(), STI.getFeatureBits(), Options.getABIName());
+ RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits());
}
~RISCVAsmBackend() override {}
def RV64 : HwMode<"+64bit">;
def RV32 : HwMode<"-64bit">;
+def FeatureRV32E
+ : SubtargetFeature<"e", "IsRV32E", "true",
+ "Implements RV32E (provides 16 rather than 32 GPRs)">;
+def IsRV32E : Predicate<"Subtarget->isRV32E()">,
+ AssemblerPredicate<"FeatureRV32E">;
+
def FeatureRelax
: SubtargetFeature<"relax", "EnableLinkerRelax", "true",
"Enable Linker relaxation.">;
const RISCVSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
+ if (Subtarget.isRV32E())
+ report_fatal_error("Codegen not yet implemented for RV32E");
+
RISCVABI::ABI ABI = Subtarget.getTargetABI();
assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI");
}
TargetABI = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName);
+ RISCVFeatures::validate(TT, getFeatureBits());
return *this;
}
bool HasStdExtD = false;
bool HasStdExtC = false;
bool HasRV64 = false;
+ bool IsRV32E = false;
bool EnableLinkerRelax = false;
unsigned XLen = 32;
MVT XLenVT = MVT::i32;
bool hasStdExtD() const { return HasStdExtD; }
bool hasStdExtC() const { return HasStdExtC; }
bool is64Bit() const { return HasRV64; }
+ bool isRV32E() const { return IsRV32E; }
bool enableLinkerRelax() const { return EnableLinkerRelax; }
MVT getXLenVT() const { return XLenVT; }
unsigned getXLen() const { return XLen; }
.Case("lp64d", ABI_LP64D)
.Default(ABI_Unknown);
+ bool IsRV64 = TT.isArch64Bit();
+ bool IsRV32E = FeatureBits[RISCV::FeatureRV32E];
+
if (!ABIName.empty() && TargetABI == ABI_Unknown) {
errs()
<< "'" << ABIName
<< "' is not a recognized ABI for this target (ignoring target-abi)\n";
- } else if (ABIName.startswith("ilp32") && TT.isArch64Bit()) {
+ } else if (ABIName.startswith("ilp32") && IsRV64) {
errs() << "32-bit ABIs are not supported for 64-bit targets (ignoring "
"target-abi)\n";
TargetABI = ABI_Unknown;
- } else if (ABIName.startswith("lp64") && !TT.isArch64Bit()) {
+ } else if (ABIName.startswith("lp64") && !IsRV64) {
errs() << "64-bit ABIs are not supported for 32-bit targets (ignoring "
"target-abi)\n";
TargetABI = ABI_Unknown;
"doesn't support the D instruction set extension (ignoring "
"target-abi)\n";
TargetABI = ABI_Unknown;
+ } else if (IsRV32E && TargetABI != ABI_ILP32E && TargetABI != ABI_Unknown) {
+ errs()
+ << "Only the ilp32e ABI is supported for RV32E (ignoring target-abi)\n";
+ TargetABI = ABI_Unknown;
}
- // For now, default to the ilp32/lp64 if no explicit ABI is given or an
- // invalid/unrecognised string is given. In the future, it might be worth
- // changing this to default to ilp32f/lp64f and ilp32d/lp64d when hardware
- // support for floating point is present.
- if (TargetABI == ABI_Unknown) {
- TargetABI = TT.isArch64Bit() ? ABI_LP64 : ABI_ILP32;
- }
+ if (TargetABI != ABI_Unknown)
+ return TargetABI;
- return TargetABI;
+ // For now, default to the ilp32/ilp32e/lp64 ABI if no explicit ABI is given
+ // or an invalid/unrecognised string is given. In the future, it might be
+ // worth changing this to default to ilp32f/lp64f and ilp32d/lp64d when
+ // hardware support for floating point is present.
+ if (IsRV32E)
+ return ABI_ILP32E;
+ if (IsRV64)
+ return ABI_LP64;
+ return ABI_ILP32;
}
} // namespace RISCVABI
+
+namespace RISCVFeatures {
+
+void validate(const Triple &TT, const FeatureBitset &FeatureBits) {
+ if (TT.isArch64Bit() && FeatureBits[RISCV::FeatureRV32E])
+ report_fatal_error("RV32E can't be enabled for an RV64 target");
+}
+
+} // namespace RISCVFeatures
+
} // namespace llvm
} // namespace RISCVABI
+namespace RISCVFeatures {
+
+// Validates if the given combination of features are valid for the target
+// triple. Exits with report_fatal_error if not.
+void validate(const Triple &TT, const FeatureBitset &FeatureBits);
+
+} // namespace RISCVFeatures
+
} // namespace llvm
#endif
--- /dev/null
+; RUN: not llc -mtriple=riscv64 -mattr=+e < %s 2>&1 \
+; RUN: | FileCheck -check-prefix=RV64E %s
+
+; RV64E: LLVM ERROR: RV32E can't be enabled for an RV64 target
--- /dev/null
+; RUN: not llc -mtriple=riscv32 -mattr=+e < %s 2>&1 | FileCheck %s
+
+; CHECK: LLVM ERROR: Codegen not yet implemented for RV32E
+
+define void @nothing() nounwind {
+ ret void
+}
# RUN: llvm-mc -triple=riscv64 -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVI %s
# RUN: llvm-mc -triple=riscv32 -mattr=+c -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVIC %s
# RUN: llvm-mc -triple=riscv64 -mattr=+c -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVIC %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e -filetype=obj < %s \
+# RUN: | llvm-readobj -file-headers - \
+# RUN: | FileCheck -check-prefix=CHECK-RVE %s
# CHECK-RVI: Flags [ (0x0)
# CHECK-RVI-NEXT: ]
# CHECK-RVIC-NEXT: EF_RISCV_RVC (0x1)
# CHECK-RVIC-NEXT: ]
+# CHECK-RVE: Flags [ (0x8)
+# CHECK-RVE-NEXT: EF_RISCV_RVE (0x8)
+# CHECK-RVE-NEXT: ]
+
nop
--- /dev/null
+# RUN: not llvm-mc -triple riscv64 -mattr=+e < %s 2>&1 \
+# RUN: | FileCheck %s -check-prefix=RV64E
+
+# RV64E: LLVM ERROR: RV32E can't be enabled for an RV64 target
--- /dev/null
+# RUN: not llvm-mc -triple riscv32 -mattr=+e < %s 2>&1 | FileCheck %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 < %s \
+# RUN: | llvm-objdump -mattr=+e -riscv-no-aliases -d -r - \
+# RUN: | FileCheck -check-prefix=CHECK-DIS %s
+
+# Perform a simple sanity check that registers x16-x31 (and the equivalent
+# ABI names) are rejected for RV32E, when both assembling and disassembling.
+
+
+# CHECK-DIS: 37 18 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x16, 1
+# CHECK-DIS: b7 28 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x17, 2
+# CHECK-DIS: 37 39 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x18, 3
+# CHECK-DIS: b7 49 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x19, 4
+# CHECK-DIS: 37 5a 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x20, 5
+# CHECK-DIS: b7 6a 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x21, 6
+# CHECK-DIS: 37 7b 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x22, 7
+# CHECK-DIS: b7 8b 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x23, 8
+# CHECK-DIS: 37 9c 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x24, 9
+# CHECK-DIS: b7 ac 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x25, 10
+# CHECK-DIS: 37 bd 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x26, 11
+# CHECK-DIS: b7 cd 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x27, 12
+# CHECK-DIS: 37 de 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x28, 13
+# CHECK-DIS: b7 ee 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x29, 14
+# CHECK-DIS: 37 ff 00 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x30, 15
+# CHECK-DIS: b7 0f 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction
+lui x31, 16
+
+# CHECK-DIS: 17 18 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc a6, 17
+# CHECK-DIS: 97 28 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc a7, 18
+# CHECK-DIS: 17 39 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s2, 19
+# CHECK-DIS: 97 49 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s3, 20
+# CHECK-DIS: 17 5a 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s4, 21
+# CHECK-DIS: 97 6a 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s5, 22
+# CHECK-DIS: 17 7b 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s6, 23
+# CHECK-DIS: 97 8b 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s7, 24
+# CHECK-DIS: 17 9c 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s8, 25
+# CHECK-DIS: 97 ac 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s9, 26
+# CHECK-DIS: 17 bd 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s10, 27
+# CHECK-DIS: 97 cd 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc s11, 28
+# CHECK-DIS: 17 de 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc t3, 29
+# CHECK-DIS: 97 ee 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc t4, 30
+# CHECK-DIS: 17 ff 01 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc t5, 31
+# CHECK-DIS: 97 0f 02 00 <unknown>
+# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction
+auipc t6, 32
--- /dev/null
+# RUN: llvm-mc %s -triple=riscv32 -riscv-no-aliases -mattr=+e -show-encoding \
+# RUN: | FileCheck -check-prefix=CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+e < %s \
+# RUN: | llvm-objdump -riscv-no-aliases -d -r - \
+# RUN: | FileCheck -check-prefix=CHECK-ASM-AND-OBJ %s
+
+# This file provides a basic sanity check for RV32E, checking that the expected
+# set of registers and instructions are accepted.
+
+# CHECK-ASM-AND-OBJ: lui zero, 1
+lui x0, 1
+# CHECK-ASM-AND-OBJ: auipc ra, 2
+auipc x1, 2
+
+# CHECK-ASM-AND-OBJ: jal sp, 4
+jal x2, 4
+# CHECK-ASM-AND-OBJ: jalr gp, gp, 4
+jalr x3, x3, 4
+
+# CHECK-ASM-AND-OBJ: beq tp, t0, 8
+beq x4, x5, 8
+# CHECK-ASM-AND-OBJ: bne t1, t2, 12
+bne x6, x7, 12
+# CHECK-ASM-AND-OBJ: blt s0, s1, 16
+blt x8, x9, 16
+# CHECK-ASM-AND-OBJ: bge a0, a1, 20
+bge x10, x11, 20
+# CHECK-ASM-AND-OBJ: bgeu a2, a3, 24
+bgeu x12, x13, 24
+
+# CHECK-ASM-AND-OBJ: lb a4, 25(a5)
+lb x14, 25(x15)
+# CHECK-ASM-AND-OBJ: lh zero, 26(ra)
+lh zero, 26(ra)
+# CHECK-ASM-AND-OBJ: lw sp, 28(gp)
+lw sp, 28(gp)
+# CHECK-ASM-AND-OBJ: lbu tp, 29(t0)
+lbu tp, 29(t0)
+# CHECK-ASM-AND-OBJ: lhu t1, 30(t2)
+lhu t1, 30(t2)
+# CHECK-ASM-AND-OBJ: sb s0, 31(s1)
+sb s0, 31(s1)
+# CHECK-ASM-AND-OBJ: sh a0, 32(a1)
+sh a0, 32(a1)
+# CHECK-ASM-AND-OBJ: sw a2, 36(a3)
+sw a2, 36(a3)
+
+# CHECK-ASM-AND-OBJ: addi a4, a5, 37
+addi a4, a5, 37
+# CHECK-ASM-AND-OBJ: slti a0, a2, -20
+slti a0, a2, -20
+# CHECK-ASM-AND-OBJ: xori tp, t1, -99
+xori tp, t1, -99
+# CHECK-ASM-AND-OBJ: ori a0, a1, -2048
+ori a0, a1, -2048
+# CHECK-ASM-AND-OBJ: andi ra, sp, 2047
+andi ra, sp, 2047
+# CHECK-ASM-AND-OBJ: slli t1, t1, 31
+slli t1, t1, 31
+# CHECK-ASM-AND-OBJ: srli a0, a4, 0
+srli a0, a4, 0
+# CHECK-ASM-AND-OBJ: srai a1, sp, 15
+srai a1, sp, 15
+# CHECK-ASM-AND-OBJ: slli t0, t1, 13
+slli t0, t1, 13
+
+# CHECK-ASM-AND-OBJ: add ra, zero, zero
+add ra, zero, zero
+# CHECK-ASM-AND-OBJ: sub t0, t2, t1
+sub t0, t2, t1
+# CHECK-ASM-AND-OBJ: sll a5, a4, a3
+sll a5, a4, a3
+# CHECK-ASM-AND-OBJ: slt s0, s0, s0
+slt s0, s0, s0
+# CHECK-ASM-AND-OBJ: sltu gp, a0, a1
+sltu gp, a0, a1
+# CHECK-ASM-AND-OBJ: xor s1, s0, s1
+xor s1, s0, s1
+# CHECK-ASM-AND-OBJ: srl a0, s0, t0
+srl a0, s0, t0
+# CHECK-ASM-AND-OBJ: sra t0, a3, zero
+sra t0, a3, zero
+# CHECK-ASM-AND-OBJ: or a5, t1, ra
+or a5, t1, ra
+# CHECK-ASM-AND-OBJ: and a0, s1, a3
+and a0, s1, a3
+
+# CHECK-ASM-AND-OBJ: fence iorw, iorw
+fence iorw, iorw
+# CHECK-ASM-AND-OBJ: fence.tso
+fence.tso
+# CHECK-ASM-AND-OBJ: fence.i
+fence.i
+
+# CHECK-ASM-AND-OBJ: ecall
+ecall
+# CHECK-ASM-AND-OBJ: ebreak
+ebreak
+# CHECK-ASM-AND-OBJ: unimp
+unimp
+
+# CHECK-ASM-AND-OBJ: csrrw t0, 4095, t1
+csrrw t0, 0xfff, t1
+# CHECK-ASM-AND-OBJ: csrrs s0, cycle, zero
+csrrs s0, 0xc00, x0
+# CHECK-ASM-AND-OBJ: csrrs s0, fflags, a5
+csrrs s0, 0x001, a5
+# CHECK-ASM-AND-OBJ: csrrc sp, ustatus, ra
+csrrc sp, 0x000, ra
+# CHECK-ASM-AND-OBJ: csrrwi a5, ustatus, 0
+csrrwi a5, 0x000, 0
+# CHECK-ASM-AND-OBJ: csrrsi t2, 4095, 31
+csrrsi t2, 0xfff, 31
+# CHECK-ASM-AND-OBJ: csrrci t1, sscratch, 5
+csrrci t1, 0x140, 5
# RUN: | FileCheck -check-prefix=RV32IF-LP64F %s
# RUN: llvm-mc -triple=riscv32 -mattr=+d -target-abi lp64d < %s 2>&1 \
# RUN: | FileCheck -check-prefix=RV32IFD-LP64D %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e -target-abi lp64 < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32E-LP64 %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e,+f -target-abi lp64f < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32EF-LP64F %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e,+d -target-abi lp64f < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32EFD-LP64D %s
# RV32I-LP64: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi)
# RV32IF-LP64F: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi)
# RV32IFD-LP64D: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi)
+# RV32E-LP64: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi)
+# RV32EF-LP64F: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi)
+# RV32EFD-LP64D: 64-bit ABIs are not supported for 32-bit targets (ignoring target-abi)
# RUN: llvm-mc -triple=riscv32 -target-abi ilp32f < %s 2>&1 \
# RUN: | FileCheck -check-prefix=RV32I-ILP32F %s
# RV64I-LP64D: Hard-float 'd' ABI can't be used for a target that doesn't support the D instruction set extension (ignoring target-abi)
# RV64IF-LP64D: Hard-float 'd' ABI can't be used for a target that doesn't support the D instruction set extension (ignoring target-abi)
+# RUN: llvm-mc -triple=riscv32 -mattr=+e -target-abi ilp32 < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32EF-ILP32F %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e,+f -target-abi ilp32f < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32EF-ILP32F %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e,+d -target-abi ilp32f < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32EFD-ILP32F %s
+# RUN: llvm-mc -triple=riscv32 -mattr=+e,+d -target-abi ilp32d < %s 2>&1 \
+# RUN: | FileCheck -check-prefix=RV32EFD-ILP32D %s
+
+# RV32E-ILP32: Only the ilp32e ABI is supported for RV32E (ignoring target-abi)
+# RV32EF-ILP32F: Only the ilp32e ABI is supported for RV32E (ignoring target-abi)
+# RV32EFD-ILP32F: Only the ilp32e ABI is supported for RV32E (ignoring target-abi)
+# RV32EFD-ILP32D: Only the ilp32e ABI is supported for RV32E (ignoring target-abi)
+
nop