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