Use unaligned instructions for simd struct member access (#3596)
This commit is contained in:
+2
-3
@@ -318,13 +318,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
updateRef(value, ptr, onStack = true)
|
updateRef(value, ptr, onStack = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun storeAny(value: LLVMValueRef, ptr: LLVMValueRef, onStack: Boolean) {
|
fun storeAny(value: LLVMValueRef, ptr: LLVMValueRef, onStack: Boolean) = if (isObjectRef(value)) {
|
||||||
if (isObjectRef(value)) {
|
|
||||||
if (onStack) storeStackRef(value, ptr) else storeHeapRef(value, ptr)
|
if (onStack) storeStackRef(value, ptr) else storeHeapRef(value, ptr)
|
||||||
|
null
|
||||||
} else {
|
} else {
|
||||||
LLVMBuildStore(builder, value, ptr)
|
LLVMBuildStore(builder, value, ptr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun freeze(value: LLVMValueRef, exceptionHandler: ExceptionHandler) {
|
fun freeze(value: LLVMValueRef, exceptionHandler: ExceptionHandler) {
|
||||||
if (isObjectRef(value))
|
if (isObjectRef(value))
|
||||||
|
|||||||
+16
-6
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
@@ -1476,15 +1477,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
|
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
|
||||||
context.log{"evaluateGetField : ${ir2string(value)}"}
|
context.log { "evaluateGetField : ${ir2string(value)}" }
|
||||||
if (!value.symbol.owner.isStatic) {
|
return if (!value.symbol.owner.isStatic) {
|
||||||
val thisPtr = evaluateExpression(value.receiver!!)
|
val thisPtr = evaluateExpression(value.receiver!!)
|
||||||
return functionGenerationContext.loadSlot(
|
functionGenerationContext.loadSlot(
|
||||||
fieldPtrOfClass(thisPtr, value.symbol.owner), !value.symbol.owner.isFinal)
|
fieldPtrOfClass(thisPtr, value.symbol.owner), !value.symbol.owner.isFinal)
|
||||||
} else {
|
} else {
|
||||||
assert(value.receiver == null)
|
assert(value.receiver == null)
|
||||||
return if (value.symbol.owner.correspondingPropertySymbol?.owner?.isConst == true) {
|
if (value.symbol.owner.correspondingPropertySymbol?.owner?.isConst == true) {
|
||||||
evaluateConst(value.symbol.owner.initializer?.expression as IrConst<*>)
|
evaluateConst(value.symbol.owner.initializer?.expression as IrConst<*>)
|
||||||
} else {
|
} else {
|
||||||
if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive) {
|
if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive) {
|
||||||
functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler)
|
functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler)
|
||||||
@@ -1492,6 +1493,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
|
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
|
||||||
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal)
|
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal)
|
||||||
}
|
}
|
||||||
|
}.also {
|
||||||
|
if (value.type.classifierOrNull?.isClassWithFqName(vectorType) == true)
|
||||||
|
LLVMSetAlignment(it, 8)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1505,7 +1510,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
|
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
|
||||||
context.log{"evaluateSetField : ${ir2string(value)}"}
|
context.log{"evaluateSetField : ${ir2string(value)}"}
|
||||||
val valueToAssign = evaluateExpression(value.value)
|
val valueToAssign = evaluateExpression(value.value)
|
||||||
if (!value.symbol.owner.isStatic) {
|
val store = if (!value.symbol.owner.isStatic) {
|
||||||
val thisPtr = evaluateExpression(value.receiver!!)
|
val thisPtr = evaluateExpression(value.receiver!!)
|
||||||
assert(thisPtr.type == codegen.kObjHeaderPtr) {
|
assert(thisPtr.type == codegen.kObjHeaderPtr) {
|
||||||
LLVMPrintTypeToString(thisPtr.type)?.toKString().toString()
|
LLVMPrintTypeToString(thisPtr.type)?.toKString().toString()
|
||||||
@@ -1525,11 +1530,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
|
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
|
||||||
functionGenerationContext.storeAny(valueToAssign, globalValue, false)
|
functionGenerationContext.storeAny(valueToAssign, globalValue, false)
|
||||||
}
|
}
|
||||||
|
if (store != null && value.value.type.classifierOrNull?.isClassWithFqName(vectorType) == true) {
|
||||||
|
LLVMSetAlignment(store, 8)
|
||||||
|
}
|
||||||
|
|
||||||
assert (value.type.isUnit())
|
assert (value.type.isUnit())
|
||||||
return codegen.theUnitInstanceRef.llvm
|
return codegen.theUnitInstanceRef.llvm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val vectorType = FqName("kotlin.native.Vector128").toUnsafe()
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
|
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
|
||||||
val fieldInfo = context.llvmDeclarations.forField(value)
|
val fieldInfo = context.llvmDeclarations.forField(value)
|
||||||
|
|||||||
+3
-1
@@ -24,7 +24,9 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
|||||||
|
|
||||||
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record {
|
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record {
|
||||||
override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar)
|
override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar)
|
||||||
override fun store(value: LLVMValueRef) = functionGenerationContext.storeAny(value, address, true)
|
override fun store(value: LLVMValueRef) {
|
||||||
|
functionGenerationContext.storeAny(value, address, true)
|
||||||
|
}
|
||||||
override fun address() : LLVMValueRef = this.address
|
override fun address() : LLVMValueRef = this.address
|
||||||
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
|
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import kotlin.test.*
|
|||||||
|
|
||||||
|
|
||||||
@Test fun runTest() {
|
@Test fun runTest() {
|
||||||
|
testBoxingSimple()
|
||||||
|
testBoxing()
|
||||||
testSetGet()
|
testSetGet()
|
||||||
testString()
|
testString()
|
||||||
testOOB()
|
testOOB()
|
||||||
@@ -17,19 +19,42 @@ import kotlin.test.*
|
|||||||
testDefaultValue()
|
testDefaultValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Box<T>(t: T) {
|
||||||
|
var value = t
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnalignedC(t: Vector128) {
|
||||||
|
var smth = 1
|
||||||
|
var value = t
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testBoxingSimple() {
|
||||||
|
val v = vectorOf(1f, 3.162f, 10f, 31f)
|
||||||
|
val box: Box<Vector128> = Box<Vector128>(v)
|
||||||
|
assertEquals(v, box.value, "testBoxingSimple FAILED")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testBoxing() {
|
||||||
|
var u = UnalignedC(vectorOf(0, 1, 2, 3))
|
||||||
|
assertEquals(3, u.value.getIntAt(3))
|
||||||
|
u.value = vectorOf(0f, 1f, 2f, 3f)
|
||||||
|
assertEquals(vectorOf(0f, 1f, 2f, 3f), u.value, "testBoxing FAILED")
|
||||||
|
}
|
||||||
|
|
||||||
fun testSetGet() {
|
fun testSetGet() {
|
||||||
var v4any = vectorOf(0, 1, 2, 3)
|
var v4any = vectorOf(0, 1, 2, 3)
|
||||||
(0 until 4).forEach { assertEquals(it, v4any.getIntAt(it)) }
|
(0 until 4).forEach { assertEquals(it, v4any.getIntAt(it), "testSetGet FAILED for <4 x i32>") }
|
||||||
|
|
||||||
// type punning: set the variable to another runtime type
|
// type punning: set the variable to another runtime type
|
||||||
val a = arrayOf(1f, 3.162f, 10f, 31f)
|
val a = arrayOf(1f, 3.162f, 10f, 31f)
|
||||||
v4any = vectorOf(a[0], a[1], a[2], a[3])
|
v4any = vectorOf(a[0], a[1], a[2], a[3])
|
||||||
(0 until 4).forEach { assertEquals(a[it], v4any.getFloatAt(it)) }
|
(0 until 4).forEach { assertEquals(a[it], v4any.getFloatAt(it), "testSetGet FAILED for <4 x float>") }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testString() {
|
fun testString() {
|
||||||
val v4i = vectorOf(100, 1024, Int.MAX_VALUE, Int.MIN_VALUE)
|
val v4i = vectorOf(100, 1024, Int.MAX_VALUE, Int.MIN_VALUE)
|
||||||
assertEquals("(0x64, 0x400, 0x7fffffff, 0x80000000)", v4i.toString())
|
assertEquals("(0x64, 0x400, 0x7fffffff, 0x80000000)", v4i.toString(), "testString FAILED")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testOOB() {
|
fun testOOB() {
|
||||||
|
|||||||
Reference in New Issue
Block a user