Index: clang/lib/Basic/Targets/RISCV.h =================================================================== --- clang/lib/Basic/Targets/RISCV.h +++ clang/lib/Basic/Targets/RISCV.h @@ -44,6 +44,7 @@ bool HasZbs = false; bool HasZbt = false; bool HasZfh = false; + bool HasZmmul = false; bool HasZvamo = false; bool HasZvlsseg = false; Index: clang/lib/Basic/Targets/RISCV.cpp =================================================================== --- clang/lib/Basic/Targets/RISCV.cpp +++ clang/lib/Basic/Targets/RISCV.cpp @@ -141,9 +141,12 @@ Builder.defineMacro("__riscv_arch_test"); Builder.defineMacro("__riscv_i", "2000000"); + if (HasZmmul || HasM) { + Builder.defineMacro("__riscv_mul"); + } + if (HasM) { Builder.defineMacro("__riscv_m", "2000000"); - Builder.defineMacro("__riscv_mul"); Builder.defineMacro("__riscv_div"); Builder.defineMacro("__riscv_muldiv"); } @@ -276,6 +279,7 @@ .Case("experimental-zbs", HasZbs) .Case("experimental-zbt", HasZbt) .Case("experimental-zfh", HasZfh) + .Case("experimental-zmmul", HasZmmul) .Case("experimental-zvamo", HasZvamo) .Case("experimental-zvlsseg", HasZvlsseg) .Default(false); @@ -323,6 +327,8 @@ HasZbt = true; else if (Feature == "+experimental-zfh") HasZfh = true; + else if (Feature == "+experimental-zmmul") + HasZmmul = true; else if (Feature == "+experimental-zvamo") HasZvamo = true; else if (Feature == "+experimental-zvlsseg") Index: clang/lib/Driver/ToolChains/Arch/RISCV.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -66,6 +66,8 @@ return RISCVExtensionVersion{"0", "10"}; if (Ext == "zfh") return RISCVExtensionVersion{"0", "1"}; + if (Ext == "zmmul") + return RISCVExtensionVersion{"0", "1"}; return None; } Index: clang/test/Driver/riscv-arch.c =================================================================== --- clang/test/Driver/riscv-arch.c +++ clang/test/Driver/riscv-arch.c @@ -488,3 +488,22 @@ // RUN: %clang -target riscv32-unknown-elf -march=rv32izvlsseg0p10 -menable-experimental-extensions -### %s -c 2>&1 | \ // RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS %s // RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS: "-target-feature" "+experimental-zvlsseg" + +// RUN: %clang -target riscv32-unknown-elf -march=rv32i_zmmul -### %s \ +// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZMMUL-NOFLAG %s +// RV32-EXPERIMENTAL-ZMMUL-NOFLAG: error: invalid arch name 'rv32i_zmmul' +// RV32-EXPERIMENTAL-ZMMUL-NOFLAG: requires '-menable-experimental-extensions' + +// RUN: %clang -target riscv32-unknown-elf -march=rv32i_zmmul -menable-experimental-extensions -### %s \ +// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZMMUL-NOVERS %s +// RV32-EXPERIMENTAL-ZMMUL-NOVERS: error: invalid arch name 'rv32i_zmmul' +// RV32-EXPERIMENTAL-ZMMUL-NOVERS: experimental extension requires explicit version number + +// RUN: %clang -target riscv32-unknown-elf -march=rv32i_zmmul2p0 -menable-experimental-extensions -### %s \ +// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZMMUL-BADVERS %s +// RV32-EXPERIMENTAL-ZMMUL-BADVERS: error: invalid arch name 'rv32i_zmmul2p0' +// RV32-EXPERIMENTAL-ZMMUL-BADVERS: unsupported version number 2.0 for experimental extension + +// RUN: %clang -target riscv32-unknown-elf -march=rv32i_zmmul0p1 -menable-experimental-extensions -### %s \ +// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZMMUL-GOODVERS %s +// RV32-EXPERIMENTAL-ZMMUL-GOODVERS: "-target-feature" "+experimental-zmmul" Index: llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -2056,6 +2056,7 @@ clearFeatureBits(RISCV::FeatureExtZbr, "experimental-zbr"); clearFeatureBits(RISCV::FeatureExtZbs, "experimental-zbs"); clearFeatureBits(RISCV::FeatureExtZbt, "experimental-zbt"); + clearFeatureBits(RISCV::FeatureStdExtZmmul, "experimental-zmmul"); clearFeatureBits(RISCV::FeatureExtZvamo, "experimental-zvamo"); clearFeatureBits(RISCV::FeatureStdExtZvlsseg, "experimental-zvlsseg"); @@ -2114,6 +2115,8 @@ setFeatureBits(RISCV::FeatureExtZbt, "experimental-zbt"); else if (Ext == "zfh") setFeatureBits(RISCV::FeatureExtZfh, "experimental-zfh"); + else if (Ext == "zmmul") + setFeatureBits(RISCV::FeatureStdExtZmmul, "experimental-zmmul"); else if (Ext == "zvamo") setFeatureBits(RISCV::FeatureExtZvamo, "experimental-zvamo"); else if (Ext == "zvlsseg") Index: llvm/lib/Target/RISCV/RISCV.td =================================================================== --- llvm/lib/Target/RISCV/RISCV.td +++ llvm/lib/Target/RISCV/RISCV.td @@ -12,9 +12,17 @@ // RISC-V subtarget features and instruction predicates. //===----------------------------------------------------------------------===// +def FeatureStdExtZmmul + : SubtargetFeature<"experimental-zmmul", "HasStdExtZmmul", "true", + "'Zmmul' (Integer Multiplication)">; +def HasStdExtZmmul : Predicate<"Subtarget->hasStdExtZmmul()">, + AssemblerPredicate<(all_of FeatureStdExtZmmul), + "'Zmmul' (Integer Multiplication)">; + def FeatureStdExtM : SubtargetFeature<"m", "HasStdExtM", "true", - "'M' (Integer Multiplication and Division)">; + "'M' (Integer Multiplication and Division)", + [FeatureStdExtZmmul]>; def HasStdExtM : Predicate<"Subtarget->hasStdExtM()">, AssemblerPredicate<(all_of FeatureStdExtM), "'M' (Integer Multiplication and Division)">; Index: llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -201,19 +201,26 @@ setOperationAction(ISD::USUBSAT, MVT::i32, Custom); } - if (!Subtarget.hasStdExtM()) { + if (!Subtarget.hasStdExtZmmul()) { setOperationAction(ISD::MUL, XLenVT, Expand); setOperationAction(ISD::MULHS, XLenVT, Expand); setOperationAction(ISD::MULHU, XLenVT, Expand); + } else { + if (Subtarget.is64Bit()) { + setOperationAction(ISD::MUL, MVT::i32, Custom); + setOperationAction(ISD::MUL, MVT::i128, Custom); + } else { + setOperationAction(ISD::MUL, MVT::i64, Custom); + } + } + + if (!Subtarget.hasStdExtM()) { setOperationAction(ISD::SDIV, XLenVT, Expand); setOperationAction(ISD::UDIV, XLenVT, Expand); setOperationAction(ISD::SREM, XLenVT, Expand); setOperationAction(ISD::UREM, XLenVT, Expand); } else { if (Subtarget.is64Bit()) { - setOperationAction(ISD::MUL, MVT::i32, Custom); - setOperationAction(ISD::MUL, MVT::i128, Custom); - setOperationAction(ISD::SDIV, MVT::i8, Custom); setOperationAction(ISD::UDIV, MVT::i8, Custom); setOperationAction(ISD::UREM, MVT::i8, Custom); @@ -223,8 +230,6 @@ setOperationAction(ISD::SDIV, MVT::i32, Custom); setOperationAction(ISD::UDIV, MVT::i32, Custom); setOperationAction(ISD::UREM, MVT::i32, Custom); - } else { - setOperationAction(ISD::MUL, MVT::i64, Custom); } } Index: llvm/lib/Target/RISCV/RISCVInstrInfoM.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfoM.td +++ llvm/lib/Target/RISCV/RISCVInstrInfoM.td @@ -24,7 +24,7 @@ // Instructions //===----------------------------------------------------------------------===// -let Predicates = [HasStdExtM] in { +let Predicates = [HasStdExtZmmul] in { def MUL : ALU_rr<0b0000001, 0b000, "mul">, Sched<[WriteIMul, ReadIMul, ReadIMul]>; def MULH : ALU_rr<0b0000001, 0b001, "mulh">, @@ -33,6 +33,9 @@ Sched<[WriteIMul, ReadIMul, ReadIMul]>; def MULHU : ALU_rr<0b0000001, 0b011, "mulhu">, Sched<[WriteIMul, ReadIMul, ReadIMul]>; +} // Predicates = [HasStdExtZmmul] + +let Predicates = [HasStdExtM] in { def DIV : ALU_rr<0b0000001, 0b100, "div">, Sched<[WriteIDiv, ReadIDiv, ReadIDiv]>; def DIVU : ALU_rr<0b0000001, 0b101, "divu">, @@ -43,9 +46,12 @@ Sched<[WriteIDiv, ReadIDiv, ReadIDiv]>; } // Predicates = [HasStdExtM] -let Predicates = [HasStdExtM, IsRV64] in { +let Predicates = [HasStdExtZmmul, IsRV64] in { def MULW : ALUW_rr<0b0000001, 0b000, "mulw">, Sched<[WriteIMul32, ReadIMul32, ReadIMul32]>; +} // Predicates = [HasStdExtZmmul, IsRV64] + +let Predicates = [HasStdExtM, IsRV64] in { def DIVW : ALUW_rr<0b0000001, 0b100, "divw">, Sched<[WriteIDiv32, ReadIDiv32, ReadIDiv32]>; def DIVUW : ALUW_rr<0b0000001, 0b101, "divuw">, @@ -60,21 +66,25 @@ // Pseudo-instructions and codegen patterns //===----------------------------------------------------------------------===// -let Predicates = [HasStdExtM] in { +let Predicates = [HasStdExtZmmul] in { def : PatGprGpr; def : PatGprGpr; def : PatGprGpr; def : PatGprGpr; +} // Predicates = [HasStdExtZmmul] + +let Predicates = [HasStdExtM] in { def : PatGprGpr; def : PatGprGpr; def : PatGprGpr; def : PatGprGpr; } // Predicates = [HasStdExtM] -let Predicates = [HasStdExtM, IsRV64] in { +let Predicates = [HasStdExtZmmul] in def : Pat<(sext_inreg (mul GPR:$rs1, GPR:$rs2), i32), (MULW GPR:$rs1, GPR:$rs2)>; +let Predicates = [HasStdExtM, IsRV64] in { def : PatGprGpr; def : PatGprGpr; def : PatGprGpr; @@ -96,7 +106,7 @@ (REMW GPR:$rs1, GPR:$rs2)>; } // Predicates = [HasStdExtM, IsRV64] -let Predicates = [HasStdExtM, IsRV64, NotHasStdExtZba] in { +let Predicates = [HasStdExtZmmul, IsRV64, NotHasStdExtZba] in { // Special case for calculating the full 64-bit product of a 32x32 unsigned // multiply where the inputs aren't known to be zero extended. We can shift the // inputs left by 32 and use a MULHU. This saves two SRLIs needed to finish @@ -112,4 +122,4 @@ def : Pat<(sext_inreg (mul (and GPR:$rs1, 0xffffffff), (and GPR:$rs2, 0xffffffff)), i32), (ADDIW (MULHU (SLLI GPR:$rs1, 32), (SLLI GPR:$rs2, 32)), 0)>; -} // Predicates = [HasStdExtM, IsRV64, NotHasStdExtZba] +} // Predicates = [HasStdExtZmmul, IsRV64, NotHasStdExtZba] Index: llvm/lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- llvm/lib/Target/RISCV/RISCVSubtarget.h +++ llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -35,6 +35,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { virtual void anchor(); bool HasStdExtM = false; + bool HasStdExtZmmul = false; bool HasStdExtA = false; bool HasStdExtF = false; bool HasStdExtD = false; @@ -103,6 +104,7 @@ } bool enableMachineScheduler() const override { return true; } bool hasStdExtM() const { return HasStdExtM; } + bool hasStdExtZmmul() const { return HasStdExtZmmul; } bool hasStdExtA() const { return HasStdExtA; } bool hasStdExtF() const { return HasStdExtF; } bool hasStdExtD() const { return HasStdExtD; } Index: llvm/test/CodeGen/RISCV/zmmul.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/zmmul.ll @@ -0,0 +1,41 @@ +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-DIV %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-DIV %s +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-REM %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-REM %s + +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-UDIV %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-UDIV %s +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-UREM %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | not FileCheck -check-prefix=CHECK-UREM %s + +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CHECK-MUL %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zmmul -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CHECK-MUL %s + +; RUN: llc -mtriple=riscv32 -mattr=+m -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefixes=CHECK-MUL,CHECK-UDIV,CHECK-DIV,CHECK-UREM,CHECK-REM %s +; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefixes=CHECK-MUL,CHECK-UDIV,CHECK-DIV,CHECK-UREM,CHECK-REM %s + +define i32 @foo(i32 %a, i32 %b) { +; CHECK-UDIV: divu{{w?}} {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}} + %1 = udiv i32 %a, %b +; CHECK-DIV: div{{w?}} {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}} + %2 = sdiv i32 %a, %1 +; CHECK-MUL: mul{{w?}} {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}} + %3 = mul i32 %b, %2 +; CHECK-UREM: remu{{w?}} {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}} + %4 = urem i32 %3, %b +; CHECK-REM: rem {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}}, {{[as]}}{{[0-9]}} + %5 = srem i32 %4, %a + ret i32 %5 +} Index: llvm/test/MC/RISCV/rv32i-invalid.s =================================================================== --- llvm/test/MC/RISCV/rv32i-invalid.s +++ llvm/test/MC/RISCV/rv32i-invalid.s @@ -169,7 +169,7 @@ xor s2, s2 # CHECK: :[[@LINE]]:1: error: too few operands for instruction # Instruction not in the base ISA -mul a4, ra, s0 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +div a4, ra, s0 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) amomaxu.w s5, s4, (s3) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'A' (Atomic Instructions) fadd.s ft0, ft1, ft2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'F' (Single-Precision Floating-Point) fadd.h ft0, ft1, ft2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) Index: llvm/test/MC/RISCV/rv32zmmul-invaild.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/rv32zmmul-invaild.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc %s -triple=riscv32 -mattr=+experimental-zmmul -riscv-no-aliases 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-ERROR %s + +# CHECK-ERROR: 5:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +div s0, s0, s0 + +# CHECK-ERROR: 8:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +divu gp, a0, a1 + +# CHECK-ERROR: 11:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +rem s2, s2, s8 + +# CHECK-ERROR: 14:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +remu x18, x18, x24 Index: llvm/test/MC/RISCV/rv32zmmul-valid.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/rv32zmmul-valid.s @@ -0,0 +1,14 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zmmul -riscv-no-aliases 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-INST %s + +# CHECK-INST: mul a4, ra, s0 +mul a4, ra, s0 + +# CHECK-INST: mulh ra, zero, zero +mulh x1, x0, x0 + +# CHECK-INST: mulhsu t0, t2, t1 +mulhsu t0, t2, t1 + +# CHECK-INST: mulhu a5, a4, a3 +mulhu a5, a4, a3 Index: llvm/test/MC/RISCV/rv64zmmul-invalid.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/rv64zmmul-invalid.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc %s -triple=riscv64 -mattr=+experimental-zmmul -riscv-no-aliases 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-ERROR %s + +# CHECK-ERROR: 5:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +divw tp, t0, t1 + +# CHECK-ERROR: 8:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +divuw t2, s0, s2 + +# CHECK-ERROR: 11:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +remw a0, a1, a2 + +# CHECK-ERROR: 14:1: error: instruction requires the following: 'M' (Integer Multiplication and Division) +remuw a3, a4, a5 Index: llvm/test/MC/RISCV/rv64zmmul-valid.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/rv64zmmul-valid.s @@ -0,0 +1,5 @@ +# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zmmul -riscv-no-aliases 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-INST %s + +# CHECK-INST: mulw ra, sp, gp +mulw ra, sp, gp