diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -4130,6 +4130,19 @@ /// unsigned getNumIndirectDests() const { return NumIndirectDests; } + /// Given an argument number, is that argument an indirect destination? + /// + bool isArgNoAnIndirectDest(unsigned ArgNo) const { + if (ArgNo < arg_size()) + if (Value *Arg = getArgOperand(ArgNo)) + if (const auto *BA = dyn_cast(Arg)) + if (const BasicBlock *BB = BA->getBasicBlock()) { + const auto ID = getIndirectDests(); + return llvm::find(ID, BB) != ID.end(); + } + return false; + } + /// getIndirectDestLabel - Return the i-th indirect dest label. /// Value *getIndirectDestLabel(unsigned i) const { diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8557,7 +8557,8 @@ unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. unsigned ResNo = 0; // ResNo - The result number of the next output. - unsigned NumMatchingOps = 0; + const auto *CBR = dyn_cast(&Call); + for (auto &T : TargetConstraints) { ConstraintOperands.push_back(SDISelAsmOperandInfo(T)); SDISelAsmOperandInfo &OpInfo = ConstraintOperands.back(); @@ -8565,18 +8566,9 @@ // Compute the value type for each operand. if (OpInfo.Type == InlineAsm::isInput || (OpInfo.Type == InlineAsm::isOutput && OpInfo.isIndirect)) { - OpInfo.CallOperandVal = Call.getArgOperand(ArgNo++); - - // Process the call argument. BasicBlocks are labels, currently appearing - // only in asm's. - if (isa(Call) && - ArgNo - 1 >= (cast(&Call)->arg_size() - - cast(&Call)->getNumIndirectDests() - - NumMatchingOps) && - (NumMatchingOps == 0 || - ArgNo - 1 < - (cast(&Call)->arg_size() - NumMatchingOps))) { - const auto *BA = cast(OpInfo.CallOperandVal); + OpInfo.CallOperandVal = Call.getArgOperand(ArgNo); + if (CBR && CBR->isArgNoAnIndirectDest(ArgNo)) { + const auto *BA = dyn_cast(OpInfo.CallOperandVal); EVT VT = TLI.getValueType(DAG.getDataLayout(), BA->getType(), true); OpInfo.CallOperand = DAG.getTargetBlockAddress(BA, VT); } else if (const auto *BB = dyn_cast(OpInfo.CallOperandVal)) { @@ -8588,6 +8580,7 @@ EVT VT = OpInfo.getCallOperandValEVT(*DAG.getContext(), TLI, DAG.getDataLayout()); OpInfo.ConstraintVT = VT.isSimple() ? VT.getSimpleVT() : MVT::Other; + ++ArgNo; } else if (OpInfo.Type == InlineAsm::isOutput && !OpInfo.isIndirect) { // The return value of the call is this value. As such, there is no // corresponding argument. @@ -8605,9 +8598,6 @@ OpInfo.ConstraintVT = MVT::Other; } - if (OpInfo.hasMatchingInput()) - ++NumMatchingOps; - if (!HasSideEffect) HasSideEffect = OpInfo.hasMemory(TLI); diff --git a/llvm/test/CodeGen/X86/callbr-asm-outputs.ll b/llvm/test/CodeGen/X86/callbr-asm-outputs.ll --- a/llvm/test/CodeGen/X86/callbr-asm-outputs.ll +++ b/llvm/test/CodeGen/X86/callbr-asm-outputs.ll @@ -204,3 +204,31 @@ %retval.0 = phi i32 [ %add, %asm.fallthrough2 ], [ -2, %label_true ], [ -1, %asm.fallthrough ], [ -1, %entry ] ret i32 %retval.0 } + +; Test5 - test that we don't rely on a positional constraint. ie. +r in +; GCCAsmStmt being turned into "={esp},0" since after D87279 they're turned +; into "={esp},{esp}". This previously caused an ICE; this test is more so +; about avoiding another ICE than what the actual output is. +define dso_local void @test5() { +; CHECK-LABEL: test5: +; CHECK: # %bb.0: +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: .Ltmp6: # Block address taken +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: retl + %1 = call i32 @llvm.read_register.i32(metadata !3) + %2 = callbr i32 asm "", "={esp},X,{esp},~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test5, %4), i32 %1) + to label %3 [label %4] + +3: + call void @llvm.write_register.i32(metadata !3, i32 %2) + br label %4 + +4: + ret void +} + +declare i32 @llvm.read_register.i32(metadata) +declare void @llvm.write_register.i32(metadata, i32) +!3 = !{!"esp"}