1 //===-- lib/CodeGen/GlobalISel/InlineAsmLowering.cpp ----------------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements the lowering from LLVM IR inline asm to MIR INLINEASM
12 //===----------------------------------------------------------------------===//
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"
21 #define DEBUG_TYPE "inline-asm-lowering"
25 void InlineAsmLowering::anchor() {}
29 /// GISelAsmOperandInfo - This contains information for each constraint that we
31 class GISelAsmOperandInfo
: public TargetLowering::AsmOperandInfo
{
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
;
37 explicit GISelAsmOperandInfo(const TargetLowering::AsmOperandInfo
&Info
)
38 : TargetLowering::AsmOperandInfo(Info
) {}
41 using GISelAsmOperandInfoVector
= SmallVector
<GISelAsmOperandInfo
, 16>;
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
;
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
);
74 unsigned get() const { return Flags
; }
79 /// Assign virtual/physical registers for the specified register operand.
80 static void getRegistersForValue(MachineFunction
&MF
,
81 MachineIRBuilder
&MIRBuilder
,
82 GISelAsmOperandInfo
&OpInfo
,
83 GISelAsmOperandInfo
&RefOpInfo
) {
85 const TargetLowering
&TLI
= *MF
.getSubtarget().getTargetLowering();
86 const TargetRegisterInfo
&TRI
= *MF
.getSubtarget().getRegisterInfo();
88 // No work to do for memory operations.
89 if (OpInfo
.ConstraintType
== TargetLowering::C_Memory
)
92 // If this is a constraint for a single physreg, or a constraint for a
93 // register class, find it.
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.
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())
107 // Initialize NumRegs.
108 unsigned NumRegs
= 1;
109 if (OpInfo
.ConstraintVT
!= MVT::Other
)
111 TLI
.getNumRegisters(MF
.getFunction().getContext(), OpInfo
.ConstraintVT
);
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
117 // For this, first retrieve a register iterator for the given register class
118 TargetRegisterClass::iterator I
= RC
->begin();
119 MachineRegisterInfo
&RegInfo
= MF
.getRegInfo();
121 // Advance the iterator to the assigned register (if set)
123 for (; *I
!= AssignedReg
; ++I
)
124 assert(I
!= RC
->end() && "AssignedReg should be a member of provided RC");
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
);
136 static void computeConstraintToUse(const TargetLowering
*TLI
,
137 TargetLowering::AsmOperandInfo
&OpInfo
) {
138 assert(!OpInfo
.Codes
.empty() && "Must have at least one constraint");
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
);
145 TargetLowering::ConstraintGroup G
= TLI
->getConstraintPreferences(OpInfo
);
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
);
155 OpInfo
.ConstraintCode
= G
[BestIdx
].first
;
156 OpInfo
.ConstraintType
= G
[BestIdx
].second
;
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
))
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
);
177 static unsigned getNumOpRegs(const MachineInstr
&I
, unsigned OpIdx
) {
178 const InlineAsm::Flag
F(I
.getOperand(OpIdx
).getImm());
179 return F
.getNumOperandRegisters();
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();
188 auto SrcTy
= MRI
->getType(Src
);
189 if (!SrcTy
.isValid()) {
190 LLVM_DEBUG(dbgs() << "Source type for copy is not valid\n");
193 unsigned SrcSize
= TRI
->getRegSizeInBits(Src
, *MRI
);
194 unsigned DstSize
= TRI
->getRegSizeInBits(Dst
, *MRI
);
196 if (DstSize
< SrcSize
) {
197 LLVM_DEBUG(dbgs() << "Input can't fit in destination reg class\n");
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");
208 Src
= MIRBuilder
.buildAnyExt(LLT::scalar(DstSize
), Src
).getReg(0);
211 MIRBuilder
.buildCopy(Dst
, Src
);
215 bool InlineAsmLowering::lowerInlineAsm(
216 MachineIRBuilder
&MIRBuilder
, const CallBase
&Call
,
217 std::function
<ArrayRef
<Register
>(const Value
&Val
)> GetOrCreateVRegs
)
219 const InlineAsm
*IA
= cast
<InlineAsm
>(Call
.getCalledOperand());
221 /// ConstraintOperands - Information about all of the constraints.
222 GISelAsmOperandInfoVector ConstraintOperands
;
224 MachineFunction
&MF
= MIRBuilder
.getMF();
225 const Function
&F
= MF
.getFunction();
226 const DataLayout
&DL
= F
.getDataLayout();
227 const TargetRegisterInfo
*TRI
= MF
.getSubtarget().getRegisterInfo();
229 MachineRegisterInfo
*MRI
= MIRBuilder
.getMRI();
231 TargetLowering::AsmOperandInfoVector TargetConstraints
=
232 TLI
->ParseConstraints(DL
, TRI
, Call
);
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();
241 // Compute the value type for each operand.
242 if (OpInfo
.hasArg()) {
243 OpInfo
.CallOperandVal
= const_cast<Value
*>(Call
.getArgOperand(ArgNo
));
245 if (isa
<BasicBlock
>(OpInfo
.CallOperandVal
)) {
246 LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n");
250 Type
*OpTy
= OpInfo
.CallOperandVal
->getType();
252 // If this is an indirect operand, the operand is a pointer to the
254 if (OpInfo
.isIndirect
) {
255 OpTy
= Call
.getParamElementType(ArgNo
);
256 assert(OpTy
&& "Indirect operand must have elementtype attribute");
259 // FIXME: Support aggregate input operands
260 if (!OpTy
->isSingleValueType()) {
262 dbgs() << "Aggregate input operands are not supported yet\n");
266 OpInfo
.ConstraintVT
=
267 TLI
->getAsmOperandValueType(DL
, OpTy
, true).getSimpleVT();
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
));
275 assert(ResNo
== 0 && "Asm only has one result!");
276 OpInfo
.ConstraintVT
=
277 TLI
->getAsmOperandValueType(DL
, Call
.getType()).getSimpleVT();
281 assert(OpInfo
.Type
!= InlineAsm::isLabel
&&
282 "GlobalISel currently doesn't support callbr");
283 OpInfo
.ConstraintVT
= MVT::Other
;
286 if (OpInfo
.ConstraintVT
== MVT::i64x8
)
289 // Compute the constraint code and ConstraintType to use.
290 computeConstraintToUse(TLI
, OpInfo
);
292 // The selected constraint type might expose new sideeffects
293 ExtraInfo
.update(OpInfo
);
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());
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();
307 // Collects the output operands for later processing
308 GISelAsmOperandInfoVector OutputOperands
;
310 for (auto &OpInfo
: ConstraintOperands
) {
311 GISelAsmOperandInfo
&RefOpInfo
=
312 OpInfo
.isMatchingInputConstraint()
313 ? ConstraintOperands
[OpInfo
.getMatchedOperand()]
316 // Assign registers for register operands
317 getRegistersForValue(MF
, MIRBuilder
, OpInfo
, RefOpInfo
);
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.");
327 // Add information to the INLINEASM instruction to know about this
329 InlineAsm::Flag
Flag(InlineAsm::Kind::Mem
, 1);
330 Flag
.setMemConstraint(ConstraintID
);
332 ArrayRef
<Register
> SourceRegs
=
333 GetOrCreateVRegs(*OpInfo
.CallOperandVal
);
335 SourceRegs
.size() == 1 &&
336 "Expected the memory output to fit into a single virtual register");
337 Inst
.addReg(SourceRegs
[0]);
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
);
345 // Find a register that we can use.
346 if (OpInfo
.Regs
.empty()) {
348 << "Couldn't allocate output register for constraint\n");
352 // Add information to the INLINEASM instruction to know that this
354 InlineAsm::Flag
Flag(OpInfo
.isEarlyClobber
355 ? InlineAsm::Kind::RegDefEarlyClobber
356 : InlineAsm::Kind::RegDef
,
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());
369 for (Register Reg
: OpInfo
.Regs
) {
371 RegState::Define
| getImplRegState(Reg
.isPhysical()) |
372 (OpInfo
.isEarlyClobber
? RegState::EarlyClobber
: 0));
375 // Remember this output operand for later processing
376 OutputOperands
.push_back(OpInfo
);
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");
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");
396 if (!MatchedOperandFlag
.isRegDefKind() && !MatchedOperandFlag
.isRegDefEarlyClobberKind()) {
397 LLVM_DEBUG(dbgs() << "Unknown matching constraint\n");
401 // We want to tie input to register in next operand.
402 unsigned DefRegIdx
= InstFlagIdx
+ 1;
403 Register Def
= Inst
->getOperand(DefRegIdx
).getReg();
405 ArrayRef
<Register
> SrcRegs
= GetOrCreateVRegs(*OpInfo
.CallOperandVal
);
406 assert(SrcRegs
.size() == 1 && "Single register is expected here");
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
))
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
);
422 Inst
->tieOperands(DefRegIdx
, Inst
->getNumOperands() - 1);
426 if (OpInfo
.ConstraintType
== TargetLowering::C_Other
&&
428 LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "
429 "not supported yet\n");
433 if (OpInfo
.ConstraintType
== TargetLowering::C_Immediate
||
434 OpInfo
.ConstraintType
== TargetLowering::C_Other
) {
436 std::vector
<MachineOperand
> Ops
;
437 if (!lowerAsmOperandForConstraint(OpInfo
.CallOperandVal
,
438 OpInfo
.ConstraintCode
, Ops
,
440 LLVM_DEBUG(dbgs() << "Don't support constraint: "
441 << OpInfo
.ConstraintCode
<< " yet\n");
445 assert(Ops
.size() > 0 &&
446 "Expected constraint to be lowered to at least one operand");
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
);
456 if (OpInfo
.ConstraintType
== TargetLowering::C_Memory
) {
458 if (!OpInfo
.isIndirect
) {
460 << "Cannot indirectify memory input operands yet\n");
464 assert(OpInfo
.isIndirect
&& "Operand must be indirect to be a mem!");
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
);
474 SourceRegs
.size() == 1 &&
475 "Expected the memory input to fit into a single virtual register");
476 Inst
.addReg(SourceRegs
[0]);
480 assert((OpInfo
.ConstraintType
== TargetLowering::C_RegisterClass
||
481 OpInfo
.ConstraintType
== TargetLowering::C_Register
) &&
482 "Unknown constraint type!");
484 if (OpInfo
.isIndirect
) {
485 LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "
487 << OpInfo
.ConstraintCode
<< "'\n");
491 // Copy the input into the appropriate registers.
492 if (OpInfo
.Regs
.empty()) {
495 << "Couldn't allocate input register for register constraint\n");
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 "
506 LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are "
507 "not supported yet\n");
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());
518 if (!buildAnyextOrCopy(OpInfo
.Regs
[0], SourceRegs
[0], MIRBuilder
))
520 Inst
.addReg(OpInfo
.Regs
[0]);
524 case InlineAsm::isClobber
: {
526 const unsigned NumRegs
= OpInfo
.Regs
.size();
528 unsigned Flag
= InlineAsm::Flag(InlineAsm::Kind::Clobber
, NumRegs
);
531 for (Register Reg
: OpInfo
.Regs
) {
532 Inst
.addReg(Reg
, RegState::Define
| RegState::EarlyClobber
|
533 getImplRegState(Reg
.isPhysical()));
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
);
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
);
556 if (const MDNode
*SrcLoc
= Call
.getMetadata("srcloc"))
557 Inst
.addMetadata(SrcLoc
);
559 // All inputs are handled, insert the instruction now
560 MIRBuilder
.insertInstr(Inst
);
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");
569 for (unsigned int i
= 0, e
= ResRegs
.size(); i
< e
; i
++) {
570 GISelAsmOperandInfo
&OpInfo
= OutputOperands
[i
];
572 if (OpInfo
.Regs
.empty())
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");
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
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
);
598 LLVM_DEBUG(dbgs() << "Unhandled output operand with "
599 "mismatched register size\n");
605 case TargetLowering::C_Immediate
:
606 case TargetLowering::C_Other
:
608 dbgs() << "Cannot lower target specific output constraints yet\n");
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");
623 bool InlineAsmLowering::lowerAsmOperandForConstraint(
624 Value
*Val
, StringRef Constraint
, std::vector
<MachineOperand
> &Ops
,
625 MachineIRBuilder
&MIRBuilder
) const {
626 if (Constraint
.size() > 1)
629 char ConstraintLetter
= Constraint
[0];
630 switch (ConstraintLetter
) {
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
));