Skip to content

Conversation

@AditiRM
Copy link
Member

@AditiRM AditiRM commented Jun 19, 2025

Support the following BCD format conversion builtins for PowerPC.

  • __builtin_bcdcopysign – Conversion that returns the decimal value of the first parameter combined with the sign code of the second parameter. `
  • __builtin_bcdsetsign – Conversion that sets the sign code of the input parameter in packed decimal format.

Note: This built-in function is valid only when all following conditions are met:
-qarch is set to utilize POWER9 technology.
The bcd.h file is included.

Prototypes

vector unsigned char __builtin_bcdcopysign(vector unsigned char, vector unsigned char);
vector unsigned char __builtin_bcdsetsign(vector unsigned char, unsigned char);

Usage Details

__builtin_bcdsetsign: Returns the packed decimal value of the first parameter combined with the sign code.
The sign code is set according to the following rules:

  • If the packed decimal value of the first parameter is positive, the following rules apply:
    • If the second parameter is 0, the sign code is set to 0xC.
    • If the second parameter is 1, the sign code is set to 0xF.
  • If the packed decimal value of the first parameter is negative, the sign code is set to 0xD.

notes:
The second parameter can only be 0 or 1.
You can determine whether a packed decimal value is positive or negative as follows:
- Packed decimal values with sign codes 0xA, 0xC, 0xE, or 0xF are interpreted as positive.
- Packed decimal values with sign codes 0xB or 0xD are interpreted as negative.

@AditiRM AditiRM self-assigned this Jun 19, 2025
@AditiRM AditiRM added clang Clang issues not falling into any other category backend:PowerPC clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:ir labels Jun 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 19, 2025

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-backend-powerpc

Author: Aditi Medhane (AditiRM)

Changes

Support the following BCD format conversion builtins for PowerPC.

  • __builtin_bcdcopysign – Conversion that returns the decimal value of the first parameter combined with the sign code of the second parameter.
  • __builtin_bcdsetsign – Conversion that sets the sign code of the input parameter in packed decimal format.

Prototypes

vector unsigned char __builtin_bcdcopysign(vector unsigned char, vector unsigned char);
vector unsigned char __builtin_bcdsetsign(vector unsigned char, unsigned char);

Reference Links


Full diff: https://github.com/llvm/llvm-project/pull/144874.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsPPC.def (+4)
  • (modified) clang/lib/Basic/Targets/PPC.cpp (+2)
  • (modified) clang/lib/Sema/SemaPPC.cpp (+2)
  • (added) clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c (+29)
  • (modified) llvm/include/llvm/IR/IntrinsicsPowerPC.td (+8)
  • (modified) llvm/lib/Target/PowerPC/PPCInstrAltivec.td (+4-2)
  • (added) llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll (+40)
diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def
index bb7d54bbb793e..c3825822ce0b8 100644
--- a/clang/include/clang/Basic/BuiltinsPPC.def
+++ b/clang/include/clang/Basic/BuiltinsPPC.def
@@ -515,6 +515,10 @@ TARGET_BUILTIN(__builtin_altivec_vctzh, "V8UsV8Us", "", "power9-vector")
 TARGET_BUILTIN(__builtin_altivec_vctzw, "V4UiV4Ui", "", "power9-vector")
 TARGET_BUILTIN(__builtin_altivec_vctzd, "V2ULLiV2ULLi", "", "power9-vector")
 
+//P9 BCD builtins
+TARGET_BUILTIN(__builtin_ppc_bcdcopysign, "V16UcV16UcV16Uc", "", "power9-vector")
+TARGET_BUILTIN(__builtin_ppc_bcdsetsign, "V16UcV16UcUc", "t", "power9-vector")
+
 // P7 BCD builtins.
 TARGET_BUILTIN(__builtin_cdtbcd, "UiUi", "", "isa-v206-instructions")
 TARGET_BUILTIN(__builtin_cbcdtd, "UiUi", "", "isa-v206-instructions")
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index e6ef0ecc526ba..876348c29b707 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -88,6 +88,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
 }
 
 static void defineXLCompatMacros(MacroBuilder &Builder) {
+  Builder.defineMacro("__builtin_bcdcopysign", "__builtin_ppc_bcdcopysign");
+  Builder.defineMacro("__builtin_bcdsetsign", "__builtin_ppc_bcdsetsign");
   Builder.defineMacro("__cdtbcd", "__builtin_ppc_cdtbcd");
   Builder.defineMacro("__cbcdtd", "__builtin_ppc_cbcdtd");
   Builder.defineMacro("__addg6s", "__builtin_ppc_addg6s");
diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp
index 9b4d82745f881..71673062044af 100644
--- a/clang/lib/Sema/SemaPPC.cpp
+++ b/clang/lib/Sema/SemaPPC.cpp
@@ -106,6 +106,8 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI,
   switch (BuiltinID) {
   default:
     return false;
+  case PPC::BI__builtin_ppc_bcdsetsign:
+    return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
   case PPC::BI__builtin_altivec_crypto_vshasigmaw:
   case PPC::BI__builtin_altivec_crypto_vshasigmad:
     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
diff --git a/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c b/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c
new file mode 100644
index 0000000000000..0aeb720e545ed
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c
@@ -0,0 +1,29 @@
+// NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: test_bcdcopysign
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8> %a, <16 x i8> %b)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdcopysign(vector unsigned char a, vector unsigned char b) {
+    return __builtin_ppc_bcdcopysign(a, b);
+}
+
+// CHECK-LABEL: test_bcdsetsign_imm0
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 0)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdsetsign_imm0(vector unsigned char a) {
+    return __builtin_ppc_bcdsetsign(a, '\0');
+}
+
+// CHECK-LABEL: test_bcdsetsign_imm1
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdsetsign_imm1(vector unsigned char a) {
+    return __builtin_ppc_bcdsetsign(a, '\1');
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
index 84c26599b5b70..bd9d85fdaab92 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -668,6 +668,14 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
   def int_ppc_addg6s: ClangBuiltin<"__builtin_addg6s">,
     DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>;
 
+  // BCD Format conversion intrinsics 
+  def int_ppc_bcdcopysign : ClangBuiltin<"__builtin_ppc_bcdcopysign">,
+    DefaultAttrsIntrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; 
+  def int_ppc_bcdsetsign : ClangBuiltin<"__builtin_ppc_bcdsetsign">,
+    DefaultAttrsIntrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_i32_ty], 
+    [IntrNoMem, ImmArg<ArgIndex<1>>]>;
+ 
+
   def int_ppc_bcdadd : ClangBuiltin<"__builtin_ppc_bcdadd">,
     DefaultAttrsIntrinsic<
     [llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty],
diff --git a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
index 386c94a324996..bf268a074496b 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
@@ -1626,9 +1626,11 @@ def BCDCTSQ_rec : VX_VT5_EO5_VB5_XO9_o    <0, 385, "bcdctsq.", []>;
 
 // Decimal Copy-Sign/Set-Sign
 let Defs = [CR6] in
-def BCDCPSGN_rec : VX1_VT5_VA5_VB5<833, "bcdcpsgn.", []>;
+def BCDCPSGN_rec : VX1_VT5_VA5_VB5<833, "bcdcpsgn.",
+    [(set v16i8:$VD, (int_ppc_bcdcopysign v16i8:$VA, v16i8:$VB))]>;
 
-def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.", []>;
+def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.",
+    [(set v16i8:$VD, (int_ppc_bcdsetsign v16i8:$VB, i32:$PS))]>;
 
 // Decimal Shift/Unsigned-Shift/Shift-and-Round
 def BCDS_rec :  VX_VT5_VA5_VB5_PS1_XO9_o<193, "bcds." , []>;
diff --git a/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll b/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll
new file mode 100644
index 0000000000000..ede86254b1516
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-unknown -mcpu=pwr9 \
+; RUN:  --ppc-asm-full-reg-names < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-unknown -mcpu=pwr9 \
+; RUN:     --ppc-asm-full-reg-names < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mcpu=pwr9 -mtriple=powerpc64-ibm-aix-xcoff \
+; RUN:   -ppc-asm-full-reg-names  < %s | FileCheck %s
+
+define dso_local <16 x i8> @test_bcdcopysign(<16 x i8> noundef %a, <16 x i8> noundef %b) {
+; CHECK-LABEL: test_bcdcopysign:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdcpsgn. v2, v2, v3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8> %a, <16 x i8> %b)
+  ret <16 x i8> %0
+}
+
+define dso_local <16 x i8> @test_bcdsetsign_imm0(<16 x i8> noundef %a) {
+; CHECK-LABEL: test_bcdsetsign_imm0:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdsetsgn. v2, v2, 0
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 0)
+  ret <16 x i8> %0
+}
+
+define dso_local <16 x i8> @test_bcdsetsign_imm1(<16 x i8> noundef %a) {
+; CHECK-LABEL: test_bcdsetsign_imm1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdsetsgn. v2, v2, 1
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
+  ret <16 x i8> %0
+}
+
+declare <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8>, <16 x i8>)
+declare <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8>, i32)

@llvmbot
Copy link
Member

llvmbot commented Jun 19, 2025

@llvm/pr-subscribers-clang

Author: Aditi Medhane (AditiRM)

Changes

Support the following BCD format conversion builtins for PowerPC.

  • __builtin_bcdcopysign – Conversion that returns the decimal value of the first parameter combined with the sign code of the second parameter.
  • __builtin_bcdsetsign – Conversion that sets the sign code of the input parameter in packed decimal format.

Prototypes

vector unsigned char __builtin_bcdcopysign(vector unsigned char, vector unsigned char);
vector unsigned char __builtin_bcdsetsign(vector unsigned char, unsigned char);

Reference Links


Full diff: https://github.com/llvm/llvm-project/pull/144874.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsPPC.def (+4)
  • (modified) clang/lib/Basic/Targets/PPC.cpp (+2)
  • (modified) clang/lib/Sema/SemaPPC.cpp (+2)
  • (added) clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c (+29)
  • (modified) llvm/include/llvm/IR/IntrinsicsPowerPC.td (+8)
  • (modified) llvm/lib/Target/PowerPC/PPCInstrAltivec.td (+4-2)
  • (added) llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll (+40)
diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def
index bb7d54bbb793e..c3825822ce0b8 100644
--- a/clang/include/clang/Basic/BuiltinsPPC.def
+++ b/clang/include/clang/Basic/BuiltinsPPC.def
@@ -515,6 +515,10 @@ TARGET_BUILTIN(__builtin_altivec_vctzh, "V8UsV8Us", "", "power9-vector")
 TARGET_BUILTIN(__builtin_altivec_vctzw, "V4UiV4Ui", "", "power9-vector")
 TARGET_BUILTIN(__builtin_altivec_vctzd, "V2ULLiV2ULLi", "", "power9-vector")
 
+//P9 BCD builtins
+TARGET_BUILTIN(__builtin_ppc_bcdcopysign, "V16UcV16UcV16Uc", "", "power9-vector")
+TARGET_BUILTIN(__builtin_ppc_bcdsetsign, "V16UcV16UcUc", "t", "power9-vector")
+
 // P7 BCD builtins.
 TARGET_BUILTIN(__builtin_cdtbcd, "UiUi", "", "isa-v206-instructions")
 TARGET_BUILTIN(__builtin_cbcdtd, "UiUi", "", "isa-v206-instructions")
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index e6ef0ecc526ba..876348c29b707 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -88,6 +88,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
 }
 
 static void defineXLCompatMacros(MacroBuilder &Builder) {
+  Builder.defineMacro("__builtin_bcdcopysign", "__builtin_ppc_bcdcopysign");
+  Builder.defineMacro("__builtin_bcdsetsign", "__builtin_ppc_bcdsetsign");
   Builder.defineMacro("__cdtbcd", "__builtin_ppc_cdtbcd");
   Builder.defineMacro("__cbcdtd", "__builtin_ppc_cbcdtd");
   Builder.defineMacro("__addg6s", "__builtin_ppc_addg6s");
diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp
index 9b4d82745f881..71673062044af 100644
--- a/clang/lib/Sema/SemaPPC.cpp
+++ b/clang/lib/Sema/SemaPPC.cpp
@@ -106,6 +106,8 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI,
   switch (BuiltinID) {
   default:
     return false;
+  case PPC::BI__builtin_ppc_bcdsetsign:
+    return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
   case PPC::BI__builtin_altivec_crypto_vshasigmaw:
   case PPC::BI__builtin_altivec_crypto_vshasigmad:
     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
diff --git a/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c b/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c
new file mode 100644
index 0000000000000..0aeb720e545ed
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c
@@ -0,0 +1,29 @@
+// NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: test_bcdcopysign
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8> %a, <16 x i8> %b)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdcopysign(vector unsigned char a, vector unsigned char b) {
+    return __builtin_ppc_bcdcopysign(a, b);
+}
+
+// CHECK-LABEL: test_bcdsetsign_imm0
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 0)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdsetsign_imm0(vector unsigned char a) {
+    return __builtin_ppc_bcdsetsign(a, '\0');
+}
+
+// CHECK-LABEL: test_bcdsetsign_imm1
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdsetsign_imm1(vector unsigned char a) {
+    return __builtin_ppc_bcdsetsign(a, '\1');
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
index 84c26599b5b70..bd9d85fdaab92 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -668,6 +668,14 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
   def int_ppc_addg6s: ClangBuiltin<"__builtin_addg6s">,
     DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>;
 
+  // BCD Format conversion intrinsics 
+  def int_ppc_bcdcopysign : ClangBuiltin<"__builtin_ppc_bcdcopysign">,
+    DefaultAttrsIntrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; 
+  def int_ppc_bcdsetsign : ClangBuiltin<"__builtin_ppc_bcdsetsign">,
+    DefaultAttrsIntrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_i32_ty], 
+    [IntrNoMem, ImmArg<ArgIndex<1>>]>;
+ 
+
   def int_ppc_bcdadd : ClangBuiltin<"__builtin_ppc_bcdadd">,
     DefaultAttrsIntrinsic<
     [llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty],
diff --git a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
index 386c94a324996..bf268a074496b 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
@@ -1626,9 +1626,11 @@ def BCDCTSQ_rec : VX_VT5_EO5_VB5_XO9_o    <0, 385, "bcdctsq.", []>;
 
 // Decimal Copy-Sign/Set-Sign
 let Defs = [CR6] in
-def BCDCPSGN_rec : VX1_VT5_VA5_VB5<833, "bcdcpsgn.", []>;
+def BCDCPSGN_rec : VX1_VT5_VA5_VB5<833, "bcdcpsgn.",
+    [(set v16i8:$VD, (int_ppc_bcdcopysign v16i8:$VA, v16i8:$VB))]>;
 
-def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.", []>;
+def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.",
+    [(set v16i8:$VD, (int_ppc_bcdsetsign v16i8:$VB, i32:$PS))]>;
 
 // Decimal Shift/Unsigned-Shift/Shift-and-Round
 def BCDS_rec :  VX_VT5_VA5_VB5_PS1_XO9_o<193, "bcds." , []>;
diff --git a/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll b/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll
new file mode 100644
index 0000000000000..ede86254b1516
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-unknown -mcpu=pwr9 \
+; RUN:  --ppc-asm-full-reg-names < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-unknown -mcpu=pwr9 \
+; RUN:     --ppc-asm-full-reg-names < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mcpu=pwr9 -mtriple=powerpc64-ibm-aix-xcoff \
+; RUN:   -ppc-asm-full-reg-names  < %s | FileCheck %s
+
+define dso_local <16 x i8> @test_bcdcopysign(<16 x i8> noundef %a, <16 x i8> noundef %b) {
+; CHECK-LABEL: test_bcdcopysign:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdcpsgn. v2, v2, v3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8> %a, <16 x i8> %b)
+  ret <16 x i8> %0
+}
+
+define dso_local <16 x i8> @test_bcdsetsign_imm0(<16 x i8> noundef %a) {
+; CHECK-LABEL: test_bcdsetsign_imm0:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdsetsgn. v2, v2, 0
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 0)
+  ret <16 x i8> %0
+}
+
+define dso_local <16 x i8> @test_bcdsetsign_imm1(<16 x i8> noundef %a) {
+; CHECK-LABEL: test_bcdsetsign_imm1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdsetsgn. v2, v2, 1
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
+  ret <16 x i8> %0
+}
+
+declare <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8>, <16 x i8>)
+declare <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8>, i32)

@llvmbot
Copy link
Member

llvmbot commented Jun 19, 2025

@llvm/pr-subscribers-llvm-ir

Author: Aditi Medhane (AditiRM)

Changes

Support the following BCD format conversion builtins for PowerPC.

  • __builtin_bcdcopysign – Conversion that returns the decimal value of the first parameter combined with the sign code of the second parameter.
  • __builtin_bcdsetsign – Conversion that sets the sign code of the input parameter in packed decimal format.

Prototypes

vector unsigned char __builtin_bcdcopysign(vector unsigned char, vector unsigned char);
vector unsigned char __builtin_bcdsetsign(vector unsigned char, unsigned char);

Reference Links


Full diff: https://github.com/llvm/llvm-project/pull/144874.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsPPC.def (+4)
  • (modified) clang/lib/Basic/Targets/PPC.cpp (+2)
  • (modified) clang/lib/Sema/SemaPPC.cpp (+2)
  • (added) clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c (+29)
  • (modified) llvm/include/llvm/IR/IntrinsicsPowerPC.td (+8)
  • (modified) llvm/lib/Target/PowerPC/PPCInstrAltivec.td (+4-2)
  • (added) llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll (+40)
diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def
index bb7d54bbb793e..c3825822ce0b8 100644
--- a/clang/include/clang/Basic/BuiltinsPPC.def
+++ b/clang/include/clang/Basic/BuiltinsPPC.def
@@ -515,6 +515,10 @@ TARGET_BUILTIN(__builtin_altivec_vctzh, "V8UsV8Us", "", "power9-vector")
 TARGET_BUILTIN(__builtin_altivec_vctzw, "V4UiV4Ui", "", "power9-vector")
 TARGET_BUILTIN(__builtin_altivec_vctzd, "V2ULLiV2ULLi", "", "power9-vector")
 
+//P9 BCD builtins
+TARGET_BUILTIN(__builtin_ppc_bcdcopysign, "V16UcV16UcV16Uc", "", "power9-vector")
+TARGET_BUILTIN(__builtin_ppc_bcdsetsign, "V16UcV16UcUc", "t", "power9-vector")
+
 // P7 BCD builtins.
 TARGET_BUILTIN(__builtin_cdtbcd, "UiUi", "", "isa-v206-instructions")
 TARGET_BUILTIN(__builtin_cbcdtd, "UiUi", "", "isa-v206-instructions")
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index e6ef0ecc526ba..876348c29b707 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -88,6 +88,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
 }
 
 static void defineXLCompatMacros(MacroBuilder &Builder) {
+  Builder.defineMacro("__builtin_bcdcopysign", "__builtin_ppc_bcdcopysign");
+  Builder.defineMacro("__builtin_bcdsetsign", "__builtin_ppc_bcdsetsign");
   Builder.defineMacro("__cdtbcd", "__builtin_ppc_cdtbcd");
   Builder.defineMacro("__cbcdtd", "__builtin_ppc_cbcdtd");
   Builder.defineMacro("__addg6s", "__builtin_ppc_addg6s");
diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp
index 9b4d82745f881..71673062044af 100644
--- a/clang/lib/Sema/SemaPPC.cpp
+++ b/clang/lib/Sema/SemaPPC.cpp
@@ -106,6 +106,8 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI,
   switch (BuiltinID) {
   default:
     return false;
+  case PPC::BI__builtin_ppc_bcdsetsign:
+    return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
   case PPC::BI__builtin_altivec_crypto_vshasigmaw:
   case PPC::BI__builtin_altivec_crypto_vshasigmad:
     return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
diff --git a/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c b/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c
new file mode 100644
index 0000000000000..0aeb720e545ed
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/builtins-bcd-helpers.c
@@ -0,0 +1,29 @@
+// NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc-unknown-unknown -O2 -target-cpu pwr9 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: test_bcdcopysign
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8> %a, <16 x i8> %b)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdcopysign(vector unsigned char a, vector unsigned char b) {
+    return __builtin_ppc_bcdcopysign(a, b);
+}
+
+// CHECK-LABEL: test_bcdsetsign_imm0
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 0)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdsetsign_imm0(vector unsigned char a) {
+    return __builtin_ppc_bcdsetsign(a, '\0');
+}
+
+// CHECK-LABEL: test_bcdsetsign_imm1
+// CHECK:         [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
+// CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+vector unsigned char test_bcdsetsign_imm1(vector unsigned char a) {
+    return __builtin_ppc_bcdsetsign(a, '\1');
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
index 84c26599b5b70..bd9d85fdaab92 100644
--- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td
+++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td
@@ -668,6 +668,14 @@ let TargetPrefix = "ppc" in {  // All intrinsics start with "llvm.ppc.".
   def int_ppc_addg6s: ClangBuiltin<"__builtin_addg6s">,
     DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>;
 
+  // BCD Format conversion intrinsics 
+  def int_ppc_bcdcopysign : ClangBuiltin<"__builtin_ppc_bcdcopysign">,
+    DefaultAttrsIntrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; 
+  def int_ppc_bcdsetsign : ClangBuiltin<"__builtin_ppc_bcdsetsign">,
+    DefaultAttrsIntrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_i32_ty], 
+    [IntrNoMem, ImmArg<ArgIndex<1>>]>;
+ 
+
   def int_ppc_bcdadd : ClangBuiltin<"__builtin_ppc_bcdadd">,
     DefaultAttrsIntrinsic<
     [llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty],
diff --git a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
index 386c94a324996..bf268a074496b 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
@@ -1626,9 +1626,11 @@ def BCDCTSQ_rec : VX_VT5_EO5_VB5_XO9_o    <0, 385, "bcdctsq.", []>;
 
 // Decimal Copy-Sign/Set-Sign
 let Defs = [CR6] in
-def BCDCPSGN_rec : VX1_VT5_VA5_VB5<833, "bcdcpsgn.", []>;
+def BCDCPSGN_rec : VX1_VT5_VA5_VB5<833, "bcdcpsgn.",
+    [(set v16i8:$VD, (int_ppc_bcdcopysign v16i8:$VA, v16i8:$VB))]>;
 
-def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.", []>;
+def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.",
+    [(set v16i8:$VD, (int_ppc_bcdsetsign v16i8:$VB, i32:$PS))]>;
 
 // Decimal Shift/Unsigned-Shift/Shift-and-Round
 def BCDS_rec :  VX_VT5_VA5_VB5_PS1_XO9_o<193, "bcds." , []>;
diff --git a/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll b/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll
new file mode 100644
index 0000000000000..ede86254b1516
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/builtins-bcd-helpers.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-unknown -mcpu=pwr9 \
+; RUN:  --ppc-asm-full-reg-names < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-unknown -mcpu=pwr9 \
+; RUN:     --ppc-asm-full-reg-names < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mcpu=pwr9 -mtriple=powerpc64-ibm-aix-xcoff \
+; RUN:   -ppc-asm-full-reg-names  < %s | FileCheck %s
+
+define dso_local <16 x i8> @test_bcdcopysign(<16 x i8> noundef %a, <16 x i8> noundef %b) {
+; CHECK-LABEL: test_bcdcopysign:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdcpsgn. v2, v2, v3
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8> %a, <16 x i8> %b)
+  ret <16 x i8> %0
+}
+
+define dso_local <16 x i8> @test_bcdsetsign_imm0(<16 x i8> noundef %a) {
+; CHECK-LABEL: test_bcdsetsign_imm0:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdsetsgn. v2, v2, 0
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 0)
+  ret <16 x i8> %0
+}
+
+define dso_local <16 x i8> @test_bcdsetsign_imm1(<16 x i8> noundef %a) {
+; CHECK-LABEL: test_bcdsetsign_imm1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    bcdsetsgn. v2, v2, 1
+; CHECK-NEXT:    blr
+entry:
+  %0 = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
+  ret <16 x i8> %0
+}
+
+declare <16 x i8> @llvm.ppc.bcdcopysign(<16 x i8>, <16 x i8>)
+declare <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8>, i32)

Copy link
Contributor

@tonykuttai tonykuttai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AditiRM AditiRM requested a review from mandlebug June 24, 2025 05:33
Copy link
Contributor

@lei137 lei137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@tonykuttai tonykuttai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall—just minor comments to address.

Aditi-Medhane added 2 commits August 1, 2025 05:49
Custom buiiltin and testcase renaming
@AditiRM AditiRM requested review from lei137 and tonykuttai August 1, 2025 14:02
// CHECK: [[TMP0:%.*]] = tail call <16 x i8> @llvm.ppc.bcdsetsign(<16 x i8> %a, i32 1)
// CHECK-NEXT: ret <16 x i8> [[TMP0]]
vector unsigned char test_bcdsetsign_imm1(vector unsigned char a) {
return __builtin_ppc_bcdsetsign(a, '\1');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's strange that the 2nd arg need to be a const of 1 or 0 and we are making the users specify it as a char via \1 or \0. Seems like this should just be 1 or 0.

Copy link
Member Author

@AditiRM AditiRM Aug 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it works with 0 and 1, we use '\0' and '\1' as that’s the conventional way to pass an unsigned character, and it ensures the value is treated as a character literal. At runtime, these literals are converted to their corresponding ASCII values.


def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.", []>;
def BCDSETSGN_rec : VX_VT5_EO5_VB5_PS1_XO9_o<31, 385, "bcdsetsgn.",
[(set v16i8:$VD, (int_ppc_bcdsetsign v16i8:$VB, i32:$PS))]>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i32 should be uimm1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping it as i32 since the backend expects and handles it correctly

Copy link
Contributor

@tonykuttai tonykuttai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@tonykuttai tonykuttai merged commit 948abf1 into llvm:main Aug 19, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:PowerPC clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category llvm:ir

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants