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
14 #include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h"
15 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
16 #include "llvm/CodeGen/MachineOperand.h"
17 #include "llvm/CodeGen/MachineRegisterInfo.h"
18 #include "llvm/CodeGen/TargetLowering.h"
19 #include "llvm/IR/Module.h"
20
21 #define DEBUG_TYPE "inline-asm-lowering"
22
23 using namespace llvm;
24
anchor()25 void InlineAsmLowering::anchor() {}
26
27 namespace {
28
29 /// GISelAsmOperandInfo - This contains information for each constraint that we
30 /// are lowering.
31 class GISelAsmOperandInfo : public TargetLowering::AsmOperandInfo {
32 public:
33 /// Regs - If this is a register or register class operand, this
34 /// contains the set of assigned registers corresponding to the operand.
35 SmallVector<Register, 1> Regs;
36
GISelAsmOperandInfo(const TargetLowering::AsmOperandInfo & Info)37 explicit GISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &Info)
38 : TargetLowering::AsmOperandInfo(Info) {}
39 };
40
41 using GISelAsmOperandInfoVector = SmallVector<GISelAsmOperandInfo, 16>;
42
43 class ExtraFlags {
44 unsigned Flags = 0;
45
46 public:
ExtraFlags(const CallBase & CB)47 explicit ExtraFlags(const CallBase &CB) {
48 const InlineAsm *IA = cast<InlineAsm>(CB.getCalledOperand());
49 if (IA->hasSideEffects())
50 Flags |= InlineAsm::Extra_HasSideEffects;
51 if (IA->isAlignStack())
52 Flags |= InlineAsm::Extra_IsAlignStack;
53 if (CB.isConvergent())
54 Flags |= InlineAsm::Extra_IsConvergent;
55 Flags |= IA->getDialect() * InlineAsm::Extra_AsmDialect;
56 }
57
update(const TargetLowering::AsmOperandInfo & OpInfo)58 void update(const TargetLowering::AsmOperandInfo &OpInfo) {
59 // Ideally, we would only check against memory constraints. However, the
60 // meaning of an Other constraint can be target-specific and we can't easily
61 // reason about it. Therefore, be conservative and set MayLoad/MayStore
62 // for Other constraints as well.
63 if (OpInfo.ConstraintType == TargetLowering::C_Memory ||
64 OpInfo.ConstraintType == TargetLowering::C_Other) {
65 if (OpInfo.Type == InlineAsm::isInput)
66 Flags |= InlineAsm::Extra_MayLoad;
67 else if (OpInfo.Type == InlineAsm::isOutput)
68 Flags |= InlineAsm::Extra_MayStore;
69 else if (OpInfo.Type == InlineAsm::isClobber)
70 Flags |= (InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore);
71 }
72 }
73
get() const74 unsigned get() const { return Flags; }
75 };
76
77 } // namespace
78
79 /// Assign virtual/physical registers for the specified register operand.
getRegistersForValue(MachineFunction & MF,MachineIRBuilder & MIRBuilder,GISelAsmOperandInfo & OpInfo,GISelAsmOperandInfo & RefOpInfo)80 static void getRegistersForValue(MachineFunction &MF,
81 MachineIRBuilder &MIRBuilder,
82 GISelAsmOperandInfo &OpInfo,
83 GISelAsmOperandInfo &RefOpInfo) {
84
85 const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
86 const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
87
88 // No work to do for memory operations.
89 if (OpInfo.ConstraintType == TargetLowering::C_Memory)
90 return;
91
92 // If this is a constraint for a single physreg, or a constraint for a
93 // register class, find it.
94 Register AssignedReg;
95 const TargetRegisterClass *RC;
96 std::tie(AssignedReg, RC) = TLI.getRegForInlineAsmConstraint(
97 &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT);
98 // RC is unset only on failure. Return immediately.
99 if (!RC)
100 return;
101
102 // No need to allocate a matching input constraint since the constraint it's
103 // matching to has already been allocated.
104 if (OpInfo.isMatchingInputConstraint())
105 return;
106
107 // Initialize NumRegs.
108 unsigned NumRegs = 1;
109 if (OpInfo.ConstraintVT != MVT::Other)
110 NumRegs =
111 TLI.getNumRegisters(MF.getFunction().getContext(), OpInfo.ConstraintVT);
112
113 // If this is a constraint for a specific physical register, but the type of
114 // the operand requires more than one register to be passed, we allocate the
115 // required amount of physical registers, starting from the selected physical
116 // register.
117 // For this, first retrieve a register iterator for the given register class
118 TargetRegisterClass::iterator I = RC->begin();
119 MachineRegisterInfo &RegInfo = MF.getRegInfo();
120
121 // Advance the iterator to the assigned register (if set)
122 if (AssignedReg) {
123 for (; *I != AssignedReg; ++I)
124 assert(I != RC->end() && "AssignedReg should be a member of provided RC");
125 }
126
127 // Finally, assign the registers. If the AssignedReg isn't set, create virtual
128 // registers with the provided register class
129 for (; NumRegs; --NumRegs, ++I) {
130 assert(I != RC->end() && "Ran out of registers to allocate!");
131 Register R = AssignedReg ? Register(*I) : RegInfo.createVirtualRegister(RC);
132 OpInfo.Regs.push_back(R);
133 }
134 }
135
computeConstraintToUse(const TargetLowering * TLI,TargetLowering::AsmOperandInfo & OpInfo)136 static void computeConstraintToUse(const TargetLowering *TLI,
137 TargetLowering::AsmOperandInfo &OpInfo) {
138 assert(!OpInfo.Codes.empty() && "Must have at least one constraint");
139
140 // Single-letter constraints ('r') are very common.
141 if (OpInfo.Codes.size() == 1) {
142 OpInfo.ConstraintCode = OpInfo.Codes[0];
143 OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode);
144 } else {
145 TargetLowering::ConstraintGroup G = TLI->getConstraintPreferences(OpInfo);
146 if (G.empty())
147 return;
148 // FIXME: prefer immediate constraints if the target allows it
149 unsigned BestIdx = 0;
150 for (const unsigned E = G.size();
151 BestIdx < E && (G[BestIdx].second == TargetLowering::C_Other ||
152 G[BestIdx].second == TargetLowering::C_Immediate);
153 ++BestIdx)
154 ;
155 OpInfo.ConstraintCode = G[BestIdx].first;
156 OpInfo.ConstraintType = G[BestIdx].second;
157 }
158
159 // 'X' matches anything.
160 if (OpInfo.ConstraintCode == "X" && OpInfo.CallOperandVal) {
161 // Labels and constants are handled elsewhere ('X' is the only thing
162 // that matches labels). For Functions, the type here is the type of
163 // the result, which is not what we want to look at; leave them alone.
164 Value *Val = OpInfo.CallOperandVal;
165 if (isa<BasicBlock>(Val) || isa<ConstantInt>(Val) || isa<Function>(Val))
166 return;
167
168 // Otherwise, try to resolve it to something we know about by looking at
169 // the actual operand type.
170 if (const char *Repl = TLI->LowerXConstraint(OpInfo.ConstraintVT)) {
171 OpInfo.ConstraintCode = Repl;
172 OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode);
173 }
174 }
175 }
176
getNumOpRegs(const MachineInstr & I,unsigned OpIdx)177 static unsigned getNumOpRegs(const MachineInstr &I, unsigned OpIdx) {
178 const InlineAsm::Flag F(I.getOperand(OpIdx).getImm());
179 return F.getNumOperandRegisters();
180 }
181
buildAnyextOrCopy(Register Dst,Register Src,MachineIRBuilder & MIRBuilder)182 static bool buildAnyextOrCopy(Register Dst, Register Src,
183 MachineIRBuilder &MIRBuilder) {
184 const TargetRegisterInfo *TRI =
185 MIRBuilder.getMF().getSubtarget().getRegisterInfo();
186 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
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 // Attempt to anyext small scalar sources.
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 }
208 Src = MIRBuilder.buildAnyExt(LLT::scalar(DstSize), Src).getReg(0);
209 }
210
211 MIRBuilder.buildCopy(Dst, Src);
212 return true;
213 }
214
lowerInlineAsm(MachineIRBuilder & MIRBuilder,const CallBase & Call,std::function<ArrayRef<Register> (const Value & Val)> GetOrCreateVRegs) const215 bool InlineAsmLowering::lowerInlineAsm(
216 MachineIRBuilder &MIRBuilder, const CallBase &Call,
217 std::function<ArrayRef<Register>(const Value &Val)> GetOrCreateVRegs)
218 const {
219 const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
220
221 /// ConstraintOperands - Information about all of the constraints.
222 GISelAsmOperandInfoVector ConstraintOperands;
223
224 MachineFunction &MF = MIRBuilder.getMF();
225 const Function &F = MF.getFunction();
226 const DataLayout &DL = F.getDataLayout();
227 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
228
229 MachineRegisterInfo *MRI = MIRBuilder.getMRI();
230
231 TargetLowering::AsmOperandInfoVector TargetConstraints =
232 TLI->ParseConstraints(DL, TRI, Call);
233
234 ExtraFlags ExtraInfo(Call);
235 unsigned ArgNo = 0; // ArgNo - The argument of the CallInst.
236 unsigned ResNo = 0; // ResNo - The result number of the next output.
237 for (auto &T : TargetConstraints) {
238 ConstraintOperands.push_back(GISelAsmOperandInfo(T));
239 GISelAsmOperandInfo &OpInfo = ConstraintOperands.back();
240
241 // Compute the value type for each operand.
242 if (OpInfo.hasArg()) {
243 OpInfo.CallOperandVal = const_cast<Value *>(Call.getArgOperand(ArgNo));
244
245 if (isa<BasicBlock>(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 // If this is an indirect operand, the operand is a pointer to the
253 // accessed type.
254 if (OpInfo.isIndirect) {
255 OpTy = Call.getParamElementType(ArgNo);
256 assert(OpTy && "Indirect operand must have elementtype attribute");
257 }
258
259 // FIXME: Support aggregate input operands
260 if (!OpTy->isSingleValueType()) {
261 LLVM_DEBUG(
262 dbgs() << "Aggregate input operands are not supported yet\n");
263 return false;
264 }
265
266 OpInfo.ConstraintVT =
267 TLI->getAsmOperandValueType(DL, OpTy, true).getSimpleVT();
268 ++ArgNo;
269 } else if (OpInfo.Type == InlineAsm::isOutput && !OpInfo.isIndirect) {
270 assert(!Call.getType()->isVoidTy() && "Bad inline asm!");
271 if (StructType *STy = dyn_cast<StructType>(Call.getType())) {
272 OpInfo.ConstraintVT =
273 TLI->getSimpleValueType(DL, STy->getElementType(ResNo));
274 } else {
275 assert(ResNo == 0 && "Asm only has one result!");
276 OpInfo.ConstraintVT =
277 TLI->getAsmOperandValueType(DL, Call.getType()).getSimpleVT();
278 }
279 ++ResNo;
280 } else {
281 assert(OpInfo.Type != InlineAsm::isLabel &&
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 // Compute the constraint code and ConstraintType to use.
290 computeConstraintToUse(TLI, OpInfo);
291
292 // The selected constraint type might expose new sideeffects
293 ExtraInfo.update(OpInfo);
294 }
295
296 // At this point, all operand types are decided.
297 // Create the MachineInstr, but don't insert it yet since input
298 // operands still need to insert instructions before this one
299 auto Inst = MIRBuilder.buildInstrNoInsert(TargetOpcode::INLINEASM)
300 .addExternalSymbol(IA->getAsmString().c_str())
301 .addImm(ExtraInfo.get());
302
303 // Starting from this operand: flag followed by register(s) will be added as
304 // operands to Inst for each constraint. Used for matching input constraints.
305 unsigned StartIdx = Inst->getNumOperands();
306
307 // Collects the output operands for later processing
308 GISelAsmOperandInfoVector OutputOperands;
309
310 for (auto &OpInfo : ConstraintOperands) {
311 GISelAsmOperandInfo &RefOpInfo =
312 OpInfo.isMatchingInputConstraint()
313 ? ConstraintOperands[OpInfo.getMatchedOperand()]
314 : OpInfo;
315
316 // Assign registers for register operands
317 getRegistersForValue(MF, MIRBuilder, OpInfo, RefOpInfo);
318
319 switch (OpInfo.Type) {
320 case InlineAsm::isOutput:
321 if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
322 const InlineAsm::ConstraintCode ConstraintID =
323 TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);
324 assert(ConstraintID != InlineAsm::ConstraintCode::Unknown &&
325 "Failed to convert memory constraint code to constraint id.");
326
327 // Add information to the INLINEASM instruction to know about this
328 // output.
329 InlineAsm::Flag Flag(InlineAsm::Kind::Mem, 1);
330 Flag.setMemConstraint(ConstraintID);
331 Inst.addImm(Flag);
332 ArrayRef<Register> SourceRegs =
333 GetOrCreateVRegs(*OpInfo.CallOperandVal);
334 assert(
335 SourceRegs.size() == 1 &&
336 "Expected the memory output to fit into a single virtual register");
337 Inst.addReg(SourceRegs[0]);
338 } else {
339 // Otherwise, this outputs to a register (directly for C_Register /
340 // C_RegisterClass/C_Other.
341 assert(OpInfo.ConstraintType == TargetLowering::C_Register ||
342 OpInfo.ConstraintType == TargetLowering::C_RegisterClass ||
343 OpInfo.ConstraintType == TargetLowering::C_Other);
344
345 // Find a register that we can use.
346 if (OpInfo.Regs.empty()) {
347 LLVM_DEBUG(dbgs()
348 << "Couldn't allocate output register for constraint\n");
349 return false;
350 }
351
352 // Add information to the INLINEASM instruction to know that this
353 // register is set.
354 InlineAsm::Flag Flag(OpInfo.isEarlyClobber
355 ? InlineAsm::Kind::RegDefEarlyClobber
356 : InlineAsm::Kind::RegDef,
357 OpInfo.Regs.size());
358 if (OpInfo.Regs.front().isVirtual()) {
359 // Put the register class of the virtual registers in the flag word.
360 // That way, later passes can recompute register class constraints for
361 // inline assembly as well as normal instructions. Don't do this for
362 // tied operands that can use the regclass information from the def.
363 const TargetRegisterClass *RC = MRI->getRegClass(OpInfo.Regs.front());
364 Flag.setRegClass(RC->getID());
365 }
366
367 Inst.addImm(Flag);
368
369 for (Register Reg : OpInfo.Regs) {
370 Inst.addReg(Reg,
371 RegState::Define | getImplRegState(Reg.isPhysical()) |
372 (OpInfo.isEarlyClobber ? RegState::EarlyClobber : 0));
373 }
374
375 // Remember this output operand for later processing
376 OutputOperands.push_back(OpInfo);
377 }
378
379 break;
380 case InlineAsm::isInput:
381 case InlineAsm::isLabel: {
382 if (OpInfo.isMatchingInputConstraint()) {
383 unsigned DefIdx = OpInfo.getMatchedOperand();
384 // Find operand with register def that corresponds to DefIdx.
385 unsigned InstFlagIdx = StartIdx;
386 for (unsigned i = 0; i < DefIdx; ++i)
387 InstFlagIdx += getNumOpRegs(*Inst, InstFlagIdx) + 1;
388 assert(getNumOpRegs(*Inst, InstFlagIdx) == 1 && "Wrong flag");
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 }
396 if (!MatchedOperandFlag.isRegDefKind() && !MatchedOperandFlag.isRegDefEarlyClobberKind()) {
397 LLVM_DEBUG(dbgs() << "Unknown matching constraint\n");
398 return false;
399 }
400
401 // We want to tie input to register in next operand.
402 unsigned DefRegIdx = InstFlagIdx + 1;
403 Register Def = Inst->getOperand(DefRegIdx).getReg();
404
405 ArrayRef<Register> SrcRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);
406 assert(SrcRegs.size() == 1 && "Single register is expected here");
407
408 // When Def is physreg: use given input.
409 Register In = SrcRegs[0];
410 // When Def is vreg: copy input to new vreg with same reg class as Def.
411 if (Def.isVirtual()) {
412 In = MRI->createVirtualRegister(MRI->getRegClass(Def));
413 if (!buildAnyextOrCopy(In, SrcRegs[0], MIRBuilder))
414 return false;
415 }
416
417 // Add Flag and input register operand (In) to Inst. Tie In to Def.
418 InlineAsm::Flag UseFlag(InlineAsm::Kind::RegUse, 1);
419 UseFlag.setMatchingOp(DefIdx);
420 Inst.addImm(UseFlag);
421 Inst.addReg(In);
422 Inst->tieOperands(DefRegIdx, Inst->getNumOperands() - 1);
423 break;
424 }
425
426 if (OpInfo.ConstraintType == TargetLowering::C_Other &&
427 OpInfo.isIndirect) {
428 LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "
429 "not supported yet\n");
430 return false;
431 }
432
433 if (OpInfo.ConstraintType == TargetLowering::C_Immediate ||
434 OpInfo.ConstraintType == TargetLowering::C_Other) {
435
436 std::vector<MachineOperand> Ops;
437 if (!lowerAsmOperandForConstraint(OpInfo.CallOperandVal,
438 OpInfo.ConstraintCode, Ops,
439 MIRBuilder)) {
440 LLVM_DEBUG(dbgs() << "Don't support constraint: "
441 << OpInfo.ConstraintCode << " yet\n");
442 return false;
443 }
444
445 assert(Ops.size() > 0 &&
446 "Expected constraint to be lowered to at least one operand");
447
448 // Add information to the INLINEASM node to know about this input.
449 const unsigned OpFlags =
450 InlineAsm::Flag(InlineAsm::Kind::Imm, Ops.size());
451 Inst.addImm(OpFlags);
452 Inst.add(Ops);
453 break;
454 }
455
456 if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
457
458 if (!OpInfo.isIndirect) {
459 LLVM_DEBUG(dbgs()
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
466 const InlineAsm::ConstraintCode ConstraintID =
467 TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);
468 InlineAsm::Flag OpFlags(InlineAsm::Kind::Mem, 1);
469 OpFlags.setMemConstraint(ConstraintID);
470 Inst.addImm(OpFlags);
471 ArrayRef<Register> SourceRegs =
472 GetOrCreateVRegs(*OpInfo.CallOperandVal);
473 assert(
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
480 assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass ||
481 OpInfo.ConstraintType == TargetLowering::C_Register) &&
482 "Unknown constraint type!");
483
484 if (OpInfo.isIndirect) {
485 LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "
486 "for constraint '"
487 << OpInfo.ConstraintCode << "'\n");
488 return false;
489 }
490
491 // Copy the input into the appropriate registers.
492 if (OpInfo.Regs.empty()) {
493 LLVM_DEBUG(
494 dbgs()
495 << "Couldn't allocate input register for register constraint\n");
496 return false;
497 }
498
499 unsigned NumRegs = OpInfo.Regs.size();
500 ArrayRef<Register> SourceRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal);
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
511 InlineAsm::Flag Flag(InlineAsm::Kind::RegUse, NumRegs);
512 if (OpInfo.Regs.front().isVirtual()) {
513 // Put the register class of the virtual registers in the flag word.
514 const TargetRegisterClass *RC = MRI->getRegClass(OpInfo.Regs.front());
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
524 case InlineAsm::isClobber: {
525
526 const unsigned NumRegs = OpInfo.Regs.size();
527 if (NumRegs > 0) {
528 unsigned Flag = InlineAsm::Flag(InlineAsm::Kind::Clobber, NumRegs);
529 Inst.addImm(Flag);
530
531 for (Register Reg : OpInfo.Regs) {
532 Inst.addReg(Reg, RegState::Define | RegState::EarlyClobber |
533 getImplRegState(Reg.isPhysical()));
534 }
535 }
536 break;
537 }
538 }
539 }
540
541 // Add rounding control registers as implicit def for inline asm.
542 if (MF.getFunction().hasFnAttribute(Attribute::StrictFP)) {
543 ArrayRef<MCPhysReg> RCRegs = TLI->getRoundingControlRegisters();
544 for (MCPhysReg Reg : RCRegs)
545 Inst.addReg(Reg, RegState::ImplicitDefine);
546 }
547
548 if (auto Bundle = Call.getOperandBundle(LLVMContext::OB_convergencectrl)) {
549 auto *Token = Bundle->Inputs[0].get();
550 ArrayRef<Register> SourceRegs = GetOrCreateVRegs(*Token);
551 assert(SourceRegs.size() == 1 &&
552 "Expected the control token to fit into a single virtual register");
553 Inst.addUse(SourceRegs[0], RegState::Implicit);
554 }
555
556 if (const MDNode *SrcLoc = Call.getMetadata("srcloc"))
557 Inst.addMetadata(SrcLoc);
558
559 // All inputs are handled, insert the instruction now
560 MIRBuilder.insertInstr(Inst);
561
562 // Finally, copy the output operands into the output registers
563 ArrayRef<Register> ResRegs = GetOrCreateVRegs(Call);
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) {
576 case TargetLowering::C_Register:
577 case TargetLowering::C_RegisterClass: {
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]);
587 if (ResTy.isScalar() && ResTy.getSizeInBits() < SrcSize) {
588 // First copy the non-typed virtual register into a generic virtual
589 // register
590 Register Tmp1Reg =
591 MRI->createGenericVirtualRegister(LLT::scalar(SrcSize));
592 MIRBuilder.buildCopy(Tmp1Reg, SrcReg);
593 // Need to truncate the result of the register
594 MIRBuilder.buildTrunc(ResRegs[i], Tmp1Reg);
595 } else if (ResTy.getSizeInBits() == SrcSize) {
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 }
605 case TargetLowering::C_Immediate:
606 case TargetLowering::C_Other:
607 LLVM_DEBUG(
608 dbgs() << "Cannot lower target specific output constraints yet\n");
609 return false;
610 case TargetLowering::C_Memory:
611 break; // Already handled.
612 case TargetLowering::C_Address:
613 break; // Silence warning.
614 case TargetLowering::C_Unknown:
615 LLVM_DEBUG(dbgs() << "Unexpected unknown constraint\n");
616 return false;
617 }
618 }
619
620 return true;
621 }
622
lowerAsmOperandForConstraint(Value * Val,StringRef Constraint,std::vector<MachineOperand> & Ops,MachineIRBuilder & MIRBuilder) const623 bool InlineAsmLowering::lowerAsmOperandForConstraint(
624 Value *Val, StringRef Constraint, std::vector<MachineOperand> &Ops,
625 MachineIRBuilder &MIRBuilder) const {
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': // Simple Integer or Relocatable Constant
634 case 'n': // immediate integer with a known value.
635 if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
636 assert(CI->getBitWidth() <= 64 &&
637 "expected immediate to fit into 64-bits");
638 // Boolean constants should be zero-extended, others are sign-extended
639 bool IsBool = CI->getBitWidth() == 1;
640 int64_t ExtVal = IsBool ? CI->getZExtValue() : CI->getSExtValue();
641 Ops.push_back(MachineOperand::CreateImm(ExtVal));
642 return true;
643 }
644 return false;
645 }
646 }
647