Skip to content

Commit 932756a

Browse files
nikicdyung
authored andcommitted
[X86][FastISel] Restore support for struct returns (llvm#194586)
After llvm#180322, X86 FastISel forces SDAG fallback for any call with a struct return. This caused major compile-time regressions for debug builds in Rust, where struct returns are very common. The type legality check should work on the de-aggregated types, not on the return type directly. (cherry picked from commit 30fa415)
1 parent 19f65f3 commit 932756a

3 files changed

Lines changed: 105 additions & 12 deletions

File tree

llvm/lib/Target/X86/X86FastISel.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "X86Subtarget.h"
2222
#include "X86TargetMachine.h"
2323
#include "llvm/Analysis/BranchProbabilityInfo.h"
24+
#include "llvm/CodeGen/Analysis.h"
2425
#include "llvm/CodeGen/FastISel.h"
2526
#include "llvm/CodeGen/FunctionLoweringInfo.h"
2627
#include "llvm/CodeGen/MachineConstantPool.h"
@@ -3273,18 +3274,22 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
32733274
// the value from FuncInfo.ValueMap.
32743275
// However, i1 is promoted to i8 and return i8 defined by ABI, so FastISel can
32753276
// lower it without switching to DAGISel.
3276-
MVT RetVT = MVT::Other;
3277-
if (!isTypeLegal(CLI.RetTy, RetVT) && !CLI.RetTy->isVoidTy()) {
3278-
if (RetVT == MVT::Other)
3279-
return false; // Unknown type, let DAG ISel handle it.
3280-
3281-
// RetVT is not MVT::Other, it must be simple now. It is something rely on
3282-
// the logic of isTypeLegal().
3283-
MVT ABIVT = TLI.getRegisterTypeForCallingConv(CLI.RetTy->getContext(),
3284-
CLI.CallConv, RetVT);
3285-
MVT RegVT = TLI.getRegisterType(CLI.RetTy->getContext(), RetVT);
3286-
if (ABIVT != RegVT)
3287-
return false;
3277+
SmallVector<Type *> RetTys;
3278+
ComputeValueTypes(DL, CLI.RetTy, RetTys);
3279+
for (Type *RetTy : RetTys) {
3280+
MVT RetVT = MVT::Other;
3281+
if (!isTypeLegal(RetTy, RetVT)) {
3282+
if (RetVT == MVT::Other)
3283+
return false; // Unknown type, let DAG ISel handle it.
3284+
3285+
// RetVT is not MVT::Other, it must be simple now. It is something rely on
3286+
// the logic of isTypeLegal().
3287+
MVT ABIVT = TLI.getRegisterTypeForCallingConv(CLI.RetTy->getContext(),
3288+
CLI.CallConv, RetVT);
3289+
MVT RegVT = TLI.getRegisterType(CLI.RetTy->getContext(), RetVT);
3290+
if (ABIVT != RegVT)
3291+
return false;
3292+
}
32883293
}
32893294

32903295
// Call / invoke instructions with NoCfCheck attribute require special

llvm/test/CodeGen/X86/bf16-fast-isel.ll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,36 @@ entry:
116116
ret i8 %call2
117117
}
118118

119+
declare { bfloat, bfloat } @get_bfloats()
120+
declare void @take_bfloats({ bfloat, bfloat })
121+
122+
define void @call_get_bfloats() nounwind {
123+
; CHECK-LABEL: call_get_bfloats:
124+
; CHECK: # %bb.0:
125+
; CHECK-NEXT: pushq %rax
126+
; CHECK-NEXT: callq get_bfloats@PLT
127+
; CHECK-NEXT: pextrw $0, %xmm1, %eax
128+
; CHECK-NEXT: shll $16, %eax
129+
; CHECK-NEXT: movl %eax, (%rsp) # 4-byte Spill
130+
; CHECK-NEXT: pextrw $0, %xmm0, %eax
131+
; CHECK-NEXT: shll $16, %eax
132+
; CHECK-NEXT: movd %eax, %xmm0
133+
; CHECK-NEXT: callq __truncsfbf2@PLT
134+
; CHECK-NEXT: movd %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 4-byte Folded Spill
135+
; CHECK-NEXT: movss (%rsp), %xmm0 # 4-byte Reload
136+
; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero
137+
; CHECK-NEXT: callq __truncsfbf2@PLT
138+
; CHECK-NEXT: movaps %xmm0, %xmm1
139+
; CHECK-NEXT: movss {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 4-byte Reload
140+
; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero
141+
; CHECK-NEXT: callq take_bfloats@PLT
142+
; CHECK-NEXT: popq %rax
143+
; CHECK-NEXT: retq
144+
%res = call { bfloat, bfloat } @get_bfloats()
145+
call void @take_bfloats({ bfloat, bfloat } %res)
146+
ret void
147+
}
148+
119149
declare bfloat @foo(ptr %f)
120150
declare zeroext i8 @bar(bfloat)
121151
declare fastcc bfloat @foo_fast(ptr %f)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
2+
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -fast-isel -fast-isel-abort=3 < %s | FileCheck %s
3+
4+
declare { i32, i32 } @get_i32s()
5+
6+
define i32 @call_get_i32s() nounwind {
7+
; CHECK-LABEL: call_get_i32s:
8+
; CHECK: # %bb.0:
9+
; CHECK-NEXT: pushq %rax
10+
; CHECK-NEXT: callq get_i32s@PLT
11+
; CHECK-NEXT: addl %edx, %eax
12+
; CHECK-NEXT: popq %rcx
13+
; CHECK-NEXT: retq
14+
%res = call { i32, i32 } @get_i32s()
15+
%res.0 = extractvalue { i32, i32 } %res, 0
16+
%res.1 = extractvalue { i32, i32 } %res, 1
17+
%add = add i32 %res.0, %res.1
18+
ret i32 %add
19+
}
20+
21+
declare { ptr, ptr } @get_ptrs()
22+
23+
define i64 @call_get_ptrs() nounwind {
24+
; CHECK-LABEL: call_get_ptrs:
25+
; CHECK: # %bb.0:
26+
; CHECK-NEXT: pushq %rax
27+
; CHECK-NEXT: callq get_ptrs@PLT
28+
; CHECK-NEXT: subq %rdx, %rax
29+
; CHECK-NEXT: popq %rcx
30+
; CHECK-NEXT: retq
31+
%res = call { ptr, ptr } @get_ptrs()
32+
%res.0 = extractvalue { ptr, ptr } %res, 0
33+
%res.1 = extractvalue { ptr, ptr } %res, 1
34+
%res.0.addr = ptrtoaddr ptr %res.0 to i64
35+
%res.1.addr = ptrtoaddr ptr %res.1 to i64
36+
%sub = sub i64 %res.0.addr, %res.1.addr
37+
ret i64 %sub
38+
}
39+
40+
declare { i64, i1 } @get_i64_and_bool()
41+
42+
define i64 @call_get_i64_and_bool() nounwind {
43+
; CHECK-LABEL: call_get_i64_and_bool:
44+
; CHECK: # %bb.0:
45+
; CHECK-NEXT: pushq %rax
46+
; CHECK-NEXT: callq get_i64_and_bool@PLT
47+
; CHECK-NEXT: andb $1, %dl
48+
; CHECK-NEXT: movzbl %dl, %ecx
49+
; CHECK-NEXT: addq %rcx, %rax
50+
; CHECK-NEXT: popq %rcx
51+
; CHECK-NEXT: retq
52+
%res = call { i64, i1 } @get_i64_and_bool()
53+
%res.0 = extractvalue { i64, i1 } %res, 0
54+
%res.1 = extractvalue { i64, i1 } %res, 1
55+
%res.1.ext = zext i1 %res.1 to i64
56+
%add = add i64 %res.0, %res.1.ext
57+
ret i64 %add
58+
}

0 commit comments

Comments
 (0)