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

1

2

3

4

5

6

7

8

9

10

11

12

13

20

21#define DEBUG_TYPE "inline-asm-lowering"

22

23using namespace llvm;

24

25void InlineAsmLowering::anchor() {}

26

27namespace {

28

29

30

32public:

33

34

36

39};

40

42

43class ExtraFlags {

44 unsigned Flags = 0;

45

46public:

47 explicit ExtraFlags(const CallBase &CB) {

49 if (IA->hasSideEffects())

51 if (IA->isAlignStack())

56 }

57

59

60

61

62

71 }

72 }

73

74 unsigned get() const { return Flags; }

75};

76

77}

78

79

82 GISelAsmOperandInfo &OpInfo,

83 GISelAsmOperandInfo &RefOpInfo) {

84

87

88

90 return;

91

92

93

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

98

99 if (!RC)

100 return;

101

102

103

104 if (OpInfo.isMatchingInputConstraint())

105 return;

106

107

108 unsigned NumRegs = 1;

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

110 NumRegs =

112

113

114

115

116

117

120

121

122 if (AssignedReg) {

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

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

125 }

126

127

128

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

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

132 OpInfo.Regs.push_back(R);

133 }

134}

135

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

139

140

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

144 } else {

146 if (G.empty())

147 return;

148

149 unsigned BestIdx = 0;

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

153 ++BestIdx)

154 ;

157 }

158

159

161

162

163

165 if (isa(Val) || isa(Val) || isa(Val))

166 return;

167

168

169

173 }

174 }

175}

176

179 return F.getNumOperandRegisters();

180}

181

187

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

189 if (!SrcTy.isValid()) {

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

191 return false;

192 }

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

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

195

196 if (DstSize < SrcSize) {

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

198 return false;

199 }

200

201

202 if (DstSize > SrcSize) {

203 if (!SrcTy.isScalar()) {

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

205 "destination register class\n");

206 return false;

207 }

209 }

210

212 return true;

213}

214

218 const {

219 const InlineAsm *IA = cast(Call.getCalledOperand());

220

221

222 GISelAsmOperandInfoVector ConstraintOperands;

223

228

230

233

234 ExtraFlags ExtraInfo(Call);

235 unsigned ArgNo = 0;

236 unsigned ResNo = 0;

237 for (auto &T : TargetConstraints) {

238 ConstraintOperands.push_back(GISelAsmOperandInfo(T));

239 GISelAsmOperandInfo &OpInfo = ConstraintOperands.back();

240

241

242 if (OpInfo.hasArg()) {

244

245 if (isa(OpInfo.CallOperandVal)) {

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

247 return false;

248 }

249

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

251

252

253

254 if (OpInfo.isIndirect) {

255 OpTy = Call.getParamElementType(ArgNo);

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

257 }

258

259

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

263 return false;

264 }

265

266 OpInfo.ConstraintVT =

268 ++ArgNo;

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

271 if (StructType *STy = dyn_cast(Call.getType())) {

272 OpInfo.ConstraintVT =

274 } else {

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

276 OpInfo.ConstraintVT =

278 }

279 ++ResNo;

280 } else {

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

283 OpInfo.ConstraintVT = MVT::Other;

284 }

285

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

287 return false;

288

289

291

292

293 ExtraInfo.update(OpInfo);

294 }

295

296

297

298

301 .addImm(ExtraInfo.get());

302

303

304

306

307

308 GISelAsmOperandInfoVector OutputOperands;

309

310 for (auto &OpInfo : ConstraintOperands) {

311 GISelAsmOperandInfo &RefOpInfo =

314 : OpInfo;

315

316

318

319 switch (OpInfo.Type) {

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

326

327

328

330 Flag.setMemConstraint(ConstraintID);

331 Inst.addImm(Flag);

335 SourceRegs.size() == 1 &&

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

337 Inst.addReg(SourceRegs[0]);

338 } else {

339

340

344

345

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

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

349 return false;

350 }

351

352

353

357 OpInfo.Regs.size());

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

359

360

361

362

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

365 }

366

367 Inst.addImm(Flag);

368

369 for (Register Reg : OpInfo.Regs) {

370 Inst.addReg(Reg,

373 }

374

375

376 OutputOperands.push_back(OpInfo);

377 }

378

379 break;

384

385 unsigned InstFlagIdx = StartIdx;

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

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

389

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

391 if (MatchedOperandFlag.isMemKind()) {

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

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

394 return false;

395 }

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

398 return false;

399 }

400

401

402 unsigned DefRegIdx = InstFlagIdx + 1;

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

404

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

407

408

410

411 if (Def.isVirtual()) {

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

414 return false;

415 }

416

417

420 Inst.addImm(UseFlag);

421 Inst.addReg(In);

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

423 break;

424 }

425

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

429 "not supported yet\n");

430 return false;

431 }

432

435

436 std::vector Ops;

439 MIRBuilder)) {

442 return false;

443 }

444

445 assert(Ops.size() > 0 &&

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

447

448

449 const unsigned OpFlags =

451 Inst.addImm(OpFlags);

452 Inst.add(Ops);

453 break;

454 }

455

457

460 << "Cannot indirectify memory input operands yet\n");

461 return false;

462 }

463

464 assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!");

465

470 Inst.addImm(OpFlags);

474 SourceRegs.size() == 1 &&

475 "Expected the memory input to fit into a single virtual register");

476 Inst.addReg(SourceRegs[0]);

477 break;

478 }

479

482 "Unknown constraint type!");

483

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

486 "for constraint '"

488 return false;

489 }

490

491

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

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

496 return false;

497 }

498

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

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

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

503 "source registers");

504

505 if (NumRegs > 1) {

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

507 "not supported yet\n");

508 return false;

509 }

510

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

513

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

516 }

517 Inst.addImm(Flag);

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

519 return false;

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

521 break;

522 }

523

525

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

527 if (NumRegs > 0) {

529 Inst.addImm(Flag);

530

531 for (Register Reg : OpInfo.Regs) {

534 }

535 }

536 break;

537 }

538 }

539 }

540

541

546 }

547

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

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

554 }

555

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

557 Inst.addMetadata(SrcLoc);

558

559

561

562

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

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

566 "number of destination registers\n");

567 return false;

568 }

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

570 GISelAsmOperandInfo &OpInfo = OutputOperands[i];

571

572 if (OpInfo.Regs.empty())

573 continue;

574

575 switch (OpInfo.ConstraintType) {

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

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

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

581 return false;

582 }

583

584 Register SrcReg = OpInfo.Regs[0];

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

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

588

589

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

592 MIRBuilder.buildCopy(Tmp1Reg, SrcReg);

593

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

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

597 } else {

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

599 "mismatched register size\n");

600 return false;

601 }

602

603 break;

604 }

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

609 return false;

611 break;

613 break;

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

616 return false;

617 }

618 }

619

620 return true;

621}

622

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

626 if (Constraint.size() > 1)

627 return false;

628

629 char ConstraintLetter = Constraint[0];

630 switch (ConstraintLetter) {

631 default:

632 return false;

633 case 'i':

634 case 'n':

635 if (ConstantInt *CI = dyn_cast(Val)) {

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

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

638

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

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

642 return true;

643 }

644 return false;

645 }

646}

unsigned const MachineRegisterInfo * MRI

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Analysis containing CSE Info

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

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

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

Assign virtual/physical registers for the specified register operand.

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

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

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

This file declares the MachineIRBuilder class.

unsigned const TargetRegisterInfo * TRI

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

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 ...

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

Lower the specified operand into the Ops vector.

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".

constexpr TypeSize getSizeInBits() const

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

const TargetSubtargetInfo & getSubtarget() const

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

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.

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.

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.

MVT getSimpleValueType(const DataLayout &DL, Type *Ty, bool AllowUnknown=false) const

Return the MVT corresponding to this LLVM type. See getValueType.

virtual EVT getAsmOperandValueType(const DataLayout &DL, Type *Ty, bool AllowUnknown=false) const

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

virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const

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.

virtual AsmOperandInfoVector ParseConstraints(const DataLayout &DL, const TargetRegisterInfo *TRI, const CallBase &Call) const

Split up the constraint string from the inline assembly value into the specific constraints and their...

virtual ArrayRef< MCPhysReg > getRoundingControlRegisters() const

Returns a 0 terminated array of rounding control registers that can be attached into strict FP call.

unsigned getID() const

Return the register class ID number.

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

getRegisterInfo - If register information is available, return it.

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.

@ 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.

unsigned getImplRegState(bool B)

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

raw_ostream & dbgs()

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

MVT getSimpleVT() const

Return the SimpleValueType held in the specified simple EVT.

ConstraintPrefix Type

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

ConstraintCodeVector Codes

Code - The constraint code, either the register name (in braces) or the constraint letter/number.

bool isIndirect

isIndirect - True if this operand is an indirect operand.

bool isEarlyClobber

isEarlyClobber - "&": output operand writes result before inputs are all read.

This contains information for each constraint that we are lowering.

MVT ConstraintVT

The ValueType for the operand value.

TargetLowering::ConstraintType ConstraintType

Information about the constraint code, e.g.

std::string ConstraintCode

This contains the actual string for the code, like "m".

Value * CallOperandVal

If this is the result output operand or a clobber, this is null, otherwise it is the incoming operand...

unsigned getMatchedOperand() const

If this is an input matching constraint, this method returns the output operand it matches.

bool isMatchingInputConstraint() const

Return true of this is an input operand that is a matching constraint like "4".