56 changes: 36 additions & 20 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ def SDT_PPCstbrx : SDTypeProfile<0, 3, [
SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>
]>;

def SDT_PPClarx : SDTypeProfile<1, 1, [
SDTCisInt<0>, SDTCisPtrTy<1>
]>;
def SDT_PPCstcx : SDTypeProfile<0, 2, [
SDTCisInt<0>, SDTCisPtrTy<1>
]>;

def SDT_PPCTC_ret : SDTypeProfile<0, 2, [
SDTCisPtrTy<0>, SDTCisVT<1, i32>
]>;
Expand Down Expand Up @@ -225,12 +218,6 @@ def PPCcr6set : SDNode<"PPCISD::CR6SET", SDTNone,
def PPCcr6unset : SDNode<"PPCISD::CR6UNSET", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;

// Instructions to support atomic operations
def PPClarx : SDNode<"PPCISD::LARX", SDT_PPClarx,
[SDNPHasChain, SDNPMayLoad]>;
def PPCstcx : SDNode<"PPCISD::STCX", SDT_PPCstcx,
[SDNPHasChain, SDNPMayStore]>;

// Instructions to support dynamic alloca.
def SDTDynOp : SDTypeProfile<1, 2, []>;
def PPCdynalloc : SDNode<"PPCISD::DYNALLOC", SDTDynOp, [SDNPHasChain]>;
Expand Down Expand Up @@ -724,7 +711,7 @@ def IsPPC6xx : Predicate<"PPCSubTarget->isPPC6xx()">;
def IsE500 : Predicate<"PPCSubTarget->isE500()">;
def HasSPE : Predicate<"PPCSubTarget->HasSPE()">;
def HasICBT : Predicate<"PPCSubTarget->hasICBT()">;

def HasPartwordAtomics : Predicate<"PPCSubTarget->hasPartwordAtomics()">;
def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">;
def NaNsFPMath : Predicate<"!TM.Options.NoNaNsFPMath">;

Expand Down Expand Up @@ -1455,15 +1442,44 @@ let usesCustomInserter = 1 in {
}

// Instructions to support atomic operations
let mayLoad = 1, hasSideEffects = 0 in {
def LBARX : XForm_1<31, 52, (outs gprc:$rD), (ins memrr:$src),
"lbarx $rD, $src", IIC_LdStLWARX, []>,
Requires<[HasPartwordAtomics]>;

def LHARX : XForm_1<31, 116, (outs gprc:$rD), (ins memrr:$src),
"lharx $rD, $src", IIC_LdStLWARX, []>,
Requires<[HasPartwordAtomics]>;

def LWARX : XForm_1<31, 20, (outs gprc:$rD), (ins memrr:$src),
"lwarx $rD, $src", IIC_LdStLWARX,
[(set i32:$rD, (PPClarx xoaddr:$src))]>;
"lwarx $rD, $src", IIC_LdStLWARX, []>;

// Instructions to support lock versions of atomics
// (EH=1 - see Power ISA 2.07 Book II 4.4.2)
def LBARXL : XForm_1<31, 52, (outs gprc:$rD), (ins memrr:$src),
"lbarx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT,
Requires<[HasPartwordAtomics]>;

def LHARXL : XForm_1<31, 116, (outs gprc:$rD), (ins memrr:$src),
"lharx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT,
Requires<[HasPartwordAtomics]>;

def LWARXL : XForm_1<31, 20, (outs gprc:$rD), (ins memrr:$src),
"lwarx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT;
}

let Defs = [CR0], mayStore = 1, hasSideEffects = 0 in {
def STBCX : XForm_1<31, 694, (outs), (ins gprc:$rS, memrr:$dst),
"stbcx. $rS, $dst", IIC_LdStSTWCX, []>,
isDOT, Requires<[HasPartwordAtomics]>;

def STHCX : XForm_1<31, 726, (outs), (ins gprc:$rS, memrr:$dst),
"sthcx. $rS, $dst", IIC_LdStSTWCX, []>,
isDOT, Requires<[HasPartwordAtomics]>;

let Defs = [CR0] in
def STWCX : XForm_1<31, 150, (outs), (ins gprc:$rS, memrr:$dst),
"stwcx. $rS, $dst", IIC_LdStSTWCX,
[(PPCstcx i32:$rS, xoaddr:$dst)]>,
isDOT;
"stwcx. $rS, $dst", IIC_LdStSTWCX, []>, isDOT;
}

let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in
def TRAP : XForm_24<31, 4, (outs), (ins), "trap", IIC_LdStLoad, [(trap)]>;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/PowerPC/PPCSubtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ void PPCSubtarget::initializeEnvironment() {
HasLazyResolverStubs = false;
HasICBT = false;
HasInvariantFunctionDescriptors = false;
HasPartwordAtomics = false;
IsQPXStackUnaligned = false;
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/PowerPC/PPCSubtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
bool IsLittleEndian;
bool HasICBT;
bool HasInvariantFunctionDescriptors;
bool HasPartwordAtomics;

/// When targeting QPX running a stock PPC64 Linux kernel where the stack
/// alignment has not been changed, we need to keep the 16-byte alignment
Expand Down Expand Up @@ -236,6 +237,7 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
bool hasInvariantFunctionDescriptors() const {
return HasInvariantFunctionDescriptors;
}
bool hasPartwordAtomics() const { return HasPartwordAtomics; }

bool isQPXStackUnaligned() const { return IsQPXStackUnaligned; }
unsigned getPlatformStackAlignment() const {
Expand Down
54 changes: 54 additions & 0 deletions llvm/test/CodeGen/PowerPC/atomic-2.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
; RUN: llc < %s -march=ppc64 | FileCheck %s
; RUN: llc < %s -march=ppc64 -mcpu=pwr7 | FileCheck %s -check-prefix=CHECK-P7U
; RUN: llc < %s -march=ppc64 -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-P7U

define i64 @exchange_and_add(i64* %mem, i64 %val) nounwind {
; CHECK-LABEL: exchange_and_add:
Expand All @@ -8,6 +10,22 @@ define i64 @exchange_and_add(i64* %mem, i64 %val) nounwind {
ret i64 %tmp
}

define i8 @exchange_and_add8(i8* %mem, i8 %val) nounwind {
; CHECK-LABEL: exchange_and_add8:
; CHECK-P7U: lbarx
%tmp = atomicrmw add i8* %mem, i8 %val monotonic
; CHECK-P7U: stbcx.
ret i8 %tmp
}

define i16 @exchange_and_add16(i16* %mem, i16 %val) nounwind {
; CHECK-LABEL: exchange_and_add16:
; CHECK-P7U: lharx
%tmp = atomicrmw add i16* %mem, i16 %val monotonic
; CHECK-P7U: sthcx.
ret i16 %tmp
}

define i64 @exchange_and_cmp(i64* %mem) nounwind {
; CHECK-LABEL: exchange_and_cmp:
; CHECK: ldarx
Expand All @@ -18,6 +36,26 @@ define i64 @exchange_and_cmp(i64* %mem) nounwind {
ret i64 %tmp
}

define i8 @exchange_and_cmp8(i8* %mem) nounwind {
; CHECK-LABEL: exchange_and_cmp8:
; CHECK-P7U: lbarx
%tmppair = cmpxchg i8* %mem, i8 0, i8 1 monotonic monotonic
%tmp = extractvalue { i8, i1 } %tmppair, 0
; CHECK-P7U: stbcx.
; CHECK-P7U: stbcx.
ret i8 %tmp
}

define i16 @exchange_and_cmp16(i16* %mem) nounwind {
; CHECK-LABEL: exchange_and_cmp16:
; CHECK-P7U: lharx
%tmppair = cmpxchg i16* %mem, i16 0, i16 1 monotonic monotonic
%tmp = extractvalue { i16, i1 } %tmppair, 0
; CHECK-P7U: sthcx.
; CHECK-P7U: sthcx.
ret i16 %tmp
}

define i64 @exchange(i64* %mem, i64 %val) nounwind {
; CHECK-LABEL: exchange:
; CHECK: ldarx
Expand All @@ -26,6 +64,22 @@ define i64 @exchange(i64* %mem, i64 %val) nounwind {
ret i64 %tmp
}

define i8 @exchange8(i8* %mem, i8 %val) nounwind {
; CHECK-LABEL: exchange8:
; CHECK-P7U: lbarx
%tmp = atomicrmw xchg i8* %mem, i8 1 monotonic
; CHECK-P7U: stbcx.
ret i8 %tmp
}

define i16 @exchange16(i16* %mem, i16 %val) nounwind {
; CHECK-LABEL: exchange16:
; CHECK-P7U: lharx
%tmp = atomicrmw xchg i16* %mem, i16 1 monotonic
; CHECK-P7U: sthcx.
ret i16 %tmp
}

define void @atomic_store(i64* %mem, i64 %val) nounwind {
entry:
; CHECK: @atomic_store
Expand Down
22 changes: 20 additions & 2 deletions llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-bookII.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,30 @@
# CHECK: dcbf 2, 3
0x7c 0x02 0x18 0xac

# CHECK: lwarx 2, 3, 4
# CHECK: lbarx 2, 3, 4
0x7c 0x43 0x20 0x68

# CHECK: lharx 2, 3, 4
0x7c 0x43 0x20 0xe8

# CHECK: lwarx 2, 3, 4
0x7c 0x43 0x20 0x28

# CHECK: ldarx 2, 3, 4
# CHECK: ldarx 2, 3, 4
0x7c 0x43 0x20 0xa8

# CHECK: lbarx 2, 3, 4, 1
0x7c 0x43 0x20 0x69

# CHECK: lharx 2, 3, 4, 1
0x7c 0x43 0x20 0xe9

# CHECK: lwarx 2, 3, 4, 1
0x7c 0x43 0x20 0x29

# CHECK: ldarx 2, 3, 4, 1
0x7c 0x43 0x20 0xa9

# CHECK: sync 0
0x7c 0x00 0x04 0xac

Expand Down
32 changes: 25 additions & 7 deletions llvm/test/MC/PowerPC/ppc64-encoding-bookII.s
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@
# CHECK-LE: isync # encoding: [0x2c,0x01,0x00,0x4c]
isync

# FIXME: lbarx 2, 3, 4, 1
# FIXME: lharx 2, 3, 4, 1
# FIXME: lwarx 2, 3, 4, 1
# FIXME: ldarx 2, 3, 4, 1

# FIXME: stbcx. 2, 3, 4
# FIXME: sthcx. 2, 3, 4
# CHECK-BE: stwcx. 2, 3, 4 # encoding: [0x7c,0x43,0x21,0x2d]
Expand Down Expand Up @@ -70,15 +65,38 @@
dcbf 2, 3
# FIXME: dcbfl 2, 3

# FIXME: lbarx 2, 3, 4
# FIXME: lharx 2, 3, 4
# CHECK-BE: lbarx 2, 3, 4 # encoding: [0x7c,0x43,0x20,0x68]
# CHECK-LE: lbarx 2, 3, 4 # encoding: [0x68,0x20,0x43,0x7c]
lbarx 2, 3, 4

# CHECK-BE: lharx 2, 3, 4 # encoding: [0x7c,0x43,0x20,0xe8]
# CHECK-LE: lharx 2, 3, 4 # encoding: [0xe8,0x20,0x43,0x7c]
lharx 2, 3, 4

# CHECK-BE: lwarx 2, 3, 4 # encoding: [0x7c,0x43,0x20,0x28]
# CHECK-LE: lwarx 2, 3, 4 # encoding: [0x28,0x20,0x43,0x7c]
lwarx 2, 3, 4

# CHECK-BE: ldarx 2, 3, 4 # encoding: [0x7c,0x43,0x20,0xa8]
# CHECK-LE: ldarx 2, 3, 4 # encoding: [0xa8,0x20,0x43,0x7c]
ldarx 2, 3, 4

# CHECK-BE: lbarx 2, 3, 4, 1 # encoding: [0x7c,0x43,0x20,0x69]
# CHECK-LE: lbarx 2, 3, 4, 1 # encoding: [0x69,0x20,0x43,0x7c]
lbarx 2, 3, 4, 1

# CHECK-BE: lharx 2, 3, 4, 1 # encoding: [0x7c,0x43,0x20,0xe9]
# CHECK-LE: lharx 2, 3, 4, 1 # encoding: [0xe9,0x20,0x43,0x7c]
lharx 2, 3, 4, 1

# CHECK-BE: lwarx 2, 3, 4, 1 # encoding: [0x7c,0x43,0x20,0x29]
# CHECK-LE: lwarx 2, 3, 4, 1 # encoding: [0x29,0x20,0x43,0x7c]
lwarx 2, 3, 4, 1

# CHECK-BE: ldarx 2, 3, 4, 1 # encoding: [0x7c,0x43,0x20,0xa9]
# CHECK-LE: ldarx 2, 3, 4, 1 # encoding: [0xa9,0x20,0x43,0x7c]
ldarx 2, 3, 4, 1

# CHECK-BE: sync 0 # encoding: [0x7c,0x00,0x04,0xac]
# CHECK-LE: sync 0 # encoding: [0xac,0x04,0x00,0x7c]
sync
Expand Down