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 @@ -11637,24 +11637,6 @@ return Reg; } -static size_t PopulateResultValues(const CallBrInst &CBR, SelectionDAG &DAG, - SmallVectorImpl &ResultVTs, - SmallVectorImpl &ResultValues) { - Type *CBRType = CBR.getType(); - assert(!CBRType->isVoidTy() && - "callbr landing pad for callbr without returns"); - ArrayRef ResultTypes = CBRType->isStructTy() - ? cast(CBRType)->elements() - : ArrayRef(CBRType); - size_t NumReturnValues = ResultTypes.size(); - ResultVTs.reserve(NumReturnValues); - ResultValues.reserve(NumReturnValues); - const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - for (Type *T : ResultTypes) - ResultVTs.emplace_back(TLI.getValueType(DAG.getDataLayout(), T)); - return NumReturnValues; -} - // We must do this walk rather than the simpler // setValue(&I, getCopyFromRegs(CBR, CBR->getType())); // otherwise we will end up with copies of virtregs only valid along direct @@ -11664,20 +11646,53 @@ SmallVector ResultValues; const auto *CBR = cast(I.getParent()->getUniquePredecessor()->getTerminator()); - const size_t NumReturnValues = - PopulateResultValues(*CBR, DAG, ResultVTs, ResultValues); - MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo(); + + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + TargetLowering::AsmOperandInfoVector TargetConstraints = TLI.ParseConstraints( + DAG.getDataLayout(), DAG.getSubtarget().getRegisterInfo(), *CBR); + unsigned Reg = FuncInfo.ValueMap[CBR]; + MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo(); SDValue Chain = DAG.getRoot(); + SmallVector ConstraintOperands; + // This loop is necessary for the hasMatchingInput machinery below. + for (auto &T : TargetConstraints) + ConstraintOperands.emplace_back(T); + for (SDISelAsmOperandInfo &OpInfo : ConstraintOperands) { + if (OpInfo.Type != InlineAsm::isOutput) + continue; - for (size_t i = 0; i != NumReturnValues; ++i, ++Reg) { - Register Output = FollowCopyChain(MRI, Reg); + if (OpInfo.hasMatchingInput()) { + SDISelAsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; + patchMatchingInput(OpInfo, Input, DAG); + } - if (Register::isPhysicalRegister(Output)) - FuncInfo.MBB->addLiveIn(Output); + TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG); - SDValue V = DAG.getCopyFromReg(Chain, getCurSDLoc(), Output, ResultVTs[i]); - ResultValues.push_back(V); + switch (OpInfo.ConstraintType) { + case TargetLowering::C_Register: + case TargetLowering::C_RegisterClass: { + Register Output = FollowCopyChain(MRI, Reg++); + if (Register::isPhysicalRegister(Output)) + FuncInfo.MBB->addLiveIn(Output); + SDValue V = + DAG.getCopyFromReg(Chain, getCurSDLoc(), Output, OpInfo.ConstraintVT); + ResultValues.push_back(V); + ResultVTs.push_back(OpInfo.ConstraintVT); + break; + } + case TargetLowering::C_Other: { + SDValue Flag; + SDValue V = TLI.LowerAsmOutputForConstraint(Chain, Flag, getCurSDLoc(), + OpInfo, DAG); + ++Reg; + ResultValues.push_back(V); + ResultVTs.push_back(OpInfo.ConstraintVT); + break; + } + default: + break; + } } SDValue V = DAG.getNode(ISD::MERGE_VALUES, getCurSDLoc(), DAG.getVTList(ResultVTs), ResultValues); diff --git a/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel-m32.ll b/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel-m32.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel-m32.ll @@ -0,0 +1,80 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -mtriple=i386-linux-gnu %s -o - -stop-after=finalize-isel \ +; RUN: -start-before=x86-isel | FileCheck %s + +define i8 @emulator_cmpxchg_emulated() { + ; CHECK-LABEL: name: emulator_cmpxchg_emulated + ; CHECK: bb.0.entry: + ; CHECK-NEXT: successors: %bb.1(0x80000000), %bb.2(0x00000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm $noreg, 1, $noreg, 0, $noreg :: (load (s32) from `ptr null`, align 8) + ; CHECK-NEXT: INLINEASM_BR &"", 16 /* maystore attdialect */, 2359306 /* regdef:GR32 */, def %2, 2359306 /* regdef:GR32 */, def %3, 2147549193 /* reguse tiedto:$1 */, [[MOV32rm]](tied-def 5), 13 /* imm */, %bb.2 + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr32 = COPY $eflags + ; CHECK-NEXT: $eflags = COPY [[COPY]] + ; CHECK-NEXT: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr32 = COPY %3 + ; CHECK-NEXT: JMP_1 %bb.1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1.asm.fallthrough: + ; CHECK-NEXT: $al = COPY [[SETCCr]] + ; CHECK-NEXT: RET 0, $al + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2.efaultu64.split (machine-block-address-taken, inlineasm-br-indirect-target): + ; CHECK-NEXT: [[SETCCr1:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK-NEXT: $al = COPY [[SETCCr1]] + ; CHECK-NEXT: RET 0, $al +entry: + %0 = load i32, ptr null, align 8 + %1 = callbr { i8, i32 } asm "", "={@ccz},=r,1,!i"(i32 %0) + to label %asm.fallthrough [label %efaultu64.split] + +asm.fallthrough: + %asmresult = extractvalue { i8, i32 } %1, 0 + %asmresult1 = extractvalue { i8, i32 } %1, 1 + ret i8 %asmresult + +efaultu64.split: + %2 = call { i8, i32 } @llvm.callbr.landingpad.sl_i8i32s({ i8, i32 } %1) + %asmresult2 = extractvalue { i8, i32 } %2, 0 + %asmresult3 = extractvalue { i8, i32 } %2, 1 + ret i8 %asmresult2 +} + +; Same test but return second value +define i32 @emulator_cmpxchg_emulated2() { + ; CHECK-LABEL: name: emulator_cmpxchg_emulated2 + ; CHECK: bb.0.entry: + ; CHECK-NEXT: successors: %bb.1(0x80000000), %bb.2(0x00000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm $noreg, 1, $noreg, 0, $noreg :: (load (s32) from `ptr null`, align 8) + ; CHECK-NEXT: INLINEASM_BR &"", 16 /* maystore attdialect */, 2359306 /* regdef:GR32 */, def %2, 2359306 /* regdef:GR32 */, def %3, 2147549193 /* reguse tiedto:$1 */, [[MOV32rm]](tied-def 5), 13 /* imm */, %bb.2 + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr32 = COPY $eflags + ; CHECK-NEXT: $eflags = COPY [[COPY]] + ; CHECK-NEXT: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr32 = COPY %3 + ; CHECK-NEXT: JMP_1 %bb.1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1.asm.fallthrough: + ; CHECK-NEXT: $eax = COPY [[COPY1]] + ; CHECK-NEXT: RET 0, $eax + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2.efaultu64.split (machine-block-address-taken, inlineasm-br-indirect-target): + ; CHECK-NEXT: $eax = COPY %3 + ; CHECK-NEXT: RET 0, $eax +entry: + %0 = load i32, ptr null, align 8 + %1 = callbr { i8, i32 } asm "", "={@ccz},=r,1,!i"(i32 %0) + to label %asm.fallthrough [label %efaultu64.split] + +asm.fallthrough: + %asmresult = extractvalue { i8, i32 } %1, 0 + %asmresult1 = extractvalue { i8, i32 } %1, 1 + ret i32 %asmresult1 + +efaultu64.split: + %2 = call { i8, i32 } @llvm.callbr.landingpad.sl_i8i32s({ i8, i32 } %1) + %asmresult2 = extractvalue { i8, i32 } %2, 0 + %asmresult3 = extractvalue { i8, i32 } %2, 1 + ret i32 %asmresult3 +} +declare { i8, i32 } @llvm.callbr.landingpad.sl_i8i32s({ i8, i32 }) diff --git a/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel.ll b/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel.ll --- a/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel.ll +++ b/llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel.ll @@ -331,6 +331,38 @@ ret i32 %indirect } +define i64 @condition_code() { + ; CHECK-LABEL: name: condition_code + ; CHECK: bb.0 (%ir-block.0): + ; CHECK-NEXT: successors: %bb.1(0x80000000), %bb.2(0x00000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: INLINEASM_BR &"", 16 /* maystore attdialect */, 2359306 /* regdef:GR32 */, def %1, 13 /* imm */, %bb.2 + ; CHECK-NEXT: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK-NEXT: [[MOVZX32rr8_:%[0-9]+]]:gr32 = MOVZX32rr8 killed [[SETCCr]] + ; CHECK-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, killed [[MOVZX32rr8_]], %subreg.sub_32bit + ; CHECK-NEXT: JMP_1 %bb.1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1.b: + ; CHECK-NEXT: $rax = COPY [[SUBREG_TO_REG]] + ; CHECK-NEXT: RET 0, $rax + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2.c (machine-block-address-taken, inlineasm-br-indirect-target): + ; CHECK-NEXT: [[SETCCr1:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK-NEXT: [[MOVZX32rr8_1:%[0-9]+]]:gr32 = MOVZX32rr8 killed [[SETCCr1]] + ; CHECK-NEXT: [[SUBREG_TO_REG1:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, killed [[MOVZX32rr8_1]], %subreg.sub_32bit + ; CHECK-NEXT: $rax = COPY [[SUBREG_TO_REG1]] + ; CHECK-NEXT: RET 0, $rax + %a = callbr i64 asm "", "={@ccz},!i"() + to label %b [label %c] + +b: + ret i64 %a + +c: + %1 = call i64 @llvm.callbr.landingpad.i64(i64 %a) + ret i64 %1 +} + declare i64 @llvm.callbr.landingpad.i64(i64) declare i32 @llvm.callbr.landingpad.i32(i32) declare { i32, i32 } @llvm.callbr.landingpad.sl_i32i32s({ i32, i32 })