[K/N] Support volatile intrinsics on globals
Also, make intrinsics signature more consistent with other intrinsics, e.g. with isInitialized on lateinit field. ^KT-54944
This commit is contained in:
committed by
Space Team
parent
49d286e4e8
commit
6ab00a65dd
+37
-10
@@ -129,6 +129,8 @@ internal interface IntrinsicGeneratorEnvironment {
|
||||
fun evaluateExpression(value: IrExpression, resultSlot: LLVMValueRef?): LLVMValueRef
|
||||
|
||||
fun getObjectFieldPointer(thisRef: LLVMValueRef, field: IrField): LLVMValueRef
|
||||
|
||||
fun getStaticFieldPointer(field: IrField): LLVMValueRef
|
||||
}
|
||||
|
||||
internal fun tryGetIntrinsicType(callSite: IrFunctionAccessExpression): IntrinsicType? =
|
||||
@@ -320,17 +322,31 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
|
||||
private fun FunctionGenerationContext.emitCmpExchange(callSite: IrCall, args: List<LLVMValueRef>, mode: CmpExchangeMode, resultSlot: LLVMValueRef?): LLVMValueRef {
|
||||
val field = context.mapping.functionToVolatileField[callSite.symbol.owner]!!
|
||||
require(args.size == 3)
|
||||
val address = environment.getObjectFieldPointer(args[0], field)
|
||||
val address: LLVMValueRef
|
||||
val expected: LLVMValueRef
|
||||
val new: LLVMValueRef
|
||||
if (callSite.dispatchReceiver != null) {
|
||||
require(!field.isStatic)
|
||||
require(args.size == 3)
|
||||
address = environment.getObjectFieldPointer(args[0], field)
|
||||
expected = args[1]
|
||||
new = args[2]
|
||||
} else {
|
||||
require(field.isStatic)
|
||||
require(args.size == 2)
|
||||
address = environment.getStaticFieldPointer(field)
|
||||
expected = args[0]
|
||||
new = args[1]
|
||||
}
|
||||
return if (isObjectRef(args[1])) {
|
||||
require(context.memoryModel == MemoryModel.EXPERIMENTAL)
|
||||
when (mode) {
|
||||
CmpExchangeMode.SET -> call(llvm.CompareAndSetVolatileHeapRef, listOf(address, args[1], args[2]))
|
||||
CmpExchangeMode.SWAP -> call(llvm.CompareAndSwapVolatileHeapRef, listOf(address, args[1], args[2]),
|
||||
CmpExchangeMode.SET -> call(llvm.CompareAndSetVolatileHeapRef, listOf(address, expected, new))
|
||||
CmpExchangeMode.SWAP -> call(llvm.CompareAndSwapVolatileHeapRef, listOf(address, expected, new),
|
||||
environment.calculateLifetime(callSite), resultSlot = resultSlot)
|
||||
}
|
||||
} else {
|
||||
val cmp = LLVMBuildAtomicCmpXchg(builder, address, args[1], args[2],
|
||||
val cmp = LLVMBuildAtomicCmpXchg(builder, address, expected, new,
|
||||
LLVMAtomicOrdering.LLVMAtomicOrderingSequentiallyConsistent,
|
||||
LLVMAtomicOrdering.LLVMAtomicOrderingSequentiallyConsistent,
|
||||
SingleThread = 0
|
||||
@@ -342,15 +358,26 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
||||
|
||||
private fun FunctionGenerationContext.emitAtomicRMW(callSite: IrCall, args: List<LLVMValueRef>, op: LLVMAtomicRMWBinOp, resultSlot: LLVMValueRef?): LLVMValueRef {
|
||||
val field = context.mapping.functionToVolatileField[callSite.symbol.owner]!!
|
||||
require(args.size == 2)
|
||||
val address = environment.getObjectFieldPointer(args[0], field)
|
||||
return if (isObjectRef(args[1])) {
|
||||
val address: LLVMValueRef
|
||||
val value: LLVMValueRef
|
||||
if (callSite.dispatchReceiver != null) {
|
||||
require(!field.isStatic)
|
||||
require(args.size == 2)
|
||||
address = environment.getObjectFieldPointer(args[0], field)
|
||||
value = args[1]
|
||||
} else {
|
||||
require(field.isStatic)
|
||||
require(args.size == 1)
|
||||
address = environment.getStaticFieldPointer(field)
|
||||
value = args[0]
|
||||
}
|
||||
return if (isObjectRef(value)) {
|
||||
require(op == LLVMAtomicRMWBinOp.LLVMAtomicRMWBinOpXchg)
|
||||
require(context.memoryModel == MemoryModel.EXPERIMENTAL)
|
||||
call(llvm.GetAndSetVolatileHeapRef, listOf(address, args[1]),
|
||||
call(llvm.GetAndSetVolatileHeapRef, listOf(address, value),
|
||||
environment.calculateLifetime(callSite), resultSlot = resultSlot)
|
||||
} else {
|
||||
LLVMBuildAtomicRMW(builder, op, address, args[1],
|
||||
LLVMBuildAtomicRMW(builder, op, address, value,
|
||||
LLVMAtomicOrdering.LLVMAtomicOrderingSequentiallyConsistent,
|
||||
singleThread = 0
|
||||
)!!
|
||||
|
||||
+16
-16
@@ -231,6 +231,9 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
|
||||
override fun getObjectFieldPointer(thisRef: LLVMValueRef, field: IrField): LLVMValueRef =
|
||||
this@CodeGeneratorVisitor.fieldPtrOfClass(thisRef, field)
|
||||
|
||||
override fun getStaticFieldPointer(field: IrField) =
|
||||
this@CodeGeneratorVisitor.staticFieldPtr(field, functionGenerationContext)
|
||||
}
|
||||
|
||||
private val intrinsicGenerator = IntrinsicGenerator(intrinsicGeneratorEnvironment)
|
||||
@@ -339,12 +342,12 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
|
||||
private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) {
|
||||
val initializer = irField.initializer ?: return
|
||||
val address = generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
|
||||
val address = staticFieldPtr(irField, this)
|
||||
storeAny(evaluateExpression(initializer.expression), address, false)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.initGlobalField(irField: IrField) {
|
||||
val address = generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
|
||||
val address = staticFieldPtr(irField, this)
|
||||
val initialValue = if (irField.hasNonConstInitializer) {
|
||||
val initialization = evaluateExpression(irField.initializer!!.expression)
|
||||
if (irField.shouldBeFrozen(context))
|
||||
@@ -514,9 +517,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
// Only if a subject for memory management.
|
||||
.forEach { irField ->
|
||||
if (irField.type.binaryTypeIsReference() && irField.storageKind(context) != FieldStorageKind.THREAD_LOCAL) {
|
||||
val address = generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
|
||||
functionGenerationContext
|
||||
)
|
||||
val address = staticFieldPtr(irField, functionGenerationContext)
|
||||
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
||||
}
|
||||
}
|
||||
@@ -1685,12 +1686,8 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
if (context.config.threadsAreAllowed && value.symbol.owner.isGlobalNonPrimitive(context)) {
|
||||
functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler)
|
||||
}
|
||||
val info = generationState.llvmDeclarations
|
||||
.forStaticField(value.symbol.owner)
|
||||
fieldAddress = info
|
||||
.storageAddressAccess
|
||||
.getAddress(functionGenerationContext)
|
||||
alignment = info.alignment
|
||||
fieldAddress = staticFieldPtr(value.symbol.owner, functionGenerationContext)
|
||||
alignment = generationState.llvmDeclarations.forStaticField(value.symbol.owner).alignment
|
||||
}
|
||||
}
|
||||
return functionGenerationContext.loadSlot(
|
||||
@@ -1764,9 +1761,8 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler)
|
||||
if (value.symbol.owner.shouldBeFrozen(context) && value.origin != ObjectClassLowering.IrStatementOriginFieldPreInit)
|
||||
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
|
||||
val info = generationState.llvmDeclarations.forStaticField(value.symbol.owner)
|
||||
address = info.storageAddressAccess.getAddress(functionGenerationContext)
|
||||
alignment = info.alignment
|
||||
address = staticFieldPtr(value.symbol.owner, functionGenerationContext)
|
||||
alignment = generationState.llvmDeclarations.forStaticField(value.symbol.owner).alignment
|
||||
}
|
||||
functionGenerationContext.storeAny(
|
||||
valueToAssign, address, false,
|
||||
@@ -1778,8 +1774,6 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
private val vectorType = FqName("kotlin.native.Vector128").toUnsafe()
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
|
||||
val fieldInfo = generationState.llvmDeclarations.forField(value)
|
||||
@@ -1791,6 +1785,12 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
return fieldPtr!!
|
||||
}
|
||||
|
||||
private fun staticFieldPtr(value: IrField, context: FunctionGenerationContext) =
|
||||
generationState.llvmDeclarations
|
||||
.forStaticField(value.symbol.owner)
|
||||
.storageAddressAccess
|
||||
.getAddress(context)
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private fun evaluateStringConst(value: IrConst<String>) =
|
||||
llvm.staticData.kotlinStringLiteral(value.value)
|
||||
|
||||
+30
-12
@@ -51,12 +51,17 @@ internal class VolatileFieldsLowering(val context: Context) : FileLoweringPass {
|
||||
startOffset = irField.startOffset
|
||||
endOffset = irField.endOffset
|
||||
}.apply {
|
||||
val parentClass = irField.parents.filterIsInstance<IrClass>().first()
|
||||
parent = parentClass
|
||||
addDispatchReceiver {
|
||||
startOffset = irField.startOffset
|
||||
endOffset = irField.endOffset
|
||||
type = parentClass.defaultType
|
||||
val property = irField.correspondingPropertySymbol?.owner
|
||||
val scope = property?.parent
|
||||
require(scope != null)
|
||||
require(scope is IrClass || scope is IrFile)
|
||||
parent = scope
|
||||
if (scope is IrClass) {
|
||||
addDispatchReceiver {
|
||||
startOffset = irField.startOffset
|
||||
endOffset = irField.endOffset
|
||||
type = scope.defaultType
|
||||
}
|
||||
}
|
||||
builder()
|
||||
annotations += buildSimpleAnnotation(context.irBuiltIns,
|
||||
@@ -124,7 +129,18 @@ internal class VolatileFieldsLowering(val context: Context) : FileLoweringPass {
|
||||
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
declaration.transformChildrenVoid()
|
||||
declaration.declarations.transformFlat {
|
||||
processDeclarationList(declaration.declarations)
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitFile(declaration: IrFile): IrFile {
|
||||
declaration.transformChildrenVoid()
|
||||
processDeclarationList(declaration.declarations)
|
||||
return declaration
|
||||
}
|
||||
|
||||
private fun processDeclarationList(declarations: MutableList<IrDeclaration>) {
|
||||
declarations.transformFlat {
|
||||
when {
|
||||
it !is IrProperty -> null
|
||||
it.backingField?.hasAnnotation(KonanFqNames.volatile) != true -> null
|
||||
@@ -144,13 +160,15 @@ internal class VolatileFieldsLowering(val context: Context) : FileLoweringPass {
|
||||
}
|
||||
}
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField): IrStatement {
|
||||
if (declaration.type == irBuiltins.booleanType && declaration.hasAnnotation(KonanFqNames.volatile)) {
|
||||
convertedBooleanFields.add(declaration.symbol)
|
||||
declaration.type = irBuiltins.byteType
|
||||
declaration.initializer?.let {
|
||||
it.expression = context.createIrBuilder(declaration.symbol).at(it.expression).irBoolToByte(it.expression)
|
||||
}
|
||||
}
|
||||
return super.visitField(declaration)
|
||||
}
|
||||
@@ -189,7 +207,7 @@ internal class VolatileFieldsLowering(val context: Context) : FileLoweringPass {
|
||||
expression.transformChildrenVoid(this)
|
||||
val intrinsicType = tryGetIntrinsicType(expression).takeIf { it in intrinsicMap } ?: return expression
|
||||
builder.at(expression)
|
||||
val reference = expression.getValueArgument(0) as? IrPropertyReference
|
||||
val reference = expression.extensionReceiver as? IrPropertyReference
|
||||
?: return unsupported("Only compile-time known IrProperties supported for $intrinsicType")
|
||||
val property = reference.symbol.owner
|
||||
val backingField = property.backingField
|
||||
@@ -201,10 +219,10 @@ internal class VolatileFieldsLowering(val context: Context) : FileLoweringPass {
|
||||
}
|
||||
val function = intrinsicMap[intrinsicType]!!(backingField)
|
||||
return builder.irCall(function).apply {
|
||||
dispatchReceiver = expression.extensionReceiver
|
||||
putValueArgument(0, expression.getValueArgument(1))
|
||||
dispatchReceiver = reference.dispatchReceiver
|
||||
putValueArgument(0, expression.getValueArgument(0))
|
||||
if (intrinsicType == IntrinsicType.COMPARE_AND_SET_FIELD || intrinsicType == IntrinsicType.COMPARE_AND_SWAP_FIELD) {
|
||||
putValueArgument(1, expression.getValueArgument(2))
|
||||
putValueArgument(1, expression.getValueArgument(1))
|
||||
}
|
||||
}.let {
|
||||
if (backingField.requiresBooleanConversion()) {
|
||||
|
||||
Reference in New Issue
Block a user