diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7153,6 +7153,12 @@ establishes an association with additional labels to define where control flow goes after the call. +Outputs of a '``callbr``' instruction are valid only on the '``normal``' path. +Use of outputs on the '``other``' path(s) results in :ref:`poison values +`. Care should be taken if the '``normal``' block is also listed +in the '``other``' blocks. The outputs may or may not result in :ref:`poison +values ` depending on the behavior of the inline assembly. + The only use of this today is to implement the "goto" feature of gcc inline assembly where additional labels can be provided as locations for the inline assembly to jump to. @@ -7160,10 +7166,15 @@ Example: """""""" -.. code-block:: text +.. code-block:: llvm - callbr void asm "", "r,x"(i32 %x, i8 *blockaddress(@foo, %fail)) - to label %normal [label %fail] + ; "asm goto" without output constraints. + callbr void asm "", "r,X"(i32 %x, i8 *blockaddress(@foo, %abnormal)) + to label %normal [label %abnormal] + + ; "asm goto" with output constraints. + = callbr i32 asm "", "=r,r,X"(i32 %x, i8 *blockaddress(@foo, %abnormal)) + to label %normal [label %abnormal] .. _i_resume: diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -6416,9 +6416,6 @@ /*IsCall=*/true)) return true; - if (isa(Callee) && !Ty->getReturnType()->isVoidTy()) - return Error(RetTypeLoc, "asm-goto outputs not supported"); - // Set up the Attribute for the function. SmallVector Args; SmallVector ArgAttrs; 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 @@ -2834,6 +2834,7 @@ assert(isa(I.getCalledValue()) && "Only know how to handle inlineasm callbr"); visitInlineAsm(&I); + CopyToExportRegsIfNeeded(&I); // Retrieve successors. MachineBasicBlock *Return = FuncInfo.MBBMap[I.getDefaultDest()]; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2492,8 +2492,6 @@ void Verifier::visitCallBrInst(CallBrInst &CBI) { Assert(CBI.isInlineAsm(), "Callbr is currently only used for asm-goto!", &CBI); - Assert(CBI.getType()->isVoidTy(), "Callbr return value is not supported!", - &CBI); for (unsigned i = 0, e = CBI.getNumSuccessors(); i != e; ++i) Assert(CBI.getSuccessor(i)->getType()->isLabelTy(), "Callbr successors must all have pointer type!", &CBI); 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 @@ -1,18 +1,26 @@ -; RUN: not llc -mtriple=i686-- < %s 2> %t -; RUN: FileCheck %s < %t +; RUN: llc -mtriple=i686-- < %s | FileCheck %s -; CHECK: error: asm-goto outputs not supported +; A test for asm-goto output -; A test for asm-goto output prohibition - -define i32 @test(i32 %a) { +; CHECK-LABEL: test1: +; CHECK: movl 4(%esp), %eax +; CHECK-NEXT: addl $4, %eax +; CHECK-NEXT: #APP +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: jmp .Ltmp0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: .LBB0_1: +; CHECK-NEXT: retl +; CHECK-NEXT: .Ltmp0: +define i32 @test1(i32 %x) { entry: - %0 = add i32 %a, 4 - %1 = callbr i32 asm "xorl $1, $1; jmp ${1:l}", "=&r,r,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@test, %fail)) to label %normal [label %fail] + %add = add nsw i32 %x, 4 + %ret = callbr i32 asm "xorl $1, $0; jmp ${2:l}", "=r,r,X,~{dirflag},~{fpsr},~{flags}"(i32 %add, i8* blockaddress(@test1, %abnormal)) + to label %normal [label %abnormal] normal: - ret i32 %1 + ret i32 %ret -fail: +abnormal: ret i32 1 }