From e0e2a57e3d6c43e15fe2b9001c75f92c20c2c51d Mon Sep 17 00:00:00 2001 From: Vladimir Sukharev Date: Mon, 11 Sep 2023 21:28:34 +0000 Subject: [PATCH] [K/N] Add filecheck tests for atomic intrinsics https://youtrack.jetbrains.com/issue/KT-60514/Add-llvm-filecheck-tests-for-atomic-intrinsics Merge-request: KT-MR-12067 Merged-by: Vladimir Sukharev --- .../box/volatile/intrinsicsOnGlobal.kt | 22 ++ .../backend.native/tests/build.gradle | 4 + .../backend.native/tests/filecheck/atomics.kt | 285 ++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 kotlin-native/backend.native/tests/filecheck/atomics.kt diff --git a/compiler/testData/codegen/box/volatile/intrinsicsOnGlobal.kt b/compiler/testData/codegen/box/volatile/intrinsicsOnGlobal.kt index 110c3e4f0fa..974172fc362 100644 --- a/compiler/testData/codegen/box/volatile/intrinsicsOnGlobal.kt +++ b/compiler/testData/codegen/box/volatile/intrinsicsOnGlobal.kt @@ -27,12 +27,34 @@ val a = "1" val b = "2" val c = "3" +@Volatile var byte: Byte = 1 +@Volatile var short: Short = 1 @Volatile var x: Int = 1 @Volatile var y: Long = 1L @Volatile var z: String = a @Volatile var t: Boolean = true fun box() : String { + if (::byte.compareAndSetField(1.toByte(), 2.toByte()) != true) return "FAIL Byte: 1" + if (::byte.compareAndSetField(1.toByte(), 2.toByte()) != false) return "FAIL Byte: 2" + if (::byte.compareAndExchangeField(2.toByte(), 1.toByte()) != 2.toByte()) return "FAIL Byte: 3" + if (::byte.compareAndExchangeField(2.toByte(), 1.toByte()) != 1.toByte()) return "FAIL Byte: 4" + if (::byte.getAndSetField(3.toByte()) != 1.toByte()) return "FAIL Byte: 5" + if (::byte.getAndSetField(1.toByte()) != 3.toByte()) return "FAIL Byte: 6" + if (::byte.getAndAddFieldLocal(1.toByte()) != 1.toByte()) return "FAIL Byte: 7" + if (::byte.getAndAddFieldLocal(1.toByte()) != 2.toByte()) return "FAIL Byte: 8" + if (byte != 3.toByte()) return "FAIL Byte: 9" + + if (::short.compareAndSetField(1.toShort(), 2.toShort()) != true) return "FAIL Short: 1" + if (::short.compareAndSetField(1.toShort(), 2.toShort()) != false) return "FAIL Short: 2" + if (::short.compareAndExchangeField(2.toShort(), 1.toShort()) != 2.toShort()) return "FAIL Short: 3" + if (::short.compareAndExchangeField(2.toShort(), 1.toShort()) != 1.toShort()) return "FAIL Short: 4" + if (::short.getAndSetField(3.toShort()) != 1.toShort()) return "FAIL Short: 5" + if (::short.getAndSetField(1.toShort()) != 3.toShort()) return "FAIL Short: 6" + if (::short.getAndAddFieldLocal(1.toShort()) != 1.toShort()) return "FAIL Short: 7" + if (::short.getAndAddFieldLocal(1.toShort()) != 2.toShort()) return "FAIL Short: 8" + if (short != 3.toShort()) return "FAIL Short: 9" + if (::x.compareAndSetField(1, 2) != true) return "FAIL Int: 1" if (::x.compareAndSetField(1, 2) != false) return "FAIL Int: 2" if (::x.compareAndExchangeField(2, 1) != 2) return "FAIL Int: 3" diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 6dd0c7ec206..ba17e16b803 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -6197,6 +6197,10 @@ fileCheckTest("filecheck_objc_direct") { enabled = target.family.appleFamily } +fileCheckTest("filecheck_atomics") { + annotatedSource = project.file('filecheck/atomics.kt') +} + dependencies { nopPluginApi kotlinCompilerModule diff --git a/kotlin-native/backend.native/tests/filecheck/atomics.kt b/kotlin-native/backend.native/tests/filecheck/atomics.kt new file mode 100644 index 00000000000..619ba23de12 --- /dev/null +++ b/kotlin-native/backend.native/tests/filecheck/atomics.kt @@ -0,0 +1,285 @@ +import kotlin.concurrent.* + +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +// CHECK-LABEL: define {{signext i8|i8}} @"kfun:#(){}kotlin.Byte"() +// CHECK: load atomic i8, i8* @"kvar:byteGlobal#internal" seq_cst +// CHECK-LABEL: define void @"kfun:#(kotlin.Byte){}"(i8 +// CHECK: store atomic i8 %{{[0-9]+}}, i8* @"kvar:byteGlobal#internal" seq_cst +@Volatile var byteGlobal: Byte = 42 + +// CHECK-LABEL: define {{signext i16|i16}} @"kfun:#(){}kotlin.Short"() +// CHECK: load atomic i16, i16* @"kvar:shortGlobal#internal" seq_cst +// CHECK-LABEL: define void @"kfun:#(kotlin.Short){}"(i16 +// CHECK: store atomic i16 %{{[0-9]+}}, i16* @"kvar:shortGlobal#internal" seq_cst +@Volatile var shortGlobal: Short = 42 + +// CHECK-LABEL: define i32 @"kfun:#(){}kotlin.Int"() +// CHECK: load atomic i32, i32* @"kvar:intGlobal#internal" seq_cst +// CHECK-LABEL: define void @"kfun:#(kotlin.Int){}"(i32 +// CHECK: store atomic i32 %{{[0-9]+}}, i32* @"kvar:intGlobal#internal" seq_cst +@Volatile var intGlobal: Int = 42 + +// CHECK-LABEL: define i64 @"kfun:#(){}kotlin.Long"() +// CHECK: load atomic i64, i64* @"kvar:longGlobal#internal" seq_cst +// CHECK-LABEL: define void @"kfun:#(kotlin.Long){}"(i64 +// CHECK: store atomic i64 %{{[0-9]+}}, i64* @"kvar:longGlobal#internal" seq_cst +@Volatile var longGlobal: Long = 42 + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#(){}kotlin.Boolean"() +// CHECK: load atomic i8, i8* @"kvar:booleanGlobal#internal" seq_cst +// CHECK-LABEL: define void @"kfun:#(kotlin.Boolean){}"(i1 +// CHECK: store atomic i8 %{{[0-9]+}}, i8* @"kvar:booleanGlobal#internal" seq_cst +@Volatile var booleanGlobal: Boolean = true + +// Byte + +// CHECK-LABEL: define {{signext i8|i8}} @"kfun:#byteGlobal_getAndSetField(){}kotlin.Byte"() +// CHECK: atomicrmw xchg i8* @"kvar:byteGlobal#internal", i8 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun byteGlobal_getAndSetField() = ::byteGlobal.getAndSetField(0.toByte()) + +// CHECK-LABEL: define {{signext i8|i8}} @"kfun:#byteGlobal_getAndAddField(){}kotlin.Byte"() +// CHECK: atomicrmw add i8* @"kvar:byteGlobal#internal", i8 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun byteGlobal_getAndAddField() = ::byteGlobal.getAndAddField(0.toByte()) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#byteGlobal_compareAndSetField(){}kotlin.Boolean"() +// CHECK: cmpxchg i8* @"kvar:byteGlobal#internal", i8 0, i8 1 seq_cst seq_cst +// CHECK: extractvalue { i8, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun byteGlobal_compareAndSetField() = ::byteGlobal.compareAndSetField(0.toByte(), 1.toByte()) + +// CHECK-LABEL: define {{signext i8|i8}} @"kfun:#byteGlobal_compareAndExchangeField(){}kotlin.Byte"() +// CHECK: cmpxchg i8* @"kvar:byteGlobal#internal", i8 0, i8 1 seq_cst seq_cst +// CHECK: extractvalue { i8, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun byteGlobal_compareAndExchangeField() = ::byteGlobal.compareAndExchangeField(0.toByte(), 1.toByte()) + +// Short + +// CHECK-LABEL: define {{signext i16|i16}} @"kfun:#shortGlobal_getAndSetField(){} +// CHECK: atomicrmw xchg i16* @"kvar:shortGlobal#internal", i16 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun shortGlobal_getAndSetField() = ::shortGlobal.getAndSetField(0.toShort()) + +// CHECK-LABEL: define {{signext i16|i16}} @"kfun:#shortGlobal_getAndAddField(){} +// CHECK: atomicrmw add i16* @"kvar:shortGlobal#internal", i16 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun shortGlobal_getAndAddField() = ::shortGlobal.getAndAddField(0.toShort()) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#shortGlobal_compareAndSetField(){} +// CHECK: cmpxchg i16* @"kvar:shortGlobal#internal", i16 0, i16 1 seq_cst seq_cst +// CHECK: extractvalue { i16, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun shortGlobal_compareAndSetField() = ::shortGlobal.compareAndSetField(0.toShort(), 1.toShort()) + +// CHECK-LABEL: define {{signext i16|i16}} @"kfun:#shortGlobal_compareAndExchangeField(){} +// CHECK: cmpxchg i16* @"kvar:shortGlobal#internal", i16 0, i16 1 seq_cst seq_cst +// CHECK: extractvalue { i16, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun shortGlobal_compareAndExchangeField() = ::shortGlobal.compareAndExchangeField(0.toShort(), 1.toShort()) + +// Int + +// CHECK-LABEL: define i32 @"kfun:#intGlobal_getAndSetField(){} +// CHECK: atomicrmw xchg i32* @"kvar:intGlobal#internal", i32 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intGlobal_getAndSetField() = ::intGlobal.getAndSetField(0) + +// CHECK-LABEL: define i32 @"kfun:#intGlobal_getAndAddField(){} +// CHECK: atomicrmw add i32* @"kvar:intGlobal#internal", i32 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intGlobal_getAndAddField() = ::intGlobal.getAndAddField(0) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#intGlobal_compareAndSetField(){} +// CHECK: cmpxchg i32* @"kvar:intGlobal#internal", i32 0, i32 1 seq_cst seq_cst +// CHECK: extractvalue { i32, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intGlobal_compareAndSetField() = ::intGlobal.compareAndSetField(0, 1) + +// CHECK-LABEL: define i32 @"kfun:#intGlobal_compareAndExchangeField(){} +// CHECK: cmpxchg i32* @"kvar:intGlobal#internal", i32 0, i32 1 seq_cst seq_cst +// CHECK: extractvalue { i32, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intGlobal_compareAndExchangeField() = ::intGlobal.compareAndExchangeField(0, 1) + +// Long + +// CHECK-LABEL: define i64 @"kfun:#longGlobal_getAndSetField(){} +// CHECK: atomicrmw xchg i64* @"kvar:longGlobal#internal", i64 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longGlobal_getAndSetField() = ::longGlobal.getAndSetField(0L) + +// CHECK-LABEL: define i64 @"kfun:#longGlobal_getAndAddField(){} +// CHECK: atomicrmw add i64* @"kvar:longGlobal#internal", i64 0 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longGlobal_getAndAddField() = ::longGlobal.getAndAddField(0L) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#longGlobal_compareAndSetField(){} +// CHECK: cmpxchg i64* @"kvar:longGlobal#internal", i64 0, i64 1 seq_cst seq_cst +// CHECK: extractvalue { i64, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longGlobal_compareAndSetField() = ::longGlobal.compareAndSetField(0L, 1L) + +// CHECK-LABEL: define i64 @"kfun:#longGlobal_compareAndExchangeField(){} +// CHECK: cmpxchg i64* @"kvar:longGlobal#internal", i64 0, i64 1 seq_cst seq_cst +// CHECK: extractvalue { i64, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longGlobal_compareAndExchangeField() = ::longGlobal.compareAndExchangeField(0L, 1L) + +// Boolean + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#booleanGlobal_getAndSetField(){}kotlin.Boolean" +// CHECK: atomicrmw xchg i8* @"kvar:booleanGlobal#internal", i8 %{{[0-9]+}} seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun booleanGlobal_getAndSetField() = ::booleanGlobal.getAndSetField(false) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#booleanGlobal_compareAndSetField(){} +// CHECK: cmpxchg i8* @"kvar:booleanGlobal#internal", i8 %{{[0-9]+}}, i8 %{{[0-9]+}} seq_cst seq_cst +// CHECK: extractvalue { i8, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun booleanGlobal_compareAndSetField() = ::booleanGlobal.compareAndSetField(false, true) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#booleanGlobal_compareAndExchangeField(){} +// CHECK: cmpxchg i8* @"kvar:booleanGlobal#internal", i8 %{{[0-9]+}}, i8 %{{[0-9]+}} seq_cst seq_cst +// CHECK: extractvalue { i8, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun booleanGlobal_compareAndExchangeField() = ::booleanGlobal.compareAndExchangeField(false, true) + +// IntArray +val intArr = IntArray(2) + +// CHECK-LABEL: define i32 @"kfun:#intArr_atomicGet(){}kotlin.Int"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.IntArray" +// CHECK: call i32* @Kotlin_intArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: load atomic i32, i32* %{{[0-9]+}} seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intArr_atomicGet() = intArr.atomicGet(0) + +// CHECK-LABEL: define void @"kfun:#intArr_atomicSet(){}"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.IntArray" +// CHECK: call i32* @Kotlin_intArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: store atomic i32 1, i32* %{{[0-9]+}} seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intArr_atomicSet() = intArr.atomicSet(0, 1) + +// CHECK-LABEL: define i32 @"kfun:#intArr_getAndSet(){}kotlin.Int"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.IntArray" +// CHECK: call i32* @Kotlin_intArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: atomicrmw xchg i32* %{{[0-9]+}}, i32 1 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intArr_getAndSet() = intArr.getAndSet(0, 1) + +// CHECK-LABEL: define i32 @"kfun:#intArr_getAndAdd(){}kotlin.Int"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.IntArray" +// CHECK: call i32* @Kotlin_intArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: atomicrmw add i32* %{{[0-9]+}}, i32 1 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intArr_getAndAdd() = intArr.getAndAdd(0, 1) + +// CHECK-LABEL: define i32 @"kfun:#intArr_compareAndExchange(){}kotlin.Int"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.IntArray" +// CHECK: call i32* @Kotlin_intArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: cmpxchg i32* %{{[0-9]+}}, i32 1, i32 2 seq_cst seq_cst +// CHECK: extractvalue { i32, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intArr_compareAndExchange() = intArr.compareAndExchange(0, 1, 2) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#intArr_compareAndSet(){}kotlin.Boolean"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.IntArray" +// CHECK: call i32* @Kotlin_intArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: cmpxchg i32* %{{[0-9]+}}, i32 1, i32 2 seq_cst seq_cst +// CHECK: extractvalue { i32, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun intArr_compareAndSet() = intArr.compareAndSet(0, 1, 2) + +// LongArray +val longArr = LongArray(2) + +// CHECK-LABEL: define i64 @"kfun:#longArr_atomicGet(){}kotlin.Long"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.LongArray" +// CHECK: call i64* @Kotlin_longArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: load atomic i64, i64* %{{[0-9]+}} seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longArr_atomicGet() = longArr.atomicGet(0) + +// CHECK-LABEL: define void @"kfun:#longArr_atomicSet(){}"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.LongArray" +// CHECK: call i64* @Kotlin_longArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: store atomic i64 1, i64* %{{[0-9]+}} seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longArr_atomicSet() = longArr.atomicSet(0, 1L) + +// CHECK-LABEL: define i64 @"kfun:#longArr_getAndSet(){}kotlin.Long"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.LongArray" +// CHECK: call i64* @Kotlin_longArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: atomicrmw xchg i64* %{{[0-9]+}}, i64 1 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longArr_getAndSet() = longArr.getAndSet(0, 1L) + +// CHECK-LABEL: define i64 @"kfun:#longArr_getAndAdd(){}kotlin.Long"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.LongArray" +// CHECK: call i64* @Kotlin_longArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: atomicrmw add i64* %{{[0-9]+}}, i64 1 seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longArr_getAndAdd() = longArr.getAndAdd(0, 1L) + +// CHECK-LABEL: define i64 @"kfun:#longArr_compareAndExchange(){}kotlin.Long"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.LongArray" +// CHECK: call i64* @Kotlin_longArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: cmpxchg i64* %{{[0-9]+}}, i64 1, i64 2 seq_cst seq_cst +// CHECK: extractvalue { i64, i1 } %{{[0-9]+}}, 0 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longArr_compareAndExchange() = longArr.compareAndExchange(0, 1L, 2L) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#longArr_compareAndSet(){}kotlin.Boolean"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.LongArray" +// CHECK: call i64* @Kotlin_longArrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: cmpxchg i64* %{{[0-9]+}}, i64 1, i64 2 seq_cst seq_cst +// CHECK: extractvalue { i64, i1 } %{{[0-9]+}}, 1 +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun longArr_compareAndSet() = longArr.compareAndSet(0, 1L, 2L) + +// Array +val refArr = arrayOfNulls(2) + +// CHECK-LABEL: define %struct.ObjHeader* @"kfun:#refArr_atomicGet(){}kotlin.String?" +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.Array" +// CHECK: call %struct.ObjHeader** @Kotlin_arrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: load atomic %struct.ObjHeader*, %struct.ObjHeader** %{{[0-9]+}} seq_cst +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun refArr_atomicGet() = refArr.atomicGet(0) + +// CHECK-LABEL: define void @"kfun:#refArr_atomicSet(){}"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.Array" +// CHECK: call %struct.ObjHeader** @Kotlin_arrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: call void @UpdateVolatileHeapRef(%struct.ObjHeader** %{{[0-9]+}}, %struct.ObjHeader* null) +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun refArr_atomicSet() = refArr.atomicSet(0, null) + +// CHECK-LABEL: define %struct.ObjHeader* @"kfun:#refArr_getAndSet(){}kotlin.String?" +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.Array" +// CHECK: call %struct.ObjHeader** @Kotlin_arrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: call %struct.ObjHeader* @GetAndSetVolatileHeapRef(%struct.ObjHeader** %{{[0-9]+}}, %struct.ObjHeader* null, %struct.ObjHeader** %{{[0-9]+}}) +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun refArr_getAndSet() = refArr.getAndSet(0, null) + +// CHECK-LABEL: define %struct.ObjHeader* @"kfun:#refArr_compareAndExchange(){}kotlin.String?" +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.Array" +// CHECK: call %struct.ObjHeader** @Kotlin_arrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: call %struct.ObjHeader* @CompareAndSwapVolatileHeapRef(%struct.ObjHeader** %{{[0-9]+}}, %struct.ObjHeader* null, %struct.ObjHeader* null, %struct.ObjHeader** %{{[0-9]+}}) +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun refArr_compareAndExchange() = refArr.compareAndExchange(0, null, null) + +// CHECK-LABEL: define {{zeroext i1|i1}} @"kfun:#refArr_compareAndSet(){}kotlin.Boolean"() +// CHECK: call %struct.ObjHeader* @"kfun:#(){}kotlin.Array" +// CHECK: call %struct.ObjHeader** @Kotlin_arrayGetElementAddress(%struct.ObjHeader* %{{[0-9]+}}, i32 0) +// CHECK: call {{zeroext i1|i1}} @CompareAndSetVolatileHeapRef(%struct.ObjHeader** %{{[0-9]+}}, %struct.ObjHeader* null, %struct.ObjHeader* null) +@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +fun refArr_compareAndSet() = refArr.compareAndSet(0, null, null) + +fun main() {}