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/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/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); }