diff --git a/clang/test/Driver/riscv-arch.c b/clang/test/Driver/riscv-arch.c --- a/clang/test/Driver/riscv-arch.c +++ b/clang/test/Driver/riscv-arch.c @@ -426,6 +426,15 @@ // RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZFH %s // RV32-EXPERIMENTAL-ZFH: "-target-feature" "+experimental-zfh" +// RUN: %clang -target riscv32-unknown-elf -march=rv32izfhmin -### %s \ +// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZFHMIN-NOFLAG %s +// RV32-EXPERIMENTAL-ZFHMIN-NOFLAG: error: invalid arch name 'rv32izfhmin' +// RV32-EXPERIMENTAL-ZFHMIN-NOFLAG: requires '-menable-experimental-extensions' + +// RUN: %clang -target riscv32-unknown-elf -march=rv32izfhmin0p1 -menable-experimental-extensions -### %s \ +// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZFHMIN %s +// RV32-EXPERIMENTAL-ZFHMIN: "-target-feature" "+experimental-zfhmin" + // RUN: %clang -target riscv32-unknown-elf -march=rv32izvamo -### %s -c 2>&1 | \ // RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVAMO-NOFLAG %s // RV32-EXPERIMENTAL-ZVAMO-NOFLAG: error: invalid arch name 'rv32izvamo' diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -65,6 +65,7 @@ {"zvlsseg", RISCVExtensionVersion{0, 10}}, {"zfh", RISCVExtensionVersion{0, 1}}, + {"zfhmin", RISCVExtensionVersion{0, 1}}, }; static bool stripExperimentalPrefix(StringRef &Ext) { diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -41,10 +41,18 @@ AssemblerPredicate<(all_of FeatureStdExtD), "'D' (Double-Precision Floating-Point)">; +def FeatureStdExtZfhmin + : SubtargetFeature<"experimental-zfhmin", "HasStdExtZfhmin", "true", + "'Zfhmin' (Half-Precision Floating-Point Minimal)", + [FeatureStdExtF]>; +def HasStdExtZfhmin : Predicate<"Subtarget->hasStdExtZfhmin()">, + AssemblerPredicate<(all_of FeatureStdExtZfhmin), + "'Zfhmin' (Half-Precision Floating-Point Minimal)">; + def FeatureStdExtZfh : SubtargetFeature<"experimental-zfh", "HasStdExtZfh", "true", "'Zfh' (Half-Precision Floating-Point)", - [FeatureStdExtF]>; + [FeatureStdExtZfhmin, FeatureStdExtF]>; def HasStdExtZfh : Predicate<"Subtarget->hasStdExtZfh()">, AssemblerPredicate<(all_of FeatureStdExtZfh), "'Zfh' (Half-Precision Floating-Point)">; diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -85,7 +85,7 @@ // Set up the register classes. addRegisterClass(XLenVT, &RISCV::GPRRegClass); - if (Subtarget.hasStdExtZfh()) + if (Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh()) addRegisterClass(MVT::f16, &RISCV::FPR16RegClass); if (Subtarget.hasStdExtF()) addRegisterClass(MVT::f32, &RISCV::FPR32RegClass); @@ -131,7 +131,7 @@ for (MVT VT : IntVecVTs) addRegClassForRVV(VT); - if (Subtarget.hasStdExtZfh()) + if (Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh()) for (MVT VT : F16VecVTs) addRegClassForRVV(VT); @@ -316,7 +316,7 @@ ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FP16_TO_FP, ISD::FP_TO_FP16}; - if (Subtarget.hasStdExtZfh()) + if (Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh()) setOperationAction(ISD::BITCAST, MVT::i16, Custom); if (Subtarget.hasStdExtZfh()) { @@ -1154,7 +1154,8 @@ bool RISCVTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const { - if (VT == MVT::f16 && !Subtarget.hasStdExtZfh()) + if (VT == MVT::f16 && !Subtarget.hasStdExtZfhmin() && + !Subtarget.hasStdExtZfh()) return false; if (VT == MVT::f32 && !Subtarget.hasStdExtF()) return false; @@ -1166,7 +1167,8 @@ } bool RISCVTargetLowering::hasBitPreservingFPLogic(EVT VT) const { - return (VT == MVT::f16 && Subtarget.hasStdExtZfh()) || + return (VT == MVT::f16 && + (Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh())) || (VT == MVT::f32 && Subtarget.hasStdExtF()) || (VT == MVT::f64 && Subtarget.hasStdExtD()); } @@ -1174,9 +1176,10 @@ MVT RISCVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const { - // Use f32 to pass f16 if it is legal and Zfh is not enabled. We might still - // end up using a GPR but that will be decided based on ABI. - if (VT == MVT::f16 && Subtarget.hasStdExtF() && !Subtarget.hasStdExtZfh()) + // Use f32 to pass f16 if it is legal and Zfhmin/Zfh is not enabled. + // We might still end up using a GPR but that will be decided based on ABI. + if (VT == MVT::f16 && Subtarget.hasStdExtF() && + !Subtarget.hasStdExtZfhmin() && !Subtarget.hasStdExtZfh()) return MVT::f32; return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT); @@ -1185,9 +1188,10 @@ unsigned RISCVTargetLowering::getNumRegistersForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const { - // Use f32 to pass f16 if it is legal and Zfh is not enabled. We might still - // end up using a GPR but that will be decided based on ABI. - if (VT == MVT::f16 && Subtarget.hasStdExtF() && !Subtarget.hasStdExtZfh()) + // Use f32 to pass f16 if it is legal and Zfhmin/Zfh is not enabled. + // We might still end up using a GPR but that will be decided based on ABI. + if (VT == MVT::f16 && Subtarget.hasStdExtF() && + !Subtarget.hasStdExtZfhmin() && !Subtarget.hasStdExtZfh()) return 1; return TargetLowering::getNumRegistersForCallingConv(Context, CC, VT); @@ -1351,7 +1355,7 @@ return true; if (ScalarTy->isHalfTy()) - return Subtarget.hasStdExtZfh(); + return Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh(); if (ScalarTy->isFloatTy()) return Subtarget.hasStdExtF(); if (ScalarTy->isDoubleTy()) @@ -1394,7 +1398,7 @@ case MVT::i64: break; case MVT::f16: - if (!Subtarget.hasStdExtZfh()) + if (!Subtarget.hasStdExtZfh() && !Subtarget.hasStdExtZfh()) return false; break; case MVT::f32: @@ -2404,7 +2408,8 @@ return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, BVec, DAG.getConstant(0, DL, XLenVT)); } - if (VT == MVT::f16 && Op0VT == MVT::i16 && Subtarget.hasStdExtZfh()) { + if (VT == MVT::f16 && Op0VT == MVT::i16 && + (Subtarget.hasStdExtZfh() || Subtarget.hasStdExtZfh())) { SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, XLenVT, Op0); SDValue FPConv = DAG.getNode(RISCVISD::FMV_H_X, DL, MVT::f16, NewOp0); return FPConv; @@ -5672,7 +5677,8 @@ SDValue Op0 = N->getOperand(0); EVT Op0VT = Op0.getValueType(); MVT XLenVT = Subtarget.getXLenVT(); - if (VT == MVT::i16 && Op0VT == MVT::f16 && Subtarget.hasStdExtZfh()) { + if (VT == MVT::i16 && Op0VT == MVT::f16 && + (Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh())) { SDValue FPConv = DAG.getNode(RISCVISD::FMV_X_ANYEXTH, DL, XLenVT, Op0); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FPConv)); } else if (VT == MVT::i32 && Op0VT == MVT::f32 && Subtarget.is64Bit() && @@ -9290,7 +9296,8 @@ case 'r': return std::make_pair(0U, &RISCV::GPRRegClass); case 'f': - if (Subtarget.hasStdExtZfh() && VT == MVT::f16) + if ((Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh()) && + VT == MVT::f16) return std::make_pair(0U, &RISCV::FPR16RegClass); if (Subtarget.hasStdExtF() && VT == MVT::f32) return std::make_pair(0U, &RISCV::FPR32RegClass); @@ -9692,7 +9699,7 @@ switch (VT.getSimpleVT().SimpleTy) { case MVT::f16: - return Subtarget.hasStdExtZfh(); + return Subtarget.hasStdExtZfhmin() || Subtarget.hasStdExtZfh(); case MVT::f32: return Subtarget.hasStdExtF(); case MVT::f64: diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td @@ -66,7 +66,7 @@ // Instructions //===----------------------------------------------------------------------===// -let Predicates = [HasStdExtZfh] in { +let Predicates = [HasStdExtZfhmin] in { let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in def FLH : RVInstI<0b001, OPC_LOAD_FP, (outs FPR16:$rd), (ins GPR:$rs1, simm12:$imm12), @@ -81,7 +81,9 @@ (ins FPR16:$rs2, GPR:$rs1, simm12:$imm12), "fsh", "$rs2, ${imm12}(${rs1})">, Sched<[WriteFST16, ReadStoreData, ReadFMemBase]>; +} // Predicates = [HasStdExtZfhmin] +let Predicates = [HasStdExtZfh] in { def FMADD_H : FPFMAH_rrr_frm, Sched<[WriteFMA16, ReadFMA16, ReadFMA16, ReadFMA16]>; def : FPFMAHDynFrmAlias; @@ -148,7 +150,9 @@ let rs2 = 0b00001; } def : FPUnaryOpDynFrmAlias; +} // Predicates = [HasStdExtZfh] +let Predicates = [HasStdExtZfhmin] in { def FCVT_H_S : FPUnaryOp_r_frm<0b0100010, FPR16, FPR32, "fcvt.h.s">, Sched<[WriteFCvtF32ToF16, ReadFCvtF32ToF16]> { let rs2 = 0b00000; @@ -169,7 +173,9 @@ Sched<[WriteFMovI16ToF16, ReadFMovI16ToF16]> { let rs2 = 0b00000; } +} // Predicates = [HasStdExtZfhmin] +let Predicates = [HasStdExtZfh] in { def FEQ_H : FPCmpH_rr<0b010, "feq.h">; def FLT_H : FPCmpH_rr<0b001, "flt.h">; def FLE_H : FPCmpH_rr<0b000, "fle.h">; @@ -178,7 +184,7 @@ Sched<[WriteFClass16, ReadFClass16]> { let rs2 = 0b00000; } -} // Predicates = [HasStdExtZfh] +} let Predicates = [HasStdExtZfh, IsRV64] in { def FCVT_L_H : FPUnaryOp_r_frm<0b1100010, GPR, FPR16, "fcvt.l.h">, @@ -206,7 +212,7 @@ def : FPUnaryOpDynFrmAlias; } // Predicates = [HasStdExtZfh, IsRV64] -let Predicates = [HasStdExtZfh, HasStdExtD] in { +let Predicates = [HasStdExtZfhmin, HasStdExtD] in { def FCVT_H_D : FPUnaryOp_r_frm<0b0100010, FPR16, FPR64, "fcvt.h.d">, Sched<[WriteFCvtF64ToF16, ReadFCvtF64ToF16]> { let rs2 = 0b00001; @@ -223,10 +229,12 @@ // Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) //===----------------------------------------------------------------------===// -let Predicates = [HasStdExtZfh] in { +let Predicates = [HasStdExtZfhmin] in { def : InstAlias<"flh $rd, (${rs1})", (FLH FPR16:$rd, GPR:$rs1, 0), 0>; def : InstAlias<"fsh $rs2, (${rs1})", (FSH FPR16:$rs2, GPR:$rs1, 0), 0>; +} // Predicates = [HasStdExtZfhmin] +let Predicates = [HasStdExtZfh] in { def : InstAlias<"fmv.h $rd, $rs", (FSGNJ_H FPR16:$rd, FPR16:$rs, FPR16:$rs)>; def : InstAlias<"fabs.h $rd, $rs", (FSGNJX_H FPR16:$rd, FPR16:$rs, FPR16:$rs)>; def : InstAlias<"fneg.h $rd, $rs", (FSGNJN_H FPR16:$rd, FPR16:$rs, FPR16:$rs)>; @@ -237,7 +245,9 @@ (FLT_H GPR:$rd, FPR16:$rt, FPR16:$rs), 0>; def : InstAlias<"fge.h $rd, $rs, $rt", (FLE_H GPR:$rd, FPR16:$rt, FPR16:$rs), 0>; +} // Predicates = [HasStdExtZfh] +let Predicates = [HasStdExtZfhmin] in { def PseudoFLH : PseudoFloatLoad<"flh", FPR16>; def PseudoFSH : PseudoStore<"fsh", FPR16>; } // Predicates = [HasStdExtZfh] @@ -313,7 +323,9 @@ def : PatFpr16Fpr16; def Select_FPR16_Using_CC_GPR : SelectCC_rrirr; +} // Predicates = [HasStdExtZfh] +let Predicates = [HasStdExtZfhmin] in { /// Loads defm : LdPat; @@ -331,7 +343,7 @@ // Moves (no conversion) def : Pat<(riscv_fmv_h_x GPR:$src), (FMV_H_X GPR:$src)>; def : Pat<(riscv_fmv_x_anyexth FPR16:$src), (FMV_X_H FPR16:$src)>; -} // Predicates = [HasStdExtZfh] +} // Predicates = [HasStdExtZfhmin] let Predicates = [HasStdExtZfh, IsRV32] in { // half->[u]int. Round-to-zero must be used. @@ -383,7 +395,7 @@ def : Pat<(uint_to_fp (i64 GPR:$rs1)), (FCVT_H_LU $rs1, 0b111)>; } // Predicates = [HasStdExtZfh, IsRV64] -let Predicates = [HasStdExtZfh, HasStdExtD] in { +let Predicates = [HasStdExtZfhmin, HasStdExtD] in { /// Float conversion operations // f64 -> f16, f16 -> f64 def : Pat<(fpround FPR64:$rs1), (FCVT_H_D FPR64:$rs1, 0b111)>; diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -53,6 +53,7 @@ bool HasStdExtZvlsseg = false; bool HasStdExtZvamo = false; bool HasStdExtZfh = false; + bool HasStdExtZfhmin = false; bool HasRV64 = false; bool IsRV32E = false; bool EnableLinkerRelax = false; @@ -119,6 +120,7 @@ bool hasStdExtZvlsseg() const { return HasStdExtZvlsseg; } bool hasStdExtZvamo() const { return HasStdExtZvamo; } bool hasStdExtZfh() const { return HasStdExtZfh; } + bool hasStdExtZfhmin() const { return HasStdExtZfhmin; } bool is64Bit() const { return HasRV64; } bool isRV32E() const { return IsRV32E; } bool enableLinkerRelax() const { return EnableLinkerRelax; } diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll --- a/llvm/test/CodeGen/RISCV/attributes.ll +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -6,6 +6,7 @@ ; RUN: llc -mtriple=riscv32 -mattr=+d %s -o - | FileCheck --check-prefix=RV32D %s ; RUN: llc -mtriple=riscv32 -mattr=+c %s -o - | FileCheck --check-prefix=RV32C %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-v,+experimental-zvamo,+experimental-zvlsseg %s -o - | FileCheck --check-prefix=RV32V %s +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zfhmin %s -o - | FileCheck --check-prefix=RV32ZFHMIN %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zfh %s -o - | FileCheck --check-prefix=RV32ZFH %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zba %s -o - | FileCheck --check-prefix=RV32ZBA %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbb %s -o - | FileCheck --check-prefix=RV32ZBB %s @@ -24,6 +25,7 @@ ; RUN: llc -mtriple=riscv64 -mattr=+d %s -o - | FileCheck --check-prefix=RV64D %s ; RUN: llc -mtriple=riscv64 -mattr=+c %s -o - | FileCheck --check-prefix=RV64C %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-v,+experimental-zvamo,+experimental-zvlsseg %s -o - | FileCheck --check-prefix=RV64V %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zfhmin %s -o - | FileCheck --check-prefix=RV64ZFHMIN %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zfh %s -o - | FileCheck --check-prefix=RV64ZFH %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zba %s -o - | FileCheck --check-prefix=RV64ZBA %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbb %s -o - | FileCheck --check-prefix=RV64ZBB %s @@ -43,7 +45,8 @@ ; RV32D: .attribute 5, "rv32i2p0_f2p0_d2p0" ; RV32C: .attribute 5, "rv32i2p0_c2p0" ; RV32V: .attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10" -; RV32ZFH: .attribute 5, "rv32i2p0_f2p0_zfh0p1" +; RV32ZFHMIN: .attribute 5, "rv32i2p0_f2p0_zfhmin0p1" +; RV32ZFH: .attribute 5, "rv32i2p0_f2p0_zfh0p1_zfhmin0p1" ; RV32ZBA: .attribute 5, "rv32i2p0_zba1p0" ; RV32ZBB: .attribute 5, "rv32i2p0_zbb1p0" ; RV32ZBC: .attribute 5, "rv32i2p0_zbc1p0" @@ -54,14 +57,15 @@ ; RV32ZBR: .attribute 5, "rv32i2p0_zbr0p93" ; RV32ZBS: .attribute 5, "rv32i2p0_zbs1p0" ; RV32ZBT: .attribute 5, "rv32i2p0_zbt0p93" -; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvlsseg0p10" +; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_zfhmin0p1_zbb1p0_zvamo0p10_zvlsseg0p10" ; RV64M: .attribute 5, "rv64i2p0_m2p0" ; RV64A: .attribute 5, "rv64i2p0_a2p0" ; RV64F: .attribute 5, "rv64i2p0_f2p0" ; RV64D: .attribute 5, "rv64i2p0_f2p0_d2p0" ; RV64C: .attribute 5, "rv64i2p0_c2p0" -; RV64ZFH: .attribute 5, "rv64i2p0_f2p0_zfh0p1" +; RV64ZFHMIN: .attribute 5, "rv64i2p0_f2p0_zfhmin0p1" +; RV64ZFH: .attribute 5, "rv64i2p0_f2p0_zfh0p1_zfhmin0p1" ; RV64ZBA: .attribute 5, "rv64i2p0_zba1p0" ; RV64ZBB: .attribute 5, "rv64i2p0_zbb1p0" ; RV64ZBC: .attribute 5, "rv64i2p0_zbc1p0" @@ -73,7 +77,7 @@ ; RV64ZBS: .attribute 5, "rv64i2p0_zbs1p0" ; RV64ZBT: .attribute 5, "rv64i2p0_zbt0p93" ; RV64V: .attribute 5, "rv64i2p0_v0p10_zvamo0p10_zvlsseg0p10" -; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvlsseg0p10" +; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zfhmin0p1_zbb1p0_zvamo0p10_zvlsseg0p10" define i32 @addi(i32 %a) { diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s --- a/llvm/test/MC/RISCV/attribute-arch.s +++ b/llvm/test/MC/RISCV/attribute-arch.s @@ -66,8 +66,11 @@ .attribute arch, "rv32izbt" # CHECK: attribute 5, "rv32i2p0_zbt0p93" +.attribute arch, "rv32ifzfhmin" +# CHECK: attribute 5, "rv32i2p0_f2p0_zfhmin0p1" + .attribute arch, "rv32ifzfh" -# CHECK: attribute 5, "rv32i2p0_f2p0_zfh0p1" +# CHECK: attribute 5, "rv32i2p0_f2p0_zfh0p1_zfhmin0p1" .attribute arch, "rv32ivzvamo_zvlsseg" # CHECK: attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10" diff --git a/llvm/test/MC/RISCV/rv32zfhmin-invalid.s b/llvm/test/MC/RISCV/rv32zfhmin-invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32zfhmin-invalid.s @@ -0,0 +1,23 @@ +# RUN: not llvm-mc -triple riscv32 -mattr=+experimental-zfhmin < %s 2>&1 | \ +# RUN: FileCheck %s + +# Out of range immediates +## simm12 +flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047] +fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047] + +# Memory operand not formatted correctly +flh ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction + +# Invalid register names +flh ft15, 100(a0) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction +flh ft1, 100(a10) # CHECK: :[[@LINE]]:14: error: expected register + +# Integer registers where FP regs are expected +fmv.x.h fs7, a2 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction + +# FP registers where integer regs are expected +fmv.h.x a8, ft2 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction + +# Zfh instructions +fmadd.h f10, f11, f12, f13, dyn # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) diff --git a/llvm/test/MC/RISCV/rv32zfhmin-valid.s b/llvm/test/MC/RISCV/rv32zfhmin-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32zfhmin-valid.s @@ -0,0 +1,62 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zfhmin,+d -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zfhmin,+d -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zfhmin,+d < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zfhmin,+d -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-zfhmin,+d < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zfhmin,+d -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: flh ft0, 12(a0) +# CHECK-ASM: encoding: [0x07,0x10,0xc5,0x00] +flh f0, 12(a0) +# CHECK-ASM-AND-OBJ: flh ft1, 4(ra) +# CHECK-ASM: encoding: [0x87,0x90,0x40,0x00] +flh f1, +4(ra) +# CHECK-ASM-AND-OBJ: flh ft2, -2048(a3) +# CHECK-ASM: encoding: [0x07,0x91,0x06,0x80] +flh f2, -2048(x13) +# CHECK-ASM-AND-OBJ: flh ft3, -2048(s1) +# CHECK-ASM: encoding: [0x87,0x91,0x04,0x80] +flh f3, %lo(2048)(s1) +# CHECK-ASM-AND-OBJ: flh ft4, 2047(s2) +# CHECK-ASM: encoding: [0x07,0x12,0xf9,0x7f] +flh f4, 2047(s2) +# CHECK-ASM-AND-OBJ: flh ft5, 0(s3) +# CHECK-ASM: encoding: [0x87,0x92,0x09,0x00] +flh f5, 0(s3) + +# CHECK-ASM-AND-OBJ: fsh ft6, 2047(s4) +# CHECK-ASM: encoding: [0xa7,0x1f,0x6a,0x7e] +fsh f6, 2047(s4) +# CHECK-ASM-AND-OBJ: fsh ft7, -2048(s5) +# CHECK-ASM: encoding: [0x27,0x90,0x7a,0x80] +fsh f7, -2048(s5) +# CHECK-ASM-AND-OBJ: fsh fs0, -2048(s6) +# CHECK-ASM: encoding: [0x27,0x10,0x8b,0x80] +fsh f8, %lo(2048)(s6) +# CHECK-ASM-AND-OBJ: fsh fs1, 999(s7) +# CHECK-ASM: encoding: [0xa7,0x93,0x9b,0x3e] +fsh f9, 999(s7) + +# CHECK-ASM-AND-OBJ: fmv.x.h a2, fs7 +# CHECK-ASM: encoding: [0x53,0x86,0x0b,0xe4] +fmv.x.h a2, fs7 +# CHECK-ASM-AND-OBJ: fmv.h.x ft1, a6 +# CHECK-ASM: encoding: [0xd3,0x00,0x08,0xf4] +fmv.h.x ft1, a6 + +# CHECK-ASM-AND-OBJ: fcvt.s.h fa0, ft0 +# CHECK-ASM: encoding: [0x53,0x05,0x20,0x40] +fcvt.s.h fa0, ft0 +# CHECK-ASM-AND-OBJ: fcvt.h.s ft2, fa2 +# CHECK-ASM: encoding: [0x53,0x71,0x06,0x44] +fcvt.h.s ft2, fa2 +# CHECK-ASM-AND-OBJ: fcvt.d.h fa0, ft0 +# CHECK-ASM: encoding: [0x53,0x05,0x20,0x42] +fcvt.d.h fa0, ft0 +# CHECK-ASM-AND-OBJ: fcvt.h.d ft2, fa2 +# CHECK-ASM: encoding: [0x53,0x71,0x16,0x44] +fcvt.h.d ft2, fa2