21#define DEBUG_TYPE "inline-asm-lowering"
25void InlineAsmLowering::anchor() {}
47 explicit ExtraFlags(
const CallBase &CB) {
49 if (
IA->hasSideEffects())
51 if (
IA->isAlignStack())
74 unsigned get()
const {
return Flags; }
82 GISelAsmOperandInfo &OpInfo,
83 GISelAsmOperandInfo &RefOpInfo) {
97 &
TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT);
104 if (OpInfo.isMatchingInputConstraint())
108 unsigned NumRegs = 1;
109 if (OpInfo.ConstraintVT != MVT::Other)
123 for (; *
I != AssignedReg; ++
I)
124 assert(
I != RC->
end() &&
"AssignedReg should be a member of provided RC");
129 for (; NumRegs; --NumRegs, ++
I) {
130 assert(
I != RC->
end() &&
"Ran out of registers to allocate!");
132 OpInfo.Regs.push_back(R);
138 assert(!OpInfo.
Codes.empty() &&
"Must have at least one constraint");
141 if (OpInfo.
Codes.size() == 1) {
149 unsigned BestIdx = 0;
150 for (
const unsigned E =
G.size();
165 if (isa<BasicBlock>(Val) || isa<ConstantInt>(Val) || isa<Function>(Val))
179 return F.getNumOperandRegisters();
188 auto SrcTy =
MRI->getType(Src);
189 if (!SrcTy.isValid()) {
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");
202 if (DstSize > SrcSize) {
203 if (!SrcTy.isScalar()) {
205 "destination register class\n");
219 const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
222 GISelAsmOperandInfoVector ConstraintOperands;
234 ExtraFlags ExtraInfo(Call);
237 for (
auto &
T : TargetConstraints) {
238 ConstraintOperands.push_back(GISelAsmOperandInfo(
T));
239 GISelAsmOperandInfo &OpInfo = ConstraintOperands.back();
242 if (OpInfo.hasArg()) {
245 if (isa<BasicBlock>(OpInfo.CallOperandVal)) {
246 LLVM_DEBUG(
dbgs() <<
"Basic block input operands not supported yet\n");
250 Type *OpTy = OpInfo.CallOperandVal->getType();
254 if (OpInfo.isIndirect) {
255 OpTy = Call.getParamElementType(ArgNo);
256 assert(OpTy &&
"Indirect operand must have elementtype attribute");
262 dbgs() <<
"Aggregate input operands are not supported yet\n");
266 OpInfo.ConstraintVT =
270 assert(!Call.getType()->isVoidTy() &&
"Bad inline asm!");
271 if (
StructType *STy = dyn_cast<StructType>(Call.getType())) {
272 OpInfo.ConstraintVT =
275 assert(ResNo == 0 &&
"Asm only has one result!");
276 OpInfo.ConstraintVT =
282 "GlobalISel currently doesn't support callbr");
283 OpInfo.ConstraintVT = MVT::Other;
286 if (OpInfo.ConstraintVT == MVT::i64x8)
293 ExtraInfo.update(OpInfo);
308 GISelAsmOperandInfoVector OutputOperands;
310 for (
auto &OpInfo : ConstraintOperands) {
311 GISelAsmOperandInfo &RefOpInfo =
319 switch (OpInfo.
Type) {
325 "Failed to convert memory constraint code to constraint id.");
330 Flag.setMemConstraint(ConstraintID);
335 SourceRegs.
size() == 1 &&
336 "Expected the memory output to fit into a single virtual register");
337 Inst.addReg(SourceRegs[0]);
346 if (OpInfo.Regs.empty()) {
348 <<
"Couldn't allocate output register for constraint\n");
358 if (OpInfo.Regs.front().isVirtual()) {
364 Flag.setRegClass(RC->
getID());
376 OutputOperands.push_back(OpInfo);
385 unsigned InstFlagIdx = StartIdx;
386 for (
unsigned i = 0; i < DefIdx; ++i)
390 const InlineAsm::Flag MatchedOperandFlag(Inst->getOperand(InstFlagIdx).getImm());
392 LLVM_DEBUG(
dbgs() <<
"Matching input constraint to mem operand not "
393 "supported. This should be target specific.\n");
402 unsigned DefRegIdx = InstFlagIdx + 1;
403 Register Def = Inst->getOperand(DefRegIdx).getReg();
406 assert(SrcRegs.
size() == 1 &&
"Single register is expected here");
411 if (Def.isVirtual()) {
412 In =
MRI->createVirtualRegister(
MRI->getRegClass(Def));
420 Inst.addImm(UseFlag);
422 Inst->tieOperands(DefRegIdx, Inst->getNumOperands() - 1);
428 LLVM_DEBUG(
dbgs() <<
"Indirect input operands with unknown constraint "
429 "not supported yet\n");
436 std::vector<MachineOperand> Ops;
446 "Expected constraint to be lowered to at least one operand");
449 const unsigned OpFlags =
451 Inst.addImm(OpFlags);
460 <<
"Cannot indirectify memory input operands yet\n");
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]);
482 "Unknown constraint type!");
492 if (OpInfo.Regs.empty()) {
495 <<
"Couldn't allocate input register for register constraint\n");
499 unsigned NumRegs = OpInfo.Regs.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");
512 if (OpInfo.Regs.front().isVirtual()) {
515 Flag.setRegClass(RC->
getID());
520 Inst.addReg(OpInfo.Regs[0]);
526 const unsigned NumRegs = OpInfo.Regs.size();
549 auto *Token = Bundle->Inputs[0].get();
552 "Expected the control token to fit into a single virtual register");
556 if (
const MDNode *SrcLoc = Call.getMetadata(
"srcloc"))
557 Inst.addMetadata(SrcLoc);
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) {
578 if (OpInfo.Regs.size() > 1) {
580 "registers are not supported yet\n");
585 unsigned SrcSize =
TRI->getRegSizeInBits(SrcReg, *
MRI);
586 LLT ResTy =
MRI->getType(ResRegs[i]);
596 MIRBuilder.
buildCopy(ResRegs[i], SrcReg);
599 "mismatched register size\n");
608 dbgs() <<
"Cannot lower target specific output constraints yet\n");
624 Value *Val,
StringRef Constraint, std::vector<MachineOperand> &Ops,
626 if (Constraint.
size() > 1)
629 char ConstraintLetter = Constraint[0];
630 switch (ConstraintLetter) {
635 if (
ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
636 assert(CI->getBitWidth() <= 64 &&
637 "expected immediate to fit into 64-bits");
639 bool IsBool = CI->getBitWidth() == 1;
640 int64_t ExtVal = IsBool ? CI->getZExtValue() : CI->getSExtValue();
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Analysis containing CSE Info
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
Module.h This file contains the declarations for the Module class.
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 <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 & 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".