Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/BuiltinsPPC.def
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,10 @@ TARGET_BUILTIN(__builtin_darn_32, "i", "", "isa-v30-instructions")
TARGET_BUILTIN(__builtin_unpack_vector_int128, "ULLiV1LLLii", "", "vsx")
TARGET_BUILTIN(__builtin_pack_vector_int128, "V1LLLiULLiULLi", "", "vsx")

// AMO builtins
TARGET_BUILTIN(__builtin_amo_lwat, "UiUi*UiIi", "", "isa-v30-instructions")
TARGET_BUILTIN(__builtin_amo_ldat, "ULiULi*ULiIi", "", "isa-v30-instructions")

// Set the floating point rounding mode
BUILTIN(__builtin_setrnd, "di", "")

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ set(opencl_files

set(ppc_files
altivec.h
amo.h
)

set(ppc_htm_files
Expand Down
97 changes: 97 additions & 0 deletions clang/lib/Headers/amo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*===---- amo.h - PowerPC Atomic Memory Operations ------------------------===*\
*
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
\*===----------------------------------------------------------------------===*/

/* This header provides compatibility wrappers for GCC's AMO functions.
* The functions here call Clang's underlying AMO builtins.
*/

#ifndef _AMO_H
#define _AMO_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* AMO Load Operation Codes (FC values) */
enum {
_AMO_LD_ADD = 0x00, /* Fetch and Add */
_AMO_LD_XOR = 0x01, /* Fetch and XOR */
_AMO_LD_IOR = 0x02, /* Fetch and OR */
_AMO_LD_AND = 0x03, /* Fetch and AND */
_AMO_LD_UMAX = 0x04, /* Fetch and Maximum Unsigned */
_AMO_LD_SMAX = 0x05, /* Fetch and Maximum Signed */
_AMO_LD_UMIN = 0x06, /* Fetch and Minimum Unsigned */
_AMO_LD_SMIN = 0x07, /* Fetch and Minimum Signed */
_AMO_LD_SWAP = 0x08 /* Swap */
};

/* 32-bit unsigned AMO load operations */
static inline uint32_t amo_lwat_add(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_ADD);
}

static inline uint32_t amo_lwat_xor(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_XOR);
}

static inline uint32_t amo_lwat_ior(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_IOR);
}

static inline uint32_t amo_lwat_and(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_AND);
}

static inline uint32_t amo_lwat_umax(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_UMAX);
}

static inline uint32_t amo_lwat_umin(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_UMIN);
}

static inline uint32_t amo_lwat_swap(uint32_t *ptr, uint32_t val) {
return __builtin_amo_lwat(ptr, val, _AMO_LD_SWAP);
}

/* 64-bit unsigned AMO load operations */
static inline uint64_t amo_ldat_add(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_ADD);
}

static inline uint64_t amo_ldat_xor(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_XOR);
}

static inline uint64_t amo_ldat_ior(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_IOR);
}

static inline uint64_t amo_ldat_and(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_AND);
}

static inline uint64_t amo_ldat_umax(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_UMAX);
}

static inline uint64_t amo_ldat_umin(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_UMIN);
}

static inline uint64_t amo_ldat_swap(uint64_t *ptr, uint64_t val) {
return __builtin_amo_ldat(ptr, val, _AMO_LD_SWAP);
}

#ifdef __cplusplus
}
#endif

#endif /* _AMO_H */
15 changes: 15 additions & 0 deletions clang/lib/Sema/SemaPPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ static bool isPPC_64Builtin(unsigned BuiltinID) {
case PPC::BI__builtin_ppc_fetch_and_andlp:
case PPC::BI__builtin_ppc_fetch_and_orlp:
case PPC::BI__builtin_ppc_fetch_and_swaplp:
case PPC::BI__builtin_amo_lwat:
case PPC::BI__builtin_amo_ldat:
return true;
}
return false;
Expand Down Expand Up @@ -253,6 +255,19 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI,
case PPC::BI__builtin_##Name: \
return BuiltinPPCMMACall(TheCall, BuiltinID, Types);
#include "clang/Basic/BuiltinsPPC.def"
case PPC::BI__builtin_amo_lwat:
case PPC::BI__builtin_amo_ldat: {
llvm::APSInt Result;
if (SemaRef.BuiltinConstantArg(TheCall, 2, Result))
return true;
unsigned Val = Result.getZExtValue();
static constexpr unsigned ValidFC[] = {0, 1, 2, 3, 4, 6, 8};
if (llvm::is_contained(ValidFC, Val))
return false;
Expr *Arg = TheCall->getArg(2);
return SemaRef.Diag(Arg->getBeginLoc(), diag::err_argument_invalid_range)
<< toString(Result, 10) << "0-4, 6" << "8" << Arg->getSourceRange();
}
}
llvm_unreachable("must return from switch");
}
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGen/PowerPC/builtins-amo-err.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: not %clang_cc1 -triple powerpc-ibm-aix -target-cpu pwr9 \
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=AIX32-ERROR
// RUN: not %clang_cc1 -triple powerpc64-ibm-aix -target-cpu pwr9 \
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=FC-ERROR

void test_amo() {
unsigned int *ptr1, value1;
// AIX32-ERROR: error: this builtin is only available on 64-bit targets
__builtin_amo_lwat(ptr1, value1, 0);
// FC-ERROR: argument value 9 is outside the valid range [0-4, 6, 8]
__builtin_amo_lwat(ptr1, value1, 9);

unsigned long int *ptr2, value2;
// AIX32-ERROR: error: this builtin is only available on 64-bit targets
__builtin_amo_ldat(ptr2, value2, 3);
// FC-ERROR: error: argument value 26 is outside the valid range [0-4, 6, 8]
__builtin_amo_ldat(ptr2, value2, 26);
}
58 changes: 58 additions & 0 deletions clang/test/CodeGen/PowerPC/builtins-ppc-amo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
// RUN: %clang_cc1 -O3 -triple powerpc64le-unknown-unknown -target-cpu pwr9 \
// RUN: -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -O3 -triple powerpc64-ibm-aix -target-cpu pwr9 \
// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=AIX

// CHECK-LABEL: define dso_local void @test_unsigned_lwat(
// CHECK-SAME: ptr noundef [[PTR:%.*]], i32 noundef zeroext [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 4)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ppc.amo.lwat(ptr [[PTR]], i32 [[VALUE]], i32 0)
// CHECK-NEXT: store i32 [[TMP0]], ptr [[RESP]], align 4, !tbaa [[INT_TBAA2:![0-9]+]]
// CHECK-NEXT: ret void
//
// AIX-LABEL: define void @test_unsigned_lwat(
// AIX-SAME: ptr noundef [[PTR:%.*]], i32 noundef zeroext [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 4)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// AIX-NEXT: [[ENTRY:.*:]]
// AIX-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ppc.amo.lwat(ptr [[PTR]], i32 [[VALUE]], i32 0)
// AIX-NEXT: store i32 [[TMP0]], ptr [[RESP]], align 4, !tbaa [[INT_TBAA2:![0-9]+]]
// AIX-NEXT: ret void
//
void test_unsigned_lwat(unsigned int *ptr, unsigned int value, unsigned int * resp) {
unsigned int res = __builtin_amo_lwat(ptr, value, 0);
*resp = res;
}

// CHECK-LABEL: define dso_local void @test_unsigned_ldat(
// CHECK-SAME: ptr noundef [[PTR:%.*]], i64 noundef [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 8)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ppc.amo.ldat(ptr [[PTR]], i64 [[VALUE]], i32 3)
// CHECK-NEXT: store i64 [[TMP0]], ptr [[RESP]], align 8, !tbaa [[LONG_TBAA6:![0-9]+]]
// CHECK-NEXT: ret void
//
// AIX-LABEL: define void @test_unsigned_ldat(
// AIX-SAME: ptr noundef [[PTR:%.*]], i64 noundef [[VALUE:%.*]], ptr noundef writeonly captures(none) initializes((0, 8)) [[RESP:%.*]]) local_unnamed_addr #[[ATTR0]] {
// AIX-NEXT: [[ENTRY:.*:]]
// AIX-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ppc.amo.ldat(ptr [[PTR]], i64 [[VALUE]], i32 3)
// AIX-NEXT: store i64 [[TMP0]], ptr [[RESP]], align 8, !tbaa [[LONG_TBAA6:![0-9]+]]
// AIX-NEXT: ret void
//
void test_unsigned_ldat(unsigned long int *ptr, unsigned long int value, unsigned long int * resp) {
unsigned long int res = __builtin_amo_ldat(ptr, value, 3);
*resp = res;
}
//.
// CHECK: [[INT_TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
// CHECK: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
// CHECK: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
// CHECK: [[META5]] = !{!"Simple C/C++ TBAA"}
// CHECK: [[LONG_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
// CHECK: [[META7]] = !{!"long", [[META4]], i64 0}
//.
// AIX: [[INT_TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
// AIX: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
// AIX: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
// AIX: [[META5]] = !{!"Simple C/C++ TBAA"}
// AIX: [[LONG_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
// AIX: [[META7]] = !{!"long", [[META4]], i64 0}
//.
91 changes: 91 additions & 0 deletions clang/test/CodeGen/PowerPC/ppc-amo-header.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// REQUIRES: powerpc-registered-target
// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -target-cpu pwr9 \
// RUN: -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple powerpc64-ibm-aix -target-cpu pwr9 \
// RUN: -emit-llvm %s -o - | FileCheck %s

#include <amo.h>

uint32_t test_lwat_add(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_add
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 0)
return amo_lwat_add(ptr, val);
}

uint32_t test_lwat_xor(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_xor
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 1)
return amo_lwat_xor(ptr, val);
}

uint32_t test_lwat_ior(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_ior
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 2)
return amo_lwat_ior(ptr, val);
}

uint32_t test_lwat_and(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_and
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 3)
return amo_lwat_and(ptr, val);
}

uint32_t test_lwat_umax(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_umax
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 4)
return amo_lwat_umax(ptr, val);
}

uint32_t test_lwat_umin(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_umin
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 6)
return amo_lwat_umin(ptr, val);
}

uint32_t test_lwat_swap(uint32_t *ptr, uint32_t val) {
// CHECK-LABEL: @test_lwat_swap
// CHECK: call i32 @llvm.ppc.amo.lwat(ptr %{{.*}}, i32 %{{.*}}, i32 8)
return amo_lwat_swap(ptr, val);
}

uint64_t test_ldat_add(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_add
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 0)
return amo_ldat_add(ptr, val);
}

uint64_t test_ldat_xor(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_xor
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 1)
return amo_ldat_xor(ptr, val);
}

uint64_t test_ldat_ior(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_ior
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 2)
return amo_ldat_ior(ptr, val);
}

uint64_t test_ldat_and(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_and
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 3)
return amo_ldat_and(ptr, val);
}

uint64_t test_ldat_umax(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_umax
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 4)
return amo_ldat_umax(ptr, val);
}

uint64_t test_ldat_umin(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_umin
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 6)
return amo_ldat_umin(ptr, val);
}

uint64_t test_ldat_swap(uint64_t *ptr, uint64_t val) {
// CHECK-LABEL: @test_ldat_swap
// CHECK: call i64 @llvm.ppc.amo.ldat(ptr %{{.*}}, i64 %{{.*}}, i32 8)
return amo_ldat_swap(ptr, val);
}
12 changes: 12 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsPowerPC.td
Original file line number Diff line number Diff line change
Expand Up @@ -2139,3 +2139,15 @@ let TargetPrefix = "ppc" in {
Intrinsic<[], [llvm_i64_ty, llvm_i64_ty, llvm_ptr_ty],
[IntrArgMemOnly, IntrWriteMem, NoCapture<ArgIndex<2>>]>;
}

// AMO intrisics
let TargetPrefix = "ppc" in {
def int_ppc_amo_lwat : ClangBuiltin<"__builtin_amo_lwat">,
DefaultAttrsIntrinsic<[llvm_i32_ty],[llvm_ptr_ty,
llvm_i32_ty, llvm_i32_ty],
[IntrArgMemOnly, ImmArg<ArgIndex<2>>]>;
def int_ppc_amo_ldat : ClangBuiltin<"__builtin_amo_ldat">,
DefaultAttrsIntrinsic<[llvm_i64_ty],[llvm_ptr_ty,
llvm_i64_ty, llvm_i32_ty],
[IntrArgMemOnly, ImmArg<ArgIndex<2>>]>;
}
Loading
Loading