Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/CMakeLists.txt =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/CMakeLists.txt +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/CMakeLists.txt @@ -5,19 +5,25 @@ set(LLVM_OPTIONAL_SOURCES example_proto_to_asm.cpp proto_to_asm_main.cpp proto_to_asm_riscv.cpp proto_to_asm_riscv_fuzz_opnd_values.cpp) +set(LLVM_TARGET_DEFINITIONS ${CMAKE_CURRENT_SOURCE_DIR}/../../../lib/Target/RISCV/RISCV.td) +tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../lib/Target/RISCV) +tablegen(LLVM RISCVGenRegisterInfo.inc -gen-register-info -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../lib/Target/RISCV) +add_public_tablegen_target(RISCVTableGen) + + llvm_add_library(mcProtoToASM example_proto_to_asm.cpp - DEPENDS mcASMProto + DEPENDS mcASMProto RISCVTableGen LINK_LIBS mcASMProto ${PROTOBUF_LIBRARIES} ) llvm_add_library(mcRISCVProtoToASM proto_to_asm_riscv.cpp - DEPENDS mcRISCVASMProto + DEPENDS mcRISCVASMProto RISCVTableGen LINK_LIBS mcRISCVASMProto ${PROTOBUF_LIBRARIES} ) llvm_add_library(mcRISCVFuzzOpndValuesProtoToASM proto_to_asm_riscv_fuzz_opnd_values.cpp - DEPENDS mcRISCVFuzzOpndValuesASMProto + DEPENDS mcRISCVFuzzOpndValuesASMProto RISCVTableGen LINK_LIBS mcRISCVFuzzOpndValuesASMProto ${PROTOBUF_LIBRARIES} ) Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/example_proto_to_asm.cpp =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/example_proto_to_asm.cpp +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/example_proto_to_asm.cpp @@ -22,28 +22,82 @@ using namespace google::protobuf; -static void EmitAsm(std::ostream &OS, const EnumDescriptor *Enum, int Num) { - const EnumValueDescriptor *D = Enum->FindValueByNumber(Num); - std::string Msg = D->name(); - std::transform(Msg.begin(), Msg.end(), Msg.begin(), ::tolower); - OS << Msg; +namespace mc_proto_fuzzer { + +template +static void getMessageName(const T &X, std::string &Msg) { + const EnumDescriptor *D = X.ValueRange_descriptor(); + const EnumValueDescriptor *VD = D->FindValueByNumber(X.value()); + Msg = VD->name(); + std::transform(Msg.begin(), Msg.end(), Msg.begin(), ::toupper); +} +// --------------------------------- +// Emit MC Instruction +// --------------------------------- +#define EMIT_MC_INST +#ifdef EMIT_MC_INST +#include "riscv_support.h" + +template +static void EmitMCOpcode(std::ostream &OS, const T &X) { + std::string Msg; + getMessageName(X, Msg); + unsigned MCOpcode; + if (getMCOpcode(Msg, MCOpcode)) + OS << " #" << MCOpcode << ' ' << Msg; + else + OS << " #ERROR " << Msg; } -namespace mc_proto_fuzzer { +static void EmitMCOperand(std::ostream &OS, const Register &X) { + std::string Msg; + getMessageName(X, Msg); + unsigned MCReg; + OS << "\n# '; +} + +static void EmitMC(std::ostream &OS, const RTypeStatement &X) { + EmitMCOpcode(OS, X.opcode()); + // Directly handling RTypeOperands which has 3 operands. + auto Y = X.operands(); + EmitMCOperand(OS, Y.operand1()); + EmitMCOperand(OS, Y.operand2()); + EmitMCOperand(OS, Y.operand3()); +} + +static void EmitMC(std::ostream &OS, const AsmStatement &X) { + OS << "# \n"; +} + +#endif // EMIT_MC_INST + + +// --------------------------------- +// Emit Assembly Instruction +// --------------------------------- template -void Emit(std::ostream &OS, const T &X) { - const EnumDescriptor *ED = X.ValueRange_descriptor(); - EmitAsm(OS, ED, X.value()); +void EmitAsm(std::ostream &OS, const T &X) { + std::string Msg; + getMessageName(X, Msg); + std::transform(Msg.begin(), Msg.end(), Msg.begin(), ::tolower); + OS << Msg; } std::ostream &operator<<(std::ostream &OS, const Register &X) { - Emit(OS, X); + EmitAsm(OS, X); return OS; } std::ostream &operator<<(std::ostream &OS, const RTypeOpcode &X) { - Emit(OS, X); + EmitAsm(OS, X); return OS; } @@ -65,8 +119,12 @@ } std::ostream &operator<<(std::ostream &OS, const Assembly &X) { - for (auto &ST : X.statements()) + for (auto &ST : X.statements()) { OS << ST; +#ifdef EMIT_MC_INST + EmitMC(OS, ST); +#endif // EMIT_MC_INST + } return OS; } Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm_riscv.cpp =================================================================== --- tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm_riscv.cpp +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/proto_to_asm_riscv.cpp @@ -31,22 +31,369 @@ using namespace google::protobuf; -static void EmitAsm(std::ostream &OS, const EnumDescriptor * Enum, - int Num, bool SkipReplace = false) { - const EnumValueDescriptor * D = Enum->FindValueByNumber(Num); - std::string Msg = D->name(); +namespace mc_proto_fuzzer { + +template +static void getMessageName(const T &X, std::string &Msg) { + const EnumDescriptor *D = X.ValueRange_descriptor(); + const EnumValueDescriptor *VD = D->FindValueByNumber(X.value()); + Msg = VD->name(); + assert(Msg.length() > 0); + std::transform(Msg.begin(), Msg.end(), Msg.begin(), ::toupper); +} + +// --------------------------------- +// Emit MC Instruction +// --------------------------------- +#define EMIT_MC_INST +#ifdef EMIT_MC_INST +#include "riscv_support.h" + +template +static void EmitMCOpcode(std::ostream &OS, const T &X) { + std::string Msg; + getMessageName(X, Msg); + unsigned MCOpcode; + if (getMCOpcode(Msg, MCOpcode)) + OS << " #" << MCOpcode << ' ' << Msg; + else + OS << " #ERROR " << Msg; +} + +static void CheckAndEmitMCOpcode(std::ostream &OS, const Opcode &X) { + if (X.has_opcode1()) + EmitMCOpcode(OS, X.opcode1()); + else if (X.has_opcode2()) + EmitMCOpcode(OS, X.opcode2()); + else if (X.has_opcode3()) + EmitMCOpcode(OS, X.opcode3()); + else if (X.has_opcode4()) + EmitMCOpcode(OS, X.opcode4()); + else if (X.has_opcode5()) + EmitMCOpcode(OS, X.opcode5()); + else if (X.has_opcode6()) + EmitMCOpcode(OS, X.opcode6()); + else if (X.has_opcode7()) + EmitMCOpcode(OS, X.opcode7()); + else if (X.has_opcode8()) + EmitMCOpcode(OS, X.opcode8()); + else if (X.has_opcode9()) + EmitMCOpcode(OS, X.opcode9()); + else if (X.has_opcode10()) + EmitMCOpcode(OS, X.opcode10()); + else if (X.has_opcode11()) + EmitMCOpcode(OS, X.opcode11()); + else if (X.has_opcode12()) + EmitMCOpcode(OS, X.opcode12()); + else if (X.has_opcode13()) + EmitMCOpcode(OS, X.opcode13()); + else if (X.has_opcode14()) + EmitMCOpcode(OS, X.opcode14()); + else if (X.has_opcode15()) + EmitMCOpcode(OS, X.opcode15()); + else if (X.has_opcode16()) + EmitMCOpcode(OS, X.opcode16()); + else if (X.has_opcode17()) + EmitMCOpcode(OS, X.opcode17()); + else if (X.has_opcode18()) + EmitMCOpcode(OS, X.opcode18()); + else if (X.has_opcode19()) + EmitMCOpcode(OS, X.opcode19()); + else if (X.has_opcode20()) + EmitMCOpcode(OS, X.opcode20()); + else if (X.has_opcode21()) + EmitMCOpcode(OS, X.opcode21()); + else if (X.has_opcode22()) + EmitMCOpcode(OS, X.opcode22()); + else if (X.has_opcode23()) + EmitMCOpcode(OS, X.opcode23()); + else if (X.has_opcode24()) + EmitMCOpcode(OS, X.opcode24()); + else if (X.has_opcode25()) + EmitMCOpcode(OS, X.opcode25()); + else if (X.has_opcode26()) + EmitMCOpcode(OS, X.opcode26()); + else if (X.has_opcode27()) + EmitMCOpcode(OS, X.opcode27()); + else if (X.has_opcode28()) + EmitMCOpcode(OS, X.opcode28()); + else if (X.has_opcode29()) + EmitMCOpcode(OS, X.opcode29()); + else if (X.has_opcode30()) + EmitMCOpcode(OS, X.opcode30()); + else if (X.has_opcode31()) + EmitMCOpcode(OS, X.opcode31()); + else if (X.has_opcode32()) + EmitMCOpcode(OS, X.opcode32()); + else if (X.has_opcode33()) + EmitMCOpcode(OS, X.opcode33()); + else if (X.has_opcode34()) + EmitMCOpcode(OS, X.opcode34()); + else if (X.has_opcode35()) + EmitMCOpcode(OS, X.opcode35()); + else if (X.has_opcode36()) + EmitMCOpcode(OS, X.opcode36()); + else if (X.has_opcode37()) + EmitMCOpcode(OS, X.opcode37()); + else if (X.has_opcode38()) + EmitMCOpcode(OS, X.opcode38()); + else if (X.has_opcode39()) + EmitMCOpcode(OS, X.opcode39()); + else if (X.has_opcode40()) + EmitMCOpcode(OS, X.opcode40()); + else if (X.has_opcode41()) + EmitMCOpcode(OS, X.opcode41()); + else if (X.has_opcode42()) + EmitMCOpcode(OS, X.opcode42()); + else if (X.has_opcode43()) + EmitMCOpcode(OS, X.opcode43()); + else if (X.has_opcode44()) + EmitMCOpcode(OS, X.opcode44()); + else if (X.has_opcode45()) + EmitMCOpcode(OS, X.opcode45()); + else if (X.has_opcode46()) + EmitMCOpcode(OS, X.opcode46()); + else if (X.has_opcode47()) + EmitMCOpcode(OS, X.opcode47()); + else if (X.has_opcode48()) + EmitMCOpcode(OS, X.opcode48()); + else if (X.has_opcode49()) + EmitMCOpcode(OS, X.opcode49()); + else if (X.has_opcode50()) + EmitMCOpcode(OS, X.opcode50()); + else if (X.has_opcode51()) + EmitMCOpcode(OS, X.opcode51()); + else if (X.has_opcode52()) + EmitMCOpcode(OS, X.opcode52()); + else if (X.has_opcode53()) + EmitMCOpcode(OS, X.opcode53()); + else if (X.has_opcode54()) + EmitMCOpcode(OS, X.opcode54()); + else if (X.has_opcode55()) + EmitMCOpcode(OS, X.opcode55()); + else if (X.has_opcode56()) + EmitMCOpcode(OS, X.opcode56()); + else if (X.has_opcode57()) + EmitMCOpcode(OS, X.opcode57()); + else if (X.has_opcode58()) + EmitMCOpcode(OS, X.opcode58()); + else if (X.has_opcode59()) + EmitMCOpcode(OS, X.opcode59()); + else if (X.has_opcode60()) + EmitMCOpcode(OS, X.opcode60()); + else if (X.has_opcode61()) + EmitMCOpcode(OS, X.opcode61()); + else if (X.has_opcode62()) + EmitMCOpcode(OS, X.opcode62()); + else if (X.has_opcode63()) + EmitMCOpcode(OS, X.opcode63()); + else if (X.has_opcode64()) + EmitMCOpcode(OS, X.opcode64()); + else if (X.has_opcode65()) + EmitMCOpcode(OS, X.opcode65()); + else if (X.has_opcode66()) + EmitMCOpcode(OS, X.opcode66()); + else if (X.has_opcode67()) + EmitMCOpcode(OS, X.opcode67()); + else if (X.has_opcode68()) + EmitMCOpcode(OS, X.opcode68()); + else { + auto Msg = "ADD"; + unsigned MCOpcode; + if (getMCOpcode(Msg, MCOpcode)) + OS << " #" << MCOpcode << ' ' << Msg; + else + OS << " #ERROR " << Msg; + } +} + +static void EmitMCOperand(std::ostream &OS, const IORWString &X, + bool UseSymbol = false) { + std::string S; + std::string C; + for (auto &IORWChar : X.iorwstr()) { + getMessageName(IORWChar, C); + S += C; + } + if (UseSymbol) + OS << S; + else { + std::transform(S.begin(), S.end(), S.begin(), ::tolower); + unsigned Imm; + if (getMCIORW(S, Imm)) + OS << "Imm:" << Imm; + else + OS << "Imm:ERROR-IORW"; + } +} + +static void EmitMCOperand(std::ostream &OS, const RoundingMode &X, + bool UseSymbol = false) { + std::string S; + getMessageName(X, S); + if (UseSymbol) + OS << S; + else { + unsigned Imm; + std::transform(S.begin(), S.end(), S.begin(), ::tolower); + if (getMCRoundingMode(S, Imm)) + OS << "Imm:" << Imm; + else + OS << "Imm:ERROR-RoundingMode"; + } +} + +static void EmitMCOperand(std::ostream &OS, const Register &X, + bool UseSymbol = false) { + std::string Reg; + if (X.has_reg1()) + getMessageName(X.reg1(), Reg); + else if (X.has_reg2()) + getMessageName(X.reg2(), Reg); + else + Reg = "X0"; + + if (UseSymbol) + OS << Reg; + else { + unsigned MCReg; + if (getMCReg(Reg, MCReg)) + OS << "Reg:" << MCReg; + else + OS << "Reg:ERROR"; + } +} + +static void EmitMCOperand(std::ostream &OS, const Label &X) { + bool HasSuffix = false; + std::string Suffix; + if (X.has_suffix()) { + HasSuffix = true; + getMessageName(X.suffix(), Suffix); + std::transform(Suffix.begin(), Suffix.end(), Suffix.begin(), ::tolower); + } + + // FIXME: Using a default text label. + if (X.has_num()) { + if (HasSuffix) + OS << "Expr:(" << X.num() << Suffix << ")"; + else + OS << "Imm:" << X.num(); + } + else + OS << "Expr:(" << "foo" << ")"; +} + +static void EmitMCOperand(std::ostream &OS, const Immediate &X) { + if (X.has_s_imm()) { + OS << "Imm:"; + OS << X.s_imm(); + } else if (X.has_u_imm()) { + OS << "Imm:"; + OS << X.u_imm(); + } else if (X.has_label()) + EmitMCOperand(OS, X.label()); + else + OS << "Imm:0"; +} + +static void EmitMCOperand(std::ostream &OS, const ImmRegPair &X) { + // Emit register followed by immediate. + EmitMCOperand(OS, X.reg()); + OS << ">"; + OS << "\n# "; +} + +static void EmitMC(std::ostream &OS, const AsmStmt &X) { + OS << "# \n"; +} + +#endif // EMIT_MC_INST + + + +// --------------------------------- +// Emit Assembly Instruction +// --------------------------------- +template +static void EmitAsm(std::ostream &OS, const T &X, + bool SkipReplace = false) { + std::string Msg; + getMessageName(X, Msg); std::transform(Msg.begin(), Msg.end(), Msg.begin(), ::tolower); if (!SkipReplace) std::replace(Msg.begin(), Msg.end(), '_', '.'); OS << Msg; } -namespace mc_proto_fuzzer { - template void Emit(std::ostream &OS, const T &X) { - const EnumDescriptor *ED = X.ValueRange_descriptor(); - EmitAsm(OS, ED, X.value()); + EmitAsm(OS, X); } std::ostream &operator<<(std::ostream &OS, const IORWString &X) { @@ -56,8 +403,7 @@ } std::ostream &operator<<(std::ostream &OS, const Modifier &X) { - const EnumDescriptor *ED = X.ValueRange_descriptor(); - EmitAsm(OS, ED, X.value(), true /* SkipReplace */); + EmitAsm(OS, X, true /* SkipReplace */); return OS; } @@ -282,19 +628,24 @@ std::ostream &operator<<(std::ostream &OS, const AsmStmt &X) { OS << "\t" << X.opcode() << "\t"; - int NumOperands = 0; + bool FirstOp = true; for (auto &Opnd : X.operands()) { - if (NumOperands != 0) - OS << ","; + if (FirstOp) + FirstOp = false; + else + OS << ','; OS << Opnd; - ++NumOperands; } return OS << "\n"; } std::ostream &operator<<(std::ostream &OS, const Assembly &X) { - for (auto &ST : X.stmts()) + for (auto &ST : X.stmts()) { OS << ST; +#ifdef EMIT_MC_INST + EmitMC(OS, ST); +#endif + } return OS; } Index: tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/riscv_support.h =================================================================== --- /dev/null +++ tools/llvm-mc-assemble-proto-fuzzer/proto-to-asm/riscv_support.h @@ -0,0 +1,219 @@ +//===- riscv_support.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits llvm-exegesis information. +// +//===----------------------------------------------------------------------===// + +// Defines symbolic names for RISC-V registers. +#define GET_REGINFO_ENUM +#include "RISCVGenRegisterInfo.inc" + +// Defines symbolic names for RISC-V instructions. +#define GET_INSTRINFO_ENUM +#include "RISCVGenInstrInfo.inc" + +using namespace llvm; + +static std::map MCOpcodeMap { + {"ADD", RISCV::ADD}, + {"SUB", RISCV::SUB} +}; + +static std::map MCRegMap { + {"X0", RISCV::X0}, + {"X1", RISCV::X1}, + {"X2", RISCV::X2}, + {"X3", RISCV::X3}, + {"X4", RISCV::X4}, + {"X5", RISCV::X5}, + {"X6", RISCV::X6}, + {"X7", RISCV::X7}, + {"X8", RISCV::X8}, + {"X9", RISCV::X9}, + {"X10", RISCV::X10}, + {"X11", RISCV::X11}, + {"X12", RISCV::X12}, + {"X13", RISCV::X13}, + {"X14", RISCV::X14}, + {"X15", RISCV::X15}, + {"X16", RISCV::X16}, + {"X17", RISCV::X17}, + {"X18", RISCV::X18}, + {"X19", RISCV::X19}, + {"X20", RISCV::X20}, + {"X21", RISCV::X21}, + {"X22", RISCV::X22}, + {"X23", RISCV::X23}, + {"X24", RISCV::X24}, + {"X25", RISCV::X25}, + {"X26", RISCV::X26}, + {"X27", RISCV::X27}, + {"X28", RISCV::X28}, + {"X29", RISCV::X29}, + {"X30", RISCV::X30}, + {"X31", RISCV::X31}, + + // ABI names + {"ZERO", RISCV::X0}, + {"RA", RISCV::X1}, + {"SP", RISCV::X2}, + {"GP", RISCV::X3}, + {"TP", RISCV::X4}, + {"T0", RISCV::X5}, + {"T1", RISCV::X6}, + {"T2", RISCV::X7}, + {"S0", RISCV::X8}, + {"S1", RISCV::X9}, + {"A0", RISCV::X10}, + {"A1", RISCV::X11}, + {"A2", RISCV::X12}, + {"A3", RISCV::X13}, + {"A4", RISCV::X14}, + {"A5", RISCV::X15}, + {"A6", RISCV::X16}, + {"A7", RISCV::X17}, + {"S2", RISCV::X18}, + {"S3", RISCV::X19}, + {"S4", RISCV::X20}, + {"S5", RISCV::X21}, + {"S6", RISCV::X22}, + {"S7", RISCV::X23}, + {"S8", RISCV::X24}, + {"S9", RISCV::X25}, + {"S10", RISCV::X26}, + {"S11", RISCV::X27}, + {"T3", RISCV::X28}, + {"T4", RISCV::X29}, + {"T5", RISCV::X30}, + {"T6", RISCV::X31}, + + + //TODO: Map 64 bit registers. + {"F0", RISCV::F0_32}, + {"F1", RISCV::F1_32}, + {"F2", RISCV::F2_32}, + {"F3", RISCV::F3_32}, + {"F4", RISCV::F4_32}, + {"F5", RISCV::F5_32}, + {"F6", RISCV::F6_32}, + {"F7", RISCV::F7_32}, + {"F8", RISCV::F8_32}, + {"F9", RISCV::F9_32}, + {"F10", RISCV::F10_32}, + {"F11", RISCV::F11_32}, + {"F12", RISCV::F12_32}, + {"F13", RISCV::F13_32}, + {"F14", RISCV::F14_32}, + {"F15", RISCV::F15_32}, + {"F16", RISCV::F16_32}, + {"F17", RISCV::F17_32}, + {"F18", RISCV::F18_32}, + {"F19", RISCV::F19_32}, + {"F20", RISCV::F20_32}, + {"F21", RISCV::F21_32}, + {"F22", RISCV::F22_32}, + {"F23", RISCV::F23_32}, + {"F24", RISCV::F24_32}, + {"F25", RISCV::F25_32}, + {"F26", RISCV::F26_32}, + {"F27", RISCV::F27_32}, + {"F28", RISCV::F28_32}, + {"F29", RISCV::F29_32}, + {"F30", RISCV::F30_32}, + {"F31", RISCV::F31_32}, + + // ABI Names + //TODO: Map 64 bit registers. + {"FT0", RISCV::F0_32}, + {"FT1", RISCV::F1_32}, + {"FT2", RISCV::F2_32}, + {"FT3", RISCV::F3_32}, + {"FT4", RISCV::F4_32}, + {"FT5", RISCV::F5_32}, + {"FT6", RISCV::F6_32}, + {"FT7", RISCV::F7_32}, + {"FS0", RISCV::F8_32}, + {"FS1", RISCV::F9_32}, + {"FA0", RISCV::F10_32}, + {"FA1", RISCV::F11_32}, + {"FA2", RISCV::F12_32}, + {"FA3", RISCV::F13_32}, + {"FA4", RISCV::F14_32}, + {"FA5", RISCV::F15_32}, + {"FA6", RISCV::F16_32}, + {"FA7", RISCV::F17_32}, + {"FS2", RISCV::F18_32}, + {"FS3", RISCV::F19_32}, + {"FS4", RISCV::F20_32}, + {"FS5", RISCV::F21_32}, + {"FS6", RISCV::F22_32}, + {"FS7", RISCV::F23_32}, + {"FS8", RISCV::F24_32}, + {"FS9", RISCV::F25_32}, + {"FS10", RISCV::F26_32}, + {"FS11", RISCV::F27_32}, + {"FT8", RISCV::F28_32}, + {"FT9", RISCV::F29_32}, + {"FT10", RISCV::F30_32}, + {"FT11", RISCV::F31_32} +}; + +namespace { +static bool getMCOpcode(const std::string &Opcode, unsigned &MCOpcode) { + auto I = MCOpcodeMap.find(Opcode); + if (I == MCOpcodeMap.end()) + return false; + MCOpcode = I->second; + return true; +} + +static bool getMCReg(const std::string &Opcode, unsigned &MCReg) { + auto I = MCRegMap.find(Opcode); + if (I == MCRegMap.end()) + return false; + MCReg = I->second; + return true; +} + +static bool getMCIORW(const std::string &IORW, unsigned &Imm) { + Imm = 0; + for (auto c: IORW) + switch (c) { + default: + return false; + case 'i': Imm |= 8; break; + case 'o': Imm |= 4; break; + case 'r': Imm |= 2; break; + case 'w': Imm |= 1; break; + } + if ((Imm >> 4) != 0) + return false; + return true; +} + +static std::map MCRoundModeMap { + {"rne", 0}, + {"rtz", 1}, + {"rdn", 2}, + {"rup", 3}, + {"rmm", 4}, + {"dyn", 7} +}; + + +static bool getMCRoundingMode(const std::string &Mode, unsigned &Imm) { + auto I = MCRoundModeMap.find(Mode); + if (I == MCRoundModeMap.end()) + return false; + Imm = I->second; + return true; +} +} // end anonymous namespace. +