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