brintos

brintos / llvm-project-archived public Read only

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