[K/N] LLVM: Transition to opaque pointers
This commit is contained in:
committed by
Space Cloud
parent
c1f72de6e5
commit
b059754f64
+11
-4
@@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
import llvm.LLVMArrayType
|
import llvm.*
|
||||||
import llvm.LLVMConstInt
|
|
||||||
import llvm.LLVMTypeRef
|
|
||||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.ConstValue
|
import org.jetbrains.kotlin.backend.konan.llvm.ConstValue
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.StaticData
|
import org.jetbrains.kotlin.backend.konan.llvm.StaticData
|
||||||
@@ -183,7 +181,16 @@ internal fun IrConstantPrimitive.toBoxCacheValue(generationState: NativeGenerati
|
|||||||
val (start, end) = generationState.config.target.getBoxCacheRange(cacheType)
|
val (start, end) = generationState.config.target.getBoxCacheRange(cacheType)
|
||||||
return if (value in start..end) {
|
return if (value in start..end) {
|
||||||
generationState.llvm.let { llvm ->
|
generationState.llvm.let { llvm ->
|
||||||
llvm.boxCacheGlobals[cacheType]?.pointer?.getElementPtr(llvm, value.toInt() - start)?.getElementPtr(llvm, 0)
|
val llvmType = llvm.structType(llvm.runtime.objHeaderType, when (cacheType) {
|
||||||
|
BoxCache.BOOLEAN -> llvm.int1Type
|
||||||
|
BoxCache.BYTE -> llvm.int8Type
|
||||||
|
BoxCache.SHORT -> llvm.int16Type
|
||||||
|
BoxCache.CHAR -> llvm.int16Type
|
||||||
|
BoxCache.INT -> llvm.int32Type
|
||||||
|
BoxCache.LONG -> llvm.int64Type
|
||||||
|
})
|
||||||
|
val llvmArrayType = LLVMArrayType(llvmType, end - start + 1)!!
|
||||||
|
llvm.boxCacheGlobals[cacheType]?.pointer?.getElementPtr(llvm, llvmArrayType, value.toInt() - start)?.getElementPtr(llvm, llvmType, 0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|||||||
+2
-1
@@ -127,7 +127,8 @@ private class CallsChecker(generationState: NativeGenerationState, goodFunctions
|
|||||||
callSiteDescription = "$functionName (over objc_msgSendSuper2)"
|
callSiteDescription = "$functionName (over objc_msgSendSuper2)"
|
||||||
calledName = null
|
calledName = null
|
||||||
val superStruct = LLVMGetArgOperand(call, 0)
|
val superStruct = LLVMGetArgOperand(call, 0)
|
||||||
val superClassPtrPtr = LLVMBuildGEP(builder, superStruct, listOf(llvm.int32(0), llvm.int32(1)).toCValues(), 2, "")
|
val superStructType = llvm.structType(llvm.int8PtrType, llvm.int8PtrType)
|
||||||
|
val superClassPtrPtr = LLVMBuildStructGEP2(builder, superStructType, superStruct, 1, "")
|
||||||
val superClassPtr = LLVMBuildLoad2(builder, llvm.int8PtrType, superClassPtrPtr, "")!!
|
val superClassPtr = LLVMBuildLoad2(builder, llvm.int8PtrType, superClassPtrPtr, "")!!
|
||||||
val classPtr = getSuperClass.buildCall(builder, listOf(superClassPtr))
|
val classPtr = getSuperClass.buildCall(builder, listOf(superClassPtr))
|
||||||
val calledPtrLlvmFunPtr = getMethodImpl.buildCall(builder, listOf(classPtr, LLVMGetArgOperand(call, 1)!!))
|
val calledPtrLlvmFunPtr = getMethodImpl.buildCall(builder, listOf(classPtr, LLVMGetArgOperand(call, 1)!!))
|
||||||
|
|||||||
+2
-1
@@ -148,7 +148,8 @@ internal fun insertAliasToEntryPoint(context: PhaseContext, module: LLVMModuleRe
|
|||||||
val entryPointName = config.entryPointName
|
val entryPointName = config.entryPointName
|
||||||
val entryPoint = LLVMGetNamedFunction(module, entryPointName)
|
val entryPoint = LLVMGetNamedFunction(module, entryPointName)
|
||||||
?: error("Module doesn't contain `$entryPointName`")
|
?: error("Module doesn't contain `$entryPointName`")
|
||||||
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
|
val programAddressSpace = LLVMGetProgramAddressSpace(module)
|
||||||
|
LLVMAddAlias2(module, getGlobalFunctionType(entryPoint), programAddressSpace, entryPoint, "main")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun linkBitcodeDependencies(generationState: NativeGenerationState,
|
internal fun linkBitcodeDependencies(generationState: NativeGenerationState,
|
||||||
|
|||||||
+30
-26
@@ -209,13 +209,13 @@ private inline fun <T : FunctionGenerationContext> generateFunctionBody(
|
|||||||
internal object VirtualTablesLookup {
|
internal object VirtualTablesLookup {
|
||||||
private fun FunctionGenerationContext.getInterfaceTableRecord(typeInfo: LLVMValueRef, interfaceId: Int): LLVMValueRef {
|
private fun FunctionGenerationContext.getInterfaceTableRecord(typeInfo: LLVMValueRef, interfaceId: Int): LLVMValueRef {
|
||||||
val interfaceTableRecordPtrType = pointerType(runtime.interfaceTableRecordType)
|
val interfaceTableRecordPtrType = pointerType(runtime.interfaceTableRecordType)
|
||||||
val interfaceTableSize = load(llvm.int32Type, structGep(typeInfo, 9 /* interfaceTableSize_ */))
|
val interfaceTableSize = load(llvm.int32Type, structGep(runtime.typeInfoType, typeInfo, 9 /* interfaceTableSize_ */))
|
||||||
val interfaceTable = load(interfaceTableRecordPtrType, structGep(typeInfo, 10 /* interfaceTable_ */))
|
val interfaceTable = load(interfaceTableRecordPtrType, structGep(runtime.typeInfoType, typeInfo, 10 /* interfaceTable_ */))
|
||||||
|
|
||||||
fun fastPath(): LLVMValueRef {
|
fun fastPath(): LLVMValueRef {
|
||||||
// The fastest optimistic version.
|
// The fastest optimistic version.
|
||||||
val interfaceTableIndex = and(interfaceTableSize, llvm.int32(interfaceId))
|
val interfaceTableIndex = and(interfaceTableSize, llvm.int32(interfaceId))
|
||||||
return gep(interfaceTable, interfaceTableIndex)
|
return gep(runtime.interfaceTableRecordType, interfaceTable, interfaceTableIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See details in ClassLayoutBuilder.
|
// See details in ClassLayoutBuilder.
|
||||||
@@ -260,7 +260,7 @@ internal object VirtualTablesLookup {
|
|||||||
// Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId
|
// Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId
|
||||||
val interfaceId = dstHierarchyInfo.interfaceId
|
val interfaceId = dstHierarchyInfo.interfaceId
|
||||||
val interfaceTableRecord = getInterfaceTableRecord(objTypeInfo, interfaceId)
|
val interfaceTableRecord = getInterfaceTableRecord(objTypeInfo, interfaceId)
|
||||||
icmpEq(load(llvm.int32Type, structGep(interfaceTableRecord, 0 /* id */)), llvm.int32(interfaceId))
|
icmpEq(load(llvm.int32Type, structGep(runtime.interfaceTableRecordType, interfaceTableRecord, 0 /* id */)), llvm.int32(interfaceId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,14 +278,15 @@ internal object VirtualTablesLookup {
|
|||||||
val canCallViaVtable = !owner.isInterface
|
val canCallViaVtable = !owner.isInterface
|
||||||
val layoutBuilder = generationState.context.getLayoutBuilder(owner)
|
val layoutBuilder = generationState.context.getLayoutBuilder(owner)
|
||||||
|
|
||||||
val functionPtrType = pointerType(codegen.getLlvmFunctionType(irFunction))
|
val functionType = codegen.getLlvmFunctionType(irFunction)
|
||||||
|
val functionPtrType = pointerType(functionType)
|
||||||
val functionPtrPtrType = pointerType(functionPtrType)
|
val functionPtrPtrType = pointerType(functionPtrType)
|
||||||
val llvmMethod = when {
|
val llvmMethod = when {
|
||||||
canCallViaVtable -> {
|
canCallViaVtable -> {
|
||||||
val index = layoutBuilder.vtableIndex(irFunction)
|
val index = layoutBuilder.vtableIndex(irFunction)
|
||||||
val vtablePlace = gep(typeInfoPtr, llvm.int32(1)) // typeInfoPtr + 1
|
val vtablePlace = gep(runtime.typeInfoType, typeInfoPtr, llvm.int32(1)) // typeInfoPtr + 1
|
||||||
val vtable = bitcast(llvm.int8PtrPtrType, vtablePlace)
|
val vtable = bitcast(llvm.int8PtrPtrType, vtablePlace)
|
||||||
val slot = gep(vtable, llvm.int32(index))
|
val slot = gep(llvm.int8PtrType, vtable, llvm.int32(index))
|
||||||
load(functionPtrType, bitcast(functionPtrPtrType, slot))
|
load(functionPtrType, bitcast(functionPtrPtrType, slot))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,12 +294,13 @@ internal object VirtualTablesLookup {
|
|||||||
// Essentially: typeInfo.itable[place(interfaceId)].vtable[method]
|
// Essentially: typeInfo.itable[place(interfaceId)].vtable[method]
|
||||||
val itablePlace = layoutBuilder.itablePlace(irFunction)
|
val itablePlace = layoutBuilder.itablePlace(irFunction)
|
||||||
val interfaceTableRecord = getInterfaceTableRecord(typeInfoPtr, itablePlace.interfaceId)
|
val interfaceTableRecord = getInterfaceTableRecord(typeInfoPtr, itablePlace.interfaceId)
|
||||||
val vtable = load(llvm.int8PtrPtrType, structGep(interfaceTableRecord, 2 /* vtable */))
|
val vtable = load(llvm.int8PtrPtrType, structGep(runtime.interfaceTableRecordType, interfaceTableRecord, 2 /* vtable */))
|
||||||
val slot = gep(vtable, llvm.int32(itablePlace.methodIndex))
|
val slot = gep(llvm.int8PtrType, vtable, llvm.int32(itablePlace.methodIndex))
|
||||||
load(functionPtrType, bitcast(functionPtrPtrType, slot))
|
load(functionPtrType, bitcast(functionPtrPtrType, slot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LlvmCallable(
|
return LlvmCallable(
|
||||||
|
functionType,
|
||||||
bitcast(functionPtrType, llvmMethod),
|
bitcast(functionPtrType, llvmMethod),
|
||||||
LlvmFunctionSignature(irFunction, this)
|
LlvmFunctionSignature(irFunction, this)
|
||||||
)
|
)
|
||||||
@@ -418,7 +420,7 @@ internal class StackLocalsManagerImpl(
|
|||||||
|
|
||||||
memset(bitcast(llvm.int8PtrType, stackSlot), 0, LLVMSizeOfTypeInBits(codegen.llvmTargetData, type).toInt() / 8)
|
memset(bitcast(llvm.int8PtrType, stackSlot), 0, LLVMSizeOfTypeInBits(codegen.llvmTargetData, type).toInt() / 8)
|
||||||
|
|
||||||
val objectHeader = structGep(stackSlot, 0, "objHeader")
|
val objectHeader = structGep(type, stackSlot, 0, "objHeader")
|
||||||
val typeInfo = codegen.typeInfoForAllocation(irClass)
|
val typeInfo = codegen.typeInfoForAllocation(irClass)
|
||||||
setTypeInfoForLocalObject(objectHeader, typeInfo)
|
setTypeInfoForLocalObject(objectHeader, typeInfo)
|
||||||
val gcRootSetSlot = createRootSetSlot()
|
val gcRootSetSlot = createRootSetSlot()
|
||||||
@@ -472,12 +474,12 @@ internal class StackLocalsManagerImpl(
|
|||||||
val typeInfo = codegen.typeInfoValue(irClass)
|
val typeInfo = codegen.typeInfoValue(irClass)
|
||||||
val arraySlot = LLVMBuildAlloca(builder, arrayType, "")!!
|
val arraySlot = LLVMBuildAlloca(builder, arrayType, "")!!
|
||||||
// Set array size in ArrayHeader.
|
// Set array size in ArrayHeader.
|
||||||
val arrayHeaderSlot = structGep(arraySlot, 0, "arrayHeader")
|
val arrayHeaderSlot = structGep(arrayType, arraySlot, 0, "arrayHeader")
|
||||||
setTypeInfoForLocalObject(arrayHeaderSlot, typeInfo)
|
setTypeInfoForLocalObject(arrayHeaderSlot, typeInfo)
|
||||||
val sizeField = structGep(arrayHeaderSlot, 1, "count_")
|
val sizeField = structGep(runtime.arrayHeaderType, arrayHeaderSlot, 1, "count_")
|
||||||
store(count, sizeField)
|
store(count, sizeField)
|
||||||
|
|
||||||
memset(bitcast(llvm.int8PtrType, structGep(arraySlot, 1, "arrayBody")),
|
memset(bitcast(llvm.int8PtrType, structGep(arrayType, arraySlot, 1, "arrayBody")),
|
||||||
0,
|
0,
|
||||||
constCount * LLVMSizeOfTypeInBits(codegen.llvmTargetData, arrayToElementType[irClass.symbol]).toInt() / 8
|
constCount * LLVMSizeOfTypeInBits(codegen.llvmTargetData, arrayToElementType[irClass.symbol]).toInt() / 8
|
||||||
)
|
)
|
||||||
@@ -503,9 +505,10 @@ internal class StackLocalsManagerImpl(
|
|||||||
if (stackLocal.irClass.symbol == context.ir.symbols.array) {
|
if (stackLocal.irClass.symbol == context.ir.symbols.array) {
|
||||||
call(llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
|
call(llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
|
||||||
} else if (!refsOnly) {
|
} else if (!refsOnly) {
|
||||||
memset(bitcast(llvm.int8PtrType, structGep(stackLocal.stackAllocationPtr, 1, "arrayBody")),
|
val arrayType = localArrayType(stackLocal.irClass, stackLocal.arraySize!!)
|
||||||
|
memset(bitcast(llvm.int8PtrType, structGep(arrayType, stackLocal.stackAllocationPtr, 1, "arrayBody")),
|
||||||
0,
|
0,
|
||||||
stackLocal.arraySize!! * LLVMSizeOfTypeInBits(codegen.llvmTargetData, arrayToElementType[stackLocal.irClass.symbol]).toInt() / 8
|
stackLocal.arraySize * LLVMSizeOfTypeInBits(codegen.llvmTargetData, arrayToElementType[stackLocal.irClass.symbol]).toInt() / 8
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -515,7 +518,7 @@ internal class StackLocalsManagerImpl(
|
|||||||
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
|
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
|
||||||
|
|
||||||
if (isObjectType(fieldType)) {
|
if (isObjectType(fieldType)) {
|
||||||
val fieldPtr = LLVMBuildStructGEP(builder, stackLocal.stackAllocationPtr, fieldIndex, "")!!
|
val fieldPtr = structGep(type, stackLocal.stackAllocationPtr, fieldIndex, "")
|
||||||
if (refsOnly)
|
if (refsOnly)
|
||||||
storeHeapRef(kNullObjHeaderPtr, fieldPtr)
|
storeHeapRef(kNullObjHeaderPtr, fieldPtr)
|
||||||
else
|
else
|
||||||
@@ -538,7 +541,7 @@ internal class StackLocalsManagerImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setTypeInfoForLocalObject(objectHeader: LLVMValueRef, typeInfoPointer: LLVMValueRef) = with(functionGenerationContext) {
|
private fun setTypeInfoForLocalObject(objectHeader: LLVMValueRef, typeInfoPointer: LLVMValueRef) = with(functionGenerationContext) {
|
||||||
val typeInfo = structGep(objectHeader, 0, "typeInfoOrMeta_")
|
val typeInfo = structGep(runtime.objHeaderType, objectHeader, 0, "typeInfoOrMeta_")
|
||||||
// Set tag OBJECT_TAG_PERMANENT_CONTAINER | OBJECT_TAG_NONTRIVIAL_CONTAINER.
|
// Set tag OBJECT_TAG_PERMANENT_CONTAINER | OBJECT_TAG_NONTRIVIAL_CONTAINER.
|
||||||
val typeInfoValue = intToPtr(or(ptrToInt(typeInfoPointer, codegen.intPtrType),
|
val typeInfoValue = intToPtr(or(ptrToInt(typeInfoPointer, codegen.intPtrType),
|
||||||
codegen.immThreeIntPtrType), kTypeInfoPtr)
|
codegen.immThreeIntPtrType), kTypeInfoPtr)
|
||||||
@@ -681,7 +684,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
fun alloca(type: LLVMTypeRef?, name: String = "", variableLocation: VariableDebugLocation? = null): LLVMValueRef {
|
fun alloca(type: LLVMTypeRef?, name: String = "", variableLocation: VariableDebugLocation? = null): LLVMValueRef {
|
||||||
if (isObjectType(type!!)) {
|
if (isObjectType(type!!)) {
|
||||||
appendingTo(localsInitBb) {
|
appendingTo(localsInitBb) {
|
||||||
val slotAddress = gep(slotsPhi!!, llvm.int32(slotCount), name)
|
val slotAddress = gep(type, slotsPhi!!, llvm.int32(slotCount), name)
|
||||||
variableLocation?.let {
|
variableLocation?.let {
|
||||||
slotToVariableLocation[slotCount] = it
|
slotToVariableLocation[slotCount] = it
|
||||||
}
|
}
|
||||||
@@ -1036,11 +1039,12 @@ internal abstract class FunctionGenerationContext(
|
|||||||
|
|
||||||
fun intToPtr(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, value, DestTy, Name)!!
|
fun intToPtr(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, value, DestTy, Name)!!
|
||||||
fun ptrToInt(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildPtrToInt(builder, value, DestTy, Name)!!
|
fun ptrToInt(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildPtrToInt(builder, value, DestTy, Name)!!
|
||||||
fun gep(base: LLVMValueRef, index: LLVMValueRef, name: String = ""): LLVMValueRef {
|
|
||||||
return LLVMBuildGEP(builder, base, cValuesOf(index), 1, name)!!
|
fun gep(type: LLVMTypeRef, base: LLVMValueRef, index: LLVMValueRef, name: String = ""): LLVMValueRef =
|
||||||
}
|
LLVMBuildGEP2(builder, type, base, cValuesOf(index), 1, name)!!
|
||||||
fun structGep(base: LLVMValueRef, index: Int, name: String = ""): LLVMValueRef =
|
|
||||||
LLVMBuildStructGEP(builder, base, index, name)!!
|
fun structGep(type: LLVMTypeRef, base: LLVMValueRef, index: Int, name: String = ""): LLVMValueRef =
|
||||||
|
LLVMBuildStructGEP2(builder, type, base, index, name)!!
|
||||||
|
|
||||||
fun extractValue(aggregate: LLVMValueRef, index: Int, name: String = ""): LLVMValueRef =
|
fun extractValue(aggregate: LLVMValueRef, index: Int, name: String = ""): LLVMValueRef =
|
||||||
LLVMBuildExtractValue(builder, aggregate, index, name)!!
|
LLVMBuildExtractValue(builder, aggregate, index, name)!!
|
||||||
@@ -1276,7 +1280,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun loadTypeInfo(objPtr: LLVMValueRef): LLVMValueRef {
|
fun loadTypeInfo(objPtr: LLVMValueRef): LLVMValueRef {
|
||||||
val typeInfoOrMetaPtr = structGep(objPtr, 0 /* typeInfoOrMeta_ */)
|
val typeInfoOrMetaPtr = structGep(runtime.objHeaderType, objPtr, 0 /* typeInfoOrMeta_ */)
|
||||||
|
|
||||||
val memoryOrder = if (context.config.targetHasAddressDependency) {
|
val memoryOrder = if (context.config.targetHasAddressDependency) {
|
||||||
/**
|
/**
|
||||||
@@ -1294,7 +1298,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
// Clear two lower bits.
|
// Clear two lower bits.
|
||||||
val typeInfoOrMetaRaw = and(typeInfoOrMetaWithFlags, codegen.immTypeInfoMask)
|
val typeInfoOrMetaRaw = and(typeInfoOrMetaWithFlags, codegen.immTypeInfoMask)
|
||||||
val typeInfoOrMeta = intToPtr(typeInfoOrMetaRaw, kTypeInfoPtr)
|
val typeInfoOrMeta = intToPtr(typeInfoOrMetaRaw, kTypeInfoPtr)
|
||||||
val typeInfoPtrPtr = structGep(typeInfoOrMeta, 0 /* typeInfo */)
|
val typeInfoPtrPtr = structGep(runtime.typeInfoType, typeInfoOrMeta, 0 /* typeInfo */)
|
||||||
return load(codegen.kTypeInfoPtr, typeInfoPtrPtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic)
|
return load(codegen.kTypeInfoPtr, typeInfoPtrPtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1345,7 +1349,7 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val classInfo = codegen.kotlinObjCClassInfo(irClass)
|
val classInfo = codegen.kotlinObjCClassInfo(irClass)
|
||||||
val classPointerGlobal = load(llvm.int8PtrPtrType, structGep(classInfo, KotlinObjCClassInfoGenerator.createdClassFieldIndex))
|
val classPointerGlobal = load(llvm.int8PtrPtrType, structGep(runtime.kotlinObjCClassInfo, classInfo, KotlinObjCClassInfoGenerator.createdClassFieldIndex))
|
||||||
|
|
||||||
val storedClass = this.load(llvm.int8PtrType, classPointerGlobal)
|
val storedClass = this.load(llvm.int8PtrType, classPointerGlobal)
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -327,12 +327,12 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
|
|||||||
|
|
||||||
val attributesCopier = LlvmFunctionAttributeProvider.copyFromExternal(externalFunction)
|
val attributesCopier = LlvmFunctionAttributeProvider.copyFromExternal(externalFunction)
|
||||||
|
|
||||||
val functionType = getFunctionType(externalFunction)
|
val functionType = getGlobalFunctionType(externalFunction)
|
||||||
val function = LLVMAddFunction(module, name, functionType)!!
|
val function = LLVMAddFunction(module, name, functionType)!!
|
||||||
|
|
||||||
attributesCopier.addFunctionAttributes(function)
|
attributesCopier.addFunctionAttributes(function)
|
||||||
|
|
||||||
return LlvmCallable(function, attributesCopier)
|
return LlvmCallable(functionType, function, attributesCopier)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun importGlobal(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
|
private fun importGlobal(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
|
||||||
@@ -358,7 +358,7 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
|
|||||||
val kindId = getLlvmAttributeKindId(it)
|
val kindId = getLlvmAttributeKindId(it)
|
||||||
addLlvmFunctionEnumAttribute(result, kindId)
|
addLlvmFunctionEnumAttribute(result, kindId)
|
||||||
}
|
}
|
||||||
return LlvmCallable(result, LlvmFunctionAttributeProvider.copyFromExternal(result))
|
return LlvmCallable(type, result, LlvmFunctionAttributeProvider.copyFromExternal(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable {
|
internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable {
|
||||||
@@ -367,12 +367,13 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS
|
|||||||
}
|
}
|
||||||
val found = LLVMGetNamedFunction(module, llvmFunctionProto.name)
|
val found = LLVMGetNamedFunction(module, llvmFunctionProto.name)
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
require(getFunctionType(found) == llvmFunctionProto.signature.llvmFunctionType) {
|
require(getGlobalFunctionType(found) == llvmFunctionProto.signature.llvmFunctionType) {
|
||||||
"Expected: ${LLVMPrintTypeToString(llvmFunctionProto.signature.llvmFunctionType)!!.toKString()} " +
|
"Expected: ${LLVMPrintTypeToString(llvmFunctionProto.signature.llvmFunctionType)!!.toKString()} " +
|
||||||
"found: ${LLVMPrintTypeToString(getFunctionType(found))!!.toKString()}"
|
"found: ${LLVMPrintTypeToString(getGlobalFunctionType(found))!!.toKString()}"
|
||||||
}
|
}
|
||||||
require(LLVMGetLinkage(found) == llvmFunctionProto.linkage)
|
require(LLVMGetLinkage(found) == llvmFunctionProto.linkage)
|
||||||
return LlvmCallable(found, llvmFunctionProto.signature)
|
val functionType = getGlobalFunctionType(found)
|
||||||
|
return LlvmCallable(functionType, found, llvmFunctionProto.signature)
|
||||||
} else {
|
} else {
|
||||||
return llvmFunctionProto.createLlvmFunction(context, module)
|
return llvmFunctionProto.createLlvmFunction(context, module)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -1,6 +1,5 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.llvm
|
package org.jetbrains.kotlin.backend.konan.llvm
|
||||||
|
|
||||||
import kotlinx.cinterop.cValuesOf
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||||
import org.jetbrains.kotlin.backend.konan.MemoryModel
|
import org.jetbrains.kotlin.backend.konan.MemoryModel
|
||||||
@@ -447,7 +446,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
llvm.kNullInt8Ptr
|
llvm.kNullInt8Ptr
|
||||||
|
|
||||||
private fun FunctionGenerationContext.emitNativePtrPlusLong(args: List<LLVMValueRef>): LLVMValueRef =
|
private fun FunctionGenerationContext.emitNativePtrPlusLong(args: List<LLVMValueRef>): LLVMValueRef =
|
||||||
gep(args[0], args[1])
|
gep(llvm.int8Type, args[0], args[1])
|
||||||
|
|
||||||
private fun FunctionGenerationContext.emitNativePtrToLong(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
private fun FunctionGenerationContext.emitNativePtrToLong(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||||
val intPtrValue = ptrToInt(args.single(), codegen.intPtrType)
|
val intPtrValue = ptrToInt(args.single(), codegen.intPtrType)
|
||||||
@@ -508,7 +507,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum
|
val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum
|
||||||
val bitsWithPaddingType = LLVMIntTypeInContext(llvm.llvmContext, bitsWithPaddingNum)!!
|
val bitsWithPaddingType = LLVMIntTypeInContext(llvm.llvmContext, bitsWithPaddingNum)!!
|
||||||
|
|
||||||
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, llvm.int64(offset / 8)))
|
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(llvm.int8Type, ptr, llvm.int64(offset / 8)))
|
||||||
val bitsWithPadding = load(bitsWithPaddingType, bitsWithPaddingPtr).setUnaligned()
|
val bitsWithPadding = load(bitsWithPaddingType, bitsWithPaddingPtr).setUnaligned()
|
||||||
|
|
||||||
val bits = shr(
|
val bits = shr(
|
||||||
@@ -551,7 +550,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
|
|
||||||
val preservedBitsMask = LLVMConstNot(discardBitsMask)!!
|
val preservedBitsMask = LLVMConstNot(discardBitsMask)!!
|
||||||
|
|
||||||
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, llvm.int64(offset / 8)))
|
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(llvm.int8Type, ptr, llvm.int64(offset / 8)))
|
||||||
|
|
||||||
val bits = trunc(value, bitsType)
|
val bits = trunc(value, bitsType)
|
||||||
|
|
||||||
@@ -581,8 +580,8 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
|
|
||||||
val structType = llvm.structType(llvm.int8PtrType, llvm.int8PtrType)
|
val structType = llvm.structType(llvm.int8PtrType, llvm.int8PtrType)
|
||||||
val ptr = alloca(structType)
|
val ptr = alloca(structType)
|
||||||
store(receiver, LLVMBuildGEP(builder, ptr, cValuesOf(llvm.kImmInt32Zero, llvm.kImmInt32Zero), 2, "")!!)
|
store(receiver, structGep(structType, ptr, 0, ""))
|
||||||
store(superClass, LLVMBuildGEP(builder, ptr, cValuesOf(llvm.kImmInt32Zero, llvm.kImmInt32One), 2, "")!!)
|
store(superClass, structGep(structType, ptr, 1, ""))
|
||||||
return bitcast(llvm.int8PtrType, ptr)
|
return bitcast(llvm.int8PtrType, ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -11,8 +11,12 @@ import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
|
|
||||||
private fun ConstPointer.add(index: LLVMValueRef): ConstPointer {
|
private fun ConstPointer.addBits(llvm: CodegenLlvmHelpers, type: LLVMTypeRef, bits: Int): ConstPointer {
|
||||||
return constPointer(LLVMConstGEP(llvm, cValuesOf(index), 1)!!)
|
val rawPtr = LLVMConstBitCast(this.llvm, llvm.int8PtrType)
|
||||||
|
// Only pointer arithmetic via GEP works on constant pointers in LLVM.
|
||||||
|
val withBits = LLVMConstGEP2(llvm.int8Type, rawPtr, cValuesOf(llvm.int32(bits)), 1)!!
|
||||||
|
val withType = LLVMConstBitCast(withBits, type)!!
|
||||||
|
return constPointer(withType)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: CodegenLlvmHelpers, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) {
|
internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: CodegenLlvmHelpers, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) {
|
||||||
@@ -20,8 +24,7 @@ internal class KotlinStaticData(override val generationState: NativeGenerationSt
|
|||||||
|
|
||||||
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
|
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
|
||||||
private fun permanentTag(typeInfo: ConstPointer): ConstPointer {
|
private fun permanentTag(typeInfo: ConstPointer): ConstPointer {
|
||||||
// Only pointer arithmetic via GEP works on constant pointers in LLVM.
|
return typeInfo.addBits(llvm, kTypeInfoPtr, 1)
|
||||||
return typeInfo.bitcast(llvm.int8PtrType).add(llvm.int32(1)).bitcast(kTypeInfoPtr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -58,7 +61,7 @@ internal class KotlinStaticData(override val generationState: NativeGenerationSt
|
|||||||
|
|
||||||
val global = this.createGlobal(compositeType, "")
|
val global = this.createGlobal(compositeType, "")
|
||||||
|
|
||||||
val objHeaderPtr = global.pointer.getElementPtr(llvm, 0)
|
val objHeaderPtr = global.pointer.getElementPtr(llvm, compositeType, 0)
|
||||||
val arrayHeader = arrayHeader(typeInfo, elements.size)
|
val arrayHeader = arrayHeader(typeInfo, elements.size)
|
||||||
|
|
||||||
global.setInitializer(Struct(compositeType, arrayHeader, arrayBody))
|
global.setInitializer(Struct(compositeType, arrayHeader, arrayBody))
|
||||||
@@ -73,7 +76,7 @@ internal class KotlinStaticData(override val generationState: NativeGenerationSt
|
|||||||
global.setUnnamedAddr(true)
|
global.setUnnamedAddr(true)
|
||||||
global.setConstant(true)
|
global.setConstant(true)
|
||||||
|
|
||||||
val objHeaderPtr = global.pointer.getElementPtr(llvm, 0)
|
val objHeaderPtr = global.pointer.bitcast(llvm.runtime.objHeaderPtrType)
|
||||||
|
|
||||||
return createRef(objHeaderPtr)
|
return createRef(objHeaderPtr)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-10
@@ -14,7 +14,7 @@ import llvm.*
|
|||||||
* @todo This class mixes "something that can be called" and function abstractions.
|
* @todo This class mixes "something that can be called" and function abstractions.
|
||||||
* Some of it's methods make sense only for functions. Probably, LlvmFunction sub-class should be extracted.
|
* Some of it's methods make sense only for functions. Probably, LlvmFunction sub-class should be extracted.
|
||||||
*/
|
*/
|
||||||
class LlvmCallable(private val llvmValue: LLVMValueRef, private val attributeProvider: LlvmFunctionAttributeProvider) {
|
class LlvmCallable(val functionType: LLVMTypeRef, private val llvmValue: LLVMValueRef, private val attributeProvider: LlvmFunctionAttributeProvider) {
|
||||||
val returnType: LLVMTypeRef by lazy {
|
val returnType: LLVMTypeRef by lazy {
|
||||||
LLVMGetReturnType(functionType)!!
|
LLVMGetReturnType(functionType)!!
|
||||||
}
|
}
|
||||||
@@ -23,12 +23,8 @@ class LlvmCallable(private val llvmValue: LLVMValueRef, private val attributePro
|
|||||||
llvmValue.name
|
llvmValue.name
|
||||||
}
|
}
|
||||||
|
|
||||||
val functionType: LLVMTypeRef by lazy {
|
|
||||||
getFunctionType(llvmValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
val numParams by lazy {
|
val numParams by lazy {
|
||||||
LLVMCountParams(llvmValue)
|
LLVMCountParamTypes(functionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
val pgoFunctionNameVar by lazy {
|
val pgoFunctionNameVar by lazy {
|
||||||
@@ -40,12 +36,12 @@ class LlvmCallable(private val llvmValue: LLVMValueRef, private val attributePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun buildCall(builder: LLVMBuilderRef, args: List<LLVMValueRef>, name: String = "") =
|
fun buildCall(builder: LLVMBuilderRef, args: List<LLVMValueRef>, name: String = "") =
|
||||||
LLVMBuildCall(builder, llvmValue, args.toCValues(), args.size, name)!!.also {
|
LLVMBuildCall2(builder, functionType, llvmValue, args.toCValues(), args.size, name)!!.also {
|
||||||
attributeProvider.addCallSiteAttributes(it)
|
attributeProvider.addCallSiteAttributes(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildInvoke(builder: LLVMBuilderRef, args: List<LLVMValueRef>, success: LLVMBasicBlockRef, catch: LLVMBasicBlockRef, name: String = "") =
|
fun buildInvoke(builder: LLVMBuilderRef, args: List<LLVMValueRef>, success: LLVMBasicBlockRef, catch: LLVMBasicBlockRef, name: String = "") =
|
||||||
LLVMBuildInvoke(builder, llvmValue, args.toCValues(), args.size, success, catch, name)!!.also {
|
LLVMBuildInvoke2(builder, functionType, llvmValue, args.toCValues(), args.size, success, catch, name)!!.also {
|
||||||
attributeProvider.addCallSiteAttributes(it)
|
attributeProvider.addCallSiteAttributes(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -305,7 +305,7 @@ private class DeclarationsGeneratorVisitor(override val generationState: NativeG
|
|||||||
typeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage)
|
typeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage)
|
||||||
}
|
}
|
||||||
|
|
||||||
typeInfoPtr = typeInfoGlobal.pointer.getElementPtr(llvm, 0)
|
typeInfoPtr = typeInfoGlobal.pointer.getElementPtr(llvm, typeInfoWithVtableType, 0)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType,
|
typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType,
|
||||||
|
|||||||
+1
-1
@@ -178,7 +178,7 @@ internal class LlvmFunctionProto(
|
|||||||
addTargetCpuAndFeaturesAttributes(context, function)
|
addTargetCpuAndFeaturesAttributes(context, function)
|
||||||
signature.addFunctionAttributes(function)
|
signature.addFunctionAttributes(function)
|
||||||
LLVMSetLinkage(function, linkage)
|
LLVMSetLinkage(function, linkage)
|
||||||
return LlvmCallable(function, signature)
|
return LlvmCallable(signature.llvmFunctionType, function, signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-10
@@ -23,7 +23,8 @@ internal val ConstValue.llvmType: LLVMTypeRef
|
|||||||
get() = this.llvm.type
|
get() = this.llvm.type
|
||||||
|
|
||||||
internal interface ConstPointer : ConstValue {
|
internal interface ConstPointer : ConstValue {
|
||||||
fun getElementPtr(llvm: CodegenLlvmHelpers, index: Int): ConstPointer = ConstGetElementPtr(llvm, this, index)
|
fun getElementPtr(llvm: CodegenLlvmHelpers, pointeeType: LLVMTypeRef, index: Int): ConstPointer =
|
||||||
|
ConstGetElementPtr(llvm, pointeeType, this, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
||||||
@@ -34,8 +35,8 @@ internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
|||||||
override val llvm = value
|
override val llvm = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ConstGetElementPtr(llvm: CodegenLlvmHelpers, pointer: ConstPointer, index: Int) : ConstPointer {
|
private class ConstGetElementPtr(llvm: CodegenLlvmHelpers, pointeeType: LLVMTypeRef, pointer: ConstPointer, index: Int) : ConstPointer {
|
||||||
override val llvm = LLVMConstInBoundsGEP(pointer.llvm, cValuesOf(llvm.int32(0), llvm.int32(index)), 2)!!
|
override val llvm = LLVMConstInBoundsGEP2(pointeeType, pointer.llvm, cValuesOf(llvm.int32(0), llvm.int32(index)), 2)!!
|
||||||
// TODO: squash multiple GEPs
|
// TODO: squash multiple GEPs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,11 +117,6 @@ internal val RuntimeAware.kNothingFakeValue: LLVMValueRef
|
|||||||
|
|
||||||
internal fun pointerType(pointeeType: LLVMTypeRef) = LLVMPointerType(pointeeType, 0)!!
|
internal fun pointerType(pointeeType: LLVMTypeRef) = LLVMPointerType(pointeeType, 0)!!
|
||||||
|
|
||||||
internal fun ContextUtils.numParameters(functionType: LLVMTypeRef) : Int {
|
|
||||||
// Note that type is usually function pointer, so we have to dereference it.
|
|
||||||
return LLVMCountParamTypes(LLVMGetElementType(functionType))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun extractConstUnsignedInt(value: LLVMValueRef): Long {
|
fun extractConstUnsignedInt(value: LLVMValueRef): Long {
|
||||||
assert(LLVMIsConstant(value) != 0)
|
assert(LLVMIsConstant(value) != 0)
|
||||||
return LLVMConstIntGetZExtValue(value)
|
return LLVMConstIntGetZExtValue(value)
|
||||||
@@ -150,12 +146,12 @@ internal fun LLVMValueRef.getAsCString() : String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun getFunctionType(ptrToFunction: LLVMValueRef): LLVMTypeRef {
|
internal fun getGlobalFunctionType(ptrToFunction: LLVMValueRef): LLVMTypeRef {
|
||||||
return getGlobalType(ptrToFunction)
|
return getGlobalType(ptrToFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getGlobalType(ptrToGlobal: LLVMValueRef): LLVMTypeRef {
|
internal fun getGlobalType(ptrToGlobal: LLVMValueRef): LLVMTypeRef {
|
||||||
return LLVMGetElementType(ptrToGlobal.type)!!
|
return LLVMGlobalGetValueType(ptrToGlobal)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): LLVMValueRef {
|
internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): LLVMValueRef {
|
||||||
|
|||||||
+5
-4
@@ -404,7 +404,7 @@ internal class RTTIGenerator(
|
|||||||
private val debugOperations: ConstValue by lazy {
|
private val debugOperations: ConstValue by lazy {
|
||||||
if (debugRuntimeOrNull != null) {
|
if (debugRuntimeOrNull != null) {
|
||||||
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
|
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
|
||||||
val local = LLVMAddGlobal(llvm.module, LLVMGetElementType(LLVMTypeOf(external)),"Konan_debugOperationsList")!!
|
val local = LLVMAddGlobal(llvm.module, LLVMGlobalGetValueType(external),"Konan_debugOperationsList")!!
|
||||||
constPointer(LLVMConstBitCast(local, llvm.int8PtrPtrType)!!)
|
constPointer(LLVMConstBitCast(local, llvm.int8PtrPtrType)!!)
|
||||||
} else {
|
} else {
|
||||||
Zero(llvm.int8PtrPtrType)
|
Zero(llvm.int8PtrPtrType)
|
||||||
@@ -414,7 +414,7 @@ internal class RTTIGenerator(
|
|||||||
val debugOperationsSize: ConstValue by lazy {
|
val debugOperationsSize: ConstValue by lazy {
|
||||||
if (debugRuntimeOrNull != null) {
|
if (debugRuntimeOrNull != null) {
|
||||||
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
|
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
|
||||||
llvm.constInt32(LLVMGetArrayLength(LLVMGetElementType(LLVMTypeOf(external))))
|
llvm.constInt32(LLVMGetArrayLength(LLVMGlobalGetValueType(external)))
|
||||||
} else
|
} else
|
||||||
llvm.constInt32(0)
|
llvm.constInt32(0)
|
||||||
}
|
}
|
||||||
@@ -531,7 +531,7 @@ internal class RTTIGenerator(
|
|||||||
val vtable = vtable(superClass)
|
val vtable = vtable(superClass)
|
||||||
val typeInfoWithVtableType = llvm.structType(runtime.typeInfoType, vtable.llvmType)
|
val typeInfoWithVtableType = llvm.structType(runtime.typeInfoType, vtable.llvmType)
|
||||||
val typeInfoWithVtableGlobal = staticData.createGlobal(typeInfoWithVtableType, "", isExported = false)
|
val typeInfoWithVtableGlobal = staticData.createGlobal(typeInfoWithVtableType, "", isExported = false)
|
||||||
val result = typeInfoWithVtableGlobal.pointer.getElementPtr(llvm, 0)
|
val result = typeInfoWithVtableGlobal.pointer.getElementPtr(llvm, typeInfoWithVtableType, 0)
|
||||||
val typeHierarchyInfo = if (!context.ghaEnabled())
|
val typeHierarchyInfo = if (!context.ghaEnabled())
|
||||||
ClassGlobalHierarchyInfo.DUMMY
|
ClassGlobalHierarchyInfo.DUMMY
|
||||||
else
|
else
|
||||||
@@ -546,10 +546,11 @@ internal class RTTIGenerator(
|
|||||||
} else {
|
} else {
|
||||||
val vtableEntries = layoutBuilder.interfaceVTableEntries.map { methodImpls[it]!!.bitcast(llvm.int8PtrType) }
|
val vtableEntries = layoutBuilder.interfaceVTableEntries.map { methodImpls[it]!!.bitcast(llvm.int8PtrType) }
|
||||||
val interfaceVTable = staticData.placeGlobalArray("", llvm.int8PtrType, vtableEntries)
|
val interfaceVTable = staticData.placeGlobalArray("", llvm.int8PtrType, vtableEntries)
|
||||||
|
val interfaceVTableType = LLVMArrayType(llvm.int8PtrType, vtableEntries.size)!!
|
||||||
InterfaceTableRecord(
|
InterfaceTableRecord(
|
||||||
llvm.constInt32(layoutBuilder.classId),
|
llvm.constInt32(layoutBuilder.classId),
|
||||||
llvm.constInt32(layoutBuilder.interfaceVTableEntries.size),
|
llvm.constInt32(layoutBuilder.interfaceVTableEntries.size),
|
||||||
interfaceVTable.pointer.getElementPtr(llvm, 0)
|
interfaceVTable.pointer.getElementPtr(llvm, interfaceVTableType, 0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -142,7 +142,7 @@ internal open class StaticData(val module: LLVMModuleRef, private val llvm: Code
|
|||||||
if (elements.isNotEmpty() || isExported) {
|
if (elements.isNotEmpty() || isExported) {
|
||||||
val global = placeGlobalArray(name, elemType, elements, isExported)
|
val global = placeGlobalArray(name, elemType, elements, isExported)
|
||||||
global.setConstant(true)
|
global.setConstant(true)
|
||||||
return global.pointer.getElementPtr(llvm, 0)
|
return global.pointer.getElementPtr(llvm, LLVMArrayType(elemType, elements.size)!!, 0)
|
||||||
} else {
|
} else {
|
||||||
return NullPointer(elemType)
|
return NullPointer(elemType)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-5
@@ -4,11 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.kotlin.backend.konan.llvm.coverage
|
package org.jetbrains.kotlin.backend.konan.llvm.coverage
|
||||||
|
|
||||||
import llvm.LLVMConstBitCast
|
import llvm.*
|
||||||
import llvm.LLVMCreatePGOFunctionNameVar
|
|
||||||
import llvm.LLVMInstrProfIncrement
|
|
||||||
import llvm.LLVMValueRef
|
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
|
||||||
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
@@ -31,6 +27,7 @@ internal class LLVMCoverageInstrumentation(
|
|||||||
private val instrProfIncrement by lazy {
|
private val instrProfIncrement by lazy {
|
||||||
val incrementFun = LLVMInstrProfIncrement(llvm.module)!!
|
val incrementFun = LLVMInstrProfIncrement(llvm.module)!!
|
||||||
LlvmCallable(
|
LlvmCallable(
|
||||||
|
getGlobalFunctionType(incrementFun),
|
||||||
incrementFun,
|
incrementFun,
|
||||||
LlvmFunctionAttributeProvider.copyFromExternal(incrementFun)
|
LlvmFunctionAttributeProvider.copyFromExternal(incrementFun)
|
||||||
)
|
)
|
||||||
|
|||||||
+10
-11
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm.objc
|
|||||||
|
|
||||||
import kotlinx.cinterop.signExtend
|
import kotlinx.cinterop.signExtend
|
||||||
import kotlinx.cinterop.toCValues
|
import kotlinx.cinterop.toCValues
|
||||||
import llvm.LLVMGetElementType
|
import llvm.*
|
||||||
import llvm.LLVMGetInlineAsm
|
|
||||||
import llvm.LLVMInlineAsmDialect
|
|
||||||
import llvm.LLVMValueRef
|
|
||||||
import org.jetbrains.kotlin.backend.konan.getARCRetainAutoreleasedReturnValueMarker
|
import org.jetbrains.kotlin.backend.konan.getARCRetainAutoreleasedReturnValueMarker
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
|
|
||||||
@@ -79,16 +76,18 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this doesn't support stret.
|
// TODO: this doesn't support stret.
|
||||||
fun msgSender(functionType: LlvmFunctionSignature): LlvmCallable =
|
fun msgSender(functionType: LlvmFunctionSignature): LlvmCallable {
|
||||||
LlvmCallable(
|
val llvmType = functionType.llvmFunctionType
|
||||||
objcMsgSend.bitcast(pointerType(functionType.llvmFunctionType)).llvm,
|
return LlvmCallable(
|
||||||
functionType
|
llvmType,
|
||||||
)
|
objcMsgSend.bitcast(pointerType(llvmType)).llvm,
|
||||||
|
functionType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun FunctionGenerationContext.genObjCSelector(selector: String): LLVMValueRef {
|
internal fun FunctionGenerationContext.genObjCSelector(selector: String): LLVMValueRef {
|
||||||
val selectorRef = codegen.objCDataGenerator!!.genSelectorRef(selector)
|
val selectorRef = codegen.objCDataGenerator!!.genSelectorRef(selector).llvm
|
||||||
// TODO: clang emits it with `invariant.load` metadata.
|
// TODO: clang emits it with `invariant.load` metadata.
|
||||||
// TODO: Propagate the type here without using the typed pointer.
|
// TODO: Propagate the type here without using the typed pointer.
|
||||||
return load(LLVMGetElementType(selectorRef.llvmType)!!, selectorRef.llvm)
|
return load(LLVMGlobalGetValueType(selectorRef)!!, selectorRef)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -254,7 +254,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
|
|||||||
fun get(value: String) = literals.getOrPut(value) {
|
fun get(value: String) = literals.getOrPut(value) {
|
||||||
val globalPointer = generator.generate(llvm.module, llvm, value)
|
val globalPointer = generator.generate(llvm.module, llvm, value)
|
||||||
llvm.compilerUsedGlobals += globalPointer.llvm
|
llvm.compilerUsedGlobals += globalPointer.llvm
|
||||||
globalPointer.getElementPtr(llvm, 0)
|
globalPointer.bitcast(llvm.int8PtrType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -203,7 +203,7 @@ private fun patchLiteral(
|
|||||||
) {
|
) {
|
||||||
val module = LLVMGetGlobalParent(global)!!
|
val module = LLVMGetGlobalParent(global)!!
|
||||||
|
|
||||||
val newFirstCharPtr = generator.generate(module, llvm, newValue).getElementPtr(llvm, 0).llvm
|
val newFirstCharPtr = generator.generate(module, llvm, newValue).bitcast(llvm.int8PtrType).llvm
|
||||||
|
|
||||||
generateSequence(LLVMGetFirstUse(global), { LLVMGetNextUse(it) }).forEach { use ->
|
generateSequence(LLVMGetFirstUse(global), { LLVMGetNextUse(it) }).forEach { use ->
|
||||||
val firstCharPtr = LLVMGetUser(use)!!.also {
|
val firstCharPtr = LLVMGetUser(use)!!.also {
|
||||||
|
|||||||
+13
-12
@@ -41,7 +41,7 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
|||||||
val thisRef = param(0)
|
val thisRef = param(0)
|
||||||
val associatedObjectHolder = if (useSeparateHolder) {
|
val associatedObjectHolder = if (useSeparateHolder) {
|
||||||
val bodyPtr = bitcast(pointerType(bodyType), thisRef)
|
val bodyPtr = bitcast(pointerType(bodyType), thisRef)
|
||||||
loadSlot(codegen.kObjHeaderPtr, structGep(bodyPtr, 1), isVar = false)
|
loadSlot(codegen.kObjHeaderPtr, structGep(bodyType, bodyPtr, 1), isVar = false)
|
||||||
} else {
|
} else {
|
||||||
thisRef
|
thisRef
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
|||||||
retainedBlockPtr,
|
retainedBlockPtr,
|
||||||
Lifetime.ARGUMENT
|
Lifetime.ARGUMENT
|
||||||
)
|
)
|
||||||
storeHeapRef(holder, structGep(bodyPtr, 1))
|
storeHeapRef(holder, structGep(bodyType, bodyPtr, 1))
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
allocInstanceWithAssociatedObject(typeInfo, retainedBlockPtr, Lifetime.RETURN_VALUE)
|
allocInstanceWithAssociatedObject(typeInfo, retainedBlockPtr, Lifetime.RETURN_VALUE)
|
||||||
@@ -123,11 +123,12 @@ private fun FunctionGenerationContext.loadBlockInvoke(
|
|||||||
blockPtr: LLVMValueRef,
|
blockPtr: LLVMValueRef,
|
||||||
bridge: BlockPointerBridge
|
bridge: BlockPointerBridge
|
||||||
): LlvmCallable {
|
): LlvmCallable {
|
||||||
val invokePtr = structGep(bitcast(pointerType(codegen.runtime.blockLiteralType), blockPtr), 3)
|
val invokePtr = structGep(codegen.runtime.blockLiteralType, bitcast(pointerType(codegen.runtime.blockLiteralType), blockPtr), 3)
|
||||||
val signature = bridge.blockType.toBlockInvokeLlvmType(llvm)
|
val signature = bridge.blockType.toBlockInvokeLlvmType(llvm)
|
||||||
val functionPointerType = pointerType(signature.llvmFunctionType)
|
val functionType = signature.llvmFunctionType
|
||||||
|
val functionPointerType = pointerType(functionType)
|
||||||
val functionPointer = load(functionPointerType, bitcast(pointerType(functionPointerType), invokePtr))
|
val functionPointer = load(functionPointerType, bitcast(pointerType(functionPointerType), invokePtr))
|
||||||
return LlvmCallable(functionPointer, signature)
|
return LlvmCallable(functionType, functionPointer, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
|
private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
|
||||||
@@ -180,7 +181,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
|||||||
switchToRunnable = true
|
switchToRunnable = true
|
||||||
) {
|
) {
|
||||||
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
||||||
val refHolder = structGep(blockPtr, 1)
|
val refHolder = structGep(blockLiteralType, blockPtr, 1)
|
||||||
call(llvm.kRefSharedHolderDispose, listOf(refHolder))
|
call(llvm.kRefSharedHolderDispose, listOf(refHolder))
|
||||||
|
|
||||||
ret(null)
|
ret(null)
|
||||||
@@ -200,10 +201,10 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
|||||||
copyProto,
|
copyProto,
|
||||||
) {
|
) {
|
||||||
val dstBlockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
val dstBlockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
||||||
val dstRefHolder = structGep(dstBlockPtr, 1)
|
val dstRefHolder = structGep(blockLiteralType, dstBlockPtr, 1)
|
||||||
|
|
||||||
val srcBlockPtr = bitcast(pointerType(blockLiteralType), param(1))
|
val srcBlockPtr = bitcast(pointerType(blockLiteralType), param(1))
|
||||||
val srcRefHolder = structGep(srcBlockPtr, 1)
|
val srcRefHolder = structGep(blockLiteralType, srcBlockPtr, 1)
|
||||||
|
|
||||||
// Note: in current implementation copy helper is invoked only for stack-allocated blocks from the same thread,
|
// Note: in current implementation copy helper is invoked only for stack-allocated blocks from the same thread,
|
||||||
// so it is technically not necessary to check owner.
|
// so it is technically not necessary to check owner.
|
||||||
@@ -267,7 +268,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
|||||||
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
||||||
val kotlinObject = call(
|
val kotlinObject = call(
|
||||||
llvm.kRefSharedHolderRef,
|
llvm.kRefSharedHolderRef,
|
||||||
listOf(structGep(blockPtr, 1)),
|
listOf(structGep(blockLiteralType, blockPtr, 1)),
|
||||||
exceptionHandler = ExceptionHandler.Caller,
|
exceptionHandler = ExceptionHandler.Caller,
|
||||||
verbatim = true
|
verbatim = true
|
||||||
)
|
)
|
||||||
@@ -335,13 +336,13 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
|||||||
val descriptor = blockDescriptor.llvmGlobal
|
val descriptor = blockDescriptor.llvmGlobal
|
||||||
|
|
||||||
val blockOnStack = alloca(blockLiteralType)
|
val blockOnStack = alloca(blockLiteralType)
|
||||||
val blockOnStackBase = structGep(blockOnStack, 0)
|
val blockOnStackBase = structGep(blockLiteralType, blockOnStack, 0)
|
||||||
val refHolder = structGep(blockOnStack, 1)
|
val refHolder = structGep(blockLiteralType, blockOnStack, 1)
|
||||||
|
|
||||||
listOf(bitcast(llvm.int8PtrType, isa), flags, reserved, invoke, descriptor).forEachIndexed { index, value ->
|
listOf(bitcast(llvm.int8PtrType, isa), flags, reserved, invoke, descriptor).forEachIndexed { index, value ->
|
||||||
// Although value is actually on the stack, it's not in normal slot area, so we cannot handle it
|
// Although value is actually on the stack, it's not in normal slot area, so we cannot handle it
|
||||||
// as if it was on the stack.
|
// as if it was on the stack.
|
||||||
store(value, structGep(blockOnStackBase, index))
|
store(value, structGep(codegen.runtime.blockLiteralType, blockOnStackBase, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
call(llvm.kRefSharedHolderInitLocal, listOf(refHolder, kotlinRef))
|
call(llvm.kRefSharedHolderInitLocal, listOf(refHolder, kotlinRef))
|
||||||
|
|||||||
+10
-7
@@ -177,13 +177,13 @@ internal fun ObjCExportFunctionGenerationContext.callAndMaybeRetainAutoreleased(
|
|||||||
forbidRuntime = true // Don't emit safe points, frame management etc.
|
forbidRuntime = true // Don't emit safe points, frame management etc.
|
||||||
|
|
||||||
val actualArgs = signature.parameterTypes.indices.map { param(it) }
|
val actualArgs = signature.parameterTypes.indices.map { param(it) }
|
||||||
val actualCallable = if (functionIsPassedAsLastParameter) LlvmCallable(param(signature.parameterTypes.size), signature) else function
|
val actualCallable = if (functionIsPassedAsLastParameter) LlvmCallable(signature.llvmFunctionType, param(signature.parameterTypes.size), signature) else function
|
||||||
|
|
||||||
// Use LLVMBuildCall instead of call, because the latter enforces using exception handler, which is exactly what we have to avoid.
|
// Use LLVMBuildCall instead of call, because the latter enforces using exception handler, which is exactly what we have to avoid.
|
||||||
val result = actualCallable.buildCall(builder, actualArgs).let { callResult ->
|
val result = actualCallable.buildCall(builder, actualArgs).let { callResult ->
|
||||||
// Simplified version of emitAutoreleasedReturnValueMarker in Clang:
|
// Simplified version of emitAutoreleasedReturnValueMarker in Clang:
|
||||||
objCExportCodegen.objcRetainAutoreleasedReturnValueMarker?.let {
|
objCExportCodegen.objcRetainAutoreleasedReturnValueMarker?.let {
|
||||||
LLVMBuildCall(arg0 = builder, Fn = it, Args = null, NumArgs = 0, Name = "")
|
LLVMBuildCall2(arg0 = builder, functionType(llvm.voidType), Fn = it, Args = null, NumArgs = 0, Name = "")
|
||||||
}
|
}
|
||||||
|
|
||||||
call(objCExportCodegen.objcRetainAutoreleasedReturnValue, listOf(callResult)).also {
|
call(objCExportCodegen.objcRetainAutoreleasedReturnValue, listOf(callResult)).also {
|
||||||
@@ -217,8 +217,9 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
|
|||||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT
|
resultLifetime: Lifetime = Lifetime.IRRELEVANT
|
||||||
): LLVMValueRef {
|
): LLVMValueRef {
|
||||||
val llvmDeclarations = LlvmCallable(
|
val llvmDeclarations = LlvmCallable(
|
||||||
llvmFunction,
|
getGlobalFunctionType(llvmFunction),
|
||||||
// llvmFunction could be a function pointer here, and we can't infer attributes from it.
|
// llvmFunction could be a function pointer here, and we can't infer attributes from it.
|
||||||
|
llvmFunction,
|
||||||
LlvmFunctionAttributeProvider.makeEmpty()
|
LlvmFunctionAttributeProvider.makeEmpty()
|
||||||
)
|
)
|
||||||
return callFromBridge(llvmDeclarations, args, resultLifetime)
|
return callFromBridge(llvmDeclarations, args, resultLifetime)
|
||||||
@@ -831,11 +832,12 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
|
|||||||
} ?: NullPointer(objCToKotlinFunctionType)
|
} ?: NullPointer(objCToKotlinFunctionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val type = pointerType(objCToKotlinFunctionType)
|
||||||
val ptr = staticData.placeGlobalArray(
|
val ptr = staticData.placeGlobalArray(
|
||||||
"",
|
"",
|
||||||
pointerType(objCToKotlinFunctionType),
|
type,
|
||||||
converters
|
converters
|
||||||
).pointer.getElementPtr(llvm, 0)
|
).pointer.getElementPtr(llvm, LLVMArrayType(type, converters.size)!!, 0)
|
||||||
|
|
||||||
// Note: defining globals declared in runtime.
|
// Note: defining globals declared in runtime.
|
||||||
staticData.placeGlobal("Kotlin_ObjCExport_blockToFunctionConverters", ptr, isExported = true)
|
staticData.placeGlobal("Kotlin_ObjCExport_blockToFunctionConverters", ptr, isExported = true)
|
||||||
@@ -1628,9 +1630,10 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val vtable = if (!irClass.isInterface && !irClass.typeInfoHasVtableAttached) {
|
val vtable = if (!irClass.isInterface && !irClass.typeInfoHasVtableAttached) {
|
||||||
staticData.placeGlobal("", rttiGenerator.vtable(irClass)).also {
|
val table = rttiGenerator.vtable(irClass)
|
||||||
|
staticData.placeGlobal("", table).also {
|
||||||
it.setConstant(true)
|
it.setConstant(true)
|
||||||
}.pointer.getElementPtr(llvm, 0)
|
}.pointer.getElementPtr(llvm, LLVMArrayType(llvm.int8PtrType, table.elements.size)!!, 0)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ excludedFunctions = LLVMInitializeAllAsmParsers LLVMInitializeAllAsmPrinters LLV
|
|||||||
LLVMX86FP80Type LLVMFP128Type LLVMPPCFP128Type LLVMX86MMXType LLVMStructType LLVMVoidType LLVMLabelType \
|
LLVMX86FP80Type LLVMFP128Type LLVMPPCFP128Type LLVMX86MMXType LLVMStructType LLVMVoidType LLVMLabelType \
|
||||||
LLVMMDString LLVMMDNode LLVMConstString LLVMConstStruct LLVMAppendBasicBlock LLVMInsertBasicBlock LLVMCreateBuilder \
|
LLVMMDString LLVMMDNode LLVMConstString LLVMConstStruct LLVMAppendBasicBlock LLVMInsertBasicBlock LLVMCreateBuilder \
|
||||||
LLVMParseBitcode LLVMParseBitcode2 LLVMGetBitcodeModule LLVMGetBitcodeModule2 LLVMGetGlobalContext LLVMModuleCreateWithName \
|
LLVMParseBitcode LLVMParseBitcode2 LLVMGetBitcodeModule LLVMGetBitcodeModule2 LLVMGetGlobalContext LLVMModuleCreateWithName \
|
||||||
LLVMBuildLoad
|
LLVMBuildLoad LLVMBuildGEP LLVMBuildStructGEP LLVMConstGEP LLVMConstInBoundsGEP LLVMAddAlias LLVMBuildInvoke LLVMBuildCall \
|
||||||
|
LLVMGetElementType
|
||||||
|
|
||||||
strictEnums = LLVMIntPredicate LLVMOpcode LLVMDLLStorageClass LLVMCallConv LLVMThreadLocalMode LLVMAtomicOrdering
|
strictEnums = LLVMIntPredicate LLVMOpcode LLVMDLLStorageClass LLVMCallConv LLVMThreadLocalMode LLVMAtomicOrdering
|
||||||
|
|||||||
@@ -34,4 +34,9 @@ LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
|
|||||||
NumIndices);
|
NumIndices);
|
||||||
Constant *Val = unwrap<Constant>(ConstantVal);
|
Constant *Val = unwrap<Constant>(ConstantVal);
|
||||||
return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
|
return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned LLVMGetProgramAddressSpace(LLVMModuleRef moduleRef) {
|
||||||
|
auto module = unwrap(moduleRef);
|
||||||
|
return module ? module->getDataLayout().getProgramAddressSpace() : 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ LLVMValueRef LLVMAddAlias2(LLVMModuleRef M, LLVMTypeRef ValueTy,
|
|||||||
unsigned AddrSpace, LLVMValueRef Aliasee,
|
unsigned AddrSpace, LLVMValueRef Aliasee,
|
||||||
const char *Name);
|
const char *Name);
|
||||||
|
|
||||||
|
unsigned LLVMGetProgramAddressSpace(LLVMModuleRef moduleRef);
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
Reference in New Issue
Block a user