Newer
Older
let Inst{5} = 0;
let Inst{6} = 0;
}
Raul Herbster
committed
def BT : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
!strconcat(opc, "bt"), " $dst, $a, $b",
[(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16),
(sra GPR:$b, 16)))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 0;
let Inst{6} = 1;
}
Raul Herbster
committed
def TB : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
!strconcat(opc, "tb"), " $dst, $a, $b",
[(set GPR:$dst, (opnode (sra GPR:$a, 16),
(sext_inreg GPR:$b, i16)))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 1;
let Inst{6} = 0;
}
Raul Herbster
committed
def TT : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
!strconcat(opc, "tt"), " $dst, $a, $b",
[(set GPR:$dst, (opnode (sra GPR:$a, 16),
(sra GPR:$b, 16)))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 1;
let Inst{6} = 1;
}
Raul Herbster
committed
def WB : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
!strconcat(opc, "wb"), " $dst, $a, $b",
[(set GPR:$dst, (sra (opnode GPR:$a,
(sext_inreg GPR:$b, i16)), 16))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 1;
let Inst{6} = 0;
}
Raul Herbster
committed
def WT : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
!strconcat(opc, "wt"), " $dst, $a, $b",
[(set GPR:$dst, (sra (opnode GPR:$a,
(sra GPR:$b, 16)), 16))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 1;
let Inst{6} = 1;
}
Raul Herbster
committed
multiclass AI_smla<string opc, PatFrag opnode> {
def BB : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
!strconcat(opc, "bb"), " $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;
}
Raul Herbster
committed
def BT : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
!strconcat(opc, "bt"), " $dst, $a, $b, $acc",
[(set GPR:$dst, (add GPR:$acc, (opnode (sext_inreg GPR:$a, i16),
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 0;
let Inst{6} = 1;
}
Raul Herbster
committed
def TB : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
!strconcat(opc, "tb"), " $dst, $a, $b, $acc",
[(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, 16),
(sext_inreg GPR:$b, i16))))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 1;
let Inst{6} = 0;
}
Raul Herbster
committed
def TT : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
!strconcat(opc, "tt"), " $dst, $a, $b, $acc",
[(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, 16),
(sra GPR:$b, 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),
!strconcat(opc, "wb"), " $dst, $a, $b, $acc",
[(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a,
(sext_inreg GPR:$b, i16)), 16)))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 0;
let Inst{6} = 0;
}
Raul Herbster
committed
def WT : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
!strconcat(opc, "wt"), " $dst, $a, $b, $acc",
[(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a,
(sra GPR:$b, 16)), 16)))]>,
Requires<[IsARM, HasV5TE]> {
let Inst{5} = 0;
let Inst{6} = 1;
}
Raul Herbster
committed
defm SMUL : AI_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
defm SMLA : AI_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
// TODO: Halfword multiple accumulate long: SMLAL<x><y>
// TODO: Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD
//===----------------------------------------------------------------------===//
// Misc. Arithmetic Instructions.
//
def CLZ : AMiscA1I<0b000010110, (outs GPR:$dst), (ins GPR:$src),
"clz", " $dst, $src",
[(set GPR:$dst, (ctlz GPR:$src))]>, Requires<[IsARM, HasV5T]> {
let Inst{7-4} = 0b0001;
let Inst{11-8} = 0b1111;
let Inst{19-16} = 0b1111;
}
def REV : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src),
"rev", " $dst, $src",
[(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),
"rev16", " $dst, $src",
[(set GPR:$dst,
(or (and (srl GPR:$src, 8), 0xFF),
(or (and (shl GPR:$src, 8), 0xFF00),
(or (and (srl GPR:$src, 8), 0xFF0000),
(and (shl GPR:$src, 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),
"revsh", " $dst, $src",
(or (srl (and GPR:$src, 0xFF00), 8),
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),
"pkhbt", " $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),
"pkhtb", " $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, 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)>;
//===----------------------------------------------------------------------===//
// Comparison Instructions...
//
Jim Grosbach
committed
defm CMP : AI1_cmp_irs<0b1010, "cmp",
BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
Jim Grosbach
committed
defm CMN : AI1_cmp_irs<0b1011, "cmn",
BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;
// Note that TST/TEQ don't set all the same flags that CMP does!
Evan Cheng
committed
defm TST : AI1_cmp_irs<0b1000, "tst",
BinOpFrag<(ARMcmpNZ (and node:$LHS, node:$RHS), 0)>>;
Evan Cheng
committed
defm TEQ : AI1_cmp_irs<0b1001, "teq",
BinOpFrag<(ARMcmpNZ (xor node:$LHS, node:$RHS), 0)>>;
Lauro Ramos Venancio
committed
Jim Grosbach
committed
defm CMPnz : AI1_cmp_irs<0b1010, "cmp",
BinOpFrag<(ARMcmpNZ node:$LHS, node:$RHS)>>;
Jim Grosbach
committed
defm CMNnz : AI1_cmp_irs<0b1011, "cmn",
BinOpFrag<(ARMcmpNZ node:$LHS,(ineg node:$RHS))>>;
def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm),
(CMNri GPR:$src, so_imm_neg:$imm)>;
Lauro Ramos Venancio
committed
def : ARMPat<(ARMcmpNZ GPR:$src, so_imm_neg:$imm),
(CMNri GPR:$src, so_imm_neg:$imm)>;
// FIXME: should be able to write a pattern for ARMcmov, but can't use
// a two-value operand where a dag node expects two operands. :(
Evan Cheng
committed
def MOVCCr : AI1<0b1101, (outs GPR:$dst), (ins GPR:$false, GPR:$true), DPFrm,
Evan Cheng
committed
"mov", " $dst, $true",
[/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
Evan Cheng
committed
RegConstraint<"$false = $dst">, UnaryDP;
Evan Cheng
committed
def MOVCCs : AI1<0b1101, (outs GPR:$dst),
(ins GPR:$false, so_reg:$true), DPSoRegFrm,
Evan Cheng
committed
"mov", " $dst, $true",
[/*(set GPR:$dst, (ARMcmov GPR:$false, so_reg:$true, imm:$cc, CCR:$ccr))*/]>,
Evan Cheng
committed
RegConstraint<"$false = $dst">, UnaryDP;
Evan Cheng
committed
def MOVCCi : AI1<0b1101, (outs GPR:$dst),
(ins GPR:$false, so_imm:$true), DPFrm,
Evan Cheng
committed
"mov", " $dst, $true",
[/*(set GPR:$dst, (ARMcmov GPR:$false, so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
Evan Cheng
committed
RegConstraint<"$false = $dst">, UnaryDP;
// LEApcrel - Load a pc-relative address into a register without offending the
// assembler.
def LEApcrel : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, pred:$p), Pseudo,
!strconcat(!strconcat(".set PCRELV${:uid}, ($label-(",
"${:private}PCRELL${:uid}+8))\n"),
!strconcat("${:private}PCRELL${:uid}:\n\t",
"add$p $dst, pc, #PCRELV${:uid}")),
def LEApcrelJT : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, i32imm:$id, pred:$p),
Pseudo,
!strconcat(!strconcat(".set PCRELV${:uid}, (${label}_${id:no_hash}-(",
"${:private}PCRELL${:uid}+8))\n"),
!strconcat("${:private}PCRELL${:uid}:\n\t",
"add$p $dst, pc, #PCRELV${:uid}")),
Lauro Ramos Venancio
committed
//===----------------------------------------------------------------------===//
// TLS Instructions
//
// __aeabi_read_tp preserves the registers r1-r3.
Evan Cheng
committed
let isCall = 1,
Defs = [R0, R12, LR, CPSR] in {
def TPsoft : ABXI<0b1011, (outs), (ins),
Evan Cheng
committed
"bl __aeabi_read_tp",
Lauro Ramos Venancio
committed
[(set R0, ARMthread_pointer)]>;
}
Jim Grosbach
committed
//===----------------------------------------------------------------------===//
// SJLJ Exception handling intrinsics
// eh_sjlj_setjmp() is a three instruction sequence to store the return
// address and save #0 in R0 for the non-longjmp case.
Jim Grosbach
committed
// Since by its nature we may be coming from some other function to get
// here, and we're using the stack frame for the containing function to
// save/restore registers, we can't keep anything live in regs across
// the eh_sjlj_setjmp(), else it will almost certainly have been tromped upon
Jim Grosbach
committed
// when we get here from a longjmp(). We force everthing out of registers
// except for our own input by listing the relevant registers in Defs. By
// doing so, we also cause the prologue/epilogue code to actively preserve
// all of the callee-saved resgisters, which is exactly what we want.
Jim Grosbach
committed
let Defs =
[ R0, R1, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR,
D0, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15 ] in {
def Int_eh_sjlj_setjmp : XI<(outs), (ins GPR:$src),
Jim Grosbach
committed
AddrModeNone, SizeSpecial, IndexModeNone, Pseudo,
"add r0, pc, #4\n\t"
"str r0, [$src, #+4]\n\t"
"mov r0, #0 @ eh_setjmp", "",
[(set R0, (ARMeh_sjlj_setjmp GPR:$src))]>;
Jim Grosbach
committed
}
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//
// ConstantPool, GlobalAddress, and JumpTable
def : ARMPat<(ARMWrapper tglobaladdr :$dst), (LEApcrel tglobaladdr :$dst)>;
def : ARMPat<(ARMWrapper tconstpool :$dst), (LEApcrel tconstpool :$dst)>;
def : ARMPat<(ARMWrapperJT tjumptable:$dst, imm:$id),
(LEApcrelJT tjumptable:$dst, imm:$id)>;
let isReMaterializable = 1 in
Evan Cheng
committed
def MOVi2pieces : AI1x2<(outs GPR:$dst), (ins so_imm2part:$src), Pseudo,
"mov", " $dst, $src",
[(set GPR:$dst, so_imm2part:$src)]>;
def : ARMPat<(or GPR:$LHS, so_imm2part:$RHS),
(ORRri (ORRri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
(so_imm2part_2 imm:$RHS))>;
def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS),
(EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
(so_imm2part_2 imm:$RHS))>;
// Direct calls
def : ARMPat<(ARMcall texternalsym:$func), (BL texternalsym:$func)>;
// zextload i1 -> zextload i8
def : ARMPat<(zextloadi1 addrmode2:$addr), (LDRB addrmode2:$addr)>;
// extload -> zextload
def : ARMPat<(extloadi1 addrmode2:$addr), (LDRB addrmode2:$addr)>;
def : ARMPat<(extloadi8 addrmode2:$addr), (LDRB addrmode2:$addr)>;
def : ARMPat<(extloadi16 addrmode3:$addr), (LDRH addrmode3:$addr)>;
def : ARMPat<(extloadi8 addrmodepc:$addr), (PICLDRB addrmodepc:$addr)>;
def : ARMPat<(extloadi16 addrmodepc:$addr), (PICLDRH addrmodepc:$addr)>;
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
// smul* and smla*
def : ARMV5TEPat<(mul (sra (shl GPR:$a, 16), 16), (sra (shl GPR:$b, 16), 16)),
(SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, sext_16_node:$b),
(SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra (shl GPR:$a, 16), 16), (sra GPR:$b, 16)),
(SMULBT GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, (sra GPR:$b, 16)),
(SMULBT GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra GPR:$a, 16), (sra (shl GPR:$b, 16), 16)),
(SMULTB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra GPR:$a, 16), sext_16_node:$b),
(SMULTB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(sra (mul GPR:$a, (sra (shl GPR:$b, 16), 16)), 16),
(SMULWB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(sra (mul GPR:$a, sext_16_node:$b), 16),
(SMULWB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(add GPR:$acc,
(mul (sra (shl GPR:$a, 16), 16),
(sra (shl GPR:$b, 16), 16))),
(SMLABB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(mul sext_16_node:$a, sext_16_node:$b)),
(SMLABB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(mul (sra (shl GPR:$a, 16), 16), (sra GPR:$b, 16))),
(SMLABT GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(mul sext_16_node:$a, (sra GPR:$b, 16))),
(SMLABT GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(mul (sra GPR:$a, 16), (sra (shl GPR:$b, 16), 16))),
(SMLATB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(mul (sra GPR:$a, 16), sext_16_node:$b)),
(SMLATB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(sra (mul GPR:$a, (sra (shl GPR:$b, 16), 16)), 16)),
(SMLAWB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
(sra (mul GPR:$a, sext_16_node:$b), 16)),
(SMLAWB GPR:$a, GPR:$b, GPR:$acc)>;
//===----------------------------------------------------------------------===//
// Thumb Support
//
//===----------------------------------------------------------------------===//
// Floating Point Support
//