[Native] Use LLVMBuildLoad2 instead of LLVMBuildLoad.

This is a first step in the move from typed to opaque pointers.
This commit is contained in:
Mads Ager
2023-09-29 13:32:16 +02:00
committed by Space Cloud
parent 847442d547
commit a487ec1889
6 changed files with 45 additions and 38 deletions
@@ -208,8 +208,9 @@ 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 interfaceTableSize = load(structGep(typeInfo, 9 /* interfaceTableSize_ */)) val interfaceTableRecordPtrType = pointerType(runtime.interfaceTableRecordType)
val interfaceTable = load(structGep(typeInfo, 10 /* interfaceTable_ */)) val interfaceTableSize = load(llvm.int32Type, structGep(typeInfo, 9 /* interfaceTableSize_ */))
val interfaceTable = load(interfaceTableRecordPtrType, structGep(typeInfo, 10 /* interfaceTable_ */))
fun fastPath(): LLVMValueRef { fun fastPath(): LLVMValueRef {
// The fastest optimistic version. // The fastest optimistic version.
@@ -231,7 +232,7 @@ internal object VirtualTablesLookup {
val takeResBB = basicBlock("take_res", startLocationInfo) val takeResBB = basicBlock("take_res", startLocationInfo)
condBr(icmpGe(interfaceTableSize, llvm.kImmInt32Zero), fastPathBB, slowPathBB) condBr(icmpGe(interfaceTableSize, llvm.kImmInt32Zero), fastPathBB, slowPathBB)
positionAtEnd(takeResBB) positionAtEnd(takeResBB)
val resultPhi = phi(pointerType(runtime.interfaceTableRecordType)) val resultPhi = phi(interfaceTableRecordPtrType)
appendingTo(fastPathBB) { appendingTo(fastPathBB) {
val fastValue = fastPath() val fastValue = fastPath()
br(takeResBB) br(takeResBB)
@@ -259,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(structGep(interfaceTableRecord, 0 /* id */)), llvm.int32(interfaceId)) icmpEq(load(llvm.int32Type, structGep(interfaceTableRecord, 0 /* id */)), llvm.int32(interfaceId))
} }
} }
@@ -277,23 +278,26 @@ 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 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(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(vtable, llvm.int32(index))
load(slot) load(functionPtrType, bitcast(functionPtrPtrType, slot))
} }
else -> { else -> {
// 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)
load(gep(load(structGep(interfaceTableRecord, 2 /* vtable */)), llvm.int32(itablePlace.methodIndex))) val vtable = load(llvm.int8PtrPtrType, structGep(interfaceTableRecord, 2 /* vtable */))
val slot = gep(vtable, llvm.int32(itablePlace.methodIndex))
load(functionPtrType, bitcast(functionPtrPtrType, slot))
} }
} }
val functionPtrType = pointerType(codegen.getLlvmFunctionType(irFunction))
return LlvmCallable( return LlvmCallable(
bitcast(functionPtrType, llvmMethod), bitcast(functionPtrType, llvmMethod),
LlvmFunctionSignature(irFunction, this) LlvmFunctionSignature(irFunction, this)
@@ -707,10 +711,7 @@ internal abstract class FunctionGenerationContext(
fun param(index: Int): LLVMValueRef = function.param(index) fun param(index: Int): LLVMValueRef = function.param(index)
fun load(address: LLVMValueRef, name: String = "", private fun applyMemoryOrderAndAlignment(value: LLVMValueRef, memoryOrder: LLVMAtomicOrdering?, alignment: Int?): LLVMValueRef {
memoryOrder: LLVMAtomicOrdering? = null, alignment: Int? = null
): LLVMValueRef {
val value = LLVMBuildLoad(builder, address, name)!!
memoryOrder?.let { LLVMSetOrdering(value, it) } memoryOrder?.let { LLVMSetOrdering(value, it) }
alignment?.let { LLVMSetAlignment(value, it) } alignment?.let { LLVMSetAlignment(value, it) }
// Use loadSlot() API for that. // Use loadSlot() API for that.
@@ -718,6 +719,12 @@ internal abstract class FunctionGenerationContext(
return value return value
} }
fun load(type: LLVMTypeRef, address: LLVMValueRef, name: String = "",
memoryOrder: LLVMAtomicOrdering? = null, alignment: Int? = null
): LLVMValueRef {
return applyMemoryOrderAndAlignment(LLVMBuildLoad2(builder, type, address, name)!!, memoryOrder, alignment)
}
fun loadSlot(address: LLVMValueRef, isVar: Boolean, resultSlot: LLVMValueRef? = null, name: String = "", fun loadSlot(address: LLVMValueRef, isVar: Boolean, resultSlot: LLVMValueRef? = null, name: String = "",
memoryOrder: LLVMAtomicOrdering? = null, alignment: Int? = null): LLVMValueRef { memoryOrder: LLVMAtomicOrdering? = null, alignment: Int? = null): LLVMValueRef {
val value = LLVMBuildLoad(builder, address, name)!! val value = LLVMBuildLoad(builder, address, name)!!
@@ -1274,13 +1281,14 @@ internal abstract class FunctionGenerationContext(
LLVMAtomicOrdering.LLVMAtomicOrderingAcquire LLVMAtomicOrdering.LLVMAtomicOrderingAcquire
} }
val typeInfoOrMetaWithFlags = load(typeInfoOrMetaPtr, memoryOrder = memoryOrder) // TODO: Get rid of the bitcast here by supplying the type in the GEP above.
val typeInfoOrMetaPtrRaw = bitcast(pointerType(codegen.intPtrType), typeInfoOrMetaPtr)
val typeInfoOrMetaWithFlags = load(codegen.intPtrType, typeInfoOrMetaPtrRaw, memoryOrder = memoryOrder)
// Clear two lower bits. // Clear two lower bits.
val typeInfoOrMetaWithFlagsRaw = ptrToInt(typeInfoOrMetaWithFlags, codegen.intPtrType) val typeInfoOrMetaRaw = and(typeInfoOrMetaWithFlags, codegen.immTypeInfoMask)
val typeInfoOrMetaRaw = and(typeInfoOrMetaWithFlagsRaw, codegen.immTypeInfoMask)
val typeInfoOrMeta = intToPtr(typeInfoOrMetaRaw, kTypeInfoPtr) val typeInfoOrMeta = intToPtr(typeInfoOrMetaRaw, kTypeInfoPtr)
val typeInfoPtrPtr = structGep(typeInfoOrMeta, 0 /* typeInfo */) val typeInfoPtrPtr = structGep(typeInfoOrMeta, 0 /* typeInfo */)
return load(typeInfoPtrPtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic) return load(codegen.kTypeInfoPtr, typeInfoPtrPtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic)
} }
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
@@ -1330,9 +1338,9 @@ internal abstract class FunctionGenerationContext(
} }
val classInfo = codegen.kotlinObjCClassInfo(irClass) val classInfo = codegen.kotlinObjCClassInfo(irClass)
val classPointerGlobal = load(structGep(classInfo, KotlinObjCClassInfoGenerator.createdClassFieldIndex)) val classPointerGlobal = load(llvm.int8PtrPtrType, structGep(classInfo, KotlinObjCClassInfoGenerator.createdClassFieldIndex))
val storedClass = this.load(classPointerGlobal) val storedClass = this.load(llvm.int8PtrType, classPointerGlobal)
val storedClassIsNotNull = this.icmpNe(storedClass, llvm.kNullInt8Ptr) val storedClassIsNotNull = this.icmpNe(storedClass, llvm.kNullInt8Ptr)
@@ -1346,7 +1354,7 @@ internal abstract class FunctionGenerationContext(
} }
} }
private fun getObjCClass(binaryName: String) = load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm) private fun getObjCClass(binaryName: String) = load(llvm.int8PtrType, codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef { fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef {
generationState.dependenciesTracker.addNativeRuntime() generationState.dependenciesTracker.addNativeRuntime()
@@ -480,7 +480,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
val pointerType = pointerType(callSite.llvmReturnType) val pointerType = pointerType(callSite.llvmReturnType)
val rawPointer = args.last() val rawPointer = args.last()
val pointer = bitcast(pointerType, rawPointer) val pointer = bitcast(pointerType, rawPointer)
return load(pointer) return load(callSite.llvmReturnType, pointer)
} }
private fun FunctionGenerationContext.emitWritePrimitive(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef { private fun FunctionGenerationContext.emitWritePrimitive(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
@@ -509,7 +509,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
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(ptr, llvm.int64(offset / 8)))
val bitsWithPadding = load(bitsWithPaddingPtr).setUnaligned() val bitsWithPadding = load(bitsWithPaddingType, bitsWithPaddingPtr).setUnaligned()
val bits = shr( val bits = shr(
shl(bitsWithPadding, suffixBitsNum), shl(bitsWithPadding, suffixBitsNum),
@@ -558,7 +558,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
val bitsToStore = if (prefixBitsNum == 0 && suffixBitsNum == 0) { val bitsToStore = if (prefixBitsNum == 0 && suffixBitsNum == 0) {
bits bits
} else { } else {
val previousValue = load(bitsWithPaddingPtr).setUnaligned() val previousValue = load(bitsWithPaddingType, bitsWithPaddingPtr).setUnaligned()
val preservedBits = and(previousValue, preservedBitsMask) val preservedBits = and(previousValue, preservedBitsMask)
val bitsWithPadding = shl(zext(bits, bitsWithPaddingType), prefixBitsNum) val bitsWithPadding = shl(zext(bits, bitsWithPaddingType), prefixBitsNum)
@@ -1873,11 +1873,9 @@ internal class CodeGeneratorVisitor(
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef { private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
val fieldInfo = generationState.llvmDeclarations.forField(value) val fieldInfo = generationState.llvmDeclarations.forField(value)
val classBodyType = fieldInfo.classBodyType
val typePtr = pointerType(fieldInfo.classBodyType) val typedBodyPtr = functionGenerationContext.bitcast(pointerType(classBodyType), thisPtr)
val fieldPtr = LLVMBuildStructGEP2(functionGenerationContext.builder, classBodyType, typedBodyPtr, fieldInfo.index, "")
val typedBodyPtr = functionGenerationContext.bitcast(typePtr, thisPtr)
val fieldPtr = LLVMBuildStructGEP(functionGenerationContext.builder, typedBodyPtr, fieldInfo.index, "")
return fieldPtr!! return fieldPtr!!
} }
@@ -2507,7 +2505,7 @@ internal class CodeGeneratorVisitor(
val bbExit = basicBlock("label_continue", null) val bbExit = basicBlock("label_continue", null)
moveBlockAfterEntry(bbExit) moveBlockAfterEntry(bbExit)
moveBlockAfterEntry(bbInit) moveBlockAfterEntry(bbInit)
val state = load(statePtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingAcquire) val state = load(llvm.int32Type, statePtr, memoryOrder = LLVMAtomicOrdering.LLVMAtomicOrderingAcquire)
condBr(icmpEq(state, llvm.int32(FILE_INITIALIZED)), bbExit, bbInit) condBr(icmpEq(state, llvm.int32(FILE_INITIALIZED)), bbExit, bbInit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
call(llvm.callInitGlobalPossiblyLock, listOf(statePtr, initializerPtr), call(llvm.callInitGlobalPossiblyLock, listOf(statePtr, initializerPtr),
@@ -2529,13 +2527,13 @@ internal class CodeGeneratorVisitor(
moveBlockAfterEntry(bbExit) moveBlockAfterEntry(bbExit)
moveBlockAfterEntry(bbCheckLocalState) moveBlockAfterEntry(bbCheckLocalState)
moveBlockAfterEntry(bbInit) moveBlockAfterEntry(bbInit)
val globalState = load(globalStatePtr) val globalState = load(llvm.int32Type, globalStatePtr)
LLVMSetVolatile(globalState, 1) LLVMSetVolatile(globalState, 1)
// Make sure we're not in the middle of global initializer invocation - // Make sure we're not in the middle of global initializer invocation -
// thread locals can be initialized only after all shared globals have been initialized. // thread locals can be initialized only after all shared globals have been initialized.
condBr(icmpNe(globalState, llvm.int32(FILE_INITIALIZED)), bbExit, bbCheckLocalState) condBr(icmpNe(globalState, llvm.int32(FILE_INITIALIZED)), bbExit, bbCheckLocalState)
positionAtEnd(bbCheckLocalState) positionAtEnd(bbCheckLocalState)
condBr(icmpNe(load(localStatePtr), llvm.int32(FILE_INITIALIZED)), bbInit, bbExit) condBr(icmpNe(load(llvm.int32Type, localStatePtr), llvm.int32(FILE_INITIALIZED)), bbInit, bbExit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
call(llvm.callInitThreadLocal, listOf(globalStatePtr, localStatePtr, initializerPtr), call(llvm.callInitThreadLocal, listOf(globalStatePtr, localStatePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler) exceptionHandler = currentCodeContext.exceptionHandler)
@@ -2553,7 +2551,7 @@ internal class CodeGeneratorVisitor(
val bbExit = basicBlock("label_continue", null) val bbExit = basicBlock("label_continue", null)
moveBlockAfterEntry(bbExit) moveBlockAfterEntry(bbExit)
moveBlockAfterEntry(bbInit) moveBlockAfterEntry(bbInit)
condBr(icmpEq(load(statePtr), llvm.int32(FILE_INITIALIZED)), bbExit, bbInit) condBr(icmpEq(load(llvm.int32Type, statePtr), llvm.int32(FILE_INITIALIZED)), bbExit, bbInit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
call(llvm.callInitThreadLocal, listOf(llvm.kNullInt32Ptr, statePtr, initializerPtr), call(llvm.callInitThreadLocal, listOf(llvm.kNullInt32Ptr, statePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler) exceptionHandler = currentCodeContext.exceptionHandler)
@@ -7,6 +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.LLVMGetInlineAsm import llvm.LLVMGetInlineAsm
import llvm.LLVMInlineAsmDialect import llvm.LLVMInlineAsmDialect
import llvm.LLVMValueRef import llvm.LLVMValueRef
@@ -24,7 +25,7 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
fun FunctionGenerationContext.genGetLinkedClass(name: String): LLVMValueRef { fun FunctionGenerationContext.genGetLinkedClass(name: String): LLVMValueRef {
val classRef = dataGenerator.genClassRef(name) val classRef = dataGenerator.genClassRef(name)
return load(classRef.llvm) return load(llvm.int8PtrType, classRef.llvm)
} }
private val objcMsgSend = llvm.externalNativeRuntimeFunction( private val objcMsgSend = llvm.externalNativeRuntimeFunction(
@@ -88,5 +89,6 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
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)
// TODO: clang emits it with `invariant.load` metadata. // TODO: clang emits it with `invariant.load` metadata.
return load(selectorRef.llvm) // TODO: Propagate the type here without using the typed pointer.
return load(LLVMGetElementType(selectorRef.llvmType)!!, selectorRef.llvm)
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.konan.llvm.objcexport package org.jetbrains.kotlin.backend.konan.llvm.objcexport
import llvm.LLVMLinkage import llvm.LLVMLinkage
import llvm.LLVMSetLinkage
import llvm.LLVMStoreSizeOfType import llvm.LLVMStoreSizeOfType
import llvm.LLVMValueRef import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
@@ -126,8 +125,9 @@ private fun FunctionGenerationContext.loadBlockInvoke(
): LlvmCallable { ): LlvmCallable {
val invokePtr = structGep(bitcast(pointerType(codegen.runtime.blockLiteralType), blockPtr), 3) val invokePtr = structGep(bitcast(pointerType(codegen.runtime.blockLiteralType), blockPtr), 3)
val signature = bridge.blockType.toBlockInvokeLlvmType(llvm) val signature = bridge.blockType.toBlockInvokeLlvmType(llvm)
val functionPointerType = pointerType(signature.llvmFunctionType)
return LlvmCallable(bitcast(pointerType(signature.llvmFunctionType), load(invokePtr)), signature) val functionPointer = load(functionPointerType, bitcast(pointerType(functionPointerType), invokePtr))
return LlvmCallable(functionPointer, signature)
} }
private fun FunctionGenerationContext.allocInstanceWithAssociatedObject( private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.backend.konan.llvm.objcexport package org.jetbrains.kotlin.backend.konan.llvm.objcexport
import kotlinx.cinterop.toCValues
import kotlinx.cinterop.toKString import kotlinx.cinterop.toKString
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
@@ -1287,7 +1286,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
assert(baseMethod.symbol !is IrConstructorSymbol) assert(baseMethod.symbol !is IrConstructorSymbol)
fun rethrow() { fun rethrow() {
val error = load(errorOutPtr!!) val error = load(llvm.int8PtrType, errorOutPtr!!)
val exception = callFromBridge( val exception = callFromBridge(
llvm.Kotlin_ObjCExport_NSErrorAsException, llvm.Kotlin_ObjCExport_NSErrorAsException,
listOf(error), listOf(error),
@@ -1326,7 +1325,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
is MethodBridge.ReturnValue.WithError.ZeroForError -> { is MethodBridge.ReturnValue.WithError.ZeroForError -> {
if (returnBridge.successMayBeZero) { if (returnBridge.successMayBeZero) {
val error = load(errorOutPtr!!) val error = load(llvm.int8PtrType, errorOutPtr!!)
ifThen(icmpNe(error, llvm.kNullInt8Ptr)) { ifThen(icmpNe(error, llvm.kNullInt8Ptr)) {
// error is not null, so targetResult should be null => no need for objc_release on it. // error is not null, so targetResult should be null => no need for objc_release on it.
rethrow() rethrow()