Skip to content
ARMInstrInfo.td 106 KiB
Newer Older
// Return From Exception is a system instruction -- for disassembly only
def RFEW : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, GPR:$base),
                NoItinerary, "rfe${addr:submode}\t$base!",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b011; // W = 1
}

def RFE  : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, GPR:$base),
                NoItinerary, "rfe${addr:submode}\t$base",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b001; // W = 0
}

//===----------------------------------------------------------------------===//
//  Load / store Instructions.
//
Rafael Espindola's avatar
Rafael Espindola committed

Jim Grosbach's avatar
Jim Grosbach committed
let canFoldAsLoad = 1, isReMaterializable = 1, mayHaveSideEffects = 1 in
def LDR  : AI2ldw<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, IIC_iLoadr,
               [(set GPR:$dst, (load addrmode2:$addr))]>;

// Special LDR for loads from non-pc-relative constpools.
let canFoldAsLoad = 1, mayLoad = 1, isReMaterializable = 1,
    mayHaveSideEffects = 1  in
def LDRcp : AI2ldw<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, IIC_iLoadr,
// Loads with zero extension
def LDRH  : AI3ldh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                  IIC_iLoadr, "ldrh", "\t$dst, $addr",
                  [(set GPR:$dst, (zextloadi16 addrmode3:$addr))]>;
Jim Grosbach's avatar
Jim Grosbach committed
def LDRB  : AI2ldb<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm,
                  IIC_iLoadr, "ldrb", "\t$dst, $addr",
                  [(set GPR:$dst, (zextloadi8 addrmode2:$addr))]>;

// Loads with sign extension
def LDRSH : AI3ldsh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                   IIC_iLoadr, "ldrsh", "\t$dst, $addr",
                   [(set GPR:$dst, (sextloadi16 addrmode3:$addr))]>;
def LDRSB : AI3ldsb<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                   IIC_iLoadr, "ldrsb", "\t$dst, $addr",
                   [(set GPR:$dst, (sextloadi8 addrmode3:$addr))]>;
let mayLoad = 1, hasExtraDefRegAllocReq = 1 in {
// Load doubleword
Evan Cheng's avatar
Evan Cheng committed
def LDRD : AI3ldd<(outs GPR:$dst1, GPR:$dst2), (ins addrmode3:$addr), LdMiscFrm,
                 IIC_iLoadr, "ldrd", "\t$dst1, $addr",
                 []>, Requires<[IsARM, HasV5TE]>;

// Indexed loads
def LDR_PRE  : AI2ldwpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode2:$addr), LdFrm, IIC_iLoadru,
                     "ldr", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDR_POST : AI2ldwpo<(outs GPR:$dst, GPR:$base_wb),
                     (ins GPR:$base, am2offset:$offset), LdFrm, IIC_iLoadru,
                     "ldr", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRH_PRE  : AI3ldhpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru,
                     "ldrh", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRH_POST : AI3ldhpo<(outs GPR:$dst, GPR:$base_wb),
                     (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                    "ldrh", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRB_PRE  : AI2ldbpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode2:$addr), LdFrm, IIC_iLoadru,
                     "ldrb", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRB_POST : AI2ldbpo<(outs GPR:$dst, GPR:$base_wb),
                     (ins GPR:$base,am2offset:$offset), LdFrm, IIC_iLoadru,
                    "ldrb", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRSH_PRE : AI3ldshpr<(outs GPR:$dst, GPR:$base_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru,
                      "ldrsh", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRSH_POST: AI3ldshpo<(outs GPR:$dst, GPR:$base_wb),
                      (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                   "ldrsh", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRSB_PRE : AI3ldsbpr<(outs GPR:$dst, GPR:$base_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru,
                      "ldrsb", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRSB_POST: AI3ldsbpo<(outs GPR:$dst, GPR:$base_wb),
                      (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                   "ldrsb", "\t$dst, [$base], $offset", "$base = $base_wb", []>;

// For disassembly only
def LDRD_PRE : AI3lddpr<(outs GPR:$dst1, GPR:$dst2, GPR:$base_wb),
                        (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadr,
                 "ldrd", "\t$dst1, $dst2, $addr!", "$addr.base = $base_wb", []>,
                Requires<[IsARM, HasV5TE]>;

// For disassembly only
def LDRD_POST : AI3lddpo<(outs GPR:$dst1, GPR:$dst2, GPR:$base_wb),
                       (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadr,
            "ldrd", "\t$dst1, $dst2, [$base], $offset", "$base = $base_wb", []>,
                Requires<[IsARM, HasV5TE]>;

// LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only.

def LDRT : AI2ldwpo<(outs GPR:$dst, GPR:$base_wb),
                   (ins GPR:$base, am2offset:$offset), LdFrm, IIC_iLoadru,
                   "ldrt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRBT : AI2ldbpo<(outs GPR:$dst, GPR:$base_wb),
                  (ins GPR:$base,am2offset:$offset), LdFrm, IIC_iLoadru,
                  "ldrbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRSBT : AI3ldsbpo<(outs GPR:$dst, GPR:$base_wb),
                 (ins GPR:$base,am2offset:$offset), LdMiscFrm, IIC_iLoadru,
                 "ldrsbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRHT : AI3ldhpo<(outs GPR:$dst, GPR:$base_wb),
                  (ins GPR:$base, am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                  "ldrht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRSHT : AI3ldshpo<(outs GPR:$dst, GPR:$base_wb),
                 (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                 "ldrsht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def STR  : AI2stw<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStorer,
               [(store GPR:$src, addrmode2:$addr)]>;

// Stores with truncate
Jim Grosbach's avatar
Jim Grosbach committed
def STRH : AI3sth<(outs), (ins GPR:$src, addrmode3:$addr), StMiscFrm,
               IIC_iStorer, "strh", "\t$src, $addr",
               [(truncstorei16 GPR:$src, addrmode3:$addr)]>;

def STRB : AI2stb<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStorer,
               "strb", "\t$src, $addr",
               [(truncstorei8 GPR:$src, addrmode2:$addr)]>;

// Store doubleword
let mayStore = 1, hasExtraSrcRegAllocReq = 1 in
def STRD : AI3std<(outs), (ins GPR:$src1, GPR:$src2, addrmode3:$addr),
               "strd", "\t$src1, $addr", []>, Requires<[IsARM, HasV5TE]>;

// Indexed stores
def STR_PRE  : AI2stwpr<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base, am2offset:$offset),
                    "str", "\t$src, [$base, $offset]!", "$base = $base_wb",
                    [(set GPR:$base_wb,
                      (pre_store GPR:$src, GPR:$base, am2offset:$offset))]>;

def STR_POST : AI2stwpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                    "str", "\t$src, [$base], $offset", "$base = $base_wb",
                    [(set GPR:$base_wb,
                      (post_store GPR:$src, GPR:$base, am2offset:$offset))]>;

def STRH_PRE : AI3sthpr<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am3offset:$offset),
                     "strh", "\t$src, [$base, $offset]!", "$base = $base_wb",
                    [(set GPR:$base_wb,
                      (pre_truncsti16 GPR:$src, GPR:$base,am3offset:$offset))]>;

def STRH_POST: AI3sthpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am3offset:$offset),
                     "strh", "\t$src, [$base], $offset", "$base = $base_wb",
                    [(set GPR:$base_wb, (post_truncsti16 GPR:$src,
                                         GPR:$base, am3offset:$offset))]>;

def STRB_PRE : AI2stbpr<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                     "strb", "\t$src, [$base, $offset]!", "$base = $base_wb",
                    [(set GPR:$base_wb, (pre_truncsti8 GPR:$src,
                                         GPR:$base, am2offset:$offset))]>;

def STRB_POST: AI2stbpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                     "strb", "\t$src, [$base], $offset", "$base = $base_wb",
                    [(set GPR:$base_wb, (post_truncsti8 GPR:$src,
                                         GPR:$base, am2offset:$offset))]>;
// For disassembly only
def STRD_PRE : AI3stdpr<(outs GPR:$base_wb),
                     (ins GPR:$src1, GPR:$src2, GPR:$base, am3offset:$offset),
                     StMiscFrm, IIC_iStoreru,
                     "strd", "\t$src1, $src2, [$base, $offset]!",
                     "$base = $base_wb", []>;

// For disassembly only
def STRD_POST: AI3stdpo<(outs GPR:$base_wb),
                     (ins GPR:$src1, GPR:$src2, GPR:$base, am3offset:$offset),
                     StMiscFrm, IIC_iStoreru,
                     "strd", "\t$src1, $src2, [$base], $offset",
                     "$base = $base_wb", []>;

// STRT and STRBT are for disassembly only.

def STRT : AI2stwpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                    (ins GPR:$src, GPR:$base,am2offset:$offset),
                    StFrm, IIC_iStoreru,
                    "strt", "\t$src, [$base], $offset", "$base = $base_wb",
                    [/* For disassembly only; pattern left blank */]> {
  let Inst{21} = 1; // overwrite
}

def STRBT : AI2stbpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                     StFrm, IIC_iStoreru,
                     "strbt", "\t$src, [$base], $offset", "$base = $base_wb",
                     [/* For disassembly only; pattern left blank */]> {
  let Inst{21} = 1; // overwrite
}

//===----------------------------------------------------------------------===//
//  Load / store multiple Instructions.
//
let mayLoad = 1, hasExtraDefRegAllocReq = 1 in
               (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops),
               LdStMulFrm, IIC_iLoadm, "ldm${addr:submode}${p}\t$addr, $wb",
let mayStore = 1, hasExtraSrcRegAllocReq = 1 in
               (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops),
               LdStMulFrm, IIC_iStorem, "stm${addr:submode}${p}\t$addr, $wb",
//===----------------------------------------------------------------------===//
//  Move Instructions.
//
let neverHasSideEffects = 1 in
def MOVr : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
Jim Grosbach's avatar
Jim Grosbach committed
def MOVs : AsI1<0b1101, (outs GPR:$dst), (ins so_reg:$src),
                "mov", "\t$dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP {
Evan Cheng's avatar
Evan Cheng committed
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi : AsI1<0b1101, (outs GPR:$dst), (ins so_imm:$src), DPFrm, IIC_iMOVi,
                "mov", "\t$dst, $src", [(set GPR:$dst, so_imm:$src)]>, UnaryDP {
  let Inst{25} = 1;
}

let isReMaterializable = 1, isAsCheapAsAMove = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def MOVi16 : AI1<0b1000, (outs GPR:$dst), (ins i32imm:$src),
                 [(set GPR:$dst, imm0_65535:$src)]>,
  let Inst{20} = 0;
def MOVTi16 : AI1<0b1010, (outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
                  DPFrm, IIC_iMOVi,
Jim Grosbach's avatar
Jim Grosbach committed
                        (or (and GPR:$src, 0xffff),
                            lo16AllZero:$imm))]>, UnaryDP,
                  Requires<[IsARM, HasV6T2]> {
  let Inst{20} = 0;
Evan Cheng's avatar
Evan Cheng committed
def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>,
      Requires<[IsARM, HasV6T2]>;

David Goodwin's avatar
David Goodwin committed
let Uses = [CPSR] in
def MOVrx : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, IIC_iMOVsi,
                 [(set GPR:$dst, (ARMrrx GPR:$src))]>, UnaryDP;
// These aren't really mov instructions, but we have to define them this way
// due to flag operands.
Jim Grosbach's avatar
Jim Grosbach committed
def MOVsrl_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo,
                      IIC_iMOVsi, "movs", "\t$dst, $src, lsr #1",
                      [(set GPR:$dst, (ARMsrl_flag GPR:$src))]>, UnaryDP;
def MOVsra_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo,
                      IIC_iMOVsi, "movs", "\t$dst, $src, asr #1",
                      [(set GPR:$dst, (ARMsra_flag GPR:$src))]>, UnaryDP;
//===----------------------------------------------------------------------===//
//  Extend Instructions.
//
// Sign extenders
Rafael Espindola's avatar
Rafael Espindola committed

defm SXTB  : AI_unary_rrot<0b01101010,
                           "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>;
defm SXTH  : AI_unary_rrot<0b01101011,
                           "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>;
defm SXTAB : AI_bin_rrot<0b01101010,
               "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>;
defm SXTAH : AI_bin_rrot<0b01101011,
               "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>;
// TODO: SXT(A){B|H}16
// Zero extenders
let AddedComplexity = 16 in {
defm UXTB   : AI_unary_rrot<0b01101110,
                            "uxtb"  , UnOpFrag<(and node:$Src, 0x000000FF)>>;
defm UXTH   : AI_unary_rrot<0b01101111,
                            "uxth"  , UnOpFrag<(and node:$Src, 0x0000FFFF)>>;
defm UXTB16 : AI_unary_rrot<0b01101100,
                            "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>;
def : ARMV6Pat<(and (shl GPR:$Src, (i32 8)), 0xFF00FF),
               (UXTB16r_rot GPR:$Src, 24)>;
def : ARMV6Pat<(and (srl GPR:$Src, (i32 8)), 0xFF00FF),
               (UXTB16r_rot GPR:$Src, 8)>;

defm UXTAB : AI_bin_rrot<0b01101110, "uxtab",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>;
defm UXTAH : AI_bin_rrot<0b01101111, "uxtah",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>;
// This isn't safe in general, the add is two 16-bit units, not a 32-bit add.
//defm UXTAB16 : xxx<"uxtab16", 0xff00ff>;
// TODO: UXT(A){B|H}16

def SBFX  : I<(outs GPR:$dst),
              (ins GPR:$src, imm0_31:$lsb, imm0_31:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iALUi,
               "sbfx", "\t$dst, $src, $lsb, $width", "", []>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111101;
  let Inst{6-4}   = 0b101;
}

def UBFX  : I<(outs GPR:$dst),
              (ins GPR:$src, imm0_31:$lsb, imm0_31:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iALUi,
               "ubfx", "\t$dst, $src, $lsb, $width", "", []>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111111;
  let Inst{6-4}   = 0b101;
}

//===----------------------------------------------------------------------===//
//  Arithmetic Instructions.
//

                         BinOpFrag<(add  node:$LHS, node:$RHS)>, 1>;
                         BinOpFrag<(sub  node:$LHS, node:$RHS)>>;
defm ADDS : AI1_bin_s_irs<0b0100, "adds",
                          BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>;
defm SUBS : AI1_bin_s_irs<0b0010, "subs",
                          BinOpFrag<(adde_dead_carry node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(sube_dead_carry node:$LHS, node:$RHS)>>;
defm ADCS : AI1_adde_sube_s_irs<0b0101, "adcs",
                          BinOpFrag<(adde_live_carry node:$LHS, node:$RHS)>, 1>;
defm SBCS : AI1_adde_sube_s_irs<0b0110, "sbcs",
                          BinOpFrag<(sube_live_carry node:$LHS, node:$RHS) >>;
// These don't define reg/reg forms, because they are handled above.
def RSBri : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
                  [(set GPR:$dst, (sub so_imm:$b, GPR:$a))]> {
    let Inst{25} = 1;
}
def RSBrs : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
                  [(set GPR:$dst, (sub so_reg:$b, GPR:$a))]> {
    let Inst{25} = 0;
}
def RSBSri : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
                 IIC_iALUi, "rsbs", "\t$dst, $a, $b",
def RSBSrs : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
                 IIC_iALUsr, "rsbs", "\t$dst, $a, $b",
                 [(set GPR:$dst, (subc so_reg:$b, GPR:$a))]> {
    let Inst{20} = 1;
    let Inst{25} = 0;
}
let Uses = [CPSR] in {
def RSCri : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
                 [(set GPR:$dst, (sube_dead_carry so_imm:$b, GPR:$a))]>,
                 Requires<[IsARM]> {
def RSCrs : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
                 DPSoRegFrm, IIC_iALUsr, "rsc", "\t$dst, $a, $b",
                 [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>,
                 Requires<[IsARM]> {
let Defs = [CPSR], Uses = [CPSR] in {
def RSCSri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
                  [(set GPR:$dst, (sube_dead_carry so_imm:$b, GPR:$a))]>,
                  Requires<[IsARM]> {
def RSCSrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
                  DPSoRegFrm, IIC_iALUsr, "rscs\t$dst, $a, $b",
                  [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>,
                  Requires<[IsARM]> {
// (sub X, imm) gets canonicalized to (add X, -imm).  Match this form.
def : ARMPat<(add    GPR:$src, so_imm_neg:$imm),
             (SUBri  GPR:$src, so_imm_neg:$imm)>;
//def : ARMPat<(addc   GPR:$src, so_imm_neg:$imm),
//             (SUBSri GPR:$src, so_imm_neg:$imm)>;
//def : ARMPat<(adde   GPR:$src, so_imm_neg:$imm),
//             (SBCri  GPR:$src, so_imm_neg:$imm)>;
Rafael Espindola's avatar
Rafael Espindola committed

// Note: These are implemented in C++ code, because they have to generate
// ADD/SUBrs instructions, which use a complex pattern that a xform function
// cannot produce.
// (mul X, 2^n+1) -> (add (X << n), X)
// (mul X, 2^n-1) -> (rsb X, (X << n))
// ARM Arithmetic Instruction -- for disassembly only
class AAI<bits<8> op27_20, bits<4> op7_4, string opc>
  : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, IIC_iALUr,
       opc, "\t$dst, $a, $b",
       [/* For disassembly only; pattern left blank */]> {
  let Inst{27-20} = op27_20;
  let Inst{7-4} = op7_4;
}

// Saturating add/subtract -- for disassembly only

def QADD    : AAI<0b00010000, 0b0101, "qadd">;
def QADD16  : AAI<0b01100010, 0b0001, "qadd16">;
def QADD8   : AAI<0b01100010, 0b1001, "qadd8">;
def QASX    : AAI<0b01100010, 0b0011, "qasx">;
def QDADD   : AAI<0b00010100, 0b0101, "qdadd">;
def QDSUB   : AAI<0b00010110, 0b0101, "qdsub">;
def QSAX    : AAI<0b01100010, 0b0101, "qsax">;
def QSUB    : AAI<0b00010010, 0b0101, "qsub">;
def QSUB16  : AAI<0b01100010, 0b0111, "qsub16">;
def QSUB8   : AAI<0b01100010, 0b1111, "qsub8">;
def UQADD16 : AAI<0b01100110, 0b0001, "uqadd16">;
def UQADD8  : AAI<0b01100110, 0b1001, "uqadd8">;
def UQASX   : AAI<0b01100110, 0b0011, "uqasx">;
def UQSAX   : AAI<0b01100110, 0b0101, "uqsax">;
def UQSUB16 : AAI<0b01100110, 0b0111, "uqsub16">;
def UQSUB8  : AAI<0b01100110, 0b1111, "uqsub8">;

// Signed/Unsigned add/subtract -- for disassembly only

def SASX   : AAI<0b01100001, 0b0011, "sasx">;
def SADD16 : AAI<0b01100001, 0b0001, "sadd16">;
def SADD8  : AAI<0b01100001, 0b1001, "sadd8">;
def SSAX   : AAI<0b01100001, 0b0101, "ssax">;
def SSUB16 : AAI<0b01100001, 0b0111, "ssub16">;
def SSUB8  : AAI<0b01100001, 0b1111, "ssub8">;
def UASX   : AAI<0b01100101, 0b0011, "uasx">;
def UADD16 : AAI<0b01100101, 0b0001, "uadd16">;
def UADD8  : AAI<0b01100101, 0b1001, "uadd8">;
def USAX   : AAI<0b01100101, 0b0101, "usax">;
def USUB16 : AAI<0b01100101, 0b0111, "usub16">;
def USUB8  : AAI<0b01100101, 0b1111, "usub8">;

// Signed/Unsigned halving add/subtract -- for disassembly only

def SHASX   : AAI<0b01100011, 0b0011, "shasx">;
def SHADD16 : AAI<0b01100011, 0b0001, "shadd16">;
def SHADD8  : AAI<0b01100011, 0b1001, "shadd8">;
def SHSAX   : AAI<0b01100011, 0b0101, "shsax">;
def SHSUB16 : AAI<0b01100011, 0b0111, "shsub16">;
def SHSUB8  : AAI<0b01100011, 0b1111, "shsub8">;
def UHASX   : AAI<0b01100111, 0b0011, "uhasx">;
def UHADD16 : AAI<0b01100111, 0b0001, "uhadd16">;
def UHADD8  : AAI<0b01100111, 0b1001, "uhadd8">;
def UHSAX   : AAI<0b01100111, 0b0101, "uhsax">;
def UHSUB16 : AAI<0b01100111, 0b0111, "uhsub16">;
def UHSUB8  : AAI<0b01100111, 0b1111, "uhsub8">;

// Unsigned Sum of Absolute Difference [and Accumulate] -- for disassembly only

def USAD8  : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                MulFrm /* for convenience */, NoItinerary, "usad8",
                "\t$dst, $a, $b", []>,
             Requires<[IsARM, HasV6]> {
  let Inst{27-20} = 0b01111000;
  let Inst{15-12} = 0b1111;
  let Inst{7-4} = 0b0001;
}
def USADA8 : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                MulFrm /* for convenience */, NoItinerary, "usada8",
                "\t$dst, $a, $b, $acc", []>,
             Requires<[IsARM, HasV6]> {
  let Inst{27-20} = 0b01111000;
  let Inst{7-4} = 0b0001;
}

// Signed/Unsigned saturate -- for disassembly only

def SSATlsl : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt),
                 DPFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a, LSL $shamt",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{27-21} = 0b0110101;
  let Inst{6-4} = 0b001;
}

def SSATasr : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt),
                 DPFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a, ASR $shamt",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{27-21} = 0b0110101;
  let Inst{6-4} = 0b101;
}

def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), DPFrm,
                NoItinerary, "ssat16", "\t$dst, $bit_pos, $a",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{27-20} = 0b01101010;
  let Inst{7-4} = 0b0011;
}

def USATlsl : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt),
                 DPFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a, LSL $shamt",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{27-21} = 0b0110111;
  let Inst{6-4} = 0b001;
}

def USATasr : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt),
                 DPFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a, ASR $shamt",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{27-21} = 0b0110111;
  let Inst{6-4} = 0b101;
}

def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), DPFrm,
                NoItinerary, "usat16", "\t$dst, $bit_pos, $a",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{27-20} = 0b01101110;
  let Inst{7-4} = 0b0011;
}
//===----------------------------------------------------------------------===//
//  Bitwise Instructions.
//
                          BinOpFrag<(and node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(or  node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(xor node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
Evan Cheng's avatar
Evan Cheng committed
def BFC    : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
Evan Cheng's avatar
Evan Cheng committed
               [(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111110;
  let Inst{6-0}   = 0b0011111;
}

// A8.6.18  BFI - Bitfield insert (Encoding A1)
// Added for disassembler with the pattern field purposely left blank.
def BFI    : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
               "bfi", "\t$dst, $src, $imm", "",
               [/* For disassembly only; pattern left blank */]>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111110;
  let Inst{6-4}   = 0b001; // Rn: Inst{3-0} != 15
}

def  MVNr  : AsI1<0b1111, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
                  [(set GPR:$dst, (not GPR:$src))]>, UnaryDP {
def  MVNs  : AsI1<0b1111, (outs GPR:$dst), (ins so_reg:$src), DPSoRegFrm,
                  [(set GPR:$dst, (not so_reg:$src))]>, UnaryDP {
  let Inst{25} = 0;
}
Evan Cheng's avatar
Evan Cheng committed
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def  MVNi  : AsI1<0b1111, (outs GPR:$dst), (ins so_imm:$imm), DPFrm,
                  [(set GPR:$dst, so_imm_not:$imm)]>,UnaryDP {
    let Inst{25} = 1;
}
def : ARMPat<(and   GPR:$src, so_imm_not:$imm),
             (BICri GPR:$src, so_imm_not:$imm)>;
//===----------------------------------------------------------------------===//
//  Multiply Instructions.
//
let isCommutable = 1 in
def MUL   : AsMul1I<0b0000000, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                   [(set GPR:$dst, (mul GPR:$a, GPR:$b))]>;
def MLA   : AsMul1I<0b0000001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
                   [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>;
def MLS   : AMul1I<0b0000011, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
Evan Cheng's avatar
Evan Cheng committed
                   [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>,
                   Requires<[IsARM, HasV6T2]>;

// Extra precision multiplies with low / high results
let neverHasSideEffects = 1 in {
let isCommutable = 1 in {
def SMULL : AsMul1I<0b0000110, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMUL64,
def UMULL : AsMul1I<0b0000100, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMUL64,

// Multiply + accumulate
def SMLAL : AsMul1I<0b0000111, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMAC64,
def UMLAL : AsMul1I<0b0000101, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMAC64,
def UMAAL : AMul1I <0b0000010, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMAC64,

// Most significant word multiply
def SMMUL : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
            Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b0001;
  let Inst{15-12} = 0b1111;
}
def SMMLA : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               [(set GPR:$dst, (add (mulhs GPR:$a, GPR:$b), GPR:$c))]>,
def SMMLS : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               [(set GPR:$dst, (sub GPR:$c, (mulhs GPR:$a, GPR:$b)))]>,
  def BB : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL32, !strconcat(opc, "bb"), "\t$dst, $a, $b",
              [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16),
                                      (sext_inreg GPR:$b, i16)))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 0;
             let Inst{6} = 0;
           }
  def BT : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL32, !strconcat(opc, "bt"), "\t$dst, $a, $b",
              [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16),
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 0;
             let Inst{6} = 1;
           }
  def TB : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL32, !strconcat(opc, "tb"), "\t$dst, $a, $b",
              [(set GPR:$dst, (opnode (sra GPR:$a, (i32 16)),
                                      (sext_inreg GPR:$b, i16)))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 1;
             let Inst{6} = 0;
           }
  def TT : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL32, !strconcat(opc, "tt"), "\t$dst, $a, $b",
              [(set GPR:$dst, (opnode (sra GPR:$a, (i32 16)),
                                      (sra GPR:$b, (i32 16))))]>,
            Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 1;
             let Inst{6} = 1;
           }
  def WB : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL16, !strconcat(opc, "wb"), "\t$dst, $a, $b",
              [(set GPR:$dst, (sra (opnode GPR:$a,
                                    (sext_inreg GPR:$b, i16)), (i32 16)))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 1;
             let Inst{6} = 0;
           }
  def WT : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL16, !strconcat(opc, "wt"), "\t$dst, $a, $b",
              [(set GPR:$dst, (sra (opnode GPR:$a,
                                    (sra GPR:$b, (i32 16))), (i32 16)))]>,
            Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 1;
             let Inst{6} = 1;
           }
  def BB : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
              IIC_iMAC16, !strconcat(opc, "bb"), "\t$dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc,
                               (opnode (sext_inreg GPR:$a, i16),
                                       (sext_inreg GPR:$b, i16))))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 0;
             let Inst{6} = 0;
           }
  def BT : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
              IIC_iMAC16, !strconcat(opc, "bt"), "\t$dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (opnode (sext_inreg GPR:$a, i16),
Jim Grosbach's avatar
Jim Grosbach committed
                                                    (sra GPR:$b, (i32 16)))))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 0;
             let Inst{6} = 1;
           }
  def TB : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
              IIC_iMAC16, !strconcat(opc, "tb"), "\t$dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, (i32 16)),
                                                 (sext_inreg GPR:$b, i16))))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 1;
             let Inst{6} = 0;
           }
  def TT : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
              IIC_iMAC16, !strconcat(opc, "tt"), "\t$dst, $a, $b, $acc",
             [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, (i32 16)),
                                                    (sra GPR:$b, (i32 16)))))]>,
            Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 1;
             let Inst{6} = 1;
           }
  def WB : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
              IIC_iMAC16, !strconcat(opc, "wb"), "\t$dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a,
                                       (sext_inreg GPR:$b, i16)), (i32 16))))]>,
           Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 0;
             let Inst{6} = 0;
           }
  def WT : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
              IIC_iMAC16, !strconcat(opc, "wt"), "\t$dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a,
                                         (sra GPR:$b, (i32 16))), (i32 16))))]>,
            Requires<[IsARM, HasV5TE]> {
             let Inst{5} = 0;
             let Inst{6} = 1;
           }
defm SMUL : AI_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
defm SMLA : AI_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
// Halfword multiply accumulate long: SMLAL<x><y> -- for disassembly only
def SMLALBB : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 0;
  let Inst{6} = 0;
}

def SMLALBT : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 0;
  let Inst{6} = 1;
}

def SMLALTB : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 1;
  let Inst{6} = 0;
}

def SMLALTT : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlaltt", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 1;
  let Inst{6} = 1;
}

// Helper class for AI_smld -- for disassembly only
class AMulDualI<bit long, bit sub, bit swap, dag oops, dag iops,
                InstrItinClass itin, string opc, string asm>
  : AI<oops, iops, MulFrm, itin, opc, asm, []>, Requires<[IsARM, HasV6]> {
  let Inst{4}     = 1;
  let Inst{5}     = swap;
  let Inst{6}     = sub;
  let Inst{7}     = 0;
  let Inst{21-20} = 0b00;
  let Inst{22}    = long;
  let Inst{27-23} = 0b01110;
}

multiclass AI_smld<bit sub, string opc> {

  def D : AMulDualI<0, sub, 0, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                  NoItinerary, !strconcat(opc, "d"), "\t$dst, $a, $b, $acc">;

  def DX : AMulDualI<0, sub, 1, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                  NoItinerary, !strconcat(opc, "dx"), "\t$dst, $a, $b, $acc">;

  def LD : AMulDualI<1, sub, 0, (outs GPR:$ldst,GPR:$hdst), (ins GPR:$a,GPR:$b),
                  NoItinerary, !strconcat(opc, "ld"), "\t$ldst, $hdst, $a, $b">;

  def LDX : AMulDualI<1, sub, 1, (outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                  NoItinerary, !strconcat(opc, "ldx"),"\t$ldst, $hdst, $a, $b">;

}

defm SMLA : AI_smld<0, "smla">;
defm SMLS : AI_smld<1, "smls">;

// TODO: Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD
// Note: SMLAD, SMLSD, SMLALD, SMLSLD have been defined for disassembly only.
//===----------------------------------------------------------------------===//
//  Misc. Arithmetic Instructions.
//
def CLZ  : AMiscA1I<0b000010110, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
              [(set GPR:$dst, (ctlz GPR:$src))]>, Requires<[IsARM, HasV5T]> {
  let Inst{7-4}   = 0b0001;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
Jim Grosbach's avatar
Jim Grosbach committed
def RBIT : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
              "rbit", "\t$dst, $src",
              [(set GPR:$dst, (ARMrbit GPR:$src))]>,
           Requires<[IsARM, HasV6T2]> {
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{7-4}   = 0b0011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}

def REV  : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
              [(set GPR:$dst, (bswap GPR:$src))]>, Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b0011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
def REV16 : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
               [(set GPR:$dst,
                   (or (and (srl GPR:$src, (i32 8)), 0xFF),
                       (or (and (shl GPR:$src, (i32 8)), 0xFF00),
                           (or (and (srl GPR:$src, (i32 8)), 0xFF0000),
                               (and (shl GPR:$src, (i32 8)), 0xFF000000)))))]>,
               Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b1011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
def REVSH : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
               [(set GPR:$dst,
                  (sext_inreg
                    (or (srl (and GPR:$src, 0xFF00), (i32 8)),
                        (shl GPR:$src, (i32 8))), i16))]>,
               Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b1011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
def PKHBT : AMiscA1I<0b01101000, (outs GPR:$dst),
                                 (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
               IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2, LSL $shamt",
               [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF),
                                   (and (shl GPR:$src2, (i32 imm:$shamt)),
                                        0xFFFF0000)))]>,
               Requires<[IsARM, HasV6]> {
  let Inst{6-4} = 0b001;
}

// Alternate cases for PKHBT where identities eliminate some nodes.
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (and GPR:$src2, 0xFFFF0000)),
               (PKHBT GPR:$src1, GPR:$src2, 0)>;
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$shamt)),
               (PKHBT GPR:$src1, GPR:$src2, imm16_31:$shamt)>;


def PKHTB : AMiscA1I<0b01101000, (outs GPR:$dst),
                                 (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
               IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2, ASR $shamt",
               [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000),
                                   (and (sra GPR:$src2, imm16_31:$shamt),
                                        0xFFFF)))]>, Requires<[IsARM, HasV6]> {
  let Inst{6-4} = 0b101;
}

// Alternate cases for PKHTB where identities eliminate some nodes.  Note that
// a shift amount of 0 is *not legal* here, it is PKHBT instead.
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, (i32 16))),
               (PKHTB GPR:$src1, GPR:$src2, 16)>;
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000),
                   (and (srl GPR:$src2, imm1_15:$shamt), 0xFFFF)),
               (PKHTB GPR:$src1, GPR:$src2, imm1_15:$shamt)>;