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