1*5ffd83dbSDimitry Andric //===-- lib/CodeGen/GlobalISel/InlineAsmLowering.cpp ----------------------===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric /// 9*5ffd83dbSDimitry Andric /// \file 10*5ffd83dbSDimitry Andric /// This file implements the lowering from LLVM IR inline asm to MIR INLINEASM 11*5ffd83dbSDimitry Andric /// 12*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 13*5ffd83dbSDimitry Andric 14*5ffd83dbSDimitry Andric #include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h" 15*5ffd83dbSDimitry Andric #include "llvm/CodeGen/Analysis.h" 16*5ffd83dbSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 17*5ffd83dbSDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 18*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 19*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 20*5ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 21*5ffd83dbSDimitry Andric #include "llvm/IR/DataLayout.h" 22*5ffd83dbSDimitry Andric #include "llvm/IR/Instructions.h" 23*5ffd83dbSDimitry Andric #include "llvm/IR/LLVMContext.h" 24*5ffd83dbSDimitry Andric #include "llvm/IR/Module.h" 25*5ffd83dbSDimitry Andric 26*5ffd83dbSDimitry Andric #define DEBUG_TYPE "inline-asm-lowering" 27*5ffd83dbSDimitry Andric 28*5ffd83dbSDimitry Andric using namespace llvm; 29*5ffd83dbSDimitry Andric 30*5ffd83dbSDimitry Andric void InlineAsmLowering::anchor() {} 31*5ffd83dbSDimitry Andric 32*5ffd83dbSDimitry Andric namespace { 33*5ffd83dbSDimitry Andric 34*5ffd83dbSDimitry Andric /// GISelAsmOperandInfo - This contains information for each constraint that we 35*5ffd83dbSDimitry Andric /// are lowering. 36*5ffd83dbSDimitry Andric class GISelAsmOperandInfo : public TargetLowering::AsmOperandInfo { 37*5ffd83dbSDimitry Andric public: 38*5ffd83dbSDimitry Andric /// Regs - If this is a register or register class operand, this 39*5ffd83dbSDimitry Andric /// contains the set of assigned registers corresponding to the operand. 40*5ffd83dbSDimitry Andric SmallVector<Register, 1> Regs; 41*5ffd83dbSDimitry Andric 42*5ffd83dbSDimitry Andric explicit GISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &Info) 43*5ffd83dbSDimitry Andric : TargetLowering::AsmOperandInfo(Info) {} 44*5ffd83dbSDimitry Andric }; 45*5ffd83dbSDimitry Andric 46*5ffd83dbSDimitry Andric using GISelAsmOperandInfoVector = SmallVector<GISelAsmOperandInfo, 16>; 47*5ffd83dbSDimitry Andric 48*5ffd83dbSDimitry Andric class ExtraFlags { 49*5ffd83dbSDimitry Andric unsigned Flags = 0; 50*5ffd83dbSDimitry Andric 51*5ffd83dbSDimitry Andric public: 52*5ffd83dbSDimitry Andric explicit ExtraFlags(const CallBase &CB) { 53*5ffd83dbSDimitry Andric const InlineAsm *IA = cast<InlineAsm>(CB.getCalledOperand()); 54*5ffd83dbSDimitry Andric if (IA->hasSideEffects()) 55*5ffd83dbSDimitry Andric Flags |= InlineAsm::Extra_HasSideEffects; 56*5ffd83dbSDimitry Andric if (IA->isAlignStack()) 57*5ffd83dbSDimitry Andric Flags |= InlineAsm::Extra_IsAlignStack; 58*5ffd83dbSDimitry Andric if (CB.isConvergent()) 59*5ffd83dbSDimitry Andric Flags |= InlineAsm::Extra_IsConvergent; 60*5ffd83dbSDimitry Andric Flags |= IA->getDialect() * InlineAsm::Extra_AsmDialect; 61*5ffd83dbSDimitry Andric } 62*5ffd83dbSDimitry Andric 63*5ffd83dbSDimitry Andric void update(const TargetLowering::AsmOperandInfo &OpInfo) { 64*5ffd83dbSDimitry Andric // Ideally, we would only check against memory constraints. However, the 65*5ffd83dbSDimitry Andric // meaning of an Other constraint can be target-specific and we can't easily 66*5ffd83dbSDimitry Andric // reason about it. Therefore, be conservative and set MayLoad/MayStore 67*5ffd83dbSDimitry Andric // for Other constraints as well. 68*5ffd83dbSDimitry Andric if (OpInfo.ConstraintType == TargetLowering::C_Memory || 69*5ffd83dbSDimitry Andric OpInfo.ConstraintType == TargetLowering::C_Other) { 70*5ffd83dbSDimitry Andric if (OpInfo.Type == InlineAsm::isInput) 71*5ffd83dbSDimitry Andric Flags |= InlineAsm::Extra_MayLoad; 72*5ffd83dbSDimitry Andric else if (OpInfo.Type == InlineAsm::isOutput) 73*5ffd83dbSDimitry Andric Flags |= InlineAsm::Extra_MayStore; 74*5ffd83dbSDimitry Andric else if (OpInfo.Type == InlineAsm::isClobber) 75*5ffd83dbSDimitry Andric Flags |= (InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore); 76*5ffd83dbSDimitry Andric } 77*5ffd83dbSDimitry Andric } 78*5ffd83dbSDimitry Andric 79*5ffd83dbSDimitry Andric unsigned get() const { return Flags; } 80*5ffd83dbSDimitry Andric }; 81*5ffd83dbSDimitry Andric 82*5ffd83dbSDimitry Andric } // namespace 83*5ffd83dbSDimitry Andric 84*5ffd83dbSDimitry Andric /// Assign virtual/physical registers for the specified register operand. 85*5ffd83dbSDimitry Andric static void getRegistersForValue(MachineFunction &MF, 86*5ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder, 87*5ffd83dbSDimitry Andric GISelAsmOperandInfo &OpInfo, 88*5ffd83dbSDimitry Andric GISelAsmOperandInfo &RefOpInfo) { 89*5ffd83dbSDimitry Andric 90*5ffd83dbSDimitry Andric const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering(); 91*5ffd83dbSDimitry Andric const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); 92*5ffd83dbSDimitry Andric 93*5ffd83dbSDimitry Andric // No work to do for memory operations. 94*5ffd83dbSDimitry Andric if (OpInfo.ConstraintType == TargetLowering::C_Memory) 95*5ffd83dbSDimitry Andric return; 96*5ffd83dbSDimitry Andric 97*5ffd83dbSDimitry Andric // If this is a constraint for a single physreg, or a constraint for a 98*5ffd83dbSDimitry Andric // register class, find it. 99*5ffd83dbSDimitry Andric Register AssignedReg; 100*5ffd83dbSDimitry Andric const TargetRegisterClass *RC; 101*5ffd83dbSDimitry Andric std::tie(AssignedReg, RC) = TLI.getRegForInlineAsmConstraint( 102*5ffd83dbSDimitry Andric &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT); 103*5ffd83dbSDimitry Andric // RC is unset only on failure. Return immediately. 104*5ffd83dbSDimitry Andric if (!RC) 105*5ffd83dbSDimitry Andric return; 106*5ffd83dbSDimitry Andric 107*5ffd83dbSDimitry Andric // No need to allocate a matching input constraint since the constraint it's 108*5ffd83dbSDimitry Andric // matching to has already been allocated. 109*5ffd83dbSDimitry Andric if (OpInfo.isMatchingInputConstraint()) 110*5ffd83dbSDimitry Andric return; 111*5ffd83dbSDimitry Andric 112*5ffd83dbSDimitry Andric // Initialize NumRegs. 113*5ffd83dbSDimitry Andric unsigned NumRegs = 1; 114*5ffd83dbSDimitry Andric if (OpInfo.ConstraintVT != MVT::Other) 115*5ffd83dbSDimitry Andric NumRegs = 116*5ffd83dbSDimitry Andric TLI.getNumRegisters(MF.getFunction().getContext(), OpInfo.ConstraintVT); 117*5ffd83dbSDimitry Andric 118*5ffd83dbSDimitry Andric // If this is a constraint for a specific physical register, but the type of 119*5ffd83dbSDimitry Andric // the operand requires more than one register to be passed, we allocate the 120*5ffd83dbSDimitry Andric // required amount of physical registers, starting from the selected physical 121*5ffd83dbSDimitry Andric // register. 122*5ffd83dbSDimitry Andric // For this, first retrieve a register iterator for the given register class 123*5ffd83dbSDimitry Andric TargetRegisterClass::iterator I = RC->begin(); 124*5ffd83dbSDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 125*5ffd83dbSDimitry Andric 126*5ffd83dbSDimitry Andric // Advance the iterator to the assigned register (if set) 127*5ffd83dbSDimitry Andric if (AssignedReg) { 128*5ffd83dbSDimitry Andric for (; *I != AssignedReg; ++I) 129*5ffd83dbSDimitry Andric assert(I != RC->end() && "AssignedReg should be a member of provided RC"); 130*5ffd83dbSDimitry Andric } 131*5ffd83dbSDimitry Andric 132*5ffd83dbSDimitry Andric // Finally, assign the registers. If the AssignedReg isn't set, create virtual 133*5ffd83dbSDimitry Andric // registers with the provided register class 134*5ffd83dbSDimitry Andric for (; NumRegs; --NumRegs, ++I) { 135*5ffd83dbSDimitry Andric assert(I != RC->end() && "Ran out of registers to allocate!"); 136*5ffd83dbSDimitry Andric Register R = AssignedReg ? Register(*I) : RegInfo.createVirtualRegister(RC); 137*5ffd83dbSDimitry Andric OpInfo.Regs.push_back(R); 138*5ffd83dbSDimitry Andric } 139*5ffd83dbSDimitry Andric } 140*5ffd83dbSDimitry Andric 141*5ffd83dbSDimitry Andric /// Return an integer indicating how general CT is. 142*5ffd83dbSDimitry Andric static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { 143*5ffd83dbSDimitry Andric switch (CT) { 144*5ffd83dbSDimitry Andric case TargetLowering::C_Immediate: 145*5ffd83dbSDimitry Andric case TargetLowering::C_Other: 146*5ffd83dbSDimitry Andric case TargetLowering::C_Unknown: 147*5ffd83dbSDimitry Andric return 0; 148*5ffd83dbSDimitry Andric case TargetLowering::C_Register: 149*5ffd83dbSDimitry Andric return 1; 150*5ffd83dbSDimitry Andric case TargetLowering::C_RegisterClass: 151*5ffd83dbSDimitry Andric return 2; 152*5ffd83dbSDimitry Andric case TargetLowering::C_Memory: 153*5ffd83dbSDimitry Andric return 3; 154*5ffd83dbSDimitry Andric } 155*5ffd83dbSDimitry Andric llvm_unreachable("Invalid constraint type"); 156*5ffd83dbSDimitry Andric } 157*5ffd83dbSDimitry Andric 158*5ffd83dbSDimitry Andric static void chooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, 159*5ffd83dbSDimitry Andric const TargetLowering *TLI) { 160*5ffd83dbSDimitry Andric assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options"); 161*5ffd83dbSDimitry Andric unsigned BestIdx = 0; 162*5ffd83dbSDimitry Andric TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown; 163*5ffd83dbSDimitry Andric int BestGenerality = -1; 164*5ffd83dbSDimitry Andric 165*5ffd83dbSDimitry Andric // Loop over the options, keeping track of the most general one. 166*5ffd83dbSDimitry Andric for (unsigned i = 0, e = OpInfo.Codes.size(); i != e; ++i) { 167*5ffd83dbSDimitry Andric TargetLowering::ConstraintType CType = 168*5ffd83dbSDimitry Andric TLI->getConstraintType(OpInfo.Codes[i]); 169*5ffd83dbSDimitry Andric 170*5ffd83dbSDimitry Andric // Indirect 'other' or 'immediate' constraints are not allowed. 171*5ffd83dbSDimitry Andric if (OpInfo.isIndirect && !(CType == TargetLowering::C_Memory || 172*5ffd83dbSDimitry Andric CType == TargetLowering::C_Register || 173*5ffd83dbSDimitry Andric CType == TargetLowering::C_RegisterClass)) 174*5ffd83dbSDimitry Andric continue; 175*5ffd83dbSDimitry Andric 176*5ffd83dbSDimitry Andric // If this is an 'other' or 'immediate' constraint, see if the operand is 177*5ffd83dbSDimitry Andric // valid for it. For example, on X86 we might have an 'rI' constraint. If 178*5ffd83dbSDimitry Andric // the operand is an integer in the range [0..31] we want to use I (saving a 179*5ffd83dbSDimitry Andric // load of a register), otherwise we must use 'r'. 180*5ffd83dbSDimitry Andric if (CType == TargetLowering::C_Other || 181*5ffd83dbSDimitry Andric CType == TargetLowering::C_Immediate) { 182*5ffd83dbSDimitry Andric assert(OpInfo.Codes[i].size() == 1 && 183*5ffd83dbSDimitry Andric "Unhandled multi-letter 'other' constraint"); 184*5ffd83dbSDimitry Andric // FIXME: prefer immediate constraints if the target allows it 185*5ffd83dbSDimitry Andric } 186*5ffd83dbSDimitry Andric 187*5ffd83dbSDimitry Andric // Things with matching constraints can only be registers, per gcc 188*5ffd83dbSDimitry Andric // documentation. This mainly affects "g" constraints. 189*5ffd83dbSDimitry Andric if (CType == TargetLowering::C_Memory && OpInfo.hasMatchingInput()) 190*5ffd83dbSDimitry Andric continue; 191*5ffd83dbSDimitry Andric 192*5ffd83dbSDimitry Andric // This constraint letter is more general than the previous one, use it. 193*5ffd83dbSDimitry Andric int Generality = getConstraintGenerality(CType); 194*5ffd83dbSDimitry Andric if (Generality > BestGenerality) { 195*5ffd83dbSDimitry Andric BestType = CType; 196*5ffd83dbSDimitry Andric BestIdx = i; 197*5ffd83dbSDimitry Andric BestGenerality = Generality; 198*5ffd83dbSDimitry Andric } 199*5ffd83dbSDimitry Andric } 200*5ffd83dbSDimitry Andric 201*5ffd83dbSDimitry Andric OpInfo.ConstraintCode = OpInfo.Codes[BestIdx]; 202*5ffd83dbSDimitry Andric OpInfo.ConstraintType = BestType; 203*5ffd83dbSDimitry Andric } 204*5ffd83dbSDimitry Andric 205*5ffd83dbSDimitry Andric static void computeConstraintToUse(const TargetLowering *TLI, 206*5ffd83dbSDimitry Andric TargetLowering::AsmOperandInfo &OpInfo) { 207*5ffd83dbSDimitry Andric assert(!OpInfo.Codes.empty() && "Must have at least one constraint"); 208*5ffd83dbSDimitry Andric 209*5ffd83dbSDimitry Andric // Single-letter constraints ('r') are very common. 210*5ffd83dbSDimitry Andric if (OpInfo.Codes.size() == 1) { 211*5ffd83dbSDimitry Andric OpInfo.ConstraintCode = OpInfo.Codes[0]; 212*5ffd83dbSDimitry Andric OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode); 213*5ffd83dbSDimitry Andric } else { 214*5ffd83dbSDimitry Andric chooseConstraint(OpInfo, TLI); 215*5ffd83dbSDimitry Andric } 216*5ffd83dbSDimitry Andric 217*5ffd83dbSDimitry Andric // 'X' matches anything. 218*5ffd83dbSDimitry Andric if (OpInfo.ConstraintCode == "X" && OpInfo.CallOperandVal) { 219*5ffd83dbSDimitry Andric // Labels and constants are handled elsewhere ('X' is the only thing 220*5ffd83dbSDimitry Andric // that matches labels). For Functions, the type here is the type of 221*5ffd83dbSDimitry Andric // the result, which is not what we want to look at; leave them alone. 222*5ffd83dbSDimitry Andric Value *Val = OpInfo.CallOperandVal; 223*5ffd83dbSDimitry Andric if (isa<BasicBlock>(Val) || isa<ConstantInt>(Val) || isa<Function>(Val)) 224*5ffd83dbSDimitry Andric return; 225*5ffd83dbSDimitry Andric 226*5ffd83dbSDimitry Andric // Otherwise, try to resolve it to something we know about by looking at 227*5ffd83dbSDimitry Andric // the actual operand type. 228*5ffd83dbSDimitry Andric if (const char *Repl = TLI->LowerXConstraint(OpInfo.ConstraintVT)) { 229*5ffd83dbSDimitry Andric OpInfo.ConstraintCode = Repl; 230*5ffd83dbSDimitry Andric OpInfo.ConstraintType = TLI->getConstraintType(OpInfo.ConstraintCode); 231*5ffd83dbSDimitry Andric } 232*5ffd83dbSDimitry Andric } 233*5ffd83dbSDimitry Andric } 234*5ffd83dbSDimitry Andric 235*5ffd83dbSDimitry Andric static unsigned getNumOpRegs(const MachineInstr &I, unsigned OpIdx) { 236*5ffd83dbSDimitry Andric unsigned Flag = I.getOperand(OpIdx).getImm(); 237*5ffd83dbSDimitry Andric return InlineAsm::getNumOperandRegisters(Flag); 238*5ffd83dbSDimitry Andric } 239*5ffd83dbSDimitry Andric 240*5ffd83dbSDimitry Andric static bool buildAnyextOrCopy(Register Dst, Register Src, 241*5ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder) { 242*5ffd83dbSDimitry Andric const TargetRegisterInfo *TRI = 243*5ffd83dbSDimitry Andric MIRBuilder.getMF().getSubtarget().getRegisterInfo(); 244*5ffd83dbSDimitry Andric MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 245*5ffd83dbSDimitry Andric 246*5ffd83dbSDimitry Andric auto SrcTy = MRI->getType(Src); 247*5ffd83dbSDimitry Andric if (!SrcTy.isValid()) { 248*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Source type for copy is not valid\n"); 249*5ffd83dbSDimitry Andric return false; 250*5ffd83dbSDimitry Andric } 251*5ffd83dbSDimitry Andric unsigned SrcSize = TRI->getRegSizeInBits(Src, *MRI); 252*5ffd83dbSDimitry Andric unsigned DstSize = TRI->getRegSizeInBits(Dst, *MRI); 253*5ffd83dbSDimitry Andric 254*5ffd83dbSDimitry Andric if (DstSize < SrcSize) { 255*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Input can't fit in destination reg class\n"); 256*5ffd83dbSDimitry Andric return false; 257*5ffd83dbSDimitry Andric } 258*5ffd83dbSDimitry Andric 259*5ffd83dbSDimitry Andric // Attempt to anyext small scalar sources. 260*5ffd83dbSDimitry Andric if (DstSize > SrcSize) { 261*5ffd83dbSDimitry Andric if (!SrcTy.isScalar()) { 262*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Can't extend non-scalar input to size of" 263*5ffd83dbSDimitry Andric "destination register class\n"); 264*5ffd83dbSDimitry Andric return false; 265*5ffd83dbSDimitry Andric } 266*5ffd83dbSDimitry Andric Src = MIRBuilder.buildAnyExt(LLT::scalar(DstSize), Src).getReg(0); 267*5ffd83dbSDimitry Andric } 268*5ffd83dbSDimitry Andric 269*5ffd83dbSDimitry Andric MIRBuilder.buildCopy(Dst, Src); 270*5ffd83dbSDimitry Andric return true; 271*5ffd83dbSDimitry Andric } 272*5ffd83dbSDimitry Andric 273*5ffd83dbSDimitry Andric bool InlineAsmLowering::lowerInlineAsm( 274*5ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder, const CallBase &Call, 275*5ffd83dbSDimitry Andric std::function<ArrayRef<Register>(const Value &Val)> GetOrCreateVRegs) 276*5ffd83dbSDimitry Andric const { 277*5ffd83dbSDimitry Andric const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand()); 278*5ffd83dbSDimitry Andric 279*5ffd83dbSDimitry Andric /// ConstraintOperands - Information about all of the constraints. 280*5ffd83dbSDimitry Andric GISelAsmOperandInfoVector ConstraintOperands; 281*5ffd83dbSDimitry Andric 282*5ffd83dbSDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 283*5ffd83dbSDimitry Andric const Function &F = MF.getFunction(); 284*5ffd83dbSDimitry Andric const DataLayout &DL = F.getParent()->getDataLayout(); 285*5ffd83dbSDimitry Andric const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); 286*5ffd83dbSDimitry Andric 287*5ffd83dbSDimitry Andric MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 288*5ffd83dbSDimitry Andric 289*5ffd83dbSDimitry Andric TargetLowering::AsmOperandInfoVector TargetConstraints = 290*5ffd83dbSDimitry Andric TLI->ParseConstraints(DL, TRI, Call); 291*5ffd83dbSDimitry Andric 292*5ffd83dbSDimitry Andric ExtraFlags ExtraInfo(Call); 293*5ffd83dbSDimitry Andric unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. 294*5ffd83dbSDimitry Andric unsigned ResNo = 0; // ResNo - The result number of the next output. 295*5ffd83dbSDimitry Andric for (auto &T : TargetConstraints) { 296*5ffd83dbSDimitry Andric ConstraintOperands.push_back(GISelAsmOperandInfo(T)); 297*5ffd83dbSDimitry Andric GISelAsmOperandInfo &OpInfo = ConstraintOperands.back(); 298*5ffd83dbSDimitry Andric 299*5ffd83dbSDimitry Andric // Compute the value type for each operand. 300*5ffd83dbSDimitry Andric if (OpInfo.Type == InlineAsm::isInput || 301*5ffd83dbSDimitry Andric (OpInfo.Type == InlineAsm::isOutput && OpInfo.isIndirect)) { 302*5ffd83dbSDimitry Andric 303*5ffd83dbSDimitry Andric OpInfo.CallOperandVal = const_cast<Value *>(Call.getArgOperand(ArgNo++)); 304*5ffd83dbSDimitry Andric 305*5ffd83dbSDimitry Andric if (isa<BasicBlock>(OpInfo.CallOperandVal)) { 306*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n"); 307*5ffd83dbSDimitry Andric return false; 308*5ffd83dbSDimitry Andric } 309*5ffd83dbSDimitry Andric 310*5ffd83dbSDimitry Andric Type *OpTy = OpInfo.CallOperandVal->getType(); 311*5ffd83dbSDimitry Andric 312*5ffd83dbSDimitry Andric // If this is an indirect operand, the operand is a pointer to the 313*5ffd83dbSDimitry Andric // accessed type. 314*5ffd83dbSDimitry Andric if (OpInfo.isIndirect) { 315*5ffd83dbSDimitry Andric PointerType *PtrTy = dyn_cast<PointerType>(OpTy); 316*5ffd83dbSDimitry Andric if (!PtrTy) 317*5ffd83dbSDimitry Andric report_fatal_error("Indirect operand for inline asm not a pointer!"); 318*5ffd83dbSDimitry Andric OpTy = PtrTy->getElementType(); 319*5ffd83dbSDimitry Andric } 320*5ffd83dbSDimitry Andric 321*5ffd83dbSDimitry Andric // FIXME: Support aggregate input operands 322*5ffd83dbSDimitry Andric if (!OpTy->isSingleValueType()) { 323*5ffd83dbSDimitry Andric LLVM_DEBUG( 324*5ffd83dbSDimitry Andric dbgs() << "Aggregate input operands are not supported yet\n"); 325*5ffd83dbSDimitry Andric return false; 326*5ffd83dbSDimitry Andric } 327*5ffd83dbSDimitry Andric 328*5ffd83dbSDimitry Andric OpInfo.ConstraintVT = TLI->getValueType(DL, OpTy, true).getSimpleVT(); 329*5ffd83dbSDimitry Andric 330*5ffd83dbSDimitry Andric } else if (OpInfo.Type == InlineAsm::isOutput && !OpInfo.isIndirect) { 331*5ffd83dbSDimitry Andric assert(!Call.getType()->isVoidTy() && "Bad inline asm!"); 332*5ffd83dbSDimitry Andric if (StructType *STy = dyn_cast<StructType>(Call.getType())) { 333*5ffd83dbSDimitry Andric OpInfo.ConstraintVT = 334*5ffd83dbSDimitry Andric TLI->getSimpleValueType(DL, STy->getElementType(ResNo)); 335*5ffd83dbSDimitry Andric } else { 336*5ffd83dbSDimitry Andric assert(ResNo == 0 && "Asm only has one result!"); 337*5ffd83dbSDimitry Andric OpInfo.ConstraintVT = TLI->getSimpleValueType(DL, Call.getType()); 338*5ffd83dbSDimitry Andric } 339*5ffd83dbSDimitry Andric ++ResNo; 340*5ffd83dbSDimitry Andric } else { 341*5ffd83dbSDimitry Andric OpInfo.ConstraintVT = MVT::Other; 342*5ffd83dbSDimitry Andric } 343*5ffd83dbSDimitry Andric 344*5ffd83dbSDimitry Andric // Compute the constraint code and ConstraintType to use. 345*5ffd83dbSDimitry Andric computeConstraintToUse(TLI, OpInfo); 346*5ffd83dbSDimitry Andric 347*5ffd83dbSDimitry Andric // The selected constraint type might expose new sideeffects 348*5ffd83dbSDimitry Andric ExtraInfo.update(OpInfo); 349*5ffd83dbSDimitry Andric } 350*5ffd83dbSDimitry Andric 351*5ffd83dbSDimitry Andric // At this point, all operand types are decided. 352*5ffd83dbSDimitry Andric // Create the MachineInstr, but don't insert it yet since input 353*5ffd83dbSDimitry Andric // operands still need to insert instructions before this one 354*5ffd83dbSDimitry Andric auto Inst = MIRBuilder.buildInstrNoInsert(TargetOpcode::INLINEASM) 355*5ffd83dbSDimitry Andric .addExternalSymbol(IA->getAsmString().c_str()) 356*5ffd83dbSDimitry Andric .addImm(ExtraInfo.get()); 357*5ffd83dbSDimitry Andric 358*5ffd83dbSDimitry Andric // Starting from this operand: flag followed by register(s) will be added as 359*5ffd83dbSDimitry Andric // operands to Inst for each constraint. Used for matching input constraints. 360*5ffd83dbSDimitry Andric unsigned StartIdx = Inst->getNumOperands(); 361*5ffd83dbSDimitry Andric 362*5ffd83dbSDimitry Andric // Collects the output operands for later processing 363*5ffd83dbSDimitry Andric GISelAsmOperandInfoVector OutputOperands; 364*5ffd83dbSDimitry Andric 365*5ffd83dbSDimitry Andric for (auto &OpInfo : ConstraintOperands) { 366*5ffd83dbSDimitry Andric GISelAsmOperandInfo &RefOpInfo = 367*5ffd83dbSDimitry Andric OpInfo.isMatchingInputConstraint() 368*5ffd83dbSDimitry Andric ? ConstraintOperands[OpInfo.getMatchedOperand()] 369*5ffd83dbSDimitry Andric : OpInfo; 370*5ffd83dbSDimitry Andric 371*5ffd83dbSDimitry Andric // Assign registers for register operands 372*5ffd83dbSDimitry Andric getRegistersForValue(MF, MIRBuilder, OpInfo, RefOpInfo); 373*5ffd83dbSDimitry Andric 374*5ffd83dbSDimitry Andric switch (OpInfo.Type) { 375*5ffd83dbSDimitry Andric case InlineAsm::isOutput: 376*5ffd83dbSDimitry Andric if (OpInfo.ConstraintType == TargetLowering::C_Memory) { 377*5ffd83dbSDimitry Andric unsigned ConstraintID = 378*5ffd83dbSDimitry Andric TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode); 379*5ffd83dbSDimitry Andric assert(ConstraintID != InlineAsm::Constraint_Unknown && 380*5ffd83dbSDimitry Andric "Failed to convert memory constraint code to constraint id."); 381*5ffd83dbSDimitry Andric 382*5ffd83dbSDimitry Andric // Add information to the INLINEASM instruction to know about this 383*5ffd83dbSDimitry Andric // output. 384*5ffd83dbSDimitry Andric unsigned OpFlags = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1); 385*5ffd83dbSDimitry Andric OpFlags = InlineAsm::getFlagWordForMem(OpFlags, ConstraintID); 386*5ffd83dbSDimitry Andric Inst.addImm(OpFlags); 387*5ffd83dbSDimitry Andric ArrayRef<Register> SourceRegs = 388*5ffd83dbSDimitry Andric GetOrCreateVRegs(*OpInfo.CallOperandVal); 389*5ffd83dbSDimitry Andric assert( 390*5ffd83dbSDimitry Andric SourceRegs.size() == 1 && 391*5ffd83dbSDimitry Andric "Expected the memory output to fit into a single virtual register"); 392*5ffd83dbSDimitry Andric Inst.addReg(SourceRegs[0]); 393*5ffd83dbSDimitry Andric } else { 394*5ffd83dbSDimitry Andric // Otherwise, this outputs to a register (directly for C_Register / 395*5ffd83dbSDimitry Andric // C_RegisterClass. Find a register that we can use. 396*5ffd83dbSDimitry Andric assert(OpInfo.ConstraintType == TargetLowering::C_Register || 397*5ffd83dbSDimitry Andric OpInfo.ConstraintType == TargetLowering::C_RegisterClass); 398*5ffd83dbSDimitry Andric 399*5ffd83dbSDimitry Andric if (OpInfo.Regs.empty()) { 400*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() 401*5ffd83dbSDimitry Andric << "Couldn't allocate output register for constraint\n"); 402*5ffd83dbSDimitry Andric return false; 403*5ffd83dbSDimitry Andric } 404*5ffd83dbSDimitry Andric 405*5ffd83dbSDimitry Andric // Add information to the INLINEASM instruction to know that this 406*5ffd83dbSDimitry Andric // register is set. 407*5ffd83dbSDimitry Andric unsigned Flag = InlineAsm::getFlagWord( 408*5ffd83dbSDimitry Andric OpInfo.isEarlyClobber ? InlineAsm::Kind_RegDefEarlyClobber 409*5ffd83dbSDimitry Andric : InlineAsm::Kind_RegDef, 410*5ffd83dbSDimitry Andric OpInfo.Regs.size()); 411*5ffd83dbSDimitry Andric if (OpInfo.Regs.front().isVirtual()) { 412*5ffd83dbSDimitry Andric // Put the register class of the virtual registers in the flag word. 413*5ffd83dbSDimitry Andric // That way, later passes can recompute register class constraints for 414*5ffd83dbSDimitry Andric // inline assembly as well as normal instructions. Don't do this for 415*5ffd83dbSDimitry Andric // tied operands that can use the regclass information from the def. 416*5ffd83dbSDimitry Andric const TargetRegisterClass *RC = MRI->getRegClass(OpInfo.Regs.front()); 417*5ffd83dbSDimitry Andric Flag = InlineAsm::getFlagWordForRegClass(Flag, RC->getID()); 418*5ffd83dbSDimitry Andric } 419*5ffd83dbSDimitry Andric 420*5ffd83dbSDimitry Andric Inst.addImm(Flag); 421*5ffd83dbSDimitry Andric 422*5ffd83dbSDimitry Andric for (Register Reg : OpInfo.Regs) { 423*5ffd83dbSDimitry Andric Inst.addReg(Reg, 424*5ffd83dbSDimitry Andric RegState::Define | getImplRegState(Reg.isPhysical()) | 425*5ffd83dbSDimitry Andric (OpInfo.isEarlyClobber ? RegState::EarlyClobber : 0)); 426*5ffd83dbSDimitry Andric } 427*5ffd83dbSDimitry Andric 428*5ffd83dbSDimitry Andric // Remember this output operand for later processing 429*5ffd83dbSDimitry Andric OutputOperands.push_back(OpInfo); 430*5ffd83dbSDimitry Andric } 431*5ffd83dbSDimitry Andric 432*5ffd83dbSDimitry Andric break; 433*5ffd83dbSDimitry Andric case InlineAsm::isInput: { 434*5ffd83dbSDimitry Andric if (OpInfo.isMatchingInputConstraint()) { 435*5ffd83dbSDimitry Andric unsigned DefIdx = OpInfo.getMatchedOperand(); 436*5ffd83dbSDimitry Andric // Find operand with register def that corresponds to DefIdx. 437*5ffd83dbSDimitry Andric unsigned InstFlagIdx = StartIdx; 438*5ffd83dbSDimitry Andric for (unsigned i = 0; i < DefIdx; ++i) 439*5ffd83dbSDimitry Andric InstFlagIdx += getNumOpRegs(*Inst, InstFlagIdx) + 1; 440*5ffd83dbSDimitry Andric assert(getNumOpRegs(*Inst, InstFlagIdx) == 1 && "Wrong flag"); 441*5ffd83dbSDimitry Andric 442*5ffd83dbSDimitry Andric unsigned MatchedOperandFlag = Inst->getOperand(InstFlagIdx).getImm(); 443*5ffd83dbSDimitry Andric if (InlineAsm::isMemKind(MatchedOperandFlag)) { 444*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Matching input constraint to mem operand not " 445*5ffd83dbSDimitry Andric "supported. This should be target specific.\n"); 446*5ffd83dbSDimitry Andric return false; 447*5ffd83dbSDimitry Andric } 448*5ffd83dbSDimitry Andric if (!InlineAsm::isRegDefKind(MatchedOperandFlag) && 449*5ffd83dbSDimitry Andric !InlineAsm::isRegDefEarlyClobberKind(MatchedOperandFlag)) { 450*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Unknown matching constraint\n"); 451*5ffd83dbSDimitry Andric return false; 452*5ffd83dbSDimitry Andric } 453*5ffd83dbSDimitry Andric 454*5ffd83dbSDimitry Andric // We want to tie input to register in next operand. 455*5ffd83dbSDimitry Andric unsigned DefRegIdx = InstFlagIdx + 1; 456*5ffd83dbSDimitry Andric Register Def = Inst->getOperand(DefRegIdx).getReg(); 457*5ffd83dbSDimitry Andric 458*5ffd83dbSDimitry Andric // Copy input to new vreg with same reg class as Def 459*5ffd83dbSDimitry Andric const TargetRegisterClass *RC = MRI->getRegClass(Def); 460*5ffd83dbSDimitry Andric ArrayRef<Register> SrcRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal); 461*5ffd83dbSDimitry Andric assert(SrcRegs.size() == 1 && "Single register is expected here"); 462*5ffd83dbSDimitry Andric Register Tmp = MRI->createVirtualRegister(RC); 463*5ffd83dbSDimitry Andric if (!buildAnyextOrCopy(Tmp, SrcRegs[0], MIRBuilder)) 464*5ffd83dbSDimitry Andric return false; 465*5ffd83dbSDimitry Andric 466*5ffd83dbSDimitry Andric // Add Flag and input register operand (Tmp) to Inst. Tie Tmp to Def. 467*5ffd83dbSDimitry Andric unsigned UseFlag = InlineAsm::getFlagWord(InlineAsm::Kind_RegUse, 1); 468*5ffd83dbSDimitry Andric unsigned Flag = InlineAsm::getFlagWordForMatchingOp(UseFlag, DefIdx); 469*5ffd83dbSDimitry Andric Inst.addImm(Flag); 470*5ffd83dbSDimitry Andric Inst.addReg(Tmp); 471*5ffd83dbSDimitry Andric Inst->tieOperands(DefRegIdx, Inst->getNumOperands() - 1); 472*5ffd83dbSDimitry Andric break; 473*5ffd83dbSDimitry Andric } 474*5ffd83dbSDimitry Andric 475*5ffd83dbSDimitry Andric if (OpInfo.ConstraintType == TargetLowering::C_Other && 476*5ffd83dbSDimitry Andric OpInfo.isIndirect) { 477*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint " 478*5ffd83dbSDimitry Andric "not supported yet\n"); 479*5ffd83dbSDimitry Andric return false; 480*5ffd83dbSDimitry Andric } 481*5ffd83dbSDimitry Andric 482*5ffd83dbSDimitry Andric if (OpInfo.ConstraintType == TargetLowering::C_Immediate || 483*5ffd83dbSDimitry Andric OpInfo.ConstraintType == TargetLowering::C_Other) { 484*5ffd83dbSDimitry Andric 485*5ffd83dbSDimitry Andric std::vector<MachineOperand> Ops; 486*5ffd83dbSDimitry Andric if (!lowerAsmOperandForConstraint(OpInfo.CallOperandVal, 487*5ffd83dbSDimitry Andric OpInfo.ConstraintCode, Ops, 488*5ffd83dbSDimitry Andric MIRBuilder)) { 489*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Don't support constraint: " 490*5ffd83dbSDimitry Andric << OpInfo.ConstraintCode << " yet\n"); 491*5ffd83dbSDimitry Andric return false; 492*5ffd83dbSDimitry Andric } 493*5ffd83dbSDimitry Andric 494*5ffd83dbSDimitry Andric assert(Ops.size() > 0 && 495*5ffd83dbSDimitry Andric "Expected constraint to be lowered to at least one operand"); 496*5ffd83dbSDimitry Andric 497*5ffd83dbSDimitry Andric // Add information to the INLINEASM node to know about this input. 498*5ffd83dbSDimitry Andric unsigned OpFlags = 499*5ffd83dbSDimitry Andric InlineAsm::getFlagWord(InlineAsm::Kind_Imm, Ops.size()); 500*5ffd83dbSDimitry Andric Inst.addImm(OpFlags); 501*5ffd83dbSDimitry Andric Inst.add(Ops); 502*5ffd83dbSDimitry Andric break; 503*5ffd83dbSDimitry Andric } 504*5ffd83dbSDimitry Andric 505*5ffd83dbSDimitry Andric if (OpInfo.ConstraintType == TargetLowering::C_Memory) { 506*5ffd83dbSDimitry Andric 507*5ffd83dbSDimitry Andric if (!OpInfo.isIndirect) { 508*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() 509*5ffd83dbSDimitry Andric << "Cannot indirectify memory input operands yet\n"); 510*5ffd83dbSDimitry Andric return false; 511*5ffd83dbSDimitry Andric } 512*5ffd83dbSDimitry Andric 513*5ffd83dbSDimitry Andric assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!"); 514*5ffd83dbSDimitry Andric 515*5ffd83dbSDimitry Andric unsigned ConstraintID = 516*5ffd83dbSDimitry Andric TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode); 517*5ffd83dbSDimitry Andric unsigned OpFlags = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1); 518*5ffd83dbSDimitry Andric OpFlags = InlineAsm::getFlagWordForMem(OpFlags, ConstraintID); 519*5ffd83dbSDimitry Andric Inst.addImm(OpFlags); 520*5ffd83dbSDimitry Andric ArrayRef<Register> SourceRegs = 521*5ffd83dbSDimitry Andric GetOrCreateVRegs(*OpInfo.CallOperandVal); 522*5ffd83dbSDimitry Andric assert( 523*5ffd83dbSDimitry Andric SourceRegs.size() == 1 && 524*5ffd83dbSDimitry Andric "Expected the memory input to fit into a single virtual register"); 525*5ffd83dbSDimitry Andric Inst.addReg(SourceRegs[0]); 526*5ffd83dbSDimitry Andric break; 527*5ffd83dbSDimitry Andric } 528*5ffd83dbSDimitry Andric 529*5ffd83dbSDimitry Andric assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass || 530*5ffd83dbSDimitry Andric OpInfo.ConstraintType == TargetLowering::C_Register) && 531*5ffd83dbSDimitry Andric "Unknown constraint type!"); 532*5ffd83dbSDimitry Andric 533*5ffd83dbSDimitry Andric if (OpInfo.isIndirect) { 534*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet " 535*5ffd83dbSDimitry Andric "for constraint '" 536*5ffd83dbSDimitry Andric << OpInfo.ConstraintCode << "'\n"); 537*5ffd83dbSDimitry Andric return false; 538*5ffd83dbSDimitry Andric } 539*5ffd83dbSDimitry Andric 540*5ffd83dbSDimitry Andric // Copy the input into the appropriate registers. 541*5ffd83dbSDimitry Andric if (OpInfo.Regs.empty()) { 542*5ffd83dbSDimitry Andric LLVM_DEBUG( 543*5ffd83dbSDimitry Andric dbgs() 544*5ffd83dbSDimitry Andric << "Couldn't allocate input register for register constraint\n"); 545*5ffd83dbSDimitry Andric return false; 546*5ffd83dbSDimitry Andric } 547*5ffd83dbSDimitry Andric 548*5ffd83dbSDimitry Andric unsigned NumRegs = OpInfo.Regs.size(); 549*5ffd83dbSDimitry Andric ArrayRef<Register> SourceRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal); 550*5ffd83dbSDimitry Andric assert(NumRegs == SourceRegs.size() && 551*5ffd83dbSDimitry Andric "Expected the number of input registers to match the number of " 552*5ffd83dbSDimitry Andric "source registers"); 553*5ffd83dbSDimitry Andric 554*5ffd83dbSDimitry Andric if (NumRegs > 1) { 555*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are " 556*5ffd83dbSDimitry Andric "not supported yet\n"); 557*5ffd83dbSDimitry Andric return false; 558*5ffd83dbSDimitry Andric } 559*5ffd83dbSDimitry Andric 560*5ffd83dbSDimitry Andric unsigned Flag = InlineAsm::getFlagWord(InlineAsm::Kind_RegUse, NumRegs); 561*5ffd83dbSDimitry Andric Inst.addImm(Flag); 562*5ffd83dbSDimitry Andric if (!buildAnyextOrCopy(OpInfo.Regs[0], SourceRegs[0], MIRBuilder)) 563*5ffd83dbSDimitry Andric return false; 564*5ffd83dbSDimitry Andric Inst.addReg(OpInfo.Regs[0]); 565*5ffd83dbSDimitry Andric break; 566*5ffd83dbSDimitry Andric } 567*5ffd83dbSDimitry Andric 568*5ffd83dbSDimitry Andric case InlineAsm::isClobber: { 569*5ffd83dbSDimitry Andric 570*5ffd83dbSDimitry Andric unsigned NumRegs = OpInfo.Regs.size(); 571*5ffd83dbSDimitry Andric if (NumRegs > 0) { 572*5ffd83dbSDimitry Andric unsigned Flag = 573*5ffd83dbSDimitry Andric InlineAsm::getFlagWord(InlineAsm::Kind_Clobber, NumRegs); 574*5ffd83dbSDimitry Andric Inst.addImm(Flag); 575*5ffd83dbSDimitry Andric 576*5ffd83dbSDimitry Andric for (Register Reg : OpInfo.Regs) { 577*5ffd83dbSDimitry Andric Inst.addReg(Reg, RegState::Define | RegState::EarlyClobber | 578*5ffd83dbSDimitry Andric getImplRegState(Reg.isPhysical())); 579*5ffd83dbSDimitry Andric } 580*5ffd83dbSDimitry Andric } 581*5ffd83dbSDimitry Andric break; 582*5ffd83dbSDimitry Andric } 583*5ffd83dbSDimitry Andric } 584*5ffd83dbSDimitry Andric } 585*5ffd83dbSDimitry Andric 586*5ffd83dbSDimitry Andric if (const MDNode *SrcLoc = Call.getMetadata("srcloc")) 587*5ffd83dbSDimitry Andric Inst.addMetadata(SrcLoc); 588*5ffd83dbSDimitry Andric 589*5ffd83dbSDimitry Andric // All inputs are handled, insert the instruction now 590*5ffd83dbSDimitry Andric MIRBuilder.insertInstr(Inst); 591*5ffd83dbSDimitry Andric 592*5ffd83dbSDimitry Andric // Finally, copy the output operands into the output registers 593*5ffd83dbSDimitry Andric ArrayRef<Register> ResRegs = GetOrCreateVRegs(Call); 594*5ffd83dbSDimitry Andric if (ResRegs.size() != OutputOperands.size()) { 595*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Expected the number of output registers to match the " 596*5ffd83dbSDimitry Andric "number of destination registers\n"); 597*5ffd83dbSDimitry Andric return false; 598*5ffd83dbSDimitry Andric } 599*5ffd83dbSDimitry Andric for (unsigned int i = 0, e = ResRegs.size(); i < e; i++) { 600*5ffd83dbSDimitry Andric GISelAsmOperandInfo &OpInfo = OutputOperands[i]; 601*5ffd83dbSDimitry Andric 602*5ffd83dbSDimitry Andric if (OpInfo.Regs.empty()) 603*5ffd83dbSDimitry Andric continue; 604*5ffd83dbSDimitry Andric 605*5ffd83dbSDimitry Andric switch (OpInfo.ConstraintType) { 606*5ffd83dbSDimitry Andric case TargetLowering::C_Register: 607*5ffd83dbSDimitry Andric case TargetLowering::C_RegisterClass: { 608*5ffd83dbSDimitry Andric if (OpInfo.Regs.size() > 1) { 609*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Output operands with multiple defining " 610*5ffd83dbSDimitry Andric "registers are not supported yet\n"); 611*5ffd83dbSDimitry Andric return false; 612*5ffd83dbSDimitry Andric } 613*5ffd83dbSDimitry Andric 614*5ffd83dbSDimitry Andric Register SrcReg = OpInfo.Regs[0]; 615*5ffd83dbSDimitry Andric unsigned SrcSize = TRI->getRegSizeInBits(SrcReg, *MRI); 616*5ffd83dbSDimitry Andric if (MRI->getType(ResRegs[i]).getSizeInBits() < SrcSize) { 617*5ffd83dbSDimitry Andric // First copy the non-typed virtual register into a generic virtual 618*5ffd83dbSDimitry Andric // register 619*5ffd83dbSDimitry Andric Register Tmp1Reg = 620*5ffd83dbSDimitry Andric MRI->createGenericVirtualRegister(LLT::scalar(SrcSize)); 621*5ffd83dbSDimitry Andric MIRBuilder.buildCopy(Tmp1Reg, SrcReg); 622*5ffd83dbSDimitry Andric // Need to truncate the result of the register 623*5ffd83dbSDimitry Andric MIRBuilder.buildTrunc(ResRegs[i], Tmp1Reg); 624*5ffd83dbSDimitry Andric } else { 625*5ffd83dbSDimitry Andric MIRBuilder.buildCopy(ResRegs[i], SrcReg); 626*5ffd83dbSDimitry Andric } 627*5ffd83dbSDimitry Andric break; 628*5ffd83dbSDimitry Andric } 629*5ffd83dbSDimitry Andric case TargetLowering::C_Immediate: 630*5ffd83dbSDimitry Andric case TargetLowering::C_Other: 631*5ffd83dbSDimitry Andric LLVM_DEBUG( 632*5ffd83dbSDimitry Andric dbgs() << "Cannot lower target specific output constraints yet\n"); 633*5ffd83dbSDimitry Andric return false; 634*5ffd83dbSDimitry Andric case TargetLowering::C_Memory: 635*5ffd83dbSDimitry Andric break; // Already handled. 636*5ffd83dbSDimitry Andric case TargetLowering::C_Unknown: 637*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Unexpected unknown constraint\n"); 638*5ffd83dbSDimitry Andric return false; 639*5ffd83dbSDimitry Andric } 640*5ffd83dbSDimitry Andric } 641*5ffd83dbSDimitry Andric 642*5ffd83dbSDimitry Andric return true; 643*5ffd83dbSDimitry Andric } 644*5ffd83dbSDimitry Andric 645*5ffd83dbSDimitry Andric bool InlineAsmLowering::lowerAsmOperandForConstraint( 646*5ffd83dbSDimitry Andric Value *Val, StringRef Constraint, std::vector<MachineOperand> &Ops, 647*5ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder) const { 648*5ffd83dbSDimitry Andric if (Constraint.size() > 1) 649*5ffd83dbSDimitry Andric return false; 650*5ffd83dbSDimitry Andric 651*5ffd83dbSDimitry Andric char ConstraintLetter = Constraint[0]; 652*5ffd83dbSDimitry Andric switch (ConstraintLetter) { 653*5ffd83dbSDimitry Andric default: 654*5ffd83dbSDimitry Andric return false; 655*5ffd83dbSDimitry Andric case 'i': // Simple Integer or Relocatable Constant 656*5ffd83dbSDimitry Andric if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) { 657*5ffd83dbSDimitry Andric assert(CI->getBitWidth() <= 64 && 658*5ffd83dbSDimitry Andric "expected immediate to fit into 64-bits"); 659*5ffd83dbSDimitry Andric // Boolean constants should be zero-extended, others are sign-extended 660*5ffd83dbSDimitry Andric bool IsBool = CI->getBitWidth() == 1; 661*5ffd83dbSDimitry Andric int64_t ExtVal = IsBool ? CI->getZExtValue() : CI->getSExtValue(); 662*5ffd83dbSDimitry Andric Ops.push_back(MachineOperand::CreateImm(ExtVal)); 663*5ffd83dbSDimitry Andric return true; 664*5ffd83dbSDimitry Andric } 665*5ffd83dbSDimitry Andric return false; 666*5ffd83dbSDimitry Andric } 667*5ffd83dbSDimitry Andric } 668