4 changes: 4 additions & 0 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2544,6 +2544,10 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
MF.getFunction()->hasStructRetAttr(), CLI.RetTy,
Outs, OutVals, Ins, DAG);

if (!isTailCall && CLI.CS && CLI.CS->isMustTailCall())
report_fatal_error("failed to perform tail call elimination on a call "
"site marked musttail");

// Sibcalls are automatically detected tailcalls which do not require
// ABI changes.
if (!MF.getTarget().Options.GuaranteedTailCallOpt && isTailCall)
Expand Down
17 changes: 17 additions & 0 deletions llvm/test/Bitcode/tailcall.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; RUN: llvm-as < %s | llvm-dis | FileCheck %s

; Check that musttail and tail roundtrip.

declare cc8191 void @t1_callee()
define cc8191 void @t1() {
; CHECK: tail call cc8191 void @t1_callee()
tail call cc8191 void @t1_callee()
ret void
}

declare cc8191 void @t2_callee()
define cc8191 void @t2() {
; CHECK: musttail call cc8191 void @t2_callee()
musttail call cc8191 void @t2_callee()
ret void
}
23 changes: 23 additions & 0 deletions llvm/test/CodeGen/X86/musttail.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
; RUN: llc -march=x86 < %s | FileCheck %s

; FIXME: Eliminate this tail call at -O0, since musttail is a correctness
; requirement.
; RUN: not llc -march=x86 -O0 < %s

declare void @t1_callee(i8*)
define void @t1(i32* %a) {
; CHECK-LABEL: t1:
; CHECK: jmp {{_?}}t1_callee
%b = bitcast i32* %a to i8*
musttail call void @t1_callee(i8* %b)
ret void
}

declare i8* @t2_callee()
define i32* @t2() {
; CHECK-LABEL: t2:
; CHECK: jmp {{_?}}t2_callee
%v = musttail call i8* @t2_callee()
%w = bitcast i8* %v to i32*
ret i32* %w
}
75 changes: 75 additions & 0 deletions llvm/test/Verifier/musttail-invalid.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s

; Each musttail call should fail to validate.

declare x86_stdcallcc void @cc_mismatch_callee()
define void @cc_mismatch() {
; CHECK: mismatched calling conv
musttail call x86_stdcallcc void @cc_mismatch_callee()
ret void
}

declare void @more_parms_callee(i32)
define void @more_parms() {
; CHECK: mismatched parameter counts
musttail call void @more_parms_callee(i32 0)
ret void
}

declare void @mismatched_intty_callee(i8)
define void @mismatched_intty(i32) {
; CHECK: mismatched parameter types
musttail call void @mismatched_intty_callee(i8 0)
ret void
}

declare void @mismatched_vararg_callee(i8*, ...)
define void @mismatched_vararg(i8*) {
; CHECK: mismatched varargs
musttail call void (i8*, ...)* @mismatched_vararg_callee(i8* null)
ret void
}

; We would make this an implicit sret parameter, which would disturb the
; tail call.
declare { i32, i32, i32 } @mismatched_retty_callee(i32)
define void @mismatched_retty(i32) {
; CHECK: mismatched return types
musttail call { i32, i32, i32 } @mismatched_retty_callee(i32 0)
ret void
}

declare void @mismatched_byval_callee({ i32 }*)
define void @mismatched_byval({ i32 }* byval %a) {
; CHECK: mismatched ABI impacting function attributes
musttail call void @mismatched_byval_callee({ i32 }* %a)
ret void
}

declare void @mismatched_inreg_callee(i32 inreg)
define void @mismatched_inreg(i32 %a) {
; CHECK: mismatched ABI impacting function attributes
musttail call void @mismatched_inreg_callee(i32 inreg %a)
ret void
}

declare void @mismatched_sret_callee(i32* sret)
define void @mismatched_sret(i32* %a) {
; CHECK: mismatched ABI impacting function attributes
musttail call void @mismatched_sret_callee(i32* sret %a)
ret void
}

declare i32 @not_tail_pos_callee()
define i32 @not_tail_pos() {
; CHECK: musttail call must be precede a ret with an optional bitcast
%v = musttail call i32 @not_tail_pos_callee()
%w = add i32 %v, 1
ret i32 %w
}

define void @inline_asm() {
; CHECK: cannot use musttail call with inline asm
musttail call void asm "ret", ""()
ret void
}
16 changes: 16 additions & 0 deletions llvm/test/Verifier/musttail-valid.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
; RUN: llvm-as %s -o /dev/null

; Should assemble without error.

declare void @similar_param_ptrty_callee(i8*)
define void @similar_param_ptrty(i32*) {
musttail call void @similar_param_ptrty_callee(i8* null)
ret void
}

declare i8* @similar_ret_ptrty_callee()
define i32* @similar_ret_ptrty() {
%v = musttail call i8* @similar_ret_ptrty_callee()
%w = bitcast i8* %v to i32*
ret i32* %w
}