Skip to content

Commit d9c31ee

Browse files
committed
Fix overflow flag for i128 USUBO
We use the VSCBIQ/VSBIQ/VSBCBIQ family of instructions to implement USUBO/USUBO_CARRY for the i128 data type. However, these instructions use an inverted sense of the borrow indication flag (a value of 1 indicates *no* borrow, while a value of 0 indicated borrow). This does not match the semantics of the boolean "overflow" flag of the USUBO/USUBO_CARRY ISD nodes. Fix this by generating code to explicitly invert the flag. These cancel out of the result of USUBO feeds into an USUBO_CARRY. To avoid unnecessary zero-extend operations, also improve the DAGCombine handling of ZERO_EXTEND to optimize (zext (xor (trunc))) sequences where appropriate. Fixes: llvm#83268
1 parent 6bc6e1a commit d9c31ee

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,6 +4263,7 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op,
42634263
if (N->getValueType(0) == MVT::i128) {
42644264
unsigned BaseOp = 0;
42654265
unsigned FlagOp = 0;
4266+
bool IsBorrow = false;
42664267
switch (Op.getOpcode()) {
42674268
default: llvm_unreachable("Unknown instruction!");
42684269
case ISD::UADDO:
@@ -4272,13 +4273,17 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op,
42724273
case ISD::USUBO:
42734274
BaseOp = ISD::SUB;
42744275
FlagOp = SystemZISD::VSCBI;
4276+
IsBorrow = true;
42754277
break;
42764278
}
42774279
SDValue Result = DAG.getNode(BaseOp, DL, MVT::i128, LHS, RHS);
42784280
SDValue Flag = DAG.getNode(FlagOp, DL, MVT::i128, LHS, RHS);
42794281
Flag = DAG.getNode(ISD::AssertZext, DL, MVT::i128, Flag,
42804282
DAG.getValueType(MVT::i1));
42814283
Flag = DAG.getZExtOrTrunc(Flag, DL, N->getValueType(1));
4284+
if (IsBorrow)
4285+
Flag = DAG.getNode(ISD::XOR, DL, Flag.getValueType(),
4286+
Flag, DAG.getConstant(1, DL, Flag.getValueType()));
42824287
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Flag);
42834288
}
42844289

@@ -4351,6 +4356,7 @@ SDValue SystemZTargetLowering::lowerUADDSUBO_CARRY(SDValue Op,
43514356
if (VT == MVT::i128) {
43524357
unsigned BaseOp = 0;
43534358
unsigned FlagOp = 0;
4359+
bool IsBorrow = false;
43544360
switch (Op.getOpcode()) {
43554361
default: llvm_unreachable("Unknown instruction!");
43564362
case ISD::UADDO_CARRY:
@@ -4360,14 +4366,21 @@ SDValue SystemZTargetLowering::lowerUADDSUBO_CARRY(SDValue Op,
43604366
case ISD::USUBO_CARRY:
43614367
BaseOp = SystemZISD::VSBI;
43624368
FlagOp = SystemZISD::VSBCBI;
4369+
IsBorrow = true;
43634370
break;
43644371
}
4372+
if (IsBorrow)
4373+
Carry = DAG.getNode(ISD::XOR, DL, Carry.getValueType(),
4374+
Carry, DAG.getConstant(1, DL, Carry.getValueType()));
43654375
Carry = DAG.getZExtOrTrunc(Carry, DL, MVT::i128);
43664376
SDValue Result = DAG.getNode(BaseOp, DL, MVT::i128, LHS, RHS, Carry);
43674377
SDValue Flag = DAG.getNode(FlagOp, DL, MVT::i128, LHS, RHS, Carry);
43684378
Flag = DAG.getNode(ISD::AssertZext, DL, MVT::i128, Flag,
43694379
DAG.getValueType(MVT::i1));
43704380
Flag = DAG.getZExtOrTrunc(Flag, DL, N->getValueType(1));
4381+
if (IsBorrow)
4382+
Flag = DAG.getNode(ISD::XOR, DL, Flag.getValueType(),
4383+
Flag, DAG.getConstant(1, DL, Flag.getValueType()));
43714384
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Flag);
43724385
}
43734386

@@ -6571,6 +6584,27 @@ SDValue SystemZTargetLowering::combineTruncateExtract(
65716584
}
65726585
}
65736586
}
6587+
// Convert (zext (xor (trunc X), C)) into (xor (trunc X), C') if the size
6588+
// of the result is smaller than the size of X and all the truncated bits
6589+
// of X are already zero.
6590+
if (N0.getOpcode() == ISD::XOR &&
6591+
N0.hasOneUse() && N0.getOperand(0).hasOneUse() &&
6592+
N0.getOperand(0).getOpcode() == ISD::TRUNCATE &&
6593+
N0.getOperand(1).getOpcode() == ISD::Constant) {
6594+
SDValue X = N0.getOperand(0).getOperand(0);
6595+
if (VT.isScalarInteger() && VT.getSizeInBits() < X.getValueSizeInBits()) {
6596+
KnownBits Known = DAG.computeKnownBits(X);
6597+
APInt TruncatedBits = APInt::getBitsSet(X.getValueSizeInBits(),
6598+
N0.getValueSizeInBits(),
6599+
VT.getSizeInBits());
6600+
if (TruncatedBits.isSubsetOf(Known.Zero)) {
6601+
X = DAG.getNode(ISD::TRUNCATE, SDLoc(X), VT, X);
6602+
APInt Mask = N0.getConstantOperandAPInt(1).zext(VT.getSizeInBits());
6603+
return DAG.getNode(ISD::XOR, SDLoc(N0), VT,
6604+
X, DAG.getConstant(Mask, SDLoc(N0), VT));
6605+
}
6606+
}
6607+
}
65746608
return SDValue();
65756609
}
65766610

llvm/test/CodeGen/SystemZ/int-usub-12.ll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ define zeroext i1 @f1(i128 %a, i128 %b, ptr %res) {
1111
; CHECK-NEXT: vscbiq %v2, %v1, %v0
1212
; CHECK-NEXT: vlgvg %r2, %v2, 1
1313
; CHECK-NEXT: vsq %v0, %v1, %v0
14+
; CHECK-NEXT: xilf %r2, 1
1415
; CHECK-NEXT: vst %v0, 0(%r4), 3
1516
; CHECK-NEXT: br %r14
1617
%t = call {i128, i1} @llvm.usub.with.overflow.i128(i128 %a, i128 %b)
@@ -27,6 +28,7 @@ define zeroext i1 @f2(i128 %a, i128 %b) {
2728
; CHECK-NEXT: vl %v1, 0(%r2), 3
2829
; CHECK-NEXT: vscbiq %v0, %v1, %v0
2930
; CHECK-NEXT: vlgvg %r2, %v0, 1
31+
; CHECK-NEXT: xilf %r2, 1
3032
; CHECK-NEXT: br %r14
3133
%t = call {i128, i1} @llvm.usub.with.overflow.i128(i128 %a, i128 %b)
3234
%obit = extractvalue {i128, i1} %t, 1
@@ -46,5 +48,25 @@ define i128 @f3(i128 %a, i128 %b) {
4648
ret i128 %val
4749
}
4850

51+
define i128 @f4(i128 %a, i128 %b) {
52+
; CHECK-LABEL: f4:
53+
; CHECK: # %bb.0:
54+
; CHECK-NEXT: vl %v0, 0(%r4), 3
55+
; CHECK-NEXT: vl %v1, 0(%r3), 3
56+
; CHECK-NEXT: vscbiq %v2, %v1, %v0
57+
; CHECK-NEXT: vlgvf %r0, %v2, 3
58+
; CHECK-NEXT: vgbm %v2, 0
59+
; CHECK-NEXT: xilf %r0, 1
60+
; CHECK-NEXT: jl .LBB3_2
61+
; CHECK-NEXT: # %bb.1:
62+
; CHECK-NEXT: vsq %v2, %v1, %v0
63+
; CHECK-NEXT: .LBB3_2:
64+
; CHECK-NEXT: vst %v2, 0(%r2), 3
65+
; CHECK-NEXT: br %r14
66+
%val = call i128 @llvm.usub.sat.i128(i128 %a, i128 %b)
67+
ret i128 %val
68+
}
69+
4970
declare {i128, i1} @llvm.usub.with.overflow.i128(i128, i128) nounwind readnone
71+
declare i128 @llvm.usub.sat.i128(i128, i128) nounwind readnone
5072

llvm/test/CodeGen/SystemZ/int-usub-13.ll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ define zeroext i1 @f1(i256 %a, i256 %b, ptr %res) {
1515
; CHECK-NEXT: vlgvg %r2, %v5, 1
1616
; CHECK-NEXT: vsbiq %v0, %v1, %v0, %v4
1717
; CHECK-NEXT: vsq %v1, %v3, %v2
18+
; CHECK-NEXT: xilf %r2, 1
1819
; CHECK-NEXT: vst %v1, 16(%r4), 3
1920
; CHECK-NEXT: vst %v0, 0(%r4), 3
2021
; CHECK-NEXT: br %r14
@@ -35,6 +36,7 @@ define zeroext i1 @f2(i256 %a, i256 %b) {
3536
; CHECK-NEXT: vscbiq %v2, %v3, %v2
3637
; CHECK-NEXT: vsbcbiq %v0, %v1, %v0, %v2
3738
; CHECK-NEXT: vlgvg %r2, %v0, 1
39+
; CHECK-NEXT: xilf %r2, 1
3840
; CHECK-NEXT: br %r14
3941
%t = call {i256, i1} @llvm.usub.with.overflow.i256(i256 %a, i256 %b)
4042
%obit = extractvalue {i256, i1} %t, 1

0 commit comments

Comments
 (0)