diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index 062266bb485..c9ec6bc1f99 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -382,13 +382,14 @@ let neverHasSideEffects = 1 in { def LRVGR : UnaryRRE<"lrvgr", 0xB90F, bswap, GR64, GR64>; } -// Byte-swapping loads. -def LRV : UnaryRXY<"lrv", 0xE31E, loadu, GR32>; -def LRVG : UnaryRXY<"lrvg", 0xE30F, loadu, GR64>; +// Byte-swapping loads. Unlike normal loads, these instructions are +// allowed to access storage more than once. +def LRV : UnaryRXY<"lrv", 0xE31E, loadu, GR32>; +def LRVG : UnaryRXY<"lrvg", 0xE30F, loadu, GR64>; -// Byte-swapping stores. -def STRV : StoreRXY<"strv", 0xE33E, storeu, GR32>; -def STRVG : StoreRXY<"strvg", 0xE32F, storeu, GR64>; +// Likewise byte-swapping stores. +def STRV : StoreRXY<"strv", 0xE33E, storeu, GR32>; +def STRVG : StoreRXY<"strvg", 0xE32F, storeu, GR64>; //===----------------------------------------------------------------------===// // Load address instructions diff --git a/lib/Target/SystemZ/SystemZOperators.td b/lib/Target/SystemZ/SystemZOperators.td index 8c4df56b461..ab01b2527a8 100644 --- a/lib/Target/SystemZ/SystemZOperators.td +++ b/lib/Target/SystemZ/SystemZOperators.td @@ -142,6 +142,23 @@ def aligned_store : AlignedStore; def aligned_truncstorei16 : AlignedStore; def aligned_truncstorei32 : AlignedStore; +// Non-volatile loads. Used for instructions that might access the storage +// location multiple times. +class NonvolatileLoad + : PatFrag<(ops node:$addr), (load node:$addr), [{ + LoadSDNode *Load = cast(N); + return !Load->isVolatile(); +}]>; +def nonvolatile_load : NonvolatileLoad; + +// Non-volatile stores. +class NonvolatileStore + : PatFrag<(ops node:$src, node:$addr), (store node:$src, node:$addr), [{ + StoreSDNode *Store = cast(N); + return !Store->isVolatile(); +}]>; +def nonvolatile_store : NonvolatileStore; + // Insertions. def inserti8 : PatFrag<(ops node:$src1, node:$src2), (or (and node:$src1, -256), node:$src2)>; @@ -186,11 +203,11 @@ def fnabs : PatFrag<(ops node:$ptr), (fneg (fabs node:$ptr))>; // Create a unary operator that loads from memory and then performs // the given operation on it. -class loadu +class loadu : PatFrag<(ops node:$addr), (operator (load node:$addr))>; // Create a store operator that performs the given unary operation // on the value before storing it. -class storeu +class storeu : PatFrag<(ops node:$value, node:$addr), (store (operator node:$value), node:$addr)>; diff --git a/test/CodeGen/SystemZ/bswap-02.ll b/test/CodeGen/SystemZ/bswap-02.ll index e9b7eb5f055..8b99077f4c1 100644 --- a/test/CodeGen/SystemZ/bswap-02.ll +++ b/test/CodeGen/SystemZ/bswap-02.ll @@ -85,3 +85,15 @@ define i32 @f7(i64 %src, i64 %index) { %swapped = call i32 @llvm.bswap.i32(i32 %a) ret i32 %swapped } + +; Check that volatile accesses do not use LRV, which might access the +; storage multple times. +define i32 @f8(i32 *%src) { +; CHECK: f8: +; CHECK: l [[REG:%r[0-5]]], 0(%r2) +; CHECK: lrvr %r2, [[REG]] +; CHECK: br %r14 + %a = load volatile i32 *%src + %swapped = call i32 @llvm.bswap.i32(i32 %a) + ret i32 %swapped +} diff --git a/test/CodeGen/SystemZ/bswap-03.ll b/test/CodeGen/SystemZ/bswap-03.ll index 2e6bcdce265..df6624e5b46 100644 --- a/test/CodeGen/SystemZ/bswap-03.ll +++ b/test/CodeGen/SystemZ/bswap-03.ll @@ -85,3 +85,15 @@ define i64 @f7(i64 %src, i64 %index) { %swapped = call i64 @llvm.bswap.i64(i64 %a) ret i64 %swapped } + +; Check that volatile accesses do not use LRVG, which might access the +; storage multple times. +define i64 @f8(i64 *%src) { +; CHECK: f8: +; CHECK: lg [[REG:%r[0-5]]], 0(%r2) +; CHECK: lrvgr %r2, [[REG]] +; CHECK: br %r14 + %a = load volatile i64 *%src + %swapped = call i64 @llvm.bswap.i64(i64 %a) + ret i64 %swapped +} diff --git a/test/CodeGen/SystemZ/bswap-04.ll b/test/CodeGen/SystemZ/bswap-04.ll index 192327bd256..63b202044e4 100644 --- a/test/CodeGen/SystemZ/bswap-04.ll +++ b/test/CodeGen/SystemZ/bswap-04.ll @@ -5,21 +5,21 @@ declare i32 @llvm.bswap.i32(i32 %a) ; Check STRV with no displacement. -define void @f1(i32 *%src, i32 %a) { +define void @f1(i32 *%dst, i32 %a) { ; CHECK: f1: ; CHECK: strv %r3, 0(%r2) ; CHECK: br %r14 %swapped = call i32 @llvm.bswap.i32(i32 %a) - store i32 %swapped, i32 *%src + store i32 %swapped, i32 *%dst ret void } ; Check the high end of the aligned STRV range. -define void @f2(i32 *%src, i32 %a) { +define void @f2(i32 *%dst, i32 %a) { ; CHECK: f2: ; CHECK: strv %r3, 524284(%r2) ; CHECK: br %r14 - %ptr = getelementptr i32 *%src, i64 131071 + %ptr = getelementptr i32 *%dst, i64 131071 %swapped = call i32 @llvm.bswap.i32(i32 %a) store i32 %swapped, i32 *%ptr ret void @@ -27,34 +27,34 @@ define void @f2(i32 *%src, i32 %a) { ; Check the next word up, which needs separate address logic. ; Other sequences besides this one would be OK. -define void @f3(i32 *%src, i32 %a) { +define void @f3(i32 *%dst, i32 %a) { ; CHECK: f3: ; CHECK: agfi %r2, 524288 ; CHECK: strv %r3, 0(%r2) ; CHECK: br %r14 - %ptr = getelementptr i32 *%src, i64 131072 + %ptr = getelementptr i32 *%dst, i64 131072 %swapped = call i32 @llvm.bswap.i32(i32 %a) store i32 %swapped, i32 *%ptr ret void } ; Check the high end of the negative aligned STRV range. -define void @f4(i32 *%src, i32 %a) { +define void @f4(i32 *%dst, i32 %a) { ; CHECK: f4: ; CHECK: strv %r3, -4(%r2) ; CHECK: br %r14 - %ptr = getelementptr i32 *%src, i64 -1 + %ptr = getelementptr i32 *%dst, i64 -1 %swapped = call i32 @llvm.bswap.i32(i32 %a) store i32 %swapped, i32 *%ptr ret void } ; Check the low end of the STRV range. -define void @f5(i32 *%src, i32 %a) { +define void @f5(i32 *%dst, i32 %a) { ; CHECK: f5: ; CHECK: strv %r3, -524288(%r2) ; CHECK: br %r14 - %ptr = getelementptr i32 *%src, i64 -131072 + %ptr = getelementptr i32 *%dst, i64 -131072 %swapped = call i32 @llvm.bswap.i32(i32 %a) store i32 %swapped, i32 *%ptr ret void @@ -62,12 +62,12 @@ define void @f5(i32 *%src, i32 %a) { ; Check the next word down, which needs separate address logic. ; Other sequences besides this one would be OK. -define void @f6(i32 *%src, i32 %a) { +define void @f6(i32 *%dst, i32 %a) { ; CHECK: f6: ; CHECK: agfi %r2, -524292 ; CHECK: strv %r3, 0(%r2) ; CHECK: br %r14 - %ptr = getelementptr i32 *%src, i64 -131073 + %ptr = getelementptr i32 *%dst, i64 -131073 %swapped = call i32 @llvm.bswap.i32(i32 %a) store i32 %swapped, i32 *%ptr ret void @@ -85,3 +85,15 @@ define void @f7(i64 %src, i64 %index, i32 %a) { store i32 %swapped, i32 *%ptr ret void } + +; Check that volatile stores do not use STRV, which might access the +; storage multple times. +define void @f8(i32 *%dst, i32 %a) { +; CHECK: f8: +; CHECK: lrvr [[REG:%r[0-5]]], %r3 +; CHECK: st [[REG]], 0(%r2) +; CHECK: br %r14 + %swapped = call i32 @llvm.bswap.i32(i32 %a) + store volatile i32 %swapped, i32 *%dst + ret void +} diff --git a/test/CodeGen/SystemZ/bswap-05.ll b/test/CodeGen/SystemZ/bswap-05.ll index e58cb80c398..6f25d3c10ab 100644 --- a/test/CodeGen/SystemZ/bswap-05.ll +++ b/test/CodeGen/SystemZ/bswap-05.ll @@ -5,21 +5,21 @@ declare i64 @llvm.bswap.i64(i64 %a) ; Check STRVG with no displacement. -define void @f1(i64 *%src, i64 %a) { +define void @f1(i64 *%dst, i64 %a) { ; CHECK: f1: ; CHECK: strvg %r3, 0(%r2) ; CHECK: br %r14 %swapped = call i64 @llvm.bswap.i64(i64 %a) - store i64 %swapped, i64 *%src + store i64 %swapped, i64 *%dst ret void } ; Check the high end of the aligned STRVG range. -define void @f2(i64 *%src, i64 %a) { +define void @f2(i64 *%dst, i64 %a) { ; CHECK: f2: ; CHECK: strvg %r3, 524280(%r2) ; CHECK: br %r14 - %ptr = getelementptr i64 *%src, i64 65535 + %ptr = getelementptr i64 *%dst, i64 65535 %swapped = call i64 @llvm.bswap.i64(i64 %a) store i64 %swapped, i64 *%ptr ret void @@ -27,34 +27,34 @@ define void @f2(i64 *%src, i64 %a) { ; Check the next doubleword up, which needs separate address logic. ; Other sequences besides this one would be OK. -define void @f3(i64 *%src, i64 %a) { +define void @f3(i64 *%dst, i64 %a) { ; CHECK: f3: ; CHECK: agfi %r2, 524288 ; CHECK: strvg %r3, 0(%r2) ; CHECK: br %r14 - %ptr = getelementptr i64 *%src, i64 65536 + %ptr = getelementptr i64 *%dst, i64 65536 %swapped = call i64 @llvm.bswap.i64(i64 %a) store i64 %swapped, i64 *%ptr ret void } ; Check the high end of the negative aligned STRVG range. -define void @f4(i64 *%src, i64 %a) { +define void @f4(i64 *%dst, i64 %a) { ; CHECK: f4: ; CHECK: strvg %r3, -8(%r2) ; CHECK: br %r14 - %ptr = getelementptr i64 *%src, i64 -1 + %ptr = getelementptr i64 *%dst, i64 -1 %swapped = call i64 @llvm.bswap.i64(i64 %a) store i64 %swapped, i64 *%ptr ret void } ; Check the low end of the STRVG range. -define void @f5(i64 *%src, i64 %a) { +define void @f5(i64 *%dst, i64 %a) { ; CHECK: f5: ; CHECK: strvg %r3, -524288(%r2) ; CHECK: br %r14 - %ptr = getelementptr i64 *%src, i64 -65536 + %ptr = getelementptr i64 *%dst, i64 -65536 %swapped = call i64 @llvm.bswap.i64(i64 %a) store i64 %swapped, i64 *%ptr ret void @@ -62,12 +62,12 @@ define void @f5(i64 *%src, i64 %a) { ; Check the next doubleword down, which needs separate address logic. ; Other sequences besides this one would be OK. -define void @f6(i64 *%src, i64 %a) { +define void @f6(i64 *%dst, i64 %a) { ; CHECK: f6: ; CHECK: agfi %r2, -524296 ; CHECK: strvg %r3, 0(%r2) ; CHECK: br %r14 - %ptr = getelementptr i64 *%src, i64 -65537 + %ptr = getelementptr i64 *%dst, i64 -65537 %swapped = call i64 @llvm.bswap.i64(i64 %a) store i64 %swapped, i64 *%ptr ret void @@ -85,3 +85,15 @@ define void @f7(i64 %src, i64 %index, i64 %a) { store i64 %swapped, i64 *%ptr ret void } + +; Check that volatile stores do not use STRVG, which might access the +; storage multple times. +define void @f8(i64 *%dst, i64 %a) { +; CHECK: f8: +; CHECK: lrvgr [[REG:%r[0-5]]], %r3 +; CHECK: stg [[REG]], 0(%r2) +; CHECK: br %r14 + %swapped = call i64 @llvm.bswap.i64(i64 %a) + store volatile i64 %swapped, i64 *%dst + ret void +}