Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -47,6 +47,7 @@ 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(); @@ -910,11 +911,15 @@ // 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; } @@ -926,7 +931,7 @@ 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. @@ -954,7 +959,7 @@ case AsmToken::Identifier: StringRef Name = getLexer().getTok().getIdentifier(); unsigned RegNo; - matchRegisterNameHelper(RegNo, Name); + matchRegisterNameHelper(isRV32E(), RegNo, Name); if (RegNo == 0) { if (HadParens) Index: lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp =================================================================== --- lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -69,7 +69,13 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, const void *Decoder) { - if (RegNo > array_lengthof(GPRDecoderTable)) + const FeatureBitset &FeatureBits = + static_cast(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. Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -36,6 +36,7 @@ TargetOptions(Options) { TargetABI = RISCVABI::computeTargetABI( STI.getTargetTriple(), STI.getFeatureBits(), Options.getABIName()); + RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits()); } ~RISCVAsmBackend() override {} Index: lib/Target/RISCV/RISCV.td =================================================================== --- lib/Target/RISCV/RISCV.td +++ lib/Target/RISCV/RISCV.td @@ -54,6 +54,12 @@ 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.">; Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -42,6 +42,9 @@ 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"); Index: lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- lib/Target/RISCV/RISCVSubtarget.h +++ lib/Target/RISCV/RISCVSubtarget.h @@ -36,6 +36,7 @@ bool HasStdExtD = false; bool HasStdExtC = false; bool HasRV64 = false; + bool IsRV32E = false; bool EnableLinkerRelax = false; unsigned XLen = 32; MVT XLenVT = MVT::i32; @@ -80,6 +81,7 @@ 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; } Index: lib/Target/RISCV/RISCVSubtarget.cpp =================================================================== --- lib/Target/RISCV/RISCVSubtarget.cpp +++ lib/Target/RISCV/RISCVSubtarget.cpp @@ -39,6 +39,7 @@ } TargetABI = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName); + RISCVFeatures::validate(TT, getFeatureBits()); return *this; } Index: lib/Target/RISCV/Utils/RISCVBaseInfo.h =================================================================== --- lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -172,6 +172,14 @@ } // 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 Index: lib/Target/RISCV/Utils/RISCVBaseInfo.cpp =================================================================== --- lib/Target/RISCV/Utils/RISCVBaseInfo.cpp +++ lib/Target/RISCV/Utils/RISCVBaseInfo.cpp @@ -22,15 +22,18 @@ .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; @@ -44,17 +47,34 @@ "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 Index: test/CodeGen/RISCV/mattr-invalid-combination.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/mattr-invalid-combination.ll @@ -0,0 +1,4 @@ +; 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 Index: test/CodeGen/RISCV/rv32e.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/rv32e.ll @@ -0,0 +1,7 @@ +; 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 +} Index: test/MC/RISCV/elf-flags.s =================================================================== --- test/MC/RISCV/elf-flags.s +++ test/MC/RISCV/elf-flags.s @@ -2,6 +2,9 @@ # 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: ] @@ -10,4 +13,8 @@ # 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 Index: test/MC/RISCV/mattr-invalid-combination.s =================================================================== --- /dev/null +++ test/MC/RISCV/mattr-invalid-combination.s @@ -0,0 +1,4 @@ +# 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 Index: test/MC/RISCV/rv32e-invalid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv32e-invalid.s @@ -0,0 +1,106 @@ +# 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 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x16, 1 +# CHECK-DIS: b7 28 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x17, 2 +# CHECK-DIS: 37 39 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x18, 3 +# CHECK-DIS: b7 49 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x19, 4 +# CHECK-DIS: 37 5a 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x20, 5 +# CHECK-DIS: b7 6a 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x21, 6 +# CHECK-DIS: 37 7b 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x22, 7 +# CHECK-DIS: b7 8b 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x23, 8 +# CHECK-DIS: 37 9c 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x24, 9 +# CHECK-DIS: b7 ac 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x25, 10 +# CHECK-DIS: 37 bd 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x26, 11 +# CHECK-DIS: b7 cd 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x27, 12 +# CHECK-DIS: 37 de 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x28, 13 +# CHECK-DIS: b7 ee 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x29, 14 +# CHECK-DIS: 37 ff 00 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x30, 15 +# CHECK-DIS: b7 0f 01 00 +# CHECK: :[[@LINE+1]]:5: error: invalid operand for instruction +lui x31, 16 + +# CHECK-DIS: 17 18 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc a6, 17 +# CHECK-DIS: 97 28 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc a7, 18 +# CHECK-DIS: 17 39 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s2, 19 +# CHECK-DIS: 97 49 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s3, 20 +# CHECK-DIS: 17 5a 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s4, 21 +# CHECK-DIS: 97 6a 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s5, 22 +# CHECK-DIS: 17 7b 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s6, 23 +# CHECK-DIS: 97 8b 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s7, 24 +# CHECK-DIS: 17 9c 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s8, 25 +# CHECK-DIS: 97 ac 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s9, 26 +# CHECK-DIS: 17 bd 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s10, 27 +# CHECK-DIS: 97 cd 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc s11, 28 +# CHECK-DIS: 17 de 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc t3, 29 +# CHECK-DIS: 97 ee 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc t4, 30 +# CHECK-DIS: 17 ff 01 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc t5, 31 +# CHECK-DIS: 97 0f 02 00 +# CHECK: :[[@LINE+1]]:7: error: invalid operand for instruction +auipc t6, 32 Index: test/MC/RISCV/rv32e-valid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv32e-valid.s @@ -0,0 +1,115 @@ +# 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 Index: test/MC/RISCV/target-abi-invalid.s =================================================================== --- test/MC/RISCV/target-abi-invalid.s +++ test/MC/RISCV/target-abi-invalid.s @@ -26,10 +26,19 @@ # 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 @@ -53,4 +62,18 @@ # 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