LLVM: lib/CodeGen/GlobalISel/InlineAsmLowering.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

21

22#define DEBUG_TYPE "inline-asm-lowering"

23

24using namespace llvm;

25

26void InlineAsmLowering::anchor() {}

27

28namespace {

29

30

31

33public:

34

35

36 SmallVector<Register, 1> Regs;

37

38 explicit GISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &Info)

39 : TargetLowering::AsmOperandInfo(Info) {}

40};

41

43

44class ExtraFlags {

45 unsigned Flags = 0;

46

47public:

48 explicit ExtraFlags(const CallBase &CB) {

50 if (IA->hasSideEffects())

52 if (IA->isAlignStack())

57 }

58

59 void update(const TargetLowering::AsmOperandInfo &OpInfo) {

60

61

62

63

72 }

73 }

74

75 unsigned get() const { return Flags; }

76};

77

78}

79

80

83 GISelAsmOperandInfo &OpInfo,

84 GISelAsmOperandInfo &RefOpInfo) {

85

88

89

91 return;

92

93

94

98 &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT);

99

100 if (!RC)

101 return;

102

103

104

105 if (OpInfo.isMatchingInputConstraint())

106 return;

107

108

109 unsigned NumRegs = 1;

110 if (OpInfo.ConstraintVT != MVT::Other)

111 NumRegs =

113

114

115

116

117

118

121

122

123 if (AssignedReg) {

124 for (; *I != AssignedReg; ++I)

125 assert(I != RC->end() && "AssignedReg should be a member of provided RC");

126 }

127

128

129

130 for (; NumRegs; --NumRegs, ++I) {

131 assert(I != RC->end() && "Ran out of registers to allocate!");

133 OpInfo.Regs.push_back(R);

134 }

135}

136

139 assert(!OpInfo.Codes.empty() && "Must have at least one constraint");

140

141

142 if (OpInfo.Codes.size() == 1) {

143 OpInfo.ConstraintCode = OpInfo.Codes[0];

144 OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode);

145 } else {

147 if (G.empty())

148 return;

149

150 unsigned BestIdx = 0;

151 for (const unsigned E = G.size();

154 ++BestIdx)

155 ;

156 OpInfo.ConstraintCode = G[BestIdx].first;

157 OpInfo.ConstraintType = G[BestIdx].second;

158 }

159

160

161 if (OpInfo.ConstraintCode == "X" && OpInfo.CallOperandVal) {

162

163

164

165 Value *Val = OpInfo.CallOperandVal;

167 return;

168

169

170

171 if (const char *Repl = TLI->LowerXConstraint(OpInfo.ConstraintVT)) {

172 OpInfo.ConstraintCode = Repl;

173 OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode);

174 }

175 }

176}

177

180 return F.getNumOperandRegisters();

181}

182

188

189 auto SrcTy = MRI->getType(Src);

190 if (!SrcTy.isValid()) {

191 LLVM_DEBUG(dbgs() << "Source type for copy is not valid\n");

192 return false;

193 }

194 unsigned SrcSize = TRI->getRegSizeInBits(Src, *MRI);

195 unsigned DstSize = TRI->getRegSizeInBits(Dst, *MRI);

196

197 if (DstSize < SrcSize) {

198 LLVM_DEBUG(dbgs() << "Input can't fit in destination reg class\n");

199 return false;

200 }

201

202

203 if (DstSize > SrcSize) {

204 if (!SrcTy.isScalar()) {

205 LLVM_DEBUG(dbgs() << "Can't extend non-scalar input to size of"

206 "destination register class\n");

207 return false;

208 }

210 }

211

213 return true;

214}

215

219 const {

221

222

223 GISelAsmOperandInfoVector ConstraintOperands;

224

229

231

233 TLI->ParseConstraints(DL, TRI, Call);

234

235 ExtraFlags ExtraInfo(Call);

236 unsigned ArgNo = 0;

237 unsigned ResNo = 0;

238 for (auto &T : TargetConstraints) {

239 ConstraintOperands.push_back(GISelAsmOperandInfo(T));

240 GISelAsmOperandInfo &OpInfo = ConstraintOperands.back();

241

242

243 if (OpInfo.hasArg()) {

244 OpInfo.CallOperandVal = Call.getArgOperand(ArgNo);

245

247 LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n");

248 return false;

249 }

250

251 Type *OpTy = OpInfo.CallOperandVal->getType();

252

253

254

255 if (OpInfo.isIndirect) {

256 OpTy = Call.getParamElementType(ArgNo);

257 assert(OpTy && "Indirect operand must have elementtype attribute");

258 }

259

260

263 dbgs() << "Aggregate input operands are not supported yet\n");

264 return false;

265 }

266

267 OpInfo.ConstraintVT =

268 TLI->getAsmOperandValueType(DL, OpTy, true).getSimpleVT();

269 ++ArgNo;

271 assert(Call.getType()->isVoidTy() && "Bad inline asm!");

273 OpInfo.ConstraintVT =

274 TLI->getSimpleValueType(DL, STy->getElementType(ResNo));

275 } else {

276 assert(ResNo == 0 && "Asm only has one result!");

277 OpInfo.ConstraintVT =

278 TLI->getAsmOperandValueType(DL, Call.getType()).getSimpleVT();

279 }

280 ++ResNo;

281 } else {

283 "GlobalISel currently doesn't support callbr");

284 OpInfo.ConstraintVT = MVT::Other;

285 }

286

287 if (OpInfo.ConstraintVT == MVT::i64x8)

288 return false;

289

290

292

293

294 ExtraInfo.update(OpInfo);

295 }

296

297

298

299

302 .addImm(ExtraInfo.get());

303

304

305

307

308

309 GISelAsmOperandInfoVector OutputOperands;

310

311 for (auto &OpInfo : ConstraintOperands) {

312 GISelAsmOperandInfo &RefOpInfo =

313 OpInfo.isMatchingInputConstraint()

314 ? ConstraintOperands[OpInfo.getMatchedOperand()]

315 : OpInfo;

316

317

319

320 switch (OpInfo.Type) {

324 TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);

326 "Failed to convert memory constraint code to constraint id.");

327

328

329

331 Flag.setMemConstraint(ConstraintID);

332 Inst.addImm(Flag);

334 GetOrCreateVRegs(*OpInfo.CallOperandVal);

336 SourceRegs.size() == 1 &&

337 "Expected the memory output to fit into a single virtual register");

338 Inst.addReg(SourceRegs[0]);

339 } else {

340

341

345

346

347 if (OpInfo.Regs.empty()) {

349 << "Couldn't allocate output register for constraint\n");

350 return false;

351 }

352

353

354

358 OpInfo.Regs.size());

359 if (OpInfo.Regs.front().isVirtual()) {

360

361

362

363

365 Flag.setRegClass(RC->getID());

366 }

367

368 Inst.addImm(Flag);

369

370 for (Register Reg : OpInfo.Regs) {

371 Inst.addReg(Reg,

374 }

375

376

377 OutputOperands.push_back(OpInfo);

378 }

379

380 break;

383 if (OpInfo.isMatchingInputConstraint()) {

384 unsigned DefIdx = OpInfo.getMatchedOperand();

385

386 unsigned InstFlagIdx = StartIdx;

387 for (unsigned i = 0; i < DefIdx; ++i)

388 InstFlagIdx += getNumOpRegs(*Inst, InstFlagIdx) + 1;

390

391 const InlineAsm::Flag MatchedOperandFlag(Inst->getOperand(InstFlagIdx).getImm());

392 if (MatchedOperandFlag.isMemKind()) {

393 LLVM_DEBUG(dbgs() << "Matching input constraint to mem operand not "

394 "supported. This should be target specific.\n");

395 return false;

396 }

398 LLVM_DEBUG(dbgs() << "Unknown matching constraint\n");

399 return false;

400 }

401

402

403 unsigned DefRegIdx = InstFlagIdx + 1;

404 Register Def = Inst->getOperand(DefRegIdx).getReg();

405

406 ArrayRef SrcRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);

407 assert(SrcRegs.size() == 1 && "Single register is expected here");

408

409

411

412 if (Def.isVirtual()) {

413 In = MRI->createVirtualRegister(MRI->getRegClass(Def));

415 return false;

416 }

417

418

421 Inst.addImm(UseFlag);

422 Inst.addReg(In);

423 Inst->tieOperands(DefRegIdx, Inst->getNumOperands() - 1);

424 break;

425 }

426

428 OpInfo.isIndirect) {

429 LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "

430 "not supported yet\n");

431 return false;

432 }

433

436

437 std::vector Ops;

439 OpInfo.ConstraintCode, Ops,

440 MIRBuilder)) {

442 << OpInfo.ConstraintCode << " yet\n");

443 return false;

444 }

445

447 "Expected constraint to be lowered to at least one operand");

448

449

450 const unsigned OpFlags =

452 Inst.addImm(OpFlags);

453 Inst.add(Ops);

454 break;

455 }

456

459 TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);

462 Inst.addImm(OpFlags);

463

464 if (OpInfo.isIndirect) {

465

467 GetOrCreateVRegs(*OpInfo.CallOperandVal);

468 if (SourceRegs.size() != 1) {

469 LLVM_DEBUG(dbgs() << "Expected the memory input to fit into a "

470 "single virtual register "

471 "for constraint '"

472 << OpInfo.ConstraintCode << "'\n");

473 return false;

474 }

475 Inst.addReg(SourceRegs[0]);

476 break;

477 }

478

479

480

481 Value *OpVal = OpInfo.CallOperandVal;

483 Align Alignment = DL.getPrefTypeAlign(OpVal->getType());

484 int FrameIdx =

486

487 unsigned AddrSpace = DL.getAllocaAddrSpace();

488 LLT FramePtrTy =

489 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));

492 GetOrCreateVRegs(*OpInfo.CallOperandVal);

493 if (SourceRegs.size() != 1) {

494 LLVM_DEBUG(dbgs() << "Expected the memory input to fit into a single "

495 "virtual register "

496 "for constraint '"

497 << OpInfo.ConstraintCode << "'\n");

498 return false;

499 }

500 MIRBuilder.buildStore(SourceRegs[0], Ptr,

502 Alignment);

504 break;

505 }

506

509 "Unknown constraint type!");

510

511 if (OpInfo.isIndirect) {

512 LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "

513 "for constraint '"

514 << OpInfo.ConstraintCode << "'\n");

515 return false;

516 }

517

518

519 if (OpInfo.Regs.empty()) {

522 << "Couldn't allocate input register for register constraint\n");

523 return false;

524 }

525

526 unsigned NumRegs = OpInfo.Regs.size();

527 ArrayRef SourceRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);

528 assert(NumRegs == SourceRegs.size() &&

529 "Expected the number of input registers to match the number of "

530 "source registers");

531

532 if (NumRegs > 1) {

533 LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are "

534 "not supported yet\n");

535 return false;

536 }

537

539 if (OpInfo.Regs.front().isVirtual()) {

540

542 Flag.setRegClass(RC->getID());

543 }

544 Inst.addImm(Flag);

545 if (buildAnyextOrCopy(OpInfo.Regs[0], SourceRegs[0], MIRBuilder))

546 return false;

547 Inst.addReg(OpInfo.Regs[0]);

548 break;

549 }

550

552

553 const unsigned NumRegs = OpInfo.Regs.size();

554 if (NumRegs > 0) {

556 Inst.addImm(Flag);

557

558 for (Register Reg : OpInfo.Regs) {

561 }

562 }

563 break;

564 }

565 }

566 }

567

569 auto *Token = Bundle->Inputs[0].get();

572 "Expected the control token to fit into a single virtual register");

574 }

575

576 if (const MDNode *SrcLoc = Call.getMetadata("srcloc"))

577 Inst.addMetadata(SrcLoc);

578

579

584 }

585

586

588

589

591 if (ResRegs.size() != OutputOperands.size()) {

592 LLVM_DEBUG(dbgs() << "Expected the number of output registers to match the "

593 "number of destination registers\n");

594 return false;

595 }

596 for (unsigned int i = 0, e = ResRegs.size(); i < e; i++) {

597 GISelAsmOperandInfo &OpInfo = OutputOperands[i];

598

599 if (OpInfo.Regs.empty())

600 continue;

601

602 switch (OpInfo.ConstraintType) {

605 if (OpInfo.Regs.size() > 1) {

606 LLVM_DEBUG(dbgs() << "Output operands with multiple defining "

607 "registers are not supported yet\n");

608 return false;

609 }

610

611 Register SrcReg = OpInfo.Regs[0];

612 unsigned SrcSize = TRI->getRegSizeInBits(SrcReg, *MRI);

613 LLT ResTy = MRI->getType(ResRegs[i]);

615

616

618 MRI->createGenericVirtualRegister(LLT::scalar(SrcSize));

619 MIRBuilder.buildCopy(Tmp1Reg, SrcReg);

620

621 MIRBuilder.buildTrunc(ResRegs[i], Tmp1Reg);

623 MIRBuilder.buildCopy(ResRegs[i], SrcReg);

624 } else {

625 LLVM_DEBUG(dbgs() << "Unhandled output operand with "

626 "mismatched register size\n");

627 return false;

628 }

629

630 break;

631 }

635 dbgs() << "Cannot lower target specific output constraints yet\n");

636 return false;

638 break;

640 break;

642 LLVM_DEBUG(dbgs() << "Unexpected unknown constraint\n");

643 return false;

644 }

645 }

646

647 return true;

648}

649

651 Value *Val, StringRef Constraint, std::vector &Ops,

653 if (Constraint.size() > 1)

654 return false;

655

656 char ConstraintLetter = Constraint[0];

657 switch (ConstraintLetter) {

658 default:

659 return false;

660 case 'i':

661 case 'n':

663 assert(CI->getBitWidth() <= 64 &&

664 "expected immediate to fit into 64-bits");

665

666 bool IsBool = CI->getBitWidth() == 1;

667 int64_t ExtVal = IsBool ? CI->getZExtValue() : CI->getSExtValue();

669 return true;

670 }

671 return false;

672 }

673}

unsigned const MachineRegisterInfo * MRI

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

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

Analysis containing CSE Info

Module.h This file contains the declarations for the Module class.

static unsigned getNumOpRegs(const MachineInstr &I, unsigned OpIdx)

Definition InlineAsmLowering.cpp:178

static void getRegistersForValue(MachineFunction &MF, MachineIRBuilder &MIRBuilder, GISelAsmOperandInfo &OpInfo, GISelAsmOperandInfo &RefOpInfo)

Assign virtual/physical registers for the specified register operand.

Definition InlineAsmLowering.cpp:81

static void computeConstraintToUse(const TargetLowering *TLI, TargetLowering::AsmOperandInfo &OpInfo)

Definition InlineAsmLowering.cpp:137

static bool buildAnyextOrCopy(Register Dst, Register Src, MachineIRBuilder &MIRBuilder)

Definition InlineAsmLowering.cpp:183

This file describes how to lower LLVM inline asm to machine code INLINEASM.

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

This file declares the MachineIRBuilder class.

Register const TargetRegisterInfo * TRI

Promote Memory to Register

MachineInstr unsigned OpIdx

This file describes how to lower LLVM code to machine code.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

size_t size() const

size - Get the array size.

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

Value * getCalledOperand() const

bool isConvergent() const

Determine if the invoke is convergent.

This is the shared class of boolean and integer constants.

A parsed version of the target data layout string in and methods for querying it.

LLVMContext & getContext() const

getContext - Return a reference to the LLVMContext associated with this function.

bool hasFnAttribute(Attribute::AttrKind Kind) const

Return true if the function has the attribute.

bool lowerInlineAsm(MachineIRBuilder &MIRBuilder, const CallBase &CB, std::function< ArrayRef< Register >(const Value &Val)> GetOrCreateVRegs) const

Lower the given inline asm call instruction GetOrCreateVRegs is a callback to materialize a register ...

Definition InlineAsmLowering.cpp:216

virtual bool lowerAsmOperandForConstraint(Value *Val, StringRef Constraint, std::vector< MachineOperand > &Ops, MachineIRBuilder &MIRBuilder) const

Lower the specified operand into the Ops vector.

Definition InlineAsmLowering.cpp:650

void setMatchingOp(unsigned OperandNo)

setMatchingOp - Augment an existing flag with information indicating that this input operand is tied ...

void setMemConstraint(ConstraintCode C)

setMemConstraint - Augment an existing flag with the constraint code for a memory constraint.

bool isRegDefEarlyClobberKind() const

bool isRegDefKind() const

constexpr bool isScalar() const

static constexpr LLT scalar(unsigned SizeInBits)

Get a low-level scalar or aggregate "bag of bits".

static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)

Get a low-level pointer in the given address space.

constexpr TypeSize getSizeInBits() const

Returns the total size of the type. Must only be called on sized types.

LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)

Create a new statically sized stack object, returning a nonnegative identifier to represent it.

const TargetSubtargetInfo & getSubtarget() const

getSubtarget - Return the subtarget for which this machine code is being compiled.

MachineFrameInfo & getFrameInfo()

getFrameInfo - Return the frame info object for the current function.

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

Function & getFunction()

Return the LLVM function that this machine code represents.

Helper class to build MachineInstr.

MachineInstrBuilder insertInstr(MachineInstrBuilder MIB)

Insert an existing instruction at the insertion point.

MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)

Build and insert G_STORE Val, Addr, MMO.

MachineInstrBuilder buildFrameIndex(const DstOp &Res, int Idx)

Build and insert Res = G_FRAME_INDEX Idx.

MachineFunction & getMF()

Getter for the function we currently build.

MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)

Build and insert Res = G_TRUNC Op.

MachineInstrBuilder buildAnyExt(const DstOp &Res, const SrcOp &Op)

Build and insert Res = G_ANYEXT Op0.

MachineRegisterInfo * getMRI()

Getter for MRI.

MachineInstrBuilder buildInstrNoInsert(unsigned Opcode)

Build but don't insert = Opcode .

MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)

Build and insert Res = COPY Op.

Register getReg(unsigned Idx) const

Get the register for the operand index.

const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const

const MachineInstrBuilder & addImm(int64_t Val) const

Add a new immediate operand.

const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const

Add a new virtual register operand.

Representation of each machine instruction.

unsigned getNumOperands() const

Retuns the total number of operands.

static MachineOperand CreateImm(int64_t Val)

MachineRegisterInfo - Keep track of information for virtual and physical registers,...

Wrapper class representing virtual and physical registers.

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

StringRef - Represent a constant reference to a string, i.e.

constexpr size_t size() const

size - Get the string size.

Class to represent struct types.

virtual unsigned getNumRegisters(LLVMContext &Context, EVT VT, std::optional< MVT > RegisterVT=std::nullopt) const

Return the number of registers that this ValueType will eventually require.

This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...

SmallVector< ConstraintPair > ConstraintGroup

std::vector< AsmOperandInfo > AsmOperandInfoVector

virtual ConstraintType getConstraintType(StringRef Constraint) const

Given a constraint, return the type of constraint it is for this target.

virtual const char * LowerXConstraint(EVT ConstraintVT) const

Try to replace an X constraint, which matches anything, with another that has more specific requireme...

ConstraintGroup getConstraintPreferences(AsmOperandInfo &OpInfo) const

Given an OpInfo with list of constraints codes as strings, return a sorted Vector of pairs of constra...

virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const

Given a physical register constraint (e.g.

unsigned getID() const

Return the register class ID number.

const MCPhysReg * iterator

iterator begin() const

begin/end - Return all of the registers in this class.

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

virtual const TargetRegisterInfo * getRegisterInfo() const =0

Return the target's register information.

virtual const TargetLowering * getTargetLowering() const

The instances of the Type class are immutable: once they are created, they are never changed.

bool isSingleValueType() const

Return true if the type is a valid type for a register in codegen.

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

@ Implicit

Not emitted register (e.g. carry, or temporary result).

@ Define

Register definition.

@ EarlyClobber

Register definition happens before uses.

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.

unsigned getImplRegState(bool B)

decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)

LLVM_ABI raw_ostream & dbgs()

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

bool isa(const From &Val)

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

uint16_t MCPhysReg

An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...

decltype(auto) cast(const From &Val)

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

This struct is a compact representation of a valid (non-zero power of two) alignment.

ConstraintPrefix Type

Type - The basic type of the constraint: input/output/clobber/label.

static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)

Return a MachinePointerInfo record that refers to the specified FrameIndex.

This contains information for each constraint that we are lowering.

TargetLowering::ConstraintType ConstraintType

Information about the constraint code, e.g.