Skip to content

Commit bc62bcb

Browse files
authored
[Backport to 17] Add SPV_INTEL_16bit_atomics extension (#3424)
This continues #3343 and reflects specification update, including extension renaming. Specification: intel/llvm#20009
1 parent 3f4d6e8 commit bc62bcb

File tree

13 files changed

+174
-25
lines changed

13 files changed

+174
-25
lines changed

include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,6 @@ EXT(SPV_INTEL_bfloat16_arithmetic)
8080
EXT(SPV_INTEL_ternary_bitwise_function)
8181
EXT(SPV_INTEL_int4)
8282
EXT(SPV_INTEL_function_variants)
83-
EXT(SPV_INTEL_shader_atomic_bfloat16)
83+
EXT(SPV_INTEL_16bit_atomics)
8484
EXT(SPV_INTEL_predicated_io)
8585
EXT(SPV_INTEL_sigmoid)

lib/SPIRV/libSPIRV/SPIRVEnum.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,16 @@ template <> inline void SPIRVMap<SPIRVCapabilityKind, SPIRVCapVec>::init() {
226226
{CapabilityInt4TypeINTEL, CapabilityCooperativeMatrixKHR});
227227
ADD_VEC_INIT(internal::CapabilityBFloat16ArithmeticINTEL,
228228
{CapabilityBFloat16TypeKHR});
229+
ADD_VEC_INIT(internal::CapabilityAtomicInt16CompareExchangeINTEL,
230+
{CapabilityInt16});
231+
ADD_VEC_INIT(internal::CapabilityInt16AtomicsINTEL,
232+
{internal::CapabilityAtomicInt16CompareExchangeINTEL});
233+
ADD_VEC_INIT(internal::CapabilityAtomicBFloat16LoadStoreINTEL,
234+
{CapabilityBFloat16TypeKHR});
235+
ADD_VEC_INIT(internal::CapabilityAtomicBFloat16AddINTEL,
236+
{CapabilityBFloat16TypeKHR});
237+
ADD_VEC_INIT(internal::CapabilityAtomicBFloat16MinMaxINTEL,
238+
{CapabilityBFloat16TypeKHR});
229239
}
230240

231241
template <> inline void SPIRVMap<SPIRVExecutionModelKind, SPIRVCapVec>::init() {

lib/SPIRV/libSPIRV/SPIRVInstruction.h

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2827,8 +2827,16 @@ class SPIRVAtomicInstBase : public SPIRVInstTemplateBase {
28272827
// Besides, OpAtomicCompareExchangeWeak, OpAtomicFlagTestAndSet and
28282828
// OpAtomicFlagClear instructions require the "kernel" capability. But this
28292829
// capability should be added by setting the OpenCL memory model.
2830-
if (hasType() && getType()->isTypeInt(64))
2831-
return {CapabilityInt64Atomics};
2830+
if (hasType()) {
2831+
if (getType()->isTypeInt(64))
2832+
return {CapabilityInt64Atomics};
2833+
if (getType()->isTypeInt(16) &&
2834+
Module->isAllowedToUseExtension(
2835+
ExtensionID::SPV_INTEL_16bit_atomics)) {
2836+
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
2837+
return {internal::CapabilityInt16AtomicsINTEL};
2838+
}
2839+
}
28322840
return {};
28332841
}
28342842

@@ -2842,7 +2850,24 @@ class SPIRVAtomicInstBase : public SPIRVInstTemplateBase {
28422850
}
28432851
};
28442852

2845-
class SPIRVAtomicStoreInst : public SPIRVAtomicInstBase {
2853+
// This specialization will handle smaller set of compare-and-swap instructions
2854+
// that require only one capability. The instructions are: OpAtomicLoad,
2855+
// OpAtomicStore, OpAtomicExchange, OpAtomicCompareExchange and
2856+
// OpAtomicCompareExchangeWeak.
2857+
class SPIRVAtomicCompareExchangeInstructions : public SPIRVAtomicInstBase {
2858+
public:
2859+
SPIRVCapVec getRequiredCapability() const override {
2860+
if (hasType() && getType()->isTypeInt(16) &&
2861+
this->getModule()->isAllowedToUseExtension(
2862+
ExtensionID::SPV_INTEL_16bit_atomics)) {
2863+
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
2864+
return {internal::CapabilityAtomicInt16CompareExchangeINTEL};
2865+
}
2866+
return SPIRVAtomicInstBase::getRequiredCapability();
2867+
}
2868+
};
2869+
2870+
class SPIRVAtomicStoreInst : public SPIRVAtomicCompareExchangeInstructions {
28462871
public:
28472872
// Overriding the following method because of 'const'-related
28482873
// issues with overriding getRequiredCapability(). TODO: Resolve.
@@ -2859,7 +2884,7 @@ class SPIRVAtomicFAddEXTInst : public SPIRVAtomicInstBase {
28592884
std::optional<ExtensionID> getRequiredExtension() const override {
28602885
assert(hasType());
28612886
if (getType()->isTypeFloat(16, FPEncodingBFloat16KHR))
2862-
return ExtensionID::SPV_INTEL_shader_atomic_bfloat16;
2887+
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
28632888
if (getType()->isTypeFloat(16))
28642889
return ExtensionID::SPV_EXT_shader_atomic_float16_add;
28652890
return ExtensionID::SPV_EXT_shader_atomic_float_add;
@@ -2884,7 +2909,7 @@ class SPIRVAtomicFMinMaxEXTBase : public SPIRVAtomicInstBase {
28842909
public:
28852910
std::optional<ExtensionID> getRequiredExtension() const override {
28862911
if (getType()->isTypeFloat(16, FPEncodingBFloat16KHR))
2887-
return ExtensionID::SPV_INTEL_shader_atomic_bfloat16;
2912+
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
28882913
return ExtensionID::SPV_EXT_shader_atomic_float_min_max;
28892914
}
28902915

@@ -2908,10 +2933,6 @@ class SPIRVAtomicFMinMaxEXTBase : public SPIRVAtomicInstBase {
29082933
// Atomic builtins
29092934
_SPIRV_OP(AtomicFlagTestAndSet, true, 6)
29102935
_SPIRV_OP(AtomicFlagClear, false, 4)
2911-
_SPIRV_OP(AtomicLoad, true, 6)
2912-
_SPIRV_OP(AtomicExchange, true, 7)
2913-
_SPIRV_OP(AtomicCompareExchange, true, 9)
2914-
_SPIRV_OP(AtomicCompareExchangeWeak, true, 9)
29152936
_SPIRV_OP(AtomicIIncrement, true, 6)
29162937
_SPIRV_OP(AtomicIDecrement, true, 6)
29172938
_SPIRV_OP(AtomicIAdd, true, 7)
@@ -2928,7 +2949,11 @@ _SPIRV_OP(MemoryBarrier, false, 3)
29282949
#define _SPIRV_OP(x, BaseClass, ...) \
29292950
typedef SPIRVInstTemplate<SPIRV##BaseClass, Op##x, __VA_ARGS__> SPIRV##x;
29302951
// Specialized atomic builtins
2952+
_SPIRV_OP(AtomicLoad, AtomicCompareExchangeInstructions, true, 6)
29312953
_SPIRV_OP(AtomicStore, AtomicStoreInst, false, 5)
2954+
_SPIRV_OP(AtomicExchange, AtomicCompareExchangeInstructions, true, 7)
2955+
_SPIRV_OP(AtomicCompareExchange, AtomicCompareExchangeInstructions, true, 9)
2956+
_SPIRV_OP(AtomicCompareExchangeWeak, AtomicCompareExchangeInstructions, true, 9)
29322957
_SPIRV_OP(AtomicFAddEXT, AtomicFAddEXTInst, true, 7)
29332958
_SPIRV_OP(AtomicFMinEXT, AtomicFMinMaxEXTBase, true, 7)
29342959
_SPIRV_OP(AtomicFMaxEXT, AtomicFMinMaxEXTBase, true, 7)

lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -619,9 +619,6 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
619619
add(CapabilityLongCompositesINTEL, "LongCompositesINTEL");
620620
add(CapabilityOptNoneEXT, "OptNoneEXT");
621621
add(CapabilityAtomicFloat16AddEXT, "AtomicFloat16AddEXT");
622-
add(internal::CapabilityAtomicBFloat16AddINTEL, "AtomicBFloat16AddINTEL");
623-
add(internal::CapabilityAtomicBFloat16MinMaxINTEL,
624-
"AtomicBFloat16MinMaxINTEL");
625622
add(CapabilityDebugInfoModuleINTEL, "DebugInfoModuleINTEL");
626623
add(CapabilitySplitBarrierINTEL, "SplitBarrierINTEL");
627624
add(CapabilityGlobalVariableFPGADecorationsINTEL,
@@ -681,6 +678,14 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
681678
add(internal::CapabilityBFloat16ArithmeticINTEL, "BFloat16ArithmeticINTEL");
682679
add(internal::CapabilityPredicatedIOINTEL, "PredicatedIOINTEL");
683680
add(internal::CapabilitySigmoidINTEL, "SigmoidINTEL");
681+
add(internal::CapabilityAtomicBFloat16AddINTEL, "AtomicBFloat16AddINTEL");
682+
add(internal::CapabilityAtomicBFloat16MinMaxINTEL,
683+
"AtomicBFloat16MinMaxINTEL");
684+
add(internal::CapabilityAtomicInt16CompareExchangeINTEL,
685+
"AtomicInt16CompareExchangeINTEL");
686+
add(internal::CapabilityInt16AtomicsINTEL, "Int16AtomicsINTEL");
687+
add(internal::CapabilityAtomicBFloat16LoadStoreINTEL,
688+
"AtomicBFloat16LoadStoreINTEL");
684689
}
685690
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)
686691

lib/SPIRV/libSPIRV/spirv_internal.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ enum InternalCapability {
111111
ICapabilityAtomicBFloat16AddINTEL = 6255,
112112
ICapabilityAtomicBFloat16MinMaxINTEL = 6256,
113113
ICapabilityPredicatedIOINTEL = 6257,
114+
ICapabilityAtomicInt16CompareExchangeINTEL = 6260,
115+
ICapabilityInt16AtomicsINTEL = 6261,
116+
ICapabilityAtomicBFloat16LoadStoreINTEL = 6262,
114117
ICapabilityCooperativeMatrixPrefetchINTEL = 6411,
115118
ICapabilityComplexFloatMulDivINTEL = 6414,
116119
ICapabilityTensorFloat32RoundingINTEL = 6425,
@@ -274,6 +277,13 @@ constexpr Capability CapabilityGlobalVariableDecorationsINTEL =
274277
constexpr Capability CapabilityBFloat16ArithmeticINTEL =
275278
static_cast<Capability>(ICapabilityBFloat16ArithmeticINTEL);
276279

280+
constexpr Capability CapabilityAtomicInt16CompareExchangeINTEL =
281+
static_cast<Capability>(ICapabilityAtomicInt16CompareExchangeINTEL);
282+
constexpr Capability CapabilityInt16AtomicsINTEL =
283+
static_cast<Capability>(ICapabilityInt16AtomicsINTEL);
284+
constexpr Capability CapabilityAtomicBFloat16LoadStoreINTEL =
285+
static_cast<Capability>(ICapabilityAtomicBFloat16LoadStoreINTEL);
286+
277287
} // namespace internal
278288
} // namespace spv
279289

test/extensions/INTEL/SPV_INTEL_shader_atomic_bfloat16/AtomicFAddEXT.ll renamed to test/extensions/INTEL/SPV_INTEL_16bit_atomics/AtomicFAddEXT.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; RUN: llvm-as %s -o %t.bc
2-
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_shader_atomic_bfloat16,+SPV_KHR_bfloat16 -o %t.spv
2+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_16bit_atomics,+SPV_KHR_bfloat16,+SPV_EXT_shader_atomic_float_add -o %t.spv
33
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
44
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
55

@@ -11,7 +11,7 @@ target triple = "spir64-unknown-unknown"
1111

1212
; CHECK-SPIRV-DAG: Capability AtomicBFloat16AddINTEL
1313
; CHECK-SPIRV-DAG: Capability BFloat16TypeKHR
14-
; CHECK-SPIRV-DAG: Extension "SPV_INTEL_shader_atomic_bfloat16"
14+
; CHECK-SPIRV-DAG: Extension "SPV_INTEL_16bit_atomics"
1515
; CHECK-SPIRV-DAG: Extension "SPV_KHR_bfloat16"
1616

1717
; CHECK-SPIRV: TypeFloat [[BFLOAT:[0-9]+]] 16 0

test/extensions/INTEL/SPV_INTEL_shader_atomic_bfloat16/AtomicFMaxEXT.ll renamed to test/extensions/INTEL/SPV_INTEL_16bit_atomics/AtomicFMaxEXT.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; RUN: llvm-as %s -o %t.bc
2-
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_shader_atomic_bfloat16,+SPV_KHR_bfloat16 -o %t.spv
2+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_16bit_atomics,+SPV_KHR_bfloat16,+SPV_EXT_shader_atomic_float_min_max -o %t.spv
33
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
44
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
55

@@ -11,7 +11,7 @@ target triple = "spir64-unknown-unknown"
1111

1212
; CHECK-SPIRV-DAG: Capability AtomicBFloat16MinMaxINTEL
1313
; CHECK-SPIRV-DAG: Capability BFloat16TypeKHR
14-
; CHECK-SPIRV-DAG: Extension "SPV_INTEL_shader_atomic_bfloat16"
14+
; CHECK-SPIRV-DAG: Extension "SPV_INTEL_16bit_atomics"
1515
; CHECK-SPIRV-DAG: Extension "SPV_KHR_bfloat16"
1616

1717
; CHECK-SPIRV: TypeFloat [[BFLOAT:[0-9]+]] 16 0

test/extensions/INTEL/SPV_INTEL_shader_atomic_bfloat16/AtomicFMinEXT.ll renamed to test/extensions/INTEL/SPV_INTEL_16bit_atomics/AtomicFMinEXT.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; RUN: llvm-as %s -o %t.bc
2-
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_shader_atomic_bfloat16,+SPV_KHR_bfloat16 -o %t.spv
2+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_16bit_atomics,+SPV_KHR_bfloat16,+SPV_EXT_shader_atomic_float_min_max -o %t.spv
33
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
44
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
55

@@ -11,7 +11,7 @@ target triple = "spir64-unknown-unknown"
1111

1212
; CHECK-SPIRV-DAG: Capability AtomicBFloat16MinMaxINTEL
1313
; CHECK-SPIRV-DAG: Capability BFloat16TypeKHR
14-
; CHECK-SPIRV-DAG: Extension "SPV_INTEL_shader_atomic_bfloat16"
14+
; CHECK-SPIRV-DAG: Extension "SPV_INTEL_16bit_atomics"
1515
; CHECK-SPIRV-DAG: Extension "SPV_KHR_bfloat16"
1616

1717
; CHECK-SPIRV: TypeFloat [[BFLOAT:[0-9]+]] 16 0
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -o %t.spv --spirv-ext=+SPV_INTEL_16bit_atomics
3+
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
4+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
5+
6+
; RUN: llvm-spirv -r --spirv-target-env=CL2.0 %t.spv -o %t.rev.bc
7+
; RUN: llvm-dis %t.rev.bc
8+
; RUN: FileCheck < %t.rev.ll %s --check-prefixes=CHECK-LLVM
9+
10+
; Check that without extension we don't use its capabilities - there is no
11+
; limitation on using i16 with atomic instruction in the core specification.
12+
; RUN: llvm-spirv %t.bc -o %t.noext.spv
13+
; RUN: spirv-val %t.noext.spv
14+
; RUN: llvm-spirv -to-text %t.noext.spv -o %t.noext.spt
15+
; RUN: FileCheck < %t.noext.spt %s --check-prefix=CHECK-SPIRV-NOEXT
16+
17+
; CHECK-SPIRV: Capability Int16
18+
; CHECK-SPIRV: Capability AtomicInt16CompareExchangeINTEL
19+
; CHECK-SPIRV-NOT: Capability Int16AtomicsINTEL
20+
; CHECK-SPIRV: Extension "SPV_INTEL_16bit_atomics"
21+
22+
; CHECK-SPIRV-NOEXT: Capability Int16
23+
; CHECK-SPIRV-NOEXT-NOT: Capability AtomicInt16CompareExchangeINTEL
24+
; CHECK-SPIRV-NOEXT-NOT: Capability Int16AtomicsINTEL
25+
; CHECK-SPIRV-NOEXT-NOT: Extension "SPV_INTEL_16bit_atomics"
26+
27+
; CHECK-SPIRV-DAG: Constant [[#]] [[#DeviceScope:]] 1
28+
; CHECK-SPIRV-DAG: Constant [[#]] [[#Release:]] 4
29+
; CHECK-SPIRV-DAG: Constant [[#]] [[#SequentiallyConsistent:]] 16
30+
; CHECK-SPIRV-DAG: Constant [[#]] [[#Acquire:]] 2
31+
32+
; CHECK-LLVM: call spir_func void @_Z21atomic_store_explicitPU3AS4VU7_Atomicss12memory_order12memory_scope
33+
; CHECK-LLVM: call spir_func i16 @_Z20atomic_load_explicitPU3AS4VU7_Atomics12memory_order12memory_scope
34+
; CHECK-LLVM: call spir_func i16 @_Z24atomic_exchange_explicitPU3AS4VU7_Atomicss12memory_order12memory_scope
35+
; CHECK-LLVM: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomicsPU3AS4ss12memory_orderS4_12memory_scope
36+
37+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
38+
target triple = "spir64"
39+
40+
@ui = common dso_local addrspace(1) global i16 0, align 4
41+
; Function Attrs: nounwind
42+
define dso_local spir_func void @test() {
43+
entry:
44+
; CHECK-SPIRV: Variable [[#]] [[#PTR:]] 7
45+
%0 = alloca i16
46+
; CHECK-SPIRV: AtomicStore [[#PTR]] [[#DeviceScope]] [[#Release]] [[#]]
47+
store atomic i16 0, ptr %0 release, align 4
48+
; CHECK-SPIRV: AtomicLoad [[#]] [[#]] [[#PTR]] [[#DeviceScope]] [[#Acquire]]
49+
%1 = load atomic i16, ptr %0 acquire, align 4
50+
; CHECK-SPIRV: AtomicExchange [[#]] [[#]] [[#]] [[#DeviceScope]] [[#]] {{.+}}
51+
%2 = atomicrmw xchg ptr addrspace(1) @ui, i16 42 acq_rel
52+
; CHECK-SPIRV: AtomicCompareExchange [[#]] [[#]] [[#]] [[#DeviceScope]] [[#SequentiallyConsistent]] [[#Acquire]] {{.+}}
53+
%3 = cmpxchg ptr %0, i16 128, i16 456 seq_cst acquire
54+
ret void
55+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -o %t.spv --spirv-ext=+SPV_INTEL_16bit_atomics
3+
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
4+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
5+
6+
; RUN: llvm-spirv -r --spirv-target-env=CL2.0 %t.spv -o %t.rev.bc
7+
; RUN: llvm-dis %t.rev.bc
8+
; RUN: FileCheck < %t.rev.ll %s --check-prefixes=CHECK-LLVM
9+
10+
; RUN: llvm-spirv -r --spirv-target-env="SPV-IR" %t.spv -o %t.rev.bc
11+
; RUN: llvm-dis %t.rev.bc
12+
; RUN: FileCheck < %t.rev.ll %s --check-prefixes=CHECK-LLVM-SPV-IR
13+
14+
; Check that without extension we don't use its capabilities - there is no
15+
; limitation on using i16 with atomic instruction in the core specification.
16+
; RUN: llvm-spirv %t.bc -o %t.noext.spv
17+
; RUN: spirv-val %t.noext.spv
18+
; RUN: llvm-spirv -to-text %t.noext.spv -o %t.noext.spt
19+
; RUN: FileCheck < %t.noext.spt %s --check-prefix=CHECK-SPIRV-NOEXT
20+
21+
; CHECK-SPIRV: Capability Int16
22+
; CHECK-SPIRV: Capability AtomicInt16CompareExchangeINTEL
23+
; CHECK-SPIRV: Capability Int16AtomicsINTEL
24+
; CHECK-SPIRV: Extension "SPV_INTEL_16bit_atomics"
25+
; CHECK-SPIRV: AtomicOr
26+
27+
; CHECK-SPIRV-NOEXT: Capability Int16
28+
; CHECK-SPIRV-NOEXT-NOT: Capability AtomicInt16CompareExchangeINTEL
29+
; CHECK-SPIRV-NOEXT-NOT: Capability Int16AtomicsINTEL
30+
; CHECK-SPIRV-NOEXT-NOT: Extension "SPV_INTEL_16bit_atomics"
31+
32+
; CHECK-LLVM: call spir_func i16 @_Z24atomic_fetch_or_explicitPU3AS4VU7_Atomicss12memory_order12memory_scope
33+
; CHECK-LLVM-SPV-IR: call spir_func i16 @_Z16__spirv_AtomicOrPU3AS1siis
34+
35+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
36+
target triple = "spir64"
37+
38+
@ui = common dso_local addrspace(1) global i16 0, align 4
39+
40+
define dso_local spir_func void @test() {
41+
entry:
42+
%0 = atomicrmw or ptr addrspace(1) @ui, i16 42 release
43+
ret void
44+
}

0 commit comments

Comments
 (0)