//===-- M68kInstrArithmetic.td - Integer Arith Instrs ------*- 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 // //===----------------------------------------------------------------------===// /// /// \file /// This file describes the integer arithmetic instructions in the M68k /// architecture. Here is the current status of the file: /// /// Machine: /// /// ADD [~] ADDA [~] ADDI [~] ADDQ [ ] ADDX [~] /// CLR [ ] CMP [~] CMPA [~] CMPI [~] CMPM [ ] /// CMP2 [ ] DIVS/DIVU [~] DIVSL/DIVUL [ ] EXT [~] EXTB [ ] /// MULS/MULU [~] NEG [~] NEGX [~] SUB [~] SUBA [~] /// SUBI [~] SUBQ [ ] SUBX [~] /// /// Map: /// /// [ ] - was not touched at all /// [!] - requires extarnal stuff implemented /// [~] - functional implementation /// [X] - complete implementation /// //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Encoding //===----------------------------------------------------------------------===// /// Encoding for Normal forms /// ---------------------------------------------------- /// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 /// ---------------------------------------------------- /// | | | EFFECTIVE ADDRESS /// x x x x | REG | OP MODE | MODE | REG /// ---------------------------------------------------- class MxArithEncoding : MxEncoding; /// Encoding for Extended forms /// ------------------------------------------------------ /// F E D C | B A 9 | 8 | 7 6 | 5 4 | 3 | 2 1 0 /// ------------------------------------------------------ /// x x x x | REG Rx | 1 | SIZE | 0 0 | M | REG Ry /// ------------------------------------------------------ /// Rx - destination /// Ry - source /// M - address mode switch class MxArithXEncoding : MxEncoding, SIZE, MxBead1Bit<0b1>, DST, CMD>; /// Encoding for Immediate forms /// --------------------------------------------------- /// F E D C B A 9 8 | 7 6 | 5 4 3 | 2 1 0 /// --------------------------------------------------- /// | | EFFECTIVE ADDRESS /// x x x x x x x x | SIZE | MODE | REG /// --------------------------------------------------- /// 16-BIT WORD DATA | 8-BIT BYTE DATA /// --------------------------------------------------- /// 32-BIT LONG DATA /// --------------------------------------------------- /// NOTE It is used to store an immediate to memory, imm-to-reg are handled with /// normal version class MxArithImmEncoding : MxEncoding, // Source SRC_EXT.Imm, SRC_EXT.B8, SRC_EXT.Scale, SRC_EXT.WL, SRC_EXT.DAReg, // Destination DST_EXT.Imm, DST_EXT.B8, DST_EXT.Scale, DST_EXT.WL, DST_EXT.DAReg>; //===----------------------------------------------------------------------===// // Add/Sub //===----------------------------------------------------------------------===// let Defs = [CCR] in { let Constraints = "$src = $dst" in { // $reg, $ccr <- $reg op $reg class MxBiArOp_RFRR_xEA CMD, MxBead REG> : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.VT:$opd))], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#TYPE.RLet#"EA"), REG, !cast("MxEncEA"#TYPE.RLet#"_2"), MxExtEmpty>>; /// This Op is similar to the one above except it uses reversed opmode, some /// commands(e.g. eor) do not support dEA or rEA modes and require EAd for /// register only operations. /// NOTE when using dd commands it is irrelevant which opmode to use(as it seems) /// but some opcodes support address register and some do not which creates this /// mess. class MxBiArOp_RFRR_EAd CMD> : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.VT:$opd))], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#"EAd"), MxBeadDReg<2>, MxEncEAd_0, MxExtEmpty>>; // $reg <- $reg op $imm class MxBiArOp_RFRI_xEA CMD> : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.IOp:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.IPat:$opd))], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#TYPE.RLet#"EA"), MxBeadDReg<0>, MxEncEAi, !cast("MxExtI"#TYPE.Size#"_2")>>; // Again, there are two ways to write an immediate to Dn register either dEA // opmode or using *I encoding, and again some instrucitons also support address // registers some do not. class MxBiArOp_RFRI CMD> : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.IOp:$opd), MN#"i."#TYPE.Prefix#"\t$opd, $dst", [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.IPat:$opd))], MxArithImmEncoding, !cast("MxEncSize"#TYPE.Size), !cast("MxEncEA"#TYPE.RLet#"_0"), MxExtEmpty, !cast("MxExtI"#TYPE.Size#"_2")>>; let mayLoad = 1 in class MxBiArOp_RFRM CMD, MxEncEA EA, MxEncExt EXT> : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, OPD:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, (TYPE.Load PAT:$opd)))], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#TYPE.RLet#"EA"), MxBeadDReg<0>, EA, EXT>>; } // Constraints let mayLoad = 1, mayStore = 1 in { // FIXME MxBiArOp_FMR/FMI cannot consume CCR from MxAdd/MxSub which leads for // MxAdd to survive the match and subsequent mismatch. class MxBiArOp_FMR CMD, MxEncEA EA, MxEncExt EXT> : MxInst<(outs), (ins MEMOpd:$dst, TYPE.ROp:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#"EA"#TYPE.RLet), MxBeadDReg<1>, EA, EXT>>; class MxBiArOp_FMI CMD, MxEncEA MEMEA, MxEncExt MEMExt> : MxInst<(outs), (ins MEMOpd:$dst, TYPE.IOp:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [], MxArithImmEncoding, !cast("MxEncSize"#TYPE.Size), MEMEA, MEMExt, !cast("MxExtI"#TYPE.Size#"_1")>>; } // mayLoad, mayStore } // Defs = [CCR] multiclass MxBiArOp_DF CMD, bits<4> CMDI> { // op $mem, $reg def NAME#"8dk" : MxBiArOp_RFRM; def NAME#"16dk" : MxBiArOp_RFRM; def NAME#"32dk" : MxBiArOp_RFRM; def NAME#"8dq" : MxBiArOp_RFRM; def NAME#"16dq" : MxBiArOp_RFRM; def NAME#"32dq" : MxBiArOp_RFRM; def NAME#"8dp" : MxBiArOp_RFRM; def NAME#"16dp" : MxBiArOp_RFRM; def NAME#"32dp" : MxBiArOp_RFRM; def NAME#"8df" : MxBiArOp_RFRM; def NAME#"16df" : MxBiArOp_RFRM; def NAME#"32df" : MxBiArOp_RFRM; def NAME#"8dj" : MxBiArOp_RFRM; def NAME#"16dj" : MxBiArOp_RFRM; def NAME#"32dj" : MxBiArOp_RFRM; // op $imm, $reg def NAME#"8di" : MxBiArOp_RFRI_xEA; def NAME#"16di" : MxBiArOp_RFRI_xEA; def NAME#"32di" : MxBiArOp_RFRI_xEA; // op $reg, $mem def NAME#"8pd" : MxBiArOp_FMR; def NAME#"16pd" : MxBiArOp_FMR; def NAME#"32pd" : MxBiArOp_FMR; def NAME#"8fd" : MxBiArOp_FMR; def NAME#"16fd" : MxBiArOp_FMR; def NAME#"32fd" : MxBiArOp_FMR; def NAME#"8jd" : MxBiArOp_FMR; def NAME#"16jd" : MxBiArOp_FMR; def NAME#"32jd" : MxBiArOp_FMR; // op $imm, $mem def NAME#"8pi" : MxBiArOp_FMI; def NAME#"16pi" : MxBiArOp_FMI; def NAME#"32pi" : MxBiArOp_FMI; def NAME#"8fi" : MxBiArOp_FMI; def NAME#"16fi" : MxBiArOp_FMI; def NAME#"32fi" : MxBiArOp_FMI; def NAME#"8ji" : MxBiArOp_FMI; def NAME#"16ji" : MxBiArOp_FMI; def NAME#"32ji" : MxBiArOp_FMI; let isCommutable = isComm in { def NAME#"8dd" : MxBiArOp_RFRR_xEA>; def NAME#"16dd" : MxBiArOp_RFRR_xEA>; def NAME#"32dd" : MxBiArOp_RFRR_xEA>; } // isComm } // MxBiArOp_DF // These special snowflakes allowed to match address registers but since *A // operations do not produce CCR we should not match them against Mx nodes that // produce it. let Pattern = [(null_frag)] in multiclass MxBiArOp_AF CMD, bits<4> CMDI> { def NAME#"32rk" : MxBiArOp_RFRM; def NAME#"32rq" : MxBiArOp_RFRM; def NAME#"32rf" : MxBiArOp_RFRM; def NAME#"32rp" : MxBiArOp_RFRM; def NAME#"32rj" : MxBiArOp_RFRM; def NAME#"32ri" : MxBiArOp_RFRI_xEA; let isCommutable = isComm in def NAME#"32rr" : MxBiArOp_RFRR_xEA>; } // MxBiArOp_AF // NOTE These naturally produce CCR defm ADD : MxBiArOp_DF<"add", MxAdd, 1, 0xD, 0x6>; defm ADD : MxBiArOp_AF<"add", MxAdd, 1, 0xD, 0x6>; defm SUB : MxBiArOp_DF<"sub", MxSub, 0, 0x9, 0x4>; defm SUB : MxBiArOp_AF<"sub", MxSub, 0, 0x9, 0x4>; let Uses = [CCR], Defs = [CCR] in { let Constraints = "$src = $dst" in { // $reg, ccr <- $reg op $reg op ccr class MxBiArOp_RFRRF CMD> : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), MN#"."#TYPE.Prefix#"\t$opd, $dst", [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.VT:$opd, CCR))], MxArithXEncoding, !cast("MxEncSize"#TYPE.Size), MxBead1Bit<0>, MxBeadDReg<2>, MxBeadDReg<0>>>; } // Constraints } // Uses, Defs multiclass MxBiArOp_RFF CMD> { let isCommutable = isComm in { def NAME#"8dd" : MxBiArOp_RFRRF; def NAME#"16dd" : MxBiArOp_RFRRF; def NAME#"32dd" : MxBiArOp_RFRRF; } // isComm } // MxBiArOp_RFF // NOTE These consume and produce CCR defm ADDX : MxBiArOp_RFF<"addx", MxAddX, 1, 0xD>; defm SUBX : MxBiArOp_RFF<"subx", MxSubX, 0, 0x9>; //===----------------------------------------------------------------------===// // And/Xor/Or //===----------------------------------------------------------------------===// defm AND : MxBiArOp_DF<"and", MxAnd, 1, 0xC, 0x2>; defm OR : MxBiArOp_DF<"or", MxOr, 1, 0x8, 0x0>; multiclass MxBiArOp_DF_EAd CMD, bits<4> CMDI> { let isCommutable = 1 in { def NAME#"8dd" : MxBiArOp_RFRR_EAd; def NAME#"16dd" : MxBiArOp_RFRR_EAd; def NAME#"32dd" : MxBiArOp_RFRR_EAd; } // isCommutable = 1 def NAME#"8di" : MxBiArOp_RFRI; def NAME#"16di" : MxBiArOp_RFRI; def NAME#"32di" : MxBiArOp_RFRI; } // MxBiArOp_DF_EAd defm XOR : MxBiArOp_DF_EAd<"eor", MxXor, 0xB, 0xA>; //===----------------------------------------------------------------------===// // CMP //===----------------------------------------------------------------------===// let Defs = [CCR] in { class MxCmp_RR : MxInst<(outs), (ins TYPE.ROp:$lhs, TYPE.ROp:$rhs), "cmp."#TYPE.Prefix#"\t$lhs, $rhs", [(set CCR, (MxCmp TYPE.VT:$lhs, TYPE.VT:$rhs))], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#"dEA"), MxBeadDReg<1>, MxEncEAd_0, MxExtEmpty>>; class MxCmp_RI : MxInst<(outs), (ins TYPE.IOp:$imm, TYPE.ROp:$reg), "cmpi."#TYPE.Prefix#"\t$imm, $reg", [(set CCR, (MxCmp TYPE.IPat:$imm, TYPE.VT:$reg))], MxArithImmEncoding, !cast("MxEncSize"#TYPE.Size), MxEncEAd_1, MxExtEmpty, !cast("MxExtI"#TYPE.Size#"_0")>>; let mayLoad = 1 in { class MxCmp_MI : MxInst<(outs), (ins TYPE.IOp:$imm, MEMOpd:$mem), "cmpi."#TYPE.Prefix#"\t$imm, $mem", [(set CCR, (MxCmp TYPE.IPat:$imm, (load MEMPat:$mem)))], MxArithImmEncoding, !cast("MxEncSize"#TYPE.Size), EA, EXT, !cast("MxExtI"#TYPE.Size#"_0")>>; class MxCmp_BI : MxInst<(outs), (ins TYPE.IOp:$imm, MxAL32:$abs), "cmpi."#TYPE.Prefix#"\t$imm, $abs", [(set CCR, (MxCmp TYPE.IPat:$imm, (load (i32 (MxWrapper tglobaladdr:$abs)))))], MxArithImmEncoding, !cast("MxEncSize"#TYPE.Size), MxEncEAb, MxExtI32_1, !cast("MxExtI"#TYPE.Size#"_0")>>; class MxCmp_RM : MxInst<(outs), (ins TYPE.ROp:$reg, MEMOpd:$mem), "cmp."#TYPE.Prefix#"\t$mem, $reg", [(set CCR, (MxCmp (load MEMPat:$mem), TYPE.ROp:$reg))], MxArithEncoding, !cast("MxOpMode"#TYPE.Size#"dEA"), MxBeadDReg<0>, EA, EXT>>; } // let mayLoad = 1 } // let Defs = [CCR] multiclass MMxCmp_RM { def NAME#TYPE.KOp.Letter : MxCmp_RM; def NAME#TYPE.QOp.Letter : MxCmp_RM; def NAME#TYPE.POp.Letter : MxCmp_RM; def NAME#TYPE.FOp.Letter : MxCmp_RM; def NAME#TYPE.JOp.Letter : MxCmp_RM; } multiclass MMxCmp_MI { def NAME#TYPE.KOp.Letter#"i" : MxCmp_MI; def NAME#TYPE.QOp.Letter#"i" : MxCmp_MI; def NAME#TYPE.POp.Letter#"i" : MxCmp_MI; def NAME#TYPE.FOp.Letter#"i" : MxCmp_MI; def NAME#TYPE.JOp.Letter#"i" : MxCmp_MI; } foreach S = [8, 16, 32] in { def CMP#S#dd : MxCmp_RR("MxType"#S#"d")>; def CMP#S#di : MxCmp_RI("MxType"#S#"d")>; def CMP#S#bi : MxCmp_BI("MxType"#S#"d")>; } // foreach // cmp mem, Dn defm CMP8d : MMxCmp_RM; defm CMP16d : MMxCmp_RM; defm CMP32d : MMxCmp_RM; // cmp #imm, mem defm CMP8 : MMxCmp_MI; defm CMP16 : MMxCmp_MI; defm CMP32 : MMxCmp_MI; //===----------------------------------------------------------------------===// // EXT //===----------------------------------------------------------------------===// def MxExtOpmode_wb : MxBead3Bits<0b010>; def MxExtOpmode_lw : MxBead3Bits<0b011>; def MxExtOpmode_lb : MxBead3Bits<0b111>; /// --------------------------------------------------- /// F E D C B A 9 | 8 7 6 | 5 4 3 | 2 1 0 /// --------------------------------------------------- /// 0 1 0 0 1 0 0 | OPMODE | 0 0 0 | REG /// --------------------------------------------------- class MxExtEncoding : MxEncoding, MxBead3Bits<0b000>, OPMODE, MxBead3Bits<0b100>, MxBead4Bits<0b0100>>; let Defs = [CCR] in let Constraints = "$src = $dst" in class MxExt : MxInst<(outs TO.ROp:$dst), (ins TO.ROp:$src), "ext."#TO.Prefix#"\t$src", [], MxExtEncoding("MxExtOpmode_"#TO.Prefix#FROM.Prefix)>>; def EXT16 : MxExt; def EXT32 : MxExt; def : Pat<(sext_inreg i16:$src, i8), (EXT16 $src)>; def : Pat<(sext_inreg i32:$src, i16), (EXT32 $src)>; def : Pat<(sext_inreg i32:$src, i8), (EXT32 (MOVXd32d16 (EXT16 (EXTRACT_SUBREG $src, MxSubRegIndex16Lo))))>; //===----------------------------------------------------------------------===// // DIV/MUL //===----------------------------------------------------------------------===// def MxSDiMuOpmode : MxBead3Bits<0b111>; def MxUDiMuOpmode : MxBead3Bits<0b011>; /// Word operation: /// ---------------------------------------------------- /// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 /// ---------------------------------------------------- /// | | | EFFECTIVE ADDRESS /// x x x x | REG | OP MODE | MODE | REG /// ---------------------------------------------------- class MxDiMuEncoding : MxEncoding, CMD, EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; let Defs = [CCR] in { let Constraints = "$src = $dst" in { // $reg <- $reg op $reg class MxDiMuOp_DD CMD, MxBead3Bits OPMODE, MxOperand DST, MxOperand OPD> : MxInst<(outs DST:$dst), (ins DST:$src, OPD:$opd), MN#"\t$opd, $dst", [], MxDiMuEncoding, OPMODE, MxEncEAd_2, MxExtEmpty>>; // $reg <- $reg op $imm class MxDiMuOp_DI CMD, MxBead3Bits OPMODE, MxOperand DST, MxOperand OPD> : MxInst<(outs DST:$dst), (ins DST:$src, OPD:$opd), MN#"\t$opd, $dst", [], MxDiMuEncoding, OPMODE, MxEncEAi, MxExtI16_2>>; } // let Constraints } // Defs = [CCR] multiclass MxDiMuOp CMD, bit isComm = 0> { let isCommutable = isComm in { def "S"#NAME#"d32d16" : MxDiMuOp_DD; def "U"#NAME#"d32d16" : MxDiMuOp_DD; } def "S"#NAME#"d32i16" : MxDiMuOp_DI; def "U"#NAME#"d32i16" : MxDiMuOp_DI; } defm DIV : MxDiMuOp<"div", 0x8>; // This is used to cast immediates to 16-bits for operations which don't // support smaller immediate sizes. def as_i16imm : SDNodeXFormgetTargetConstant(N->getSExtValue(), SDLoc(N), MVT::i16); }]>; // RR i8 def : Pat<(sdiv i8:$dst, i8:$opd), (EXTRACT_SUBREG (SDIVd32d16 (MOVSXd32d8 $dst), (MOVSXd16d8 $opd)), MxSubRegIndex8Lo)>; def : Pat<(udiv i8:$dst, i8:$opd), (EXTRACT_SUBREG (UDIVd32d16 (MOVZXd32d8 $dst), (MOVZXd16d8 $opd)), MxSubRegIndex8Lo)>; def : Pat<(srem i8:$dst, i8:$opd), (EXTRACT_SUBREG (ASR32di (ASR32di (SDIVd32d16 (MOVSXd32d8 $dst), (MOVSXd16d8 $opd)), 8), 8), MxSubRegIndex8Lo)>; def : Pat<(urem i8:$dst, i8:$opd), (EXTRACT_SUBREG (LSR32di (LSR32di (UDIVd32d16 (MOVZXd32d8 $dst), (MOVZXd16d8 $opd)), 8), 8), MxSubRegIndex8Lo)>; // RR i16 def : Pat<(sdiv i16:$dst, i16:$opd), (EXTRACT_SUBREG (SDIVd32d16 (MOVSXd32d16 $dst), $opd), MxSubRegIndex16Lo)>; def : Pat<(udiv i16:$dst, i16:$opd), (EXTRACT_SUBREG (UDIVd32d16 (MOVZXd32d16 $dst), $opd), MxSubRegIndex16Lo)>; def : Pat<(srem i16:$dst, i16:$opd), (EXTRACT_SUBREG (ASR32di (ASR32di (SDIVd32d16 (MOVSXd32d16 $dst), $opd), 8), 8), MxSubRegIndex16Lo)>; def : Pat<(urem i16:$dst, i16:$opd), (EXTRACT_SUBREG (LSR32di (LSR32di (UDIVd32d16 (MOVZXd32d16 $dst), $opd), 8), 8), MxSubRegIndex16Lo)>; // RI i8 def : Pat<(sdiv i8:$dst, MximmSExt8:$opd), (EXTRACT_SUBREG (SDIVd32i16 (MOVSXd32d8 $dst), (as_i16imm $opd)), MxSubRegIndex8Lo)>; def : Pat<(udiv i8:$dst, MximmSExt8:$opd), (EXTRACT_SUBREG (UDIVd32i16 (MOVZXd32d8 $dst), (as_i16imm $opd)), MxSubRegIndex8Lo)>; def : Pat<(srem i8:$dst, MximmSExt8:$opd), (EXTRACT_SUBREG (ASR32di (ASR32di (SDIVd32i16 (MOVSXd32d8 $dst), (as_i16imm $opd)), 8), 8), MxSubRegIndex8Lo)>; def : Pat<(urem i8:$dst, MximmSExt8:$opd), (EXTRACT_SUBREG (LSR32di (LSR32di (UDIVd32i16 (MOVZXd32d8 $dst), (as_i16imm $opd)), 8), 8), MxSubRegIndex8Lo)>; // RI i16 def : Pat<(sdiv i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (SDIVd32i16 (MOVSXd32d16 $dst), imm:$opd), MxSubRegIndex16Lo)>; def : Pat<(udiv i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (UDIVd32i16 (MOVZXd32d16 $dst), imm:$opd), MxSubRegIndex16Lo)>; def : Pat<(srem i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (ASR32di (ASR32di (SDIVd32i16 (MOVSXd32d16 $dst), imm:$opd), 8), 8), MxSubRegIndex16Lo)>; def : Pat<(urem i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (LSR32di (LSR32di (UDIVd32i16 (MOVZXd32d16 $dst), imm:$opd), 8), 8), MxSubRegIndex16Lo)>; defm MUL : MxDiMuOp<"mul", 0xC, 1>; // RR def : Pat<(mul i16:$dst, i16:$opd), (EXTRACT_SUBREG (SMULd32d16 (MOVXd32d16 $dst), $opd), MxSubRegIndex16Lo)>; def : Pat<(mulhs i16:$dst, i16:$opd), (EXTRACT_SUBREG (ASR32di (ASR32di (SMULd32d16 (MOVXd32d16 $dst), $opd), 8), 8), MxSubRegIndex16Lo)>; def : Pat<(mulhu i16:$dst, i16:$opd), (EXTRACT_SUBREG (LSR32di (LSR32di (UMULd32d16 (MOVXd32d16 $dst), $opd), 8), 8), MxSubRegIndex16Lo)>; // RI def : Pat<(mul i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (SMULd32i16 (MOVXd32d16 $dst), imm:$opd), MxSubRegIndex16Lo)>; def : Pat<(mulhs i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (ASR32di (ASR32di (SMULd32i16 (MOVXd32d16 $dst), imm:$opd), 8), 8), MxSubRegIndex16Lo)>; def : Pat<(mulhu i16:$dst, MximmSExt16:$opd), (EXTRACT_SUBREG (LSR32di (LSR32di (UMULd32i16 (MOVXd32d16 $dst), imm:$opd), 8), 8), MxSubRegIndex16Lo)>; //===----------------------------------------------------------------------===// // NEG/NEGX //===----------------------------------------------------------------------===// /// ------------+------------+------+---------+--------- /// F E D C | B A 9 8 | 7 6 | 5 4 3 | 2 1 0 /// ------------+------------+------+------------------- /// | | | EFFECTIVE ADDRESS /// 0 1 0 0 | x x x x | SIZE | MODE | REG /// ------------+------------+------+---------+--------- class MxNEGEncoding : MxEncoding, EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; let Defs = [CCR] in { let Constraints = "$src = $dst" in { class MxNeg_D : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src), "neg."#TYPE.Prefix#"\t$dst", [(set TYPE.VT:$dst, (ineg TYPE.VT:$src))], MxNEGEncoding, !cast("MxEncSize"#TYPE.Size), MxEncEAd_0, MxExtEmpty>>; let Uses = [CCR] in { class MxNegX_D : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src), "negx."#TYPE.Prefix#"\t$dst", [(set TYPE.VT:$dst, (MxSubX 0, TYPE.VT:$src, CCR))], MxNEGEncoding, !cast("MxEncSize"#TYPE.Size), MxEncEAd_0, MxExtEmpty>>; } } // let Constraints } // let Defs = [CCR] foreach S = [8, 16, 32] in { def NEG#S#d : MxNeg_D("MxType"#S#"d")>; def NEGX#S#d : MxNegX_D("MxType"#S#"d")>; } def : Pat<(MxSub 0, i8 :$src), (NEG8d MxDRD8 :$src)>; def : Pat<(MxSub 0, i16:$src), (NEG16d MxDRD16:$src)>; def : Pat<(MxSub 0, i32:$src), (NEG32d MxDRD32:$src)>; //===----------------------------------------------------------------------===// // no-CCR Patterns //===----------------------------------------------------------------------===// /// Basically the reason for this stuff is that add and addc share the same /// operand types constraints for whatever reasons and I had to define a common /// MxAdd and MxSub instructions that produce CCR and then pattern-map add and addc /// to it. /// NOTE On the other hand I see no reason why I cannot just drop explicit CCR /// result. Anyway works for now, hopefully I will better understand how this stuff /// is designed later foreach N = ["add", "addc"] in { // add reg, reg def : Pat<(!cast(N) i8 :$src, i8 :$opd), (ADD8dd MxDRD8 :$src, MxDRD8 :$opd)>; def : Pat<(!cast(N) i16:$src, i16:$opd), (ADD16dd MxDRD16:$src, MxDRD16:$opd)>; def : Pat<(!cast(N) i32:$src, i32:$opd), (ADD32rr MxXRD32:$src, MxXRD32:$opd)>; // add (An), reg def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.JPat:$opd)), (ADD8dj MxDRD8:$src, MxType8.JOp:$opd)>; def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.JPat:$opd)), (ADD16dj MxDRD16:$src, MxType16.JOp:$opd)>; def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.JPat:$opd)), (ADD32rj MxXRD32:$src, MxType32.JOp:$opd)>; // add (i,An), reg def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.PPat:$opd)), (ADD8dp MxDRD8:$src, MxType8.POp:$opd)>; def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.PPat:$opd)), (ADD16dp MxDRD16:$src, MxType16.POp:$opd)>; def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.PPat:$opd)), (ADD32rp MxXRD32:$src, MxType32.POp:$opd)>; // add (i,An,Xn), reg def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.FPat:$opd)), (ADD8df MxDRD8:$src, MxType8.FOp:$opd)>; def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.FPat:$opd)), (ADD16df MxDRD16:$src, MxType16.FOp:$opd)>; def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.FPat:$opd)), (ADD32rf MxXRD32:$src, MxType32.FOp:$opd)>; // add reg, imm def : Pat<(!cast(N) i8: $src, MximmSExt8:$opd), (ADD8di MxDRD8 :$src, imm:$opd)>; def : Pat<(!cast(N) i16:$src, MximmSExt16:$opd), (ADD16di MxDRD16:$src, imm:$opd)>; // LEAp is more complex and thus will be selected over normal ADD32ri but it cannot // be used with data registers, here by adding complexity to a simple ADD32ri insts // we make sure it will be selected over LEAp let AddedComplexity = 15 in { def : Pat<(!cast(N) i32:$src, MximmSExt32:$opd), (ADD32ri MxXRD32:$src, imm:$opd)>; } // AddedComplexity = 15 // add imm, (An) def : Pat<(store (!cast(N) (load MxType8.JPat:$dst), MxType8.IPat:$opd), MxType8.JPat:$dst), (ADD8ji MxType8.JOp:$dst, imm:$opd)>; def : Pat<(store (!cast(N) (load MxType16.JPat:$dst), MxType16.IPat:$opd), MxType16.JPat:$dst), (ADD16ji MxType16.JOp:$dst, imm:$opd)>; def : Pat<(store (!cast(N) (load MxType32.JPat:$dst), MxType32.IPat:$opd), MxType32.JPat:$dst), (ADD32ji MxType32.JOp:$dst, imm:$opd)>; } // foreach add, addc def : Pat<(adde i8 :$src, i8 :$opd), (ADDX8dd MxDRD8 :$src, MxDRD8 :$opd)>; def : Pat<(adde i16:$src, i16:$opd), (ADDX16dd MxDRD16:$src, MxDRD16:$opd)>; def : Pat<(adde i32:$src, i32:$opd), (ADDX32dd MxDRD32:$src, MxDRD32:$opd)>; foreach N = ["sub", "subc"] in { // sub reg, reg def : Pat<(!cast(N) i8 :$src, i8 :$opd), (SUB8dd MxDRD8 :$src, MxDRD8 :$opd)>; def : Pat<(!cast(N) i16:$src, i16:$opd), (SUB16dd MxDRD16:$src, MxDRD16:$opd)>; def : Pat<(!cast(N) i32:$src, i32:$opd), (SUB32rr MxXRD32:$src, MxXRD32:$opd)>; // sub (An), reg def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.JPat:$opd)), (SUB8dj MxDRD8:$src, MxType8.JOp:$opd)>; def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.JPat:$opd)), (SUB16dj MxDRD16:$src, MxType16.JOp:$opd)>; def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.JPat:$opd)), (SUB32rj MxXRD32:$src, MxType32.JOp:$opd)>; // sub (i,An), reg def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.PPat:$opd)), (SUB8dp MxDRD8:$src, MxType8.POp:$opd)>; def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.PPat:$opd)), (SUB16dp MxDRD16:$src, MxType16.POp:$opd)>; def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.PPat:$opd)), (SUB32rp MxXRD32:$src, MxType32.POp:$opd)>; // sub (i,An,Xn), reg def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.FPat:$opd)), (SUB8df MxDRD8:$src, MxType8.FOp:$opd)>; def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.FPat:$opd)), (SUB16df MxDRD16:$src, MxType16.FOp:$opd)>; def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.FPat:$opd)), (SUB32rf MxXRD32:$src, MxType32.FOp:$opd)>; // sub reg, imm def : Pat<(!cast(N) i8 :$src, MximmSExt8 :$opd), (SUB8di MxDRD8 :$src, imm:$opd)>; def : Pat<(!cast(N) i16:$src, MximmSExt16:$opd), (SUB16di MxDRD16:$src, imm:$opd)>; def : Pat<(!cast(N) i32:$src, MximmSExt32:$opd), (SUB32ri MxXRD32:$src, imm:$opd)>; // sub imm, (An) def : Pat<(store (!cast(N) (load MxType8.JPat:$dst), MxType8.IPat:$opd), MxType8.JPat:$dst), (SUB8ji MxType8.JOp:$dst, imm:$opd)>; def : Pat<(store (!cast(N) (load MxType16.JPat:$dst), MxType16.IPat:$opd), MxType16.JPat:$dst), (SUB16ji MxType16.JOp:$dst, imm:$opd)>; def : Pat<(store (!cast(N) (load MxType32.JPat:$dst), MxType32.IPat:$opd), MxType32.JPat:$dst), (SUB32ji MxType32.JOp:$dst, imm:$opd)>; } // foreach sub, subx def : Pat<(sube i8 :$src, i8 :$opd), (SUBX8dd MxDRD8 :$src, MxDRD8 :$opd)>; def : Pat<(sube i16:$src, i16:$opd), (SUBX16dd MxDRD16:$src, MxDRD16:$opd)>; def : Pat<(sube i32:$src, i32:$opd), (SUBX32dd MxDRD32:$src, MxDRD32:$opd)>; multiclass BitwisePat { // op reg, reg def : Pat<(OP i8 :$src, i8 :$opd), (!cast(INST#"8dd") MxDRD8 :$src, MxDRD8 :$opd)>; def : Pat<(OP i16:$src, i16:$opd), (!cast(INST#"16dd") MxDRD16:$src, MxDRD16:$opd)>; def : Pat<(OP i32:$src, i32:$opd), (!cast(INST#"32dd") MxDRD32:$src, MxDRD32:$opd)>; // op reg, imm def : Pat<(OP i8: $src, MximmSExt8 :$opd), (!cast(INST#"8di") MxDRD8 :$src, imm:$opd)>; def : Pat<(OP i16:$src, MximmSExt16:$opd), (!cast(INST#"16di") MxDRD16:$src, imm:$opd)>; def : Pat<(OP i32:$src, MximmSExt32:$opd), (!cast(INST#"32di") MxDRD32:$src, imm:$opd)>; } defm : BitwisePat<"AND", and>; defm : BitwisePat<"OR", or>; defm : BitwisePat<"XOR", xor>;