simd-128 basic support (#3498)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
headers = clang-c/Index.h clang-c/ext.h
|
||||
headers = clang-c/Index.h clang-c/ext.h clang-c/ExtVector.h
|
||||
|
||||
headerFilter = clang-c/**
|
||||
|
||||
|
||||
@@ -1119,3 +1119,6 @@ JNIEXPORT jint JNICALL Java_clang_clang_kniBridge337 (JNIEnv* jniEnv, jclass jcl
|
||||
JNIEXPORT jint JNICALL Java_clang_clang_kniBridge338 (JNIEnv* jniEnv, jclass jclss, jlong p0) {
|
||||
return (jint)clang_Cursor_isObjCConsumingSelfMethod(*(CXCursor*)p0);
|
||||
}
|
||||
JNIEXPORT jint JNICALL Java_clang_clang_kniBridge339 (JNIEnv* jniEnv, jclass jclss, jlong p0) {
|
||||
return (jint)clang_isExtVectorType(*(CXType*)p0);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import kotlinx.cinterop.*
|
||||
@CNaturalStruct("data", "private_flags")
|
||||
class CXString(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var data: COpaquePointer?
|
||||
get() = memberAt<COpaquePointerVar>(0).value
|
||||
@@ -23,7 +23,7 @@ class CXString(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("Strings", "Count")
|
||||
class CXStringSet(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var Strings: CPointer<CXString>?
|
||||
get() = memberAt<CPointerVar<CXString>>(0).value
|
||||
@@ -45,7 +45,7 @@ class CXTranslationUnitImpl(rawPtr: NativePtr) : COpaque(rawPtr)
|
||||
@CNaturalStruct("Filename", "Contents", "Length")
|
||||
class CXUnsavedFile(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
var Filename: CPointer<ByteVar>?
|
||||
get() = memberAt<CPointerVar<ByteVar>>(0).value
|
||||
@@ -63,7 +63,7 @@ class CXUnsavedFile(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("Major", "Minor", "Subminor")
|
||||
class CXVersion(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(12, 4)
|
||||
companion object : CStructVar.Type(12, 4)
|
||||
|
||||
var Major: Int
|
||||
get() = memberAt<IntVar>(0).value
|
||||
@@ -81,7 +81,7 @@ class CXVersion(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("data")
|
||||
class CXFileUniqueID(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
@CLength(3)
|
||||
val data: CArrayPointer<LongVar>
|
||||
@@ -91,7 +91,7 @@ class CXFileUniqueID(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("ptr_data", "int_data")
|
||||
class CXSourceLocation(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
@CLength(2)
|
||||
val ptr_data: CArrayPointer<COpaquePointerVar>
|
||||
@@ -105,7 +105,7 @@ class CXSourceLocation(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("ptr_data", "begin_int_data", "end_int_data")
|
||||
class CXSourceRange(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
@CLength(2)
|
||||
val ptr_data: CArrayPointer<COpaquePointerVar>
|
||||
@@ -123,7 +123,7 @@ class CXSourceRange(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("count", "ranges")
|
||||
class CXSourceRangeList(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var count: Int
|
||||
get() = memberAt<IntVar>(0).value
|
||||
@@ -137,7 +137,7 @@ class CXSourceRangeList(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("kind", "amount")
|
||||
class CXTUResourceUsageEntry(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var kind: CXTUResourceUsageKind
|
||||
get() = memberAt<CXTUResourceUsageKind.Var>(0).value
|
||||
@@ -151,7 +151,7 @@ class CXTUResourceUsageEntry(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("data", "numEntries", "entries")
|
||||
class CXTUResourceUsage(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
var data: COpaquePointer?
|
||||
get() = memberAt<COpaquePointerVar>(0).value
|
||||
@@ -169,7 +169,7 @@ class CXTUResourceUsage(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("kind", "xdata", "data")
|
||||
class CXCursor(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(32, 8)
|
||||
companion object : CStructVar.Type(32, 8)
|
||||
|
||||
var kind: CXCursorKind
|
||||
get() = memberAt<CXCursorKind.Var>(0).value
|
||||
@@ -187,7 +187,7 @@ class CXCursor(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("Platform", "Introduced", "Deprecated", "Obsoleted", "Unavailable", "Message")
|
||||
class CXPlatformAvailability(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(72, 8)
|
||||
companion object : CStructVar.Type(72, 8)
|
||||
|
||||
val Platform: CXString
|
||||
get() = memberAt(0)
|
||||
@@ -214,7 +214,7 @@ class CXCursorSetImpl(rawPtr: NativePtr) : COpaque(rawPtr)
|
||||
@CNaturalStruct("kind", "data")
|
||||
class CXType(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
var kind: CXTypeKind
|
||||
get() = memberAt<CXTypeKind.Var>(0).value
|
||||
@@ -228,7 +228,7 @@ class CXType(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("int_data", "ptr_data")
|
||||
class CXToken(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
@CLength(4)
|
||||
val int_data: CArrayPointer<IntVar>
|
||||
@@ -242,7 +242,7 @@ class CXToken(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("CursorKind", "CompletionString")
|
||||
class CXCompletionResult(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var CursorKind: CXCursorKind
|
||||
get() = memberAt<CXCursorKind.Var>(0).value
|
||||
@@ -256,7 +256,7 @@ class CXCompletionResult(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("Results", "NumResults")
|
||||
class CXCodeCompleteResults(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var Results: CPointer<CXCompletionResult>?
|
||||
get() = memberAt<CPointerVar<CXCompletionResult>>(0).value
|
||||
@@ -270,7 +270,7 @@ class CXCodeCompleteResults(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("context", "visit")
|
||||
class CXCursorAndRangeVisitor(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var context: COpaquePointer?
|
||||
get() = memberAt<COpaquePointerVar>(0).value
|
||||
@@ -284,7 +284,7 @@ class CXCursorAndRangeVisitor(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("ptr_data", "int_data")
|
||||
class CXIdxLoc(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
@CLength(2)
|
||||
val ptr_data: CArrayPointer<COpaquePointerVar>
|
||||
@@ -298,7 +298,7 @@ class CXIdxLoc(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("hashLoc", "filename", "file", "isImport", "isAngled", "isModuleImport")
|
||||
class CXIdxIncludedFileInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(56, 8)
|
||||
companion object : CStructVar.Type(56, 8)
|
||||
|
||||
val hashLoc: CXIdxLoc
|
||||
get() = memberAt(0)
|
||||
@@ -327,7 +327,7 @@ class CXIdxIncludedFileInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("file", "module", "loc", "isImplicit")
|
||||
class CXIdxImportedASTFileInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(48, 8)
|
||||
companion object : CStructVar.Type(48, 8)
|
||||
|
||||
var file: CXFile?
|
||||
get() = memberAt<CXFileVar>(0).value
|
||||
@@ -348,7 +348,7 @@ class CXIdxImportedASTFileInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("kind", "cursor", "loc")
|
||||
class CXIdxAttrInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(64, 8)
|
||||
companion object : CStructVar.Type(64, 8)
|
||||
|
||||
var kind: CXIdxAttrKind
|
||||
get() = memberAt<CXIdxAttrKindVar>(0).value
|
||||
@@ -364,7 +364,7 @@ class CXIdxAttrInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("kind", "templateKind", "lang", "name", "USR", "cursor", "attributes", "numAttributes")
|
||||
class CXIdxEntityInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(80, 8)
|
||||
companion object : CStructVar.Type(80, 8)
|
||||
|
||||
var kind: CXIdxEntityKind
|
||||
get() = memberAt<CXIdxEntityKind.Var>(0).value
|
||||
@@ -401,7 +401,7 @@ class CXIdxEntityInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("cursor")
|
||||
class CXIdxContainerInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(32, 8)
|
||||
companion object : CStructVar.Type(32, 8)
|
||||
|
||||
val cursor: CXCursor
|
||||
get() = memberAt(0)
|
||||
@@ -410,7 +410,7 @@ class CXIdxContainerInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("attrInfo", "objcClass", "classCursor", "classLoc")
|
||||
class CXIdxIBOutletCollectionAttrInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(72, 8)
|
||||
companion object : CStructVar.Type(72, 8)
|
||||
|
||||
var attrInfo: CPointer<CXIdxAttrInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxAttrInfo>>(0).value
|
||||
@@ -430,7 +430,7 @@ class CXIdxIBOutletCollectionAttrInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("entityInfo", "cursor", "loc", "semanticContainer", "lexicalContainer", "isRedeclaration", "isDefinition", "isContainer", "declAsContainer", "isImplicit", "attributes", "numAttributes", "flags")
|
||||
class CXIdxDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(128, 8)
|
||||
companion object : CStructVar.Type(128, 8)
|
||||
|
||||
var entityInfo: CPointer<CXIdxEntityInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxEntityInfo>>(0).value
|
||||
@@ -486,7 +486,7 @@ class CXIdxDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("declInfo", "kind")
|
||||
class CXIdxObjCContainerDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var declInfo: CPointer<CXIdxDeclInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxDeclInfo>>(0).value
|
||||
@@ -500,7 +500,7 @@ class CXIdxObjCContainerDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("base", "cursor", "loc")
|
||||
class CXIdxBaseClassInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(64, 8)
|
||||
companion object : CStructVar.Type(64, 8)
|
||||
|
||||
var base: CPointer<CXIdxEntityInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxEntityInfo>>(0).value
|
||||
@@ -516,7 +516,7 @@ class CXIdxBaseClassInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("protocol", "cursor", "loc")
|
||||
class CXIdxObjCProtocolRefInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(64, 8)
|
||||
companion object : CStructVar.Type(64, 8)
|
||||
|
||||
var protocol: CPointer<CXIdxEntityInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxEntityInfo>>(0).value
|
||||
@@ -532,7 +532,7 @@ class CXIdxObjCProtocolRefInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("protocols", "numProtocols")
|
||||
class CXIdxObjCProtocolRefListInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(16, 8)
|
||||
companion object : CStructVar.Type(16, 8)
|
||||
|
||||
var protocols: CPointer<CPointerVar<CXIdxObjCProtocolRefInfo>>?
|
||||
get() = memberAt<CPointerVar<CPointerVar<CXIdxObjCProtocolRefInfo>>>(0).value
|
||||
@@ -546,7 +546,7 @@ class CXIdxObjCProtocolRefListInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("containerInfo", "superInfo", "protocols")
|
||||
class CXIdxObjCInterfaceDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
var containerInfo: CPointer<CXIdxObjCContainerDeclInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxObjCContainerDeclInfo>>(0).value
|
||||
@@ -564,7 +564,7 @@ class CXIdxObjCInterfaceDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("containerInfo", "objcClass", "classCursor", "classLoc", "protocols")
|
||||
class CXIdxObjCCategoryDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(80, 8)
|
||||
companion object : CStructVar.Type(80, 8)
|
||||
|
||||
var containerInfo: CPointer<CXIdxObjCContainerDeclInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxObjCContainerDeclInfo>>(0).value
|
||||
@@ -588,7 +588,7 @@ class CXIdxObjCCategoryDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("declInfo", "getter", "setter")
|
||||
class CXIdxObjCPropertyDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
var declInfo: CPointer<CXIdxDeclInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxDeclInfo>>(0).value
|
||||
@@ -606,7 +606,7 @@ class CXIdxObjCPropertyDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("declInfo", "bases", "numBases")
|
||||
class CXIdxCXXClassDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(24, 8)
|
||||
companion object : CStructVar.Type(24, 8)
|
||||
|
||||
var declInfo: CPointer<CXIdxDeclInfo>?
|
||||
get() = memberAt<CPointerVar<CXIdxDeclInfo>>(0).value
|
||||
@@ -624,7 +624,7 @@ class CXIdxCXXClassDeclInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("kind", "cursor", "loc", "referencedEntity", "parentEntity", "container", "role")
|
||||
class CXIdxEntityRefInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(96, 8)
|
||||
companion object : CStructVar.Type(96, 8)
|
||||
|
||||
var kind: CXIdxEntityRefKind
|
||||
get() = memberAt<CXIdxEntityRefKindVar>(0).value
|
||||
@@ -656,7 +656,7 @@ class CXIdxEntityRefInfo(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("abortQuery", "diagnostic", "enteredMainFile", "ppIncludedFile", "importedASTFile", "startedTranslationUnit", "indexDeclaration", "indexEntityReference")
|
||||
class IndexerCallbacks(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(64, 8)
|
||||
companion object : CStructVar.Type(64, 8)
|
||||
|
||||
var abortQuery: CPointer<CFunction<(CXClientData?, COpaquePointer?) -> Int>>?
|
||||
get() = memberAt<CPointerVar<CFunction<(CXClientData?, COpaquePointer?) -> Int>>>(0).value
|
||||
@@ -694,7 +694,7 @@ class IndexerCallbacks(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
@CNaturalStruct("typeOpaquePtr")
|
||||
class CXTypeAttributes(rawPtr: NativePtr) : CStructVar(rawPtr) {
|
||||
|
||||
companion object : Type(8, 8)
|
||||
companion object : CStructVar.Type(8, 8)
|
||||
|
||||
var typeOpaquePtr: COpaquePointer?
|
||||
get() = memberAt<COpaquePointerVar>(0).value
|
||||
@@ -3838,6 +3838,12 @@ fun clang_Cursor_isObjCConsumingSelfMethod(cursor: CValue<CXCursor>): Int {
|
||||
}
|
||||
}
|
||||
|
||||
fun clang_isExtVectorType(type: CValue<CXType>): Int {
|
||||
memScoped {
|
||||
return kniBridge339(type.getPointer(memScope).rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
val CINDEX_VERSION_MAJOR: Int get() = 0
|
||||
|
||||
val CINDEX_VERSION_MINOR: Int get() = 50
|
||||
@@ -4723,4 +4729,5 @@ private external fun kniBridge335(p0: NativePtr, p1: Int, p2: NativePtr): Unit
|
||||
private external fun kniBridge336(p0: NativePtr): Int
|
||||
private external fun kniBridge337(p0: NativePtr): Int
|
||||
private external fun kniBridge338(p0: NativePtr): Int
|
||||
private val loadLibrary = loadKonanLibrary("clangstubs")
|
||||
private external fun kniBridge339(p0: NativePtr): Int
|
||||
private val loadLibrary = loadKonanLibrary("clangstubs")
|
||||
|
||||
+37
@@ -499,6 +499,43 @@ internal class NativeIndexImpl(val library: NativeLibrary, val verbose: Boolean
|
||||
spelling = clang_getTypeSpelling(type).convertAndDispose().dropConstQualifier()
|
||||
)
|
||||
|
||||
CXType_Unexposed -> {
|
||||
// FIXME Remove this cludge for libclang version >= 9 (CINDEX_VERSION > 55)
|
||||
if (clang_isExtVectorType(type) != 0) {
|
||||
val size = clang_Type_getSizeOf(type)
|
||||
if (size == 16L) {
|
||||
// ExtVector elementType and elementCount are ignored for now but stubs are still needed for
|
||||
// CXType_Vector compatibility. Incoming clang v9 provide CXType_ExtVector compatible with CXType_Vector
|
||||
val spelling = "__attribute__((__vector_size__($size))) float"
|
||||
VectorType(FloatingType(4, "float"), 4, spelling)
|
||||
} else {
|
||||
UnsupportedType
|
||||
}
|
||||
} else {
|
||||
UnsupportedType
|
||||
}
|
||||
}
|
||||
|
||||
CXType_Vector -> {
|
||||
val elementCXType = clang_getElementType(type)
|
||||
val elementType = convertType(elementCXType)
|
||||
val size = clang_Type_getSizeOf(type)
|
||||
val elemSize = clang_Type_getSizeOf(elementCXType)
|
||||
val elementCount = clang_getNumElements(type)
|
||||
assert(size >= elemSize * elementCount && size % elemSize == 0L)
|
||||
|
||||
// Spelling example: `__attribute__((__vector_size__(4 * sizeof(float)))) const float`
|
||||
// Re-generate spelling removing constness and typedefs to limit number of variants for bridge generator
|
||||
// Supposed to be the same (i.e. natively compatible) as clang_getTypeSpelling(type) aka type.name
|
||||
val spelling = "__attribute__((__vector_size__($size))) ${clang_getCanonicalType(elementCXType).name}"
|
||||
|
||||
if (size == 16L) {
|
||||
VectorType(elementType, elementCount.toInt(), spelling)
|
||||
} else {
|
||||
UnsupportedType
|
||||
}
|
||||
}
|
||||
|
||||
CXTypeKind.CXType_Bool -> CBoolType
|
||||
|
||||
else -> UnsupportedType
|
||||
|
||||
+3
-1
@@ -271,6 +271,8 @@ data class IntegerType(val size: Int, val isSigned: Boolean, val spelling: Strin
|
||||
// TODO: floating type is not actually defined entirely by its size.
|
||||
data class FloatingType(val size: Int, val spelling: String) : PrimitiveType
|
||||
|
||||
data class VectorType(val elementType: Type, val elementCount: Int, val spelling: String) : PrimitiveType
|
||||
|
||||
object VoidType : Type
|
||||
|
||||
data class RecordType(val decl: StructDecl) : Type
|
||||
@@ -326,4 +328,4 @@ data class ObjCBlockPointer(
|
||||
val parameterTypes: List<Type>, val returnType: Type
|
||||
) : ObjCPointer()
|
||||
|
||||
object UnsupportedType : Type
|
||||
object UnsupportedType : Type
|
||||
|
||||
@@ -30,6 +30,12 @@ internal val CValue<CXType>.kind: CXTypeKind get() = this.useContents { kind }
|
||||
|
||||
internal val CValue<CXCursor>.kind: CXCursorKind get() = this.useContents { kind }
|
||||
|
||||
internal val CValue<CXCursor>.type: CValue<CXType> get() = clang_getCursorType(this)
|
||||
internal val CValue<CXCursor>.spelling: String get() = clang_getCursorSpelling(this).convertAndDispose()
|
||||
internal val CValue<CXType>.name: String get() = clang_getTypeSpelling(this).convertAndDispose()
|
||||
internal val CXTypeKind.spelling: String get() = clang_getTypeKindSpelling(this).convertAndDispose()
|
||||
internal val CXCursorKind.spelling: String get() = clang_getCursorKindSpelling(this).convertAndDispose()
|
||||
|
||||
internal fun CValue<CXString>.convertAndDispose(): String {
|
||||
try {
|
||||
return clang_getCString(this)!!.toKString()
|
||||
|
||||
@@ -470,4 +470,4 @@ public typealias CArrayPointerVar<T> = CPointerVar<T>
|
||||
/**
|
||||
* The C function.
|
||||
*/
|
||||
public class CFunction<T : Function<*>>(rawPtr: NativePtr) : CPointed(rawPtr)
|
||||
public class CFunction<T : Function<*>>(rawPtr: NativePtr) : CPointed(rawPtr)
|
||||
|
||||
@@ -53,6 +53,9 @@ internal object nativeMemUtils {
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getNativePtr(mem: NativePointed): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putNativePtr(mem: NativePointed, value: NativePtr)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_PRIMITIVE) external fun getVector(mem: NativePointed): Vector128
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_WRITE_PRIMITIVE) external fun putVector(mem: NativePointed, value: Vector128)
|
||||
|
||||
// TODO: optimize
|
||||
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
||||
val sourceArray = source.reinterpret<ByteVar>().ptr
|
||||
|
||||
@@ -56,6 +56,14 @@ external fun CPointer<*>.getRawValue(): NativePtr
|
||||
|
||||
internal fun CPointer<*>.cPointerToString() = "CPointer(raw=$rawValue)"
|
||||
|
||||
public class Vector128VarOf<T : Vector128>(rawPtr: NativePtr) : CVariable(rawPtr)
|
||||
|
||||
public typealias Vector128Var = Vector128VarOf<Vector128>
|
||||
|
||||
public var <T : Vector128> Vector128VarOf<T>.value: T
|
||||
get() = nativeMemUtils.getVector(this) as T
|
||||
set(value) = nativeMemUtils.putVector(this, value)
|
||||
|
||||
/**
|
||||
* Returns a pointer to C function which calls given Kotlin *static* function.
|
||||
*
|
||||
@@ -106,4 +114,4 @@ internal fun CPointer<*>.cPointerToString() = "CPointer(raw=$rawValue)"
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R>>
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R>>
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_STATIC_C_FUNCTION) external fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> staticCFunction(@VolatileLambda function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R): CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R>>
|
||||
|
||||
+2
@@ -187,6 +187,7 @@ object KotlinTypes {
|
||||
val map by CollectionClassifier
|
||||
|
||||
val nativePtr by InteropType
|
||||
val vector128 by KotlinNativeType
|
||||
|
||||
val cOpaque by InteropType
|
||||
val cOpaquePointer by InteropType
|
||||
@@ -233,6 +234,7 @@ object KotlinTypes {
|
||||
|
||||
private object InteropClassifier : ClassifierAtPackage("kotlinx.cinterop")
|
||||
private object InteropType : TypeAtPackage("kotlinx.cinterop")
|
||||
private object KotlinNativeType : TypeAtPackage("kotlin.native")
|
||||
}
|
||||
|
||||
abstract class KotlinFile(
|
||||
|
||||
+7
@@ -75,6 +75,10 @@ fun PrimitiveType.getKotlinType(declarationMapper: DeclarationMapper): KotlinCla
|
||||
else -> TODO(this.toString())
|
||||
}
|
||||
|
||||
is VectorType -> {
|
||||
/// @todo assert elementType and size here
|
||||
KotlinTypes.vector128
|
||||
}
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
|
||||
@@ -373,6 +377,9 @@ fun mirrorPrimitiveType(type: PrimitiveType, declarationMapper: DeclarationMappe
|
||||
8 -> "DoubleVar"
|
||||
else -> TODO(type.toString())
|
||||
}
|
||||
is VectorType -> {
|
||||
"Vector128Var"
|
||||
}
|
||||
else -> TODO(type.toString())
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ enum class BridgedType(val kotlinType: KotlinClassifierType, val convertor: Stri
|
||||
ULONG(KotlinTypes.uLong, "toULong"),
|
||||
FLOAT(KotlinTypes.float, "toFloat"),
|
||||
DOUBLE(KotlinTypes.double, "toDouble"),
|
||||
VECTOR128(KotlinTypes.vector128),
|
||||
NATIVE_PTR(KotlinTypes.nativePtr),
|
||||
OBJC_POINTER(KotlinTypes.nativePtr),
|
||||
VOID(KotlinTypes.unit)
|
||||
|
||||
+2
@@ -46,6 +46,7 @@ class SimpleBridgeGeneratorImpl(
|
||||
BridgedType.ULONG -> "jlong"
|
||||
BridgedType.FLOAT -> "jfloat"
|
||||
BridgedType.DOUBLE -> "jdouble"
|
||||
BridgedType.VECTOR128 -> TODO()
|
||||
BridgedType.NATIVE_PTR -> "jlong"
|
||||
BridgedType.OBJC_POINTER -> TODO()
|
||||
BridgedType.VOID -> "void"
|
||||
@@ -61,6 +62,7 @@ class SimpleBridgeGeneratorImpl(
|
||||
BridgedType.ULONG -> "uint64_t"
|
||||
BridgedType.FLOAT -> "float"
|
||||
BridgedType.DOUBLE -> "double"
|
||||
BridgedType.VECTOR128 -> TODO() // "float __attribute__ ((__vector_size__ (16)))"
|
||||
BridgedType.NATIVE_PTR -> "void*"
|
||||
BridgedType.OBJC_POINTER -> "id"
|
||||
BridgedType.VOID -> "void"
|
||||
|
||||
+3
-2
@@ -91,7 +91,8 @@ private object PredefinedTypesHandler {
|
||||
KotlinTypes.boolean,
|
||||
KotlinTypes.byte, KotlinTypes.short, KotlinTypes.int, KotlinTypes.long,
|
||||
KotlinTypes.uByte, KotlinTypes.uShort, KotlinTypes.uInt, KotlinTypes.uLong,
|
||||
KotlinTypes.float, KotlinTypes.double
|
||||
KotlinTypes.float, KotlinTypes.double,
|
||||
KotlinTypes.vector128
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -173,4 +174,4 @@ private object PredefinedTypesHandler {
|
||||
nativePtrClassifier -> expandNativePtr(platform, nullable)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ fun Type.getStringRepresentation(): String = when (this) {
|
||||
is IntegerType -> this.spelling
|
||||
is FloatingType -> this.spelling
|
||||
|
||||
is VectorType -> this.spelling
|
||||
is PointerType -> getPointerTypeStringRepresentation(this.pointeeType)
|
||||
is ArrayType -> getPointerTypeStringRepresentation(this.elemType)
|
||||
|
||||
|
||||
+1
-1
@@ -16,5 +16,5 @@ fun BinaryType<*>.primitiveBinaryTypeOrNull(): PrimitiveBinaryType? = when (this
|
||||
}
|
||||
|
||||
enum class PrimitiveBinaryType {
|
||||
BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, POINTER
|
||||
BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, POINTER, VECTOR128
|
||||
}
|
||||
|
||||
+2
@@ -846,6 +846,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
|
||||
output("typedef unsigned long long ${prefix}_KULong;")
|
||||
output("typedef float ${prefix}_KFloat;")
|
||||
output("typedef double ${prefix}_KDouble;")
|
||||
output("typedef float __attribute__ ((__vector_size__ (16))) ${prefix}_KVector128;")
|
||||
output("typedef void* ${prefix}_KNativePtr;")
|
||||
output("struct ${prefix}_KType;")
|
||||
output("typedef struct ${prefix}_KType ${prefix}_KType;")
|
||||
@@ -1026,6 +1027,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
|
||||
KonanPrimitiveType.FLOAT -> "${prefix}_KFloat"
|
||||
KonanPrimitiveType.DOUBLE -> "${prefix}_KDouble"
|
||||
KonanPrimitiveType.NON_NULL_NATIVE_PTR -> "void*"
|
||||
KonanPrimitiveType.VECTOR128 -> "${prefix}_KVector128"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
|
||||
@@ -81,7 +82,8 @@ enum class KonanPrimitiveType(val classId: ClassId, val binaryType: BinaryType.P
|
||||
LONG(PrimitiveType.LONG, PrimitiveBinaryType.LONG),
|
||||
FLOAT(PrimitiveType.FLOAT, PrimitiveBinaryType.FLOAT),
|
||||
DOUBLE(PrimitiveType.DOUBLE, PrimitiveBinaryType.DOUBLE),
|
||||
NON_NULL_NATIVE_PTR(ClassId.topLevel(KonanFqNames.nonNullNativePtr.toSafe()), PrimitiveBinaryType.POINTER)
|
||||
NON_NULL_NATIVE_PTR(ClassId.topLevel(KonanFqNames.nonNullNativePtr.toSafe()), PrimitiveBinaryType.POINTER),
|
||||
VECTOR128(ClassId.topLevel(KonanFqNames.Vector128), PrimitiveBinaryType.VECTOR128)
|
||||
|
||||
;
|
||||
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal const val NATIVE_PTR_NAME = "NativePtr"
|
||||
internal const val NON_NULL_NATIVE_PTR_NAME = "NonNullNativePtr"
|
||||
internal const val VECTOR128 = "Vector128"
|
||||
|
||||
object KonanFqNames {
|
||||
val function = FqName("kotlin.Function")
|
||||
@@ -19,6 +20,7 @@ object KonanFqNames {
|
||||
val internalPackageName = FqName("kotlin.native.internal")
|
||||
val nativePtr = internalPackageName.child(Name.identifier(NATIVE_PTR_NAME)).toUnsafe()
|
||||
val nonNullNativePtr = internalPackageName.child(Name.identifier(NON_NULL_NATIVE_PTR_NAME)).toUnsafe()
|
||||
val Vector128 = packageName.child(Name.identifier(VECTOR128))
|
||||
val throws = FqName("kotlin.native.Throws")
|
||||
val threadLocal = FqName("kotlin.native.concurrent.ThreadLocal")
|
||||
val sharedImmutable = FqName("kotlin.native.concurrent.SharedImmutable")
|
||||
|
||||
+10
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
import org.jetbrains.kotlin.backend.konan.PrimitiveBinaryType
|
||||
import org.jetbrains.kotlin.backend.konan.RuntimeNames
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
@@ -757,6 +758,13 @@ private fun KotlinStubs.mapType(type: IrType, retained: Boolean, variadic: Boole
|
||||
private fun IrType.isTypeOfNullLiteral(): Boolean = this is IrSimpleType && hasQuestionMark
|
||||
&& classifier.isClassWithFqName(KotlinBuiltIns.FQ_NAMES.nothing)
|
||||
|
||||
private fun IrType.isVector(): Boolean {
|
||||
if (this is IrSimpleType && !this.hasQuestionMark) {
|
||||
return classifier.isClassWithFqName(KonanFqNames.Vector128.toUnsafe())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun KotlinStubs.mapType(
|
||||
type: IrType,
|
||||
retained: Boolean,
|
||||
@@ -782,6 +790,8 @@ private fun KotlinStubs.mapType(
|
||||
type.isUInt() -> UnsignedValuePassing(type, CTypes.int, CTypes.unsignedInt)
|
||||
type.isULong() -> UnsignedValuePassing(type, CTypes.longLong, CTypes.unsignedLongLong)
|
||||
|
||||
type.isVector() -> TrivialValuePassing(type, CTypes.vector128)
|
||||
|
||||
type.isCEnumType() -> {
|
||||
val enumClass = type.getClass()!!
|
||||
val value = enumClass.declarations
|
||||
|
||||
+3
-1
@@ -33,6 +33,8 @@ internal object CTypes {
|
||||
val C99Bool = simple("_Bool")
|
||||
val char = simple("char")
|
||||
|
||||
val vector128 = simple("float __attribute__ ((__vector_size__ (16)))")
|
||||
|
||||
val id = simple("id")
|
||||
}
|
||||
|
||||
@@ -61,4 +63,4 @@ private class FunctionCType(
|
||||
}
|
||||
append(')')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -219,6 +219,8 @@ internal class KonanSymbols(
|
||||
|
||||
val throwArithmeticException = internalFunction("ThrowArithmeticException")
|
||||
|
||||
val throwIndexOutOfBoundsException = internalFunction("ThrowIndexOutOfBoundsException")
|
||||
|
||||
override val ThrowNullPointerException = internalFunction("ThrowNullPointerException")
|
||||
|
||||
override val ThrowNoWhenBranchMatchedException = internalFunction("ThrowNoWhenBranchMatchedException")
|
||||
|
||||
+4
@@ -558,6 +558,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
return LLVMBuildLandingPad(builder, landingpadType, personalityFunction, numClauses, name)!!
|
||||
}
|
||||
|
||||
fun extractElement(vector: LLVMValueRef, index: LLVMValueRef, name: String = ""): LLVMValueRef {
|
||||
return LLVMBuildExtractElement(builder, vector, index, name)!!
|
||||
}
|
||||
|
||||
fun filteringExceptionHandler(codeContext: CodeContext): ExceptionHandler {
|
||||
val lpBlock = basicBlockInFunction("filteringExceptionHandler", position()?.start)
|
||||
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ private fun RuntimeAware.getLlvmType(primitiveBinaryType: PrimitiveBinaryType?)
|
||||
PrimitiveBinaryType.FLOAT -> floatType
|
||||
PrimitiveBinaryType.DOUBLE -> doubleType
|
||||
|
||||
PrimitiveBinaryType.VECTOR128 -> vector128Type
|
||||
PrimitiveBinaryType.POINTER -> int8TypePtr
|
||||
}
|
||||
|
||||
@@ -37,4 +38,4 @@ internal fun RuntimeAware.getLLVMReturnType(type: IrType): LLVMTypeRef {
|
||||
type.isUnit() || type.isNothing() -> voidType
|
||||
else -> getLLVMType(type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-3
@@ -47,6 +47,7 @@ internal enum class IntrinsicType {
|
||||
UNSIGNED_COMPARE_TO,
|
||||
NOT,
|
||||
REINTERPRET,
|
||||
EXTRACT_ELEMENT,
|
||||
ARE_EQUAL_BY_VALUE,
|
||||
IEEE_754_EQUALS,
|
||||
// OBJC
|
||||
@@ -130,6 +131,9 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
private val IrCall.llvmReturnType: LLVMTypeRef
|
||||
get() = LLVMGetReturnType(codegen.getLlvmFunctionType(symbol.owner))!!
|
||||
|
||||
|
||||
private fun LLVMTypeRef.sizeInBits() = LLVMSizeOfTypeInBits(codegen.llvmTargetData, this).toInt()
|
||||
|
||||
/**
|
||||
* Some intrinsics have to be processed before evaluation of their arguments.
|
||||
* So this method looks at [callSite] and if it is call to "special" intrinsic
|
||||
@@ -213,6 +217,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
IntrinsicType.UNSIGNED_COMPARE_TO -> emitUnsignedCompareTo(args)
|
||||
IntrinsicType.NOT -> emitNot(args)
|
||||
IntrinsicType.REINTERPRET -> emitReinterpret(callSite, args)
|
||||
IntrinsicType.EXTRACT_ELEMENT -> emitExtractElement(callSite, args)
|
||||
IntrinsicType.SIGN_EXTEND -> emitSignExtend(callSite, args)
|
||||
IntrinsicType.ZERO_EXTEND -> emitZeroExtend(callSite, args)
|
||||
IntrinsicType.INT_TRUNCATE -> emitIntTruncate(callSite, args)
|
||||
@@ -485,9 +490,10 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
assert (first.type == second.type) { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" }
|
||||
|
||||
return when (val typeKind = LLVMGetTypeKind(first.type)) {
|
||||
llvm.LLVMTypeKind.LLVMFloatTypeKind, llvm.LLVMTypeKind.LLVMDoubleTypeKind -> {
|
||||
val numBits = llvm.LLVMSizeOfTypeInBits(codegen.llvmTargetData, first.type).toInt()
|
||||
val integerType = LLVMIntTypeInContext(llvmContext, numBits)!!
|
||||
llvm.LLVMTypeKind.LLVMFloatTypeKind, llvm.LLVMTypeKind.LLVMDoubleTypeKind,
|
||||
LLVMTypeKind.LLVMVectorTypeKind -> {
|
||||
// TODO LLVM API does not provide guarantee for LLVMIntTypeInContext availability for longer types; consider meaningful diag message instead of NPE
|
||||
val integerType = LLVMIntTypeInContext(llvmContext, first.type.sizeInBits())!!
|
||||
icmpEq(bitcast(integerType, first), bitcast(integerType, second))
|
||||
}
|
||||
llvm.LLVMTypeKind.LLVMIntegerTypeKind, llvm.LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(first, second)
|
||||
@@ -508,6 +514,24 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
private fun FunctionGenerationContext.emitReinterpret(callSite: IrCall, args: List<LLVMValueRef>) =
|
||||
bitcast(callSite.llvmReturnType, args[0])
|
||||
|
||||
private fun FunctionGenerationContext.emitExtractElement(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (vector, index) = args
|
||||
val elementSize = LLVMSizeOfTypeInBits(codegen.llvmTargetData, callSite.llvmReturnType).toInt()
|
||||
val vectorSize = LLVMSizeOfTypeInBits(codegen.llvmTargetData, vector.type).toInt()
|
||||
|
||||
assert(callSite.llvmReturnType.isVectorElementType()
|
||||
&& vectorSize % elementSize == 0
|
||||
) { "Invalid vector element type ${LLVMGetTypeKind(callSite.llvmReturnType)}"}
|
||||
|
||||
val elementCount = vectorSize / elementSize
|
||||
emitThrowIfOOB(index, Int32((elementCount)).llvm)
|
||||
|
||||
val targetType = LLVMVectorType(callSite.llvmReturnType, elementCount)!!
|
||||
return extractElement(
|
||||
(if (targetType == vector.type) vector else bitcast(targetType, vector)),
|
||||
index)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitNot(args: List<LLVMValueRef>) =
|
||||
not(args[0])
|
||||
|
||||
@@ -611,6 +635,14 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitThrowIfOOB(index: LLVMValueRef, size: LLVMValueRef) {
|
||||
ifThen(icmpUGe(index, size)) {
|
||||
val throwIndexOutOfBoundsException = codegen.llvmFunction(context.ir.symbols.throwIndexOutOfBoundsException.owner)
|
||||
call(throwIndexOutOfBoundsException, emptyList(), Lifetime.GLOBAL, environment.exceptionHandler)
|
||||
unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitSignedDiv(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
if (!second.type.isFloatingPoint()) {
|
||||
|
||||
+5
-1
@@ -89,7 +89,11 @@ private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>
|
||||
|
||||
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
|
||||
|
||||
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, 0)
|
||||
// LLVMStructSetBody expects the struct to be properly aligned and will insert padding accordingly. In our case
|
||||
// `allocInstance` returns 16x + 8 address, i.e. always misaligned for vector types. Workaround is to use packed struct.
|
||||
val hasBigAlignment = fields.any { LLVMABIAlignmentOfType(context.llvm.runtime.targetData, getLLVMType(it.type)) > 8 }
|
||||
val packed = if (hasBigAlignment) 1 else 0
|
||||
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, packed)
|
||||
|
||||
return classType
|
||||
}
|
||||
|
||||
+9
-1
@@ -110,6 +110,7 @@ internal val int64Type get() = LLVMInt64TypeInContext(llvmContext)!!
|
||||
internal val int8TypePtr get() = pointerType(int8Type)
|
||||
internal val floatType get() = LLVMFloatTypeInContext(llvmContext)!!
|
||||
internal val doubleType get() = LLVMDoubleTypeInContext(llvmContext)!!
|
||||
internal val vector128Type get() = LLVMVectorType(floatType, 4)!!
|
||||
|
||||
internal val voidType get() = LLVMVoidTypeInContext(llvmContext)!!
|
||||
|
||||
@@ -384,4 +385,11 @@ internal fun LLVMValueRef.setUnaligned() = apply { LLVMSetAlignment(this, 1) }
|
||||
fun LLVMTypeRef.isFloatingPoint(): Boolean = when (llvm.LLVMGetTypeKind(this)) {
|
||||
LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun LLVMTypeRef.isVectorElementType(): Boolean = when (llvm.LLVMGetTypeKind(this)) {
|
||||
LLVMTypeKind.LLVMIntegerTypeKind,
|
||||
LLVMTypeKind.LLVMFloatTypeKind,
|
||||
LLVMTypeKind.LLVMDoubleTypeKind -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
+2
-1
@@ -171,7 +171,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
floatType to 6,
|
||||
doubleType to 7,
|
||||
kInt8Ptr to 8,
|
||||
int1Type to 9
|
||||
int1Type to 9,
|
||||
vector128Type to 10
|
||||
)
|
||||
|
||||
private fun getInstanceSize(classType: LLVMTypeRef?, className: FqName) : Int {
|
||||
|
||||
+2
-2
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
@@ -29,6 +28,7 @@ internal class KonanDefaultParameterInjector(private val konanContext: KonanBack
|
||||
PrimitiveBinaryType.FLOAT -> IrConstImpl.float(startOffset, endOffset, type, 0.0F)
|
||||
PrimitiveBinaryType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, type, 0.0)
|
||||
PrimitiveBinaryType.POINTER -> irCall(startOffset, endOffset, symbols.getNativeNullPtr.owner, emptyList())
|
||||
PrimitiveBinaryType.VECTOR128 -> TODO()
|
||||
}
|
||||
|
||||
return irCall(
|
||||
@@ -40,4 +40,4 @@ internal class KonanDefaultParameterInjector(private val konanContext: KonanBack
|
||||
extensionReceiver = nullConstOfEquivalentType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -207,6 +207,7 @@ private fun ObjCExportMapper.bridgeType(
|
||||
KonanPrimitiveType.FLOAT -> ObjCValueType.FLOAT
|
||||
KonanPrimitiveType.DOUBLE -> ObjCValueType.DOUBLE
|
||||
KonanPrimitiveType.NON_NULL_NATIVE_PTR -> ObjCValueType.POINTER
|
||||
KonanPrimitiveType.VECTOR128 -> TODO()
|
||||
}
|
||||
ValueTypeBridge(objCValueType)
|
||||
},
|
||||
|
||||
@@ -764,6 +764,10 @@ task runtime_random(type: KonanLocalTest) {
|
||||
source = "runtime/basic/random.kt"
|
||||
}
|
||||
|
||||
task runtime_basic_simd(type: KonanLocalTest) {
|
||||
source = "runtime/basic/simd.kt"
|
||||
}
|
||||
|
||||
task runtime_worker_random(type: KonanLocalTest) {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses workers.
|
||||
source = "runtime/basic/worker_random.kt"
|
||||
@@ -3658,6 +3662,7 @@ dynamicTest("produce_dynamic") {
|
||||
"singleton = I am single\n" +
|
||||
"mutable = foo\n" +
|
||||
"topLevel = 777 3\n" +
|
||||
"getVector128 = (1, 2, 3, 4)\n" +
|
||||
"Error handler: kotlin.Error: Expected error\n"
|
||||
}
|
||||
|
||||
|
||||
@@ -138,4 +138,6 @@ fun getNullableString(param: Int) : String? {
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getVector128() = vectorOf(1, 2, 3, 4)
|
||||
|
||||
@@ -9,6 +9,11 @@ void errorHandler(const char* str) {
|
||||
printf("Error handler: %s\n", str);
|
||||
}
|
||||
|
||||
void testVector128() {
|
||||
int __attribute__ ((__vector_size__ (16))) v4f = __ kotlin.root.getVector128();
|
||||
printf("getVector128 = (%d, %d, %d, %d)\n", v4f[0], v4f[1], v4f[2], v4f[3]);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
T_(Singleton) singleton = __ kotlin.root.Singleton._instance();
|
||||
T_(Base) base = __ kotlin.root.Base.Base();
|
||||
@@ -65,6 +70,8 @@ int main(void) {
|
||||
|
||||
__ kotlin.root.testNullableWithNulls(nullableIntNull, nullableUnitNull);
|
||||
|
||||
testVector128();
|
||||
|
||||
__ DisposeStablePointer(singleton.pinned);
|
||||
__ DisposeString(string1);
|
||||
__ DisposeString(string2);
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package runtime.basic.simd
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
|
||||
@Test fun runTest() {
|
||||
testSetGet()
|
||||
testString()
|
||||
testOOB()
|
||||
testEquals()
|
||||
testHash()
|
||||
testDefaultValue()
|
||||
}
|
||||
|
||||
fun testSetGet() {
|
||||
var v4any = vectorOf(0, 1, 2, 3)
|
||||
(0 until 4).forEach { assertEquals(it, v4any.getIntAt(it)) }
|
||||
|
||||
// type punning: set the variable to another runtime type
|
||||
val a = arrayOf(1f, 3.162f, 10f, 31f)
|
||||
v4any = vectorOf(a[0], a[1], a[2], a[3])
|
||||
(0 until 4).forEach { assertEquals(a[it], v4any.getFloatAt(it)) }
|
||||
}
|
||||
|
||||
fun testString() {
|
||||
val v4i = vectorOf(100, 1024, Int.MAX_VALUE, Int.MIN_VALUE)
|
||||
assertEquals("(0x64, 0x400, 0x7fffffff, 0x80000000)", v4i.toString())
|
||||
}
|
||||
|
||||
fun testOOB() {
|
||||
val f = vectorOf(1f, 3.162f, 10f, 31f)
|
||||
|
||||
println("f.getByteAt(15) is OK ${f.getByteAt(15)}")
|
||||
|
||||
assertFailsWith<IndexOutOfBoundsException>("f.getByteAt(16) should fail") {
|
||||
f.getByteAt(16)
|
||||
}
|
||||
|
||||
assertFailsWith<IndexOutOfBoundsException>("f.getIntAt(-1) should fail") {
|
||||
f.getIntAt(-1)
|
||||
}
|
||||
|
||||
assertFailsWith<IndexOutOfBoundsException>("f.getFloatAt(4) should fail") {
|
||||
f.getFloatAt(4)
|
||||
}
|
||||
}
|
||||
|
||||
fun testEquals() {
|
||||
var v1 = vectorOf(-1f, 0f, 0f, -7f)
|
||||
var v2 = vectorOf(1f, 4f, 3f, 7f)
|
||||
assertEquals(false, v1 == v2)
|
||||
assertEquals(false, v1.equals(v2))
|
||||
assertEquals(false, v1.equals(Any()))
|
||||
assertEquals(true, v2 == v2)
|
||||
|
||||
v1 = v2
|
||||
assertEquals(true, v1 == v2)
|
||||
}
|
||||
|
||||
fun testHash() {
|
||||
val h1 = vectorOf(1f, 4f, 3f, 7f).hashCode()
|
||||
val h2 = vectorOf(3f, 7f, 1f, 4f).hashCode()
|
||||
assertEquals(false, h1 == h2)
|
||||
|
||||
val i = 654687
|
||||
assertEquals(true, vectorOf(0, 0, i, 0).hashCode() == i.hashCode()) // exploit little endianness
|
||||
assertEquals(true, vectorOf(1, 0, 0, 0).hashCode() == vectorOf(0, 0, 31, 0).hashCode())
|
||||
}
|
||||
|
||||
private fun funDefaultValue(v: Vector128 = vectorOf(1.0f, 2.0f, 3.0f, 4.0f)) = v
|
||||
|
||||
fun testDefaultValue() {
|
||||
assertEquals(vectorOf(1.0f, 2.0f, 3.0f, 4.0f), funDefaultValue())
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <clang/AST/Type.h>
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
||||
static inline QualType GetQualType(CXType CT) {
|
||||
return QualType::getFromOpaquePtr(CT.data[0]);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int clang_isExtVectorType(CXType CT) {
|
||||
static_assert(CINDEX_VERSION < 59, "Use CXType_ExtVector for this libclang version");
|
||||
|
||||
QualType T = GetQualType(CT);
|
||||
const clang::Type *TP = T.getTypePtrOrNull();
|
||||
return TP && TP->isExtVectorType();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int clang_isExtVectorType(CXType type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -93,4 +93,12 @@ bool IsSubInterface(const TypeInfo* thiz, const TypeInfo* other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KVector4f Kotlin_Vector4f_of(KFloat f0, KFloat f1, KFloat f2, KFloat f3) {
|
||||
return {f0, f1, f2, f3};
|
||||
}
|
||||
|
||||
KVector4i32 Kotlin_Vector4i32_of(KInt f0, KInt f1, KInt f2, KInt f3) {
|
||||
return {f0, f1, f2, f3};
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -51,6 +51,8 @@ typedef uint64_t KULong;
|
||||
typedef float KFloat;
|
||||
typedef double KDouble;
|
||||
typedef void* KNativePtr;
|
||||
typedef KFloat __attribute__ ((__vector_size__ (16))) KVector4f;
|
||||
typedef KInt __attribute__ ((__vector_size__ (16))) KVector4i32;
|
||||
|
||||
typedef const void* KConstNativePtr;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ class IntrinsicType {
|
||||
const val UNSIGNED_COMPARE_TO = "UNSIGNED_COMPARE_TO"
|
||||
const val NOT = "NOT"
|
||||
const val REINTERPRET = "REINTERPRET"
|
||||
const val EXTRACT_ELEMENT = "EXTRACT_ELEMENT"
|
||||
const val ARE_EQUAL_BY_VALUE = "ARE_EQUAL_BY_VALUE"
|
||||
const val IEEE_754_EQUALS = "IEEE_754_EQUALS"
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import kotlin.native.internal.IntrinsicType
|
||||
// Bitwise equality:
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Float, second: Float): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Double, second: Double): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Vector128, second: Vector128): Boolean
|
||||
|
||||
// IEEE754 equality:
|
||||
@TypedIntrinsic(IntrinsicType.IEEE_754_EQUALS) @PublishedApi external internal fun ieee754Equals(first: Float, second: Float): Boolean
|
||||
|
||||
@@ -13,6 +13,11 @@ fun ThrowNullPointerException(): Nothing {
|
||||
throw NullPointerException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun ThrowIndexOutOfBoundsException(): Nothing {
|
||||
throw IndexOutOfBoundsException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun ThrowArrayIndexOutOfBoundsException(): Nothing {
|
||||
throw ArrayIndexOutOfBoundsException()
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package kotlin.native
|
||||
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
|
||||
public final class Vector128 private constructor() {
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getByteAt(index: Int): Byte
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getIntAt(index: Int): Int
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getLongAt(index: Int): Long
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getFloatAt(index: Int): Float
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getDoubleAt(index: Int): Double
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getUByteAt(index: Int): UByte
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getUIntAt(index: Int): UInt
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.EXTRACT_ELEMENT)
|
||||
external fun getULongAt(index: Int): ULong
|
||||
|
||||
public override fun toString() =
|
||||
"(0x${getUIntAt(0).toString(16)}, 0x${getUIntAt(1).toString(16)}, 0x${getUIntAt(2).toString(16)}, 0x${getUIntAt(3).toString(16)})"
|
||||
|
||||
// Not as good for floating types
|
||||
public fun equals(other: Vector128): Boolean =
|
||||
getLongAt(0) == other.getLongAt(0) && getLongAt(1) == other.getLongAt(1)
|
||||
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Vector128 && this.equals(other)
|
||||
|
||||
override fun hashCode(): Int {
|
||||
val x0 = getLongAt(0)
|
||||
val x1 = getLongAt(1)
|
||||
return 31 * (x0 xor (x0 shr 32)).toInt() + (x1 xor (x1 shr 32)).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Vector4f_of")
|
||||
external fun vectorOf(f0: Float, f1: Float, f2: Float, f3: Float): Vector128
|
||||
|
||||
@SymbolName("Kotlin_Vector4i32_of")
|
||||
external fun vectorOf(f0: Int, f1: Int, f2: Int, f3: Int): Vector128
|
||||
@@ -0,0 +1,58 @@
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
import platform.Accelerate.*
|
||||
import platform.darwin.*
|
||||
|
||||
|
||||
// Custom print
|
||||
fun Vector128.toStringHex(): String {
|
||||
return "0x" + (0 until 16).map { getUByteAt(it).toString(16) }.joinToString("")
|
||||
}
|
||||
|
||||
// Custom print
|
||||
fun Vector128.toStringFloat(): String {
|
||||
return "(${(0 until 4).map { getFloatAt(it).toString() }.joinToString(", ")})"
|
||||
}
|
||||
|
||||
|
||||
fun main() {
|
||||
|
||||
// Accessors
|
||||
val vf4 = vectorOf(1f, 3.162f, 10f, 31f)
|
||||
println(vf4)
|
||||
println(vf4.toStringFloat())
|
||||
println(vf4.toStringHex())
|
||||
println(vf4.getFloatAt(1))
|
||||
println(vf4.getIntAt(0))
|
||||
println(vf4.getByteAt(3))
|
||||
// Illegal access (out of bounds)
|
||||
try {
|
||||
println(vf4.getIntAt(4))
|
||||
println("FAILED")
|
||||
} catch (e: IndexOutOfBoundsException) {
|
||||
println("Handling $e")
|
||||
}
|
||||
|
||||
// Assignment and equality
|
||||
var x1 = vectorOf(-1f, 0f, 0f, -7f)
|
||||
val y1 = vectorOf(-1f, 0f, 0f, -7f)
|
||||
var x2 = vectorOf(1f, 4f, 3f, 7f)
|
||||
println("(x1 == y1) is ${(x1 == y1)}")
|
||||
println("(x1.equals(y1)) is ${(x1.equals(y1))}")
|
||||
println("(x1 == x2) is ${(x1 == x2)}")
|
||||
x1 = x2
|
||||
println("Now (x1 == x1) is ${(x1 == x1)}")
|
||||
|
||||
|
||||
// Using library function (MacOS Accelerate framework)
|
||||
val sum = vS128Add(vectorOf(1,2,3,4), vectorOf(4,3,2,1))
|
||||
println(sum)
|
||||
// More Accelerate framework
|
||||
val q = vectorOf(1f, 9f, 25f, 49f)
|
||||
val sq = vsqrtf(q)
|
||||
println("vsqrtf$q = ${sq.toStringFloat()}")
|
||||
val f4 = vectorOf(1f, 3.162f, 10f, 31f)
|
||||
println("vlog10f($f4) = ${vlog10f(vf4).toStringFloat()}")
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user