CODEGEN: implementation of global fields initialization.
This commit is contained in:
committed by
vvlevchenko
parent
bca03288f6
commit
86bb5477c5
+4
-19
@@ -18,7 +18,6 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
if (currentFunction == descriptor) return
|
||||
variableIndex = 0
|
||||
currentFunction = declaration.descriptor
|
||||
val fn = declaration.descriptor.llvmFunction
|
||||
prologueBb = LLVMAppendBasicBlock(fn, "prologue")
|
||||
@@ -35,15 +34,6 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun fields(descriptor: ClassDescriptor):List<PropertyDescriptor> = descriptor.fields
|
||||
|
||||
fun newVar():String = currentFunction!!.tmpVariable()
|
||||
|
||||
private var variableIndex:Int = 0
|
||||
private var FunctionDescriptor.tmpVariableIndex: Int
|
||||
get() = variableIndex
|
||||
set(i:Int) { variableIndex = i}
|
||||
|
||||
fun FunctionDescriptor.tmpVariable():String = "tmp_${tmpVariableIndex++}"
|
||||
|
||||
private var prologueBb: LLVMBasicBlockRef? = null
|
||||
private var entryBb: LLVMBasicBlockRef? = null
|
||||
|
||||
@@ -143,14 +133,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
fun indexInClass(p:PropertyDescriptor):Int = (p.containingDeclaration as ClassDescriptor).fields.indexOf(p)
|
||||
|
||||
|
||||
fun basicBlock(name: String = "label_"): LLVMBasicBlockRef =
|
||||
LLVMAppendBasicBlock(currentFunction!!.llvmFunction, name)!!
|
||||
|
||||
fun basicBlock(name: String, code: () -> Unit) = basicBlock(name).apply {
|
||||
appendingTo(this) {
|
||||
code()
|
||||
}
|
||||
}
|
||||
fun basicBlock(function: LLVMValueRef, name: String = "label_"): LLVMBasicBlockRef =
|
||||
LLVMAppendBasicBlock(function, name)!!
|
||||
|
||||
fun lastBasicBlock(): LLVMBasicBlockRef? = LLVMGetLastBasicBlock(currentFunction!!.llvmFunction)
|
||||
|
||||
@@ -192,9 +176,10 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
inner class PositionHolder {
|
||||
private val builder: LLVMBuilderRef = LLVMCreateBuilder()!!
|
||||
|
||||
|
||||
fun getBuilder(): LLVMBuilderRef {
|
||||
if (isAfterTerminator) {
|
||||
positionAtEnd(basicBlock("unreachable"))
|
||||
positionAtEnd(basicBlock(currentFunction!!.llvmFunction, "unreachable"))
|
||||
}
|
||||
|
||||
return builder
|
||||
|
||||
+6
@@ -8,6 +8,7 @@ import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -190,6 +191,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
|
||||
private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule)
|
||||
|
||||
var globalInitIndex:Int = 0
|
||||
|
||||
val allocInstanceFunction = importRtFunction("AllocInstance")
|
||||
val initInstanceFunction = importRtFunction("InitInstance")
|
||||
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
||||
@@ -200,5 +203,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
val isInstanceFunction = importRtFunction("IsInstance")
|
||||
val checkInstanceFunction = importRtFunction("CheckInstance")
|
||||
val throwExceptionFunction = importRtFunction("ThrowException")
|
||||
val appendToInitalizersTail = importRtFunction("AppendToInitializersTail")
|
||||
val usedFunctions = mutableListOf<LLVMValueRef>()
|
||||
val staticInitializers = mutableListOf<LLVMValueRef>()
|
||||
val fileInitializers = mutableListOf<IrElement>()
|
||||
}
|
||||
|
||||
+170
-10
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
|
||||
internal fun emitLLVM(context: Context) {
|
||||
@@ -157,6 +158,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
* @return the requested value
|
||||
*/
|
||||
fun genGetValue(descriptor: ValueDescriptor, result: String = ""): LLVMValueRef
|
||||
|
||||
/**
|
||||
* Generates name for local llvm variable.
|
||||
*
|
||||
* @return the requested value
|
||||
*/
|
||||
fun newVar():String
|
||||
|
||||
/**
|
||||
* Returns owning function scope.
|
||||
*
|
||||
* @return the requested value
|
||||
*/
|
||||
fun functionScope(): CodeContext
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +181,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
* During function code generation [FunctionScope] should be set up.
|
||||
*/
|
||||
private object TopLevelCodeContext : CodeContext {
|
||||
|
||||
private fun unsupported(any: Any? = null): Nothing = throw UnsupportedOperationException(any?.toString() ?: "")
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) = unsupported(target)
|
||||
@@ -183,6 +198,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
override fun getDeclaredVariable(descriptor: VariableDescriptor) = null
|
||||
|
||||
override fun genGetValue(descriptor: ValueDescriptor, result: String) = unsupported(descriptor)
|
||||
|
||||
override fun newVar(): String = unsupported()
|
||||
override fun functionScope(): CodeContext = unsupported()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,9 +237,80 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
override fun visitModuleFragment(module: IrModuleFragment) {
|
||||
logger.log("visitModule : ${ir2string(module)}")
|
||||
module.acceptChildrenVoid(this)
|
||||
|
||||
appendLlvmUsed(context.llvm.usedFunctions)
|
||||
module.acceptChildrenVoid(this)
|
||||
appendLlvmUsed(context.llvm.usedFunctions)
|
||||
appendStaticInitializers(context.llvm.staticInitializers)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
val kVoidFuncType = LLVMFunctionType(LLVMVoidType(), null, 0, 0)
|
||||
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun createInitBody(initName: String) {
|
||||
val initFunction = LLVMAddFunction(context.llvmModule, initName, kVoidFuncType)!! // create LLVM function
|
||||
using(FunctionScope(initFunction)) {
|
||||
val bbEnter = LLVMAppendBasicBlock(initFunction, "label_enter")!!
|
||||
codegen.positionAtEnd(bbEnter)
|
||||
|
||||
context.llvm.fileInitializers.forEachIndexed {
|
||||
i, it ->
|
||||
val irField = it as IrField
|
||||
val descriptor = irField.descriptor
|
||||
val initialization = evaluateExpression("\$init_var_$i", irField.initializer)
|
||||
val globalPtr = LLVMGetNamedGlobal(context.llvmModule, descriptor.symbolName)
|
||||
codegen.store(initialization!!, globalPtr!!)
|
||||
}
|
||||
codegen.ret(null)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Creates static struct InitNode $nodeName = {$initName, NULL};
|
||||
|
||||
fun createInitNode(initName: String, nodeName: String) {
|
||||
memScoped {
|
||||
val initFunction = LLVMGetNamedFunction(context.llvmModule, initName)!! // Get initialization function.
|
||||
val nextInitNode = LLVMConstNull(pointerType(kNodeInitType)) // Set InitNode.next = NULL.
|
||||
val argList = allocArrayOf(initFunction, nextInitNode)[0].ptr // Allocate array of args.
|
||||
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create static object of class InitNode.
|
||||
context.llvm.staticData.placeGlobal(nodeName, constPointer(initNode)).llvmGlobal // Put the object in global var with name "nodeName".
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun createInitCtor(ctorName: String, nodeName: String) {
|
||||
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
|
||||
val bbEnter = LLVMAppendBasicBlock(ctorFunction, "label_enter")!! // Create basic block.
|
||||
|
||||
codegen.positionAtEnd(bbEnter)
|
||||
val initNodePtr = LLVMGetNamedGlobal(context.llvmModule, nodeName)!! // Get LLVM function initializing globals of current file.
|
||||
codegen.call(context.llvm.appendToInitalizersTail, initNodePtr.singletonList(), "") // Add node to the tail of initializers list.
|
||||
codegen.ret(null)
|
||||
|
||||
context.llvm.staticInitializers.add(ctorFunction) // Push newly created constructor in staticInitializers list.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
|
||||
context.llvm.fileInitializers.clear()
|
||||
super.visitFile(declaration)
|
||||
|
||||
if (context.llvm.fileInitializers.isEmpty())
|
||||
return
|
||||
val fileName = declaration.name.takeLastWhile { it != '/' }.dropLastWhile { it != '.' }.dropLast(1)
|
||||
val initName = "${fileName}_init_${context.llvm.globalInitIndex}"
|
||||
val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}"
|
||||
val ctorName = "${fileName}_ctor_${context.llvm.globalInitIndex++}"
|
||||
|
||||
createInitBody(initName)
|
||||
createInitNode(initName, nodeName)
|
||||
createInitCtor(ctorName, nodeName)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -470,10 +559,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
/**
|
||||
* The [CodeContext] enclosing the entire function body.
|
||||
*/
|
||||
private inner class FunctionScope(val declaration: IrFunction) :
|
||||
ParameterScope(bindParameters(declaration.descriptor)) {
|
||||
private inner class FunctionScope (val declaration: IrFunction?) :
|
||||
ParameterScope(bindParameters(declaration?.descriptor)) {
|
||||
constructor(llvmFunction:LLVMValueRef):this(null) {
|
||||
this.llvmFunction = llvmFunction
|
||||
}
|
||||
|
||||
var llvmFunction:LLVMValueRef? = declaration?.let{
|
||||
codegen.llvmFunction(declaration.descriptor)
|
||||
}
|
||||
|
||||
var tmpVariableCount = 0
|
||||
override fun newVar(): String = "tmp_${tmpVariableCount++}"
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
|
||||
if (declaration == null) {
|
||||
codegen.ret(value)
|
||||
return
|
||||
}
|
||||
if (target == declaration.descriptor) {
|
||||
codegen.ret(value)
|
||||
} else {
|
||||
@@ -490,12 +593,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
codegen.call(context.llvm.throwExceptionFunction, args, "")
|
||||
codegen.unreachable()
|
||||
}
|
||||
|
||||
override fun functionScope(): CodeContext = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds LLVM function parameters to IR parameter descriptors.
|
||||
*/
|
||||
private fun bindParameters(descriptor: FunctionDescriptor): Map<ParameterDescriptor, LLVMValueRef> {
|
||||
private fun bindParameters(descriptor: FunctionDescriptor?): Map<ParameterDescriptor, LLVMValueRef> {
|
||||
if (descriptor == null) return emptyMap()
|
||||
val paramDescriptors = descriptor.allValueParameters
|
||||
|
||||
assert(paramDescriptors.size == codegen.countParams(descriptor))
|
||||
@@ -606,12 +712,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val descriptor = expression.descriptor
|
||||
if (descriptor.containingDeclaration is PackageFragmentDescriptor) {
|
||||
val globalProperty = LLVMAddGlobal(context.llvmModule, codegen.getLLVMType(descriptor.type), descriptor.symbolName)
|
||||
LLVMSetInitializer(globalProperty, evaluateExpression("", expression.initializer))
|
||||
if (expression.initializer!!.expression is IrConst<*>) {
|
||||
LLVMSetInitializer(globalProperty, evaluateExpression("", expression.initializer))
|
||||
} else {
|
||||
LLVMSetInitializer(globalProperty, codegen.kNullObjHeaderPtr)
|
||||
context.llvm.fileInitializers.add(expression)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//super.visitField(expression)
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -1971,4 +2079,56 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata");
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Create type { i32, void ()*, i8* }
|
||||
|
||||
val kCtorType = memScoped {
|
||||
val ctorType = LLVMPointerType(kVoidFuncType, 0)
|
||||
val typeList = allocArrayOf(LLVMInt32Type(), ctorType, kInt8Ptr)[0].ptr
|
||||
LLVMStructType(typeList, 3, 0)
|
||||
}!!
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Create object { i32, void ()*, i8* } { i32 1, void ()* @ctorFunction, i8* null }
|
||||
|
||||
fun createGlobalCtor(ctorFunction: LLVMValueRef) = memScoped {
|
||||
val priority = kImmInt32One
|
||||
val data = kNullInt8Ptr
|
||||
val argList = allocArrayOf(priority, ctorFunction, data)[0].ptr
|
||||
val ctorItem = LLVMConstNamedStruct(kCtorType, argList, 3)!!
|
||||
constPointer(ctorItem)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Append initializers of global variables in "llvm.global_ctors" array
|
||||
|
||||
fun appendStaticInitializers(initializers: List<LLVMValueRef>) {
|
||||
if (initializers.isEmpty()) return
|
||||
|
||||
val ctorList = initializers.map { it -> createGlobalCtor(it) }
|
||||
val globalCtors = context.llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType, ctorList)
|
||||
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
/**
|
||||
* This block is devoted to coming codegen refactoring:
|
||||
* removing [Codegenerator.currentFunction] of [FunctionDesctiptor]
|
||||
* and working with local variables with [FunctionScope] and other enhancements.
|
||||
*/
|
||||
|
||||
fun CodeGenerator.newVar() = currentCodeContext.newVar()
|
||||
|
||||
fun CodeGenerator.basicBlock(name: String = "label_"): LLVMBasicBlockRef {
|
||||
val functionScope:FunctionScope = currentCodeContext.functionScope() as FunctionScope
|
||||
return basicBlock(functionScope.llvmFunction!!)
|
||||
}
|
||||
|
||||
fun CodeGenerator.basicBlock(name: String, code: () -> Unit) = basicBlock(name).apply {
|
||||
appendingTo(this) {
|
||||
code()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -123,6 +123,7 @@ internal val kInt1 = LLVMInt1Type()!!
|
||||
internal val kBoolean = kInt1
|
||||
internal val kInt8Ptr = pointerType(int8Type)
|
||||
internal val kInt8PtrPtr = pointerType(kInt8Ptr)
|
||||
internal val kNullInt8Ptr = LLVMConstNull(kInt8Ptr)
|
||||
internal val kImmInt32One = Int32(1).llvm
|
||||
internal val kImmInt64One = Int64(1).llvm
|
||||
internal val ContextUtils.kNullObjHeaderPtr: LLVMValueRef
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
|
||||
@@ -753,6 +753,7 @@ task initializers1(type: RunKonanTest) {
|
||||
source = "runtime/basic/initializers1.kt"
|
||||
}
|
||||
|
||||
|
||||
task concatenation(type: RunKonanTest) {
|
||||
goldValue = "Hello world 1 2\nHello, a\nHello, b\n"
|
||||
source = "codegen/basics/concatenation.kt"
|
||||
@@ -823,3 +824,8 @@ task lambda13(type: RunKonanTest) {
|
||||
goldValue = "foo\n"
|
||||
source = "codegen/lambda/lambda13.kt"
|
||||
}
|
||||
|
||||
task initializers2(type: RunKonanTest) {
|
||||
goldValue = "1\nA\nB\n"
|
||||
source = "runtime/basic/initializers2.kt"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,29 @@
|
||||
#include "Natives.h"
|
||||
#include "Types.h"
|
||||
|
||||
//--- Init global variables ---------------------------------------------------//
|
||||
|
||||
typedef void (*Initializer)();
|
||||
struct InitNode;
|
||||
|
||||
struct InitNode {
|
||||
Initializer init;
|
||||
struct InitNode* next;
|
||||
};
|
||||
|
||||
struct InitNode initHeadNode;
|
||||
struct InitNode* initTailNode = &initHeadNode;
|
||||
|
||||
void InitGlobalVariables() {
|
||||
struct InitNode *currNode = initHeadNode.next;
|
||||
while(currNode) {
|
||||
currNode->init();
|
||||
currNode = currNode->next;
|
||||
}
|
||||
}
|
||||
|
||||
//--- Setup args --------------------------------------------------------------//
|
||||
|
||||
ObjHeader* setupArgs(int argc, char** argv) {
|
||||
// The count is one less, because we skip argv[0] which is the binary name.
|
||||
ObjHeader* args = AllocArrayInstance(theArrayTypeInfo, SCOPE_GLOBAL, argc-1);
|
||||
@@ -15,13 +38,17 @@ ObjHeader* setupArgs(int argc, char** argv) {
|
||||
return args;
|
||||
}
|
||||
|
||||
//--- main --------------------------------------------------------------------//
|
||||
|
||||
extern "C" void Konan_start(ObjHeader* );
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
InitMemory();
|
||||
InitGlobalVariables();
|
||||
|
||||
ObjHeader* args = setupArgs(argc, argv);
|
||||
|
||||
Konan_start(args);
|
||||
|
||||
// Yes, we have to follow Java convention and return zero.
|
||||
|
||||
Reference in New Issue
Block a user