blob: dad18fd8e8821a6feb5df80c4236a64d0430ee22 [file] [log] [blame]
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +00001//===- AArch64InstructionSelector.cpp ----------------------------*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9/// \file
10/// This file implements the targeting of the InstructionSelector class for
11/// AArch64.
12/// \todo This should be generated by TableGen.
13//===----------------------------------------------------------------------===//
14
15#include "AArch64InstructionSelector.h"
16#include "AArch64InstrInfo.h"
17#include "AArch64RegisterBankInfo.h"
18#include "AArch64RegisterInfo.h"
19#include "AArch64Subtarget.h"
20#include "llvm/CodeGen/MachineBasicBlock.h"
21#include "llvm/CodeGen/MachineFunction.h"
22#include "llvm/CodeGen/MachineInstr.h"
23#include "llvm/CodeGen/MachineInstrBuilder.h"
24#include "llvm/CodeGen/MachineRegisterInfo.h"
25#include "llvm/IR/Type.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/raw_ostream.h"
28
29#define DEBUG_TYPE "aarch64-isel"
30
31using namespace llvm;
32
33#ifndef LLVM_BUILD_GLOBAL_ISEL
34#error "You shouldn't build this"
35#endif
36
37AArch64InstructionSelector::AArch64InstructionSelector(
38 const AArch64Subtarget &STI, const AArch64RegisterBankInfo &RBI)
39 : InstructionSelector(), TII(*STI.getInstrInfo()),
40 TRI(*STI.getRegisterInfo()), RBI(RBI) {}
41
42/// Select the AArch64 opcode for the basic binary operation \p GenericOpc
43/// (such as G_OR or G_ADD), appropriate for the register bank \p RegBankID
44/// and of size \p OpSize.
45/// \returns \p GenericOpc if the combination is unsupported.
46static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID,
47 unsigned OpSize) {
48 switch (RegBankID) {
49 case AArch64::GPRRegBankID:
50 switch (OpSize) {
51 case 32:
52 switch (GenericOpc) {
53 case TargetOpcode::G_OR:
54 return AArch64::ORRWrr;
Ahmed Bougacha6db3cfe2016-07-29 16:56:25 +000055 case TargetOpcode::G_XOR:
56 return AArch64::EORWrr;
Ahmed Bougacha61a79282016-07-28 16:58:31 +000057 case TargetOpcode::G_AND:
58 return AArch64::ANDWrr;
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +000059 case TargetOpcode::G_ADD:
60 return AArch64::ADDWrr;
Ahmed Bougachad7748d62016-07-28 16:58:35 +000061 case TargetOpcode::G_SUB:
62 return AArch64::SUBWrr;
Ahmed Bougacha2ac5bf92016-08-16 14:02:47 +000063 case TargetOpcode::G_SHL:
64 return AArch64::LSLVWr;
65 case TargetOpcode::G_LSHR:
66 return AArch64::LSRVWr;
67 case TargetOpcode::G_ASHR:
68 return AArch64::ASRVWr;
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +000069 default:
70 return GenericOpc;
71 }
72 case 64:
73 switch (GenericOpc) {
74 case TargetOpcode::G_OR:
75 return AArch64::ORRXrr;
Ahmed Bougacha6db3cfe2016-07-29 16:56:25 +000076 case TargetOpcode::G_XOR:
77 return AArch64::EORXrr;
Ahmed Bougacha61a79282016-07-28 16:58:31 +000078 case TargetOpcode::G_AND:
79 return AArch64::ANDXrr;
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +000080 case TargetOpcode::G_ADD:
81 return AArch64::ADDXrr;
Ahmed Bougachad7748d62016-07-28 16:58:35 +000082 case TargetOpcode::G_SUB:
83 return AArch64::SUBXrr;
Ahmed Bougacha2ac5bf92016-08-16 14:02:47 +000084 case TargetOpcode::G_SHL:
85 return AArch64::LSLVXr;
86 case TargetOpcode::G_LSHR:
87 return AArch64::LSRVXr;
88 case TargetOpcode::G_ASHR:
89 return AArch64::ASRVXr;
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +000090 default:
91 return GenericOpc;
92 }
93 }
94 };
95 return GenericOpc;
96}
97
Ahmed Bougacha7adfac52016-07-29 16:56:16 +000098/// Select the AArch64 opcode for the G_LOAD or G_STORE operation \p GenericOpc,
99/// appropriate for the (value) register bank \p RegBankID and of memory access
100/// size \p OpSize. This returns the variant with the base+unsigned-immediate
101/// addressing mode (e.g., LDRXui).
102/// \returns \p GenericOpc if the combination is unsupported.
103static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID,
104 unsigned OpSize) {
105 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
106 switch (RegBankID) {
107 case AArch64::GPRRegBankID:
108 switch (OpSize) {
109 case 32:
110 return isStore ? AArch64::STRWui : AArch64::LDRWui;
111 case 64:
112 return isStore ? AArch64::STRXui : AArch64::LDRXui;
113 }
114 };
115 return GenericOpc;
116}
117
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +0000118bool AArch64InstructionSelector::select(MachineInstr &I) const {
119 assert(I.getParent() && "Instruction should be in a basic block!");
120 assert(I.getParent()->getParent() && "Instruction should be in a function!");
121
122 MachineBasicBlock &MBB = *I.getParent();
123 MachineFunction &MF = *MBB.getParent();
124 MachineRegisterInfo &MRI = MF.getRegInfo();
125
126 // FIXME: Is there *really* nothing to be done here? This assumes that
127 // no upstream pass introduces things like generic vreg on copies or
128 // target-specific instructions.
129 // We should document (and verify) that assumption.
130 if (!isPreISelGenericOpcode(I.getOpcode()))
131 return true;
132
133 if (I.getNumOperands() != I.getNumExplicitOperands()) {
134 DEBUG(dbgs() << "Generic instruction has unexpected implicit operands\n");
135 return false;
136 }
137
138 LLT Ty = I.getType();
139 assert(Ty.isValid() && "Generic instruction doesn't have a type");
140
Ahmed Bougacha85505092016-07-28 17:15:15 +0000141 switch (I.getOpcode()) {
142 case TargetOpcode::G_BR: {
143 I.setDesc(TII.get(AArch64::B));
144 I.removeTypes();
145 return true;
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +0000146 }
147
Ahmed Bougacha0306b5e2016-08-16 14:02:42 +0000148 case TargetOpcode::G_FRAME_INDEX: {
149 // allocas and G_FRAME_INDEX are only supported in addrspace(0).
150 if (I.getType() != LLT::pointer(0)) {
151 DEBUG(dbgs() << "G_FRAME_INDEX pointer has type: " << I.getType()
152 << ", expected: " << LLT::pointer(0) << '\n');
153 return false;
154 }
155
156 I.setDesc(TII.get(AArch64::ADDXri));
157 I.removeTypes();
158
159 // MOs for a #0 shifted immediate.
160 I.addOperand(MachineOperand::CreateImm(0));
161 I.addOperand(MachineOperand::CreateImm(0));
162
163 return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
164 }
165
Ahmed Bougacha7adfac52016-07-29 16:56:16 +0000166 case TargetOpcode::G_LOAD:
167 case TargetOpcode::G_STORE: {
168 LLT MemTy = I.getType(0);
169 LLT PtrTy = I.getType(1);
170
171 if (PtrTy != LLT::pointer(0)) {
172 DEBUG(dbgs() << "Load/Store pointer has type: " << PtrTy
173 << ", expected: " << LLT::pointer(0) << '\n');
174 return false;
175 }
176
177#ifndef NDEBUG
178 // Sanity-check the pointer register.
179 const unsigned PtrReg = I.getOperand(1).getReg();
180 const RegisterBank &PtrRB = *RBI.getRegBank(PtrReg, MRI, TRI);
181 assert(PtrRB.getID() == AArch64::GPRRegBankID &&
182 "Load/Store pointer operand isn't a GPR");
183 assert(MRI.getSize(PtrReg) == 64 &&
184 "Load/Store pointer operand isn't 64-bit");
185#endif
186
187 const unsigned ValReg = I.getOperand(0).getReg();
188 const RegisterBank &RB = *RBI.getRegBank(ValReg, MRI, TRI);
189
190 const unsigned NewOpc =
191 selectLoadStoreUIOp(I.getOpcode(), RB.getID(), MemTy.getSizeInBits());
192 if (NewOpc == I.getOpcode())
193 return false;
194
195 I.setDesc(TII.get(NewOpc));
196 I.removeTypes();
197
198 I.addOperand(MachineOperand::CreateImm(0));
199 return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
200 }
201
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +0000202 case TargetOpcode::G_OR:
Ahmed Bougacha6db3cfe2016-07-29 16:56:25 +0000203 case TargetOpcode::G_XOR:
Ahmed Bougacha61a79282016-07-28 16:58:31 +0000204 case TargetOpcode::G_AND:
Ahmed Bougacha2ac5bf92016-08-16 14:02:47 +0000205 case TargetOpcode::G_SHL:
206 case TargetOpcode::G_LSHR:
207 case TargetOpcode::G_ASHR:
Ahmed Bougachad7748d62016-07-28 16:58:35 +0000208 case TargetOpcode::G_ADD:
209 case TargetOpcode::G_SUB: {
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +0000210 DEBUG(dbgs() << "AArch64: Selecting: binop\n");
211
Ahmed Bougacha85505092016-07-28 17:15:15 +0000212 if (!Ty.isSized()) {
213 DEBUG(dbgs() << "Generic binop should be sized\n");
214 return false;
215 }
216
217 // The size (in bits) of the operation, or 0 for the label type.
218 const unsigned OpSize = Ty.getSizeInBits();
219
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +0000220 // Reject the various things we don't support yet.
221 {
222 const RegisterBank *PrevOpBank = nullptr;
223 for (auto &MO : I.operands()) {
224 // FIXME: Support non-register operands.
225 if (!MO.isReg()) {
226 DEBUG(dbgs() << "Generic inst non-reg operands are unsupported\n");
227 return false;
228 }
229
230 // FIXME: Can generic operations have physical registers operands? If
231 // so, this will need to be taught about that, and we'll need to get the
232 // bank out of the minimal class for the register.
233 // Either way, this needs to be documented (and possibly verified).
234 if (!TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
235 DEBUG(dbgs() << "Generic inst has physical register operand\n");
236 return false;
237 }
238
239 const RegisterBank *OpBank = RBI.getRegBank(MO.getReg(), MRI, TRI);
240 if (!OpBank) {
241 DEBUG(dbgs() << "Generic register has no bank or class\n");
242 return false;
243 }
244
245 if (PrevOpBank && OpBank != PrevOpBank) {
246 DEBUG(dbgs() << "Generic inst operands have different banks\n");
247 return false;
248 }
249 PrevOpBank = OpBank;
250 }
251 }
252
253 const unsigned DefReg = I.getOperand(0).getReg();
254 const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
255
256 const unsigned NewOpc = selectBinaryOp(I.getOpcode(), RB.getID(), OpSize);
257 if (NewOpc == I.getOpcode())
258 return false;
259
260 I.setDesc(TII.get(NewOpc));
261 // FIXME: Should the type be always reset in setDesc?
Ahmed Bougacha46c05fc2016-07-28 16:58:27 +0000262 I.removeTypes();
Ahmed Bougacha6756a2c2016-07-27 14:31:55 +0000263
264 // Now that we selected an opcode, we need to constrain the register
265 // operands to use appropriate classes.
266 return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
267 }
268 }
269
270 return false;
271}