Use unaligned instructions for simd struct member access (#3596)

This commit is contained in:
Vladimir Ivanov
2019-11-21 14:05:43 +03:00
committed by GitHub
parent ec6fa2dcd5
commit 1fea5cdac2
4 changed files with 49 additions and 13 deletions
@@ -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))
@@ -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)
@@ -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}"
} }
+28 -3
View File
@@ -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() {