LLVM: lib/Target/AVR/AVRISelDAGToDAG.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

16

21

22#define DEBUG_TYPE "avr-isel"

23#define PASS_NAME "AVR DAG->DAG Instruction Selection"

24

25using namespace llvm;

26

27namespace {

28

29

31public:

32 AVRDAGToDAGISel() = delete;

33

36

38

40

41 bool selectIndexedLoad(SDNode *N);

42 unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, int Bank);

43

44 bool SelectInlineAsmMemoryOperand(const SDValue &Op,

46 std::vector &OutOps) override;

47

48

49#include "AVRGenDAGISel.inc"

50

51private:

53 bool trySelect(SDNode *N);

54

55 template bool select(SDNode *N);

56 bool selectMultiplication(SDNode *N);

57

59};

60

62public:

63 static char ID;

66 ID, std::make_unique(TM, OptLevel)) {}

67};

68

69}

70

71char AVRDAGToDAGISelLegacy::ID = 0;

72

74

78}

79

82 SDLoc dl(Op);

83 auto DL = CurDAG->getDataLayout();

84 MVT PtrVT = getTargetLowering()->getPointerTy(DL);

85

86

88 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);

89 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);

90

91 return true;

92 }

93

94

96 !CurDAG->isBaseWithConstantOffset(N)) {

97 return false;

98 }

99

101 int RHSC = (int)RHS->getZExtValue();

102

103

105 RHSC = -RHSC;

106 }

107

108

109

110

111

114

115 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);

116 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);

117

118 return true;

119 }

120

121

122

124

125

126

127

128 bool OkI8 = VT == MVT::i8 && RHSC <= 63;

129 bool OkI16 = VT == MVT::i16 && RHSC <= 62;

130

131 if (OkI8 || OkI16) {

132 Base = N.getOperand(0);

133 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);

134

135 return true;

136 }

137 }

138

139 return false;

140}

141

142bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {

145 MVT VT = LD->getMemoryVT().getSimpleVT();

146 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());

147

148

151

152 return false;

153 }

154

155 unsigned Opcode = 0;

158

160 case MVT::i8: {

161 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {

162 return false;

163 }

164

165 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;

166 break;

167 }

168 case MVT::i16: {

169 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {

170 return false;

171 }

172

173 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;

174 break;

175 }

176 default:

177 return false;

178 }

179

180 SDNode *ResNode =

181 CurDAG->getMachineNode(Opcode, SDLoc(N), VT, PtrVT, MVT::Other,

182 LD->getBasePtr(), LD->getChain());

183 ReplaceUses(N, ResNode);

184 CurDAG->RemoveDeadNode(N);

185

186 return true;

187}

188

189unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT,

190 int Bank) {

191

194 return 0;

195

196

197 assert((Bank == 0 || Subtarget->hasELPM()) &&

198 "cannot load from extended program memory on this mcu");

199

200 unsigned Opcode = 0;

202

203 if (VT.SimpleTy == MVT::i8 && Offs == 1 && Bank == 0)

204 Opcode = AVR::LPMRdZPi;

205

206

207

208

209

210

211 return Opcode;

212}

213

214bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(

216 std::vector &OutOps) {

217 assert((ConstraintCode == InlineAsm::ConstraintCode::m ||

218 ConstraintCode == InlineAsm::ConstraintCode::Q) &&

219 "Unexpected asm memory constraint");

220

221 MachineRegisterInfo &RI = MF->getRegInfo();

222 const AVRSubtarget &STI = MF->getSubtarget();

224 SDLoc dl(Op);

225 auto DL = CurDAG->getDataLayout();

226

228

229

230 if (RegNode &&

231 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {

232 OutOps.push_back(Op);

233 return false;

234 }

235

238

239 if (SelectAddr(Op.getNode(), Op, Base, Disp)) {

240 OutOps.push_back(Base);

241 OutOps.push_back(Disp);

242

243 return false;

244 }

245

246 return true;

247 }

248

249

250

252 SDValue CopyFromRegOp = Op->getOperand(0);

253 SDValue ImmOp = Op->getOperand(1);

255

256 unsigned Reg;

257 bool CanHandleRegImmOpt = ImmNode && ImmNode->getAPIntValue().ult(64);

258

260 RegisterSDNode *RegNode =

263 CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) ||

264 AVR::PTRDISPREGSRegClass.contains(Reg));

265 } else {

266 CanHandleRegImmOpt = false;

267 }

268

269

270

271 if (CanHandleRegImmOpt) {

273

274 if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {

275 SDLoc dl(CopyFromRegOp);

276

278

280 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);

281

282 SDValue NewCopyFromRegOp =

283 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));

284

285 Base = NewCopyFromRegOp;

286 } else {

287 Base = CopyFromRegOp;

288 }

289

291 Disp = CurDAG->getTargetConstant(ImmNode->getZExtValue(), dl, MVT::i8);

292 } else {

293 Disp = ImmOp;

294 }

295

296 OutOps.push_back(Base);

297 OutOps.push_back(Disp);

298

299 return false;

300 }

301 }

302

303

304

305

307

310 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));

311

312 OutOps.push_back(CopyFromReg);

313

314 return false;

315}

316

317template <> bool AVRDAGToDAGISel::selectISD::FrameIndex(SDNode *N) {

318 auto DL = CurDAG->getDataLayout();

319

320

321

324 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));

325

326 CurDAG->SelectNodeTo(N, AVR::FRMIDX, getTargetLowering()->getPointerTy(DL),

327 TFI, CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));

328 return true;

329}

330

331template <> bool AVRDAGToDAGISel::selectISD::STORE(SDNode *N) {

332

333

335 SDValue BasePtr = ST->getBasePtr();

336

337

339 BasePtr.isUndef()) {

340 return false;

341 }

342

344

345 if (!RN || (RN->getReg() != AVR::SP)) {

346 return false;

347 }

348

349 int CST = (int)BasePtr.getConstantOperandVal(1);

350 SDValue Chain = ST->getChain();

351 EVT VT = ST->getValue().getValueType();

353 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);

354 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};

355 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;

356

357 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);

358

359

360 CurDAG->setNodeMemRefs(cast(ResNode), {ST->getMemOperand()});

361

363 CurDAG->RemoveDeadNode(N);

364

365 return true;

366}

367

368template <> bool AVRDAGToDAGISel::selectISD::LOAD(SDNode *N) {

371

372 return selectIndexedLoad(N);

373 }

374

375 if (!Subtarget->hasLPM())

377

379 if (ProgMemBank < 0 || ProgMemBank > 5)

381 if (ProgMemBank > 0 && !Subtarget->hasELPM())

383

384

385

386 MVT VT = LD->getMemoryVT().getSimpleVT();

387 SDValue Chain = LD->getChain();

388 SDValue Ptr = LD->getBasePtr();

391

392 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());

393 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,

395

396

397 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {

398

399 if (ProgMemBank == 0) {

400 ResNode =

401 CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr);

402 } else {

403

404

405 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);

406 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);

407 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other,

409 }

410 } else {

411

413 case MVT::i8:

414 if (ProgMemBank == 0) {

415 unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;

416 ResNode = CurDAG->getMachineNode(Opc, DL, MVT::i8, MVT::Other, Ptr);

417 } else {

418

419

420 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);

421 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);

422 ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other,

424 }

425 break;

426 case MVT::i16:

427 if (ProgMemBank == 0) {

428 ResNode =

429 CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, Ptr);

430 } else {

431

432

433 SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);

434 auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);

435 ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16,

436 MVT::Other, Ptr, SDValue(NP, 0));

437 }

438 break;

439 default:

441 }

442 }

443

444

445 CurDAG->setNodeMemRefs(cast(ResNode), {LD->getMemOperand()});

446

449 CurDAG->RemoveDeadNode(N);

450

451 return true;

452}

453

454template <> bool AVRDAGToDAGISel::selectAVRISD::CALL(SDNode *N) {

456 SDValue Chain = N->getOperand(0);

457 SDValue Callee = N->getOperand(1);

458 unsigned LastOpNum = N->getNumOperands() - 1;

459

460

461 unsigned Op = Callee.getOpcode();

463 return false;

464 }

465

466

467 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {

468 --LastOpNum;

469 }

470

472 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InGlue);

474 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));

475

476

477 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {

478 Ops.push_back(N->getOperand(i));

479 }

480

481 Ops.push_back(Chain);

483

484 SDNode *ResNode = CurDAG->getMachineNode(

485 Subtarget->hasEIJMPCALL() ? AVR::EICALL : AVR::ICALL, DL, MVT::Other,

486 MVT::Glue, Ops);

487

490 CurDAG->RemoveDeadNode(N);

491

492 return true;

493}

494

495template <> bool AVRDAGToDAGISel::selectISD::BRIND(SDNode *N) {

496 SDValue Chain = N->getOperand(0);

497 SDValue JmpAddr = N->getOperand(1);

498

500

501 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);

502 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);

503

505 CurDAG->RemoveDeadNode(N);

506

507 return true;

508}

509

510bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {

511 SDLoc DL(N);

512 MVT Type = N->getSimpleValueType(0);

513

514 assert(Type == MVT::i8 && "unexpected value type");

515

517 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;

518

519 SDValue Lhs = N->getOperand(0);

520 SDValue Rhs = N->getOperand(1);

521 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);

522 SDValue InChain = CurDAG->getEntryNode();

524

525

526 if (N->hasAnyUseOfValue(0)) {

528 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);

529

530 ReplaceUses(SDValue(N, 0), CopyFromLo);

531

532 InChain = CopyFromLo.getValue(1);

533 InGlue = CopyFromLo.getValue(2);

534 }

535

536

537 if (N->hasAnyUseOfValue(1)) {

539 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);

540

541 ReplaceUses(SDValue(N, 1), CopyFromHi);

542

543 InChain = CopyFromHi.getValue(1);

544 InGlue = CopyFromHi.getValue(2);

545 }

546

547 CurDAG->RemoveDeadNode(N);

548

549

550

551

552 return true;

553}

554

555void AVRDAGToDAGISel::Select(SDNode *N) {

556

557 if (N->isMachineOpcode()) {

559 N->setNodeId(-1);

560 return;

561 }

562

563

564 if (trySelect(N))

565 return;

566

567

568 SelectCode(N);

569}

570

571bool AVRDAGToDAGISel::trySelect(SDNode *N) {

572 unsigned Opcode = N->getOpcode();

573

574 switch (Opcode) {

575

578 case ISD::BRIND:

582 return selectMultiplication(N);

583

584

585 case ISD::STORE:

587 case ISD::LOAD:

589 case AVRISD::CALL:

591 default:

592 return false;

593 }

594}

595

598 return new AVRDAGToDAGISelLegacy(TM, OptLevel);

599}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

AMDGPU Register Bank Select

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

bool AVRDAGToDAGISel::select< ISD::LOAD >(SDNode *N)

Definition AVRISelDAGToDAG.cpp:368

bool AVRDAGToDAGISel::select< ISD::FrameIndex >(SDNode *N)

Definition AVRISelDAGToDAG.cpp:317

bool AVRDAGToDAGISel::select< ISD::BRIND >(SDNode *N)

Definition AVRISelDAGToDAG.cpp:495

bool AVRDAGToDAGISel::select< AVRISD::CALL >(SDNode *N)

Definition AVRISelDAGToDAG.cpp:454

bool AVRDAGToDAGISel::select< ISD::STORE >(SDNode *N)

Definition AVRISelDAGToDAG.cpp:331

static bool isSigned(unsigned int Opcode)

const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]

Promote Memory to Register

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

bool ult(const APInt &RHS) const

Unsigned less than comparison.

A specific AVR target MCU.

const AVRTargetLowering * getTargetLowering() const override

A generic AVR implementation.

uint64_t getZExtValue() const

const APInt & getAPIntValue() const

FunctionPass class - This class is used to implement most global optimizations.

This class is used to represent ISD::LOAD nodes.

const TargetRegisterClass * getRegClass(Register Reg) const

Return the register class of the specified virtual register.

LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")

createVirtualRegister - Create and return a new virtual register in the function with the specified r...

Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...

Represents one node in the SelectionDAG.

unsigned getOpcode() const

Return the SelectionDAG opcode value for this node.

const SDValue & getOperand(unsigned Num) const

EVT getValueType(unsigned ResNo) const

Return the type of a specified result.

Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.

SDValue getValue(unsigned R) const

SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...

virtual bool runOnMachineFunction(MachineFunction &mf)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

This class is used to represent ISD::STORE nodes.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

bool isProgramMemoryAccess(MemSDNode const *N)

int getProgramMemoryBank(MemSDNode const *N)

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ SMUL_LOHI

SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...

@ ADD

Simple integer binary arithmetic operators.

@ CopyFromReg

CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...

@ TargetGlobalAddress

TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...

@ CopyToReg

CopyToReg - This node has three operands: a chain, a register number to set to this value,...

MemIndexedMode

MemIndexedMode enum - This enum defines the load / store indexed addressing modes.

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

FunctionPass * createAVRISelDag(AVRTargetMachine &TM, CodeGenOptLevel OptLevel)

Definition AVRISelDAGToDAG.cpp:596

LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)

CodeGenOptLevel

Code generation optimization level.

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

LLVM_ABI raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

DWARFExpression::Operation Op

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.