Skip to content

Commit

Permalink
[X86][SSE] Auto upgrade PADDUS/PSUBUS intrinsics to UADD_SAT/USUB_SAT…
Browse files Browse the repository at this point in the history
… generic intrinsics (clang)

Sibling patch to D55855, this emits UADD_SAT/USUB_SAT generic intrinsics for the SSE saturated math intrinsics instead of expanding to a IR code sequence that could be difficult to reassemble.

Differential Revision: https://reviews.llvm.org/D55879

llvm-svn: 349631
  • Loading branch information
RKSimon committed Dec 19, 2018
1 parent 7bfbf3c commit a7b30b4
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 133 deletions.
33 changes: 8 additions & 25 deletions clang/lib/CodeGen/CGBuiltin.cpp
Expand Up @@ -9487,31 +9487,14 @@ static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op,
return CGF.Builder.CreateSExt(Mask, DstTy, "vpmovm2");
}

// Emit addition or subtraction with saturation.
// Handles both signed and unsigned intrinsics.
static Value *EmitX86AddSubSatExpr(CodeGenFunction &CGF, const CallExpr *E,
// Emit addition or subtraction with unsigned saturation.
// TODO: Handle signed intrinsics.
static Value *EmitX86AddSubSatExpr(CodeGenFunction &CGF,
SmallVectorImpl<Value *> &Ops,
bool IsAddition) {

// Collect vector elements and type data.
llvm::Type *ResultType = CGF.ConvertType(E->getType());

Value *Res;
if (IsAddition) {
// ADDUS: a > (a+b) ? ~0 : (a+b)
// If Ops[0] > Add, overflow occurred.
Value *Add = CGF.Builder.CreateAdd(Ops[0], Ops[1]);
Value *ICmp = CGF.Builder.CreateICmp(ICmpInst::ICMP_UGT, Ops[0], Add);
Value *Max = llvm::Constant::getAllOnesValue(ResultType);
Res = CGF.Builder.CreateSelect(ICmp, Max, Add);
} else {
// SUBUS: max(a, b) - b
Value *ICmp = CGF.Builder.CreateICmp(ICmpInst::ICMP_UGT, Ops[0], Ops[1]);
Value *Select = CGF.Builder.CreateSelect(ICmp, Ops[0], Ops[1]);
Res = CGF.Builder.CreateSub(Select, Ops[1]);
}

return Res;
Intrinsic::ID IID = IsAddition ? Intrinsic::uadd_sat : Intrinsic::usub_sat;
llvm::Function *F = CGF.CGM.getIntrinsic(IID, Ops[0]->getType());
return CGF.Builder.CreateCall(F, {Ops[0], Ops[1]});
}

Value *CodeGenFunction::EmitX86CpuIs(const CallExpr *E) {
Expand Down Expand Up @@ -11382,14 +11365,14 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_paddusw256:
case X86::BI__builtin_ia32_paddusb128:
case X86::BI__builtin_ia32_paddusw128:
return EmitX86AddSubSatExpr(*this, E, Ops, true /* IsAddition */);
return EmitX86AddSubSatExpr(*this, Ops, true /* IsAddition */);
case X86::BI__builtin_ia32_psubusb512:
case X86::BI__builtin_ia32_psubusw512:
case X86::BI__builtin_ia32_psubusb256:
case X86::BI__builtin_ia32_psubusw256:
case X86::BI__builtin_ia32_psubusb128:
case X86::BI__builtin_ia32_psubusw128:
return EmitX86AddSubSatExpr(*this, E, Ops, false /* IsAddition */);
return EmitX86AddSubSatExpr(*this, Ops, false /* IsAddition */);
}
}

Expand Down
16 changes: 4 additions & 12 deletions clang/test/CodeGen/avx2-builtins.c
Expand Up @@ -69,18 +69,14 @@ __m256i test_mm256_adds_epi16(__m256i a, __m256i b) {
__m256i test_mm256_adds_epu8(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_adds_epu8
// CHECK-NOT: call <32 x i8> @llvm.x86.avx2.paddus.b(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
// CHECK: add <32 x i8> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <32 x i8> %{{.*}}, %{{.*}}
// CHECK: select <32 x i1> %{{.*}}, <32 x i8> <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>, <32 x i8> {{.*}}
// CHECK: call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
return _mm256_adds_epu8(a, b);
}

__m256i test_mm256_adds_epu16(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_adds_epu16
// CHECK-NOT: call <16 x i16> @llvm.x86.avx2.paddus.w(<16 x i16> %{{.*}}, <16 x i16> %{{.*}})
// CHECK: add <16 x i16> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <16 x i16> %{{.*}}, %{{.*}}
// CHECK: select <16 x i1> %{{.*}}, <16 x i16> <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>, <16 x i16> {{.*}}
// CHECK: call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{.*}}, <16 x i16> %{{.*}})
return _mm256_adds_epu16(a, b);
}

Expand Down Expand Up @@ -1188,18 +1184,14 @@ __m256i test_mm256_subs_epi16(__m256i a, __m256i b) {
__m256i test_mm256_subs_epu8(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_subs_epu8
// CHECK-NOT: call <32 x i8> @llvm.x86.avx2.psubus.b(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
// CHECK: icmp ugt <32 x i8> {{.*}}, {{.*}}
// CHECK: select <32 x i1> {{.*}}, <32 x i8> {{.*}}, <32 x i8> {{.*}}
// CHECK: sub <32 x i8> {{.*}}, {{.*}}
// CHECK: call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
return _mm256_subs_epu8(a, b);
}

__m256i test_mm256_subs_epu16(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_subs_epu16
// CHECK-NOT: call <16 x i16> @llvm.x86.avx2.psubus.w(<16 x i16> %{{.*}}, <16 x i16> %{{.*}})
// CHECK: icmp ugt <16 x i16> {{.*}}, {{.*}}
// CHECK: select <16 x i1> {{.*}}, <16 x i16> {{.*}}, <16 x i16> {{.*}}
// CHECK: sub <16 x i16> {{.*}}, {{.*}}
// CHECK: call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{.*}}, <16 x i16> %{{.*}})
return _mm256_subs_epu16(a, b);
}

Expand Down
48 changes: 12 additions & 36 deletions clang/test/CodeGen/avx512bw-builtins.c
Expand Up @@ -1027,52 +1027,40 @@ return _mm512_maskz_adds_epi16(__U,__A,__B);
__m512i test_mm512_adds_epu8(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_adds_epu8
// CHECK-NOT: @llvm.x86.avx512.mask.paddus.b.512
// CHECK: add <64 x i8> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <64 x i8> %{{.*}}, %{{.*}}
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>, <64 x i8> {{.*}}
// CHECK: call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{.*}}, <64 x i8> %{{.*}})
return _mm512_adds_epu8(__A,__B);
}
__m512i test_mm512_mask_adds_epu8(__m512i __W, __mmask64 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_adds_epu8
// CHECK-NOT: @llvm.x86.avx512.mask.paddus.b.512
// CHECK: add <64 x i8> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <64 x i8> %{{.*}}, %{{.*}}
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>, <64 x i8> {{.*}}
// CHECK: call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{.*}}, <64 x i8> %{{.*}})
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_adds_epu8(__W,__U,__A,__B);
}
__m512i test_mm512_maskz_adds_epu8(__mmask64 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_adds_epu8
// CHECK-NOT: @llvm.x86.avx512.mask.paddus.b.512
// CHECK: add <64 x i8> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <64 x i8> %{{.*}}, %{{.*}}
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> <i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1, i8 -1>, <64 x i8> {{.*}}
// CHECK: call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{.*}}, <64 x i8> %{{.*}})
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_adds_epu8(__U,__A,__B);
}
__m512i test_mm512_adds_epu16(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_adds_epu16
// CHECK-NOT: @llvm.x86.avx512.mask.paddus.w.512
// CHECK: add <32 x i16> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <32 x i16> %{{.*}}, %{{.*}}
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>, <32 x i16> {{.*}}
// CHECK: call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{.*}}, <32 x i16> %{{.*}})
return _mm512_adds_epu16(__A,__B);
}
__m512i test_mm512_mask_adds_epu16(__m512i __W, __mmask32 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_adds_epu16
// CHECK-NOT: @llvm.x86.avx512.mask.paddus.w.512
// CHECK: add <32 x i16> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <32 x i16> %{{.*}}, %{{.*}}
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>, <32 x i16> {{.*}}
// CHECK: call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{.*}}, <32 x i16> %{{.*}})
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_adds_epu16(__W,__U,__A,__B);
}
__m512i test_mm512_maskz_adds_epu16(__mmask32 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_adds_epu16
// CHECK-NOT: @llvm.x86.avx512.mask.paddus.w.512
// CHECK: add <32 x i16> %{{.*}}, %{{.*}}
// CHECK: icmp ugt <32 x i16> %{{.*}}, %{{.*}}
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>, <32 x i16> {{.*}}
// CHECK: call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{.*}}, <32 x i16> %{{.*}})
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_adds_epu16(__U,__A,__B);
}
Expand Down Expand Up @@ -1362,52 +1350,40 @@ return _mm512_maskz_subs_epi16(__U,__A,__B);
__m512i test_mm512_subs_epu8(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_subs_epu8
// CHECK-NOT: @llvm.x86.avx512.mask.psubus.b.512
// CHECK: icmp ugt <64 x i8> {{.*}}, {{.*}}
// CHECK: select <64 x i1> {{.*}}, <64 x i8> {{.*}}, <64 x i8> {{.*}}
// CHECK: sub <64 x i8> {{.*}}, {{.*}}
// CHECK: call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{.*}}, <64 x i8> %{{.*}})
return _mm512_subs_epu8(__A,__B);
}
__m512i test_mm512_mask_subs_epu8(__m512i __W, __mmask64 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_subs_epu8
// CHECK-NOT: @llvm.x86.avx512.mask.psubus.b.512
// CHECK: icmp ugt <64 x i8> {{.*}}, {{.*}}
// CHECK: select <64 x i1> {{.*}}, <64 x i8> {{.*}}, <64 x i8> {{.*}}
// CHECK: sub <64 x i8> {{.*}}, {{.*}}
// CHECK: call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{.*}}, <64 x i8> %{{.*}})
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_subs_epu8(__W,__U,__A,__B);
}
__m512i test_mm512_maskz_subs_epu8(__mmask64 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_subs_epu8
// CHECK-NOT: @llvm.x86.avx512.mask.psubus.b.512
// CHECK: icmp ugt <64 x i8> {{.*}}, {{.*}}
// CHECK: select <64 x i1> {{.*}}, <64 x i8> {{.*}}, <64 x i8> {{.*}}
// CHECK: sub <64 x i8> {{.*}}, {{.*}}
// CHECK: call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{.*}}, <64 x i8> %{{.*}})
// CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_subs_epu8(__U,__A,__B);
}
__m512i test_mm512_subs_epu16(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_subs_epu16
// CHECK-NOT: @llvm.x86.avx512.mask.psubus.w.512
// CHECK: icmp ugt <32 x i16> {{.*}}, {{.*}}
// CHECK: select <32 x i1> {{.*}}, <32 x i16> {{.*}}, <32 x i16> {{.*}}
// CHECK: sub <32 x i16> {{.*}}, {{.*}}
// CHECK: call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{.*}}, <32 x i16> %{{.*}})
return _mm512_subs_epu16(__A,__B);
}
__m512i test_mm512_mask_subs_epu16(__m512i __W, __mmask32 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_subs_epu16
// CHECK-NOT: @llvm.x86.avx512.mask.psubus.w.512
// CHECK: icmp ugt <32 x i16> {{.*}}, {{.*}}
// CHECK: select <32 x i1> {{.*}}, <32 x i16> {{.*}}, <32 x i16> {{.*}}
// CHECK: sub <32 x i16> {{.*}}, {{.*}}
// CHECK: call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{.*}}, <32 x i16> %{{.*}})
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_subs_epu16(__W,__U,__A,__B);
}
__m512i test_mm512_maskz_subs_epu16(__mmask32 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_subs_epu16
// CHECK-NOT: @llvm.x86.avx512.mask.psubus.w.512
// CHECK: icmp ugt <32 x i16> {{.*}}, {{.*}}
// CHECK: select <32 x i1> {{.*}}, <32 x i16> {{.*}}, <32 x i16> {{.*}}
// CHECK: sub <32 x i16> {{.*}}, {{.*}}
// CHECK: call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{.*}}, <32 x i16> %{{.*}})
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_subs_epu16(__U,__A,__B);
}
Expand Down

0 comments on commit a7b30b4

Please sign in to comment.