diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -2165,29 +2165,40 @@ return Error(Parser.getTok().getLoc(), "unexpected token, expected identifier"); - StringRef Extension = Parser.getTok().getString(); + StringRef ExtStr = Parser.getTok().getString(); - // TODO: Enable or disable extension according to extension and extension - // version number. Currently extension version number is not supported. - if (Extension.find_if(isDigit) != StringRef::npos) + if (ExtStr.find_if(isDigit) != StringRef::npos) return Error(Parser.getTok().getLoc(), - "extension version number is not yet supported"); - - for (auto Feature : RISCVFeatureKV) { - if (Extension == Feature.Key) { - if (IsAdd) { - setFeatureBits(Feature.Value, Feature.Key); - getTargetStreamer().emitDirectiveOptionArchPlus(Extension); - } else { - clearFeatureBits(Feature.Value, Feature.Key); - getTargetStreamer().emitDirectiveOptionArchMinus(Extension); - } - Parser.Lex(); - return Parser.parseToken(AsmToken::EndOfStatement, - "unexpected token, expected end of statement"); + "Don't specify version number, extensions don't rely on " + "version numbers"); + + ArrayRef KVArray(RISCVFeatureKV); + auto Ext = llvm::lower_bound(KVArray, ExtStr); + if (Ext == KVArray.end() || StringRef(Ext->Key) != ExtStr) + return Error(Parser.getTok().getLoc(), "unknown extension"); + + if (IsAdd) { + setFeatureBits(Ext->Value, Ext->Key); + getTargetStreamer().emitDirectiveOptionArchPlus(Ext->Key); + } else { + // Check dependency. It is invalid to disable an extension that + // there are other enabled extensions depend on it. + for (auto Feature : KVArray) { + if (getSTI().hasFeature(Feature.Value) && + Feature.Implies.test(Ext->Value)) + return Error(Parser.getTok().getLoc(), + Twine("Can't disable ") + Ext->Key + " extension, " + + Feature.Key + " extension requires " + Ext->Key + + " extension be enabled"); } + + clearFeatureBits(Ext->Value, Ext->Key); + getTargetStreamer().emitDirectiveOptionArchMinus(Ext->Key); } - return Error(Parser.getTok().getLoc(), "unknown extension"); + + Parser.Lex(); + return Parser.parseToken(AsmToken::EndOfStatement, + "unexpected token, expected end of statement"); } if (Option == "rvc") { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -116,10 +116,10 @@ OS << "\t .option\tarch,\t=" << Value << "\"\n"; } void RISCVTargetAsmStreamer::emitDirectiveOptionArchPlus(StringRef Value) { - OS << "\t .option\tarch,\t+" << Value << "\"\n"; + OS << "\t .option\tarch,\t+" << Value << "\n"; } void RISCVTargetAsmStreamer::emitDirectiveOptionArchMinus(StringRef Value) { - OS << "\t .option\tarch,\t-" << Value << "\"\n"; + OS << "\t .option\tarch,\t-" << Value << "\n"; } void RISCVTargetAsmStreamer::finishAttributeSection() {} diff --git a/llvm/test/MC/RISCV/option-invalid.s b/llvm/test/MC/RISCV/option-invalid.s --- a/llvm/test/MC/RISCV/option-invalid.s +++ b/llvm/test/MC/RISCV/option-invalid.s @@ -25,9 +25,13 @@ # CHECK: error: unexpected token, expected end of statement .option arch, +c foo -# CHECK: error: extension version number is not yet supported +# CHECK: error: Don't specify version number, extensions don't rely on version numbers .option arch, +c2p0 +.option arch, +d +# CHECK: error: Can't disable f extension, d extension requires f extension be enabled +.option arch, -f + # CHECK: error: unexpected token, expected end of statement .option rvc foo @@ -42,3 +46,4 @@ # CHECK: error: unexpected token, expected end of statement .option pop 123 +