Skip to content

Commit 65ae09e

Browse files
authored
[PowerPC] Fix behavior of rldimi/rlwimi/rlwnm builtins (llvm#85040)
rldimi is 64-bit instruction, so the corresponding builtin should not be available in 32-bit mode. Rotate amount should be in range and cases when mask is zero needs special handling. This change also swaps the first and second operands of rldimi/rlwimi to match previous behavior. For masks not ending at bit 63-SH, rotation will be inserted before rldimi.
1 parent c1ccf07 commit 65ae09e

File tree

7 files changed

+186
-21
lines changed

7 files changed

+186
-21
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5189,6 +5189,7 @@ static bool isPPC_64Builtin(unsigned BuiltinID) {
51895189
case PPC::BI__builtin_ppc_fetch_and_andlp:
51905190
case PPC::BI__builtin_ppc_fetch_and_orlp:
51915191
case PPC::BI__builtin_ppc_fetch_and_swaplp:
5192+
case PPC::BI__builtin_ppc_rldimi:
51925193
return true;
51935194
}
51945195
return false;
@@ -5290,8 +5291,10 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
52905291
case PPC::BI__builtin_ppc_rlwnm:
52915292
return SemaValueIsRunOfOnes(TheCall, 2);
52925293
case PPC::BI__builtin_ppc_rlwimi:
5294+
return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) ||
5295+
SemaValueIsRunOfOnes(TheCall, 3);
52935296
case PPC::BI__builtin_ppc_rldimi:
5294-
return SemaBuiltinConstantArg(TheCall, 2, Result) ||
5297+
return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63) ||
52955298
SemaValueIsRunOfOnes(TheCall, 3);
52965299
case PPC::BI__builtin_ppc_addex: {
52975300
if (SemaBuiltinConstantArgRange(TheCall, 2, 0, 3))

clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-error.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ void test_trap(void) {
2424
__tw(ia, ib, 0); //expected-error {{argument value 0 is outside the valid range [1, 31]}}
2525
}
2626

27+
#ifdef __PPC64__
2728
void test_builtin_ppc_rldimi() {
2829
unsigned int shift;
2930
unsigned long long mask;
3031
unsigned long long res = __builtin_ppc_rldimi(ull, ull, shift, 7); // expected-error {{argument to '__builtin_ppc_rldimi' must be a constant integer}}
3132
res = __builtin_ppc_rldimi(ull, ull, 63, mask); // expected-error {{argument to '__builtin_ppc_rldimi' must be a constant integer}}
3233
res = __builtin_ppc_rldimi(ull, ull, 63, 0xFFFF000000000F00); // expected-error {{argument 3 value should represent a contiguous bit field}}
34+
res = __builtin_ppc_rldimi(ull, ull, 64, 0xFFFF000000000000); // expected-error {{argument value 64 is outside the valid range [0, 63]}}
3335
}
36+
#endif
3437

3538
void test_builtin_ppc_rlwimi() {
3639
unsigned int shift;
@@ -83,6 +86,10 @@ void testalignx(const void *pointer, unsigned int alignment) {
8386
}
8487

8588
#ifndef __PPC64__
89+
unsigned long long testrldimi32() {
90+
return __rldimi(ull, ui, 3, 0x7ffff8ULL); //expected-error {{this builtin is only available on 64-bit targets}}
91+
}
92+
8693
long long testbpermd(long long bit_selector, long long source) {
8794
return __bpermd(bit_selector, source); //expected-error {{this builtin is only available on 64-bit targets}}
8895
}

clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-rotate.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// REQUIRES: powerpc-registered-target
22
// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu \
3-
// RUN: -emit-llvm %s -o - -target-cpu pwr7 | FileCheck %s
3+
// RUN: -emit-llvm %s -o - -target-cpu pwr7 | FileCheck %s \
4+
// RUN: -check-prefixes=PPC64,CHECK
45
// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu \
5-
// RUN: -emit-llvm %s -o - -target-cpu pwr8 | FileCheck %s
6+
// RUN: -emit-llvm %s -o - -target-cpu pwr8 | FileCheck %s \
7+
// RUN: -check-prefixes=PPC64,CHECK
68
// RUN: %clang_cc1 -triple powerpc-unknown-aix \
79
// RUN: -emit-llvm %s -o - -target-cpu pwr7 | FileCheck %s
810
// RUN: %clang_cc1 -triple powerpc64-unknown-aix \
@@ -11,18 +13,20 @@
1113
extern unsigned int ui;
1214
extern unsigned long long ull;
1315

16+
#ifdef __PPC64__
1417
void test_builtin_ppc_rldimi() {
15-
// CHECK-LABEL: test_builtin_ppc_rldimi
16-
// CHECK: %res = alloca i64, align 8
17-
// CHECK-NEXT: [[RA:%[0-9]+]] = load i64, ptr @ull, align 8
18-
// CHECK-NEXT: [[RB:%[0-9]+]] = load i64, ptr @ull, align 8
19-
// CHECK-NEXT: [[RC:%[0-9]+]] = call i64 @llvm.ppc.rldimi(i64 [[RA]], i64 [[RB]], i32 63, i64 72057593769492480)
20-
// CHECK-NEXT: store i64 [[RC]], ptr %res, align 8
21-
// CHECK-NEXT: ret void
18+
// PPC64-LABEL: test_builtin_ppc_rldimi
19+
// PPC64: %res = alloca i64, align 8
20+
// PPC64-NEXT: [[RA:%[0-9]+]] = load i64, ptr @ull, align 8
21+
// PPC64-NEXT: [[RB:%[0-9]+]] = load i64, ptr @ull, align 8
22+
// PPC64-NEXT: [[RC:%[0-9]+]] = call i64 @llvm.ppc.rldimi(i64 [[RA]], i64 [[RB]], i32 63, i64 72057593769492480)
23+
// PPC64-NEXT: store i64 [[RC]], ptr %res, align 8
24+
// PPC64-NEXT: ret void
2225

2326
/*shift = 63, mask = 0x00FFFFFFF0000000 = 72057593769492480, ~mask = 0xFF0000000FFFFFFF = -72057593769492481*/
2427
unsigned long long res = __builtin_ppc_rldimi(ull, ull, 63, 0x00FFFFFFF0000000);
2528
}
29+
#endif
2630

2731
void test_builtin_ppc_rlwimi() {
2832
// CHECK-LABEL: test_builtin_ppc_rlwimi

llvm/lib/Target/PowerPC/PPCISelLowering.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10764,30 +10764,54 @@ SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
1076410764
return DAG.getRegister(PPC::R2, MVT::i32);
1076510765

1076610766
case Intrinsic::ppc_rldimi: {
10767+
assert(Subtarget.isPPC64() && "rldimi is only available in 64-bit!");
10768+
SDValue Src = Op.getOperand(1);
10769+
APInt Mask = Op.getConstantOperandAPInt(4);
10770+
if (Mask.isZero())
10771+
return Op.getOperand(2);
10772+
if (Mask.isAllOnes())
10773+
return DAG.getNode(ISD::ROTL, dl, MVT::i64, Src, Op.getOperand(3));
1076710774
uint64_t SH = Op.getConstantOperandVal(3);
1076810775
unsigned MB = 0, ME = 0;
10769-
if (!isRunOfOnes64(Op.getConstantOperandVal(4), MB, ME) || ME != 63 - SH)
10776+
if (!isRunOfOnes64(Mask.getZExtValue(), MB, ME))
1077010777
report_fatal_error("invalid rldimi mask!");
10771-
return SDValue(DAG.getMachineNode(
10772-
PPC::RLDIMI, dl, MVT::i64,
10773-
{Op.getOperand(1), Op.getOperand(2), Op.getOperand(3),
10774-
DAG.getTargetConstant(MB, dl, MVT::i32)}),
10775-
0);
10778+
// rldimi requires ME=63-SH, otherwise rotation is needed before rldimi.
10779+
if (ME < 63 - SH) {
10780+
Src = DAG.getNode(ISD::ROTL, dl, MVT::i64, Src,
10781+
DAG.getConstant(ME + SH + 1, dl, MVT::i32));
10782+
} else if (ME > 63 - SH) {
10783+
Src = DAG.getNode(ISD::ROTL, dl, MVT::i64, Src,
10784+
DAG.getConstant(ME + SH - 63, dl, MVT::i32));
10785+
}
10786+
return SDValue(
10787+
DAG.getMachineNode(PPC::RLDIMI, dl, MVT::i64,
10788+
{Op.getOperand(2), Src,
10789+
DAG.getTargetConstant(63 - ME, dl, MVT::i32),
10790+
DAG.getTargetConstant(MB, dl, MVT::i32)}),
10791+
0);
1077610792
}
1077710793

1077810794
case Intrinsic::ppc_rlwimi: {
10795+
APInt Mask = Op.getConstantOperandAPInt(4);
10796+
if (Mask.isZero())
10797+
return Op.getOperand(2);
10798+
if (Mask.isAllOnes())
10799+
return DAG.getNode(ISD::ROTL, dl, MVT::i32, Op.getOperand(1),
10800+
Op.getOperand(3));
1077910801
unsigned MB = 0, ME = 0;
10780-
if (!isRunOfOnes(Op.getConstantOperandVal(4), MB, ME))
10802+
if (!isRunOfOnes(Mask.getZExtValue(), MB, ME))
1078110803
report_fatal_error("invalid rlwimi mask!");
1078210804
return SDValue(DAG.getMachineNode(
1078310805
PPC::RLWIMI, dl, MVT::i32,
10784-
{Op.getOperand(1), Op.getOperand(2), Op.getOperand(3),
10806+
{Op.getOperand(2), Op.getOperand(1), Op.getOperand(3),
1078510807
DAG.getTargetConstant(MB, dl, MVT::i32),
1078610808
DAG.getTargetConstant(ME, dl, MVT::i32)}),
1078710809
0);
1078810810
}
1078910811

1079010812
case Intrinsic::ppc_rlwnm: {
10813+
if (Op.getConstantOperandVal(3) == 0)
10814+
return DAG.getConstant(0, dl, MVT::i32);
1079110815
unsigned MB = 0, ME = 0;
1079210816
if (!isRunOfOnes(Op.getConstantOperandVal(3), MB, ME))
1079310817
report_fatal_error("invalid rlwnm mask!");

llvm/test/CodeGen/PowerPC/rldimi.ll

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ entry:
5959
ret i64 %8
6060
}
6161

62-
define i64 @rldimi_intrinsic(i64 %a) {
63-
; CHECK-LABEL: rldimi_intrinsic:
62+
define i64 @rldimi4(i64 %a) {
63+
; CHECK-LABEL: rldimi4:
6464
; CHECK: # %bb.0:
6565
; CHECK-NEXT: rldimi 3, 3, 8, 0
6666
; CHECK-NEXT: rldimi 3, 3, 16, 0
@@ -72,4 +72,71 @@ define i64 @rldimi_intrinsic(i64 %a) {
7272
ret i64 %r3
7373
}
7474

75+
define i64 @rldimi5(i64 %a, i64 %b) {
76+
; CHECK-LABEL: rldimi5:
77+
; CHECK: # %bb.0:
78+
; CHECK-NEXT: rldimi 4, 3, 8, 40
79+
; CHECK-NEXT: mr 3, 4
80+
; CHECK-NEXT: blr
81+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 8, i64 16776960) ; 0xffff << 8
82+
ret i64 %r
83+
}
84+
85+
define i64 @rldimi6(i64 %a, i64 %b) {
86+
; CHECK-LABEL: rldimi6:
87+
; CHECK: # %bb.0:
88+
; CHECK-NEXT: rotldi 3, 3, 1
89+
; CHECK-NEXT: rldimi 4, 3, 7, 41
90+
; CHECK-NEXT: mr 3, 4
91+
; CHECK-NEXT: blr
92+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 8, i64 8388480) ; 0xffff << 7
93+
ret i64 %r
94+
}
95+
96+
define i64 @rldimi7(i64 %a, i64 %b) {
97+
; CHECK-LABEL: rldimi7:
98+
; CHECK: # %bb.0:
99+
; CHECK-NEXT: rotldi 3, 3, 63
100+
; CHECK-NEXT: rldimi 4, 3, 9, 39
101+
; CHECK-NEXT: mr 3, 4
102+
; CHECK-NEXT: blr
103+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 8, i64 33553920) ; 0xffff << 9
104+
ret i64 %r
105+
}
106+
107+
define i64 @rldimi8(i64 %a, i64 %b) {
108+
; CHECK-LABEL: rldimi8:
109+
; CHECK: # %bb.0:
110+
; CHECK-NEXT: mr 3, 4
111+
; CHECK-NEXT: blr
112+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 0, i64 0)
113+
ret i64 %r
114+
}
115+
116+
define i64 @rldimi9(i64 %a, i64 %b) {
117+
; CHECK-LABEL: rldimi9:
118+
; CHECK: # %bb.0:
119+
; CHECK-NEXT: mr 3, 4
120+
; CHECK-NEXT: blr
121+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 63, i64 0)
122+
ret i64 %r
123+
}
124+
125+
define i64 @rldimi10(i64 %a, i64 %b) {
126+
; CHECK-LABEL: rldimi10:
127+
; CHECK: # %bb.0:
128+
; CHECK-NEXT: blr
129+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 0, i64 -1)
130+
ret i64 %r
131+
}
132+
133+
define i64 @rldimi11(i64 %a, i64 %b) {
134+
; CHECK-LABEL: rldimi11:
135+
; CHECK: # %bb.0:
136+
; CHECK-NEXT: rotldi 3, 3, 8
137+
; CHECK-NEXT: blr
138+
%r = call i64 @llvm.ppc.rldimi(i64 %a, i64 %b, i32 8, i64 -1)
139+
ret i64 %r
140+
}
141+
75142
declare i64 @llvm.ppc.rldimi(i64, i64, i32 immarg, i64 immarg)

llvm/test/CodeGen/PowerPC/rlwimi.ll

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,51 @@ entry:
107107
define i32 @test9(i32 %a, i32 %b) {
108108
; CHECK-LABEL: test9:
109109
; CHECK: # %bb.0: # %entry
110-
; CHECK-NEXT: rlwimi 3, 4, 8, 20, 26
110+
; CHECK-NEXT: rlwimi 4, 3, 8, 20, 26
111+
; CHECK-NEXT: mr 3, 4
111112
; CHECK-NEXT: blr
112113
entry:
113114
%r = call i32 @llvm.ppc.rlwimi(i32 %a, i32 %b, i32 8, i32 4064)
114115
ret i32 %r
115116
}
116117

118+
define i32 @test10(i32 %a, i32 %b) {
119+
; CHECK-LABEL: test10:
120+
; CHECK: # %bb.0: # %entry
121+
; CHECK-NEXT: blr
122+
entry:
123+
%r = call i32 @llvm.ppc.rlwimi(i32 %a, i32 %b, i32 0, i32 -1)
124+
ret i32 %r
125+
}
126+
127+
define i32 @test11(i32 %a, i32 %b) {
128+
; CHECK-LABEL: test11:
129+
; CHECK: # %bb.0: # %entry
130+
; CHECK-NEXT: rotlwi 3, 3, 8
131+
; CHECK-NEXT: blr
132+
entry:
133+
%r = call i32 @llvm.ppc.rlwimi(i32 %a, i32 %b, i32 8, i32 -1)
134+
ret i32 %r
135+
}
136+
137+
define i32 @test12(i32 %a, i32 %b) {
138+
; CHECK-LABEL: test12:
139+
; CHECK: # %bb.0: # %entry
140+
; CHECK-NEXT: mr 3, 4
141+
; CHECK-NEXT: blr
142+
entry:
143+
%r = call i32 @llvm.ppc.rlwimi(i32 %a, i32 %b, i32 0, i32 0)
144+
ret i32 %r
145+
}
146+
147+
define i32 @test13(i32 %a, i32 %b) {
148+
; CHECK-LABEL: test13:
149+
; CHECK: # %bb.0: # %entry
150+
; CHECK-NEXT: rlwimi 3, 4, 0, 27, 19
151+
; CHECK-NEXT: blr
152+
entry:
153+
%r = call i32 @llvm.ppc.rlwimi(i32 %a, i32 %b, i32 0, i32 4064)
154+
ret i32 %r
155+
}
156+
117157
declare i32 @llvm.ppc.rlwimi(i32, i32, i32 immarg, i32 immarg)

llvm/test/CodeGen/PowerPC/rlwinm.ll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,24 @@ entry:
9797
ret i32 %r
9898
}
9999

100+
define i32 @test10(i32 %a, i32 %s) {
101+
; CHECK-LABEL: test10:
102+
; CHECK: # %bb.0: # %entry
103+
; CHECK-NEXT: li 3, 0
104+
; CHECK-NEXT: blr
105+
entry:
106+
%r = call i32 @llvm.ppc.rlwnm(i32 %a, i32 %s, i32 0)
107+
ret i32 %r
108+
}
109+
110+
define i32 @test11(i32 %a, i32 %s) {
111+
; CHECK-LABEL: test11:
112+
; CHECK: # %bb.0: # %entry
113+
; CHECK-NEXT: rotlw 3, 3, 4
114+
; CHECK-NEXT: blr
115+
entry:
116+
%r = call i32 @llvm.ppc.rlwnm(i32 %a, i32 %s, i32 -1)
117+
ret i32 %r
118+
}
119+
100120
declare i32 @llvm.ppc.rlwnm(i32, i32, i32 immarg)

0 commit comments

Comments
 (0)