Implement CValuesRef in interop
* Represent pointer parameters of C functions as `CValuesRef`. * Represent struct value parameters as `CValue`. * Implement some helper methods to make the new approach more useful. * Migrate some code to new interop approach for pointers and values. Also do not map to `String?`: - pointers to 8-bit integers; - pointers to non-const chars.
This commit is contained in:
committed by
SvyatoslavScherbina
parent
7a876a3ccd
commit
c9d8d4d57d
+23
-28
@@ -140,7 +140,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
private var cleanupLandingpad: LLVMBasicBlockRef? = null
|
||||
|
||||
fun setName(value: LLVMValueRef, name: String) = LLVMSetValueName(value, name)
|
||||
fun getName(value: LLVMValueRef) = LLVMGetValueName(value)?.asCString().toString()
|
||||
fun getName(value: LLVMValueRef) = LLVMGetValueName(value)?.toKString()
|
||||
|
||||
fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildAdd (builder, arg0, arg1, name)!!
|
||||
fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildMul (builder, arg0, arg1, name)!!
|
||||
@@ -221,10 +221,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
}
|
||||
|
||||
fun gep(base: LLVMValueRef, index: LLVMValueRef): LLVMValueRef {
|
||||
memScoped {
|
||||
val args = allocArrayOf(index)
|
||||
return LLVMBuildGEP(builder, base, args[0].ptr, 1, "")!!
|
||||
}
|
||||
return LLVMBuildGEP(builder, base, cValuesOf(index), 1, "")!!
|
||||
}
|
||||
|
||||
fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
|
||||
@@ -277,30 +274,28 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
private fun callRaw(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
lazyLandingpad: () -> LLVMBasicBlockRef?): LLVMValueRef {
|
||||
memScoped {
|
||||
val rargs = allocArrayOf(args)[0].ptr
|
||||
|
||||
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
|
||||
(LLVMGetFunctionAttr(llvmFunction) and LLVMNoUnwindAttribute) != 0) {
|
||||
val rargs = args.toCValues()
|
||||
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
|
||||
(LLVMGetFunctionAttr(llvmFunction) and LLVMNoUnwindAttribute) != 0) {
|
||||
|
||||
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!
|
||||
} else {
|
||||
val landingpad = lazyLandingpad()
|
||||
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!
|
||||
} else {
|
||||
val landingpad = lazyLandingpad()
|
||||
|
||||
if (landingpad == null) {
|
||||
// When calling a function that is not marked as nounwind (can throw an exception),
|
||||
// it is required to specify a landingpad to handle exceptions properly.
|
||||
// Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`.
|
||||
val functionName = getName(llvmFunction)
|
||||
val message = "no landingpad specified when calling function $functionName without nounwind attr"
|
||||
throw IllegalArgumentException(message)
|
||||
}
|
||||
|
||||
val success = basicBlock()
|
||||
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, "")!!
|
||||
positionAtEnd(success)
|
||||
return result
|
||||
if (landingpad == null) {
|
||||
// When calling a function that is not marked as nounwind (can throw an exception),
|
||||
// it is required to specify a landingpad to handle exceptions properly.
|
||||
// Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`.
|
||||
val functionName = getName(llvmFunction)
|
||||
val message = "no landingpad specified when calling function $functionName without nounwind attr"
|
||||
throw IllegalArgumentException(message)
|
||||
}
|
||||
|
||||
val success = basicBlock()
|
||||
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, "")!!
|
||||
positionAtEnd(success)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,10 +307,10 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun addPhiIncoming(phi: LLVMValueRef, vararg incoming: Pair<LLVMBasicBlockRef, LLVMValueRef>) {
|
||||
memScoped {
|
||||
val incomingValues = allocArrayOf(incoming.map { it.second })
|
||||
val incomingBlocks = allocArrayOf(incoming.map { it.first })
|
||||
val incomingValues = incoming.map { it.second }.toCValues()
|
||||
val incomingBlocks = incoming.map { it.first }.toCValues()
|
||||
|
||||
LLVMAddIncoming(phi, incomingValues[0].ptr, incomingBlocks[0].ptr, incoming.size)
|
||||
LLVMAddIncoming(phi, incomingValues, incomingBlocks, incoming.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -193,11 +193,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
}
|
||||
|
||||
private fun importMemset() : LLVMValueRef {
|
||||
memScoped {
|
||||
val parameterTypes = allocArrayOf(int8TypePtr, int8Type, int32Type, int32Type, int1Type)
|
||||
val functionType = LLVMFunctionType(LLVMVoidType(), parameterTypes[0].ptr, 5, 0)
|
||||
return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!!
|
||||
}
|
||||
val parameterTypes = cValuesOf(int8TypePtr, int8Type, int32Type, int32Type, int1Type)
|
||||
val functionType = LLVMFunctionType(LLVMVoidType(), parameterTypes, 5, 0)
|
||||
return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!!
|
||||
}
|
||||
|
||||
internal fun externalFunction(name: String, type: LLVMTypeRef): LLVMValueRef {
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public fun base64Encode(data: ByteArray): String {
|
||||
val bytes = allocArrayOf(data)
|
||||
EncodeBase64(bytes.ptr, data.size, result.ptr, resultSize)
|
||||
// TODO: any better way to do that without two copies?
|
||||
return CString.fromArray(result).toString()
|
||||
return result[0].ptr.toKString()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-21
@@ -276,12 +276,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
// Creates static struct InitNode $nodeName = {$initName, NULL};
|
||||
|
||||
fun createInitNode(initFunction: LLVMValueRef, nodeName: String): LLVMValueRef {
|
||||
memScoped {
|
||||
val nextInitNode = LLVMConstNull(pointerType(kNodeInitType)) // Set InitNode.next = NULL.
|
||||
val argList = allocArrayOf(initFunction, nextInitNode)[0].ptr // Allocate array of args.
|
||||
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create static object of class InitNode.
|
||||
return context.llvm.staticData.placeGlobal(nodeName, constPointer(initNode)).llvmGlobal // Put the object in global var with name "nodeName".
|
||||
}
|
||||
val nextInitNode = LLVMConstNull(pointerType(kNodeInitType)) // Set InitNode.next = NULL.
|
||||
val argList = cValuesOf(initFunction, nextInitNode) // Construct array of args.
|
||||
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create static object of class InitNode.
|
||||
return context.llvm.staticData.placeGlobal(nodeName, constPointer(initNode)).llvmGlobal // Put the object in global var with name "nodeName".
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -1334,13 +1332,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val fieldInfo = context.llvmDeclarations.forField(value)
|
||||
|
||||
val typePtr = pointerType(fieldInfo.classBodyType)
|
||||
memScoped {
|
||||
val args = allocArrayOf(kImmOne)
|
||||
val objectPtr = LLVMBuildGEP(codegen.builder, thisPtr, args[0].ptr, 1, "")
|
||||
val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!)
|
||||
val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, fieldInfo.index, "")
|
||||
return fieldPtr!!
|
||||
}
|
||||
val objectPtr = LLVMBuildGEP(codegen.builder, thisPtr, cValuesOf(kImmOne), 1, "")
|
||||
val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!)
|
||||
val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, fieldInfo.index, "")
|
||||
return fieldPtr!!
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -1893,21 +1888,23 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
// Create type { i32, void ()*, i8* }
|
||||
|
||||
val kCtorType = memScoped {
|
||||
val ctorType = LLVMPointerType(kVoidFuncType, 0)
|
||||
val typeList = allocArrayOf(LLVMInt32Type(), ctorType, kInt8Ptr)[0].ptr
|
||||
LLVMStructType(typeList, 3, 0)
|
||||
}!!
|
||||
val kCtorType = LLVMStructType(
|
||||
cValuesOf(
|
||||
LLVMInt32Type(),
|
||||
LLVMPointerType(kVoidFuncType, 0),
|
||||
kInt8Ptr
|
||||
),
|
||||
3, 0)!!
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Create object { i32, void ()*, i8* } { i32 1, void ()* @ctorFunction, i8* null }
|
||||
|
||||
fun createGlobalCtor(ctorFunction: LLVMValueRef) = memScoped {
|
||||
fun createGlobalCtor(ctorFunction: LLVMValueRef): ConstPointer {
|
||||
val priority = kImmInt32One
|
||||
val data = kNullInt8Ptr
|
||||
val argList = allocArrayOf(priority, ctorFunction, data)[0].ptr
|
||||
val argList = cValuesOf(priority, ctorFunction, data)
|
||||
val ctorItem = LLVMConstNamedStruct(kCtorType, argList, 3)!!
|
||||
constPointer(ctorItem)
|
||||
return constPointer(ctorItem)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
+3
-5
@@ -123,14 +123,12 @@ private fun ContextUtils.getDeclaredFields(classDescriptor: ClassDescriptor): Li
|
||||
}
|
||||
|
||||
private fun ContextUtils.createClassBodyType(name: String, fields: List<PropertyDescriptor>): LLVMTypeRef {
|
||||
val fieldTypes = fields.map { getLLVMType(if (it.isDelegated) context.builtIns.nullableAnyType else it.type) }.toTypedArray()
|
||||
val fieldTypes = fields.map { getLLVMType(if (it.isDelegated) context.builtIns.nullableAnyType else it.type) }
|
||||
|
||||
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
|
||||
|
||||
memScoped {
|
||||
val fieldTypesNativeArrayPtr = allocArrayOf(*fieldTypes)[0].ptr
|
||||
LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0)
|
||||
}
|
||||
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, 0)
|
||||
|
||||
return classType
|
||||
}
|
||||
|
||||
|
||||
+13
-26
@@ -31,24 +31,15 @@ internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
||||
}
|
||||
|
||||
private class ConstGetElementPtr(val pointer: ConstPointer, val index: Int) : ConstPointer {
|
||||
override val llvm = memScoped {
|
||||
// TODO: squash multiple GEPs
|
||||
val indices = intArrayOf(0, index).map { Int32(it).llvm }
|
||||
val indicesArray = allocArrayOf(indices)
|
||||
LLVMConstInBoundsGEP(pointer.llvm, indicesArray[0].ptr, indices.size)!!
|
||||
}
|
||||
override val llvm = LLVMConstInBoundsGEP(pointer.llvm, cValuesOf(Int32(0).llvm, Int32(index).llvm), 2)!!
|
||||
// TODO: squash multiple GEPs
|
||||
}
|
||||
|
||||
internal fun ConstPointer.bitcast(toType: LLVMTypeRef) = constPointer(LLVMConstBitCast(this.llvm, toType)!!)
|
||||
|
||||
internal class ConstArray(val elemType: LLVMTypeRef?, val elements: List<ConstValue>) : ConstValue {
|
||||
|
||||
override val llvm = memScoped {
|
||||
val values = elements.map { it.llvm }.toTypedArray()
|
||||
|
||||
val valuesNativeArrayPtr = allocArrayOf(*values)[0].ptr
|
||||
LLVMConstArray(elemType, valuesNativeArrayPtr, values.size)!!
|
||||
}
|
||||
override val llvm = LLVMConstArray(elemType, elements.map { it.llvm }.toCValues(), elements.size)!!
|
||||
}
|
||||
|
||||
internal open class Struct(val type: LLVMTypeRef?, val elements: List<ConstValue>) : ConstValue {
|
||||
@@ -57,11 +48,7 @@ internal open class Struct(val type: LLVMTypeRef?, val elements: List<ConstValue
|
||||
|
||||
constructor(vararg elements: ConstValue) : this(structType(elements.map { it.llvmType }), *elements)
|
||||
|
||||
override val llvm = memScoped {
|
||||
val values = elements.map { it.llvm }.toTypedArray()
|
||||
val valuesNativeArrayPtr = allocArrayOf(*values)[0].ptr
|
||||
LLVMConstNamedStruct(type, valuesNativeArrayPtr, values.size)!!
|
||||
}
|
||||
override val llvm = LLVMConstNamedStruct(type, elements.map { it.llvm }.toCValues(), elements.size)!!
|
||||
}
|
||||
|
||||
internal class Int1(val value: Byte) : ConstValue {
|
||||
@@ -143,9 +130,8 @@ internal fun pointerType(pointeeType: LLVMTypeRef) = LLVMPointerType(pointeeType
|
||||
|
||||
internal fun structType(vararg types: LLVMTypeRef): LLVMTypeRef = structType(types.toList())
|
||||
|
||||
internal fun structType(types: List<LLVMTypeRef>): LLVMTypeRef = memScoped {
|
||||
LLVMStructType(allocArrayOf(types)[0].ptr, types.size, 0)!!
|
||||
}
|
||||
internal fun structType(types: List<LLVMTypeRef>): LLVMTypeRef =
|
||||
LLVMStructType(types.toCValues(), types.size, 0)!!
|
||||
|
||||
internal fun ContextUtils.numParameters(functionType: LLVMTypeRef) : Int {
|
||||
// Note that type is usually function pointer, so we have to dereference it.
|
||||
@@ -192,20 +178,21 @@ internal fun ContextUtils.externalGlobal(name: String, type: LLVMTypeRef): LLVMV
|
||||
}
|
||||
|
||||
internal fun functionType(returnType: LLVMTypeRef, isVarArg: Boolean = false, vararg paramTypes: LLVMTypeRef) =
|
||||
memScoped {
|
||||
val paramTypesPtr = allocArrayOf(*paramTypes)[0].ptr
|
||||
LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, if (isVarArg) 1 else 0)!!
|
||||
}
|
||||
LLVMFunctionType(
|
||||
returnType,
|
||||
cValuesOf(*paramTypes), paramTypes.size,
|
||||
if (isVarArg) 1 else 0
|
||||
)!!
|
||||
|
||||
|
||||
fun llvm2string(value: LLVMValueRef?): String {
|
||||
if (value == null) return "<null>"
|
||||
return LLVMPrintValueToString(value)!!.asCString().toString()
|
||||
return LLVMPrintValueToString(value)!!.toKString()
|
||||
}
|
||||
|
||||
fun llvmtype2string(type: LLVMTypeRef?): String {
|
||||
if (type == null) return "<null type>"
|
||||
return LLVMPrintTypeToString(type)!!.asCString().toString()
|
||||
return LLVMPrintTypeToString(type)!!.toKString()
|
||||
}
|
||||
|
||||
fun getStructElements(type: LLVMTypeRef): List<LLVMTypeRef> {
|
||||
|
||||
+3
-6
@@ -61,7 +61,7 @@ class MetadataReader(file: File) : Closeable {
|
||||
val errorRef = allocPointerTo<CInt8Var>()
|
||||
val res = LLVMCreateMemoryBufferWithContentsOfFile(file.toString(), bufRef.ptr, errorRef.ptr)
|
||||
if (res != 0) {
|
||||
throw Error(errorRef.value?.asCString()?.toString())
|
||||
throw Error(errorRef.value?.toKString())
|
||||
}
|
||||
|
||||
llvmContext = LLVMContextCreate()!!
|
||||
@@ -80,7 +80,7 @@ class MetadataReader(file: File) : Closeable {
|
||||
memScoped {
|
||||
val len = alloc<CInt32Var>()
|
||||
val str1 = LLVMGetMDString(node, len.ptr)!!
|
||||
val str = str1.asCString().toString()
|
||||
val str = str1.toKString()
|
||||
return str
|
||||
|
||||
}
|
||||
@@ -117,10 +117,7 @@ class MetadataReader(file: File) : Closeable {
|
||||
internal class MetadataGenerator(override val context: Context): ContextUtils {
|
||||
|
||||
private fun metadataNode(args: List<LLVMValueRef?>): LLVMValueRef {
|
||||
memScoped {
|
||||
val references = allocArrayOf(args)
|
||||
return LLVMMDNode(references[0].ptr, args.size)!!
|
||||
}
|
||||
return LLVMMDNode(args.toCValues(), args.size)!!
|
||||
}
|
||||
|
||||
private fun metadataFun(fn: LLVMValueRef, info: String): LLVMValueRef {
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ class Runtime(private val bitcodeFile: String) {
|
||||
|
||||
val res = LLVMCreateMemoryBufferWithContentsOfFile(bitcodeFile, bufRef.ptr, errorRef.ptr)
|
||||
if (res != 0) {
|
||||
throw Error(errorRef.value?.asCString()?.toString())
|
||||
throw Error(errorRef.value?.toKString())
|
||||
}
|
||||
|
||||
val moduleRef = alloc<LLVMModuleRefVar>()
|
||||
@@ -45,9 +45,9 @@ class Runtime(private val bitcodeFile: String) {
|
||||
val objHeaderType = getStructType("ObjHeader")
|
||||
val arrayHeaderType = getStructType("ArrayHeader")
|
||||
|
||||
val target = LLVMGetTarget(llvmModule)!!.asCString().toString()
|
||||
val target = LLVMGetTarget(llvmModule)!!.toKString()
|
||||
|
||||
val dataLayout = LLVMGetDataLayout(llvmModule)!!.asCString().toString()
|
||||
val dataLayout = LLVMGetDataLayout(llvmModule)!!.toKString()
|
||||
|
||||
val targetData = LLVMCreateTargetData(dataLayout)!!
|
||||
|
||||
|
||||
@@ -65,16 +65,9 @@ fun initialize() {
|
||||
// specify implementation-specific hints
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
|
||||
|
||||
memScoped {
|
||||
val ambLight: CArray<GLfloatVar> = allocArrayOf(0.1f, 0.1f, 0.1f, 1.0f)
|
||||
val diffuse: CArray<GLfloatVar> = allocArrayOf(0.6f, 0.6f, 0.6f, 1.0f)
|
||||
val specular: CArray<GLfloatVar> = allocArrayOf(0.7f, 0.7f, 0.3f, 1.0f)
|
||||
|
||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambLight[0].ptr)
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse[0].ptr)
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, specular[0].ptr)
|
||||
}
|
||||
|
||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, cValuesOf(0.1f, 0.1f, 0.1f, 1.0f))
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, cValuesOf(0.6f, 0.6f, 0.6f, 1.0f))
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, cValuesOf(0.7f, 0.7f, 0.3f, 1.0f))
|
||||
|
||||
glEnable(GL_LIGHT0)
|
||||
glEnable(GL_COLOR_MATERIAL)
|
||||
|
||||
Reference in New Issue
Block a user