Index: llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp +++ llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp @@ -232,6 +232,11 @@ } } +static unsigned getNumOpRegs(MachineInstr *I, unsigned OpIdx) { + unsigned Flag = I->getOperand(OpIdx).getImm(); + return InlineAsm::getNumOperandRegisters(Flag); +} + bool InlineAsmLowering::lowerInlineAsm( MachineIRBuilder &MIRBuilder, const CallBase &Call, std::function(const Value &Val)> GetOrCreateVRegs) @@ -317,6 +322,10 @@ .addExternalSymbol(IA->getAsmString().c_str()) .addImm(ExtraInfo.get()); + // Starting from this operand: flag followed by register(s) will be added as + // operands to Inst for each constraint. Used for matching input constraints. + unsigned StartIdx = Inst->getNumOperands(); + // Collects the output operands for later processing GISelAsmOperandInfoVector OutputOperands; @@ -390,8 +399,31 @@ break; case InlineAsm::isInput: { if (OpInfo.isMatchingInputConstraint()) { - LLVM_DEBUG(dbgs() << "Tied input operands not supported yet\n"); - return false; + unsigned DefIdx = OpInfo.getMatchedOperand(); + // Find operand with register def that corresponds to DefIdx. + unsigned InstFlagIdx = StartIdx; + for (unsigned i = 0; i < DefIdx; ++i) + InstFlagIdx += getNumOpRegs(Inst, InstFlagIdx) + 1; + assert(getNumOpRegs(Inst, InstFlagIdx) == 1 && "Wrong flag"); + + // We want to tie input to register in next operand. + unsigned DefRegIdx = InstFlagIdx + 1; + Register Def = Inst->getOperand(DefRegIdx).getReg(); + + // Copy input to new vreg with same reg class as Def + const TargetRegisterClass *RC = MRI->getRegClass(Def); + ArrayRef SrcRegs = GetOrCreateVRegs(*OpInfo.CallOperandVal); + assert(SrcRegs.size() == 1 && "Single register is expected here"); + Register Tmp = MRI->createVirtualRegister(RC); + MIRBuilder.buildCopy(Tmp, SrcRegs[0]); + + // Add Flag and input register operand (Tmp) to Inst. Tie Tmp to Def. + unsigned UseFlag = InlineAsm::getFlagWord(InlineAsm::Kind_RegUse, 1); + unsigned Flag = InlineAsm::getFlagWordForMatchingOp(UseFlag, DefIdx); + Inst.addImm(Flag); + Inst.addReg(Tmp); + Inst->tieOperands(DefRegIdx, Inst->getNumOperands() - 1); + break; } if (OpInfo.ConstraintType == TargetLowering::C_Other && Index: llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll +++ llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll @@ -234,4 +234,61 @@ ret i32 %1 } +define i32 @test_matching_constraint(i32 %a) nounwind { + ; CHECK-LABEL: name: test_matching_constraint + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $vgpr0, $sgpr30_sgpr31 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0 + ; CHECK: [[COPY1:%[0-9]+]]:sgpr_64 = COPY $sgpr30_sgpr31 + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY]], [[C]] + ; CHECK: [[COPY2:%[0-9]+]]:vgpr_32 = COPY [[AND]](s32) + ; CHECK: INLINEASM &"; ", 1 /* sideeffect attdialect */, 1835018 /* regdef:VGPR_32 */, def %4, 2147483657 /* reguse tiedto:$0 */, [[COPY2]](tied-def 3) + ; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY %4 + ; CHECK: $vgpr0 = COPY [[COPY3]](s32) + ; CHECK: [[COPY4:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY1]] + ; CHECK: S_SETPC_B64_return [[COPY4]], implicit $vgpr0 + %1 = and i32 %a, 1 + %2 = call i32 asm sideeffect "; ", "=v,0"(i32 %1) + ret i32 %2 +} + +define void @test_many_matching_constraint(i32 %a, i32 %b, i32 %c) nounwind { + ; CHECK-LABEL: name: test_many_matching_constraint + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $vgpr0, $vgpr1, $vgpr2, $sgpr30_sgpr31 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1 + ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2 + ; CHECK: [[COPY3:%[0-9]+]]:sgpr_64 = COPY $sgpr30_sgpr31 + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; CHECK: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF + ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[COPY]], [[C]] + ; CHECK: [[AND1:%[0-9]+]]:_(s32) = G_AND [[COPY1]], [[C]] + ; CHECK: [[AND2:%[0-9]+]]:_(s32) = G_AND [[COPY2]], [[C]] + ; CHECK: [[COPY4:%[0-9]+]]:vgpr_32 = COPY [[AND2]](s32) + ; CHECK: [[COPY5:%[0-9]+]]:vgpr_32 = COPY [[AND]](s32) + ; CHECK: [[COPY6:%[0-9]+]]:vgpr_32 = COPY [[AND1]](s32) + ; CHECK: INLINEASM &"; ", 1 /* sideeffect attdialect */, 1835018 /* regdef:VGPR_32 */, def %8, 1835018 /* regdef:VGPR_32 */, def %9, 1835018 /* regdef:VGPR_32 */, def %10, 2147483657 /* reguse tiedto:$0 */, [[COPY4]](tied-def 3), 2147614729 /* reguse tiedto:$2 */, [[COPY5]](tied-def 7), 2147549193 /* reguse tiedto:$1 */, [[COPY6]](tied-def 5) + ; CHECK: [[COPY7:%[0-9]+]]:_(s32) = COPY %8 + ; CHECK: [[COPY8:%[0-9]+]]:_(s32) = COPY %9 + ; CHECK: [[COPY9:%[0-9]+]]:_(s32) = COPY %10 + ; CHECK: G_STORE [[COPY7]](s32), [[DEF]](p1) :: (store 4 into `i32 addrspace(1)* undef`, addrspace 1) + ; CHECK: G_STORE [[COPY8]](s32), [[DEF]](p1) :: (store 4 into `i32 addrspace(1)* undef`, addrspace 1) + ; CHECK: G_STORE [[COPY9]](s32), [[DEF]](p1) :: (store 4 into `i32 addrspace(1)* undef`, addrspace 1) + ; CHECK: [[COPY10:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY3]] + ; CHECK: S_SETPC_B64_return [[COPY10]] + %1 = and i32 %a, 1 + %2 = and i32 %b, 1 + %3 = and i32 %c, 1 + %4 = call {i32, i32, i32} asm sideeffect "; ", "=v,=v,=v,0,2,1"(i32 %3, i32 %1, i32 %2) + %5 = extractvalue {i32, i32, i32} %4, 0 + store i32 %5, i32 addrspace(1)* undef + %6 = extractvalue {i32, i32, i32} %4, 1 + store i32 %6, i32 addrspace(1)* undef + %7 = extractvalue {i32, i32, i32} %4, 2 + store i32 %7, i32 addrspace(1)* undef + ret void +} + !0 = !{i32 70}