colden created this revision. InterlockedCompareExchange128 is a bit more complicated than the other InterlockedCompareExchange functions, so it requires a bit more work. It doesn't directly refer to 128bit ints, instead it takes pointers to 64bit ints for Destination and ComparandResult, and exchange is taken as two 64bit ints (high & low). The previous value is written to ComparandResult, and success is returned. This implementation does the following in order to produce a cmpxchg instruction:
1. Cast everything to 128bit ints or int pointers, and glues together the Exchange values 2. Reads from CompareandResult to get the comparand 3. Calls cmpxchg volatile (on X86 this will produce a lock cmpxchg16b instruction) 1. Result 0 (previous value) is written back to ComparandResult 2. Result 1 (success bool) is zext'ed to a uchar and returned Resolves bug 35251 <https://bugs.llvm.org/show_bug.cgi?id=35251> https://reviews.llvm.org/D41032 Files: llvm/tools/clang/include/clang/Basic/Builtins.def llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp llvm/tools/clang/test/CodeGen/ms-intrinsics.c Index: llvm/tools/clang/test/CodeGen/ms-intrinsics.c =================================================================== --- llvm/tools/clang/test/CodeGen/ms-intrinsics.c +++ llvm/tools/clang/test/CodeGen/ms-intrinsics.c @@ -329,6 +329,25 @@ // CHECK: ret i64 [[RESULT]] // CHECK: } +unsigned char test_InterlockedCompareExchange128(__int64 volatile *Destination, __int64 ExchangeHigh, __int64 ExchangeLow, __int64* ComparandResult) { + return _InterlockedCompareExchange128(Destination, ExchangeHigh, ExchangeLow, ComparandResult); +} +// CHECK-X64: define{{.*}}i8 @test_InterlockedCompareExchange128(i64*{{[a-z_ ]*}}%Destination, i64{{[a-z_ ]*}}%ExchangeHigh, i64{{[a-z_ ]*}}%ExchangeLow, i64*{{[a-z_ ]*}}%ComparandResult){{.*}}{ +// CHECK-X64: [[DST:%[0-9]+]] = bitcast i64* %Destination to i128* +// CHECK-X64: [[EH:%[0-9]+]] = zext i64 %ExchangeHigh to i128 +// CHECK-X64: [[EL:%[0-9]+]] = zext i64 %ExchangeLow to i128 +// CHECK-X64: [[CNR:%[0-9]+]] = bitcast i64* %ComparandResult to i128* +// CHECK-X64: [[EHS:%[0-9]+]] = shl nuw i128 [[EH]], 64 +// CHECK-X64: [[EXP:%[0-9]+]] = or i128 [[EHS]], [[EL]] +// CHECK-X64: [[ORG:%[0-9]+]] = load i128, i128* [[CNR]], align 16 +// CHECK-X64: [[RES:%[0-9]+]] = cmpxchg volatile i128* [[DST]], i128 [[ORG]], i128 [[EXP]] seq_cst seq_cst +// CHECK-X64: [[OLD:%[0-9]+]] = extractvalue { i128, i1 } [[RES]], 0 +// CHECK-X64: store i128 [[OLD]], i128* [[CNR]], align 16 +// CHECK-X64: [[SUC1:%[0-9]+]] = extractvalue { i128, i1 } [[RES]], 1 +// CHECK-X64: [[SUC8:%[0-9]+]] = zext i1 [[SUC1]] to i8 +// CHECK-X64: ret i8 [[SUC8]] +// CHECK-X64: } + short test_InterlockedIncrement16(short volatile *Addend) { return _InterlockedIncrement16(Addend); } Index: llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -2521,6 +2521,47 @@ CXI->setVolatile(true); return RValue::get(Builder.CreateExtractValue(CXI, 0)); } + case Builtin::BI_InterlockedCompareExchange128: { + // InterlockedCompareExchange128 doesn't directly refer to 128bit ints, + // instead it takes pointers to 64bit ints for Destination and + // ComparandResult, and exchange is taken as two 64bit ints (high & low). + // The previous value is written to ComparandResult, and success is returned. + + llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); + llvm::Type *Int128PtrTy = Int128Ty->getPointerTo(); + + Value *Destination = Builder.CreateBitCast( + EmitScalarExpr(E->getArg(0)), Int128PtrTy); + Value *ExchangeHigh128 = Builder.CreateZExt( + EmitScalarExpr(E->getArg(1)), Int128Ty); + Value *ExchangeLow128 = Builder.CreateZExt( + EmitScalarExpr(E->getArg(2)), Int128Ty); + Address ComparandResult( + Builder.CreateBitCast(EmitScalarExpr(E->getArg(3)), Int128PtrTy), + getContext().toCharUnitsFromBits(128)); + + Value *Exchange = Builder.CreateOr( + Builder.CreateShl(ExchangeHigh128, 64, "", false, false), + ExchangeLow128); + + Value *Comparand = Builder.CreateLoad(ComparandResult); + + AtomicCmpXchgInst *CXI = Builder.CreateAtomicCmpXchg( + Destination, Comparand, Exchange, + AtomicOrdering::SequentiallyConsistent, + AtomicOrdering::SequentiallyConsistent); + CXI->setVolatile(true); + + // Write the result back to the inout pointer + Builder.CreateStore(Builder.CreateExtractValue(CXI, 0), ComparandResult); + + // Get success boolean + Value *Success = Builder.CreateExtractValue(CXI, 1); + + // zext the success boolean and return it + return RValue::get( + Builder.CreateZExt(Success, ConvertType(E->getType()))); + } case Builtin::BI_InterlockedIncrement16: case Builtin::BI_InterlockedIncrement: return RValue::get( Index: llvm/tools/clang/include/clang/Basic/Builtins.def =================================================================== --- llvm/tools/clang/include/clang/Basic/Builtins.def +++ llvm/tools/clang/include/clang/Basic/Builtins.def @@ -752,6 +752,7 @@ LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedCompareExchange128, "UcLLiD*LLiLLiLLi*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
Index: llvm/tools/clang/test/CodeGen/ms-intrinsics.c =================================================================== --- llvm/tools/clang/test/CodeGen/ms-intrinsics.c +++ llvm/tools/clang/test/CodeGen/ms-intrinsics.c @@ -329,6 +329,25 @@ // CHECK: ret i64 [[RESULT]] // CHECK: } +unsigned char test_InterlockedCompareExchange128(__int64 volatile *Destination, __int64 ExchangeHigh, __int64 ExchangeLow, __int64* ComparandResult) { + return _InterlockedCompareExchange128(Destination, ExchangeHigh, ExchangeLow, ComparandResult); +} +// CHECK-X64: define{{.*}}i8 @test_InterlockedCompareExchange128(i64*{{[a-z_ ]*}}%Destination, i64{{[a-z_ ]*}}%ExchangeHigh, i64{{[a-z_ ]*}}%ExchangeLow, i64*{{[a-z_ ]*}}%ComparandResult){{.*}}{ +// CHECK-X64: [[DST:%[0-9]+]] = bitcast i64* %Destination to i128* +// CHECK-X64: [[EH:%[0-9]+]] = zext i64 %ExchangeHigh to i128 +// CHECK-X64: [[EL:%[0-9]+]] = zext i64 %ExchangeLow to i128 +// CHECK-X64: [[CNR:%[0-9]+]] = bitcast i64* %ComparandResult to i128* +// CHECK-X64: [[EHS:%[0-9]+]] = shl nuw i128 [[EH]], 64 +// CHECK-X64: [[EXP:%[0-9]+]] = or i128 [[EHS]], [[EL]] +// CHECK-X64: [[ORG:%[0-9]+]] = load i128, i128* [[CNR]], align 16 +// CHECK-X64: [[RES:%[0-9]+]] = cmpxchg volatile i128* [[DST]], i128 [[ORG]], i128 [[EXP]] seq_cst seq_cst +// CHECK-X64: [[OLD:%[0-9]+]] = extractvalue { i128, i1 } [[RES]], 0 +// CHECK-X64: store i128 [[OLD]], i128* [[CNR]], align 16 +// CHECK-X64: [[SUC1:%[0-9]+]] = extractvalue { i128, i1 } [[RES]], 1 +// CHECK-X64: [[SUC8:%[0-9]+]] = zext i1 [[SUC1]] to i8 +// CHECK-X64: ret i8 [[SUC8]] +// CHECK-X64: } + short test_InterlockedIncrement16(short volatile *Addend) { return _InterlockedIncrement16(Addend); } Index: llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -2521,6 +2521,47 @@ CXI->setVolatile(true); return RValue::get(Builder.CreateExtractValue(CXI, 0)); } + case Builtin::BI_InterlockedCompareExchange128: { + // InterlockedCompareExchange128 doesn't directly refer to 128bit ints, + // instead it takes pointers to 64bit ints for Destination and + // ComparandResult, and exchange is taken as two 64bit ints (high & low). + // The previous value is written to ComparandResult, and success is returned. + + llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); + llvm::Type *Int128PtrTy = Int128Ty->getPointerTo(); + + Value *Destination = Builder.CreateBitCast( + EmitScalarExpr(E->getArg(0)), Int128PtrTy); + Value *ExchangeHigh128 = Builder.CreateZExt( + EmitScalarExpr(E->getArg(1)), Int128Ty); + Value *ExchangeLow128 = Builder.CreateZExt( + EmitScalarExpr(E->getArg(2)), Int128Ty); + Address ComparandResult( + Builder.CreateBitCast(EmitScalarExpr(E->getArg(3)), Int128PtrTy), + getContext().toCharUnitsFromBits(128)); + + Value *Exchange = Builder.CreateOr( + Builder.CreateShl(ExchangeHigh128, 64, "", false, false), + ExchangeLow128); + + Value *Comparand = Builder.CreateLoad(ComparandResult); + + AtomicCmpXchgInst *CXI = Builder.CreateAtomicCmpXchg( + Destination, Comparand, Exchange, + AtomicOrdering::SequentiallyConsistent, + AtomicOrdering::SequentiallyConsistent); + CXI->setVolatile(true); + + // Write the result back to the inout pointer + Builder.CreateStore(Builder.CreateExtractValue(CXI, 0), ComparandResult); + + // Get success boolean + Value *Success = Builder.CreateExtractValue(CXI, 1); + + // zext the success boolean and return it + return RValue::get( + Builder.CreateZExt(Success, ConvertType(E->getType()))); + } case Builtin::BI_InterlockedIncrement16: case Builtin::BI_InterlockedIncrement: return RValue::get( Index: llvm/tools/clang/include/clang/Basic/Builtins.def =================================================================== --- llvm/tools/clang/include/clang/Basic/Builtins.def +++ llvm/tools/clang/include/clang/Basic/Builtins.def @@ -752,6 +752,7 @@ LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedCompareExchange128, "UcLLiD*LLiLLiLLi*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits