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 @@ -94,6 +94,7 @@ {"zca", RISCVExtensionVersion{1, 0}}, {"zcb", RISCVExtensionVersion{1, 0}}, {"zcd", RISCVExtensionVersion{1, 0}}, + {"zce", RISCVExtensionVersion{1, 0}}, {"zcf", RISCVExtensionVersion{1, 0}}, {"zcmp", RISCVExtensionVersion{1, 0}}, {"zcmt", RISCVExtensionVersion{1, 0}}, @@ -934,6 +935,10 @@ "' extension is incompatible with '" + (HasC ? "c" : "zcd") + "' extension when 'd' extension is enabled"); + if (XLen != 32 && Exts.count("zcf")) + return createStringError(errc::invalid_argument, + "'zcf' is only supported for 'rv32'"); + // Additional dependency checks. // TODO: The 'q' extension requires rv64. // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. @@ -948,6 +953,9 @@ static const char *ImpliedExtsXsfvcp[] = {"zve32x"}; static const char *ImpliedExtsZacas[] = {"a"}; static const char *ImpliedExtsZcb[] = {"zca"}; +static const char *ImpliedExtsZcd[] = {"zca"}; +static const char *ImpliedExtsZce[] = {"zcb", "zcmp", "zcmt"}; +static const char *ImpliedExtsZcf[] = {"zca"}; static const char *ImpliedExtsZcmp[] = {"zca"}; static const char *ImpliedExtsZcmt[] = {"zca"}; static const char *ImpliedExtsZdinx[] = {"zfinx"}; @@ -1011,6 +1019,9 @@ {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}}, {{"zacas"}, {ImpliedExtsZacas}}, {{"zcb"}, {ImpliedExtsZcb}}, + {{"zcd"}, {ImpliedExtsZcd}}, + {{"zce"}, {ImpliedExtsZce}}, + {{"zcf"}, {ImpliedExtsZcf}}, {{"zcmp"}, {ImpliedExtsZcmp}}, {{"zcmt"}, {ImpliedExtsZcmt}}, {{"zdinx"}, {ImpliedExtsZdinx}}, @@ -1088,6 +1099,13 @@ } } } + + // Add Zcf if Zce and F are enabled on RV32. + if (XLen == 32 && Exts.count("zce") && Exts.count("f") && + !Exts.count("zcf")) { + auto Version = findDefaultVersion("zcf"); + addExtension("zcf", Version->Major, Version->Minor); + } } struct CombinedExtsEntry { diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -358,15 +358,9 @@ "'Zcf' (Compressed Single-Precision Floating-Point Instructions)", [FeatureStdExtZca]>; -def HasStdExtCOrZcf - : Predicate<"Subtarget->hasStdExtC() || Subtarget->hasStdExtZcf()">, - AssemblerPredicate<(any_of FeatureStdExtC, FeatureStdExtZcf), - "'C' (Compressed Instructions) or " - "'Zcf' (Compressed Single-Precision Floating-Point Instructions)">; - def FeatureStdExtZcmp : SubtargetFeature<"zcmp", "HasStdExtZcmp", "true", - "'Zcmp' (sequenced instuctions for code-size reduction)", + "'Zcmp' (sequenced instuctions for code-size reduction)", [FeatureStdExtZca]>; def HasStdExtZcmp : Predicate<"Subtarget->hasStdExtZcmp() && !Subtarget->hasStdExtC()">, AssemblerPredicate<(all_of FeatureStdExtZcmp, (not FeatureStdExtC)), @@ -374,12 +368,26 @@ def FeatureStdExtZcmt : SubtargetFeature<"zcmt", "HasStdExtZcmt", "true", - "'Zcmt' (table jump instuctions for code-size reduction)", - [FeatureStdExtZca, FeatureStdExtZicsr]>; + "'Zcmt' (table jump instuctions for code-size reduction)", + [FeatureStdExtZca, FeatureStdExtZicsr]>; def HasStdExtZcmt : Predicate<"Subtarget->hasStdExtZcmt()">, AssemblerPredicate<(all_of FeatureStdExtZcmt), "'Zcmt' (table jump instuctions for code-size reduction)">; +def FeatureStdExtZce + : SubtargetFeature<"zce", "HasStdExtZce", "true", + "'Zce' (Compressed extensions for microcontrollers)", + [FeatureStdExtZca, FeatureStdExtZcb, FeatureStdExtZcmp, + FeatureStdExtZcmt]>; + +def HasStdExtCOrZcfOrZce + : Predicate<"Subtarget->hasStdExtC() || Subtarget->hasStdExtZcf() " + "Subtarget->hasStdExtZce()">, + AssemblerPredicate<(any_of FeatureStdExtC, FeatureStdExtZcf, + FeatureStdExtZce), + "'C' (Compressed Instructions) or " + "'Zcf' (Compressed Single-Precision Floating-Point Instructions)">; + def FeatureNoRVCHints : SubtargetFeature<"no-rvc-hints", "EnableRVCHintInstrs", "false", "Disable RVC Hint Instructions.">; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td @@ -348,7 +348,7 @@ } let DecoderNamespace = "RISCV32Only_", - Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in + Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in def C_FLW : CLoad_ri<0b011, "c.flw", FPR32C, uimm7_lsb00>, Sched<[WriteFLD32, ReadMemBase]> { bits<7> imm; @@ -382,7 +382,7 @@ } let DecoderNamespace = "RISCV32Only_", - Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in + Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in def C_FSW : CStore_rri<0b111, "c.fsw", FPR32C, uimm7_lsb00>, Sched<[WriteFST32, ReadStoreData, ReadMemBase]> { bits<7> imm; @@ -534,7 +534,7 @@ } let DecoderNamespace = "RISCV32Only_", - Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in + Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in def C_FLWSP : CStackLoad<0b011, "c.flwsp", FPR32, uimm8_lsb00>, Sched<[WriteFLD32, ReadMemBase]> { let Inst{6-4} = imm{4-2}; @@ -592,7 +592,7 @@ } let DecoderNamespace = "RISCV32Only_", - Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in + Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in def C_FSWSP : CStackStore<0b111, "c.fswsp", FPR32, uimm8_lsb00>, Sched<[WriteFST32, ReadStoreData, ReadMemBase]> { let Inst{12-9} = imm{5-2}; @@ -743,7 +743,7 @@ def : InstAlias<"c.sdsp $rs2, (${rs1})", (C_SDSP GPRC:$rs2, SPMem:$rs1, 0)>; } -let Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in { +let Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in { def : InstAlias<"c.flw $rd, (${rs1})", (C_FLW FPR32C:$rd, GPRCMem:$rs1, 0)>; def : InstAlias<"c.fsw $rs2, (${rs1})", (C_FSW FPR32C:$rs2, GPRCMem:$rs1, 0)>; def : InstAlias<"c.flwsp $rd, (${rs1})", (C_FLWSP FPR32C:$rd, SPMem:$rs1, 0)>; @@ -875,7 +875,7 @@ (C_LW GPRC:$rd, GPRCMem:$rs1, uimm7_lsb00:$imm)>; } // Predicates = [HasStdExtCOrZca] -let Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in { +let Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in { def : CompressPat<(FLW FPR32C:$rd, GPRCMem:$rs1, uimm7_lsb00:$imm), (C_FLW FPR32C:$rd, GPRCMem:$rs1, uimm7_lsb00:$imm)>; } // Predicates = [HasStdExtC, HasStdExtF, IsRV32] @@ -895,7 +895,7 @@ (C_SW GPRC:$rs2, GPRCMem:$rs1, uimm7_lsb00:$imm)>; } // Predicates = [HasStdExtCOrZca] -let Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in { +let Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in { def : CompressPat<(FSW FPR32C:$rs2, GPRCMem:$rs1, uimm7_lsb00:$imm), (C_FSW FPR32C:$rs2, GPRCMem:$rs1, uimm7_lsb00:$imm)>; } // Predicates = [HasStdExtC, HasStdExtF, IsRV32] @@ -992,7 +992,7 @@ (C_LWSP GPRNoX0:$rd, SPMem:$rs1, uimm8_lsb00:$imm)>; } // Predicates = [HasStdExtCOrZca] -let Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in { +let Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in { def : CompressPat<(FLW FPR32:$rd, SPMem:$rs1, uimm8_lsb00:$imm), (C_FLWSP FPR32:$rd, SPMem:$rs1, uimm8_lsb00:$imm)>; } // Predicates = [HasStdExtC, HasStdExtF, IsRV32] @@ -1034,7 +1034,7 @@ (C_SWSP GPR:$rs2, SPMem:$rs1, uimm8_lsb00:$imm)>; } // Predicates = [HasStdExtCOrZca] -let Predicates = [HasStdExtCOrZcf, HasStdExtF, IsRV32] in { +let Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in { def : CompressPat<(FSW FPR32:$rs2, SPMem:$rs1, uimm8_lsb00:$imm), (C_FSWSP FPR32:$rs2, SPMem:$rs1, uimm8_lsb00:$imm)>; } // Predicates = [HasStdExtC, HasStdExtF, IsRV32] diff --git a/llvm/test/CodeGen/RISCV/compress-float.ll b/llvm/test/CodeGen/RISCV/compress-float.ll --- a/llvm/test/CodeGen/RISCV/compress-float.ll +++ b/llvm/test/CodeGen/RISCV/compress-float.ll @@ -44,6 +44,27 @@ ; RUN: -disable-block-placement < %t.mixedattr \ ; RUN: | llvm-objdump -d --triple=riscv32 --mattr=+zcf,+f -M no-aliases - \ ; RUN: | FileCheck -check-prefix=RV32IFDC %s +; +; RUN: cat %s > %t.tgtattr +; RUN: echo 'attributes #0 = { nounwind }' >> %t.tgtattr +; RUN: llc -mtriple=riscv32 -target-abi ilp32f -mattr=+zce,+f -filetype=obj \ +; RUN: -disable-block-placement < %t.tgtattr \ +; RUN: | llvm-objdump -d --triple=riscv32 --mattr=+zce,+f -M no-aliases - \ +; RUN: | FileCheck -check-prefix=RV32IFDC %s +; +; RUN: cat %s > %t.fnattr +; RUN: echo 'attributes #0 = { nounwind "target-features"="+zce,+f" }' >> %t.fnattr +; RUN: llc -mtriple=riscv32 -target-abi ilp32f -filetype=obj \ +; RUN: -disable-block-placement < %t.fnattr \ +; RUN: | llvm-objdump -d --triple=riscv32 --mattr=+zce,+f -M no-aliases - \ +; RUN: | FileCheck -check-prefix=RV32IFDC %s +; +; RUN: cat %s > %t.mixedattr +; RUN: echo 'attributes #0 = { nounwind "target-features"="+f" }' >> %t.mixedattr +; RUN: llc -mtriple=riscv32 -target-abi ilp32f -mattr=+zce -filetype=obj \ +; RUN: -disable-block-placement < %t.mixedattr \ +; RUN: | llvm-objdump -d --triple=riscv32 --mattr=+zce,+f -M no-aliases - \ +; RUN: | FileCheck -check-prefix=RV32IFDC %s ; This acts as a basic correctness check for the codegen instruction compression ; path, verifying that the assembled file contains compressed instructions when 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 @@ -229,10 +229,10 @@ # CHECK: attribute 5, "rv32i2p1_zca1p0" .attribute arch, "rv32izcd1p0" -# CHECK: attribute 5, "rv32i2p1_zcd1p0" +# CHECK: attribute 5, "rv32i2p1_zca1p0_zcd1p0" .attribute arch, "rv32izcf1p0" -# CHECK: attribute 5, "rv32i2p1_zcf1p0" +# CHECK: attribute 5, "rv32i2p1_zca1p0_zcf1p0" .attribute arch, "rv32izcb1p0" # CHECK: attribute 5, "rv32i2p1_zca1p0_zcb1p0" diff --git a/llvm/test/MC/RISCV/option-arch.s b/llvm/test/MC/RISCV/option-arch.s --- a/llvm/test/MC/RISCV/option-arch.s +++ b/llvm/test/MC/RISCV/option-arch.s @@ -118,3 +118,9 @@ # Test extension name that has digits. .option arch, +zve32x # CHECK: .option arch, +zve32x + +.option arch, rv32i +.option arch, +zce, +f +# CHECK-INST: flw fa0, 0(a0) +# CHECK: # encoding: [0x08,0x61] +c.flw fa0, 0(a0) diff --git a/llvm/test/MC/RISCV/rv32fc-valid.s b/llvm/test/MC/RISCV/rv32fc-valid.s --- a/llvm/test/MC/RISCV/rv32fc-valid.s +++ b/llvm/test/MC/RISCV/rv32fc-valid.s @@ -21,9 +21,6 @@ # RUN: not llvm-mc -triple riscv64 -mattr=+c,+f \ # RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ # RUN: | FileCheck -check-prefixes=CHECK-NO-RV32 %s -# RUN: not llvm-mc -triple riscv64 -mattr=+zcf,+f \ -# RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ -# RUN: | FileCheck -check-prefixes=CHECK-NO-RV32 %s # FIXME: error messages for rv64fc are misleading diff --git a/llvm/unittests/Support/RISCVISAInfoTest.cpp b/llvm/unittests/Support/RISCVISAInfoTest.cpp --- a/llvm/unittests/Support/RISCVISAInfoTest.cpp +++ b/llvm/unittests/Support/RISCVISAInfoTest.cpp @@ -469,6 +469,11 @@ "'zcmt' extension is incompatible with 'zcd' extension when 'd' " "extension is enabled"); } + + for (StringRef Input : {"rv64if_zcf"}) { + EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()), + "'zcf' is only supported for 'rv32'"); + } } TEST(ToFeatureVector, IIsDroppedAndExperimentalExtensionsArePrefixed) { @@ -507,3 +512,95 @@ ElementsAre("i", "m", "l", "c", "y", "zicsr", "zmfoo", "zfinx", "zzfoo", "sbar", "sfoo", "xbar", "xfoo")); } + +TEST(ParseArchString, ZceImplication) { + auto MaybeRV32IZce = RISCVISAInfo::parseArchString("rv32izce", true); + ASSERT_THAT_EXPECTED(MaybeRV32IZce, Succeeded()); + RISCVISAInfo::OrderedExtensionMap ExtsRV32IZce = + (*MaybeRV32IZce)->getExtensions(); + EXPECT_EQ(ExtsRV32IZce.size(), 6UL); + EXPECT_EQ(ExtsRV32IZce.count("i"), 1U); + EXPECT_EQ(ExtsRV32IZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV32IZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV32IZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV32IZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV32IZce.count("zcmt"), 1U); + + auto MaybeRV32IFZce = RISCVISAInfo::parseArchString("rv32ifzce", true); + ASSERT_THAT_EXPECTED(MaybeRV32IFZce, Succeeded()); + RISCVISAInfo::OrderedExtensionMap ExtsRV32IFZce = + (*MaybeRV32IFZce)->getExtensions(); + EXPECT_EQ(ExtsRV32IFZce.size(), 9UL); + EXPECT_EQ(ExtsRV32IFZce.count("i"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zicsr"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("f"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zcf"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV32IFZce.count("zcmt"), 1U); + + auto MaybeRV32IDZce = RISCVISAInfo::parseArchString("rv32idzce", true); + ASSERT_THAT_EXPECTED(MaybeRV32IDZce, Succeeded()); + RISCVISAInfo::OrderedExtensionMap ExtsRV32IDZce = + (*MaybeRV32IDZce)->getExtensions(); + EXPECT_EQ(ExtsRV32IDZce.size(), 10UL); + EXPECT_EQ(ExtsRV32IDZce.count("i"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zicsr"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("f"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("d"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zcf"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV32IDZce.count("zcmt"), 1U); + + auto MaybeRV64IZce = RISCVISAInfo::parseArchString("rv64izce", true); + ASSERT_THAT_EXPECTED(MaybeRV64IZce, Succeeded()); + RISCVISAInfo::OrderedExtensionMap ExtsRV64IZce = + (*MaybeRV64IZce)->getExtensions(); + EXPECT_EQ(ExtsRV64IZce.size(), 6UL); + EXPECT_EQ(ExtsRV64IZce.count("i"), 1U); + EXPECT_EQ(ExtsRV64IZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV64IZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV64IZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV64IZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV64IZce.count("zcmt"), 1U); + + auto MaybeRV64IFZce = RISCVISAInfo::parseArchString("rv64ifzce", true); + ASSERT_THAT_EXPECTED(MaybeRV64IFZce, Succeeded()); + RISCVISAInfo::OrderedExtensionMap ExtsRV64IFZce = + (*MaybeRV64IFZce)->getExtensions(); + EXPECT_EQ(ExtsRV64IFZce.size(), 8UL); + EXPECT_EQ(ExtsRV64IFZce.count("i"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zicsr"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("f"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zcmt"), 1U); + + EXPECT_EQ(ExtsRV64IFZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV64IFZce.count("zcmt"), 1U); + + auto MaybeRV64IDZce = RISCVISAInfo::parseArchString("rv64idzce", true); + ASSERT_THAT_EXPECTED(MaybeRV64IDZce, Succeeded()); + RISCVISAInfo::OrderedExtensionMap ExtsRV64IDZce = + (*MaybeRV64IDZce)->getExtensions(); + EXPECT_EQ(ExtsRV64IDZce.size(), 9UL); + EXPECT_EQ(ExtsRV64IDZce.count("i"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("zicsr"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("f"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("d"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("zca"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("zcb"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("zce"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("zcmp"), 1U); + EXPECT_EQ(ExtsRV64IDZce.count("zcmt"), 1U); +}