summaryrefslogtreecommitdiffstats
path: root/lib/Target/ARM/ARMInstrThumb2.td
blob: 0aba2d52280952297392f1ea3efdfcb417954a79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//===- ARMInstrThumb2.td - Thumb2 support for ARM -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the Thumb2 instruction set.
//
//===----------------------------------------------------------------------===//

// Shifted operands. No register controlled shifts for Thumb2.
// Note: We do not support rrx shifted operands yet.
def t2_so_reg : Operand<i32>,    // reg imm
                ComplexPattern<i32, 2, "SelectShifterOperand",
                               [shl,srl,sra,rotr]> {
  let PrintMethod = "printSOOperand";
  let MIOperandInfo = (ops GPR, i32imm);
}

def LO16 : SDNodeXForm<imm, [{
  // Transformation function: shift the immediate value down into the low bits.
  return getI32Imm((unsigned short)N->getZExtValue());
}]>;

def HI16 : SDNodeXForm<imm, [{
  // Transformation function: shift the immediate value down into the low bits.
  return getI32Imm((unsigned)N->getZExtValue() >> 16);
}]>;

def imm16high : PatLeaf<(i32 imm), [{
  // Returns true if all bits out of the [31..16] range are 0.
  return ((N->getZExtValue() & 0xFFFF0000ULL) == N->getZExtValue());
}], HI16>;

def imm16high0xffff : PatLeaf<(i32 imm), [{
  // Returns true if lo 16 bits are set and this is a 32-bit value. 
  return ((N->getZExtValue() & 0x0000FFFFULL) == 0xFFFFULL);
}], HI16>;

def imm0_4095 : PatLeaf<(i32 imm), [{ 
  return (uint32_t)N->getZExtValue() < 4096; 
}]>; 

def imm0_4095_neg : PatLeaf<(i32 imm), [{ 
 return (uint32_t)-N->getZExtValue() < 4096; 
}], imm_neg_XFORM>; 

def imm0_65535 : PatLeaf<(i32 imm), [{ 
  return N->getZExtValue() < 65536; 
}]>; 

// A6.3.2 Modified immediate constants in Thumb instructions (#<const>)
// FIXME: Move it the the addrmode matcher code.
def t2_so_imm : PatLeaf<(i32 imm), [{
  uint64_t v = N->getZExtValue();
  if (v == 0 || v > 0xffffffffUL) return false;
  // variant1 - 0b0000x - 8-bit which could be zero (not supported for now)

  // variant2 - 0b00nnx - 8-bit repeated inside the 32-bit room
  unsigned hi16 = (unsigned)(v >> 16);
  unsigned lo16 = (unsigned)(v & 0xffffUL);
  bool valid = (hi16 == lo16) && (
    (v & 0x00ff00ffUL) == 0 ||        // type 0001x
    (v & 0xff00ff00UL) == 0 ||        // type 0010x
    ((lo16 >> 8) == (lo16 & 0xff)));  // type 0011x
  if (valid) return true;

  // variant3 - 0b01000..0b11111 - 8-bit shifted inside the 32-bit room
  unsigned shift = CountLeadingZeros_32(v);
  uint64_t mask = (0xff000000ULL >> shift);
  // If valid, it is type 01000 + shift
  return ((shift < 24) && (v & mask) > 0) && ((v & (~mask)) == 0);
}]>;


//===----------------------------------------------------------------------===//
//  Thumb-2 to cover the functionality of the ARM instruction set.
//

/// T2I_bin_irs - Defines a set of (op reg, {so_imm|reg|so_reg}) patterns for a
//  binary operation that produces a value.
multiclass T2I_bin_irs<string opc, PatFrag opnode> {
   // shifted imm
   def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
                       !strconcat(opc, " $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
                      Requires<[HasThumb2]>;
   // register
   def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
                       !strconcat(opc, " $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, 
                      Requires<[HasThumb2]>;
   // shifted register
   def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
                       !strconcat(opc, " $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, 
                      Requires<[HasThumb2]>;
}

/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the
/// instruction modifies the CPSR register.
let Defs = [CPSR] in {
multiclass T2I_bin_s_irs<string opc, PatFrag opnode> {
   // shifted imm
   def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
                       !strconcat(opc, "s $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
                      Requires<[HasThumb2]>;

   // register
   def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
                       !strconcat(opc, "s $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, 
                      Requires<[HasThumb2]>;

   // shifted register
   def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
                       !strconcat(opc, "s $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, 
                      Requires<[HasThumb2]>;
}
}

/// T2I_bin_c_irs - Similar to T2I_bin_irs except it uses the 's' bit. Also the
/// instruction can optionally set the CPSR register.
let Uses = [CPSR] in {
multiclass T2I_bin_c_irs<string opc, PatFrag opnode> {
   // shifted imm
   def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs, cc_out:$s),
                       !strconcat(opc, "${s} $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
                      Requires<[HasThumb2]>;

   // register
   def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs, cc_out:$s),
                       !strconcat(opc, "${s} $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, 
                      Requires<[HasThumb2]>;

   // shifted register
   def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s),
                       !strconcat(opc, "${s} $dst, $lhs, $rhs"),
                       [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, 
                      Requires<[HasThumb2]>;
}
}

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

//===----------------------------------------------------------------------===//
//  Move Instructions.
//
def tMOVi16  : PseudoInst<(outs GPR:$dst), (ins i32imm:$src),
                          "movw $dst, $src",
                          [(set GPR:$dst, imm0_65535:$src)]>, 
                         Requires<[HasThumb2]>;

let Constraints = "$src = $dst" in
def tMOVTi16 : PseudoInst<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
                          "movt $dst, $imm",
                          [(set GPR:$dst, (or (and GPR:$src, 0xffff), 
                                              imm16high:$imm))]>,
                         Requires<[HasThumb2]>;

def : Pat<(and (or GPR:$src, imm16high:$imm1), imm16high0xffff:$imm2),
          (tMOVTi16 GPR:$src, (HI16 imm16high:$imm1))>,
         Requires<[HasThumb2]>;

def : Pat<(i32 imm:$imm),
          (tMOVTi16 (tMOVi16 (LO16 imm:$imm)),(HI16 imm:$imm))>,
         Requires<[HasThumb2]>;

//===----------------------------------------------------------------------===//
//  Arithmetic Instructions.
//
defm t2ADD  : T2I_bin_irs <"add", BinOpFrag<(add node:$LHS, node:$RHS)>>;
defm t2SUB  : T2I_bin_irs <"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>;

def tADDri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
                          "add $dst, $lhs, $rhs", 
                          [(set GPR:$dst, (add GPR:$lhs, imm0_4095:$rhs))]>,
                         Requires<[HasThumb2]>; 
def tSUBri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), 
                          "sub $dst, $lhs, $rhs",
                          [(set GPR:$dst, (add GPR:$lhs, imm0_4095_neg:$rhs))]>,
                         Requires<[HasThumb2]>;

defm t2ADDS : T2I_bin_s_irs<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>;
defm t2SUBS : T2I_bin_s_irs<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;

defm t2ADC : T2I_bin_c_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>;
defm t2SBC : T2I_bin_c_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;


def tMLS : PseudoInst<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), 
                      "mls $dst, $a, $b, $c", 
                      [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>,
                     Requires<[HasThumb2]>;

def tORNrs : PseudoInst<(outs GPR:$dst), (ins GPR:$src1, t2_so_reg:$src2),
                        "orn $dst, $src1, $src2",
                        [(set GPR:$dst, (or GPR:$src1, (not t2_so_reg: $src2)))]>,
                       Requires<[HasThumb2]>;
OpenPOWER on IntegriCloud