1*06f32e7eSjoerg //===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===//
2*06f32e7eSjoerg //
3*06f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*06f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06f32e7eSjoerg //
7*06f32e7eSjoerg //===----------------------------------------------------------------------===//
8*06f32e7eSjoerg //
9*06f32e7eSjoerg // This file defines an instruction selector for the Lanai target.
10*06f32e7eSjoerg //
11*06f32e7eSjoerg //===----------------------------------------------------------------------===//
12*06f32e7eSjoerg
13*06f32e7eSjoerg #include "LanaiAluCode.h"
14*06f32e7eSjoerg #include "LanaiMachineFunctionInfo.h"
15*06f32e7eSjoerg #include "LanaiRegisterInfo.h"
16*06f32e7eSjoerg #include "LanaiSubtarget.h"
17*06f32e7eSjoerg #include "LanaiTargetMachine.h"
18*06f32e7eSjoerg #include "llvm/CodeGen/MachineConstantPool.h"
19*06f32e7eSjoerg #include "llvm/CodeGen/MachineFrameInfo.h"
20*06f32e7eSjoerg #include "llvm/CodeGen/MachineFunction.h"
21*06f32e7eSjoerg #include "llvm/CodeGen/MachineInstrBuilder.h"
22*06f32e7eSjoerg #include "llvm/CodeGen/MachineRegisterInfo.h"
23*06f32e7eSjoerg #include "llvm/CodeGen/SelectionDAGISel.h"
24*06f32e7eSjoerg #include "llvm/IR/CFG.h"
25*06f32e7eSjoerg #include "llvm/IR/GlobalValue.h"
26*06f32e7eSjoerg #include "llvm/IR/Instructions.h"
27*06f32e7eSjoerg #include "llvm/IR/Intrinsics.h"
28*06f32e7eSjoerg #include "llvm/IR/Type.h"
29*06f32e7eSjoerg #include "llvm/Support/Debug.h"
30*06f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
31*06f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
32*06f32e7eSjoerg #include "llvm/Target/TargetMachine.h"
33*06f32e7eSjoerg
34*06f32e7eSjoerg using namespace llvm;
35*06f32e7eSjoerg
36*06f32e7eSjoerg #define DEBUG_TYPE "lanai-isel"
37*06f32e7eSjoerg
38*06f32e7eSjoerg //===----------------------------------------------------------------------===//
39*06f32e7eSjoerg // Instruction Selector Implementation
40*06f32e7eSjoerg //===----------------------------------------------------------------------===//
41*06f32e7eSjoerg
42*06f32e7eSjoerg //===----------------------------------------------------------------------===//
43*06f32e7eSjoerg // LanaiDAGToDAGISel - Lanai specific code to select Lanai machine
44*06f32e7eSjoerg // instructions for SelectionDAG operations.
45*06f32e7eSjoerg //===----------------------------------------------------------------------===//
46*06f32e7eSjoerg namespace {
47*06f32e7eSjoerg
48*06f32e7eSjoerg class LanaiDAGToDAGISel : public SelectionDAGISel {
49*06f32e7eSjoerg public:
LanaiDAGToDAGISel(LanaiTargetMachine & TargetMachine)50*06f32e7eSjoerg explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
51*06f32e7eSjoerg : SelectionDAGISel(TargetMachine) {}
52*06f32e7eSjoerg
runOnMachineFunction(MachineFunction & MF)53*06f32e7eSjoerg bool runOnMachineFunction(MachineFunction &MF) override {
54*06f32e7eSjoerg return SelectionDAGISel::runOnMachineFunction(MF);
55*06f32e7eSjoerg }
56*06f32e7eSjoerg
57*06f32e7eSjoerg // Pass Name
getPassName() const58*06f32e7eSjoerg StringRef getPassName() const override {
59*06f32e7eSjoerg return "Lanai DAG->DAG Pattern Instruction Selection";
60*06f32e7eSjoerg }
61*06f32e7eSjoerg
62*06f32e7eSjoerg bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
63*06f32e7eSjoerg std::vector<SDValue> &OutOps) override;
64*06f32e7eSjoerg
65*06f32e7eSjoerg private:
66*06f32e7eSjoerg // Include the pieces autogenerated from the target description.
67*06f32e7eSjoerg #include "LanaiGenDAGISel.inc"
68*06f32e7eSjoerg
69*06f32e7eSjoerg // Instruction Selection not handled by the auto-generated tablgen
70*06f32e7eSjoerg void Select(SDNode *N) override;
71*06f32e7eSjoerg
72*06f32e7eSjoerg // Support functions for the opcodes of Instruction Selection
73*06f32e7eSjoerg // not handled by the auto-generated tablgen
74*06f32e7eSjoerg void selectFrameIndex(SDNode *N);
75*06f32e7eSjoerg
76*06f32e7eSjoerg // Complex Pattern for address selection.
77*06f32e7eSjoerg bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset,
78*06f32e7eSjoerg SDValue &AluOp);
79*06f32e7eSjoerg bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp);
80*06f32e7eSjoerg bool selectAddrSls(SDValue Addr, SDValue &Offset);
81*06f32e7eSjoerg bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
82*06f32e7eSjoerg SDValue &AluOp);
83*06f32e7eSjoerg
84*06f32e7eSjoerg // getI32Imm - Return a target constant with the specified value, of type i32.
getI32Imm(unsigned Imm,const SDLoc & DL)85*06f32e7eSjoerg inline SDValue getI32Imm(unsigned Imm, const SDLoc &DL) {
86*06f32e7eSjoerg return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
87*06f32e7eSjoerg }
88*06f32e7eSjoerg
89*06f32e7eSjoerg private:
90*06f32e7eSjoerg bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
91*06f32e7eSjoerg SDValue &AluOp, bool RiMode);
92*06f32e7eSjoerg };
93*06f32e7eSjoerg
canBeRepresentedAsSls(const ConstantSDNode & CN)94*06f32e7eSjoerg bool canBeRepresentedAsSls(const ConstantSDNode &CN) {
95*06f32e7eSjoerg // Fits in 21-bit signed immediate and two low-order bits are zero.
96*06f32e7eSjoerg return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0);
97*06f32e7eSjoerg }
98*06f32e7eSjoerg
99*06f32e7eSjoerg } // namespace
100*06f32e7eSjoerg
101*06f32e7eSjoerg // Helper functions for ComplexPattern used on LanaiInstrInfo
102*06f32e7eSjoerg // Used on Lanai Load/Store instructions.
selectAddrSls(SDValue Addr,SDValue & Offset)103*06f32e7eSjoerg bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
104*06f32e7eSjoerg if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
105*06f32e7eSjoerg SDLoc DL(Addr);
106*06f32e7eSjoerg // Loading from a constant address.
107*06f32e7eSjoerg if (canBeRepresentedAsSls(*CN)) {
108*06f32e7eSjoerg int32_t Imm = CN->getSExtValue();
109*06f32e7eSjoerg Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
110*06f32e7eSjoerg return true;
111*06f32e7eSjoerg }
112*06f32e7eSjoerg }
113*06f32e7eSjoerg if (Addr.getOpcode() == ISD::OR &&
114*06f32e7eSjoerg Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
115*06f32e7eSjoerg Offset = Addr.getOperand(1).getOperand(0);
116*06f32e7eSjoerg return true;
117*06f32e7eSjoerg }
118*06f32e7eSjoerg return false;
119*06f32e7eSjoerg }
120*06f32e7eSjoerg
selectAddrRiSpls(SDValue Addr,SDValue & Base,SDValue & Offset,SDValue & AluOp,bool RiMode)121*06f32e7eSjoerg bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base,
122*06f32e7eSjoerg SDValue &Offset, SDValue &AluOp,
123*06f32e7eSjoerg bool RiMode) {
124*06f32e7eSjoerg SDLoc DL(Addr);
125*06f32e7eSjoerg
126*06f32e7eSjoerg if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
127*06f32e7eSjoerg if (RiMode) {
128*06f32e7eSjoerg // Fits in 16-bit signed immediate.
129*06f32e7eSjoerg if (isInt<16>(CN->getSExtValue())) {
130*06f32e7eSjoerg int16_t Imm = CN->getSExtValue();
131*06f32e7eSjoerg Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
132*06f32e7eSjoerg Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
133*06f32e7eSjoerg AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
134*06f32e7eSjoerg return true;
135*06f32e7eSjoerg }
136*06f32e7eSjoerg // Allow SLS to match if the constant doesn't fit in 16 bits but can be
137*06f32e7eSjoerg // represented as an SLS.
138*06f32e7eSjoerg if (canBeRepresentedAsSls(*CN))
139*06f32e7eSjoerg return false;
140*06f32e7eSjoerg } else {
141*06f32e7eSjoerg // Fits in 10-bit signed immediate.
142*06f32e7eSjoerg if (isInt<10>(CN->getSExtValue())) {
143*06f32e7eSjoerg int16_t Imm = CN->getSExtValue();
144*06f32e7eSjoerg Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
145*06f32e7eSjoerg Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
146*06f32e7eSjoerg AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
147*06f32e7eSjoerg return true;
148*06f32e7eSjoerg }
149*06f32e7eSjoerg }
150*06f32e7eSjoerg }
151*06f32e7eSjoerg
152*06f32e7eSjoerg // if Address is FI, get the TargetFrameIndex.
153*06f32e7eSjoerg if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
154*06f32e7eSjoerg Base = CurDAG->getTargetFrameIndex(
155*06f32e7eSjoerg FIN->getIndex(),
156*06f32e7eSjoerg getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
157*06f32e7eSjoerg Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
158*06f32e7eSjoerg AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
159*06f32e7eSjoerg return true;
160*06f32e7eSjoerg }
161*06f32e7eSjoerg
162*06f32e7eSjoerg // Skip direct calls
163*06f32e7eSjoerg if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
164*06f32e7eSjoerg Addr.getOpcode() == ISD::TargetGlobalAddress))
165*06f32e7eSjoerg return false;
166*06f32e7eSjoerg
167*06f32e7eSjoerg // Address of the form imm + reg
168*06f32e7eSjoerg ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
169*06f32e7eSjoerg if (AluOperator == ISD::ADD) {
170*06f32e7eSjoerg AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
171*06f32e7eSjoerg // Addresses of the form FI+const
172*06f32e7eSjoerg if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
173*06f32e7eSjoerg if ((RiMode && isInt<16>(CN->getSExtValue())) ||
174*06f32e7eSjoerg (!RiMode && isInt<10>(CN->getSExtValue()))) {
175*06f32e7eSjoerg // If the first operand is a FI, get the TargetFI Node
176*06f32e7eSjoerg if (FrameIndexSDNode *FIN =
177*06f32e7eSjoerg dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
178*06f32e7eSjoerg Base = CurDAG->getTargetFrameIndex(
179*06f32e7eSjoerg FIN->getIndex(),
180*06f32e7eSjoerg getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
181*06f32e7eSjoerg } else {
182*06f32e7eSjoerg Base = Addr.getOperand(0);
183*06f32e7eSjoerg }
184*06f32e7eSjoerg
185*06f32e7eSjoerg Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i32);
186*06f32e7eSjoerg return true;
187*06f32e7eSjoerg }
188*06f32e7eSjoerg }
189*06f32e7eSjoerg
190*06f32e7eSjoerg // Let SLS match SMALL instead of RI.
191*06f32e7eSjoerg if (AluOperator == ISD::OR && RiMode &&
192*06f32e7eSjoerg Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
193*06f32e7eSjoerg return false;
194*06f32e7eSjoerg
195*06f32e7eSjoerg Base = Addr;
196*06f32e7eSjoerg Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
197*06f32e7eSjoerg AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
198*06f32e7eSjoerg return true;
199*06f32e7eSjoerg }
200*06f32e7eSjoerg
selectAddrRi(SDValue Addr,SDValue & Base,SDValue & Offset,SDValue & AluOp)201*06f32e7eSjoerg bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
202*06f32e7eSjoerg SDValue &Offset, SDValue &AluOp) {
203*06f32e7eSjoerg return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true);
204*06f32e7eSjoerg }
205*06f32e7eSjoerg
selectAddrSpls(SDValue Addr,SDValue & Base,SDValue & Offset,SDValue & AluOp)206*06f32e7eSjoerg bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
207*06f32e7eSjoerg SDValue &Offset, SDValue &AluOp) {
208*06f32e7eSjoerg return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
209*06f32e7eSjoerg }
210*06f32e7eSjoerg
selectAddrRr(SDValue Addr,SDValue & R1,SDValue & R2,SDValue & AluOp)211*06f32e7eSjoerg bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2,
212*06f32e7eSjoerg SDValue &AluOp) {
213*06f32e7eSjoerg // if Address is FI, get the TargetFrameIndex.
214*06f32e7eSjoerg if (Addr.getOpcode() == ISD::FrameIndex)
215*06f32e7eSjoerg return false;
216*06f32e7eSjoerg
217*06f32e7eSjoerg // Skip direct calls
218*06f32e7eSjoerg if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
219*06f32e7eSjoerg Addr.getOpcode() == ISD::TargetGlobalAddress))
220*06f32e7eSjoerg return false;
221*06f32e7eSjoerg
222*06f32e7eSjoerg // Address of the form OP + OP
223*06f32e7eSjoerg ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
224*06f32e7eSjoerg LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(AluOperator);
225*06f32e7eSjoerg if (AluCode != LPAC::UNKNOWN) {
226*06f32e7eSjoerg // Skip addresses of the form FI OP const
227*06f32e7eSjoerg if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
228*06f32e7eSjoerg if (isInt<16>(CN->getSExtValue()))
229*06f32e7eSjoerg return false;
230*06f32e7eSjoerg
231*06f32e7eSjoerg // Skip addresses with hi/lo operands
232*06f32e7eSjoerg if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
233*06f32e7eSjoerg Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
234*06f32e7eSjoerg Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
235*06f32e7eSjoerg Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
236*06f32e7eSjoerg Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
237*06f32e7eSjoerg Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
238*06f32e7eSjoerg return false;
239*06f32e7eSjoerg
240*06f32e7eSjoerg // Addresses of the form register OP register
241*06f32e7eSjoerg R1 = Addr.getOperand(0);
242*06f32e7eSjoerg R2 = Addr.getOperand(1);
243*06f32e7eSjoerg AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32);
244*06f32e7eSjoerg return true;
245*06f32e7eSjoerg }
246*06f32e7eSjoerg
247*06f32e7eSjoerg // Skip addresses with zero offset
248*06f32e7eSjoerg return false;
249*06f32e7eSjoerg }
250*06f32e7eSjoerg
SelectInlineAsmMemoryOperand(const SDValue & Op,unsigned ConstraintCode,std::vector<SDValue> & OutOps)251*06f32e7eSjoerg bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand(
252*06f32e7eSjoerg const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) {
253*06f32e7eSjoerg SDValue Op0, Op1, AluOp;
254*06f32e7eSjoerg switch (ConstraintCode) {
255*06f32e7eSjoerg default:
256*06f32e7eSjoerg return true;
257*06f32e7eSjoerg case InlineAsm::Constraint_m: // memory
258*06f32e7eSjoerg if (!selectAddrRr(Op, Op0, Op1, AluOp) &&
259*06f32e7eSjoerg !selectAddrRi(Op, Op0, Op1, AluOp))
260*06f32e7eSjoerg return true;
261*06f32e7eSjoerg break;
262*06f32e7eSjoerg }
263*06f32e7eSjoerg
264*06f32e7eSjoerg OutOps.push_back(Op0);
265*06f32e7eSjoerg OutOps.push_back(Op1);
266*06f32e7eSjoerg OutOps.push_back(AluOp);
267*06f32e7eSjoerg return false;
268*06f32e7eSjoerg }
269*06f32e7eSjoerg
270*06f32e7eSjoerg // Select instructions not customized! Used for
271*06f32e7eSjoerg // expanded, promoted and normal instructions
Select(SDNode * Node)272*06f32e7eSjoerg void LanaiDAGToDAGISel::Select(SDNode *Node) {
273*06f32e7eSjoerg unsigned Opcode = Node->getOpcode();
274*06f32e7eSjoerg
275*06f32e7eSjoerg // If we have a custom node, we already have selected!
276*06f32e7eSjoerg if (Node->isMachineOpcode()) {
277*06f32e7eSjoerg LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
278*06f32e7eSjoerg return;
279*06f32e7eSjoerg }
280*06f32e7eSjoerg
281*06f32e7eSjoerg // Instruction Selection not handled by the auto-generated tablegen selection
282*06f32e7eSjoerg // should be handled here.
283*06f32e7eSjoerg EVT VT = Node->getValueType(0);
284*06f32e7eSjoerg switch (Opcode) {
285*06f32e7eSjoerg case ISD::Constant:
286*06f32e7eSjoerg if (VT == MVT::i32) {
287*06f32e7eSjoerg ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node);
288*06f32e7eSjoerg // Materialize zero constants as copies from R0. This allows the coalescer
289*06f32e7eSjoerg // to propagate these into other instructions.
290*06f32e7eSjoerg if (ConstNode->isNullValue()) {
291*06f32e7eSjoerg SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
292*06f32e7eSjoerg SDLoc(Node), Lanai::R0, MVT::i32);
293*06f32e7eSjoerg return ReplaceNode(Node, New.getNode());
294*06f32e7eSjoerg }
295*06f32e7eSjoerg // Materialize all ones constants as copies from R1. This allows the
296*06f32e7eSjoerg // coalescer to propagate these into other instructions.
297*06f32e7eSjoerg if (ConstNode->isAllOnesValue()) {
298*06f32e7eSjoerg SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
299*06f32e7eSjoerg SDLoc(Node), Lanai::R1, MVT::i32);
300*06f32e7eSjoerg return ReplaceNode(Node, New.getNode());
301*06f32e7eSjoerg }
302*06f32e7eSjoerg }
303*06f32e7eSjoerg break;
304*06f32e7eSjoerg case ISD::FrameIndex:
305*06f32e7eSjoerg selectFrameIndex(Node);
306*06f32e7eSjoerg return;
307*06f32e7eSjoerg default:
308*06f32e7eSjoerg break;
309*06f32e7eSjoerg }
310*06f32e7eSjoerg
311*06f32e7eSjoerg // Select the default instruction
312*06f32e7eSjoerg SelectCode(Node);
313*06f32e7eSjoerg }
314*06f32e7eSjoerg
selectFrameIndex(SDNode * Node)315*06f32e7eSjoerg void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
316*06f32e7eSjoerg SDLoc DL(Node);
317*06f32e7eSjoerg SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
318*06f32e7eSjoerg int FI = cast<FrameIndexSDNode>(Node)->getIndex();
319*06f32e7eSjoerg EVT VT = Node->getValueType(0);
320*06f32e7eSjoerg SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
321*06f32e7eSjoerg unsigned Opc = Lanai::ADD_I_LO;
322*06f32e7eSjoerg if (Node->hasOneUse()) {
323*06f32e7eSjoerg CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
324*06f32e7eSjoerg return;
325*06f32e7eSjoerg }
326*06f32e7eSjoerg ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm));
327*06f32e7eSjoerg }
328*06f32e7eSjoerg
329*06f32e7eSjoerg // createLanaiISelDag - This pass converts a legalized DAG into a
330*06f32e7eSjoerg // Lanai-specific DAG, ready for instruction scheduling.
createLanaiISelDag(LanaiTargetMachine & TM)331*06f32e7eSjoerg FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) {
332*06f32e7eSjoerg return new LanaiDAGToDAGISel(TM);
333*06f32e7eSjoerg }
334