LLVM 24.0.0git
InlineAsmLowering.cpp
Go to the documentation of this file.
1//===-- lib/CodeGen/GlobalISel/InlineAsmLowering.cpp ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file implements the lowering from LLVM IR inline asm to MIR INLINEASM
11///
12//===----------------------------------------------------------------------===//
13
21#include "llvm/IR/Module.h"
22
23#define DEBUG_TYPE "inline-asm-lowering"
24
25using namespace llvm;
26
27void InlineAsmLowering::anchor() {}
28
29/// Emit an inline asm error diagnostic and materialize undef values for the
30/// call results so that the rest of the function remains well-formed.
31static void emitInlineAsmError(MachineIRBuilder &MIRBuilder,
32 const CallBase &Call, const Twine &Message,
33 ArrayRef<Register> ResRegs) {
34 Call.getContext().diagnose(DiagnosticInfoInlineAsm(Call, Message));
35 for (Register Reg : ResRegs)
36 MIRBuilder.buildUndef(Reg);
37}
38
39namespace {
40
41/// GISelAsmOperandInfo - This contains information for each constraint that we
42/// are lowering.
43class GISelAsmOperandInfo : public TargetLowering::AsmOperandInfo {
44public:
45 /// Regs - If this is a register or register class operand, this
46 /// contains the set of assigned registers corresponding to the operand.
47 SmallVector<Register, 1> Regs;
48
49 /// The register class selected for this operand's constraint.
50 const TargetRegisterClass *RegClass = nullptr;
51
52 explicit GISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &Info)
53 : TargetLowering::AsmOperandInfo(Info) {}
54};
55
56using GISelAsmOperandInfoVector = SmallVector<GISelAsmOperandInfo, 16>;
57
58class ExtraFlags {
59 unsigned Flags = 0;
60
61public:
62 explicit ExtraFlags(const CallBase &CB) {
63 const InlineAsm *IA = cast<InlineAsm>(CB.getCalledOperand());
64 if (IA->hasSideEffects())
66 if (IA->isAlignStack())
68 if (IA->canThrow())
70 if (CB.isConvergent())
72 Flags |= IA->getDialect() * InlineAsm::Extra_AsmDialect;
73 }
74
75 void update(const TargetLowering::AsmOperandInfo &OpInfo) {
76 // Ideally, we would only check against memory constraints. However, the
77 // meaning of an Other constraint can be target-specific and we can't easily
78 // reason about it. Therefore, be conservative and set MayLoad/MayStore
79 // for Other constraints as well.
82 if (OpInfo.Type == InlineAsm::isInput)
84 else if (OpInfo.Type == InlineAsm::isOutput)
86 else if (OpInfo.Type == InlineAsm::isClobber)
88 }
89 }
90
91 unsigned get() const { return Flags; }
92};
93
94} // namespace
95
96/// Assign virtual/physical registers for the specified register operand.
98 MachineIRBuilder &MIRBuilder,
99 GISelAsmOperandInfo &OpInfo,
100 GISelAsmOperandInfo &RefOpInfo) {
101
104
105 // No work to do for memory operations.
106 if (OpInfo.ConstraintType == TargetLowering::C_Memory)
107 return;
108
109 // If this is a constraint for a single physreg, or a constraint for a
110 // register class, find it.
111 Register AssignedReg;
112 const TargetRegisterClass *RC;
113 std::tie(AssignedReg, RC) = TLI.getRegForInlineAsmConstraint(
114 &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT);
115 // RC is unset only on failure. Return immediately.
116 if (!RC)
117 return;
118 OpInfo.RegClass = RC;
119
120 // No need to allocate a matching input constraint since the constraint it's
121 // matching to has already been allocated.
122 if (OpInfo.isMatchingInputConstraint())
123 return;
124
125 // Initialize NumRegs.
126 unsigned NumRegs = 1;
127 if (OpInfo.ConstraintVT != MVT::Other)
128 NumRegs =
129 TLI.getNumRegisters(MF.getFunction().getContext(), OpInfo.ConstraintVT);
130
131 // If this is a constraint for a specific physical register, but the type of
132 // the operand requires more than one register to be passed, we allocate the
133 // required amount of physical registers, starting from the selected physical
134 // register.
135 // For this, first retrieve a register iterator for the given register class
138
139 // Advance the iterator to the assigned register (if set)
140 if (AssignedReg) {
141 for (; *I != AssignedReg; ++I)
142 assert(I != RC->end() && "AssignedReg should be a member of provided RC");
143 }
144
145 // Finally, assign the registers. If the AssignedReg isn't set, create virtual
146 // registers with the provided register class
147 for (; NumRegs; --NumRegs, ++I) {
148 assert(I != RC->end() && "Ran out of registers to allocate!");
149 Register R = AssignedReg ? Register(*I) : RegInfo.createVirtualRegister(RC);
150 OpInfo.Regs.push_back(R);
151 }
152}
153
156 assert(!OpInfo.Codes.empty() && "Must have at least one constraint");
157
158 // Single-letter constraints ('r') are very common.
159 if (OpInfo.Codes.size() == 1) {
160 OpInfo.ConstraintCode = OpInfo.Codes[0];
161 OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode);
162 } else {
163 TargetLowering::ConstraintGroup G = TLI->getConstraintPreferences(OpInfo);
164 if (G.empty())
165 return;
166 // FIXME: prefer immediate constraints if the target allows it
167 unsigned BestIdx = 0;
168 for (const unsigned E = G.size();
169 BestIdx < E && (G[BestIdx].second == TargetLowering::C_Other ||
170 G[BestIdx].second == TargetLowering::C_Immediate);
171 ++BestIdx)
172 ;
173 OpInfo.ConstraintCode = G[BestIdx].first;
174 OpInfo.ConstraintType = G[BestIdx].second;
175 }
176
177 // 'X' matches anything.
178 if (OpInfo.ConstraintCode == "X" && OpInfo.CallOperandVal) {
179 // Labels and constants are handled elsewhere ('X' is the only thing
180 // that matches labels). For Functions, the type here is the type of
181 // the result, which is not what we want to look at; leave them alone.
182 Value *Val = OpInfo.CallOperandVal;
183 if (isa<BasicBlock>(Val) || isa<ConstantInt>(Val) || isa<Function>(Val))
184 return;
185
186 // Otherwise, try to resolve it to something we know about by looking at
187 // the actual operand type.
188 if (const char *Repl = TLI->LowerXConstraint(OpInfo.ConstraintVT)) {
189 OpInfo.ConstraintCode = Repl;
190 OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode);
191 }
192 }
193}
194
195static unsigned getNumOpRegs(const MachineInstr &I, unsigned OpIdx) {
196 const InlineAsm::Flag F(I.getOperand(OpIdx).getImm());
197 return F.getNumOperandRegisters();
198}
199
201 MachineIRBuilder &MIRBuilder) {
202 const TargetRegisterInfo *TRI =
203 MIRBuilder.getMF().getSubtarget().getRegisterInfo();
204 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
205
206 auto SrcTy = MRI->getType(Src);
207 if (!SrcTy.isValid()) {
208 LLVM_DEBUG(dbgs() << "Source type for copy is not valid\n");
209 return false;
210 }
211 unsigned SrcSize = TRI->getRegSizeInBits(Src, *MRI);
212 unsigned DstSize = TRI->getRegSizeInBits(Dst, *MRI);
213
214 if (DstSize < SrcSize) {
215 LLVM_DEBUG(dbgs() << "Input can't fit in destination reg class\n");
216 return false;
217 }
218
219 // Attempt to anyext small scalar sources.
220 if (DstSize > SrcSize) {
221 if (!SrcTy.isScalar()) {
222 LLVM_DEBUG(dbgs() << "Can't extend non-scalar input to size of"
223 "destination register class\n");
224 return false;
225 }
226 Src = MIRBuilder.buildAnyExt(LLT::integer(DstSize), Src).getReg(0);
227 }
228
229 MIRBuilder.buildCopy(Dst, Src);
230 return true;
231}
232
234 MachineIRBuilder &MIRBuilder, const CallBase &Call,
235 std::function<ArrayRef<Register>(const Value &Val)> GetOrCreateVRegs)
236 const {
237 const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
238
239 /// ConstraintOperands - Information about all of the constraints.
240 GISelAsmOperandInfoVector ConstraintOperands;
241
242 MachineFunction &MF = MIRBuilder.getMF();
243 const Function &F = MF.getFunction();
244 const DataLayout &DL = F.getDataLayout();
246
247 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
248
249 TargetLowering::AsmOperandInfoVector TargetConstraints =
250 TLI->ParseConstraints(DL, TRI, Call);
251
252 ExtraFlags ExtraInfo(Call);
253 unsigned ArgNo = 0; // ArgNo - The argument of the CallInst.
254 unsigned ResNo = 0; // ResNo - The result number of the next output.
255 for (auto &T : TargetConstraints) {
256 ConstraintOperands.push_back(GISelAsmOperandInfo(T));
257 GISelAsmOperandInfo &OpInfo = ConstraintOperands.back();
258
259 // Compute the value type for each operand.
260 if (OpInfo.hasArg()) {
261 OpInfo.CallOperandVal = Call.getArgOperand(ArgNo);
262
263 if (isa<BasicBlock>(OpInfo.CallOperandVal)) {
264 LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n");
265 return false;
266 }
267
268 Type *OpTy = OpInfo.CallOperandVal->getType();
269
270 // If this is an indirect operand, the operand is a pointer to the
271 // accessed type.
272 if (OpInfo.isIndirect) {
273 OpTy = Call.getParamElementType(ArgNo);
274 assert(OpTy && "Indirect operand must have elementtype attribute");
275 }
276
277 // FIXME: Support aggregate input operands
278 if (!OpTy->isSingleValueType()) {
280 dbgs() << "Aggregate input operands are not supported yet\n");
281 return false;
282 }
283
284 OpInfo.ConstraintVT =
285 TLI->getAsmOperandValueType(DL, OpTy, true).getSimpleVT();
286 ++ArgNo;
287 } else if (OpInfo.Type == InlineAsm::isOutput && !OpInfo.isIndirect) {
288 assert(!Call.getType()->isVoidTy() && "Bad inline asm!");
289 if (StructType *STy = dyn_cast<StructType>(Call.getType())) {
290 OpInfo.ConstraintVT =
291 TLI->getSimpleValueType(DL, STy->getElementType(ResNo));
292 } else {
293 assert(ResNo == 0 && "Asm only has one result!");
294 OpInfo.ConstraintVT =
295 TLI->getAsmOperandValueType(DL, Call.getType()).getSimpleVT();
296 }
297 ++ResNo;
298 } else {
299 assert(OpInfo.Type != InlineAsm::isLabel &&
300 "GlobalISel currently doesn't support callbr");
301 OpInfo.ConstraintVT = MVT::Other;
302 }
303
304 if (OpInfo.ConstraintVT == MVT::i64x8)
305 return false;
306
307 // Compute the constraint code and ConstraintType to use.
308 computeConstraintToUse(TLI, OpInfo);
309
310 // The selected constraint type might expose new sideeffects
311 ExtraInfo.update(OpInfo);
312 }
313
314 // At this point, all operand types are decided.
315 // Create the MachineInstr, but don't insert it yet since input
316 // operands still need to insert instructions before this one
317 auto Inst = MIRBuilder.buildInstrNoInsert(TargetOpcode::INLINEASM)
318 .addExternalSymbol(IA->getAsmString().data())
319 .addImm(ExtraInfo.get());
320
321 // Starting from this operand: flag followed by register(s) will be added as
322 // operands to Inst for each constraint. Used for matching input constraints.
323 unsigned StartIdx = Inst->getNumOperands();
324
325 // Collects the output operands for later processing
326 GISelAsmOperandInfoVector OutputOperands;
327
328 for (auto &OpInfo : ConstraintOperands) {
329 GISelAsmOperandInfo &RefOpInfo =
330 OpInfo.isMatchingInputConstraint()
331 ? ConstraintOperands[OpInfo.getMatchedOperand()]
332 : OpInfo;
333
334 // Assign registers for register operands
335 getRegistersForValue(MF, MIRBuilder, OpInfo, RefOpInfo);
336
337 switch (OpInfo.Type) {
339 if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
340 const InlineAsm::ConstraintCode ConstraintID =
341 TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);
343 "Failed to convert memory constraint code to constraint id.");
344
345 // Add information to the INLINEASM instruction to know about this
346 // output.
348 Flag.setMemConstraint(ConstraintID);
349 Inst.addImm(Flag);
350 ArrayRef<Register> SourceRegs =
351 GetOrCreateVRegs(*OpInfo.CallOperandVal);
352 assert(
353 SourceRegs.size() == 1 &&
354 "Expected the memory output to fit into a single virtual register");
355 Inst.addReg(SourceRegs[0]);
356 } else {
357 // Otherwise, this outputs to a register (directly for C_Register /
358 // C_RegisterClass/C_Other.
359 assert(OpInfo.ConstraintType == TargetLowering::C_Register ||
360 OpInfo.ConstraintType == TargetLowering::C_RegisterClass ||
361 OpInfo.ConstraintType == TargetLowering::C_Other);
362
363 // Find a register that we can use.
364 if (OpInfo.Regs.empty()) {
365 emitInlineAsmError(MIRBuilder, Call,
366 "could not allocate output register for "
367 "constraint '" +
368 Twine(OpInfo.ConstraintCode) + "'",
369 GetOrCreateVRegs(Call));
370 return true;
371 }
372
373 // Add information to the INLINEASM instruction to know that this
374 // register is set.
375 InlineAsm::Flag Flag(OpInfo.isEarlyClobber
378 OpInfo.Regs.size());
379 if (OpInfo.Regs.front().isVirtual()) {
380 // Put the register class of the virtual registers in the flag word.
381 // That way, later passes can recompute register class constraints for
382 // inline assembly as well as normal instructions. Don't do this for
383 // tied operands that can use the regclass information from the def.
384 const TargetRegisterClass *RC = MRI->getRegClass(OpInfo.Regs.front());
385 Flag.setRegClass(RC->getID());
386 }
387
388 Inst.addImm(Flag);
389
390 for (Register Reg : OpInfo.Regs) {
391 Inst.addReg(Reg, RegState::Define |
392 getImplRegState(Reg.isPhysical()) |
393 getEarlyClobberRegState(OpInfo.isEarlyClobber));
394 }
395
396 // Remember this output operand for later processing
397 OutputOperands.push_back(OpInfo);
398 }
399
400 break;
402 case InlineAsm::isLabel: {
403 if (OpInfo.isMatchingInputConstraint()) {
404 unsigned DefIdx = OpInfo.getMatchedOperand();
405 // Find operand with register def that corresponds to DefIdx.
406 unsigned InstFlagIdx = StartIdx;
407 for (unsigned i = 0; i < DefIdx; ++i)
408 InstFlagIdx += getNumOpRegs(*Inst, InstFlagIdx) + 1;
409 if (getNumOpRegs(*Inst, InstFlagIdx) != 1) {
410 LLVM_DEBUG(dbgs() << "Matching input constraints with multiple "
411 "registers are not supported yet\n");
412 return false;
413 }
414
415 const InlineAsm::Flag MatchedOperandFlag(Inst->getOperand(InstFlagIdx).getImm());
416 if (MatchedOperandFlag.isMemKind()) {
417 LLVM_DEBUG(dbgs() << "Matching input constraint to mem operand not "
418 "supported. This should be target specific.\n");
419 return false;
420 }
421 if (!MatchedOperandFlag.isRegDefKind() && !MatchedOperandFlag.isRegDefEarlyClobberKind()) {
422 LLVM_DEBUG(dbgs() << "Unknown matching constraint\n");
423 return false;
424 }
425
426 // We want to tie input to register in next operand.
427 unsigned DefRegIdx = InstFlagIdx + 1;
428 Register Def = Inst->getOperand(DefRegIdx).getReg();
429
430 ArrayRef<Register> SrcRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);
431 assert(SrcRegs.size() == 1 && "Single register is expected here");
432
433 // We need the tied input to live in the same register class as the def.
434 //
435 // - if Def is a vreg, we can just use its regclass.
436 // - if Def is a physreg, create a vreg in the regclass selected for its
437 // constraint.
438 //
439 // Otherwise RegBankSelect may leave it in the wrong bank (e.g. GPR even
440 // though it's tied to an FP physreg).
441 const TargetRegisterClass *RC =
442 Def.isVirtual() ? MRI->getRegClass(Def) : OpInfo.RegClass;
443 assert(RC && "Expected a register class for matching constraint");
444
445 // Materialize `In` in a new vreg that has a register class that matches
446 // the register class of `Def`.
447 Register In = MRI->createVirtualRegister(RC);
448 if (!buildAnyextOrCopy(In, SrcRegs[0], MIRBuilder))
449 return false;
450
451 // Add Flag and input register operand (In) to Inst. Tie In to Def.
453 UseFlag.setMatchingOp(DefIdx);
454 Inst.addImm(UseFlag);
455 Inst.addReg(In);
456 Inst->tieOperands(DefRegIdx, Inst->getNumOperands() - 1);
457 break;
458 }
459
460 if (OpInfo.ConstraintType == TargetLowering::C_Other &&
461 OpInfo.isIndirect) {
462 LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "
463 "not supported yet\n");
464 return false;
465 }
466
467 if (OpInfo.ConstraintType == TargetLowering::C_Immediate ||
468 OpInfo.ConstraintType == TargetLowering::C_Other) {
469
470 std::vector<MachineOperand> Ops;
471 if (!lowerAsmOperandForConstraint(OpInfo.CallOperandVal,
472 OpInfo.ConstraintCode, Ops,
473 MIRBuilder)) {
474 LLVM_DEBUG(dbgs() << "Don't support constraint: "
475 << OpInfo.ConstraintCode << " yet\n");
476 return false;
477 }
478
479 assert(Ops.size() > 0 &&
480 "Expected constraint to be lowered to at least one operand");
481
482 // Add information to the INLINEASM node to know about this input.
483 const unsigned OpFlags =
485 Inst.addImm(OpFlags);
486 Inst.add(Ops);
487 break;
488 }
489
490 if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
491 const InlineAsm::ConstraintCode ConstraintID =
492 TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);
494 OpFlags.setMemConstraint(ConstraintID);
495 Inst.addImm(OpFlags);
496
497 if (OpInfo.isIndirect) {
498 // already indirect
499 ArrayRef<Register> SourceRegs =
500 GetOrCreateVRegs(*OpInfo.CallOperandVal);
501 if (SourceRegs.size() != 1) {
502 LLVM_DEBUG(dbgs() << "Expected the memory input to fit into a "
503 "single virtual register "
504 "for constraint '"
505 << OpInfo.ConstraintCode << "'\n");
506 return false;
507 }
508 Inst.addReg(SourceRegs[0]);
509 break;
510 }
511
512 // Needs to be made indirect. Store the value on the stack and use
513 // a pointer to it.
514 Value *OpVal = OpInfo.CallOperandVal;
515 TypeSize Bytes = DL.getTypeStoreSize(OpVal->getType());
516 Align Alignment = DL.getPrefTypeAlign(OpVal->getType());
517 int FrameIdx =
518 MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
519
520 unsigned AddrSpace = DL.getAllocaAddrSpace();
521 LLT FramePtrTy =
522 LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
523 auto Ptr = MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx).getReg(0);
524 ArrayRef<Register> SourceRegs =
525 GetOrCreateVRegs(*OpInfo.CallOperandVal);
526 if (SourceRegs.size() != 1) {
527 LLVM_DEBUG(dbgs() << "Expected the memory input to fit into a single "
528 "virtual register "
529 "for constraint '"
530 << OpInfo.ConstraintCode << "'\n");
531 return false;
532 }
533 MIRBuilder.buildStore(SourceRegs[0], Ptr,
535 Alignment);
536 Inst.addReg(Ptr);
537 break;
538 }
539
540 assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass ||
541 OpInfo.ConstraintType == TargetLowering::C_Register) &&
542 "Unknown constraint type!");
543
544 if (OpInfo.isIndirect) {
545 LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "
546 "for constraint '"
547 << OpInfo.ConstraintCode << "'\n");
548 return false;
549 }
550
551 // Copy the input into the appropriate registers.
552 if (OpInfo.Regs.empty()) {
553 emitInlineAsmError(MIRBuilder, Call,
554 "could not allocate input reg for constraint '" +
555 Twine(OpInfo.ConstraintCode) + "'",
556 GetOrCreateVRegs(Call));
557 return true;
558 }
559
560 unsigned NumRegs = OpInfo.Regs.size();
561 ArrayRef<Register> SourceRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);
562 if (NumRegs != 1 || SourceRegs.size() != 1) {
563 LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are "
564 "not supported yet\n");
565 return false;
566 }
567
569 if (OpInfo.Regs.front().isVirtual()) {
570 // Put the register class of the virtual registers in the flag word.
571 const TargetRegisterClass *RC = MRI->getRegClass(OpInfo.Regs.front());
572 Flag.setRegClass(RC->getID());
573 }
574 Inst.addImm(Flag);
575 if (!buildAnyextOrCopy(OpInfo.Regs[0], SourceRegs[0], MIRBuilder))
576 return false;
577 Inst.addReg(OpInfo.Regs[0]);
578 break;
579 }
580
582
583 const unsigned NumRegs = OpInfo.Regs.size();
584 if (NumRegs > 0) {
585 unsigned Flag = InlineAsm::Flag(InlineAsm::Kind::Clobber, NumRegs);
586 Inst.addImm(Flag);
587
588 for (Register Reg : OpInfo.Regs) {
589 Inst.addReg(Reg, RegState::Define | RegState::EarlyClobber |
591 getImplRegState(Reg.isPhysical()));
592 }
593 }
594 break;
595 }
596 }
597 }
598
599 if (auto Bundle = Call.getOperandBundle(LLVMContext::OB_convergencectrl)) {
600 auto *Token = Bundle->Inputs[0].get();
601 ArrayRef<Register> SourceRegs = GetOrCreateVRegs(*Token);
602 assert(SourceRegs.size() == 1 &&
603 "Expected the control token to fit into a single virtual register");
604 Inst.addUse(SourceRegs[0], RegState::Implicit);
605 }
606
607 if (const MDNode *SrcLoc = Call.getMetadata("srcloc"))
608 Inst.addMetadata(SrcLoc);
609
610 // Add rounding control registers as implicit def for inline asm.
611 if (MF.getFunction().hasFnAttribute(Attribute::StrictFP)) {
612 ArrayRef<MCPhysReg> RCRegs = TLI->getRoundingControlRegisters();
613 for (MCPhysReg Reg : RCRegs)
614 Inst.addReg(Reg, RegState::ImplicitDefine);
615 }
616
617 // All inputs are handled, insert the instruction now
618 MIRBuilder.insertInstr(Inst);
619
620 // Finally, copy the output operands into the output registers
621 ArrayRef<Register> ResRegs = GetOrCreateVRegs(Call);
622 if (ResRegs.size() != OutputOperands.size()) {
623 LLVM_DEBUG(dbgs() << "Expected the number of output registers to match the "
624 "number of destination registers\n");
625 return false;
626 }
627 for (unsigned int i = 0, e = ResRegs.size(); i < e; i++) {
628 GISelAsmOperandInfo &OpInfo = OutputOperands[i];
629
630 if (OpInfo.Regs.empty())
631 continue;
632
633 switch (OpInfo.ConstraintType) {
636 if (OpInfo.Regs.size() > 1) {
637 LLVM_DEBUG(dbgs() << "Output operands with multiple defining "
638 "registers are not supported yet\n");
639 return false;
640 }
641
642 Register SrcReg = OpInfo.Regs[0];
643 unsigned SrcSize = TRI->getRegSizeInBits(SrcReg, *MRI);
644 LLT ResTy = MRI->getType(ResRegs[i]);
645 if (ResTy.isScalar() && ResTy.getSizeInBits() < SrcSize) {
646 // First copy the non-typed virtual register into a generic virtual
647 // register
648 auto Copy = MIRBuilder.buildCopy(LLT::integer(SrcSize), SrcReg);
649 // Need to truncate the result of the register
650 MIRBuilder.buildTrunc(ResRegs[i], Copy);
651 } else if (ResTy.getSizeInBits() == SrcSize) {
652 MIRBuilder.buildCopy(ResRegs[i], SrcReg);
653 } else {
654 LLVM_DEBUG(dbgs() << "Unhandled output operand with "
655 "mismatched register size\n");
656 return false;
657 }
658
659 break;
660 }
664 dbgs() << "Cannot lower target specific output constraints yet\n");
665 return false;
667 break; // Already handled.
669 break; // Silence warning.
671 LLVM_DEBUG(dbgs() << "Unexpected unknown constraint\n");
672 return false;
673 }
674 }
675
676 return true;
677}
678
680 Value *Val, StringRef Constraint, std::vector<MachineOperand> &Ops,
681 MachineIRBuilder &MIRBuilder) const {
682 if (Constraint.size() > 1)
683 return false;
684
685 char ConstraintLetter = Constraint[0];
686 switch (ConstraintLetter) {
687 default:
688 return false;
689 case 's': // Integer immediate not known at compile time
690 if (const auto *GV = dyn_cast<GlobalValue>(Val)) {
691 Ops.push_back(MachineOperand::CreateGA(GV, /*Offset=*/0));
692 return true;
693 }
694 return false;
695 case 'i': // Simple Integer or Relocatable Constant
696 if (const auto *GV = dyn_cast<GlobalValue>(Val)) {
697 Ops.push_back(MachineOperand::CreateGA(GV, /*Offset=*/0));
698 return true;
699 }
700 [[fallthrough]];
701 case 'n': // immediate integer with a known value.
702 if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
703 assert(CI->getBitWidth() <= 64 &&
704 "expected immediate to fit into 64-bits");
705 // Boolean constants should be zero-extended, others are sign-extended
706 bool IsBool = CI->getBitWidth() == 1;
707 int64_t ExtVal = IsBool ? CI->getZExtValue() : CI->getSExtValue();
708 Ops.push_back(MachineOperand::CreateImm(ExtVal));
709 return true;
710 }
711 return false;
712 }
713}
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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 emitInlineAsmError(MachineIRBuilder &MIRBuilder, const CallBase &Call, const Twine &Message, ArrayRef< Register > ResRegs)
Emit an inline asm error diagnostic and materialize undef values for the call results so that the res...
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.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
This file declares the MachineIRBuilder class.
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
MachineRegisterInfo & MRI
#define LLVM_DEBUG(...)
Definition Debug.h:119
This file describes how to lower LLVM code to machine code.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
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.
Definition Constants.h:87
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
Diagnostic information for inline asm reporting.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
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.
bool isMemKind() const
Definition InlineAsm.h:338
void setMatchingOp(unsigned OperandNo)
setMatchingOp - Augment an existing flag with information indicating that this input operand is tied ...
Definition InlineAsm.h:395
void setMemConstraint(ConstraintCode C)
setMemConstraint - Augment an existing flag with the constraint code for a memory constraint.
Definition InlineAsm.h:414
bool isRegDefEarlyClobberKind() const
Definition InlineAsm.h:333
bool isRegDefKind() const
Definition InlineAsm.h:332
constexpr bool isScalar() const
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.
static LLT integer(unsigned SizeInBits)
unsigned getID() const
getID() - Return the register class ID number.
const MCPhysReg * iterator
iterator begin() const
begin/end - Return all of the registers in this class.
iterator end() const
Metadata node.
Definition Metadata.h:1081
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 buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
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 <empty> = Opcode <empty>.
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 & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
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)
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
Class to represent struct types.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
SmallVector< ConstraintPair > ConstraintGroup
std::vector< AsmOperandInfo > AsmOperandInfoVector
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
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
CallInst * Call
This is an optimization pass for GlobalISel generic memory operations.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Dead
Unused definition.
@ EarlyClobber
Register definition happens before uses.
@ Define
Register definition.
constexpr RegState getImplRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
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.
Definition Debug.cpp:209
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
constexpr RegState getEarlyClobberRegState(bool B)
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
ConstraintPrefix Type
Type - The basic type of the constraint: input/output/clobber/label.
Definition InlineAsm.h:128
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.