123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866 |
- //===-- RISCVInstrInfo.td - Target Description for RISCV ---*- tablegen -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file describes the RISC-V instructions in TableGen format.
- //
- //===----------------------------------------------------------------------===//
- //===----------------------------------------------------------------------===//
- // RISC-V specific DAG Nodes.
- //===----------------------------------------------------------------------===//
- // Target-independent type requirements, but with target-specific formats.
- def SDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>,
- SDTCisVT<1, i32>]>;
- def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>,
- SDTCisVT<1, i32>]>;
- // Target-dependent type requirements.
- def SDT_RISCVCall : SDTypeProfile<0, -1, [SDTCisVT<0, XLenVT>]>;
- def SDT_RISCVSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>,
- SDTCisVT<3, OtherVT>,
- SDTCisSameAs<0, 4>,
- SDTCisSameAs<4, 5>]>;
- def SDT_RISCVBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>,
- SDTCisVT<2, OtherVT>,
- SDTCisVT<3, OtherVT>]>;
- def SDT_RISCVReadCSR : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisInt<1>]>;
- def SDT_RISCVWriteCSR : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisInt<1>]>;
- def SDT_RISCVSwapCSR : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisInt<1>,
- SDTCisInt<2>]>;
- def SDT_RISCVReadCycleWide : SDTypeProfile<2, 0, [SDTCisVT<0, i32>,
- SDTCisVT<1, i32>]>;
- def SDT_RISCVIntUnaryOpW : SDTypeProfile<1, 1, [
- SDTCisSameAs<0, 1>, SDTCisVT<0, i64>
- ]>;
- def SDT_RISCVIntBinOpW : SDTypeProfile<1, 2, [
- SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i64>
- ]>;
- def SDT_RISCVIntShiftDOpW : SDTypeProfile<1, 3, [
- SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i64>, SDTCisVT<3, i64>
- ]>;
- // Target-independent nodes, but with target-specific formats.
- def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart,
- [SDNPHasChain, SDNPOutGlue]>;
- def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd,
- [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
- // Target-dependent nodes.
- def riscv_call : SDNode<"RISCVISD::CALL", SDT_RISCVCall,
- [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
- SDNPVariadic]>;
- def riscv_ret_flag : SDNode<"RISCVISD::RET_FLAG", SDTNone,
- [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
- def riscv_uret_flag : SDNode<"RISCVISD::URET_FLAG", SDTNone,
- [SDNPHasChain, SDNPOptInGlue]>;
- def riscv_sret_flag : SDNode<"RISCVISD::SRET_FLAG", SDTNone,
- [SDNPHasChain, SDNPOptInGlue]>;
- def riscv_mret_flag : SDNode<"RISCVISD::MRET_FLAG", SDTNone,
- [SDNPHasChain, SDNPOptInGlue]>;
- def riscv_selectcc : SDNode<"RISCVISD::SELECT_CC", SDT_RISCVSelectCC>;
- def riscv_brcc : SDNode<"RISCVISD::BR_CC", SDT_RISCVBrCC,
- [SDNPHasChain]>;
- def riscv_tail : SDNode<"RISCVISD::TAIL", SDT_RISCVCall,
- [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
- SDNPVariadic]>;
- def riscv_sllw : SDNode<"RISCVISD::SLLW", SDT_RISCVIntBinOpW>;
- def riscv_sraw : SDNode<"RISCVISD::SRAW", SDT_RISCVIntBinOpW>;
- def riscv_srlw : SDNode<"RISCVISD::SRLW", SDT_RISCVIntBinOpW>;
- def riscv_read_csr : SDNode<"RISCVISD::READ_CSR", SDT_RISCVReadCSR,
- [SDNPHasChain]>;
- def riscv_write_csr : SDNode<"RISCVISD::WRITE_CSR", SDT_RISCVWriteCSR,
- [SDNPHasChain]>;
- def riscv_swap_csr : SDNode<"RISCVISD::SWAP_CSR", SDT_RISCVSwapCSR,
- [SDNPHasChain]>;
- def riscv_read_cycle_wide : SDNode<"RISCVISD::READ_CYCLE_WIDE",
- SDT_RISCVReadCycleWide,
- [SDNPHasChain, SDNPSideEffect]>;
- def riscv_add_lo : SDNode<"RISCVISD::ADD_LO", SDTIntBinOp>;
- def riscv_hi : SDNode<"RISCVISD::HI", SDTIntUnaryOp>;
- def riscv_lla : SDNode<"RISCVISD::LLA", SDTIntUnaryOp>;
- def riscv_add_tprel : SDNode<"RISCVISD::ADD_TPREL",
- SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
- SDTCisSameAs<0, 2>,
- SDTCisSameAs<0, 3>,
- SDTCisInt<0>]>>;
- def riscv_la : SDNode<"RISCVISD::LA", SDTLoad,
- [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
- def riscv_la_tls_ie : SDNode<"RISCVISD::LA_TLS_IE", SDTLoad,
- [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
- def riscv_la_tls_gd : SDNode<"RISCVISD::LA_TLS_GD", SDTIntUnaryOp>;
- //===----------------------------------------------------------------------===//
- // Operand and SDNode transformation definitions.
- //===----------------------------------------------------------------------===//
- class ImmXLenAsmOperand<string prefix, string suffix = ""> : AsmOperandClass {
- let Name = prefix # "ImmXLen" # suffix;
- let RenderMethod = "addImmOperands";
- let DiagnosticType = !strconcat("Invalid", Name);
- }
- class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
- let Name = prefix # "Imm" # width # suffix;
- let RenderMethod = "addImmOperands";
- let DiagnosticType = !strconcat("Invalid", Name);
- }
- def ImmZeroAsmOperand : AsmOperandClass {
- let Name = "ImmZero";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = !strconcat("Invalid", Name);
- }
- // A parse method for (${gpr}) or 0(${gpr}), where the 0 is be silently ignored.
- def ZeroOffsetMemOpOperand : AsmOperandClass {
- let Name = "ZeroOffsetMemOpOperand";
- let RenderMethod = "addRegOperands";
- let PredicateMethod = "isGPR";
- let ParserMethod = "parseZeroOffsetMemOp";
- }
- class MemOperand<RegisterClass regClass> : RegisterOperand<regClass>{
- let OperandType = "OPERAND_MEMORY";
- }
- def GPRMemZeroOffset : MemOperand<GPR> {
- let ParserMatchClass = ZeroOffsetMemOpOperand;
- let PrintMethod = "printZeroOffsetMemOp";
- }
- def GPRMem : MemOperand<GPR>;
- def SPMem : MemOperand<SP>;
- def GPRCMem : MemOperand<GPRC>;
- class SImmAsmOperand<int width, string suffix = "">
- : ImmAsmOperand<"S", width, suffix> {
- }
- class UImmAsmOperand<int width, string suffix = "">
- : ImmAsmOperand<"U", width, suffix> {
- }
- def FenceArg : AsmOperandClass {
- let Name = "FenceArg";
- let RenderMethod = "addFenceArgOperands";
- let DiagnosticType = "InvalidFenceArg";
- }
- def fencearg : Operand<XLenVT> {
- let ParserMatchClass = FenceArg;
- let PrintMethod = "printFenceArg";
- let DecoderMethod = "decodeUImmOperand<4>";
- let OperandType = "OPERAND_UIMM4";
- let OperandNamespace = "RISCVOp";
- }
- def UImmLog2XLenAsmOperand : AsmOperandClass {
- let Name = "UImmLog2XLen";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "InvalidUImmLog2XLen";
- }
- def uimmlog2xlen : Operand<XLenVT>, ImmLeaf<XLenVT, [{
- if (Subtarget->is64Bit())
- return isUInt<6>(Imm);
- return isUInt<5>(Imm);
- }]> {
- let ParserMatchClass = UImmLog2XLenAsmOperand;
- // TODO: should ensure invalid shamt is rejected when decoding.
- let DecoderMethod = "decodeUImmOperand<6>";
- let MCOperandPredicate = [{
- int64_t Imm;
- if (!MCOp.evaluateAsConstantImm(Imm))
- return false;
- if (STI.getTargetTriple().isArch64Bit())
- return isUInt<6>(Imm);
- return isUInt<5>(Imm);
- }];
- let OperandType = "OPERAND_UIMMLOG2XLEN";
- let OperandNamespace = "RISCVOp";
- }
- def uimm2 : Operand<XLenVT> {
- let ParserMatchClass = UImmAsmOperand<2>;
- let DecoderMethod = "decodeUImmOperand<2>";
- let OperandType = "OPERAND_UIMM2";
- let OperandNamespace = "RISCVOp";
- }
- def uimm3 : Operand<XLenVT> {
- let ParserMatchClass = UImmAsmOperand<3>;
- let DecoderMethod = "decodeUImmOperand<3>";
- let OperandType = "OPERAND_UIMM3";
- let OperandNamespace = "RISCVOp";
- }
- def uimm5 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]> {
- let ParserMatchClass = UImmAsmOperand<5>;
- let DecoderMethod = "decodeUImmOperand<5>";
- let OperandType = "OPERAND_UIMM5";
- let OperandNamespace = "RISCVOp";
- }
- def InsnDirectiveOpcode : AsmOperandClass {
- let Name = "InsnDirectiveOpcode";
- let ParserMethod = "parseInsnDirectiveOpcode";
- let RenderMethod = "addImmOperands";
- let PredicateMethod = "isImm";
- }
- def uimm7_opcode : Operand<XLenVT> {
- let ParserMatchClass = InsnDirectiveOpcode;
- let DecoderMethod = "decodeUImmOperand<7>";
- let OperandType = "OPERAND_UIMM7";
- let OperandNamespace = "RISCVOp";
- }
- def uimm7 : Operand<XLenVT> {
- let ParserMatchClass = UImmAsmOperand<7>;
- let DecoderMethod = "decodeUImmOperand<7>";
- let OperandType = "OPERAND_UIMM7";
- let OperandNamespace = "RISCVOp";
- }
- def simm12 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<12>(Imm);}]> {
- let ParserMatchClass = SImmAsmOperand<12>;
- let EncoderMethod = "getImmOpValue";
- let DecoderMethod = "decodeSImmOperand<12>";
- let MCOperandPredicate = [{
- int64_t Imm;
- if (MCOp.evaluateAsConstantImm(Imm))
- return isInt<12>(Imm);
- return MCOp.isBareSymbolRef();
- }];
- let OperandType = "OPERAND_SIMM12";
- let OperandNamespace = "RISCVOp";
- }
- // A 12-bit signed immediate which cannot fit in 6-bit signed immediate,
- // but even negative value fit in 12-bit.
- def simm12_no6 : ImmLeaf<XLenVT, [{
- return isInt<12>(Imm) && !isInt<6>(Imm) && isInt<12>(-Imm);}]>;
- // A 13-bit signed immediate where the least significant bit is zero.
- def simm13_lsb0 : Operand<OtherVT> {
- let ParserMatchClass = SImmAsmOperand<13, "Lsb0">;
- let PrintMethod = "printBranchOperand";
- let EncoderMethod = "getImmOpValueAsr1";
- let DecoderMethod = "decodeSImmOperandAndLsl1<13>";
- let MCOperandPredicate = [{
- int64_t Imm;
- if (MCOp.evaluateAsConstantImm(Imm))
- return isShiftedInt<12, 1>(Imm);
- return MCOp.isBareSymbolRef();
- }];
- let OperandType = "OPERAND_PCREL";
- }
- class UImm20Operand : Operand<XLenVT> {
- let EncoderMethod = "getImmOpValue";
- let DecoderMethod = "decodeUImmOperand<20>";
- let MCOperandPredicate = [{
- int64_t Imm;
- if (MCOp.evaluateAsConstantImm(Imm))
- return isUInt<20>(Imm);
- return MCOp.isBareSymbolRef();
- }];
- let OperandType = "OPERAND_UIMM20";
- let OperandNamespace = "RISCVOp";
- }
- def uimm20_lui : UImm20Operand {
- let ParserMatchClass = UImmAsmOperand<20, "LUI">;
- }
- def uimm20_auipc : UImm20Operand {
- let ParserMatchClass = UImmAsmOperand<20, "AUIPC">;
- }
- def Simm21Lsb0JALAsmOperand : SImmAsmOperand<21, "Lsb0JAL"> {
- let ParserMethod = "parseJALOffset";
- }
- // A 21-bit signed immediate where the least significant bit is zero.
- def simm21_lsb0_jal : Operand<OtherVT> {
- let ParserMatchClass = Simm21Lsb0JALAsmOperand;
- let PrintMethod = "printBranchOperand";
- let EncoderMethod = "getImmOpValueAsr1";
- let DecoderMethod = "decodeSImmOperandAndLsl1<21>";
- let MCOperandPredicate = [{
- int64_t Imm;
- if (MCOp.evaluateAsConstantImm(Imm))
- return isShiftedInt<20, 1>(Imm);
- return MCOp.isBareSymbolRef();
- }];
- let OperandType = "OPERAND_PCREL";
- }
- def BareSymbol : AsmOperandClass {
- let Name = "BareSymbol";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "InvalidBareSymbol";
- let ParserMethod = "parseBareSymbol";
- }
- // A bare symbol.
- def bare_symbol : Operand<XLenVT> {
- let ParserMatchClass = BareSymbol;
- }
- def CallSymbol : AsmOperandClass {
- let Name = "CallSymbol";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "InvalidCallSymbol";
- let ParserMethod = "parseCallSymbol";
- }
- // A bare symbol used in call/tail only.
- def call_symbol : Operand<XLenVT> {
- let ParserMatchClass = CallSymbol;
- }
- def PseudoJumpSymbol : AsmOperandClass {
- let Name = "PseudoJumpSymbol";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "InvalidPseudoJumpSymbol";
- let ParserMethod = "parsePseudoJumpSymbol";
- }
- // A bare symbol used for pseudo jumps only.
- def pseudo_jump_symbol : Operand<XLenVT> {
- let ParserMatchClass = PseudoJumpSymbol;
- }
- def TPRelAddSymbol : AsmOperandClass {
- let Name = "TPRelAddSymbol";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "InvalidTPRelAddSymbol";
- let ParserMethod = "parseOperandWithModifier";
- }
- // A bare symbol with the %tprel_add variant.
- def tprel_add_symbol : Operand<XLenVT> {
- let ParserMatchClass = TPRelAddSymbol;
- }
- def CSRSystemRegister : AsmOperandClass {
- let Name = "CSRSystemRegister";
- let ParserMethod = "parseCSRSystemRegister";
- let DiagnosticType = "InvalidCSRSystemRegister";
- }
- def csr_sysreg : Operand<XLenVT> {
- let ParserMatchClass = CSRSystemRegister;
- let PrintMethod = "printCSRSystemRegister";
- let DecoderMethod = "decodeUImmOperand<12>";
- let OperandType = "OPERAND_UIMM12";
- let OperandNamespace = "RISCVOp";
- }
- // A parameterized register class alternative to i32imm/i64imm from Target.td.
- def ixlenimm : Operand<XLenVT>;
- def ixlenimm_li : Operand<XLenVT> {
- let ParserMatchClass = ImmXLenAsmOperand<"", "LI">;
- }
- // Standalone (codegen-only) immleaf patterns.
- // A 12-bit signed immediate plus one where the imm range will be [-2047, 2048].
- def simm12_plus1 : ImmLeaf<XLenVT,
- [{return (isInt<12>(Imm) && Imm != -2048) || Imm == 2048;}]>;
- // A 6-bit constant greater than 32.
- def uimm6gt32 : ImmLeaf<XLenVT, [{
- return isUInt<6>(Imm) && Imm > 32;
- }]>;
- // Addressing modes.
- // Necessary because a frameindex can't be matched directly in a pattern.
- def FrameAddrRegImm : ComplexPattern<iPTR, 2, "SelectFrameAddrRegImm",
- [frameindex, or, add]>;
- def AddrRegImm : ComplexPattern<iPTR, 2, "SelectAddrRegImm">;
- // Return the negation of an immediate value.
- def NegImm : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(-N->getSExtValue(), SDLoc(N),
- N->getValueType(0));
- }]>;
- // Return an immediate value minus 32.
- def ImmSub32 : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(N->getSExtValue() - 32, SDLoc(N),
- N->getValueType(0));
- }]>;
- // Return an immediate subtracted from XLen.
- def ImmSubFromXLen : SDNodeXForm<imm, [{
- uint64_t XLen = Subtarget->getXLen();
- return CurDAG->getTargetConstant(XLen - N->getZExtValue(), SDLoc(N),
- N->getValueType(0));
- }]>;
- // Return an immediate subtracted from 32.
- def ImmSubFrom32 : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(32 - N->getZExtValue(), SDLoc(N),
- N->getValueType(0));
- }]>;
- // Check if (add r, imm) can be optimized to (ADDI (ADDI r, imm0), imm1),
- // in which imm = imm0 + imm1 and both imm0 and imm1 are simm12. We make imm0
- // as large as possible and imm1 as small as possible so that we might be able
- // to use c.addi for the small immediate.
- def AddiPair : PatLeaf<(imm), [{
- if (!N->hasOneUse())
- return false;
- // The immediate operand must be in range [-4096,-2049] or [2048,4094].
- int64_t Imm = N->getSExtValue();
- return (-4096 <= Imm && Imm <= -2049) || (2048 <= Imm && Imm <= 4094);
- }]>;
- // Return imm - (imm < 0 ? -2048 : 2047).
- def AddiPairImmSmall : SDNodeXForm<imm, [{
- int64_t Imm = N->getSExtValue();
- int64_t Adj = N->getSExtValue() < 0 ? -2048 : 2047;
- return CurDAG->getTargetConstant(Imm - Adj, SDLoc(N),
- N->getValueType(0));
- }]>;
- // Return -2048 if immediate is negative or 2047 if positive. These are the
- // largest simm12 values.
- def AddiPairImmLarge : SDNodeXForm<imm, [{
- int64_t Imm = N->getSExtValue() < 0 ? -2048 : 2047;
- return CurDAG->getTargetConstant(Imm, SDLoc(N),
- N->getValueType(0));
- }]>;
- def TrailingZeros : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(countTrailingZeros(N->getZExtValue()),
- SDLoc(N), N->getValueType(0));
- }]>;
- def XLenSubTrailingOnes : SDNodeXForm<imm, [{
- uint64_t XLen = Subtarget->getXLen();
- uint64_t TrailingOnes = countTrailingOnes(N->getZExtValue());
- return CurDAG->getTargetConstant(XLen - TrailingOnes, SDLoc(N),
- N->getValueType(0));
- }]>;
- // Checks if this mask is a non-empty sequence of ones starting at the
- // most/least significant bit with the remainder zero and exceeds simm32/simm12.
- def LeadingOnesMask : PatLeaf<(imm), [{
- if (!N->hasOneUse())
- return false;
- return !isInt<32>(N->getSExtValue()) && isMask_64(~N->getSExtValue());
- }], TrailingZeros>;
- def TrailingOnesMask : PatLeaf<(imm), [{
- if (!N->hasOneUse())
- return false;
- return !isInt<12>(N->getSExtValue()) && isMask_64(N->getZExtValue());
- }], XLenSubTrailingOnes>;
- // Similar to LeadingOnesMask, but only consider leading ones in the lower 32
- // bits.
- def LeadingOnesWMask : PatLeaf<(imm), [{
- if (!N->hasOneUse())
- return false;
- // If the value is a uint32 but not an int32, it must have bit 31 set and
- // bits 63:32 cleared. After that we're looking for a shifted mask but not
- // an all ones mask.
- int64_t Imm = N->getSExtValue();
- return !isInt<32>(Imm) && isUInt<32>(Imm) && isShiftedMask_64(Imm) &&
- Imm != UINT64_C(0xffffffff);
- }], TrailingZeros>;
- //===----------------------------------------------------------------------===//
- // Instruction Formats
- //===----------------------------------------------------------------------===//
- include "RISCVInstrFormats.td"
- //===----------------------------------------------------------------------===//
- // Instruction Class Templates
- //===----------------------------------------------------------------------===//
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- class BranchCC_rri<bits<3> funct3, string opcodestr>
- : RVInstB<funct3, OPC_BRANCH, (outs),
- (ins GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12),
- opcodestr, "$rs1, $rs2, $imm12">,
- Sched<[WriteJmp, ReadJmp, ReadJmp]> {
- let isBranch = 1;
- let isTerminator = 1;
- }
- let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
- class Load_ri<bits<3> funct3, string opcodestr>
- : RVInstI<funct3, OPC_LOAD, (outs GPR:$rd), (ins GPRMem:$rs1, simm12:$imm12),
- opcodestr, "$rd, ${imm12}(${rs1})">;
- class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
- : RVInstR<funct7, 0b100, OPC_SYSTEM, (outs GPR:$rd),
- (ins GPRMemZeroOffset:$rs1), opcodestr, "$rd, $rs1"> {
- let rs2 = funct5;
- }
- }
- // Operands for stores are in the order srcreg, base, offset rather than
- // reflecting the order these fields are specified in the instruction
- // encoding.
- let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
- class Store_rri<bits<3> funct3, string opcodestr>
- : RVInstS<funct3, OPC_STORE, (outs),
- (ins GPR:$rs2, GPRMem:$rs1, simm12:$imm12),
- opcodestr, "$rs2, ${imm12}(${rs1})">;
- class HStore_rr<bits<7> funct7, string opcodestr>
- : RVInstR<funct7, 0b100, OPC_SYSTEM, (outs),
- (ins GPR:$rs2, GPRMemZeroOffset:$rs1),
- opcodestr, "$rs2, $rs1"> {
- let rd = 0;
- }
- }
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- class ALU_ri<bits<3> funct3, string opcodestr>
- : RVInstI<funct3, OPC_OP_IMM, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12),
- opcodestr, "$rd, $rs1, $imm12">,
- Sched<[WriteIALU, ReadIALU]>;
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- class Shift_ri<bits<5> imm11_7, bits<3> funct3, string opcodestr>
- : RVInstIShift<imm11_7, funct3, OPC_OP_IMM, (outs GPR:$rd),
- (ins GPR:$rs1, uimmlog2xlen:$shamt), opcodestr,
- "$rd, $rs1, $shamt">,
- Sched<[WriteShiftImm, ReadShiftImm]>;
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- class ALU_rr<bits<7> funct7, bits<3> funct3, string opcodestr,
- bit Commutable = 0>
- : RVInstR<funct7, funct3, OPC_OP, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2),
- opcodestr, "$rd, $rs1, $rs2"> {
- let isCommutable = Commutable;
- }
- let hasNoSchedulingInfo = 1,
- hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
- class CSR_ir<bits<3> funct3, string opcodestr>
- : RVInstI<funct3, OPC_SYSTEM, (outs GPR:$rd), (ins csr_sysreg:$imm12, GPR:$rs1),
- opcodestr, "$rd, $imm12, $rs1">, Sched<[WriteCSR, ReadCSR]>;
- let hasNoSchedulingInfo = 1,
- hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
- class CSR_ii<bits<3> funct3, string opcodestr>
- : RVInstI<funct3, OPC_SYSTEM, (outs GPR:$rd),
- (ins csr_sysreg:$imm12, uimm5:$rs1),
- opcodestr, "$rd, $imm12, $rs1">, Sched<[WriteCSR]>;
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- class ShiftW_ri<bits<7> imm11_5, bits<3> funct3, string opcodestr>
- : RVInstIShiftW<imm11_5, funct3, OPC_OP_IMM_32, (outs GPR:$rd),
- (ins GPR:$rs1, uimm5:$shamt), opcodestr,
- "$rd, $rs1, $shamt">,
- Sched<[WriteShiftImm32, ReadShiftImm32]>;
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- class ALUW_rr<bits<7> funct7, bits<3> funct3, string opcodestr,
- bit Commutable = 0>
- : RVInstR<funct7, funct3, OPC_OP_32, (outs GPR:$rd),
- (ins GPR:$rs1, GPR:$rs2), opcodestr, "$rd, $rs1, $rs2"> {
- let isCommutable = Commutable;
- }
- let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
- class Priv<string opcodestr, bits<7> funct7>
- : RVInstR<funct7, 0b000, OPC_SYSTEM, (outs), (ins GPR:$rs1, GPR:$rs2),
- opcodestr, "">;
- let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
- class Priv_rr<string opcodestr, bits<7> funct7>
- : RVInstR<funct7, 0b000, OPC_SYSTEM, (outs), (ins GPR:$rs1, GPR:$rs2),
- opcodestr, "$rs1, $rs2"> {
- let rd = 0;
- }
- //===----------------------------------------------------------------------===//
- // Instructions
- //===----------------------------------------------------------------------===//
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
- let isReMaterializable = 1, isAsCheapAsAMove = 1,
- IsSignExtendingOpW = 1 in
- def LUI : RVInstU<OPC_LUI, (outs GPR:$rd), (ins uimm20_lui:$imm20),
- "lui", "$rd, $imm20">, Sched<[WriteIALU]>;
- def AUIPC : RVInstU<OPC_AUIPC, (outs GPR:$rd), (ins uimm20_auipc:$imm20),
- "auipc", "$rd, $imm20">, Sched<[WriteIALU]>;
- let isCall = 1 in
- def JAL : RVInstJ<OPC_JAL, (outs GPR:$rd), (ins simm21_lsb0_jal:$imm20),
- "jal", "$rd, $imm20">, Sched<[WriteJal]>;
- let isCall = 1 in
- def JALR : RVInstI<0b000, OPC_JALR, (outs GPR:$rd),
- (ins GPR:$rs1, simm12:$imm12),
- "jalr", "$rd, ${imm12}(${rs1})">,
- Sched<[WriteJalr, ReadJalr]>;
- } // hasSideEffects = 0, mayLoad = 0, mayStore = 0
- def BEQ : BranchCC_rri<0b000, "beq">;
- def BNE : BranchCC_rri<0b001, "bne">;
- def BLT : BranchCC_rri<0b100, "blt">;
- def BGE : BranchCC_rri<0b101, "bge">;
- def BLTU : BranchCC_rri<0b110, "bltu">;
- def BGEU : BranchCC_rri<0b111, "bgeu">;
- let IsSignExtendingOpW = 1 in {
- def LB : Load_ri<0b000, "lb">, Sched<[WriteLDB, ReadMemBase]>;
- def LH : Load_ri<0b001, "lh">, Sched<[WriteLDH, ReadMemBase]>;
- def LW : Load_ri<0b010, "lw">, Sched<[WriteLDW, ReadMemBase]>;
- def LBU : Load_ri<0b100, "lbu">, Sched<[WriteLDB, ReadMemBase]>;
- def LHU : Load_ri<0b101, "lhu">, Sched<[WriteLDH, ReadMemBase]>;
- }
- def SB : Store_rri<0b000, "sb">, Sched<[WriteSTB, ReadStoreData, ReadMemBase]>;
- def SH : Store_rri<0b001, "sh">, Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
- def SW : Store_rri<0b010, "sw">, Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;
- // ADDI isn't always rematerializable, but isReMaterializable will be used as
- // a hint which is verified in isReallyTriviallyReMaterializable.
- let isReMaterializable = 1, isAsCheapAsAMove = 1 in
- def ADDI : ALU_ri<0b000, "addi">;
- let IsSignExtendingOpW = 1 in {
- def SLTI : ALU_ri<0b010, "slti">;
- def SLTIU : ALU_ri<0b011, "sltiu">;
- }
- let isReMaterializable = 1, isAsCheapAsAMove = 1 in {
- def XORI : ALU_ri<0b100, "xori">;
- def ORI : ALU_ri<0b110, "ori">;
- }
- def ANDI : ALU_ri<0b111, "andi">;
- def SLLI : Shift_ri<0b00000, 0b001, "slli">;
- def SRLI : Shift_ri<0b00000, 0b101, "srli">;
- def SRAI : Shift_ri<0b01000, 0b101, "srai">;
- def ADD : ALU_rr<0b0000000, 0b000, "add", /*Commutable*/1>,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- def SUB : ALU_rr<0b0100000, 0b000, "sub">,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- def SLL : ALU_rr<0b0000000, 0b001, "sll">,
- Sched<[WriteShiftReg, ReadShiftReg, ReadShiftReg]>;
- let IsSignExtendingOpW = 1 in {
- def SLT : ALU_rr<0b0000000, 0b010, "slt">,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- def SLTU : ALU_rr<0b0000000, 0b011, "sltu">,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- }
- def XOR : ALU_rr<0b0000000, 0b100, "xor", /*Commutable*/1>,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- def SRL : ALU_rr<0b0000000, 0b101, "srl">,
- Sched<[WriteShiftReg, ReadShiftReg, ReadShiftReg]>;
- def SRA : ALU_rr<0b0100000, 0b101, "sra">,
- Sched<[WriteShiftReg, ReadShiftReg, ReadShiftReg]>;
- def OR : ALU_rr<0b0000000, 0b110, "or", /*Commutable*/1>,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- def AND : ALU_rr<0b0000000, 0b111, "and", /*Commutable*/1>,
- Sched<[WriteIALU, ReadIALU, ReadIALU]>;
- let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in {
- def FENCE : RVInstI<0b000, OPC_MISC_MEM, (outs),
- (ins fencearg:$pred, fencearg:$succ),
- "fence", "$pred, $succ">, Sched<[]> {
- bits<4> pred;
- bits<4> succ;
- let rs1 = 0;
- let rd = 0;
- let imm12 = {0b0000,pred,succ};
- }
- def FENCE_TSO : RVInstI<0b000, OPC_MISC_MEM, (outs), (ins), "fence.tso", "">, Sched<[]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = {0b1000,0b0011,0b0011};
- }
- def FENCE_I : RVInstI<0b001, OPC_MISC_MEM, (outs), (ins), "fence.i", "">, Sched<[]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = 0;
- }
- def ECALL : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ecall", "">, Sched<[WriteJmp]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = 0;
- }
- def EBREAK : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ebreak", "">,
- Sched<[]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = 1;
- }
- // This is a de facto standard (as set by GNU binutils) 32-bit unimplemented
- // instruction (i.e., it should always trap, if your implementation has invalid
- // instruction traps).
- def UNIMP : RVInstI<0b001, OPC_SYSTEM, (outs), (ins), "unimp", "">,
- Sched<[]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = 0b110000000000;
- }
- let Predicates = [HasStdExtZawrs] in {
- def WRS_NTO : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "wrs.nto", "">,
- Sched<[]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = 0b000000001101;
- }
- def WRS_STO : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "wrs.sto", "">,
- Sched<[]> {
- let rs1 = 0;
- let rd = 0;
- let imm12 = 0b000000011101;
- }
- } // Predicates = [HasStdExtZawrs]
- } // hasSideEffects = 1, mayLoad = 0, mayStore = 0
- def CSRRW : CSR_ir<0b001, "csrrw">;
- def CSRRS : CSR_ir<0b010, "csrrs">;
- def CSRRC : CSR_ir<0b011, "csrrc">;
- def CSRRWI : CSR_ii<0b101, "csrrwi">;
- def CSRRSI : CSR_ii<0b110, "csrrsi">;
- def CSRRCI : CSR_ii<0b111, "csrrci">;
- /// RV64I instructions
- let Predicates = [IsRV64] in {
- def LWU : Load_ri<0b110, "lwu">, Sched<[WriteLDW, ReadMemBase]>;
- def LD : Load_ri<0b011, "ld">, Sched<[WriteLDD, ReadMemBase]>;
- def SD : Store_rri<0b011, "sd">, Sched<[WriteSTD, ReadStoreData, ReadMemBase]>;
- let IsSignExtendingOpW = 1 in {
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
- def ADDIW : RVInstI<0b000, OPC_OP_IMM_32, (outs GPR:$rd),
- (ins GPR:$rs1, simm12:$imm12),
- "addiw", "$rd, $rs1, $imm12">,
- Sched<[WriteIALU32, ReadIALU32]>;
- def SLLIW : ShiftW_ri<0b0000000, 0b001, "slliw">;
- def SRLIW : ShiftW_ri<0b0000000, 0b101, "srliw">;
- def SRAIW : ShiftW_ri<0b0100000, 0b101, "sraiw">;
- def ADDW : ALUW_rr<0b0000000, 0b000, "addw", /*Commutable*/1>,
- Sched<[WriteIALU32, ReadIALU32, ReadIALU32]>;
- def SUBW : ALUW_rr<0b0100000, 0b000, "subw">,
- Sched<[WriteIALU32, ReadIALU32, ReadIALU32]>;
- def SLLW : ALUW_rr<0b0000000, 0b001, "sllw">,
- Sched<[WriteShiftReg32, ReadShiftReg32, ReadShiftReg32]>;
- def SRLW : ALUW_rr<0b0000000, 0b101, "srlw">,
- Sched<[WriteShiftReg32, ReadShiftReg32, ReadShiftReg32]>;
- def SRAW : ALUW_rr<0b0100000, 0b101, "sraw">,
- Sched<[WriteShiftReg32, ReadShiftReg32, ReadShiftReg32]>;
- } // IsSignExtendingOpW = 1
- } // Predicates = [IsRV64]
- //===----------------------------------------------------------------------===//
- // Privileged instructions
- //===----------------------------------------------------------------------===//
- let isBarrier = 1, isReturn = 1, isTerminator = 1 in {
- def URET : Priv<"uret", 0b0000000>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0b00010;
- }
- def SRET : Priv<"sret", 0b0001000>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0b00010;
- }
- def MRET : Priv<"mret", 0b0011000>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0b00010;
- }
- } // isBarrier = 1, isReturn = 1, isTerminator = 1
- def WFI : Priv<"wfi", 0b0001000>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0b00101;
- }
- let Predicates = [HasStdExtSvinval] in {
- def SFENCE_W_INVAL : Priv<"sfence.w.inval", 0b0001100>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0;
- }
- def SFENCE_INVAL_IR : Priv<"sfence.inval.ir", 0b0001100>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0b00001;
- }
- def SINVAL_VMA : Priv_rr<"sinval.vma", 0b0001011>, Sched<[]>;
- def HINVAL_VVMA : Priv_rr<"hinval.vvma", 0b0010011>, Sched<[]>;
- def HINVAL_GVMA : Priv_rr<"hinval.gvma", 0b0110011>, Sched<[]>;
- } // Predicates = [HasStdExtSvinval]
- def SFENCE_VMA : Priv_rr<"sfence.vma", 0b0001001>, Sched<[]>;
- let Predicates = [HasStdExtH] in {
- def HFENCE_VVMA : Priv_rr<"hfence.vvma", 0b0010001>, Sched<[]>;
- def HFENCE_GVMA : Priv_rr<"hfence.gvma", 0b0110001>, Sched<[]>;
- def HLV_B : HLoad_r<0b0110000, 0b00000, "hlv.b">, Sched<[]>;
- def HLV_BU : HLoad_r<0b0110000, 0b00001, "hlv.bu">, Sched<[]>;
- def HLV_H : HLoad_r<0b0110010, 0b00000, "hlv.h">, Sched<[]>;
- def HLV_HU : HLoad_r<0b0110010, 0b00001, "hlv.hu">, Sched<[]>;
- def HLVX_HU : HLoad_r<0b0110010, 0b00011, "hlvx.hu">, Sched<[]>;
- def HLV_W : HLoad_r<0b0110100, 0b00000, "hlv.w">, Sched<[]>;
- def HLVX_WU : HLoad_r<0b0110100, 0b00011, "hlvx.wu">, Sched<[]>;
- def HSV_B : HStore_rr<0b0110001, "hsv.b">, Sched<[]>;
- def HSV_H : HStore_rr<0b0110011, "hsv.h">, Sched<[]>;
- def HSV_W : HStore_rr<0b0110101, "hsv.w">, Sched<[]>;
- }
- let Predicates = [IsRV64, HasStdExtH] in {
- def HLV_WU : HLoad_r<0b0110100, 0b00001, "hlv.wu">, Sched<[]>;
- def HLV_D : HLoad_r<0b0110110, 0b00000, "hlv.d">, Sched<[]>;
- def HSV_D : HStore_rr<0b0110111, "hsv.d">, Sched<[]>;
- }
- //===----------------------------------------------------------------------===//
- // Debug instructions
- //===----------------------------------------------------------------------===//
- let isBarrier = 1, isReturn = 1, isTerminator = 1 in {
- def DRET : Priv<"dret", 0b0111101>, Sched<[]> {
- let rd = 0;
- let rs1 = 0;
- let rs2 = 0b10010;
- }
- } // isBarrier = 1, isReturn = 1, isTerminator = 1
- //===----------------------------------------------------------------------===//
- // Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
- //===----------------------------------------------------------------------===//
- def : InstAlias<"nop", (ADDI X0, X0, 0)>;
- // Note that the size is 32 because up to 8 32-bit instructions are needed to
- // generate an arbitrary 64-bit immediate. However, the size does not really
- // matter since PseudoLI is currently only used in the AsmParser where it gets
- // expanded to real instructions immediately.
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 32,
- isCodeGenOnly = 0, isAsmParserOnly = 1 in
- def PseudoLI : Pseudo<(outs GPR:$rd), (ins ixlenimm_li:$imm), [],
- "li", "$rd, $imm">;
- def PseudoLB : PseudoLoad<"lb">;
- def PseudoLBU : PseudoLoad<"lbu">;
- def PseudoLH : PseudoLoad<"lh">;
- def PseudoLHU : PseudoLoad<"lhu">;
- def PseudoLW : PseudoLoad<"lw">;
- def PseudoSB : PseudoStore<"sb">;
- def PseudoSH : PseudoStore<"sh">;
- def PseudoSW : PseudoStore<"sw">;
- let Predicates = [IsRV64] in {
- def PseudoLWU : PseudoLoad<"lwu">;
- def PseudoLD : PseudoLoad<"ld">;
- def PseudoSD : PseudoStore<"sd">;
- } // Predicates = [IsRV64]
- def : InstAlias<"li $rd, $imm", (ADDI GPR:$rd, X0, simm12:$imm)>;
- def : InstAlias<"mv $rd, $rs", (ADDI GPR:$rd, GPR:$rs, 0)>;
- def : InstAlias<"not $rd, $rs", (XORI GPR:$rd, GPR:$rs, -1)>;
- def : InstAlias<"neg $rd, $rs", (SUB GPR:$rd, X0, GPR:$rs)>;
- let Predicates = [IsRV64] in {
- def : InstAlias<"negw $rd, $rs", (SUBW GPR:$rd, X0, GPR:$rs)>;
- def : InstAlias<"sext.w $rd, $rs", (ADDIW GPR:$rd, GPR:$rs, 0)>;
- } // Predicates = [IsRV64]
- def : InstAlias<"seqz $rd, $rs", (SLTIU GPR:$rd, GPR:$rs, 1)>;
- def : InstAlias<"snez $rd, $rs", (SLTU GPR:$rd, X0, GPR:$rs)>;
- def : InstAlias<"sltz $rd, $rs", (SLT GPR:$rd, GPR:$rs, X0)>;
- def : InstAlias<"sgtz $rd, $rs", (SLT GPR:$rd, X0, GPR:$rs)>;
- // sgt/sgtu are recognised by the GNU assembler but the canonical slt/sltu
- // form will always be printed. Therefore, set a zero weight.
- def : InstAlias<"sgt $rd, $rs, $rt", (SLT GPR:$rd, GPR:$rt, GPR:$rs), 0>;
- def : InstAlias<"sgtu $rd, $rs, $rt", (SLTU GPR:$rd, GPR:$rt, GPR:$rs), 0>;
- def : InstAlias<"beqz $rs, $offset",
- (BEQ GPR:$rs, X0, simm13_lsb0:$offset)>;
- def : InstAlias<"bnez $rs, $offset",
- (BNE GPR:$rs, X0, simm13_lsb0:$offset)>;
- def : InstAlias<"blez $rs, $offset",
- (BGE X0, GPR:$rs, simm13_lsb0:$offset)>;
- def : InstAlias<"bgez $rs, $offset",
- (BGE GPR:$rs, X0, simm13_lsb0:$offset)>;
- def : InstAlias<"bltz $rs, $offset",
- (BLT GPR:$rs, X0, simm13_lsb0:$offset)>;
- def : InstAlias<"bgtz $rs, $offset",
- (BLT X0, GPR:$rs, simm13_lsb0:$offset)>;
- // Always output the canonical mnemonic for the pseudo branch instructions.
- // The GNU tools emit the canonical mnemonic for the branch pseudo instructions
- // as well (e.g. "bgt" will be recognised by the assembler but never printed by
- // objdump). Match this behaviour by setting a zero weight.
- def : InstAlias<"bgt $rs, $rt, $offset",
- (BLT GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
- def : InstAlias<"ble $rs, $rt, $offset",
- (BGE GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
- def : InstAlias<"bgtu $rs, $rt, $offset",
- (BLTU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
- def : InstAlias<"bleu $rs, $rt, $offset",
- (BGEU GPR:$rt, GPR:$rs, simm13_lsb0:$offset), 0>;
- def : InstAlias<"j $offset", (JAL X0, simm21_lsb0_jal:$offset)>;
- def : InstAlias<"jal $offset", (JAL X1, simm21_lsb0_jal:$offset)>;
- // Non-zero offset aliases of "jalr" are the lowest weight, followed by the
- // two-register form, then the one-register forms and finally "ret".
- def : InstAlias<"jr $rs", (JALR X0, GPR:$rs, 0), 3>;
- def : InstAlias<"jr ${offset}(${rs})", (JALR X0, GPR:$rs, simm12:$offset)>;
- def : InstAlias<"jalr $rs", (JALR X1, GPR:$rs, 0), 3>;
- def : InstAlias<"jalr ${offset}(${rs})", (JALR X1, GPR:$rs, simm12:$offset)>;
- def : InstAlias<"jalr $rd, $rs", (JALR GPR:$rd, GPR:$rs, 0), 2>;
- def : InstAlias<"ret", (JALR X0, X1, 0), 4>;
- // Non-canonical forms for jump targets also accepted by the assembler.
- def : InstAlias<"jr $rs, $offset", (JALR X0, GPR:$rs, simm12:$offset), 0>;
- def : InstAlias<"jalr $rs, $offset", (JALR X1, GPR:$rs, simm12:$offset), 0>;
- def : InstAlias<"jalr $rd, $rs, $offset", (JALR GPR:$rd, GPR:$rs, simm12:$offset), 0>;
- def : InstAlias<"fence", (FENCE 0xF, 0xF)>; // 0xF == iorw
- let Predicates = [HasStdExtZihintpause] in
- def : InstAlias<"pause", (FENCE 0x1, 0x0)>; // 0x1 == w
- def : InstAlias<"rdinstret $rd", (CSRRS GPR:$rd, INSTRET.Encoding, X0)>;
- def : InstAlias<"rdcycle $rd", (CSRRS GPR:$rd, CYCLE.Encoding, X0)>;
- def : InstAlias<"rdtime $rd", (CSRRS GPR:$rd, TIME.Encoding, X0)>;
- let Predicates = [IsRV32] in {
- def : InstAlias<"rdinstreth $rd", (CSRRS GPR:$rd, INSTRETH.Encoding, X0)>;
- def : InstAlias<"rdcycleh $rd", (CSRRS GPR:$rd, CYCLEH.Encoding, X0)>;
- def : InstAlias<"rdtimeh $rd", (CSRRS GPR:$rd, TIMEH.Encoding, X0)>;
- } // Predicates = [IsRV32]
- def : InstAlias<"csrr $rd, $csr", (CSRRS GPR:$rd, csr_sysreg:$csr, X0)>;
- def : InstAlias<"csrw $csr, $rs", (CSRRW X0, csr_sysreg:$csr, GPR:$rs)>;
- def : InstAlias<"csrs $csr, $rs", (CSRRS X0, csr_sysreg:$csr, GPR:$rs)>;
- def : InstAlias<"csrc $csr, $rs", (CSRRC X0, csr_sysreg:$csr, GPR:$rs)>;
- def : InstAlias<"csrwi $csr, $imm", (CSRRWI X0, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrsi $csr, $imm", (CSRRSI X0, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrci $csr, $imm", (CSRRCI X0, csr_sysreg:$csr, uimm5:$imm)>;
- let EmitPriority = 0 in {
- def : InstAlias<"csrw $csr, $imm", (CSRRWI X0, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrs $csr, $imm", (CSRRSI X0, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrc $csr, $imm", (CSRRCI X0, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrrw $rd, $csr, $imm", (CSRRWI GPR:$rd, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrrs $rd, $csr, $imm", (CSRRSI GPR:$rd, csr_sysreg:$csr, uimm5:$imm)>;
- def : InstAlias<"csrrc $rd, $csr, $imm", (CSRRCI GPR:$rd, csr_sysreg:$csr, uimm5:$imm)>;
- }
- def : InstAlias<"sfence.vma", (SFENCE_VMA X0, X0)>;
- def : InstAlias<"sfence.vma $rs", (SFENCE_VMA GPR:$rs, X0)>;
- def : InstAlias<"hfence.gvma", (HFENCE_GVMA X0, X0)>;
- def : InstAlias<"hfence.gvma $rs", (HFENCE_GVMA GPR:$rs, X0)>;
- def : InstAlias<"hfence.vvma", (HFENCE_VVMA X0, X0)>;
- def : InstAlias<"hfence.vvma $rs", (HFENCE_VVMA GPR:$rs, X0)>;
- let Predicates = [HasStdExtZihintntl] in {
- def : InstAlias<"ntl.p1", (ADD X0, X0, X2)>;
- def : InstAlias<"ntl.pall", (ADD X0, X0, X3)>;
- def : InstAlias<"ntl.s1", (ADD X0, X0, X4)>;
- def : InstAlias<"ntl.all", (ADD X0, X0, X5)>;
- } // Predicates = [HasStdExtZihintntl]
- let EmitPriority = 0 in {
- def : InstAlias<"lb $rd, (${rs1})",
- (LB GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"lh $rd, (${rs1})",
- (LH GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"lw $rd, (${rs1})",
- (LW GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"lbu $rd, (${rs1})",
- (LBU GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"lhu $rd, (${rs1})",
- (LHU GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"sb $rs2, (${rs1})",
- (SB GPR:$rs2, GPR:$rs1, 0)>;
- def : InstAlias<"sh $rs2, (${rs1})",
- (SH GPR:$rs2, GPR:$rs1, 0)>;
- def : InstAlias<"sw $rs2, (${rs1})",
- (SW GPR:$rs2, GPR:$rs1, 0)>;
- def : InstAlias<"add $rd, $rs1, $imm12",
- (ADDI GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- def : InstAlias<"and $rd, $rs1, $imm12",
- (ANDI GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- def : InstAlias<"xor $rd, $rs1, $imm12",
- (XORI GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- def : InstAlias<"or $rd, $rs1, $imm12",
- (ORI GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- def : InstAlias<"sll $rd, $rs1, $shamt",
- (SLLI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt)>;
- def : InstAlias<"srl $rd, $rs1, $shamt",
- (SRLI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt)>;
- def : InstAlias<"sra $rd, $rs1, $shamt",
- (SRAI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt)>;
- let Predicates = [IsRV64] in {
- def : InstAlias<"lwu $rd, (${rs1})",
- (LWU GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"ld $rd, (${rs1})",
- (LD GPR:$rd, GPR:$rs1, 0)>;
- def : InstAlias<"sd $rs2, (${rs1})",
- (SD GPR:$rs2, GPR:$rs1, 0)>;
- def : InstAlias<"addw $rd, $rs1, $imm12",
- (ADDIW GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- def : InstAlias<"sllw $rd, $rs1, $shamt",
- (SLLIW GPR:$rd, GPR:$rs1, uimm5:$shamt)>;
- def : InstAlias<"srlw $rd, $rs1, $shamt",
- (SRLIW GPR:$rd, GPR:$rs1, uimm5:$shamt)>;
- def : InstAlias<"sraw $rd, $rs1, $shamt",
- (SRAIW GPR:$rd, GPR:$rs1, uimm5:$shamt)>;
- } // Predicates = [IsRV64]
- def : InstAlias<"slt $rd, $rs1, $imm12",
- (SLTI GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- def : InstAlias<"sltu $rd, $rs1, $imm12",
- (SLTIU GPR:$rd, GPR:$rs1, simm12:$imm12)>;
- }
- def : MnemonicAlias<"move", "mv">;
- // The SCALL and SBREAK instructions wererenamed to ECALL and EBREAK in
- // version 2.1 of the user-level ISA. Like the GNU toolchain, we still accept
- // the old name for backwards compatibility.
- def : MnemonicAlias<"scall", "ecall">;
- def : MnemonicAlias<"sbreak", "ebreak">;
- // This alias was added to the spec in December 2020. Don't print it by default
- // to allow assembly we print to be compatible with versions of GNU assembler
- // that don't support this alias.
- def : InstAlias<"zext.b $rd, $rs", (ANDI GPR:$rd, GPR:$rs, 0xFF), 0>;
- //===----------------------------------------------------------------------===//
- // .insn directive instructions
- //===----------------------------------------------------------------------===//
- // isCodeGenOnly = 1 to hide them from the tablegened assembly parser.
- let isCodeGenOnly = 1, hasSideEffects = 1, mayLoad = 1, mayStore = 1,
- hasNoSchedulingInfo = 1 in {
- def InsnR : DirectiveInsnR<(outs AnyReg:$rd), (ins uimm7_opcode:$opcode, uimm3:$funct3,
- uimm7:$funct7, AnyReg:$rs1,
- AnyReg:$rs2),
- "$opcode, $funct3, $funct7, $rd, $rs1, $rs2">;
- def InsnR4 : DirectiveInsnR4<(outs AnyReg:$rd), (ins uimm7_opcode:$opcode,
- uimm3:$funct3,
- uimm2:$funct2,
- AnyReg:$rs1, AnyReg:$rs2,
- AnyReg:$rs3),
- "$opcode, $funct3, $funct2, $rd, $rs1, $rs2, $rs3">;
- def InsnI : DirectiveInsnI<(outs AnyReg:$rd), (ins uimm7_opcode:$opcode, uimm3:$funct3,
- AnyReg:$rs1, simm12:$imm12),
- "$opcode, $funct3, $rd, $rs1, $imm12">;
- def InsnI_Mem : DirectiveInsnI<(outs AnyReg:$rd), (ins uimm7_opcode:$opcode,
- uimm3:$funct3,
- AnyReg:$rs1,
- simm12:$imm12),
- "$opcode, $funct3, $rd, ${imm12}(${rs1})">;
- def InsnB : DirectiveInsnB<(outs), (ins uimm7_opcode:$opcode, uimm3:$funct3,
- AnyReg:$rs1, AnyReg:$rs2,
- simm13_lsb0:$imm12),
- "$opcode, $funct3, $rs1, $rs2, $imm12">;
- def InsnU : DirectiveInsnU<(outs AnyReg:$rd), (ins uimm7_opcode:$opcode,
- uimm20_lui:$imm20),
- "$opcode, $rd, $imm20">;
- def InsnJ : DirectiveInsnJ<(outs AnyReg:$rd), (ins uimm7_opcode:$opcode,
- simm21_lsb0_jal:$imm20),
- "$opcode, $rd, $imm20">;
- def InsnS : DirectiveInsnS<(outs), (ins uimm7_opcode:$opcode, uimm3:$funct3,
- AnyReg:$rs2, AnyReg:$rs1,
- simm12:$imm12),
- "$opcode, $funct3, $rs2, ${imm12}(${rs1})">;
- }
- // Use InstAliases to match these so that we can combine the insn and format
- // into a mnemonic to use as the key for the tablegened asm matcher table. The
- // parser will take care of creating these fake mnemonics and will only do it
- // for known formats.
- let EmitPriority = 0 in {
- def : InstAlias<".insn_r $opcode, $funct3, $funct7, $rd, $rs1, $rs2",
- (InsnR AnyReg:$rd, uimm7_opcode:$opcode, uimm3:$funct3, uimm7:$funct7,
- AnyReg:$rs1, AnyReg:$rs2)>;
- // Accept 4 register form of ".insn r" as alias for ".insn r4".
- def : InstAlias<".insn_r $opcode, $funct3, $funct2, $rd, $rs1, $rs2, $rs3",
- (InsnR4 AnyReg:$rd, uimm7_opcode:$opcode, uimm3:$funct3, uimm2:$funct2,
- AnyReg:$rs1, AnyReg:$rs2, AnyReg:$rs3)>;
- def : InstAlias<".insn_r4 $opcode, $funct3, $funct2, $rd, $rs1, $rs2, $rs3",
- (InsnR4 AnyReg:$rd, uimm7_opcode:$opcode, uimm3:$funct3, uimm2:$funct2,
- AnyReg:$rs1, AnyReg:$rs2, AnyReg:$rs3)>;
- def : InstAlias<".insn_i $opcode, $funct3, $rd, $rs1, $imm12",
- (InsnI AnyReg:$rd, uimm7_opcode:$opcode, uimm3:$funct3, AnyReg:$rs1,
- simm12:$imm12)>;
- def : InstAlias<".insn_i $opcode, $funct3, $rd, ${imm12}(${rs1})",
- (InsnI_Mem AnyReg:$rd, uimm7_opcode:$opcode, uimm3:$funct3,
- AnyReg:$rs1, simm12:$imm12)>;
- def : InstAlias<".insn_b $opcode, $funct3, $rs1, $rs2, $imm12",
- (InsnB uimm7_opcode:$opcode, uimm3:$funct3, AnyReg:$rs1,
- AnyReg:$rs2, simm13_lsb0:$imm12)>;
- // Accept sb as an alias for b.
- def : InstAlias<".insn_sb $opcode, $funct3, $rs1, $rs2, $imm12",
- (InsnB uimm7_opcode:$opcode, uimm3:$funct3, AnyReg:$rs1,
- AnyReg:$rs2, simm13_lsb0:$imm12)>;
- def : InstAlias<".insn_u $opcode, $rd, $imm20",
- (InsnU AnyReg:$rd, uimm7_opcode:$opcode, uimm20_lui:$imm20)>;
- def : InstAlias<".insn_j $opcode, $rd, $imm20",
- (InsnJ AnyReg:$rd, uimm7_opcode:$opcode, simm21_lsb0_jal:$imm20)>;
- // Accept uj as an alias for j.
- def : InstAlias<".insn_uj $opcode, $rd, $imm20",
- (InsnJ AnyReg:$rd, uimm7_opcode:$opcode, simm21_lsb0_jal:$imm20)>;
- def : InstAlias<".insn_s $opcode, $funct3, $rs2, ${imm12}(${rs1})",
- (InsnS uimm7_opcode:$opcode, uimm3:$funct3, AnyReg:$rs2,
- AnyReg:$rs1, simm12:$imm12)>;
- }
- //===----------------------------------------------------------------------===//
- // Pseudo-instructions and codegen patterns
- //
- // Naming convention: For 'generic' pattern classes, we use the naming
- // convention PatTy1Ty2. For pattern classes which offer a more complex
- // expansion, prefix the class name, e.g. BccPat.
- //===----------------------------------------------------------------------===//
- /// Generic pattern classes
- class PatGpr<SDPatternOperator OpNode, RVInst Inst>
- : Pat<(OpNode GPR:$rs1), (Inst GPR:$rs1)>;
- class PatGprGpr<SDPatternOperator OpNode, RVInst Inst>
- : Pat<(OpNode GPR:$rs1, GPR:$rs2), (Inst GPR:$rs1, GPR:$rs2)>;
- class PatGprImm<SDPatternOperator OpNode, RVInst Inst, ImmLeaf ImmType>
- : Pat<(XLenVT (OpNode (XLenVT GPR:$rs1), ImmType:$imm)),
- (Inst GPR:$rs1, ImmType:$imm)>;
- class PatGprSimm12<SDPatternOperator OpNode, RVInstI Inst>
- : PatGprImm<OpNode, Inst, simm12>;
- class PatGprUimmLog2XLen<SDPatternOperator OpNode, RVInstIShift Inst>
- : PatGprImm<OpNode, Inst, uimmlog2xlen>;
- /// Predicates
- def assertsexti32 : PatFrag<(ops node:$src), (assertsext node:$src), [{
- return cast<VTSDNode>(N->getOperand(1))->getVT().bitsLE(MVT::i32);
- }]>;
- def sexti32 : ComplexPattern<i64, 1, "selectSExti32">;
- def assertzexti32 : PatFrag<(ops node:$src), (assertzext node:$src), [{
- return cast<VTSDNode>(N->getOperand(1))->getVT().bitsLE(MVT::i32);
- }]>;
- def zexti32 : ComplexPattern<i64, 1, "selectZExtBits<32>">;
- def zexti16 : ComplexPattern<XLenVT, 1, "selectZExtBits<16>">;
- def zexti8 : ComplexPattern<XLenVT, 1, "selectZExtBits<8>">;
- class binop_oneuse<SDPatternOperator operator>
- : PatFrag<(ops node:$A, node:$B),
- (operator node:$A, node:$B), [{
- return N->hasOneUse();
- }]>;
- def and_oneuse : binop_oneuse<and>;
- def add_oneuse : binop_oneuse<add>;
- def mul_oneuse : binop_oneuse<mul>;
- def mul_const_oneuse : PatFrag<(ops node:$A, node:$B),
- (mul node:$A, node:$B), [{
- if (auto *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1)))
- if (N1C->hasOneUse())
- return true;
- return false;
- }]>;
- class unop_oneuse<SDPatternOperator operator>
- : PatFrag<(ops node:$A),
- (operator node:$A), [{
- return N->hasOneUse();
- }]>;
- def sext_oneuse : unop_oneuse<sext>;
- def zext_oneuse : unop_oneuse<zext>;
- def anyext_oneuse : unop_oneuse<anyext>;
- def fpext_oneuse : unop_oneuse<any_fpextend>;
- /// Simple arithmetic operations
- def : PatGprGpr<add, ADD>;
- def : PatGprSimm12<add, ADDI>;
- def : PatGprGpr<sub, SUB>;
- def : PatGprGpr<or, OR>;
- def : PatGprSimm12<or, ORI>;
- def : PatGprGpr<and, AND>;
- def : PatGprSimm12<and, ANDI>;
- def : PatGprGpr<xor, XOR>;
- def : PatGprSimm12<xor, XORI>;
- def : PatGprUimmLog2XLen<shl, SLLI>;
- def : PatGprUimmLog2XLen<srl, SRLI>;
- def : PatGprUimmLog2XLen<sra, SRAI>;
- // Select 'or' as ADDI if the immediate bits are known to be 0 in $rs1. This
- // can improve compressibility.
- def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
- KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
- KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
- return KnownBits::haveNoCommonBitsSet(Known0, Known1);
- }]>;
- def : PatGprSimm12<or_is_add, ADDI>;
- // negate of low bit can be done via two (compressible) shifts. The negate
- // is never compressible since rs1 and rd can't be the same register.
- def : Pat<(XLenVT (sub 0, (and_oneuse GPR:$rs, 1))),
- (SRAI (SLLI $rs, (ImmSubFromXLen (XLenVT 1))),
- (ImmSubFromXLen (XLenVT 1)))>;
- // AND with leading/trailing ones mask exceeding simm32/simm12.
- def : Pat<(i64 (and GPR:$rs, LeadingOnesMask:$mask)),
- (SLLI (SRLI $rs, LeadingOnesMask:$mask), LeadingOnesMask:$mask)>;
- def : Pat<(XLenVT (and GPR:$rs, TrailingOnesMask:$mask)),
- (SRLI (SLLI $rs, TrailingOnesMask:$mask), TrailingOnesMask:$mask)>;
- // Match both a plain shift and one where the shift amount is masked (this is
- // typically introduced when the legalizer promotes the shift amount and
- // zero-extends it). For RISC-V, the mask is unnecessary as shifts in the base
- // ISA only read the least significant 5 bits (RV32I) or 6 bits (RV64I).
- def shiftMaskXLen : ComplexPattern<XLenVT, 1, "selectShiftMaskXLen", [], [], 0>;
- def shiftMask32 : ComplexPattern<i64, 1, "selectShiftMask32", [], [], 0>;
- class shiftop<SDPatternOperator operator>
- : PatFrag<(ops node:$val, node:$count),
- (operator node:$val, (XLenVT (shiftMaskXLen node:$count)))>;
- class shiftopw<SDPatternOperator operator>
- : PatFrag<(ops node:$val, node:$count),
- (operator node:$val, (i64 (shiftMask32 node:$count)))>;
- def : PatGprGpr<shiftop<shl>, SLL>;
- def : PatGprGpr<shiftop<srl>, SRL>;
- def : PatGprGpr<shiftop<sra>, SRA>;
- // This is a special case of the ADD instruction used to facilitate the use of a
- // fourth operand to emit a relocation on a symbol relating to this instruction.
- // The relocation does not affect any bits of the instruction itself but is used
- // as a hint to the linker.
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in
- def PseudoAddTPRel : Pseudo<(outs GPR:$rd),
- (ins GPR:$rs1, GPR:$rs2, tprel_add_symbol:$src), [],
- "add", "$rd, $rs1, $rs2, $src">;
- /// FrameIndex calculations
- def : Pat<(FrameAddrRegImm GPR:$rs1, simm12:$imm12),
- (ADDI GPR:$rs1, simm12:$imm12)>;
- /// HI and ADD_LO address nodes.
- def : Pat<(riscv_hi tglobaladdr:$in), (LUI tglobaladdr:$in)>;
- def : Pat<(riscv_hi tblockaddress:$in), (LUI tblockaddress:$in)>;
- def : Pat<(riscv_hi tjumptable:$in), (LUI tjumptable:$in)>;
- def : Pat<(riscv_hi tconstpool:$in), (LUI tconstpool:$in)>;
- def : Pat<(riscv_add_lo GPR:$hi, tglobaladdr:$lo),
- (ADDI GPR:$hi, tglobaladdr:$lo)>;
- def : Pat<(riscv_add_lo GPR:$hi, tblockaddress:$lo),
- (ADDI GPR:$hi, tblockaddress:$lo)>;
- def : Pat<(riscv_add_lo GPR:$hi, tjumptable:$lo),
- (ADDI GPR:$hi, tjumptable:$lo)>;
- def : Pat<(riscv_add_lo GPR:$hi, tconstpool:$lo),
- (ADDI GPR:$hi, tconstpool:$lo)>;
- /// TLS address nodes.
- def : Pat<(riscv_hi tglobaltlsaddr:$in), (LUI tglobaltlsaddr:$in)>;
- def : Pat<(riscv_add_tprel GPR:$rs1, GPR:$rs2, tglobaltlsaddr:$src),
- (PseudoAddTPRel GPR:$rs1, GPR:$rs2, tglobaltlsaddr:$src)>;
- def : Pat<(riscv_add_lo GPR:$src, tglobaltlsaddr:$lo),
- (ADDI GPR:$src, tglobaltlsaddr:$lo)>;
- /// Setcc
- def : PatGprGpr<setlt, SLT>;
- def : PatGprSimm12<setlt, SLTI>;
- def : PatGprGpr<setult, SLTU>;
- def : PatGprSimm12<setult, SLTIU>;
- // Define pattern expansions for setcc operations that aren't directly
- // handled by a RISC-V instruction.
- def : Pat<(seteq GPR:$rs1, 0), (SLTIU GPR:$rs1, 1)>;
- def : Pat<(seteq GPR:$rs1, GPR:$rs2), (SLTIU (XOR GPR:$rs1, GPR:$rs2), 1)>;
- def : Pat<(seteq GPR:$rs1, simm12_plus1:$imm12),
- (SLTIU (ADDI GPR:$rs1, (NegImm simm12_plus1:$imm12)), 1)>;
- def : Pat<(seteq GPR:$rs1, -2048),
- (SLTIU (XORI GPR:$rs1, -2048), 1)>;
- def : Pat<(setne GPR:$rs1, 0), (SLTU X0, GPR:$rs1)>;
- def : Pat<(setne GPR:$rs1, GPR:$rs2), (SLTU X0, (XOR GPR:$rs1, GPR:$rs2))>;
- def : Pat<(setne GPR:$rs1, simm12_plus1:$imm12),
- (SLTU X0, (ADDI GPR:$rs1, (NegImm simm12_plus1:$imm12)))>;
- def : Pat<(setne GPR:$rs1, -2048),
- (SLTU X0, (XORI GPR:$rs1, -2048))>;
- def : Pat<(setne GPR:$rs1, -1), (SLTIU GPR:$rs1, -1)>;
- def IntCCtoRISCVCC : SDNodeXForm<riscv_selectcc, [{
- ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
- RISCVCC::CondCode BrCC = getRISCVCCForIntCC(CC);
- return CurDAG->getTargetConstant(BrCC, SDLoc(N), Subtarget->getXLenVT());
- }]>;
- def riscv_selectcc_frag : PatFrag<(ops node:$lhs, node:$rhs, node:$cc,
- node:$truev, node:$falsev),
- (riscv_selectcc node:$lhs, node:$rhs,
- node:$cc, node:$truev,
- node:$falsev), [{}],
- IntCCtoRISCVCC>;
- let Predicates = [HasShortForwardBranchOpt], isSelect = 1,
- Constraints = "$dst = $falsev", isCommutable = 1, Size = 8 in {
- // This instruction moves $truev to $dst when the condition is true. It will
- // be expanded to control flow in RISCVExpandPseudoInsts.
- def PseudoCCMOVGPR : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$truev),
- [(set GPR:$dst,
- (riscv_selectcc_frag:$cc GPR:$lhs, GPR:$rhs,
- cond, GPR:$truev,
- GPR:$falsev))]>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- }
- // Conditional binops, that updates update $dst to (op rs1, rs2) when condition
- // is true. Returns $falsev otherwise. Selected by optimizeSelect.
- // TODO: Can we use DefaultOperands on the regular binop to accomplish this more
- // like how ARM does predication?
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8,
- Constraints = "$dst = $falsev" in {
- def PseudoCCADD : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- def PseudoCCSUB : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- def PseudoCCAND : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- def PseudoCCOR : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- def PseudoCCXOR : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- // RV64I instructions
- def PseudoCCADDW : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- def PseudoCCSUBW : Pseudo<(outs GPR:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- GPR:$falsev, GPR:$rs1, GPR:$rs2), []>,
- Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
- }
- multiclass SelectCC_GPR_rrirr<RegisterClass valty> {
- let usesCustomInserter = 1 in
- def _Using_CC_GPR : Pseudo<(outs valty:$dst),
- (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
- valty:$truev, valty:$falsev),
- [(set valty:$dst,
- (riscv_selectcc_frag:$cc GPR:$lhs, GPR:$rhs, cond,
- valty:$truev, valty:$falsev))]>;
- // Explicitly select 0 in the condition to X0. The register coalescer doesn't
- // always do it.
- def : Pat<(riscv_selectcc_frag:$cc GPR:$lhs, 0, cond, valty:$truev,
- valty:$falsev),
- (!cast<Instruction>(NAME#"_Using_CC_GPR") GPR:$lhs, X0,
- (IntCCtoRISCVCC $cc), valty:$truev, valty:$falsev)>;
- }
- let Predicates = [NoShortForwardBranchOpt] in
- defm Select_GPR : SelectCC_GPR_rrirr<GPR>;
- class SelectCompressOpt<CondCode Cond>: Pat<(riscv_selectcc_frag:$select GPR:$lhs, simm12_no6:$Constant, Cond,
- GPR:$truev, GPR:$falsev),
- (Select_GPR_Using_CC_GPR (ADDI GPR:$lhs, (NegImm simm12:$Constant)), X0,
- (IntCCtoRISCVCC $select), GPR:$truev, GPR:$falsev)>;
- def OptForMinSize : Predicate<"MF ? MF->getFunction().hasMinSize() : false">;
- let Predicates = [HasStdExtC, OptForMinSize] in {
- def : SelectCompressOpt<SETEQ>;
- def : SelectCompressOpt<SETNE>;
- }
- /// Branches and jumps
- // Match `riscv_brcc` and lower to the appropriate RISC-V branch instruction.
- multiclass BccPat<CondCode Cond, RVInstB Inst> {
- def : Pat<(riscv_brcc GPR:$rs1, GPR:$rs2, Cond, bb:$imm12),
- (Inst GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12)>;
- // Explicitly select 0 to X0. The register coalescer doesn't always do it.
- def : Pat<(riscv_brcc GPR:$rs1, 0, Cond, bb:$imm12),
- (Inst GPR:$rs1, X0, simm13_lsb0:$imm12)>;
- }
- class BrccCompessOpt<CondCode Cond, RVInstB Inst> : Pat<(riscv_brcc GPR:$lhs, simm12_no6:$Constant, Cond, bb:$place),
- (Inst (ADDI GPR:$lhs, (NegImm simm12:$Constant)), X0, bb:$place)>;
- defm : BccPat<SETEQ, BEQ>;
- defm : BccPat<SETNE, BNE>;
- defm : BccPat<SETLT, BLT>;
- defm : BccPat<SETGE, BGE>;
- defm : BccPat<SETULT, BLTU>;
- defm : BccPat<SETUGE, BGEU>;
- let Predicates = [HasStdExtC, OptForMinSize] in {
- def : BrccCompessOpt<SETEQ, BEQ>;
- def : BrccCompessOpt<SETNE, BNE>;
- }
- let isBarrier = 1, isBranch = 1, isTerminator = 1 in
- def PseudoBR : Pseudo<(outs), (ins simm21_lsb0_jal:$imm20), [(br bb:$imm20)]>,
- PseudoInstExpansion<(JAL X0, simm21_lsb0_jal:$imm20)>;
- let isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
- def PseudoBRIND : Pseudo<(outs), (ins GPRJALR:$rs1, simm12:$imm12), []>,
- PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>;
- def : Pat<(brind GPRJALR:$rs1), (PseudoBRIND GPRJALR:$rs1, 0)>;
- def : Pat<(brind (add GPRJALR:$rs1, simm12:$imm12)),
- (PseudoBRIND GPRJALR:$rs1, simm12:$imm12)>;
- // PseudoCALLReg is a generic pseudo instruction for calls which will eventually
- // expand to auipc and jalr while encoding, with any given register used as the
- // destination.
- // Define AsmString to print "call" when compile with -S flag.
- // Define isCodeGenOnly = 0 to support parsing assembly "call" instruction.
- let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, Size = 8, hasSideEffects = 0,
- mayStore = 0, mayLoad = 0 in
- def PseudoCALLReg : Pseudo<(outs GPR:$rd), (ins call_symbol:$func), []>,
- Sched<[WriteIALU, WriteJalr, ReadJalr]> {
- let AsmString = "call\t$rd, $func";
- }
- // PseudoCALL is a pseudo instruction which will eventually expand to auipc
- // and jalr while encoding. This is desirable, as an auipc+jalr pair with
- // R_RISCV_CALL and R_RISCV_RELAX relocations can be be relaxed by the linker
- // if the offset fits in a signed 21-bit immediate.
- // Define AsmString to print "call" when compile with -S flag.
- // Define isCodeGenOnly = 0 to support parsing assembly "call" instruction.
- let isCall = 1, Defs = [X1], isCodeGenOnly = 0, Size = 8 in
- def PseudoCALL : Pseudo<(outs), (ins call_symbol:$func), []>,
- Sched<[WriteIALU, WriteJalr, ReadJalr]> {
- let AsmString = "call\t$func";
- }
- def : Pat<(riscv_call tglobaladdr:$func), (PseudoCALL tglobaladdr:$func)>;
- def : Pat<(riscv_call texternalsym:$func), (PseudoCALL texternalsym:$func)>;
- def : Pat<(riscv_uret_flag), (URET X0, X0)>;
- def : Pat<(riscv_sret_flag), (SRET X0, X0)>;
- def : Pat<(riscv_mret_flag), (MRET X0, X0)>;
- let isCall = 1, Defs = [X1] in
- def PseudoCALLIndirect : Pseudo<(outs), (ins GPRJALR:$rs1),
- [(riscv_call GPRJALR:$rs1)]>,
- PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
- let isBarrier = 1, isReturn = 1, isTerminator = 1 in
- def PseudoRET : Pseudo<(outs), (ins), [(riscv_ret_flag)]>,
- PseudoInstExpansion<(JALR X0, X1, 0)>;
- // PseudoTAIL is a pseudo instruction similar to PseudoCALL and will eventually
- // expand to auipc and jalr while encoding.
- // Define AsmString to print "tail" when compile with -S flag.
- let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [X2],
- Size = 8, isCodeGenOnly = 0 in
- def PseudoTAIL : Pseudo<(outs), (ins call_symbol:$dst), []>,
- Sched<[WriteIALU, WriteJalr, ReadJalr]> {
- let AsmString = "tail\t$dst";
- }
- let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [X2] in
- def PseudoTAILIndirect : Pseudo<(outs), (ins GPRTC:$rs1),
- [(riscv_tail GPRTC:$rs1)]>,
- PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>;
- def : Pat<(riscv_tail (iPTR tglobaladdr:$dst)),
- (PseudoTAIL tglobaladdr:$dst)>;
- def : Pat<(riscv_tail (iPTR texternalsym:$dst)),
- (PseudoTAIL texternalsym:$dst)>;
- let isCall = 0, isBarrier = 1, isBranch = 1, isTerminator = 1, Size = 8,
- isCodeGenOnly = 0, hasSideEffects = 0, mayStore = 0, mayLoad = 0 in
- def PseudoJump : Pseudo<(outs GPR:$rd), (ins pseudo_jump_symbol:$target), []>,
- Sched<[WriteIALU, WriteJalr, ReadJalr]> {
- let AsmString = "jump\t$target, $rd";
- }
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 0,
- isAsmParserOnly = 1 in
- def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
- "lla", "$dst, $src">;
- def : Pat<(riscv_lla tglobaladdr:$in), (PseudoLLA tglobaladdr:$in)>;
- def : Pat<(riscv_lla tblockaddress:$in), (PseudoLLA tblockaddress:$in)>;
- def : Pat<(riscv_lla tjumptable:$in), (PseudoLLA tjumptable:$in)>;
- def : Pat<(riscv_lla tconstpool:$in), (PseudoLLA tconstpool:$in)>;
- let hasSideEffects = 0, mayLoad = 1, mayStore = 0, Size = 8, isCodeGenOnly = 0,
- isAsmParserOnly = 1 in
- def PseudoLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
- "la", "$dst, $src">;
- def : Pat<(riscv_la tglobaladdr:$in), (PseudoLA tglobaladdr:$in)>;
- let hasSideEffects = 0, mayLoad = 1, mayStore = 0, Size = 8, isCodeGenOnly = 0,
- isAsmParserOnly = 1 in
- def PseudoLA_TLS_IE : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
- "la.tls.ie", "$dst, $src">;
- def : Pat<(riscv_la_tls_ie tglobaltlsaddr:$in),
- (PseudoLA_TLS_IE tglobaltlsaddr:$in)>;
- let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 0,
- isAsmParserOnly = 1 in
- def PseudoLA_TLS_GD : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
- "la.tls.gd", "$dst, $src">;
- def : Pat<(riscv_la_tls_gd tglobaltlsaddr:$in),
- (PseudoLA_TLS_GD tglobaltlsaddr:$in)>;
- /// Sign/Zero Extends
- // There are single-instruction versions of these in Zbb, so disable these
- // Pseudos if that extension is present.
- let hasSideEffects = 0, mayLoad = 0,
- mayStore = 0, isCodeGenOnly = 0, isAsmParserOnly = 1 in {
- def PseudoSEXT_B : Pseudo<(outs GPR:$rd), (ins GPR:$rs), [], "sext.b", "$rd, $rs">;
- def PseudoSEXT_H : Pseudo<(outs GPR:$rd), (ins GPR:$rs), [], "sext.h", "$rd, $rs">;
- // rv64's sext.w is defined above, using InstAlias<"sext.w ...
- // zext.b is defined above, using InstAlias<"zext.b ...
- def PseudoZEXT_H : Pseudo<(outs GPR:$rd), (ins GPR:$rs), [], "zext.h", "$rd, $rs">;
- } // hasSideEffects = 0, ...
- let Predicates = [IsRV64], hasSideEffects = 0, mayLoad = 0, mayStore = 0,
- isCodeGenOnly = 0, isAsmParserOnly = 1 in {
- def PseudoZEXT_W : Pseudo<(outs GPR:$rd), (ins GPR:$rs), [], "zext.w", "$rd, $rs">;
- } // Predicates = [IsRV64], ...
- /// Loads
- multiclass LdPat<PatFrag LoadOp, RVInst Inst, ValueType vt = XLenVT> {
- def : Pat<(vt (LoadOp (AddrRegImm GPR:$rs1, simm12:$imm12))),
- (Inst GPR:$rs1, simm12:$imm12)>;
- }
- defm : LdPat<sextloadi8, LB>;
- defm : LdPat<extloadi8, LB>;
- defm : LdPat<sextloadi16, LH>;
- defm : LdPat<extloadi16, LH>;
- defm : LdPat<load, LW, i32>, Requires<[IsRV32]>;
- defm : LdPat<zextloadi8, LBU>;
- defm : LdPat<zextloadi16, LHU>;
- /// Stores
- multiclass StPat<PatFrag StoreOp, RVInst Inst, RegisterClass StTy,
- ValueType vt> {
- def : Pat<(StoreOp (vt StTy:$rs2), (AddrRegImm GPR:$rs1, simm12:$imm12)),
- (Inst StTy:$rs2, GPR:$rs1, simm12:$imm12)>;
- }
- defm : StPat<truncstorei8, SB, GPR, XLenVT>;
- defm : StPat<truncstorei16, SH, GPR, XLenVT>;
- defm : StPat<store, SW, GPR, i32>, Requires<[IsRV32]>;
- /// Fences
- // Refer to Table A.6 in the version 2.3 draft of the RISC-V Instruction Set
- // Manual: Volume I.
- // fence acquire -> fence r, rw
- def : Pat<(atomic_fence (XLenVT 4), (timm)), (FENCE 0b10, 0b11)>;
- // fence release -> fence rw, w
- def : Pat<(atomic_fence (XLenVT 5), (timm)), (FENCE 0b11, 0b1)>;
- // fence acq_rel -> fence.tso
- def : Pat<(atomic_fence (XLenVT 6), (timm)), (FENCE_TSO)>;
- // fence seq_cst -> fence rw, rw
- def : Pat<(atomic_fence (XLenVT 7), (timm)), (FENCE 0b11, 0b11)>;
- // Lowering for atomic load and store is defined in RISCVInstrInfoA.td.
- // Although these are lowered to fence+load/store instructions defined in the
- // base RV32I/RV64I ISA, this lowering is only used when the A extension is
- // present. This is necessary as it isn't valid to mix __atomic_* libcalls
- // with inline atomic operations for the same object.
- /// Access to system registers
- // Helpers for defining specific operations. They are defined for each system
- // register separately. Side effect is not used because dependencies are
- // expressed via use-def properties.
- class ReadSysReg<SysReg SR, list<Register> Regs>
- : Pseudo<(outs GPR:$rd), (ins),
- [(set GPR:$rd, (riscv_read_csr (XLenVT SR.Encoding)))]>,
- PseudoInstExpansion<(CSRRS GPR:$rd, SR.Encoding, X0)> {
- let hasSideEffects = 0;
- let Uses = Regs;
- }
- class WriteSysReg<SysReg SR, list<Register> Regs>
- : Pseudo<(outs), (ins GPR:$val),
- [(riscv_write_csr (XLenVT SR.Encoding), GPR:$val)]>,
- PseudoInstExpansion<(CSRRW X0, SR.Encoding, GPR:$val)> {
- let hasSideEffects = 0;
- let Defs = Regs;
- }
- class WriteSysRegImm<SysReg SR, list<Register> Regs>
- : Pseudo<(outs), (ins uimm5:$val),
- [(riscv_write_csr (XLenVT SR.Encoding), uimm5:$val)]>,
- PseudoInstExpansion<(CSRRWI X0, SR.Encoding, uimm5:$val)> {
- let hasSideEffects = 0;
- let Defs = Regs;
- }
- class SwapSysReg<SysReg SR, list<Register> Regs>
- : Pseudo<(outs GPR:$rd), (ins GPR:$val),
- [(set GPR:$rd, (riscv_swap_csr (XLenVT SR.Encoding), GPR:$val))]>,
- PseudoInstExpansion<(CSRRW GPR:$rd, SR.Encoding, GPR:$val)> {
- let hasSideEffects = 0;
- let Uses = Regs;
- let Defs = Regs;
- }
- class SwapSysRegImm<SysReg SR, list<Register> Regs>
- : Pseudo<(outs GPR:$rd), (ins uimm5:$val),
- [(set GPR:$rd, (riscv_swap_csr (XLenVT SR.Encoding), uimm5:$val))]>,
- PseudoInstExpansion<(CSRRWI GPR:$rd, SR.Encoding, uimm5:$val)> {
- let hasSideEffects = 0;
- let Uses = Regs;
- let Defs = Regs;
- }
- def ReadFRM : ReadSysReg<SysRegFRM, [FRM]>;
- def WriteFRM : WriteSysReg<SysRegFRM, [FRM]>;
- def WriteFRMImm : WriteSysRegImm<SysRegFRM, [FRM]>;
- def SwapFRMImm : SwapSysRegImm<SysRegFRM, [FRM]>;
- let hasSideEffects = true in {
- def ReadFFLAGS : ReadSysReg<SysRegFFLAGS, [FFLAGS]>;
- def WriteFFLAGS : WriteSysReg<SysRegFFLAGS, [FFLAGS]>;
- }
- /// Other pseudo-instructions
- // Pessimistically assume the stack pointer will be clobbered
- let Defs = [X2], Uses = [X2] in {
- def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
- [(callseq_start timm:$amt1, timm:$amt2)]>;
- def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
- [(callseq_end timm:$amt1, timm:$amt2)]>;
- } // Defs = [X2], Uses = [X2]
- /// RV64 patterns
- let Predicates = [IsRV64, NotHasStdExtZba] in {
- def : Pat<(i64 (and GPR:$rs1, 0xffffffff)), (SRLI (SLLI GPR:$rs1, 32), 32)>;
- // If we're shifting a 32-bit zero extended value left by 0-31 bits, use 2
- // shifts instead of 3. This can occur when unsigned is used to index an array.
- def : Pat<(i64 (shl (and GPR:$rs1, 0xffffffff), uimm5:$shamt)),
- (SRLI (SLLI GPR:$rs1, 32), (ImmSubFrom32 uimm5:$shamt))>;
- }
- // PatFrag to allow ADDW/SUBW/MULW/SLLW to be selected from i64 add/sub/mul/shl
- // if only the lower 32 bits of their result is used.
- class binop_allwusers<SDPatternOperator operator>
- : PatFrag<(ops node:$lhs, node:$rhs),
- (i64 (operator node:$lhs, node:$rhs)), [{
- return hasAllWUsers(Node);
- }]>;
- def sexti32_allwusers : PatFrag<(ops node:$src),
- (sext_inreg node:$src, i32), [{
- return hasAllWUsers(Node);
- }]>;
- def ImmSExt32 : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(SignExtend64<32>(N->getSExtValue()),
- SDLoc(N), N->getValueType(0));
- }]>;
- // Look for constants where the upper 32 bits are 0, but sign extending bit 31
- // would be an simm12.
- def u32simm12 : ImmLeaf<XLenVT, [{
- return isUInt<32>(Imm) && isInt<12>(SignExtend64<32>(Imm));
- }], ImmSExt32>;
- let Predicates = [IsRV64] in {
- def : Pat<(i64 (and GPR:$rs, LeadingOnesWMask:$mask)),
- (SLLI (SRLIW $rs, LeadingOnesWMask:$mask), LeadingOnesWMask:$mask)>;
- /// sext and zext
- // Sign extend is not needed if all users are W instructions.
- def : Pat<(sexti32_allwusers GPR:$rs1), (XLenVT GPR:$rs1)>;
- def : Pat<(sext_inreg GPR:$rs1, i32), (ADDIW GPR:$rs1, 0)>;
- /// ALU operations
- def : Pat<(i64 (srl (and GPR:$rs1, 0xffffffff), uimm5:$shamt)),
- (SRLIW GPR:$rs1, uimm5:$shamt)>;
- def : Pat<(i64 (srl (shl GPR:$rs1, (i64 32)), uimm6gt32:$shamt)),
- (SRLIW GPR:$rs1, (ImmSub32 uimm6gt32:$shamt))>;
- def : Pat<(sra (sext_inreg GPR:$rs1, i32), uimm5:$shamt),
- (SRAIW GPR:$rs1, uimm5:$shamt)>;
- def : Pat<(i64 (sra (shl GPR:$rs1, (i64 32)), uimm6gt32:$shamt)),
- (SRAIW GPR:$rs1, (ImmSub32 uimm6gt32:$shamt))>;
- def : PatGprGpr<shiftopw<riscv_sllw>, SLLW>;
- def : PatGprGpr<shiftopw<riscv_srlw>, SRLW>;
- def : PatGprGpr<shiftopw<riscv_sraw>, SRAW>;
- // Select W instructions if only the lower 32 bits of the result are used.
- def : PatGprGpr<binop_allwusers<add>, ADDW>;
- def : PatGprSimm12<binop_allwusers<add>, ADDIW>;
- def : PatGprGpr<binop_allwusers<sub>, SUBW>;
- def : PatGprImm<binop_allwusers<shl>, SLLIW, uimm5>;
- // If this is a shr of a value sign extended from i32, and all the users only
- // use the lower 32 bits, we can use an sraiw to remove the sext_inreg. This
- // occurs because SimplifyDemandedBits prefers srl over sra.
- def : Pat<(binop_allwusers<srl> (sext_inreg GPR:$rs1, i32), uimm5:$shamt),
- (SRAIW GPR:$rs1, uimm5:$shamt)>;
- // Use binop_allwusers to recover immediates that may have been broken by
- // SimplifyDemandedBits.
- def : Pat<(binop_allwusers<and> GPR:$rs1, u32simm12:$imm),
- (ANDI GPR:$rs1, u32simm12:$imm)>;
- def : Pat<(binop_allwusers<or> GPR:$rs1, u32simm12:$imm),
- (ORI GPR:$rs1, u32simm12:$imm)>;
- def : Pat<(binop_allwusers<xor> GPR:$rs1, u32simm12:$imm),
- (XORI GPR:$rs1, u32simm12:$imm)>;
- /// Loads
- defm : LdPat<sextloadi32, LW, i64>;
- defm : LdPat<extloadi32, LW, i64>;
- defm : LdPat<zextloadi32, LWU, i64>;
- defm : LdPat<load, LD, i64>;
- /// Stores
- defm : StPat<truncstorei32, SW, GPR, i64>;
- defm : StPat<store, SD, GPR, i64>;
- } // Predicates = [IsRV64]
- /// readcyclecounter
- // On RV64, we can directly read the 64-bit "cycle" CSR.
- let Predicates = [IsRV64] in
- def : Pat<(i64 (readcyclecounter)), (CSRRS CYCLE.Encoding, X0)>;
- // On RV32, ReadCycleWide will be expanded to the suggested loop reading both
- // halves of the 64-bit "cycle" CSR.
- let Predicates = [IsRV32], usesCustomInserter = 1, hasNoSchedulingInfo = 1 in
- def ReadCycleWide : Pseudo<(outs GPR:$lo, GPR:$hi), (ins),
- [(set GPR:$lo, GPR:$hi, (riscv_read_cycle_wide))],
- "", "">;
- /// traps
- // We lower `trap` to `unimp`, as this causes a hard exception on nearly all
- // systems.
- def : Pat<(trap), (UNIMP)>;
- // We lower `debugtrap` to `ebreak`, as this will get the attention of the
- // debugger if possible.
- def : Pat<(debugtrap), (EBREAK)>;
- let Predicates = [IsRV64], Uses = [X5],
- Defs = [X1, X6, X7, X28, X29, X30, X31] in
- def HWASAN_CHECK_MEMACCESS_SHORTGRANULES
- : Pseudo<(outs), (ins GPRJALR:$ptr, i32imm:$accessinfo),
- [(int_hwasan_check_memaccess_shortgranules X5, GPRJALR:$ptr,
- (i32 timm:$accessinfo))]>;
- /// Simple optimization
- def : Pat<(add GPR:$rs1, (AddiPair:$rs2)),
- (ADDI (ADDI GPR:$rs1, (AddiPairImmLarge AddiPair:$rs2)),
- (AddiPairImmSmall GPR:$rs2))>;
- let Predicates = [IsRV64] in {
- // Select W instructions if only the lower 32-bits of the result are used.
- def : Pat<(binop_allwusers<add> GPR:$rs1, (AddiPair:$rs2)),
- (ADDIW (ADDIW GPR:$rs1, (AddiPairImmLarge AddiPair:$rs2)),
- (AddiPairImmSmall AddiPair:$rs2))>;
- }
- //===----------------------------------------------------------------------===//
- // Standard extensions
- //===----------------------------------------------------------------------===//
- include "RISCVInstrInfoM.td"
- include "RISCVInstrInfoA.td"
- include "RISCVInstrInfoF.td"
- include "RISCVInstrInfoD.td"
- include "RISCVInstrInfoC.td"
- include "RISCVInstrInfoZb.td"
- include "RISCVInstrInfoZk.td"
- include "RISCVInstrInfoV.td"
- include "RISCVInstrInfoZfh.td"
- include "RISCVInstrInfoZicbo.td"
- //===----------------------------------------------------------------------===//
- // Vendor extensions
- //===----------------------------------------------------------------------===//
- include "RISCVInstrInfoXVentana.td"
- include "RISCVInstrInfoXTHead.td"
|