[PowerPC] Add XL Compat fetch builtins
authorJinsong Ji <jji@us.ibm.com>
Mon, 28 Jun 2021 02:46:33 +0000 (02:46 +0000)
committerJinsong Ji <jji@us.ibm.com>
Mon, 28 Jun 2021 02:52:32 +0000 (02:52 +0000)
Prototype
```
unsigned int __fetch_and_add (volatile unsigned int* addr, unsigned int
val);
unsigned long __fetch_and_addlp (volatile unsigned long* addr, unsigned
long val);
```
Ref:
https://www.ibm.com/docs/en/xl-c-and-cpp-linux/16.1.1?topic=functions-fetch

Reviewed By: #powerpc, w2yehia, lkail

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

clang/include/clang/Basic/BuiltinsPPC.def
clang/lib/Basic/Targets/PPC.cpp
clang/lib/CodeGen/CGBuiltin.cpp
clang/test/CodeGen/builtins-ppc-xlcompat-fetch-error.c [new file with mode: 0644]
clang/test/CodeGen/builtins-ppc-xlcompat-fetch.c [new file with mode: 0644]

index 47b4854..e07632d 100644 (file)
@@ -47,6 +47,14 @@ BUILTIN(__builtin_ppc_dcbz, "vv*", "")
 BUILTIN(__builtin_ppc_icbt, "vv*", "")
 BUILTIN(__builtin_ppc_compare_and_swap, "iiD*i*i", "")
 BUILTIN(__builtin_ppc_compare_and_swaplp, "iLiD*Li*Li", "")
+BUILTIN(__builtin_ppc_fetch_and_add, "UiUiD*Ui", "")
+BUILTIN(__builtin_ppc_fetch_and_addlp, "ULiULiD*ULi", "")
+BUILTIN(__builtin_ppc_fetch_and_and, "UiUiD*Ui", "")
+BUILTIN(__builtin_ppc_fetch_and_andlp, "ULiULiD*ULi", "")
+BUILTIN(__builtin_ppc_fetch_and_or, "UiUiD*Ui", "")
+BUILTIN(__builtin_ppc_fetch_and_orlp, "ULiULiD*ULi", "")
+BUILTIN(__builtin_ppc_fetch_and_swap, "UiUiD*Ui", "")
+BUILTIN(__builtin_ppc_fetch_and_swaplp, "ULiULiD*ULi", "")
 
 BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n")
 
index e051826..6860b5e 100644 (file)
@@ -100,6 +100,14 @@ static void defineXLCompatMacros(MacroBuilder &Builder) {
   Builder.defineMacro("__compare_and_swap", "__builtin_ppc_compare_and_swap");
   Builder.defineMacro("__compare_and_swaplp",
                       "__builtin_ppc_compare_and_swaplp");
+  Builder.defineMacro("__fetch_and_add", "__builtin_ppc_fetch_and_add");
+  Builder.defineMacro("__fetch_and_addlp", "__builtin_ppc_fetch_and_addlp");
+  Builder.defineMacro("__fetch_and_and", "__builtin_ppc_fetch_and_and");
+  Builder.defineMacro("__fetch_and_andlp", "__builtin_ppc_fetch_and_andlp");
+  Builder.defineMacro("__fetch_and_or", "__builtin_ppc_fetch_and_or");
+  Builder.defineMacro("__fetch_and_orlp", "__builtin_ppc_fetch_and_orlp");
+  Builder.defineMacro("__fetch_and_swap", "__builtin_ppc_fetch_and_swap");
+  Builder.defineMacro("__fetch_and_swaplp", "__builtin_ppc_fetch_and_swaplp");
 }
 
 /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
index 97f2db9..2e94549 100644 (file)
@@ -15440,6 +15440,27 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
         llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic, true);
     return Pair.second;
   }
+  case PPC::BI__builtin_ppc_fetch_and_add:
+  case PPC::BI__builtin_ppc_fetch_and_addlp: {
+    return MakeBinaryAtomicValue(*this, AtomicRMWInst::Add, E,
+                                 llvm::AtomicOrdering::Monotonic);
+  }
+  case PPC::BI__builtin_ppc_fetch_and_and:
+  case PPC::BI__builtin_ppc_fetch_and_andlp: {
+    return MakeBinaryAtomicValue(*this, AtomicRMWInst::And, E,
+                                 llvm::AtomicOrdering::Monotonic);
+  }
+
+  case PPC::BI__builtin_ppc_fetch_and_or:
+  case PPC::BI__builtin_ppc_fetch_and_orlp: {
+    return MakeBinaryAtomicValue(*this, AtomicRMWInst::Or, E,
+                                 llvm::AtomicOrdering::Monotonic);
+  }
+  case PPC::BI__builtin_ppc_fetch_and_swap:
+  case PPC::BI__builtin_ppc_fetch_and_swaplp: {
+    return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E,
+                                 llvm::AtomicOrdering::Monotonic);
+  }
   }
 }
 
diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-fetch-error.c b/clang/test/CodeGen/builtins-ppc-xlcompat-fetch-error.c
new file mode 100644 (file)
index 0000000..a5124e3
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-aix -target-cpu pwr8 \
+// RUN:  -verify %s
+
+void test_builtin_ppc_fetch_and_add2() {
+  volatile int a = 0;
+  unsigned int b = 0;
+
+  __fetch_and_add(&a, b); // expected-warning {{passing 'volatile int *' to parameter of type 'volatile unsigned int *' converts between pointers to integer types with different sign}}
+}
+
+void test_builtin_ppc_fetch_and_addlp() {
+  volatile long a = 0;
+  unsigned long b = 0;
+
+  __fetch_and_addlp(&a, b); // expected-warning {{passing 'volatile long *' to parameter of type 'volatile unsigned long *' converts between pointers to integer types with different sign}}
+}
diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-fetch.c b/clang/test/CodeGen/builtins-ppc-xlcompat-fetch.c
new file mode 100644 (file)
index 0000000..7d0b674
--- /dev/null
@@ -0,0 +1,120 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown \
+// RUN:    -emit-llvm %s -o -  -target-cpu pwr8 | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown \
+// RUN:   -emit-llvm %s -o -  -target-cpu pwr8 | FileCheck %s
+
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_add(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[B:%.*]], i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw add i32* [[A_ADDR]], i32 [[TMP1]] monotonic, align 4
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_add(unsigned int a, unsigned int b) {
+  __fetch_and_add(&a, b);
+}
+
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_addlp(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
+// CHECK-NEXT:    store i64 [[B:%.*]], i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw add i64* [[A_ADDR]], i64 [[TMP1]] monotonic, align 8
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_addlp(unsigned long a, unsigned long b) {
+  __fetch_and_addlp(&a, b);
+}
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_and(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[B:%.*]], i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw and i32* [[A_ADDR]], i32 [[TMP1]] monotonic, align 4
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_and(unsigned int a, unsigned int b) {
+  __fetch_and_and(&a, b);
+}
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_andlp(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
+// CHECK-NEXT:    store i64 [[B:%.*]], i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw and i64* [[A_ADDR]], i64 [[TMP1]] monotonic, align 8
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_andlp(unsigned long a, unsigned long b) {
+  __fetch_and_andlp(&a, b);
+}
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_or(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[B:%.*]], i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw or i32* [[A_ADDR]], i32 [[TMP1]] monotonic, align 4
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_or(unsigned int a, unsigned int b) {
+  __fetch_and_or(&a, b);
+}
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_orlp(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
+// CHECK-NEXT:    store i64 [[B:%.*]], i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw or i64* [[A_ADDR]], i64 [[TMP1]] monotonic, align 8
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_orlp(unsigned long a, unsigned long b) {
+  __fetch_and_orlp(&a, b);
+}
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_swap(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[B:%.*]], i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw xchg i32* [[A_ADDR]], i32 [[TMP1]] monotonic, align 4
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_swap(unsigned int a, unsigned int b) {
+  __fetch_and_swap(&a, b);
+}
+// CHECK-LABEL: @test_builtin_ppc_fetch_and_swaplp(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
+// CHECK-NEXT:    store i64 [[B:%.*]], i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i64, i64* [[B_ADDR]], align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = atomicrmw xchg i64* [[A_ADDR]], i64 [[TMP1]] monotonic, align 8
+// CHECK-NEXT:    ret void
+//
+void test_builtin_ppc_fetch_and_swaplp(unsigned long a, unsigned long b) {
+  __fetch_and_swaplp(&a, b);
+}