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:
Svyatoslav Scherbina
2017-03-16 14:48:17 +07:00
committed by SvyatoslavScherbina
parent 7a876a3ccd
commit c9d8d4d57d
22 changed files with 2072 additions and 1557 deletions
@@ -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)
}
}
@@ -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 {
@@ -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()
}
}
@@ -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)
}
//-------------------------------------------------------------------------//
@@ -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
}
@@ -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> {
@@ -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 {
@@ -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)