LLVM: lib/CodeGen/AsmPrinter/DwarfExpression.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

23#include

24

25using namespace llvm;

26

27#define DEBUG_TYPE "dwarfdebug"

28

32 else if (Value == std::numeric_limits<uint64_t>::max()) {

33

34

35 emitOp(dwarf::DW_OP_lit0);

36 emitOp(dwarf::DW_OP_not);

37 } else {

38 emitOp(dwarf::DW_OP_constu);

40 }

41}

42

44 assert(DwarfReg >= 0 && "invalid negative dwarf register number");

46 "location description already locked down");

48 if (DwarfReg < 32) {

49 emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);

50 } else {

51 emitOp(dwarf::DW_OP_regx, Comment);

53 }

54}

55

57 assert(DwarfReg >= 0 && "invalid negative dwarf register number");

59 if (DwarfReg < 32) {

60 emitOp(dwarf::DW_OP_breg0 + DwarfReg);

61 } else {

62 emitOp(dwarf::DW_OP_bregx);

64 }

66}

67

69 emitOp(dwarf::DW_OP_fbreg);

71}

72

74 if (!SizeInBits)

75 return;

76

77 const unsigned SizeOfByte = 8;

78 if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {

79 emitOp(dwarf::DW_OP_bit_piece);

82 } else {

83 emitOp(dwarf::DW_OP_piece);

84 unsigned ByteSize = SizeInBits / SizeOfByte;

86 }

87 this->OffsetInBits += SizeInBits;

88}

89

92 emitOp(dwarf::DW_OP_shr);

93}

94

97 emitOp(dwarf::DW_OP_and);

98}

99

102 unsigned MaxSize) {

106 return true;

107 }

108

109 int64_t Reg = TRI.getDwarfRegNum(MachineReg, false);

110 if (Reg > 0) {

112 return true;

113 }

114 return false;

115 }

116

117 int64_t Reg = TRI.getDwarfRegNum(MachineReg, false);

118

119

120 if (Reg >= 0) {

122 return true;

123 }

124

125

126

127 for (MCPhysReg SR : TRI.superregs(MachineReg)) {

128 Reg = TRI.getDwarfRegNum(SR, false);

129 if (Reg >= 0) {

130 unsigned Idx = TRI.getSubRegIndex(SR, MachineReg);

131 unsigned Size = TRI.getSubRegIdxSize(Idx);

132 unsigned RegOffset = TRI.getSubRegIdxOffset(Idx);

134

136 return true;

137 }

138 }

139

140

141

142 unsigned CurPos = 0;

143

145 unsigned RegSize = TRI.getRegSizeInBits(*RC);

146

147

148

149

150

152 for (MCPhysReg SR : TRI.subregs(MachineReg)) {

153 unsigned Idx = TRI.getSubRegIndex(MachineReg, SR);

154 unsigned Size = TRI.getSubRegIdxSize(Idx);

155 unsigned Offset = TRI.getSubRegIdxOffset(Idx);

156 Reg = TRI.getDwarfRegNum(SR, false);

157 if (Reg < 0)

158 continue;

159

160

161

164

165

166

167 if (Offset < MaxSize && CurSubReg.test(Coverage)) {

168

171 -1, Offset - CurPos, "no DWARF register encoding"));

174 else

176 Reg, std::min(Size, MaxSize - Offset), "sub-register"));

177 }

178

181 }

182

183 if (CurPos == 0)

184 return false;

185

188 -1, RegSize - CurPos, "no DWARF register encoding"));

189 return true;

190}

191

194 emitOp(dwarf::DW_OP_stack_value);

195}

196

200 emitOp(dwarf::DW_OP_consts);

202}

203

208}

209

213

214 unsigned Size = Value.getBitWidth();

216

217

218

223 break;

227 }

228}

229

234 if (NumBytes == 4 || NumBytes == 8 ) {

235

236 emitOp(dwarf::DW_OP_implicit_value);

237 emitUnsigned(NumBytes );

238

239

240

241

244

245 for (int i = 0; i < NumBytes; ++i) {

247 API = API.lshr(8);

248 }

249

250 return;

251 }

253 dbgs() << "Skipped DW_OP_implicit_value creation for ConstantFP of size: "

255}

256

260 unsigned FragmentOffsetInBits) {

262 if (addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) {

264 return false;

265 }

266

267 bool HasComplexExpression = false;

268 auto Op = ExprCursor.peek();

270 HasComplexExpression = true;

271

272

273

274

275

276

277

278

279

280

281

282

288 return false;

289 }

290

291

292

293

294

300 RegSize += Reg.SubRegSize;

301 if (Reg.DwarfRegNo >= 0)

302 addReg(Reg.DwarfRegNo, Reg.Comment);

303 if (FragmentInfo)

304 if (RegSize > FragmentInfo->SizeInBits)

305

306

307 break;

309 }

310

313

316 emitOp(dwarf::DW_OP_stack_value);

317 }

318

320

321

322 auto NextOp = ExprCursor.peek();

326 return true;

327 }

328

329

332 return Op.getOp() == dwarf::DW_OP_stack_value;

333 })) {

336 return false;

337 }

338

339

340

342 LLVM_DEBUG(dbgs() << "TODO: giving up on debug information due to "

343 "multi-register usage.\n");

346 return false;

347 }

348

351 int SignedOffset = 0;

352 assert(!Reg.isSubRegister() && "full register expected");

353

354

355

356 if (Op && (Op->getOp() == dwarf::DW_OP_plus_uconst)) {

358 uint64_t IntMax = static_cast<uint64_t>(std::numeric_limits::max());

359 if (Offset <= IntMax) {

360 SignedOffset = Offset;

361 ExprCursor.take();

362 }

363 }

364

365

366

367

368 if (Op && Op->getOp() == dwarf::DW_OP_constu) {

370 uint64_t IntMax = static_cast<uint64_t>(std::numeric_limits::max());

372 if (N && N->getOp() == dwarf::DW_OP_plus && Offset <= IntMax) {

373 SignedOffset = Offset;

375 } else if (N && N->getOp() == dwarf::DW_OP_minus &&

377 SignedOffset = -static_cast<int64_t>(Offset);

379 }

380 }

381

382 if (FBReg)

384 else

385 addBReg(Reg.DwarfRegNo, SignedOffset);

387

388

389

390 auto NextOp = ExprCursor.peek();

394

395 return true;

396}

397

402}

403

408

411}

412

415 auto Op = ExprCursor.take();

416 (void)Op;

420 "Can currently only emit entry values covering a single operation");

421

427}

428

432

433 emitOp(CU.getDwarf5OrGNULocationAtom(dwarf::DW_OP_entry_value));

434

435

438

439

441

445}

446

450

451

452

454 "Began emitting entry value block before cancelling entry value");

455

458}

459

462

463

464 unsigned I = 0, E = CU.ExprRefedBaseTypes.size();

465 for (; I != E; ++I)

466 if (CU.ExprRefedBaseTypes[I].BitSize == BitSize &&

467 CU.ExprRefedBaseTypes[I].Encoding == Encoding)

468 break;

469

470 if (I == E)

471 CU.ExprRefedBaseTypes.emplace_back(BitSize, Encoding);

472 return I;

473}

474

475

476

478 while (ExprCursor) {

479 auto Op = ExprCursor.take();

480 switch (Op->getOp()) {

481 case dwarf::DW_OP_deref:

483 break;

484 default:

485 return false;

486 }

487 }

488 return true;

489}

490

495 });

496}

497

501

502

504

505 std::optionalDIExpression::ExprOperand PrevConvertOp;

506

507 while (ExprCursor) {

508 auto Op = ExprCursor.take();

510

511 if (OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) {

513 continue;

514 } else if (OpNum >= dwarf::DW_OP_breg0 && OpNum <= dwarf::DW_OP_breg31) {

515 addBReg(OpNum - dwarf::DW_OP_breg0, Op->getArg(0));

516 continue;

517 }

518

519 switch (OpNum) {

521 if (!InsertArg(Op->getArg(0), ExprCursor)) {

523 return false;

524 }

525 break;

527 unsigned SizeInBits = Op->getArg(1);

528 unsigned FragmentOffset = Op->getArg(0);

529

530

531

532 assert(OffsetInBits >= FragmentOffset && "fragment offset not added?");

533 assert(SizeInBits >= OffsetInBits - FragmentOffset && "size underflow");

534

535

536

537

539

540

541

544

545

548

549

552

554 return true;

555 }

558 unsigned SizeInBits = Op->getArg(1);

559 unsigned BitOffset = Op->getArg(0);

560

561

562

563

565 emitOp(dwarf::DW_OP_deref_size);

567 }

568

569

570

571

572

573 unsigned PtrSizeInBytes = CU.getAsmPrinter()->MAI->getCodePointerSize();

574 unsigned LeftShift = PtrSizeInBytes * 8 - (SizeInBits + BitOffset);

575 unsigned RightShift = LeftShift + BitOffset;

576 if (LeftShift) {

577 emitOp(dwarf::DW_OP_constu);

579 emitOp(dwarf::DW_OP_shl);

580 }

581 emitOp(dwarf::DW_OP_constu);

584 : dwarf::DW_OP_shr);

585

586

587

589 break;

590 }

591 case dwarf::DW_OP_plus_uconst:

593 emitOp(dwarf::DW_OP_plus_uconst);

595 break;

596 case dwarf::DW_OP_plus:

597 case dwarf::DW_OP_minus:

598 case dwarf::DW_OP_mul:

599 case dwarf::DW_OP_div:

600 case dwarf::DW_OP_mod:

601 case dwarf::DW_OP_or:

602 case dwarf::DW_OP_and:

603 case dwarf::DW_OP_xor:

604 case dwarf::DW_OP_shl:

605 case dwarf::DW_OP_shr:

606 case dwarf::DW_OP_shra:

607 case dwarf::DW_OP_lit0:

608 case dwarf::DW_OP_not:

609 case dwarf::DW_OP_dup:

610 case dwarf::DW_OP_push_object_address:

611 case dwarf::DW_OP_over:

612 case dwarf::DW_OP_eq:

613 case dwarf::DW_OP_ne:

614 case dwarf::DW_OP_gt:

615 case dwarf::DW_OP_ge:

616 case dwarf::DW_OP_lt:

617 case dwarf::DW_OP_le:

619 break;

620 case dwarf::DW_OP_deref:

623

624

626 else

627 emitOp(dwarf::DW_OP_deref);

628 break;

629 case dwarf::DW_OP_constu:

632 break;

633 case dwarf::DW_OP_consts:

635 emitOp(dwarf::DW_OP_consts);

637 break;

639 unsigned BitSize = Op->getArg(0);

641 if (DwarfVersion >= 5 && CU.getDwarfDebug().useOpConvert()) {

642 emitOp(dwarf::DW_OP_convert);

643

644

645

646

647

648

650 } else {

651 if (PrevConvertOp && PrevConvertOp->getArg(0) < BitSize) {

652 if (Encoding == dwarf::DW_ATE_signed)

654 else if (Encoding == dwarf::DW_ATE_unsigned)

656 PrevConvertOp = std::nullopt;

657 } else {

658 PrevConvertOp = Op;

659 }

660 }

661 break;

662 }

663 case dwarf::DW_OP_stack_value:

665 break;

666 case dwarf::DW_OP_swap:

668 emitOp(dwarf::DW_OP_swap);

669 break;

670 case dwarf::DW_OP_xderef:

672 emitOp(dwarf::DW_OP_xderef);

673 break;

674 case dwarf::DW_OP_deref_size:

675 emitOp(dwarf::DW_OP_deref_size);

677 break;

680 break;

681 case dwarf::DW_OP_regx:

682 emitOp(dwarf::DW_OP_regx);

684 break;

685 case dwarf::DW_OP_bregx:

686 emitOp(dwarf::DW_OP_bregx);

689 break;

690 default:

692 }

693 }

694

696

698

699 return true;

700}

701

702

709}

710

712 assert(DwarfRegs.size() == 0 && "dwarf registers not emitted");

713

715 return;

716

718 return;

720}

721

724 return;

725

728 "overlapping or duplicate fragments");

732}

733

735

736 emitOp(dwarf::DW_OP_dup);

737 emitOp(dwarf::DW_OP_constu);

739 emitOp(dwarf::DW_OP_shr);

740 emitOp(dwarf::DW_OP_lit0);

741 emitOp(dwarf::DW_OP_not);

742 emitOp(dwarf::DW_OP_mul);

743 emitOp(dwarf::DW_OP_constu);

745 emitOp(dwarf::DW_OP_shl);

746 emitOp(dwarf::DW_OP_or);

747}

748

750

751

752 if (FromBits / 7 < 1+1+1+1+1) {

753

754 emitOp(dwarf::DW_OP_constu);

756 } else {

757

758

759

760

761

762 emitOp(dwarf::DW_OP_lit1);

763 emitOp(dwarf::DW_OP_constu);

765 emitOp(dwarf::DW_OP_shl);

766 emitOp(dwarf::DW_OP_lit1);

767 emitOp(dwarf::DW_OP_minus);

768 }

769 emitOp(dwarf::DW_OP_and);

770}

771

773 emitOp(dwarf::DW_OP_WASM_location);

774 emitUnsigned(Index == 4 ? 0 : Index);

776 if (Index == 4 ) {

779 } else {

782 }

783}

This file implements a class to represent arbitrary precision integral constant values and operations...

Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx

static bool isMemoryLocation(DIExpressionCursor ExprCursor)

Assuming a well-formed expression, match "DW_OP_deref* DW_OP_LLVM_fragment?".

This file contains constants used for implementing Dwarf debug support.

unsigned const TargetRegisterInfo * TRI

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file implements the SmallBitVector class.

APInt bitcastToAPInt() const

Class for arbitrary precision integers.

uint64_t getZExtValue() const

Get zero extended value.

unsigned getBitWidth() const

Return the number of bits in the APInt.

APInt lshr(unsigned shiftAmt) const

Logical right-shift function.

This class is intended to be used as a driving class for all asm writers.

const DataLayout & getDataLayout() const

Return information about data layout.

Holds a DIExpression and keeps track of how many operands have been consumed so far.

std::optional< DIExpression::ExprOperand > peekNext() const

Return the next operation.

std::optional< DIExpression::FragmentInfo > getFragmentInfo() const

Retrieve the fragment information, if any.

std::optional< DIExpression::ExprOperand > peek() const

Return the current operation.

void consume(unsigned N)

Consume N operations.

std::optional< DIExpression::ExprOperand > take()

Consume one operation.

A lightweight wrapper around an expression operand.

bool isEntryValue() const

Check if the expression consists of exactly one entry value operand.

bool isFragment() const

Return whether this is a piece of an aggregate variable.

static std::optional< FragmentInfo > getFragmentInfo(expr_op_iterator Start, expr_op_iterator End)

Retrieve the details of this fragment expression.

This class represents an Operation in the Expression.

void addAnd(unsigned Mask)

Emit a bitwise and dwarf operation.

void setLocation(const MachineLocation &Loc, const DIExpression *DIExpr)

Set the location (Loc) and DIExpression (DIExpr) to describe.

virtual void emitOp(uint8_t Op, const char *Comment=nullptr)=0

Output a dwarf operand and an optional assembler comment.

virtual void disableTemporaryBuffer()=0

Disable emission to the temporary buffer.

bool isUnknownLocation() const

virtual unsigned getTemporaryBufferSize()=0

Return the emitted size, in number of bytes, for the data stored in the temporary buffer.

uint64_t OffsetInBits

Current Fragment Offset in Bits.

virtual bool isFrameRegister(const TargetRegisterInfo &TRI, llvm::Register MachineReg)=0

Return whether the given machine register is the frame register in the current function.

void finalize()

This needs to be called last to commit any pending changes.

void addFragmentOffset(const DIExpression *Expr)

If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to the fragment described by Ex...

void emitLegacySExt(unsigned FromBits)

void cancelEntryValue()

Cancel the emission of an entry value.

bool isRegisterLocation() const

void setMemoryLocationKind()

Lock this down to become a memory location description.

virtual void emitBaseTypeRef(uint64_t Idx)=0

virtual void emitData1(uint8_t Value)=0

bool addMachineReg(const TargetRegisterInfo &TRI, llvm::Register MachineReg, unsigned MaxSize=~1U)

Emit a partial DWARF register operation.

unsigned SavedLocationKind

std::optional< uint8_t > TagOffset

bool isImplicitLocation() const

virtual void emitUnsigned(uint64_t Value)=0

Emit a raw unsigned value.

void addConstantFP(const APFloat &Value, const AsmPrinter &AP)

Emit an floating point constant.

void maskSubRegister()

Add masking operations to stencil out a subregister.

SmallVector< Register, 2 > DwarfRegs

The register location, if any.

bool addMachineRegExpression(const TargetRegisterInfo &TRI, DIExpressionCursor &Expr, llvm::Register MachineReg, unsigned FragmentOffsetInBits=0)

Emit a machine register location.

void addStackValue()

Emit a DW_OP_stack_value, if supported.

void finalizeEntryValue()

Finalize an entry value by emitting its size operand, and committing the DWARF block which has been e...

bool isMemoryLocation() const

void addUnsignedConstant(uint64_t Value)

Emit an unsigned constant.

unsigned SubRegisterSizeInBits

Sometimes we need to add a DW_OP_bit_piece to describe a subregister.

void addFBReg(int64_t Offset)

Emit DW_OP_fbreg .

void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits)

Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed to represent a subregister.

void addExpression(DIExpressionCursor &&Expr)

Emit all remaining operations in the DIExpressionCursor.

bool isEntryValue() const

unsigned getOrCreateBaseType(unsigned BitSize, dwarf::TypeKind Encoding)

Return the index of a base type with the given properties and create one if necessary.

void addSignedConstant(int64_t Value)

Emit a signed constant.

void emitLegacyZExt(unsigned FromBits)

bool IsEmittingEntryValue

Whether we are currently emitting an entry value operation.

virtual void emitSigned(int64_t Value)=0

Emit a raw signed value.

void addReg(int64_t DwarfReg, const char *Comment=nullptr)

Emit a DW_OP_reg operation.

unsigned SubRegisterOffsetInBits

void setEntryValueFlags(const MachineLocation &Loc)

Lock this down to become an entry value location.

virtual void commitTemporaryBuffer()=0

Commit the data stored in the temporary buffer to the main output.

void addShr(unsigned ShiftBy)

Emit a shift-right dwarf operation.

void addWasmLocation(unsigned Index, uint64_t Offset)

Emit location information expressed via WebAssembly location + offset The Index is an identifier for ...

virtual void enableTemporaryBuffer()=0

Start emitting data to the temporary buffer.

void emitConstu(uint64_t Value)

Emit a normalized unsigned constant.

void beginEntryValueExpression(DIExpressionCursor &ExprCursor)

Begin emission of an entry value dwarf operation.

void addOpPiece(unsigned SizeInBits, unsigned OffsetInBits=0)

Emit a DW_OP_piece or DW_OP_bit_piece operation for a variable fragment.

void addBReg(int64_t DwarfReg, int64_t Offset)

Emit a DW_OP_breg operation.

Wrapper class representing virtual and physical registers.

constexpr bool isPhysical() const

Return true if the specified register number is in the physical register namespace.

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

bool test(unsigned Idx) const

TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...

LLVM Value Representation.

An efficient, type-erasing, non-owning reference to a callable.

#define llvm_unreachable(msg)

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

@ DW_OP_LLVM_entry_value

Only used in LLVM metadata.

@ DW_OP_LLVM_extract_bits_zext

Only used in LLVM metadata.

@ DW_OP_LLVM_tag_offset

Only used in LLVM metadata.

@ DW_OP_LLVM_fragment

Only used in LLVM metadata.

@ DW_OP_LLVM_arg

Only used in LLVM metadata.

@ DW_OP_LLVM_convert

Only used in LLVM metadata.

@ DW_OP_LLVM_extract_bits_sext

Only used in LLVM metadata.

This is an optimization pass for GlobalISel generic memory operations.

bool any_of(R &&range, UnaryPredicate P)

Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

DWARFExpression::Operation Op

Holds information about all subregisters comprising a register location.

static Register createRegister(int64_t RegNo, const char *Comment)

Create a full register, no extra DW_OP_piece operators necessary.

static Register createSubRegister(int64_t RegNo, unsigned SizeInBits, const char *Comment)

Create a subregister that needs a DW_OP_piece operator with SizeInBits.