From 630842133c5de6edd61b28d0a5d704377c1bd962 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 20 Jun 2023 18:52:09 +0100 Subject: Rename LlvmCompiler to LlvmCodeGen --- .../compiler/backends/llvm/LlvmBackend.java | 4 +- .../compiler/backends/llvm/LlvmCodeGen.java | 200 +++++++++++ .../backends/llvm/LlvmCodeGenClosures.java | 393 +++++++++++++++++++++ .../compiler/backends/llvm/LlvmCodeGenContext.java | 231 ++++++++++++ .../llvm/LlvmCodeGenLocalVariableSpace.java | 29 ++ .../backends/llvm/LlvmCodeGenNamespaces.java | 280 +++++++++++++++ .../compiler/backends/llvm/LlvmCodeGenResult.java | 7 + .../compiler/backends/llvm/LlvmCodeGenRuntime.java | 32 ++ .../compiler/backends/llvm/LlvmCodeGenStrings.java | 70 ++++ .../llvm/LlvmCodeGenTopLevelEntitySpace.java | 17 + .../compiler/backends/llvm/LlvmCodeGenTypes.java | 11 + .../compiler/backends/llvm/LlvmCompiler.java | 200 ----------- .../backends/llvm/LlvmCompilerClosures.java | 393 --------------------- .../backends/llvm/LlvmCompilerContext.java | 231 ------------ .../llvm/LlvmCompilerLocalVariableSpace.java | 29 -- .../backends/llvm/LlvmCompilerNamespaces.java | 280 --------------- .../compiler/backends/llvm/LlvmCompilerResult.java | 7 - .../backends/llvm/LlvmCompilerRuntime.java | 32 -- .../backends/llvm/LlvmCompilerStrings.java | 70 ---- .../llvm/LlvmCompilerTopLevelEntitySpace.java | 17 - .../compiler/backends/llvm/LlvmCompilerTypes.java | 11 - .../backends/llvm/LlvmGlobalDefinitionBuilder.java | 4 +- .../compiler/backends/llvm/LlvmSizeOf.java | 6 +- 23 files changed, 1277 insertions(+), 1277 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenClosures.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenContext.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenLocalVariableSpace.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenNamespaces.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenResult.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenRuntime.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTopLevelEntitySpace.java create mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerClosures.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerResult.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerRuntime.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerStrings.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTypes.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java index 49b55160..2684f18a 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java @@ -30,7 +30,7 @@ public class LlvmBackend implements Backend { var objectFilePaths = new ArrayList(); for (var namespace : namespaces.entrySet()) { var namespaceName = namespace.getKey(); - var llvmModule = LlvmCompiler.compileNamespace( + var llvmModule = LlvmCodeGen.generateNamespace( namespaceName, namespace.getValue(), typeInfo @@ -41,7 +41,7 @@ public class LlvmBackend implements Backend { } for (var bin : config.bins()) { - var mainModule = LlvmCompiler.compileMain(config.main(), typeInfo); + var mainModule = LlvmCodeGen.generateMain(config.main(), typeInfo); var objectPath = compileLlvmModule(mainModule, targetDir.resolve("bins"), bin.name()); objectFilePaths.add(objectPath); diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java new file mode 100644 index 00000000..e0060e9d --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java @@ -0,0 +1,200 @@ +package org.shedlang.compiler.backends.llvm; + +import org.shedlang.compiler.ast.typed.FreeVariables; +import org.shedlang.compiler.backends.llvm.ir.ast.*; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturn; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandInt; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandPtrToInt; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; +import org.shedlang.compiler.stackir.instructions.*; +import org.shedlang.compiler.typechecker.TypeInfo; +import org.shedlang.compiler.types.NamespaceName; + +import java.util.*; + +import static org.shedlang.compiler.util.Lists.reversed; + +public class LlvmCodeGen { + public static LlvmModule generateMain(NamespaceName main, TypeInfo typeInfo) { + var context = LlvmCodeGenContext.fromTypeInfo(typeInfo); + + var mainContext = context.enterFunction(); + + var namespaceResult = LlvmCodeGenNamespaces.importValue(main, mainContext); + var namespace = namespaceResult.value(); + mainContext = namespaceResult.context(); + + var fieldResult = LlvmCodeGenNamespaces.fieldLoad( + main, + namespace, + // TODO: check there is a main function + "main", + mainContext + ); + var field = fieldResult.value(); + mainContext = fieldResult.context(); + + mainContext = LlvmCodeGenClosures.call(field, mainContext, List.of()); + + mainContext = mainContext.addTerminatorInstruction( + new LlvmReturn(LlvmTypes.INT_32, new LlvmOperandInt(0)) + ); + + var mainBasicBlocksResult = context.exitFunction(mainContext); + var mainBasicBlocks = mainBasicBlocksResult.value(); + context = mainBasicBlocksResult.context(); + + context = context.addTopLevelEntity(new LlvmFunctionDefinition( + "main", + LlvmTypes.INT_32, + List.of(), + mainBasicBlocks + )); + + return new LlvmModule(context.topLevelEntities()); + } + + public static LlvmModule generateNamespace( + NamespaceName namespaceName, + List instructions, + TypeInfo typeInfo + ) { + var context = defaultContext(typeInfo); + for (var instruction : instructions) { + context = generateInstruction(instruction, context); + } + + context = LlvmCodeGenNamespaces.define(namespaceName, context); + + var topLevelEntities = context.topLevelEntities(); + + return new LlvmModule(topLevelEntities); + } + + private static LlvmCodeGenContext defaultContext(TypeInfo typeInfo) { + return LlvmCodeGenContext.fromTypeInfo(typeInfo) + .addTopLevelEntity(new LlvmFunctionDeclaration( + "shed__runtime__alloc", + LlvmTypes.pointer(LlvmTypes.INT_8), + List.of(new LlvmParam(LlvmTypes.INT_64, "size")) + )) + .addTopLevelEntity(new LlvmGlobalDefinition( + "shed__runtime__print_closure", + new LlvmCodeGenClosures.Types(Optional.of(FreeVariables.empty())).closureStruct(), + Optional.empty(), + false, + false, + false + )) + .addLocal("print", new LlvmOperandPtrToInt( + new LlvmVariableGlobal("shed__runtime__print_closure"), + LlvmCodeGenTypes.VALUE_TYPE + )); + } + + public static LlvmCodeGenContext generateInstruction(Instruction instruction, LlvmCodeGenContext context) { + return switch (instruction) { + case CallInstruction call -> { + var namedArgsByName = new HashMap(); + for (var argName : reversed(call.namedArgNames())) { + var argResult = context.pop(); + var arg = argResult.value(); + context = argResult.context(); + namedArgsByName.put(argName, arg); + } + var namedArgs = namedArgsByName.entrySet() + .stream().sorted(Map.Entry.comparingByKey()) + .map(x -> x.getValue()) + .toList(); + + var args = new ArrayList(); + for (var i = 0; i < call.positionalArgCount(); i++) { + var argResult = context.pop(); + var arg = argResult.value(); + context = argResult.context(); + args.add(arg); + } + Collections.reverse(args); + args.addAll(namedArgs); + + var receiverResult = context.pop(); + var receiver = receiverResult.value(); + context = receiverResult.context(); + + yield LlvmCodeGenClosures.call( + receiver, + context, + args + ); + } + case DefineFunctionInstruction defineFunction -> { + yield LlvmCodeGenClosures.create( + defineFunction.name(), + defineFunction.freeVariables(), + functionContext -> { + for (var bodyInstruction : defineFunction.body()) { + functionContext = generateInstruction(bodyInstruction, functionContext); + } + return functionContext; + }, + context + ); + } + case DiscardInstruction discardInstruction -> + context.pop().context(); + + case LocalLoadInstruction localLoad -> + context.push(context.local(localLoad.name())); + + case LocalStoreInstruction localStore -> { + var result = context.pop(); + var value = result.value(); + context = result.context(); + + yield context.addLocal(localStore.name(), value); + } + + case NamespaceFieldStoreInstruction namespaceFieldStore -> { + var popResult = context.pop(); + var fieldValue = popResult.value(); + context = popResult.context(); + + yield LlvmCodeGenNamespaces.fieldStore( + namespaceFieldStore.namespaceName(), + namespaceFieldStore.fieldName(), + fieldValue, + context + ); + } + + case PushBoolInstruction pushBool -> + context.push(new LlvmOperandInt(pushBool.value() ? 1 : 0)); + + case PushIntInstruction pushInt -> + context.push(new LlvmOperandInt(pushInt.value().longValueExact())); + + case PushStringInstruction pushString -> { + var result = LlvmCodeGenStrings.defineString(pushString.value(), context); + var globalDefinition = result.value(); + context = result.context(); + + yield context.push(LlvmCodeGenStrings.operandAsShedObject(globalDefinition)); + } + + case PushUnitInstruction pushUnit -> + context.push(new LlvmOperandInt(0)); + + case ReturnInstruction returnInstruction -> { + var result = context.pop(); + var value = result.value(); + context = result.context(); + + yield context.addTerminatorInstruction( + new LlvmReturn(LlvmCodeGenTypes.VALUE_TYPE, value) + ); + } + }; + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenClosures.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenClosures.java new file mode 100644 index 00000000..88849d2a --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenClosures.java @@ -0,0 +1,393 @@ +package org.shedlang.compiler.backends.llvm; + +import org.shedlang.compiler.ast.typed.FreeVariable; +import org.shedlang.compiler.ast.typed.FreeVariables; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmParam; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.*; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmTypedOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableLocal; +import org.shedlang.compiler.backends.llvm.ir.ast.types.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public class LlvmCodeGenClosures { + private LlvmCodeGenClosures() { + } + + public record Types(Optional freeVariables) { + public LlvmTypePointer closurePointer() { + return LlvmTypes.pointer(closureStruct()); + } + + public LlvmTypeStructure closureStruct() { + return LlvmTypes.structure(List.of( + closureFunctionPointer(), + closureEnvironment() + )); + } + + public LlvmTypePointer closureFunctionPointer() { + return LlvmTypes.pointer(closureFunction()); + } + + public LlvmTypeFunction closureFunction() { + return LlvmTypes.function( + LlvmCodeGenTypes.VALUE_TYPE, + List.of(closureEnvironmentPointer()) + ); + } + + public LlvmTypePointer closureEnvironmentPointer() { + return LlvmTypes.pointer(closureEnvironment()); + } + + public LlvmTypeArray closureEnvironment() { + return LlvmTypes.array(freeVariables.map(x -> x.size()).orElse(0), LlvmCodeGenTypes.VALUE_TYPE); + } + } + + public static final Types CALLABLE_TYPES = new Types(Optional.empty()); + + public static Types types(FreeVariables freeVariables) { + return new Types(Optional.of(freeVariables)); + } + + public static Types types(Optional freeVariables) { + return new Types(freeVariables); + } + + public static LlvmCodeGenContext create( + String name, + FreeVariables freeVariables, + Function compileBody, + LlvmCodeGenContext context + ) { + var closureTypes = LlvmCodeGenClosures.types(freeVariables); + + var topLevelEntityName = context.generateTopLevelEntityName( + LlvmCodeGenTopLevelEntitySpace.FUNCTION, + name + ); + + var functionContext = context.enterFunction(); + var functionClosurePointerResult = functionContext.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_POINTER + ); + var functionClosurePointer = functionClosurePointerResult.value(); + functionContext = functionClosurePointerResult.context(); + + for (var freeVariable : freeVariables) { + functionContext = loadClosureFreeVariable( + functionClosurePointer, + freeVariable, + closureTypes, + functionContext + ); + } + + functionContext = compileBody.apply(functionContext); + var bodyResult = context.exitFunction(functionContext); + var body = bodyResult.value(); + context = bodyResult.context(); + + context = context.addTopLevelEntity(new LlvmFunctionDefinition( + topLevelEntityName, + LlvmCodeGenTypes.VALUE_TYPE, + List.of( + new LlvmParam( + closureTypes.closurePointer(), + functionClosurePointer.name() + ) + ), + body + )); + + var closurePointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_POINTER + ); + var closurePointer = closurePointerResult.value(); + context = closurePointerResult.context(); + + var closureSizeResult = LlvmSizeOf.sizeOf( + closureTypes.closureStruct(), + context + ); + var closureSize = closureSizeResult.value(); + context = closureSizeResult.context(); + + context = LlvmCodeGenRuntime.callAlloc( + closurePointer, + closureTypes.closurePointer(), + closureSize, + context + ); + + context = storeClosureFunctionPointer( + closurePointer, + closureTypes, + new LlvmVariableGlobal(topLevelEntityName), + context + ); + + for (var freeVariable : freeVariables) { + context = storeClosureFreeVariable( + closurePointer, + freeVariable, + closureTypes, + context + ); + } + + var closureValueResult = castClosurePointerToValue(closurePointer, context); + var closureValue = closureValueResult.value(); + context = closureValueResult.context(); + + context = context.push(closureValue); + + return context; + } + + public static LlvmCodeGenContext call( + LlvmOperand closure, + LlvmCodeGenContext context, + List args + ) { + var closurePointerResult = castValueToClosurePointer(closure, context); + var closurePointer = closurePointerResult.value(); + context = closurePointerResult.context(); + + var functionPointerResult = loadClosureFunctionPointer(closurePointer, context); + var functionPointer = functionPointerResult.value(); + context = functionPointerResult.context(); + + var callTargetResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.TEMPORARY + ); + var callTarget = callTargetResult.value(); + context = callTargetResult.context(); + + var fullArgs = new ArrayList(); + fullArgs.add(new LlvmTypedOperand(CALLABLE_TYPES.closurePointer(), closurePointer)); + for (var arg : args) { + fullArgs.add(new LlvmTypedOperand(LlvmCodeGenTypes.VALUE_TYPE, arg)); + } + + return context.addInstruction(new LlvmCall( + callTarget, + LlvmCodeGenTypes.VALUE_TYPE, + functionPointer, + fullArgs + )).push(callTarget); + } + + private static LlvmCodeGenResult castClosurePointerToValue( + LlvmOperand closurePointer, + LlvmCodeGenContext context + ) { + var closureValueResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_VALUE + ); + var closureValue = closureValueResult.value(); + context = closureValueResult.context(); + + context = context.addInstruction(new LlvmPtrToInt( + closureValue, + closurePointer, + LlvmCodeGenTypes.VALUE_TYPE + )); + + return context.toResult(closureValue); + } + + private static LlvmCodeGenResult castValueToClosurePointer( + LlvmOperand value, + LlvmCodeGenContext context + ) { + var closurePointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_POINTER + ); + var closurePointer = closurePointerResult.value(); + context = closurePointerResult.context(); + + context = context.addInstruction(new LlvmIntToPtr( + closurePointer, + LlvmCodeGenTypes.VALUE_TYPE, + value + )); + + return context.toResult(closurePointer); + } + + private static LlvmCodeGenContext storeClosureFunctionPointer( + LlvmOperand closurePointer, + Types closureTypes, + LlvmOperand function, + LlvmCodeGenContext context + ) { + var closureFunctionPointerPointerResult = getClosureFunctionPointerPointer( + closurePointer, + closureTypes, + context + ); + var closureFunctionPointerPointer = closureFunctionPointerPointerResult.value(); + context = closureFunctionPointerPointerResult.context(); + + return context.addInstruction(new LlvmStore( + closureTypes.closureFunctionPointer(), + function, + closureFunctionPointerPointer + )); + } + + private static LlvmCodeGenResult loadClosureFunctionPointer( + LlvmOperand closurePointer, + LlvmCodeGenContext context + ) { + var functionPointerPointerResult = getClosureFunctionPointerPointer( + closurePointer, + CALLABLE_TYPES, + context + ); + var functionPointerPointer = functionPointerPointerResult.value(); + context = functionPointerPointerResult.context(); + + var functionPointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_FUNCTION_POINTER + ); + var functionPointer = functionPointerResult.value(); + context = functionPointerResult.context(); + + return context.addInstruction(new LlvmLoad( + functionPointer, + CALLABLE_TYPES.closureFunctionPointer(), + functionPointerPointer + )).toResult(functionPointer); + } + + private static LlvmCodeGenResult getClosureFunctionPointerPointer( + LlvmOperand closurePointer, + Types closureTypes, + LlvmCodeGenContext context + ) { + var functionPointerPointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_FUNCTION_POINTER_POINTER + ); + var functionPointerPointer = functionPointerPointerResult.value(); + context = functionPointerPointerResult.context(); + + context = context.addInstruction(new LlvmGetElementPtr( + functionPointerPointer, + closureTypes.closurePointer(), + closurePointer, + List.of(LlvmTypedOperand.arrayIndex(0), LlvmTypedOperand.structureIndex(0)) + )); + + return context.toResult(functionPointerPointer); + } + + private static LlvmCodeGenResult getClosureEnvironmentPointer( + LlvmOperand closurePointer, + LlvmCodeGenContext context + ) { + var environmentPointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_ENVIRONMENT_POINTER + ); + var environmentPointer = environmentPointerResult.value(); + context = environmentPointerResult.context(); + + context = context.addInstruction(new LlvmGetElementPtr( + environmentPointer, + CALLABLE_TYPES.closurePointer(), + closurePointer, + List.of(LlvmTypedOperand.arrayIndex(0), LlvmTypedOperand.structureIndex(1)) + )); + + return context.toResult(environmentPointer); + } + + private static LlvmCodeGenContext storeClosureFreeVariable( + LlvmOperand closurePointer, + FreeVariable freeVariable, + Types closureTypes, + LlvmCodeGenContext context + ) { + var closureEnvironmentPointerResult = getClosureFreeVariablePointer( + closurePointer, + freeVariable, + closureTypes, + context + ); + var closureEnvironmentPointer = closureEnvironmentPointerResult.value(); + context = closureEnvironmentPointerResult.context(); + + return context.addInstruction(new LlvmStore( + LlvmCodeGenTypes.VALUE_TYPE, + context.local(freeVariable.name()), + closureEnvironmentPointer + )); + } + + private static LlvmCodeGenContext loadClosureFreeVariable( + LlvmOperand closurePointer, + FreeVariable freeVariable, + Types closureTypes, + LlvmCodeGenContext context + ) { + var closureFreeVariablePointerResult = getClosureFreeVariablePointer( + closurePointer, + freeVariable, + closureTypes, + context + ); + var closureFreeVariablePointer = closureFreeVariablePointerResult.value(); + context = closureFreeVariablePointerResult.context(); + + var closureFreeVariableResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_FREE_VARIABLE, + freeVariable.name() + ); + var closureFreeVariable = closureFreeVariableResult.value(); + context = closureFreeVariableResult.context(); + + context = context.addInstruction(new LlvmLoad( + closureFreeVariable, + LlvmCodeGenTypes.VALUE_TYPE, + closureFreeVariablePointer + )); + + return context.addLocal(freeVariable.name(), closureFreeVariable); + } + + private static LlvmCodeGenResult getClosureFreeVariablePointer( + LlvmOperand closurePointer, + FreeVariable freeVariable, + Types closureTypes, + LlvmCodeGenContext context + ) { + var freeVariablePointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.CLOSURE_FREE_VARIABLE_POINTER, + freeVariable.name() + ); + var freeVariablePointer = freeVariablePointerResult.value(); + context = freeVariablePointerResult.context(); + + context = context.addInstruction(new LlvmGetElementPtr( + freeVariablePointer, + closureTypes.closurePointer(), + closurePointer, + List.of( + LlvmTypedOperand.arrayIndex(0), + LlvmTypedOperand.structureIndex(1), + LlvmTypedOperand.arrayIndex(freeVariable.index()) + ) + )); + + return context.toResult(freeVariablePointer); + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenContext.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenContext.java new file mode 100644 index 00000000..60137e9d --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenContext.java @@ -0,0 +1,231 @@ +package org.shedlang.compiler.backends.llvm; + +import org.pcollections.Empty; +import org.pcollections.PMap; +import org.pcollections.PStack; +import org.pcollections.PVector; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmBasicBlock; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmTopLevelEntity; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmInstruction; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmTerminatorInstruction; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableLocal; +import org.shedlang.compiler.typechecker.TypeInfo; +import org.shedlang.compiler.util.POrderedMap; + +import java.util.List; +import java.util.Optional; + +public record LlvmCodeGenContext( + TypeInfo typeInfo, + PStack stack, + PMap locals, + PVector basicBlocks, + PVector instructions, + POrderedMap topLevelEntitiesByName, + NameAllocator localVariableNames +) { + public static LlvmCodeGenContext EMPTY = fromTypeInfo(TypeInfo.EMPTY); + + public static LlvmCodeGenContext fromTypeInfo(TypeInfo typeInfo) { + return new LlvmCodeGenContext( + typeInfo, + Empty.stack(), + Empty.map(), + Empty.vector(), + Empty.vector(), + POrderedMap.empty(), + NameAllocator.empty() + ); + } + + public LlvmCodeGenContext push(LlvmOperand operand) { + return new LlvmCodeGenContext( + typeInfo, + stack.plus(operand), + locals, + basicBlocks, + instructions, + topLevelEntitiesByName, + localVariableNames + ); + } + + public LlvmCodeGenResult pop() { + return new LlvmCodeGenContext( + typeInfo, + stack.minus(0), + locals, + basicBlocks, + instructions, + topLevelEntitiesByName, + localVariableNames + ).toResult(stack.get(0)); + } + + public LlvmCodeGenContext addLocal(String name, LlvmOperand value) { + return new LlvmCodeGenContext( + typeInfo, + stack, + locals.plus(name, value), + basicBlocks, + instructions, + topLevelEntitiesByName, + localVariableNames + ); + } + + public LlvmOperand local(String name) { + var local = locals.get(name); + if (local == null) { + // TODO: better error + throw new RuntimeException("unrecognised local: " + name); + } else { + return local; + } + } + + public LlvmCodeGenContext addInstruction(LlvmInstruction instruction) { + return new LlvmCodeGenContext( + typeInfo, + stack, + locals, + basicBlocks, + instructions.plus(instruction), + topLevelEntitiesByName, + localVariableNames + ); + } + + public LlvmCodeGenContext addTerminatorInstruction( + LlvmTerminatorInstruction terminatorInstruction + ) { + return new LlvmCodeGenContext( + typeInfo, + stack, + locals, + basicBlocks.plus(new LlvmBasicBlock( + Optional.empty(), + instructions, + terminatorInstruction + )), + Empty.vector(), + topLevelEntitiesByName, + localVariableNames + ); + } + + public LlvmCodeGenResult addGlobalDefinition( + LlvmGlobalDefinitionBuilder builder + ) { + var globalDefinition = new LlvmGlobalDefinition( + generateTopLevelEntityName(builder.namePrefix().orElseThrow()), + builder.type().orElseThrow(), + builder.value(), + builder.constant(), + builder.isPrivate(), + builder.unnamedAddr() + ); + + return addTopLevelEntity(globalDefinition).toResult(globalDefinition); + } + + public LlvmCodeGenContext addTopLevelEntity(LlvmTopLevelEntity topLevelEntity) { + return new LlvmCodeGenContext( + typeInfo, + stack, + locals, + basicBlocks, + instructions, + topLevelEntitiesByName.plus(topLevelEntity.name(), topLevelEntity), + localVariableNames + ); + } + + public String generateTopLevelEntityName(LlvmCodeGenTopLevelEntitySpace space, String name) { + return generateTopLevelEntityName(space, Optional.of(name)); + } + + private String generateTopLevelEntityName(LlvmCodeGenTopLevelEntitySpace space) { + return generateTopLevelEntityName(space, Optional.empty()); + } + + private String generateTopLevelEntityName( + LlvmCodeGenTopLevelEntitySpace space, + Optional name + ) { + return NameAllocator.generateName( + topLevelEntitiesByName::containsKey, + "shed__" + space, + name + ); + } + + public boolean hasTopLevelEntity(String name) { + return topLevelEntitiesByName.containsKey(name); + } + + public List topLevelEntities() { + return topLevelEntitiesByName.toValues(); + } + + public LlvmCodeGenResult generateVariableLocal( + LlvmCodeGenLocalVariableSpace space + ) { + return generateVariableLocal(space, Optional.empty()); + } + + public LlvmCodeGenResult generateVariableLocal( + LlvmCodeGenLocalVariableSpace space, + String name + ) { + return generateVariableLocal(space, Optional.of(name)); + } + + private LlvmCodeGenResult generateVariableLocal( + LlvmCodeGenLocalVariableSpace space, + Optional name + ) { + var result = localVariableNames.generateName(space, name); + return new LlvmCodeGenContext( + typeInfo, + stack, + locals, + basicBlocks, + instructions, + topLevelEntitiesByName, + result.allocator() + ).toResult(new LlvmVariableLocal(result.name())); + } + + public LlvmCodeGenResult toResult(T value) { + return new LlvmCodeGenResult<>(value, this); + } + + public LlvmCodeGenContext enterFunction() { + return new LlvmCodeGenContext( + typeInfo, + Empty.stack(), + Empty.map(), + Empty.vector(), + Empty.vector(), + topLevelEntitiesByName, + NameAllocator.empty() + ); + } + + public LlvmCodeGenResult> exitFunction( + LlvmCodeGenContext functionContext + ) { + return new LlvmCodeGenContext( + typeInfo, + stack, + locals, + basicBlocks, + instructions, + functionContext.topLevelEntitiesByName, + localVariableNames + ).toResult(functionContext.basicBlocks); + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenLocalVariableSpace.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenLocalVariableSpace.java new file mode 100644 index 00000000..1da74d57 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenLocalVariableSpace.java @@ -0,0 +1,29 @@ +package org.shedlang.compiler.backends.llvm; + +public enum LlvmCodeGenLocalVariableSpace { + CLOSURE_VALUE("closureValue"), + CLOSURE_POINTER("closurePointer"), + CLOSURE_FUNCTION_POINTER("closureFunctionPointer"), + CLOSURE_FUNCTION_POINTER_POINTER("closureFunctionPointerPointer"), + CLOSURE_ENVIRONMENT_POINTER("closureEnvironmentPointer"), + CLOSURE_FREE_VARIABLE_POINTER("closureFreeVariablePointer"), + CLOSURE_FREE_VARIABLE("closureFreeVariable"), + FIELD("field"), + FIELD_POINTER("fieldPointer"), + NAMESPACE("namespace"), + NAMESPACE_STRUCT_POINTER("namespaceStructPointer"), + SIZE_PTR("sizePtr"), + SIZE("size"), + TEMPORARY("tmp"); + + private final String name; + + LlvmCodeGenLocalVariableSpace(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenNamespaces.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenNamespaces.java new file mode 100644 index 00000000..1c60bab9 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenNamespaces.java @@ -0,0 +1,280 @@ +package org.shedlang.compiler.backends.llvm; + +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmBasicBlock; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDeclaration; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.*; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.*; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypePointer; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypeStructure; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; +import org.shedlang.compiler.types.NamespaceName; +import org.shedlang.compiler.types.NamespaceTypeInfo; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.IntStream; + +public class LlvmCodeGenNamespaces { + private LlvmCodeGenNamespaces() { + } + + private static LlvmTypePointer typeNamespacePointer(NamespaceTypeInfo namespaceTypeInfo) { + return new LlvmTypePointer(typeNamespaceStruct(namespaceTypeInfo)); + } + + private static LlvmType typeNamespaceStruct(NamespaceTypeInfo namespaceTypeInfo) { + return new LlvmTypeStructure(Collections.nCopies( + namespaceTypeInfo.fieldCount(), + LlvmCodeGenTypes.VALUE_TYPE + )); + } + + private static LlvmOperand operandNamespaceValue(NamespaceName namespaceName) { + return new LlvmOperandPtrToInt( + operandNamespaceStruct(namespaceName), + LlvmCodeGenTypes.VALUE_TYPE + ); + } + + private static LlvmOperand operandNamespaceStruct(NamespaceName namespaceName) { + return new LlvmVariableGlobal(globalNameNamespaceValue(namespaceName)); + } + + private static String globalNameNamespaceValue(NamespaceName namespaceName) { + return "shed__namespace__" + namespaceNameToLlvmIdentifier(namespaceName); + } + + public static String globalNameNamespaceImport(NamespaceName namespaceName) { + return "shed__namespaceImport__" + namespaceNameToLlvmIdentifier(namespaceName); + } + + private static String globalNameNamespaceInit(NamespaceName namespaceName) { + return "shed__namespaceInit__" + namespaceNameToLlvmIdentifier(namespaceName); + } + + private static String globalNameNamespaceIsInited(NamespaceName namespaceName) { + return "shed__namespaceIsInited__" + namespaceNameToLlvmIdentifier(namespaceName); + } + + private static String namespaceNameToLlvmIdentifier(NamespaceName namespaceName) { + return String.join("_", namespaceName.parts()); + } + + public static LlvmCodeGenResult importValue( + NamespaceName namespaceName, + LlvmCodeGenContext context + ) { + var importName = globalNameNamespaceImport(namespaceName); + + if (!context.hasTopLevelEntity(importName)) { + context = context.addTopLevelEntity(new LlvmFunctionDeclaration( + importName, + LlvmCodeGenTypes.VALUE_TYPE, + List.of() + )); + } + + var namespaceResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.NAMESPACE, + namespaceNameToLlvmIdentifier(namespaceName) + ); + var namespace = namespaceResult.value(); + context = namespaceResult.context(); + + return context.addInstruction(new LlvmCall( + namespace, + LlvmCodeGenTypes.VALUE_TYPE, + new LlvmVariableGlobal(importName), + List.of() + )).toResult(namespace); + } + + public static LlvmCodeGenContext define( + NamespaceName namespaceName, + LlvmCodeGenContext context + ) { + context = context.addInstruction(new LlvmStore( + LlvmTypes.INT_1, + new LlvmOperandInt(1), + new LlvmVariableGlobal(globalNameNamespaceIsInited(namespaceName)) + )); + context = context.addTerminatorInstruction(new LlvmReturnVoid()); + var basicBlocks = context.basicBlocks(); + var namespaceInitFunction = new LlvmFunctionDefinition( + globalNameNamespaceInit(namespaceName), + LlvmTypes.VOID, + List.of(), + basicBlocks + ); + + var namespaceImportFunction = new LlvmFunctionDefinition( + globalNameNamespaceImport(namespaceName), + LlvmCodeGenTypes.VALUE_TYPE, + List.of(), + List.of( + new LlvmBasicBlock( + Optional.empty(), + List.of( + new LlvmLoad( + new LlvmVariableLocal("isInited"), + LlvmTypes.INT_1, + new LlvmVariableGlobal(globalNameNamespaceIsInited(namespaceName)) + ) + ), + new LlvmBr( + new LlvmVariableLocal("isInited"), + "inited", + "init" + ) + ), + new LlvmBasicBlock( + Optional.of("init"), + List.of( + new LlvmCall( + Optional.empty(), + LlvmTypes.VOID, + new LlvmVariableGlobal(globalNameNamespaceInit(namespaceName)), + List.of() + ) + ), + new LlvmBrUnconditional("inited") + ), + new LlvmBasicBlock( + Optional.of("inited"), + List.of(), + new LlvmReturn( + LlvmCodeGenTypes.VALUE_TYPE, + operandNamespaceValue(namespaceName) + ) + ) + ) + ); + + return context + .addTopLevelEntity(defineNamespaceIsInited(namespaceName)) + .addTopLevelEntity(defineNamespaceValue( + namespaceName, + context.typeInfo().namespaceTypeInfo(namespaceName) + )) + .addTopLevelEntity(namespaceInitFunction) + .addTopLevelEntity(namespaceImportFunction); + } + + private static LlvmGlobalDefinition defineNamespaceIsInited( + NamespaceName namespaceName + ) { + return new LlvmGlobalDefinition( + globalNameNamespaceIsInited(namespaceName), + LlvmTypes.INT_1, + Optional.of(new LlvmOperandInt(0)), + false, + true, + true + ); + } + + private static LlvmGlobalDefinition defineNamespaceValue( + NamespaceName namespaceName, + NamespaceTypeInfo namespaceTypeInfo + ) { + return new LlvmGlobalDefinition( + globalNameNamespaceValue(namespaceName), + typeNamespaceStruct(namespaceTypeInfo), + Optional.of(new LlvmOperandStructure( + IntStream.range(0, namespaceTypeInfo.fieldCount()) + .mapToObj(ignored -> new LlvmTypedOperand( + LlvmCodeGenTypes.VALUE_TYPE, + new LlvmOperandInt(0) + )) + .toList() + )), + false, + true, + true + ); + } + + public static LlvmCodeGenContext fieldStore( + NamespaceName namespaceName, + String fieldName, + LlvmOperand fieldValue, + LlvmCodeGenContext context + ) { + var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); + + var fieldPointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.FIELD_POINTER, + fieldName + ); + var fieldPointer = fieldPointerResult.value(); + context = fieldPointerResult.context(); + + return context.addInstruction(new LlvmGetElementPtr( + fieldPointer, + typeNamespacePointer(namespaceTypeInfo), + operandNamespaceStruct(namespaceName), + List.of( + LlvmTypedOperand.arrayIndex(0), + LlvmTypedOperand.structureIndex(namespaceTypeInfo.fieldIndex(fieldName)) + ) + )).addInstruction(new LlvmStore( + LlvmCodeGenTypes.VALUE_TYPE, + fieldValue, + fieldPointer + )); + } + + public static LlvmCodeGenResult fieldLoad( + NamespaceName namespaceName, + LlvmOperand namespace, + String fieldName, + LlvmCodeGenContext context + ) { + var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); + + var namespaceStructPointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.NAMESPACE_STRUCT_POINTER, + String.join("_", namespaceName.parts()) + ); + var namespaceStructPointer = namespaceStructPointerResult.value(); + context = namespaceStructPointerResult.context(); + + context = context.addInstruction(new LlvmIntToPtr( + namespaceStructPointer, + LlvmCodeGenTypes.VALUE_TYPE, + namespace + )); + + var fieldPointerResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.FIELD_POINTER, + fieldName + ); + var fieldPointer = fieldPointerResult.value(); + context = fieldPointerResult.context(); + + var fieldResult = context.generateVariableLocal( + LlvmCodeGenLocalVariableSpace.FIELD, + fieldName + ); + var field = fieldResult.value(); + context = fieldResult.context(); + + return context.addInstruction(new LlvmGetElementPtr( + fieldPointer, + typeNamespacePointer(namespaceTypeInfo), + namespaceStructPointer, + List.of( + LlvmTypedOperand.arrayIndex(0), + LlvmTypedOperand.structureIndex(namespaceTypeInfo.fieldIndex(fieldName)) + ) + )).addInstruction(new LlvmLoad( + field, + LlvmCodeGenTypes.VALUE_TYPE, + fieldPointer + )).toResult(field); + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenResult.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenResult.java new file mode 100644 index 00000000..f52c05ec --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenResult.java @@ -0,0 +1,7 @@ +package org.shedlang.compiler.backends.llvm; + +public record LlvmCodeGenResult( + T value, + LlvmCodeGenContext context +) { +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenRuntime.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenRuntime.java new file mode 100644 index 00000000..3e9c86de --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenRuntime.java @@ -0,0 +1,32 @@ +package org.shedlang.compiler.backends.llvm; + +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmCall; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmTypedOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariable; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; + +import java.util.List; + +public class LlvmCodeGenRuntime { + private LlvmCodeGenRuntime() { + } + + public static LlvmCodeGenContext callAlloc( + LlvmVariable target, + LlvmType type, + LlvmOperand size, + LlvmCodeGenContext context + ) { + return context.addInstruction(new LlvmCall( + target, + type, + new LlvmVariableGlobal("shed__runtime__alloc"), + List.of( + new LlvmTypedOperand(LlvmTypes.INT_64, size) + ) + )); + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java new file mode 100644 index 00000000..8165e3c8 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java @@ -0,0 +1,70 @@ +package org.shedlang.compiler.backends.llvm; + +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.*; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypePointer; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class LlvmCodeGenStrings { + private LlvmCodeGenStrings() { + } + + public static final LlvmType TYPE_STRING_LENGTH = LlvmTypes.INT_64; + + public static LlvmType typeStringCodeUnits(int size) { + return LlvmTypes.array(size, LlvmTypes.INT_8); + } + + public static LlvmType typeStringStruct(int size) { + return LlvmTypes.structure(List.of( + TYPE_STRING_LENGTH, + typeStringCodeUnits(size) + )); + } + + public static LlvmTypePointer typeStringPointer(int size) { + return LlvmTypes.pointer(typeStringStruct(size)); + } + + public static LlvmCodeGenResult defineString(String value, LlvmCodeGenContext context) { + var codeUnits = value.getBytes(StandardCharsets.UTF_8); + + var codeUnitOperands = new ArrayList(); + for (var codeUnit : codeUnits) { + codeUnitOperands.add(new LlvmOperandInt(codeUnit)); + } + + var llvmValue = new LlvmOperandStructure(List.of( + new LlvmTypedOperand(TYPE_STRING_LENGTH, new LlvmOperandInt(codeUnits.length)), + new LlvmTypedOperand( + typeStringCodeUnits(codeUnits.length), + new LlvmOperandArray( + LlvmTypes.INT_8, + codeUnitOperands + ) + ) + )); + + var globalDefinitionBuilder = LlvmGlobalDefinitionBuilder.builder() + .namePrefix(LlvmCodeGenTopLevelEntitySpace.STRING) + .type(typeStringStruct(codeUnits.length)) + .value(llvmValue) + .isPrivate(true) + .unnamedAddr(true) + .constant(true); + + return context.addGlobalDefinition(globalDefinitionBuilder); + } + + public static LlvmOperand operandAsShedObject(LlvmGlobalDefinition globalDefinition) { + return new LlvmOperandPtrToInt( + new LlvmVariableGlobal(globalDefinition.name()), + LlvmCodeGenTypes.VALUE_TYPE + ); + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTopLevelEntitySpace.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTopLevelEntitySpace.java new file mode 100644 index 00000000..a65ae7a6 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTopLevelEntitySpace.java @@ -0,0 +1,17 @@ +package org.shedlang.compiler.backends.llvm; + +public enum LlvmCodeGenTopLevelEntitySpace { + FUNCTION("fun"), + STRING("string"); + + private final String name; + + LlvmCodeGenTopLevelEntitySpace(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java new file mode 100644 index 00000000..d8c18bed --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java @@ -0,0 +1,11 @@ +package org.shedlang.compiler.backends.llvm; + +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypeScalar; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; + +public class LlvmCodeGenTypes { + private LlvmCodeGenTypes() { + } + + public static final LlvmTypeScalar VALUE_TYPE = LlvmTypes.INT_64; +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java deleted file mode 100644 index c9d8c8ee..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java +++ /dev/null @@ -1,200 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.backends.llvm.ir.ast.*; -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturn; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandInt; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandPtrToInt; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; -import org.shedlang.compiler.stackir.instructions.*; -import org.shedlang.compiler.typechecker.TypeInfo; -import org.shedlang.compiler.types.NamespaceName; - -import java.util.*; - -import static org.shedlang.compiler.util.Lists.reversed; - -public class LlvmCompiler { - public static LlvmModule compileMain(NamespaceName main, TypeInfo typeInfo) { - var context = LlvmCompilerContext.fromTypeInfo(typeInfo); - - var mainContext = context.enterFunction(); - - var namespaceResult = LlvmCompilerNamespaces.importValue(main, mainContext); - var namespace = namespaceResult.value(); - mainContext = namespaceResult.context(); - - var fieldResult = LlvmCompilerNamespaces.fieldLoad( - main, - namespace, - // TODO: check there is a main function - "main", - mainContext - ); - var field = fieldResult.value(); - mainContext = fieldResult.context(); - - mainContext = LlvmCompilerClosures.call(field, mainContext, List.of()); - - mainContext = mainContext.addTerminatorInstruction( - new LlvmReturn(LlvmTypes.INT_32, new LlvmOperandInt(0)) - ); - - var mainBasicBlocksResult = context.exitFunction(mainContext); - var mainBasicBlocks = mainBasicBlocksResult.value(); - context = mainBasicBlocksResult.context(); - - context = context.addTopLevelEntity(new LlvmFunctionDefinition( - "main", - LlvmTypes.INT_32, - List.of(), - mainBasicBlocks - )); - - return new LlvmModule(context.topLevelEntities()); - } - - public static LlvmModule compileNamespace( - NamespaceName namespaceName, - List instructions, - TypeInfo typeInfo - ) { - var context = defaultContext(typeInfo); - for (var instruction : instructions) { - context = compileInstruction(instruction, context); - } - - context = LlvmCompilerNamespaces.define(namespaceName, context); - - var topLevelEntities = context.topLevelEntities(); - - return new LlvmModule(topLevelEntities); - } - - private static LlvmCompilerContext defaultContext(TypeInfo typeInfo) { - return LlvmCompilerContext.fromTypeInfo(typeInfo) - .addTopLevelEntity(new LlvmFunctionDeclaration( - "shed__runtime__alloc", - LlvmTypes.pointer(LlvmTypes.INT_8), - List.of(new LlvmParam(LlvmTypes.INT_64, "size")) - )) - .addTopLevelEntity(new LlvmGlobalDefinition( - "shed__runtime__print_closure", - new LlvmCompilerClosures.Types(Optional.of(FreeVariables.empty())).closureStruct(), - Optional.empty(), - false, - false, - false - )) - .addLocal("print", new LlvmOperandPtrToInt( - new LlvmVariableGlobal("shed__runtime__print_closure"), - LlvmCompilerTypes.VALUE_TYPE - )); - } - - public static LlvmCompilerContext compileInstruction(Instruction instruction, LlvmCompilerContext context) { - return switch (instruction) { - case CallInstruction call -> { - var namedArgsByName = new HashMap(); - for (var argName : reversed(call.namedArgNames())) { - var argResult = context.pop(); - var arg = argResult.value(); - context = argResult.context(); - namedArgsByName.put(argName, arg); - } - var namedArgs = namedArgsByName.entrySet() - .stream().sorted(Map.Entry.comparingByKey()) - .map(x -> x.getValue()) - .toList(); - - var args = new ArrayList(); - for (var i = 0; i < call.positionalArgCount(); i++) { - var argResult = context.pop(); - var arg = argResult.value(); - context = argResult.context(); - args.add(arg); - } - Collections.reverse(args); - args.addAll(namedArgs); - - var receiverResult = context.pop(); - var receiver = receiverResult.value(); - context = receiverResult.context(); - - yield LlvmCompilerClosures.call( - receiver, - context, - args - ); - } - case DefineFunctionInstruction defineFunction -> { - yield LlvmCompilerClosures.create( - defineFunction.name(), - defineFunction.freeVariables(), - functionContext -> { - for (var bodyInstruction : defineFunction.body()) { - functionContext = compileInstruction(bodyInstruction, functionContext); - } - return functionContext; - }, - context - ); - } - case DiscardInstruction discardInstruction -> - context.pop().context(); - - case LocalLoadInstruction localLoad -> - context.push(context.local(localLoad.name())); - - case LocalStoreInstruction localStore -> { - var result = context.pop(); - var value = result.value(); - context = result.context(); - - yield context.addLocal(localStore.name(), value); - } - - case NamespaceFieldStoreInstruction namespaceFieldStore -> { - var popResult = context.pop(); - var fieldValue = popResult.value(); - context = popResult.context(); - - yield LlvmCompilerNamespaces.fieldStore( - namespaceFieldStore.namespaceName(), - namespaceFieldStore.fieldName(), - fieldValue, - context - ); - } - - case PushBoolInstruction pushBool -> - context.push(new LlvmOperandInt(pushBool.value() ? 1 : 0)); - - case PushIntInstruction pushInt -> - context.push(new LlvmOperandInt(pushInt.value().longValueExact())); - - case PushStringInstruction pushString -> { - var result = LlvmCompilerStrings.defineString(pushString.value(), context); - var globalDefinition = result.value(); - context = result.context(); - - yield context.push(LlvmCompilerStrings.operandAsShedObject(globalDefinition)); - } - - case PushUnitInstruction pushUnit -> - context.push(new LlvmOperandInt(0)); - - case ReturnInstruction returnInstruction -> { - var result = context.pop(); - var value = result.value(); - context = result.context(); - - yield context.addTerminatorInstruction( - new LlvmReturn(LlvmCompilerTypes.VALUE_TYPE, value) - ); - } - }; - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerClosures.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerClosures.java deleted file mode 100644 index 1f977db2..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerClosures.java +++ /dev/null @@ -1,393 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.shedlang.compiler.ast.typed.FreeVariable; -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmParam; -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.*; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmTypedOperand; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableLocal; -import org.shedlang.compiler.backends.llvm.ir.ast.types.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; - -public class LlvmCompilerClosures { - private LlvmCompilerClosures() { - } - - public record Types(Optional freeVariables) { - public LlvmTypePointer closurePointer() { - return LlvmTypes.pointer(closureStruct()); - } - - public LlvmTypeStructure closureStruct() { - return LlvmTypes.structure(List.of( - closureFunctionPointer(), - closureEnvironment() - )); - } - - public LlvmTypePointer closureFunctionPointer() { - return LlvmTypes.pointer(closureFunction()); - } - - public LlvmTypeFunction closureFunction() { - return LlvmTypes.function( - LlvmCompilerTypes.VALUE_TYPE, - List.of(closureEnvironmentPointer()) - ); - } - - public LlvmTypePointer closureEnvironmentPointer() { - return LlvmTypes.pointer(closureEnvironment()); - } - - public LlvmTypeArray closureEnvironment() { - return LlvmTypes.array(freeVariables.map(x -> x.size()).orElse(0), LlvmCompilerTypes.VALUE_TYPE); - } - } - - public static final Types CALLABLE_TYPES = new Types(Optional.empty()); - - public static Types types(FreeVariables freeVariables) { - return new Types(Optional.of(freeVariables)); - } - - public static Types types(Optional freeVariables) { - return new Types(freeVariables); - } - - public static LlvmCompilerContext create( - String name, - FreeVariables freeVariables, - Function compileBody, - LlvmCompilerContext context - ) { - var closureTypes = LlvmCompilerClosures.types(freeVariables); - - var topLevelEntityName = context.generateTopLevelEntityName( - LlvmCompilerTopLevelEntitySpace.FUNCTION, - name - ); - - var functionContext = context.enterFunction(); - var functionClosurePointerResult = functionContext.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_POINTER - ); - var functionClosurePointer = functionClosurePointerResult.value(); - functionContext = functionClosurePointerResult.context(); - - for (var freeVariable : freeVariables) { - functionContext = loadClosureFreeVariable( - functionClosurePointer, - freeVariable, - closureTypes, - functionContext - ); - } - - functionContext = compileBody.apply(functionContext); - var bodyResult = context.exitFunction(functionContext); - var body = bodyResult.value(); - context = bodyResult.context(); - - context = context.addTopLevelEntity(new LlvmFunctionDefinition( - topLevelEntityName, - LlvmCompilerTypes.VALUE_TYPE, - List.of( - new LlvmParam( - closureTypes.closurePointer(), - functionClosurePointer.name() - ) - ), - body - )); - - var closurePointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_POINTER - ); - var closurePointer = closurePointerResult.value(); - context = closurePointerResult.context(); - - var closureSizeResult = LlvmSizeOf.sizeOf( - closureTypes.closureStruct(), - context - ); - var closureSize = closureSizeResult.value(); - context = closureSizeResult.context(); - - context = LlvmCompilerRuntime.callAlloc( - closurePointer, - closureTypes.closurePointer(), - closureSize, - context - ); - - context = storeClosureFunctionPointer( - closurePointer, - closureTypes, - new LlvmVariableGlobal(topLevelEntityName), - context - ); - - for (var freeVariable : freeVariables) { - context = storeClosureFreeVariable( - closurePointer, - freeVariable, - closureTypes, - context - ); - } - - var closureValueResult = castClosurePointerToValue(closurePointer, context); - var closureValue = closureValueResult.value(); - context = closureValueResult.context(); - - context = context.push(closureValue); - - return context; - } - - public static LlvmCompilerContext call( - LlvmOperand closure, - LlvmCompilerContext context, - List args - ) { - var closurePointerResult = castValueToClosurePointer(closure, context); - var closurePointer = closurePointerResult.value(); - context = closurePointerResult.context(); - - var functionPointerResult = loadClosureFunctionPointer(closurePointer, context); - var functionPointer = functionPointerResult.value(); - context = functionPointerResult.context(); - - var callTargetResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.TEMPORARY - ); - var callTarget = callTargetResult.value(); - context = callTargetResult.context(); - - var fullArgs = new ArrayList(); - fullArgs.add(new LlvmTypedOperand(CALLABLE_TYPES.closurePointer(), closurePointer)); - for (var arg : args) { - fullArgs.add(new LlvmTypedOperand(LlvmCompilerTypes.VALUE_TYPE, arg)); - } - - return context.addInstruction(new LlvmCall( - callTarget, - LlvmCompilerTypes.VALUE_TYPE, - functionPointer, - fullArgs - )).push(callTarget); - } - - private static LlvmCompilerResult castClosurePointerToValue( - LlvmOperand closurePointer, - LlvmCompilerContext context - ) { - var closureValueResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_VALUE - ); - var closureValue = closureValueResult.value(); - context = closureValueResult.context(); - - context = context.addInstruction(new LlvmPtrToInt( - closureValue, - closurePointer, - LlvmCompilerTypes.VALUE_TYPE - )); - - return context.toResult(closureValue); - } - - private static LlvmCompilerResult castValueToClosurePointer( - LlvmOperand value, - LlvmCompilerContext context - ) { - var closurePointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_POINTER - ); - var closurePointer = closurePointerResult.value(); - context = closurePointerResult.context(); - - context = context.addInstruction(new LlvmIntToPtr( - closurePointer, - LlvmCompilerTypes.VALUE_TYPE, - value - )); - - return context.toResult(closurePointer); - } - - private static LlvmCompilerContext storeClosureFunctionPointer( - LlvmOperand closurePointer, - Types closureTypes, - LlvmOperand function, - LlvmCompilerContext context - ) { - var closureFunctionPointerPointerResult = getClosureFunctionPointerPointer( - closurePointer, - closureTypes, - context - ); - var closureFunctionPointerPointer = closureFunctionPointerPointerResult.value(); - context = closureFunctionPointerPointerResult.context(); - - return context.addInstruction(new LlvmStore( - closureTypes.closureFunctionPointer(), - function, - closureFunctionPointerPointer - )); - } - - private static LlvmCompilerResult loadClosureFunctionPointer( - LlvmOperand closurePointer, - LlvmCompilerContext context - ) { - var functionPointerPointerResult = getClosureFunctionPointerPointer( - closurePointer, - CALLABLE_TYPES, - context - ); - var functionPointerPointer = functionPointerPointerResult.value(); - context = functionPointerPointerResult.context(); - - var functionPointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_FUNCTION_POINTER - ); - var functionPointer = functionPointerResult.value(); - context = functionPointerResult.context(); - - return context.addInstruction(new LlvmLoad( - functionPointer, - CALLABLE_TYPES.closureFunctionPointer(), - functionPointerPointer - )).toResult(functionPointer); - } - - private static LlvmCompilerResult getClosureFunctionPointerPointer( - LlvmOperand closurePointer, - Types closureTypes, - LlvmCompilerContext context - ) { - var functionPointerPointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_FUNCTION_POINTER_POINTER - ); - var functionPointerPointer = functionPointerPointerResult.value(); - context = functionPointerPointerResult.context(); - - context = context.addInstruction(new LlvmGetElementPtr( - functionPointerPointer, - closureTypes.closurePointer(), - closurePointer, - List.of(LlvmTypedOperand.arrayIndex(0), LlvmTypedOperand.structureIndex(0)) - )); - - return context.toResult(functionPointerPointer); - } - - private static LlvmCompilerResult getClosureEnvironmentPointer( - LlvmOperand closurePointer, - LlvmCompilerContext context - ) { - var environmentPointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_ENVIRONMENT_POINTER - ); - var environmentPointer = environmentPointerResult.value(); - context = environmentPointerResult.context(); - - context = context.addInstruction(new LlvmGetElementPtr( - environmentPointer, - CALLABLE_TYPES.closurePointer(), - closurePointer, - List.of(LlvmTypedOperand.arrayIndex(0), LlvmTypedOperand.structureIndex(1)) - )); - - return context.toResult(environmentPointer); - } - - private static LlvmCompilerContext storeClosureFreeVariable( - LlvmOperand closurePointer, - FreeVariable freeVariable, - Types closureTypes, - LlvmCompilerContext context - ) { - var closureEnvironmentPointerResult = getClosureFreeVariablePointer( - closurePointer, - freeVariable, - closureTypes, - context - ); - var closureEnvironmentPointer = closureEnvironmentPointerResult.value(); - context = closureEnvironmentPointerResult.context(); - - return context.addInstruction(new LlvmStore( - LlvmCompilerTypes.VALUE_TYPE, - context.local(freeVariable.name()), - closureEnvironmentPointer - )); - } - - private static LlvmCompilerContext loadClosureFreeVariable( - LlvmOperand closurePointer, - FreeVariable freeVariable, - Types closureTypes, - LlvmCompilerContext context - ) { - var closureFreeVariablePointerResult = getClosureFreeVariablePointer( - closurePointer, - freeVariable, - closureTypes, - context - ); - var closureFreeVariablePointer = closureFreeVariablePointerResult.value(); - context = closureFreeVariablePointerResult.context(); - - var closureFreeVariableResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_FREE_VARIABLE, - freeVariable.name() - ); - var closureFreeVariable = closureFreeVariableResult.value(); - context = closureFreeVariableResult.context(); - - context = context.addInstruction(new LlvmLoad( - closureFreeVariable, - LlvmCompilerTypes.VALUE_TYPE, - closureFreeVariablePointer - )); - - return context.addLocal(freeVariable.name(), closureFreeVariable); - } - - private static LlvmCompilerResult getClosureFreeVariablePointer( - LlvmOperand closurePointer, - FreeVariable freeVariable, - Types closureTypes, - LlvmCompilerContext context - ) { - var freeVariablePointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.CLOSURE_FREE_VARIABLE_POINTER, - freeVariable.name() - ); - var freeVariablePointer = freeVariablePointerResult.value(); - context = freeVariablePointerResult.context(); - - context = context.addInstruction(new LlvmGetElementPtr( - freeVariablePointer, - closureTypes.closurePointer(), - closurePointer, - List.of( - LlvmTypedOperand.arrayIndex(0), - LlvmTypedOperand.structureIndex(1), - LlvmTypedOperand.arrayIndex(freeVariable.index()) - ) - )); - - return context.toResult(freeVariablePointer); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java deleted file mode 100644 index e884d9e8..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.pcollections.Empty; -import org.pcollections.PMap; -import org.pcollections.PStack; -import org.pcollections.PVector; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmBasicBlock; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmTopLevelEntity; -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmInstruction; -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmTerminatorInstruction; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableLocal; -import org.shedlang.compiler.typechecker.TypeInfo; -import org.shedlang.compiler.util.POrderedMap; - -import java.util.List; -import java.util.Optional; - -public record LlvmCompilerContext( - TypeInfo typeInfo, - PStack stack, - PMap locals, - PVector basicBlocks, - PVector instructions, - POrderedMap topLevelEntitiesByName, - NameAllocator localVariableNames -) { - public static LlvmCompilerContext EMPTY = fromTypeInfo(TypeInfo.EMPTY); - - public static LlvmCompilerContext fromTypeInfo(TypeInfo typeInfo) { - return new LlvmCompilerContext( - typeInfo, - Empty.stack(), - Empty.map(), - Empty.vector(), - Empty.vector(), - POrderedMap.empty(), - NameAllocator.empty() - ); - } - - public LlvmCompilerContext push(LlvmOperand operand) { - return new LlvmCompilerContext( - typeInfo, - stack.plus(operand), - locals, - basicBlocks, - instructions, - topLevelEntitiesByName, - localVariableNames - ); - } - - public LlvmCompilerResult pop() { - return new LlvmCompilerContext( - typeInfo, - stack.minus(0), - locals, - basicBlocks, - instructions, - topLevelEntitiesByName, - localVariableNames - ).toResult(stack.get(0)); - } - - public LlvmCompilerContext addLocal(String name, LlvmOperand value) { - return new LlvmCompilerContext( - typeInfo, - stack, - locals.plus(name, value), - basicBlocks, - instructions, - topLevelEntitiesByName, - localVariableNames - ); - } - - public LlvmOperand local(String name) { - var local = locals.get(name); - if (local == null) { - // TODO: better error - throw new RuntimeException("unrecognised local: " + name); - } else { - return local; - } - } - - public LlvmCompilerContext addInstruction(LlvmInstruction instruction) { - return new LlvmCompilerContext( - typeInfo, - stack, - locals, - basicBlocks, - instructions.plus(instruction), - topLevelEntitiesByName, - localVariableNames - ); - } - - public LlvmCompilerContext addTerminatorInstruction( - LlvmTerminatorInstruction terminatorInstruction - ) { - return new LlvmCompilerContext( - typeInfo, - stack, - locals, - basicBlocks.plus(new LlvmBasicBlock( - Optional.empty(), - instructions, - terminatorInstruction - )), - Empty.vector(), - topLevelEntitiesByName, - localVariableNames - ); - } - - public LlvmCompilerResult addGlobalDefinition( - LlvmGlobalDefinitionBuilder builder - ) { - var globalDefinition = new LlvmGlobalDefinition( - generateTopLevelEntityName(builder.namePrefix().orElseThrow()), - builder.type().orElseThrow(), - builder.value(), - builder.constant(), - builder.isPrivate(), - builder.unnamedAddr() - ); - - return addTopLevelEntity(globalDefinition).toResult(globalDefinition); - } - - public LlvmCompilerContext addTopLevelEntity(LlvmTopLevelEntity topLevelEntity) { - return new LlvmCompilerContext( - typeInfo, - stack, - locals, - basicBlocks, - instructions, - topLevelEntitiesByName.plus(topLevelEntity.name(), topLevelEntity), - localVariableNames - ); - } - - public String generateTopLevelEntityName(LlvmCompilerTopLevelEntitySpace space, String name) { - return generateTopLevelEntityName(space, Optional.of(name)); - } - - private String generateTopLevelEntityName(LlvmCompilerTopLevelEntitySpace space) { - return generateTopLevelEntityName(space, Optional.empty()); - } - - private String generateTopLevelEntityName( - LlvmCompilerTopLevelEntitySpace space, - Optional name - ) { - return NameAllocator.generateName( - topLevelEntitiesByName::containsKey, - "shed__" + space, - name - ); - } - - public boolean hasTopLevelEntity(String name) { - return topLevelEntitiesByName.containsKey(name); - } - - public List topLevelEntities() { - return topLevelEntitiesByName.toValues(); - } - - public LlvmCompilerResult generateVariableLocal( - LlvmCompilerLocalVariableSpace space - ) { - return generateVariableLocal(space, Optional.empty()); - } - - public LlvmCompilerResult generateVariableLocal( - LlvmCompilerLocalVariableSpace space, - String name - ) { - return generateVariableLocal(space, Optional.of(name)); - } - - private LlvmCompilerResult generateVariableLocal( - LlvmCompilerLocalVariableSpace space, - Optional name - ) { - var result = localVariableNames.generateName(space, name); - return new LlvmCompilerContext( - typeInfo, - stack, - locals, - basicBlocks, - instructions, - topLevelEntitiesByName, - result.allocator() - ).toResult(new LlvmVariableLocal(result.name())); - } - - public LlvmCompilerResult toResult(T value) { - return new LlvmCompilerResult<>(value, this); - } - - public LlvmCompilerContext enterFunction() { - return new LlvmCompilerContext( - typeInfo, - Empty.stack(), - Empty.map(), - Empty.vector(), - Empty.vector(), - topLevelEntitiesByName, - NameAllocator.empty() - ); - } - - public LlvmCompilerResult> exitFunction( - LlvmCompilerContext functionContext - ) { - return new LlvmCompilerContext( - typeInfo, - stack, - locals, - basicBlocks, - instructions, - functionContext.topLevelEntitiesByName, - localVariableNames - ).toResult(functionContext.basicBlocks); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java deleted file mode 100644 index 70cd13bc..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -public enum LlvmCompilerLocalVariableSpace { - CLOSURE_VALUE("closureValue"), - CLOSURE_POINTER("closurePointer"), - CLOSURE_FUNCTION_POINTER("closureFunctionPointer"), - CLOSURE_FUNCTION_POINTER_POINTER("closureFunctionPointerPointer"), - CLOSURE_ENVIRONMENT_POINTER("closureEnvironmentPointer"), - CLOSURE_FREE_VARIABLE_POINTER("closureFreeVariablePointer"), - CLOSURE_FREE_VARIABLE("closureFreeVariable"), - FIELD("field"), - FIELD_POINTER("fieldPointer"), - NAMESPACE("namespace"), - NAMESPACE_STRUCT_POINTER("namespaceStructPointer"), - SIZE_PTR("sizePtr"), - SIZE("size"), - TEMPORARY("tmp"); - - private final String name; - - LlvmCompilerLocalVariableSpace(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java deleted file mode 100644 index 7432ac35..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java +++ /dev/null @@ -1,280 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmBasicBlock; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDeclaration; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition; -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.*; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.*; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypePointer; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypeStructure; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; -import org.shedlang.compiler.types.NamespaceName; -import org.shedlang.compiler.types.NamespaceTypeInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.stream.IntStream; - -public class LlvmCompilerNamespaces { - private LlvmCompilerNamespaces() { - } - - private static LlvmTypePointer typeNamespacePointer(NamespaceTypeInfo namespaceTypeInfo) { - return new LlvmTypePointer(typeNamespaceStruct(namespaceTypeInfo)); - } - - private static LlvmType typeNamespaceStruct(NamespaceTypeInfo namespaceTypeInfo) { - return new LlvmTypeStructure(Collections.nCopies( - namespaceTypeInfo.fieldCount(), - LlvmCompilerTypes.VALUE_TYPE - )); - } - - private static LlvmOperand operandNamespaceValue(NamespaceName namespaceName) { - return new LlvmOperandPtrToInt( - operandNamespaceStruct(namespaceName), - LlvmCompilerTypes.VALUE_TYPE - ); - } - - private static LlvmOperand operandNamespaceStruct(NamespaceName namespaceName) { - return new LlvmVariableGlobal(globalNameNamespaceValue(namespaceName)); - } - - private static String globalNameNamespaceValue(NamespaceName namespaceName) { - return "shed__namespace__" + namespaceNameToLlvmIdentifier(namespaceName); - } - - public static String globalNameNamespaceImport(NamespaceName namespaceName) { - return "shed__namespaceImport__" + namespaceNameToLlvmIdentifier(namespaceName); - } - - private static String globalNameNamespaceInit(NamespaceName namespaceName) { - return "shed__namespaceInit__" + namespaceNameToLlvmIdentifier(namespaceName); - } - - private static String globalNameNamespaceIsInited(NamespaceName namespaceName) { - return "shed__namespaceIsInited__" + namespaceNameToLlvmIdentifier(namespaceName); - } - - private static String namespaceNameToLlvmIdentifier(NamespaceName namespaceName) { - return String.join("_", namespaceName.parts()); - } - - public static LlvmCompilerResult importValue( - NamespaceName namespaceName, - LlvmCompilerContext context - ) { - var importName = globalNameNamespaceImport(namespaceName); - - if (!context.hasTopLevelEntity(importName)) { - context = context.addTopLevelEntity(new LlvmFunctionDeclaration( - importName, - LlvmCompilerTypes.VALUE_TYPE, - List.of() - )); - } - - var namespaceResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.NAMESPACE, - namespaceNameToLlvmIdentifier(namespaceName) - ); - var namespace = namespaceResult.value(); - context = namespaceResult.context(); - - return context.addInstruction(new LlvmCall( - namespace, - LlvmCompilerTypes.VALUE_TYPE, - new LlvmVariableGlobal(importName), - List.of() - )).toResult(namespace); - } - - public static LlvmCompilerContext define( - NamespaceName namespaceName, - LlvmCompilerContext context - ) { - context = context.addInstruction(new LlvmStore( - LlvmTypes.INT_1, - new LlvmOperandInt(1), - new LlvmVariableGlobal(globalNameNamespaceIsInited(namespaceName)) - )); - context = context.addTerminatorInstruction(new LlvmReturnVoid()); - var basicBlocks = context.basicBlocks(); - var namespaceInitFunction = new LlvmFunctionDefinition( - globalNameNamespaceInit(namespaceName), - LlvmTypes.VOID, - List.of(), - basicBlocks - ); - - var namespaceImportFunction = new LlvmFunctionDefinition( - globalNameNamespaceImport(namespaceName), - LlvmCompilerTypes.VALUE_TYPE, - List.of(), - List.of( - new LlvmBasicBlock( - Optional.empty(), - List.of( - new LlvmLoad( - new LlvmVariableLocal("isInited"), - LlvmTypes.INT_1, - new LlvmVariableGlobal(globalNameNamespaceIsInited(namespaceName)) - ) - ), - new LlvmBr( - new LlvmVariableLocal("isInited"), - "inited", - "init" - ) - ), - new LlvmBasicBlock( - Optional.of("init"), - List.of( - new LlvmCall( - Optional.empty(), - LlvmTypes.VOID, - new LlvmVariableGlobal(globalNameNamespaceInit(namespaceName)), - List.of() - ) - ), - new LlvmBrUnconditional("inited") - ), - new LlvmBasicBlock( - Optional.of("inited"), - List.of(), - new LlvmReturn( - LlvmCompilerTypes.VALUE_TYPE, - operandNamespaceValue(namespaceName) - ) - ) - ) - ); - - return context - .addTopLevelEntity(defineNamespaceIsInited(namespaceName)) - .addTopLevelEntity(defineNamespaceValue( - namespaceName, - context.typeInfo().namespaceTypeInfo(namespaceName) - )) - .addTopLevelEntity(namespaceInitFunction) - .addTopLevelEntity(namespaceImportFunction); - } - - private static LlvmGlobalDefinition defineNamespaceIsInited( - NamespaceName namespaceName - ) { - return new LlvmGlobalDefinition( - globalNameNamespaceIsInited(namespaceName), - LlvmTypes.INT_1, - Optional.of(new LlvmOperandInt(0)), - false, - true, - true - ); - } - - private static LlvmGlobalDefinition defineNamespaceValue( - NamespaceName namespaceName, - NamespaceTypeInfo namespaceTypeInfo - ) { - return new LlvmGlobalDefinition( - globalNameNamespaceValue(namespaceName), - typeNamespaceStruct(namespaceTypeInfo), - Optional.of(new LlvmOperandStructure( - IntStream.range(0, namespaceTypeInfo.fieldCount()) - .mapToObj(ignored -> new LlvmTypedOperand( - LlvmCompilerTypes.VALUE_TYPE, - new LlvmOperandInt(0) - )) - .toList() - )), - false, - true, - true - ); - } - - public static LlvmCompilerContext fieldStore( - NamespaceName namespaceName, - String fieldName, - LlvmOperand fieldValue, - LlvmCompilerContext context - ) { - var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); - - var fieldPointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.FIELD_POINTER, - fieldName - ); - var fieldPointer = fieldPointerResult.value(); - context = fieldPointerResult.context(); - - return context.addInstruction(new LlvmGetElementPtr( - fieldPointer, - typeNamespacePointer(namespaceTypeInfo), - operandNamespaceStruct(namespaceName), - List.of( - LlvmTypedOperand.arrayIndex(0), - LlvmTypedOperand.structureIndex(namespaceTypeInfo.fieldIndex(fieldName)) - ) - )).addInstruction(new LlvmStore( - LlvmCompilerTypes.VALUE_TYPE, - fieldValue, - fieldPointer - )); - } - - public static LlvmCompilerResult fieldLoad( - NamespaceName namespaceName, - LlvmOperand namespace, - String fieldName, - LlvmCompilerContext context - ) { - var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); - - var namespaceStructPointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.NAMESPACE_STRUCT_POINTER, - String.join("_", namespaceName.parts()) - ); - var namespaceStructPointer = namespaceStructPointerResult.value(); - context = namespaceStructPointerResult.context(); - - context = context.addInstruction(new LlvmIntToPtr( - namespaceStructPointer, - LlvmCompilerTypes.VALUE_TYPE, - namespace - )); - - var fieldPointerResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.FIELD_POINTER, - fieldName - ); - var fieldPointer = fieldPointerResult.value(); - context = fieldPointerResult.context(); - - var fieldResult = context.generateVariableLocal( - LlvmCompilerLocalVariableSpace.FIELD, - fieldName - ); - var field = fieldResult.value(); - context = fieldResult.context(); - - return context.addInstruction(new LlvmGetElementPtr( - fieldPointer, - typeNamespacePointer(namespaceTypeInfo), - namespaceStructPointer, - List.of( - LlvmTypedOperand.arrayIndex(0), - LlvmTypedOperand.structureIndex(namespaceTypeInfo.fieldIndex(fieldName)) - ) - )).addInstruction(new LlvmLoad( - field, - LlvmCompilerTypes.VALUE_TYPE, - fieldPointer - )).toResult(field); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerResult.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerResult.java deleted file mode 100644 index b0d7e1b8..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerResult.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -public record LlvmCompilerResult( - T value, - LlvmCompilerContext context -) { -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerRuntime.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerRuntime.java deleted file mode 100644 index 2a9d842a..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerRuntime.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmCall; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmTypedOperand; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariable; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; - -import java.util.List; - -public class LlvmCompilerRuntime { - private LlvmCompilerRuntime() { - } - - public static LlvmCompilerContext callAlloc( - LlvmVariable target, - LlvmType type, - LlvmOperand size, - LlvmCompilerContext context - ) { - return context.addInstruction(new LlvmCall( - target, - type, - new LlvmVariableGlobal("shed__runtime__alloc"), - List.of( - new LlvmTypedOperand(LlvmTypes.INT_64, size) - ) - )); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerStrings.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerStrings.java deleted file mode 100644 index f5df0ce4..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerStrings.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.*; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypePointer; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -public class LlvmCompilerStrings { - private LlvmCompilerStrings() { - } - - public static final LlvmType TYPE_STRING_LENGTH = LlvmTypes.INT_64; - - public static LlvmType typeStringCodeUnits(int size) { - return LlvmTypes.array(size, LlvmTypes.INT_8); - } - - public static LlvmType typeStringStruct(int size) { - return LlvmTypes.structure(List.of( - TYPE_STRING_LENGTH, - typeStringCodeUnits(size) - )); - } - - public static LlvmTypePointer typeStringPointer(int size) { - return LlvmTypes.pointer(typeStringStruct(size)); - } - - public static LlvmCompilerResult defineString(String value, LlvmCompilerContext context) { - var codeUnits = value.getBytes(StandardCharsets.UTF_8); - - var codeUnitOperands = new ArrayList(); - for (var codeUnit : codeUnits) { - codeUnitOperands.add(new LlvmOperandInt(codeUnit)); - } - - var llvmValue = new LlvmOperandStructure(List.of( - new LlvmTypedOperand(TYPE_STRING_LENGTH, new LlvmOperandInt(codeUnits.length)), - new LlvmTypedOperand( - typeStringCodeUnits(codeUnits.length), - new LlvmOperandArray( - LlvmTypes.INT_8, - codeUnitOperands - ) - ) - )); - - var globalDefinitionBuilder = LlvmGlobalDefinitionBuilder.builder() - .namePrefix(LlvmCompilerTopLevelEntitySpace.STRING) - .type(typeStringStruct(codeUnits.length)) - .value(llvmValue) - .isPrivate(true) - .unnamedAddr(true) - .constant(true); - - return context.addGlobalDefinition(globalDefinitionBuilder); - } - - public static LlvmOperand operandAsShedObject(LlvmGlobalDefinition globalDefinition) { - return new LlvmOperandPtrToInt( - new LlvmVariableGlobal(globalDefinition.name()), - LlvmCompilerTypes.VALUE_TYPE - ); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java deleted file mode 100644 index 87b0a60b..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -public enum LlvmCompilerTopLevelEntitySpace { - FUNCTION("fun"), - STRING("string"); - - private final String name; - - LlvmCompilerTopLevelEntitySpace(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTypes.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTypes.java deleted file mode 100644 index 3623d829..00000000 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTypes.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.shedlang.compiler.backends.llvm; - -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypeScalar; -import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; - -public class LlvmCompilerTypes { - private LlvmCompilerTypes() { - } - - public static final LlvmTypeScalar VALUE_TYPE = LlvmTypes.INT_64; -} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmGlobalDefinitionBuilder.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmGlobalDefinitionBuilder.java index 42c692c6..b559c315 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmGlobalDefinitionBuilder.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmGlobalDefinitionBuilder.java @@ -6,7 +6,7 @@ import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; import java.util.Optional; public record LlvmGlobalDefinitionBuilder( - Optional namePrefix, + Optional namePrefix, Optional type, Optional value, boolean constant, @@ -24,7 +24,7 @@ public record LlvmGlobalDefinitionBuilder( ); } - public LlvmGlobalDefinitionBuilder namePrefix(LlvmCompilerTopLevelEntitySpace namePrefix) { + public LlvmGlobalDefinitionBuilder namePrefix(LlvmCodeGenTopLevelEntitySpace namePrefix) { return new LlvmGlobalDefinitionBuilder( Optional.of(namePrefix), this.type, diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmSizeOf.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmSizeOf.java index 53d565f7..d59ea616 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmSizeOf.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmSizeOf.java @@ -14,12 +14,12 @@ public class LlvmSizeOf { private LlvmSizeOf() { } - public static LlvmCompilerResult sizeOf(LlvmType type, LlvmCompilerContext context) { - var sizePtrResult = context.generateVariableLocal(LlvmCompilerLocalVariableSpace.SIZE_PTR); + public static LlvmCodeGenResult sizeOf(LlvmType type, LlvmCodeGenContext context) { + var sizePtrResult = context.generateVariableLocal(LlvmCodeGenLocalVariableSpace.SIZE_PTR); var sizePtr = sizePtrResult.value(); context = sizePtrResult.context(); - var sizeResult = context.generateVariableLocal(LlvmCompilerLocalVariableSpace.SIZE); + var sizeResult = context.generateVariableLocal(LlvmCodeGenLocalVariableSpace.SIZE); var size = sizeResult.value(); context = sizeResult.context(); -- cgit v1.2.3