From 685d5c6d2faafba1bac8cd23baecb3b5f1ce792a Mon Sep 17 00:00:00 2001 From: Alexander Stekelenburg Date: Thu, 22 Feb 2024 11:14:54 +0100 Subject: [PATCH] Rename VCLLVM to Pallas, Update to LLVM 17, Implement Stack Allocation --- .clang-format | 236 +++++++++ .github/workflows/release.yml | 6 +- .github/workflows/scalatest.yml | 22 +- build.sc | 223 ++++---- src/col/vct/col/ast/Node.scala | 206 ++++++-- .../expr/context/AmbiguousResultImpl.scala | 4 +- src/col/vct/col/ast/expr/op/BinExprImpl.scala | 13 + .../family/coercion/CoerceLLVMArrayImpl.scala | 8 + .../coercion/CoerceLLVMIntIntImpl.scala | 9 + .../coercion/CoerceLLVMPointerImpl.scala | 9 + .../ast/family/coercion/CoercionImpl.scala | 3 + .../col/ast/lang/llvm/LLVMAllocAImpl.scala | 9 + ...LLVMAmbiguousFunctionInvocationImpl.scala} | 18 +- .../ast/lang/llvm/LLVMArrayValueImpl.scala | 11 + .../vct/col/ast/lang/llvm/LLVMExprImpl.scala | 7 + .../lang/llvm/LLVMFunctionContractImpl.scala | 9 + .../llvm/LLVMFunctionDefinitionImpl.scala | 16 + ...scala => LLVMFunctionInvocationImpl.scala} | 8 +- .../llvm/LLVMFunctionPointerValueImpl.scala | 12 + .../lang/llvm/LLVMGetElementPointerImpl.scala | 11 + .../llvm/LLVMGlobalSpecificationImpl.scala | 12 + .../lang/llvm/LLVMGlobalVariableImpl.scala | 10 + .../ast/lang/llvm/LLVMIntegerValueImpl.scala | 11 + .../vct/col/ast/lang/llvm/LLVMLoadImpl.scala | 9 + ...lvmLocalImpl.scala => LLVMLocalImpl.scala} | 8 +- .../ast/lang/llvm/LLVMLoopContractImpl.scala | 9 + .../vct/col/ast/lang/llvm/LLVMLoopImpl.scala | 9 + .../ast/lang/llvm/LLVMLoopInvariantImpl.scala | 9 + .../ast/lang/llvm/LLVMMemoryAcquireImpl.scala | 10 + .../llvm/LLVMMemoryAcquireReleaseImpl.scala | 10 + .../lang/llvm/LLVMMemoryMonotonicImpl.scala | 10 + .../lang/llvm/LLVMMemoryNotAtomicImpl.scala | 10 + .../lang/llvm/LLVMMemoryOrderingImpl.scala | 10 + .../ast/lang/llvm/LLVMMemoryReleaseImpl.scala | 10 + ...LLVMMemorySequentiallyConsistentImpl.scala | 11 + .../lang/llvm/LLVMMemoryUnorderedImpl.scala | 10 + .../ast/lang/llvm/LLVMPointerValueImpl.scala | 23 + .../ast/lang/llvm/LLVMRawArrayValueImpl.scala | 11 + .../lang/llvm/LLVMRawVectorValueImpl.scala | 11 + .../ast/lang/llvm/LLVMSignExtendImpl.scala | 11 + ...nImpl.scala => LLVMSpecFunctionImpl.scala} | 10 +- .../col/ast/lang/llvm/LLVMStatementImpl.scala | 7 + .../vct/col/ast/lang/llvm/LLVMStoreImpl.scala | 8 + .../ast/lang/llvm/LLVMStructValueImpl.scala | 11 + .../col/ast/lang/llvm/LLVMTArrayImpl.scala | 10 + .../col/ast/lang/llvm/LLVMTFunctionImpl.scala | 10 + .../vct/col/ast/lang/llvm/LLVMTIntImpl.scala | 10 + .../col/ast/lang/llvm/LLVMTMetadataImpl.scala | 9 + .../col/ast/lang/llvm/LLVMTPointerImpl.scala | 9 + .../col/ast/lang/llvm/LLVMTStructImpl.scala | 10 + .../col/ast/lang/llvm/LLVMTVectorImpl.scala | 10 + .../col/ast/lang/llvm/LLVMTruncateImpl.scala | 11 + .../ast/lang/llvm/LLVMVectorValueImpl.scala | 11 + .../ast/lang/llvm/LLVMZeroExtendImpl.scala | 11 + .../llvm/LLVMZeroedAggregateValueImpl.scala | 12 + .../vct/col/ast/lang/llvm/LlvmExprImpl.scala | 7 - .../lang/llvm/LlvmFunctionContractImpl.scala | 9 - .../llvm/LlvmFunctionDefinitionImpl.scala | 16 - .../col/ast/lang/llvm/LlvmGlobalImpl.scala | 12 - .../ast/lang/llvm/LlvmLoopContractImpl.scala | 9 - .../vct/col/ast/lang/llvm/LlvmLoopImpl.scala | 9 - .../ast/lang/llvm/LlvmLoopInvariantImpl.scala | 9 - .../statement/exceptional/ReturnImpl.scala | 2 +- src/col/vct/col/resolve/Resolve.scala | 78 ++- .../ctx/ReferenceResolutionContext.scala | 1 + src/col/vct/col/resolve/ctx/Referrable.scala | 55 +- src/col/vct/col/resolve/lang/LLVM.scala | 8 +- .../vct/col/serialize/SerializeOrigin.scala | 2 +- .../vct/col/typerules/CoercingRewriter.scala | 70 ++- src/col/vct/col/typerules/CoercionUtils.scala | 82 +++ src/col/vct/col/typerules/Types.scala | 3 + src/col/vct/col/util/AstBuildHelpers.scala | 8 +- src/llvm/include/Origin/ContextDeriver.h | 48 +- src/llvm/include/Origin/OriginProvider.h | 62 ++- .../include/Origin/PreferredNameDeriver.h | 25 +- .../include/Origin/ShortPositionDeriver.h | 32 +- .../Passes/Function/FunctionBodyTransformer.h | 314 ++++++------ .../Function/FunctionContractDeclarer.h | 108 ++-- .../Passes/Function/FunctionDeclarer.h | 173 ++++--- .../include/Passes/Function/PureAssigner.h | 35 +- .../Passes/Module/GlobalVariableDeclarer.h | 17 + .../Passes/Module/ModuleSpecCollector.h | 32 +- .../include/Passes/Module/ProtobufPrinter.h | 16 + .../include/Passes/Module/RootContainer.h | 28 ++ src/llvm/include/Transform/BlockTransform.h | 94 ++-- .../Transform/Instruction/BinaryOpTransform.h | 18 +- .../Transform/Instruction/CastOpTransform.h | 26 +- .../Instruction/FuncletPadOpTransform.h | 18 +- .../Transform/Instruction/MemoryOpTransform.h | 33 +- .../Transform/Instruction/OtherOpTransform.h | 65 +-- .../Transform/Instruction/TermOpTransform.h | 34 +- .../Transform/Instruction/UnaryOpTransform.h | 17 +- src/llvm/include/Transform/Transform.h | 143 +++--- src/llvm/include/Util/Constants.h | 18 +- src/llvm/include/Util/Exceptions.h | 85 +++- src/llvm/lib/Origin/ContextDeriver.cpp | 81 +++ src/llvm/lib/Origin/OriginProvider.cpp | 343 +++++++++++++ src/llvm/lib/Origin/PreferredNameDeriver.cpp | 102 ++++ src/llvm/lib/Origin/ShortPositionDeriver.cpp | 49 ++ .../Function/FunctionBodyTransformer.cpp | 185 +++++++ .../Function/FunctionContractDeclarer.cpp | 87 ++++ .../lib/Passes/Function/FunctionDeclarer.cpp | 137 +++++ src/llvm/lib/Passes/Function/PureAssigner.cpp | 59 +++ .../Passes/Module/GlobalVariableDeclarer.cpp | 49 ++ .../lib/Passes/Module/ModuleSpecCollector.cpp | 46 ++ .../lib/Passes/Module/ProtobufPrinter.cpp | 30 ++ src/llvm/lib/Passes/Module/RootContainer.cpp | 26 + src/llvm/lib/Plugin.cpp | 69 +++ src/llvm/lib/Transform/BlockTransform.cpp | 77 +++ .../Instruction/BinaryOpTransform.cpp | 82 +++ .../Transform/Instruction/CastOpTransform.cpp | 87 ++++ .../Instruction/FuncletPadOpTransform.cpp | 13 + .../Instruction/MemoryOpTransform.cpp | 149 ++++++ .../Instruction/OtherOpTransform.cpp | 190 +++++++ .../Transform/Instruction/TermOpTransform.cpp | 141 ++++++ .../Instruction/UnaryOpTransform.cpp | 10 + src/llvm/lib/Transform/Transform.cpp | 306 +++++++++++ src/llvm/lib/Util/Exceptions.cpp | 109 ++++ src/llvm/lib/origin/ContextDeriver.cpp | 74 --- src/llvm/lib/origin/OriginProvider.cpp | 216 -------- src/llvm/lib/origin/PreferredNameDeriver.cpp | 69 --- src/llvm/lib/origin/ShortPositionDeriver.cpp | 43 -- .../Function/FunctionBodyTransformer.cpp | 149 ------ .../Function/FunctionContractDeclarer.cpp | 90 ---- .../lib/passes/Function/FunctionDeclarer.cpp | 120 ----- src/llvm/lib/passes/Function/PureAssigner.cpp | 50 -- .../lib/passes/Module/ModuleSpecCollector.cpp | 40 -- src/llvm/lib/transform/BlockTransform.cpp | 59 --- .../Instruction/BinaryOpTransform.cpp | 46 -- .../transform/Instruction/CastOpTransform.cpp | 14 - .../Instruction/FuncletPadOpTransform.cpp | 15 - .../Instruction/MemoryOpTransform.cpp | 15 - .../Instruction/OtherOpTransform.cpp | 151 ------ .../transform/Instruction/TermOpTransform.cpp | 120 ----- .../Instruction/UnaryOpTransform.cpp | 12 - src/llvm/lib/transform/Transform.cpp | 101 ---- src/llvm/lib/util/Exceptions.cpp | 52 -- src/llvm/tools/vcllvm/VCLLVM.cpp | 145 ------ src/main/vct/main/stages/Parsing.scala | 2 +- src/main/vct/main/stages/Resolution.scala | 46 +- src/main/vct/main/stages/Transformation.scala | 2 + src/main/vct/options/Options.scala | 6 + src/main/vct/resources/Resources.scala | 2 +- src/parsers/antlr4/LangPVLLexer.g4 | 1 + src/parsers/antlr4/LangPVLParser.g4 | 2 + .../vct/parsers/parser/ColLLVMParser.scala | 41 +- .../parsers/transform/LLVMContractToCol.scala | 6 +- .../vct/parsers/transform/PVLToCol.scala | 6 +- src/rewrite/vct/rewrite/ClassToRef.scala | 4 +- .../rewrite/DesugarPermissionOperators.scala | 2 +- .../vct/rewrite/EncodeCurrentThread.scala | 2 +- .../ResolveExpressionSideEffects.scala | 8 +- src/rewrite/vct/rewrite/TrivialAddrOf.scala | 9 +- .../vct/rewrite/VariableToPointer.scala | 213 ++++++++ .../vct/rewrite/lang/LangLLVMToCol.scala | 475 ++++++++++++++++-- .../vct/rewrite/lang/LangSpecificToCol.scala | 40 +- 156 files changed, 5244 insertions(+), 2655 deletions(-) create mode 100644 .clang-format create mode 100644 src/col/vct/col/ast/family/coercion/CoerceLLVMArrayImpl.scala create mode 100644 src/col/vct/col/ast/family/coercion/CoerceLLVMIntIntImpl.scala create mode 100644 src/col/vct/col/ast/family/coercion/CoerceLLVMPointerImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMAllocAImpl.scala rename src/col/vct/col/ast/lang/llvm/{LlvmAmbiguousFunctionInvocationImpl.scala => LLVMAmbiguousFunctionInvocationImpl.scala} (51%) create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMArrayValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMExprImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMFunctionContractImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMFunctionDefinitionImpl.scala rename src/col/vct/col/ast/lang/llvm/{LlvmFunctionInvocationImpl.scala => LLVMFunctionInvocationImpl.scala} (64%) create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMFunctionPointerValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMGetElementPointerImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMGlobalSpecificationImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMGlobalVariableImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMIntegerValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMLoadImpl.scala rename src/col/vct/col/ast/lang/llvm/{LlvmLocalImpl.scala => LLVMLocalImpl.scala} (55%) create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMLoopContractImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMLoopImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMLoopInvariantImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireReleaseImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryMonotonicImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryNotAtomicImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryOrderingImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryReleaseImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemorySequentiallyConsistentImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMMemoryUnorderedImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMPointerValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMRawArrayValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMRawVectorValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMSignExtendImpl.scala rename src/col/vct/col/ast/lang/llvm/{LlvmSpecFunctionImpl.scala => LLVMSpecFunctionImpl.scala} (86%) create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMStatementImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMStoreImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMStructValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTArrayImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTFunctionImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTIntImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTMetadataImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTPointerImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTStructImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTVectorImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMTruncateImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMVectorValueImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMZeroExtendImpl.scala create mode 100644 src/col/vct/col/ast/lang/llvm/LLVMZeroedAggregateValueImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmExprImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmFunctionContractImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmFunctionDefinitionImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmGlobalImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmLoopContractImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmLoopImpl.scala delete mode 100644 src/col/vct/col/ast/lang/llvm/LlvmLoopInvariantImpl.scala create mode 100644 src/llvm/include/Passes/Module/GlobalVariableDeclarer.h create mode 100644 src/llvm/include/Passes/Module/ProtobufPrinter.h create mode 100644 src/llvm/include/Passes/Module/RootContainer.h create mode 100644 src/llvm/lib/Origin/ContextDeriver.cpp create mode 100644 src/llvm/lib/Origin/OriginProvider.cpp create mode 100644 src/llvm/lib/Origin/PreferredNameDeriver.cpp create mode 100644 src/llvm/lib/Origin/ShortPositionDeriver.cpp create mode 100644 src/llvm/lib/Passes/Function/FunctionBodyTransformer.cpp create mode 100644 src/llvm/lib/Passes/Function/FunctionContractDeclarer.cpp create mode 100644 src/llvm/lib/Passes/Function/FunctionDeclarer.cpp create mode 100644 src/llvm/lib/Passes/Function/PureAssigner.cpp create mode 100644 src/llvm/lib/Passes/Module/GlobalVariableDeclarer.cpp create mode 100644 src/llvm/lib/Passes/Module/ModuleSpecCollector.cpp create mode 100644 src/llvm/lib/Passes/Module/ProtobufPrinter.cpp create mode 100644 src/llvm/lib/Passes/Module/RootContainer.cpp create mode 100644 src/llvm/lib/Plugin.cpp create mode 100644 src/llvm/lib/Transform/BlockTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/BinaryOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/CastOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/FuncletPadOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/MemoryOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/OtherOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/TermOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Instruction/UnaryOpTransform.cpp create mode 100644 src/llvm/lib/Transform/Transform.cpp create mode 100644 src/llvm/lib/Util/Exceptions.cpp delete mode 100644 src/llvm/lib/origin/ContextDeriver.cpp delete mode 100644 src/llvm/lib/origin/OriginProvider.cpp delete mode 100644 src/llvm/lib/origin/PreferredNameDeriver.cpp delete mode 100644 src/llvm/lib/origin/ShortPositionDeriver.cpp delete mode 100644 src/llvm/lib/passes/Function/FunctionBodyTransformer.cpp delete mode 100644 src/llvm/lib/passes/Function/FunctionContractDeclarer.cpp delete mode 100644 src/llvm/lib/passes/Function/FunctionDeclarer.cpp delete mode 100644 src/llvm/lib/passes/Function/PureAssigner.cpp delete mode 100644 src/llvm/lib/passes/Module/ModuleSpecCollector.cpp delete mode 100644 src/llvm/lib/transform/BlockTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/BinaryOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/CastOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/FuncletPadOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/MemoryOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/OtherOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/TermOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Instruction/UnaryOpTransform.cpp delete mode 100644 src/llvm/lib/transform/Transform.cpp delete mode 100644 src/llvm/lib/util/Exceptions.cpp delete mode 100644 src/llvm/tools/vcllvm/VCLLVM.cpp create mode 100644 src/rewrite/vct/rewrite/VariableToPointer.scala diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..15f70246e5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,236 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ae38ee0e7..35d4481090 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ on: jobs: Release: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout VerCors uses: actions/checkout@v2 @@ -22,8 +22,8 @@ jobs: uses: actions/setup-java@v1 with: java-version: 17 - - name: Enable VCLLVM compilation - run: touch .include-vcllvm + - name: Enable Pallas compilation + run: touch .include-pallas - name: Build Release run: ./mill -j 0 vercors.main.release - name: Set Properties diff --git a/.github/workflows/scalatest.yml b/.github/workflows/scalatest.yml index 826213d9d2..632e6fe244 100644 --- a/.github/workflows/scalatest.yml +++ b/.github/workflows/scalatest.yml @@ -16,7 +16,7 @@ concurrency: jobs: Compile: if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout VerCors uses: actions/checkout@v2 @@ -32,20 +32,20 @@ jobs: restore-keys: | vercors-ci-ubuntu-${{ hashFiles('build.sc') }} vercors-ci-ubuntu - - name: Enable VCLLVM compilation - run: touch .include-vcllvm + - name: Enable Pallas compilation + run: touch .include-pallas - name: Compile - run: ./mill -j 0 vercors.allTests.assembly + vercors.vcllvm.compile + run: ./mill -j 0 vercors.allTests.assembly + vercors.pallas.compile - name: Upload VerCors uses: actions/upload-artifact@v3 with: name: allTests path: out/vercors/allTests/assembly.dest/out.jar - - name: Upload VCLLVM + - name: Upload Pallas uses: actions/upload-artifact@v3 with: - name: vcllvm - path: out/vercors/vcllvm/compile.dest/vcllvm + name: pallas + path: out/vercors/pallas/compile.dest/pallas - name: Delete Uncached Files run: | find out -type f -name upstreamAssembly.json -print -exec rm -rf {} + @@ -130,7 +130,7 @@ jobs: matrix: batch: ["-n MATRIX[0]", "-n MATRIX[1]", "-n MATRIX[2]", "-n MATRIX[3]", "-n MATRIX[4]", "-n MATRIX[5]", "-n MATRIX[6]", "-n MATRIX[7]", "-l MATRIX"] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout VerCors uses: actions/checkout@v2 @@ -143,13 +143,11 @@ jobs: with: name: allTests path: '.' - - name: Download VCLLVM + - name: Download Pallas uses: actions/download-artifact@v3 with: - name: vcllvm + name: pallas path: '.' - - name: Make VCLLVM executable - run: chmod +x vcllvm - name: ls run: ls -lasFhR - name: Run scalatest diff --git a/build.sc b/build.sc index 23a2c215fa..4304306658 100644 --- a/build.sc +++ b/build.sc @@ -4,6 +4,7 @@ import $ivy.`com.lihaoyi::mill-contrib-buildinfo:` import util._ import os._ import mill.{util => _, _} +import mill.api.Result import scalalib.{JavaModule => _, ScalaModule => _, _} import contrib.buildinfo.BuildInfo import me.pieterbos.mill.cpp.options.implicits._ @@ -16,6 +17,32 @@ import vct.col.ast.structure.{AllFamilies, FamilyDefinition, Name, NodeDefinitio import scala.util.control.NonFatal +trait CppSharedModule extends CppModule { + def executableOptions: T[CppExecutableOptions] = T { + CppExecutableOptions( + transitiveDynamicObjects().map(_.path), + transitiveSystemLibraryDeps(), + Seq("-shared", "-fPIC"), + Nil, + ) + } + + def compile: T[PathRef] = T { +// def temp = //transitiveStaticObjects()).map(_.path)) + print("Definitely a new file") + print(compileOnly() ++ T.traverse(moduleDeps){ + case it: CppModule => it.compileOnly + case it: LinkableModule => it.staticObjects + case _ => T.task { Result.Success(Seq.empty) } + }().flatten) + PathRef(toolchain.linkExecutable((compileOnly() ++ T.traverse(moduleDeps){ + case it: CppModule => it.compileOnly + case it: LinkableModule => it.staticObjects + case _ => T.task { Result.Success(Seq.empty) } + }().flatten).map(_.path), T.dest, name(), executableOptions())) + } +} + object external extends Module { object z3 extends Module { def url = T { "https://www.sosy-lab.org/ivy/org.sosy_lab/javasmt-solver-z3/com.microsoft.z3-4.8.7.jar" } @@ -406,24 +433,25 @@ object vercors extends Module { ivy"org.apache.logging.log4j:log4j-to-slf4j:2.23.1", ) override def moduleDeps = Seq(hre, col, serialize) + override def unmanagedClasspath = super.unmanagedClasspath() ++ Agg(PathRef(pallas.compile().path / os.up)) - val includeVcllvmCross = interp.watchValue { - if(os.exists(settings.root / ".include-vcllvm")) { - Seq("vcllvm") + val includePallasCross = interp.watchValue { + if(os.exists(settings.root / ".include-pallas")) { + Seq("pallas") } else { Seq.empty[String] } } - - object vcllvmDep extends Cross[VcllvmDep](includeVcllvmCross) - trait VcllvmDep extends Cross.Module[String] { + + object pallasDep extends Cross[PallasDep](includePallasCross) + trait PallasDep extends Cross.Module[String] { def path = T { - vcllvm.compile().path / os.up + pallas.compile().path / os.up } } override def bareResourcePaths = T { - T.traverse(includeVcllvmCross.map(vcllvmDep(_)))(_.path)() + T.traverse(includePallasCross.map(pallasDep(_)))(_.path)() } trait GenModule extends Module { @@ -636,149 +664,81 @@ object vercors extends Module { } } - object vcllvm extends CppExecutableModule { - outer => - def root: T[os.Path] = T { - settings.src / "llvm" - } + object pallas extends CppSharedModule { outer => + def root: T[os.Path] = T { settings.src / "llvm" } object llvm extends LinkableModule { def moduleDeps = Nil - - def systemLibraryDeps = T { - Seq("LLVM-15") - } - - def staticObjects = T { - Seq.empty[PathRef] - } - - def dynamicObjects = T { - Seq.empty[PathRef] - } - + def systemLibraryDeps = T { Seq("LLVM-17") } + def staticObjects = T { Seq.empty[PathRef] } + def dynamicObjects = T { Seq.empty[PathRef] } def exportIncludePaths = T.sources( - os.Path("/usr/include/llvm-15"), - os.Path("/usr/include/llvm-c-15"), - os.Path("/usr/local/opt/llvm/include") + os.Path("/usr/include/llvm-17"), + os.Path("/usr/include/llvm-c-17"), ) } - object json extends LinkableModule { - def moduleDeps = Nil - - def systemLibraryDeps = T { - Seq.empty[String] - } - - def staticObjects = T { - Seq.empty[PathRef] - } - - def dynamicObjects = T { - Seq.empty[PathRef] - } - - def exportIncludePaths = T { - os.write(T.dest / "json.tar.xz", requests.get.stream("https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz")) - os.proc("tar", "-xf", T.dest / "json.tar.xz").call(cwd = T.dest) - Seq(PathRef(T.dest / "json" / "include")) - } - } - object origin extends CppModule { - def moduleDeps = Seq(llvm, json, proto, protobuf.libprotobuf) - - def sources = T.sources(vcllvm.root() / "lib" / "origin") - - def includePaths = T.sources(vcllvm.root() / "include") - - override def unixToolchain = GccCompatible("g++", "ar") - + override def moduleDeps = Seq(llvm, proto, proto.protobuf.libprotobuf) + override def sources = T.sources(pallas.root() / "lib" / "Origin") + override def includePaths = T.sources(pallas.root() / "include") + override def compileOptions: T[Seq[String]] = Seq("-fPIC") } - object passes extends CppModule { - def moduleDeps = Seq(llvm, proto, protobuf.libprotobuf) - - def sources = T.sources(vcllvm.root() / "lib" / "passes") - - def includePaths = T.sources(vcllvm.root() / "include") - - override def unixToolchain = GccCompatible("g++", "ar") - + override def moduleDeps = Seq(llvm, proto, util, origin, transform, proto.protobuf.libprotobuf) + override def sources = T.sources(pallas.root() / "lib" / "Passes") + override def includePaths = T.sources(pallas.root() / "include") + override def compileOptions: T[Seq[String]] = Seq("-fPIC") } - object transform extends CppModule { - def moduleDeps = Seq(llvm, proto, protobuf.libprotobuf) - - def sources = T.sources(vcllvm.root() / "lib" / "transform") - - def includePaths = T.sources(vcllvm.root() / "include") - - override def unixToolchain = GccCompatible("g++", "ar") - + override def moduleDeps = Seq(llvm, proto, util, origin, proto.protobuf.libprotobuf) + override def sources = T.sources(pallas.root() / "lib" / "Transform") + override def includePaths = T.sources(pallas.root() / "include") + override def compileOptions: T[Seq[String]] = Seq("-fPIC") } - object util extends CppModule { - def moduleDeps = Seq(llvm, proto, protobuf.libprotobuf) - - def sources = T.sources(vcllvm.root() / "lib" / "util") - - def includePaths = T.sources(vcllvm.root() / "include") - - override def unixToolchain = GccCompatible("g++", "ar") - + override def moduleDeps = Seq(llvm, proto, origin, proto.protobuf.libprotobuf) + override def sources = T.sources(pallas.root() / "lib" / "Util") + override def includePaths = T.sources(pallas.root() / "include") + override def compileOptions: T[Seq[String]] = Seq("-fPIC") + } + object plugin extends CppModule { + override def moduleDeps = Seq(llvm, proto, passes, transform, proto.protobuf.libprotobuf) + override def sources = T.sources(pallas.root() / "lib" / "Plugin.cpp") + override def includePaths = T.sources(pallas.root() / "include") + override def compileOptions: T[Seq[String]] = Seq("-fPIC") } - override def unixToolchain = GccCompatible("g++", "ar") - - def moduleDeps = Seq(origin, passes, transform, util, llvm, proto, protobuf.libprotobuf) - - def sources = T.sources(vcllvm.root() / "tools" / "vcllvm") - - def includePaths = T.sources(vcllvm.root() / "include") - - object protobuf extends CMakeModule { - object protobufGit extends GitModule { - override def url: T[String] = "https://github.com/protocolbuffers/protobuf" - - override def commitish: T[String] = "v25.2" - - override def fetchSubmodulesRecursively = true - } - - override def root = T.source(protobufGit.repo()) - - override def jobs = T { - 2 - } + object proto extends CppModule { + object protobuf extends CMakeModule { + object protobufGit extends GitModule { + override def url: T[String] = "https://github.com/protocolbuffers/protobuf" + override def commitish: T[String] = "v25.2" + override def fetchSubmodulesRecursively = true + } + override def root = T.source(protobufGit.repo()) + override def jobs = T { 2 } - override def cMakeBuild: T[PathRef] = T { - os.proc("cmake", "-B", T.dest, "-Dprotobuf_BUILD_TESTS=OFF", "-DABSL_PROPAGATE_CXX_STD=ON", "-S", root().path).call(cwd = T.dest) - os.proc("make", "-j", jobs(), "all").call(cwd = T.dest) - PathRef(T.dest) - } + override def cMakeBuild: T[PathRef] = T { + os.proc("cmake", "-B", T.dest, "-D", "protobuf_BUILD_TESTS=OFF", "-D", "ABSL_PROPAGATE_CXX_STD=ON", "-D", "CMAKE_POSITION_INDEPENDENT_CODE=ON", "-D", "CMAKE_CXX_FLAGS=-fPIC", "-D", "CMAKE_C_FLAGS=-fPIC", "-S", root().path).call(cwd = T.dest) + os.proc("make", "-j", jobs(), "all").call(cwd = T.dest) + PathRef(T.dest) + } - object libprotobuf extends CMakeLibrary { - def target = T { - "libprotobuf" + object libprotobuf extends CMakeLibrary { + def target = T { "libprotobuf" } } - } - object protoc extends CMakeExecutable { - def target = T { - "protoc" + object protoc extends CMakeExecutable { + def target = T { "protoc" } } } - } - object proto extends CppModule { def protoPath = T.sources( vercors.col.helpers.megacol().path / os.up / os.up / os.up / os.up, settings.src / "serialize", serialize.scalaPBUnpackProto().path ) - def generate = T { os.proc(protobuf.protoc.executable().path, protoPath().map(p => "-I=" + p.path.toString), @@ -789,16 +749,10 @@ object vercors extends Module { ).call() T.dest } - override def moduleDeps = Seq(protobuf.libprotobuf) - - override def sources = T { - Seq(PathRef(generate())) - } - - override def includePaths = T { - Seq(PathRef(generate())) - } + override def sources = T { Seq(PathRef(generate())) } + override def includePaths = T { Seq(PathRef(generate())) } + override def compileOptions: T[Seq[String]] = T { Seq("-fPIC") } def precompileHeaders: T[PathRef] = T { def isHiddenFile(path: os.Path): Boolean = path.last.startsWith(".") @@ -837,9 +791,10 @@ object vercors extends Module { override def exportIncludePaths: T[Seq[PathRef]] = T { Seq(precompileHeaders()) } - - override def unixToolchain = GccCompatible("g++", "ar") } + + override def moduleDeps = Seq(origin, passes, transform, util, llvm, plugin, proto, proto.protobuf.libprotobuf) + override def compileOptions: T[Seq[String]] = T { Seq("-fPIC") } } object allTests extends ScalaModule with ReleaseModule { diff --git a/src/col/vct/col/ast/Node.scala b/src/col/vct/col/ast/Node.scala index 838740745f..12009f3f91 100644 --- a/src/col/vct/col/ast/Node.scala +++ b/src/col/vct/col/ast/Node.scala @@ -1128,6 +1128,15 @@ final case class CoerceRatZFrac[G]()(implicit val o: Origin) final case class CoerceZFracFrac[G]()(implicit val o: Origin) extends Coercion[G] with CoerceZFracFracImpl[G] +final case class CoerceLLVMIntInt[G]()(implicit val o: Origin) + extends Coercion[G] with CoerceLLVMIntIntImpl[G] +final case class CoerceLLVMPointer[G](from: Option[Type[G]], to: Type[G])( + implicit val o: Origin +) extends Coercion[G] with CoerceLLVMPointerImpl[G] +final case class CoerceLLVMArray[G](source: Type[G], target: Type[G])( + implicit val o: Origin +) extends Coercion[G] with CoerceLLVMArrayImpl[G] + @family sealed trait Expr[G] extends NodeFamily[G] with ExprImpl[G] @@ -3422,28 +3431,37 @@ final case class BipTransitionSynchronization[G]( extends GlobalDeclaration[G] with BipTransitionSynchronizationImpl[G] @family -final class LlvmFunctionContract[G]( +final class LLVMFunctionContract[G]( + val name: String, val value: String, val variableRefs: Seq[(String, Ref[G, Variable[G]])], - val invokableRefs: Seq[(String, Ref[G, LlvmCallable[G]])], + val invokableRefs: Seq[(String, Ref[G, LLVMCallable[G]])], )(val blame: Blame[NontrivialUnsatisfiable])(implicit val o: Origin) - extends NodeFamily[G] with LlvmFunctionContractImpl[G] { + extends NodeFamily[G] with LLVMFunctionContractImpl[G] { var data: Option[ApplicableContract[G]] = None } -sealed trait LlvmCallable[G] extends GlobalDeclaration[G] + +final case class LLVMGlobalVariable[G]( + variableType: Type[G], + value: Option[Expr[G]], + constant: Boolean, +)(implicit val o: Origin) + extends GlobalDeclaration[G] with LLVMGlobalVariableImpl[G] + +sealed trait LLVMCallable[G] extends GlobalDeclaration[G] @scopes[LabelDecl] -final class LlvmFunctionDefinition[G]( +final class LLVMFunctionDefinition[G]( val returnType: Type[G], val args: Seq[Variable[G]], - val functionBody: Statement[G], - val contract: LlvmFunctionContract[G], + val functionBody: Option[Statement[G]], + val contract: LLVMFunctionContract[G], val pure: Boolean = false, )(val blame: Blame[CallableFailure])(implicit val o: Origin) - extends LlvmCallable[G] + extends LLVMCallable[G] with Applicable[G] - with LlvmFunctionDefinitionImpl[G] + with LLVMFunctionDefinitionImpl[G] @scopes[LabelDecl] -final class LlvmSpecFunction[G]( +final class LLVMSpecFunction[G]( val name: String, val returnType: Type[G], val args: Seq[Variable[G]], @@ -3453,51 +3471,179 @@ final class LlvmSpecFunction[G]( val inline: Boolean = false, val threadLocal: Boolean = false, )(val blame: Blame[ContractedFailure])(implicit val o: Origin) - extends LlvmCallable[G] + extends LLVMCallable[G] with AbstractFunction[G] - with LlvmSpecFunctionImpl[G] -final case class LlvmFunctionInvocation[G]( - ref: Ref[G, LlvmFunctionDefinition[G]], + with LLVMSpecFunctionImpl[G] +final case class LLVMFunctionInvocation[G]( + ref: Ref[G, LLVMFunctionDefinition[G]], args: Seq[Expr[G]], givenMap: Seq[(Ref[G, Variable[G]], Expr[G])], yields: Seq[(Expr[G], Ref[G, Variable[G]])], )(val blame: Blame[InvocationFailure])(implicit val o: Origin) - extends Apply[G] with LlvmFunctionInvocationImpl[G] -final case class LlvmLoop[G]( + extends Apply[G] with LLVMFunctionInvocationImpl[G] + +final case class LLVMLoop[G]( cond: Expr[G], - contract: LlvmLoopContract[G], + contract: LLVMLoopContract[G], body: Statement[G], )(implicit val o: Origin) - extends CompositeStatement[G] with LlvmLoopImpl[G] + extends CompositeStatement[G] with LLVMLoopImpl[G] + @family -sealed trait LlvmLoopContract[G] - extends NodeFamily[G] with LlvmLoopContractImpl[G] -final case class LlvmLoopInvariant[G]( +sealed trait LLVMLoopContract[G] + extends NodeFamily[G] with LLVMLoopContractImpl[G] + +final case class LLVMLoopInvariant[G]( value: String, references: Seq[(String, Ref[G, Declaration[G]])], )(val blame: Blame[LoopInvariantFailure])(implicit val o: Origin) - extends LlvmLoopContract[G] with LlvmLoopInvariantImpl[G] -sealed trait LlvmExpr[G] extends Expr[G] with LlvmExprImpl[G] -final case class LlvmLocal[G](name: String)( + extends LLVMLoopContract[G] with LLVMLoopInvariantImpl[G] + +sealed trait LLVMStatement[G] extends Statement[G] with LLVMStatementImpl[G] + +sealed trait LLVMExpr[G] extends Expr[G] with LLVMExprImpl[G] + +final case class LLVMLocal[G](name: String)( val blame: Blame[DerefInsufficientPermission] )(implicit val o: Origin) - extends LlvmExpr[G] with LlvmLocalImpl[G] { + extends LLVMExpr[G] with LLVMLocalImpl[G] { var ref: Option[Ref[G, Variable[G]]] = None } -final case class LlvmAmbiguousFunctionInvocation[G]( +final case class LLVMAmbiguousFunctionInvocation[G]( name: String, args: Seq[Expr[G]], givenMap: Seq[(Ref[G, Variable[G]], Expr[G])], yields: Seq[(Expr[G], Ref[G, Variable[G]])], )(val blame: Blame[InvocationFailure])(implicit val o: Origin) - extends LlvmExpr[G] with LlvmAmbiguousFunctionInvocationImpl[G] { - var ref: Option[Ref[G, LlvmCallable[G]]] = None + extends LLVMExpr[G] with LLVMAmbiguousFunctionInvocationImpl[G] { + var ref: Option[Ref[G, LLVMCallable[G]]] = None } -final class LlvmGlobal[G](val value: String)(implicit val o: Origin) - extends GlobalDeclaration[G] with LlvmGlobalImpl[G] { +final case class LLVMAllocA[G](allocationType: Type[G], numElements: Expr[G])( + implicit val o: Origin +) extends LLVMExpr[G] with LLVMAllocAImpl[G] + +final case class LLVMLoad[G]( + loadType: Type[G], + pointer: Expr[G], + ordering: LLVMMemoryOrdering[G], +)(implicit val o: Origin) + extends LLVMExpr[G] with LLVMLoadImpl[G] + +final case class LLVMStore[G]( + value: Expr[G], + pointer: Expr[G], + ordering: LLVMMemoryOrdering[G], +)(implicit val o: Origin) + extends LLVMStatement[G] with LLVMStoreImpl[G] + +final case class LLVMGetElementPointer[G]( + structureType: Type[G], + resultType: Type[G], + pointer: Expr[G], + indices: Seq[Expr[G]], +)(implicit val o: Origin) + extends LLVMExpr[G] with LLVMGetElementPointerImpl[G] + +final case class LLVMSignExtend[G]( + inputType: Type[G], + outputType: Type[G], + value: Expr[G], +)(implicit val o: Origin) + extends LLVMExpr[G] with LLVMSignExtendImpl[G] + +final case class LLVMZeroExtend[G]( + inputType: Type[G], + outputType: Type[G], + value: Expr[G], +)(implicit val o: Origin) + extends LLVMExpr[G] with LLVMZeroExtendImpl[G] + +final case class LLVMTruncate[G]( + inputType: Type[G], + outputType: Type[G], + value: Expr[G], +)(implicit val o: Origin) + extends LLVMExpr[G] with LLVMTruncateImpl[G] + +final class LLVMGlobalSpecification[G](val value: String)( + implicit val o: Origin +) extends GlobalDeclaration[G] with LLVMGlobalSpecificationImpl[G] { var data: Option[Seq[GlobalDeclaration[G]]] = None } + +@family +sealed trait LLVMMemoryOrdering[G] + extends NodeFamily[G] with LLVMMemoryOrderingImpl[G] + +final case class LLVMMemoryNotAtomic[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemoryNotAtomicImpl[G] +final case class LLVMMemoryUnordered[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemoryUnorderedImpl[G] +final case class LLVMMemoryMonotonic[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemoryMonotonicImpl[G] +final case class LLVMMemoryAcquire[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemoryAcquireImpl[G] +final case class LLVMMemoryRelease[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemoryReleaseImpl[G] +final case class LLVMMemoryAcquireRelease[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemoryAcquireReleaseImpl[G] +final case class LLVMMemorySequentiallyConsistent[G]()(implicit val o: Origin) + extends LLVMMemoryOrdering[G] with LLVMMemorySequentiallyConsistentImpl[G] + +final case class LLVMIntegerValue[G](value: BigInt, integerType: Type[G])( + implicit val o: Origin +) extends ConstantInt[G] with LLVMExpr[G] with LLVMIntegerValueImpl[G] +final case class LLVMPointerValue[G](value: Ref[G, Declaration[G]])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMPointerValueImpl[G] +// TODO: The LLVMFunctionPointerValue references a GlobalDeclaration instead of an LLVMFunctionDefinition because there is no other COL node we can use as a function pointer literal +final case class LLVMFunctionPointerValue[G]( + value: Ref[G, GlobalDeclaration[G]] +)(implicit val o: Origin) + extends Constant[G] with LLVMExpr[G] with LLVMFunctionPointerValueImpl[G] +final case class LLVMStructValue[G](value: Seq[Expr[G]], structType: Type[G])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMStructValueImpl[G] +final case class LLVMArrayValue[G](value: Seq[Expr[G]], arrayType: Type[G])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMArrayValueImpl[G] +final case class LLVMRawArrayValue[G](value: String, arrayType: Type[G])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMRawArrayValueImpl[G] +final case class LLVMVectorValue[G](value: Seq[Expr[G]], vectorType: Type[G])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMVectorValueImpl[G] +final case class LLVMRawVectorValue[G](value: String, vectorType: Type[G])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMRawVectorValueImpl[G] +final case class LLVMZeroedAggregateValue[G](aggregateType: Type[G])( + implicit val o: Origin +) extends Constant[G] with LLVMExpr[G] with LLVMZeroedAggregateValueImpl[G] + +final case class LLVMTInt[G](bitWidth: Int)( + implicit val o: Origin = DiagnosticOrigin +) extends IntType[G] with LLVMTIntImpl[G] +final case class LLVMTFunction[G]()(implicit val o: Origin = DiagnosticOrigin) + extends Type[G] with LLVMTFunctionImpl[G] +final case class LLVMTPointer[G](innerType: Option[Type[G]])( + implicit val o: Origin = DiagnosticOrigin +) extends Type[G] with LLVMTPointerImpl[G] +final case class LLVMTMetadata[G]()(implicit val o: Origin = DiagnosticOrigin) + extends Type[G] with LLVMTMetadataImpl[G] +final case class LLVMTStruct[G]( + name: Option[String], + packed: Boolean, + elements: Seq[Type[G]], +)(implicit val o: Origin = DiagnosticOrigin) + extends Type[G] with LLVMTStructImpl[G] +final case class LLVMTArray[G](numElements: Long, elementType: Type[G])( + implicit val o: Origin = DiagnosticOrigin +) extends Type[G] with LLVMTArrayImpl[G] +final case class LLVMTVector[G](numElements: Long, elementType: Type[G])( + implicit val o: Origin = DiagnosticOrigin +) extends Type[G] with LLVMTVectorImpl[G] + sealed trait PVLType[G] extends Type[G] with PVLTypeImpl[G] final case class PVLNamedType[G](name: String, typeArgs: Seq[Type[G]])( implicit val o: Origin = DiagnosticOrigin diff --git a/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala b/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala index eefa45fd0b..ec83c193b7 100644 --- a/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala +++ b/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala @@ -37,8 +37,8 @@ trait AmbiguousResultImpl[G] case RefProcedure(decl) => decl.returnType case RefJavaMethod(decl) => decl.returnType case RefJavaAnnotationMethod(decl) => decl.returnType - case RefLlvmFunctionDefinition(decl) => decl.returnType - case RefLlvmSpecFunction(decl) => decl.returnType + case RefLLVMFunctionDefinition(decl) => decl.returnType + case RefLLVMSpecFunction(decl) => decl.returnType case RefInstanceFunction(decl) => decl.returnType case RefInstanceMethod(decl) => decl.returnType case RefInstanceOperatorMethod(decl) => decl.returnType diff --git a/src/col/vct/col/ast/expr/op/BinExprImpl.scala b/src/col/vct/col/ast/expr/op/BinExprImpl.scala index 7bbf539079..326e807069 100644 --- a/src/col/vct/col/ast/expr/op/BinExprImpl.scala +++ b/src/col/vct/col/ast/expr/op/BinExprImpl.scala @@ -7,6 +7,7 @@ import vct.col.ast.{ IntType, TBool, TCInt, + LLVMTInt, TInt, TProcess, TRational, @@ -35,6 +36,12 @@ object BinOperatorTypes { CoercionUtils.getCoercion(lt, TBool()).isDefined && CoercionUtils.getCoercion(rt, TBool()).isDefined + def isLLVMIntOp[G](lt: Type[G], rt: Type[G]): Boolean = + (lt, rt) match { + case (LLVMTInt(_), LLVMTInt(_)) => true + case _ => false + } + def isStringOp[G](lt: Type[G], rt: Type[G]): Boolean = CoercionUtils.getCoercion(lt, TString()).isDefined @@ -78,6 +85,8 @@ object BinOperatorTypes { def getIntType[G](lt: Type[G], rt: Type[G]): IntType[G] = if (isCIntOp(lt, rt)) TCInt() + else if (isLLVMIntOp(lt, rt)) + Types.leastCommonSuperType(lt, rt).asInstanceOf[LLVMTInt[G]] else TInt() @@ -91,6 +100,8 @@ object BinOperatorTypes { def getNumericType[G](lt: Type[G], rt: Type[G], o: Origin): Type[G] = { if (isCIntOp(lt, rt)) TCInt[G]() + else if (isLLVMIntOp(lt, rt)) + Types.leastCommonSuperType(lt, rt).asInstanceOf[LLVMTInt[G]] else if (isIntOp(lt, rt)) TInt[G]() else @@ -113,6 +124,8 @@ trait BinExprImpl[G] { def isRationalOp: Boolean = BinOperatorTypes.isRationalOp(left.t, right.t) + def isLLVMIntOp: Boolean = BinOperatorTypes.isLLVMIntOp(left.t, right.t) + def isBoolOp: Boolean = BinOperatorTypes.isBoolOp(left.t, right.t) def isStringOp: Boolean = BinOperatorTypes.isStringOp(left.t, right.t) diff --git a/src/col/vct/col/ast/family/coercion/CoerceLLVMArrayImpl.scala b/src/col/vct/col/ast/family/coercion/CoerceLLVMArrayImpl.scala new file mode 100644 index 0000000000..a77db8453b --- /dev/null +++ b/src/col/vct/col/ast/family/coercion/CoerceLLVMArrayImpl.scala @@ -0,0 +1,8 @@ +package vct.col.ast.family.coercion + +import vct.col.ast.ops.CoerceLLVMArrayOps +import vct.col.ast.CoerceLLVMArray + +trait CoerceLLVMArrayImpl[G] extends CoerceLLVMArrayOps[G] { + this: CoerceLLVMArray[G] => +} diff --git a/src/col/vct/col/ast/family/coercion/CoerceLLVMIntIntImpl.scala b/src/col/vct/col/ast/family/coercion/CoerceLLVMIntIntImpl.scala new file mode 100644 index 0000000000..d0d67d7cd2 --- /dev/null +++ b/src/col/vct/col/ast/family/coercion/CoerceLLVMIntIntImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.family.coercion + +import vct.col.ast.{CoerceLLVMIntInt, TInt} +import vct.col.ast.ops.CoerceLLVMIntIntOps + +trait CoerceLLVMIntIntImpl[G] extends CoerceLLVMIntIntOps[G] { + this: CoerceLLVMIntInt[G] => + override def target: TInt[G] = TInt() +} diff --git a/src/col/vct/col/ast/family/coercion/CoerceLLVMPointerImpl.scala b/src/col/vct/col/ast/family/coercion/CoerceLLVMPointerImpl.scala new file mode 100644 index 0000000000..e686d1c593 --- /dev/null +++ b/src/col/vct/col/ast/family/coercion/CoerceLLVMPointerImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.family.coercion + +import vct.col.ast.{CoerceLLVMPointer, TPointer} +import vct.col.ast.ops.CoerceLLVMPointerOps + +trait CoerceLLVMPointerImpl[G] extends CoerceLLVMPointerOps[G] { + this: CoerceLLVMPointer[G] => + override def target: TPointer[G] = TPointer(to) +} diff --git a/src/col/vct/col/ast/family/coercion/CoercionImpl.scala b/src/col/vct/col/ast/family/coercion/CoercionImpl.scala index 738aae3fdc..998074fa51 100644 --- a/src/col/vct/col/ast/family/coercion/CoercionImpl.scala +++ b/src/col/vct/col/ast/family/coercion/CoercionImpl.scala @@ -87,5 +87,8 @@ trait CoercionImpl[G] extends CoercionFamilyOps[G] { case CoerceCFloatFloat(_, _) => true case CoerceDecreasePrecision(_, _) => false case CoerceCFloatCInt(_) => false + + case CoerceLLVMIntInt() => true + case CoerceLLVMPointer(_, _) => true } } diff --git a/src/col/vct/col/ast/lang/llvm/LLVMAllocAImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMAllocAImpl.scala new file mode 100644 index 0000000000..b14e42e820 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMAllocAImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.ops.LLVMAllocAOps +import vct.col.ast.{LLVMAllocA, Type, LLVMTPointer} + +trait LLVMAllocAImpl[G] extends LLVMAllocAOps[G] { + this: LLVMAllocA[G] => + override val t: Type[G] = LLVMTPointer(Some(this.allocationType)) +} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmAmbiguousFunctionInvocationImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMAmbiguousFunctionInvocationImpl.scala similarity index 51% rename from src/col/vct/col/ast/lang/llvm/LlvmAmbiguousFunctionInvocationImpl.scala rename to src/col/vct/col/ast/lang/llvm/LLVMAmbiguousFunctionInvocationImpl.scala index cb6b12eba3..b0217cf271 100644 --- a/src/col/vct/col/ast/lang/llvm/LlvmAmbiguousFunctionInvocationImpl.scala +++ b/src/col/vct/col/ast/lang/llvm/LLVMAmbiguousFunctionInvocationImpl.scala @@ -1,21 +1,21 @@ package vct.col.ast.lang.llvm import vct.col.ast.{ - LlvmAmbiguousFunctionInvocation, - LlvmFunctionDefinition, - LlvmSpecFunction, + LLVMAmbiguousFunctionInvocation, + LLVMFunctionDefinition, + LLVMSpecFunction, Type, } import vct.col.print.{Ctx, Doc, DocUtil, Group, Precedence, Text} -import vct.col.ast.ops.LlvmAmbiguousFunctionInvocationOps +import vct.col.ast.ops.LLVMAmbiguousFunctionInvocationOps -trait LlvmAmbiguousFunctionInvocationImpl[G] - extends LlvmAmbiguousFunctionInvocationOps[G] { - this: LlvmAmbiguousFunctionInvocation[G] => +trait LLVMAmbiguousFunctionInvocationImpl[G] + extends LLVMAmbiguousFunctionInvocationOps[G] { + this: LLVMAmbiguousFunctionInvocation[G] => override lazy val t: Type[G] = ref.get.decl match { - case func: LlvmFunctionDefinition[G] => func.returnType - case func: LlvmSpecFunction[G] => func.returnType + case func: LLVMFunctionDefinition[G] => func.returnType + case func: LLVMSpecFunction[G] => func.returnType } override def precedence: Int = Precedence.POSTFIX diff --git a/src/col/vct/col/ast/lang/llvm/LLVMArrayValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMArrayValueImpl.scala new file mode 100644 index 0000000000..d7be0dbc2e --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMArrayValueImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMArrayValue} +import vct.col.ast.ops.LLVMArrayValueOps +import vct.col.print._ + +trait LLVMArrayValueImpl[G] extends LLVMArrayValueOps[G] { + this: LLVMArrayValue[G] => + override def t: Type[G] = arrayType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMExprImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMExprImpl.scala new file mode 100644 index 0000000000..da49321904 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMExprImpl.scala @@ -0,0 +1,7 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMExpr +trait LLVMExprImpl[G] { + this: LLVMExpr[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMFunctionContractImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMFunctionContractImpl.scala new file mode 100644 index 0000000000..481e5689c7 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMFunctionContractImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMFunctionContract +import vct.col.ast.ops.{LLVMFunctionContractOps, LLVMFunctionContractFamilyOps} + +trait LLVMFunctionContractImpl[G] + extends LLVMFunctionContractOps[G] with LLVMFunctionContractFamilyOps[G] { + this: LLVMFunctionContract[G] => +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMFunctionDefinitionImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMFunctionDefinitionImpl.scala new file mode 100644 index 0000000000..326a86a142 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMFunctionDefinitionImpl.scala @@ -0,0 +1,16 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.declaration.category.ApplicableImpl +import vct.col.ast.{Declaration, LLVMFunctionDefinition, Statement} +import vct.col.ast.util.Declarator +import vct.col.ast.ops.LLVMFunctionDefinitionOps + +trait LLVMFunctionDefinitionImpl[G] + extends Declarator[G] + with ApplicableImpl[G] + with LLVMFunctionDefinitionOps[G] { + this: LLVMFunctionDefinition[G] => + override def declarations: Seq[Declaration[G]] = args + + override def body: Option[Statement[G]] = functionBody +} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmFunctionInvocationImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMFunctionInvocationImpl.scala similarity index 64% rename from src/col/vct/col/ast/lang/llvm/LlvmFunctionInvocationImpl.scala rename to src/col/vct/col/ast/lang/llvm/LLVMFunctionInvocationImpl.scala index 40f41dd1b4..e92e32fb16 100644 --- a/src/col/vct/col/ast/lang/llvm/LlvmFunctionInvocationImpl.scala +++ b/src/col/vct/col/ast/lang/llvm/LLVMFunctionInvocationImpl.scala @@ -1,11 +1,11 @@ package vct.col.ast.lang.llvm -import vct.col.ast.LlvmFunctionInvocation +import vct.col.ast.LLVMFunctionInvocation import vct.col.print.{Ctx, Doc, DocUtil, Empty, Group, Precedence, Text} -import vct.col.ast.ops.LlvmFunctionInvocationOps +import vct.col.ast.ops.LLVMFunctionInvocationOps -trait LlvmFunctionInvocationImpl[G] extends LlvmFunctionInvocationOps[G] { - this: LlvmFunctionInvocation[G] => +trait LLVMFunctionInvocationImpl[G] extends LLVMFunctionInvocationOps[G] { + this: LLVMFunctionInvocation[G] => override def precedence: Int = Precedence.POSTFIX override def layout(implicit ctx: Ctx): Doc = diff --git a/src/col/vct/col/ast/lang/llvm/LLVMFunctionPointerValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMFunctionPointerValueImpl.scala new file mode 100644 index 0000000000..4513befdb2 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMFunctionPointerValueImpl.scala @@ -0,0 +1,12 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMTPointer, LLVMFunctionPointerValue} +import vct.col.ast.ops.LLVMFunctionPointerValueOps +import vct.col.print._ + +trait LLVMFunctionPointerValueImpl[G] extends LLVMFunctionPointerValueOps[G] { + this: LLVMFunctionPointerValue[G] => + // TODO: Do we want a separate type for function pointers? For now we don't support function pointers anyway + override def t: Type[G] = LLVMTPointer(None) + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMGetElementPointerImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMGetElementPointerImpl.scala new file mode 100644 index 0000000000..795dc90cc6 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMGetElementPointerImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{LLVMGetElementPointer, LLVMTPointer, Type} +import vct.col.ast.ops.LLVMGetElementPointerOps +import vct.col.print._ + +trait LLVMGetElementPointerImpl[G] extends LLVMGetElementPointerOps[G] { + this: LLVMGetElementPointer[G] => + override def t: Type[G] = LLVMTPointer(Some(resultType)) + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMGlobalSpecificationImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMGlobalSpecificationImpl.scala new file mode 100644 index 0000000000..6a6d6274e8 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMGlobalSpecificationImpl.scala @@ -0,0 +1,12 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMGlobalSpecification +import vct.col.print.{Ctx, Doc, Text} +import vct.col.ast.ops.LLVMGlobalSpecificationOps + +trait LLVMGlobalSpecificationImpl[G] extends LLVMGlobalSpecificationOps[G] { + this: LLVMGlobalSpecification[G] => + + override def layout(implicit ctx: Ctx): Doc = Text(value) + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMGlobalVariableImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMGlobalVariableImpl.scala new file mode 100644 index 0000000000..80a7d93b43 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMGlobalVariableImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMGlobalVariable +import vct.col.ast.ops.LLVMGlobalVariableOps +import vct.col.print._ + +trait LLVMGlobalVariableImpl[G] extends LLVMGlobalVariableOps[G] { + this: LLVMGlobalVariable[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMIntegerValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMIntegerValueImpl.scala new file mode 100644 index 0000000000..6edc11d6b0 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMIntegerValueImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMIntegerValue} +import vct.col.ast.ops.LLVMIntegerValueOps +import vct.col.print._ + +trait LLVMIntegerValueImpl[G] extends LLVMIntegerValueOps[G] { + this: LLVMIntegerValue[G] => + override def t: Type[G] = integerType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMLoadImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMLoadImpl.scala new file mode 100644 index 0000000000..af05a52038 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMLoadImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{LLVMLoad, Type} +import vct.col.ast.ops.LLVMLoadOps + +trait LLVMLoadImpl[G] extends LLVMLoadOps[G] { + this: LLVMLoad[G] => + override val t: Type[G] = this.loadType +} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmLocalImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMLocalImpl.scala similarity index 55% rename from src/col/vct/col/ast/lang/llvm/LlvmLocalImpl.scala rename to src/col/vct/col/ast/lang/llvm/LLVMLocalImpl.scala index 0baa756520..0a02d992fb 100644 --- a/src/col/vct/col/ast/lang/llvm/LlvmLocalImpl.scala +++ b/src/col/vct/col/ast/lang/llvm/LLVMLocalImpl.scala @@ -1,11 +1,11 @@ package vct.col.ast.lang.llvm -import vct.col.ast.{LlvmLocal, Type} +import vct.col.ast.{LLVMLocal, Type} import vct.col.print.{Ctx, Doc, Text} -import vct.col.ast.ops.LlvmLocalOps +import vct.col.ast.ops.LLVMLocalOps -trait LlvmLocalImpl[G] extends LlvmLocalOps[G] { - this: LlvmLocal[G] => +trait LLVMLocalImpl[G] extends LLVMLocalOps[G] { + this: LLVMLocal[G] => override lazy val t: Type[G] = ref.get.decl.t override def layout(implicit ctx: Ctx): Doc = Text(name) diff --git a/src/col/vct/col/ast/lang/llvm/LLVMLoopContractImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMLoopContractImpl.scala new file mode 100644 index 0000000000..17bcc24632 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMLoopContractImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMLoopContract +import vct.col.ast.ops.LLVMLoopContractFamilyOps + +trait LLVMLoopContractImpl[G] extends LLVMLoopContractFamilyOps[G] { + this: LLVMLoopContract[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMLoopImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMLoopImpl.scala new file mode 100644 index 0000000000..49c130ba3a --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMLoopImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMLoop +import vct.col.ast.ops.LLVMLoopOps + +trait LLVMLoopImpl[G] extends LLVMLoopOps[G] { + this: LLVMLoop[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMLoopInvariantImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMLoopInvariantImpl.scala new file mode 100644 index 0000000000..ee4eeb2c2e --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMLoopInvariantImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMLoopInvariant +import vct.col.ast.ops.LLVMLoopInvariantOps + +trait LLVMLoopInvariantImpl[G] extends LLVMLoopInvariantOps[G] { + this: LLVMLoopInvariant[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireImpl.scala new file mode 100644 index 0000000000..4aaafdb0b5 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryAcquire +import vct.col.ast.ops.LLVMMemoryAcquireOps +import vct.col.print._ + +trait LLVMMemoryAcquireImpl[G] extends LLVMMemoryAcquireOps[G] { + this: LLVMMemoryAcquire[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireReleaseImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireReleaseImpl.scala new file mode 100644 index 0000000000..87fd27b4ea --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryAcquireReleaseImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryAcquireRelease +import vct.col.ast.ops.LLVMMemoryAcquireReleaseOps +import vct.col.print._ + +trait LLVMMemoryAcquireReleaseImpl[G] extends LLVMMemoryAcquireReleaseOps[G] { + this: LLVMMemoryAcquireRelease[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryMonotonicImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryMonotonicImpl.scala new file mode 100644 index 0000000000..b3d700bc42 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryMonotonicImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryMonotonic +import vct.col.ast.ops.LLVMMemoryMonotonicOps +import vct.col.print._ + +trait LLVMMemoryMonotonicImpl[G] extends LLVMMemoryMonotonicOps[G] { + this: LLVMMemoryMonotonic[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryNotAtomicImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryNotAtomicImpl.scala new file mode 100644 index 0000000000..796ceb4c7e --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryNotAtomicImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryNotAtomic +import vct.col.ast.ops.LLVMMemoryNotAtomicOps +import vct.col.print._ + +trait LLVMMemoryNotAtomicImpl[G] extends LLVMMemoryNotAtomicOps[G] { + this: LLVMMemoryNotAtomic[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryOrderingImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryOrderingImpl.scala new file mode 100644 index 0000000000..b4ece7c46b --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryOrderingImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryOrdering +import vct.col.ast.ops.LLVMMemoryOrderingFamilyOps +import vct.col.print._ + +trait LLVMMemoryOrderingImpl[G] extends LLVMMemoryOrderingFamilyOps[G] { + this: LLVMMemoryOrdering[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryReleaseImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryReleaseImpl.scala new file mode 100644 index 0000000000..e856bc3b35 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryReleaseImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryRelease +import vct.col.ast.ops.LLVMMemoryReleaseOps +import vct.col.print._ + +trait LLVMMemoryReleaseImpl[G] extends LLVMMemoryReleaseOps[G] { + this: LLVMMemoryRelease[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemorySequentiallyConsistentImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemorySequentiallyConsistentImpl.scala new file mode 100644 index 0000000000..9576bcb1e6 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemorySequentiallyConsistentImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemorySequentiallyConsistent +import vct.col.ast.ops.LLVMMemorySequentiallyConsistentOps +import vct.col.print._ + +trait LLVMMemorySequentiallyConsistentImpl[G] + extends LLVMMemorySequentiallyConsistentOps[G] { + this: LLVMMemorySequentiallyConsistent[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMMemoryUnorderedImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMMemoryUnorderedImpl.scala new file mode 100644 index 0000000000..7f929bf5fb --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMMemoryUnorderedImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMMemoryUnordered +import vct.col.ast.ops.LLVMMemoryUnorderedOps +import vct.col.print._ + +trait LLVMMemoryUnorderedImpl[G] extends LLVMMemoryUnorderedOps[G] { + this: LLVMMemoryUnordered[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMPointerValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMPointerValueImpl.scala new file mode 100644 index 0000000000..890bab6ca6 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMPointerValueImpl.scala @@ -0,0 +1,23 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{ + LLVMGlobalVariable, + LLVMPointerValue, + LLVMTPointer, + Type, + HeapVariable, +} +import vct.col.ast.ops.LLVMPointerValueOps +import vct.col.print._ + +trait LLVMPointerValueImpl[G] extends LLVMPointerValueOps[G] { + this: LLVMPointerValue[G] => + override lazy val t: Type[G] = { + value.decl match { + case LLVMGlobalVariable(variableType, _, _) => + LLVMTPointer(Some(variableType)) + case v: HeapVariable[G] => LLVMTPointer(Some(v.t)) + } + } + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMRawArrayValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMRawArrayValueImpl.scala new file mode 100644 index 0000000000..e923da0f96 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMRawArrayValueImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMRawArrayValue} +import vct.col.ast.ops.LLVMRawArrayValueOps +import vct.col.print._ + +trait LLVMRawArrayValueImpl[G] extends LLVMRawArrayValueOps[G] { + this: LLVMRawArrayValue[G] => + override def t: Type[G] = arrayType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMRawVectorValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMRawVectorValueImpl.scala new file mode 100644 index 0000000000..738f4add09 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMRawVectorValueImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMRawVectorValue} +import vct.col.ast.ops.LLVMRawVectorValueOps +import vct.col.print._ + +trait LLVMRawVectorValueImpl[G] extends LLVMRawVectorValueOps[G] { + this: LLVMRawVectorValue[G] => + override def t: Type[G] = vectorType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMSignExtendImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMSignExtendImpl.scala new file mode 100644 index 0000000000..5fb7c7b1c3 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMSignExtendImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{LLVMSignExtend, Type} +import vct.col.ast.ops.LLVMSignExtendOps +import vct.col.print._ + +trait LLVMSignExtendImpl[G] extends LLVMSignExtendOps[G] { + this: LLVMSignExtend[G] => + override def t: Type[G] = outputType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmSpecFunctionImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMSpecFunctionImpl.scala similarity index 86% rename from src/col/vct/col/ast/lang/llvm/LlvmSpecFunctionImpl.scala rename to src/col/vct/col/ast/lang/llvm/LLVMSpecFunctionImpl.scala index fe9430a026..a6b204bd7e 100644 --- a/src/col/vct/col/ast/lang/llvm/LlvmSpecFunctionImpl.scala +++ b/src/col/vct/col/ast/lang/llvm/LLVMSpecFunctionImpl.scala @@ -1,18 +1,18 @@ package vct.col.ast.lang.llvm -import vct.col.ast.LlvmSpecFunction +import vct.col.ast.LLVMSpecFunction import vct.col.ast.declaration.category.AbstractFunctionImpl import vct.col.ast.declaration.global.GlobalDeclarationImpl import vct.col.print.{Ctx, Doc, Empty, Group, Show, Text} import scala.collection.immutable.ListMap -import vct.col.ast.ops.LlvmSpecFunctionOps +import vct.col.ast.ops.LLVMSpecFunctionOps -trait LlvmSpecFunctionImpl[G] +trait LLVMSpecFunctionImpl[G] extends GlobalDeclarationImpl[G] with AbstractFunctionImpl[G] - with LlvmSpecFunctionOps[G] { - this: LlvmSpecFunction[G] => + with LLVMSpecFunctionOps[G] { + this: LLVMSpecFunction[G] => def layoutModifiers(implicit ctx: Ctx): Seq[Doc] = ListMap(inline -> "inline", threadLocal -> "thread_local").filter(_._1) diff --git a/src/col/vct/col/ast/lang/llvm/LLVMStatementImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMStatementImpl.scala new file mode 100644 index 0000000000..3e8a6f6a5c --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMStatementImpl.scala @@ -0,0 +1,7 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMStatement +trait LLVMStatementImpl[G] { + this: LLVMStatement[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMStoreImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMStoreImpl.scala new file mode 100644 index 0000000000..9b3b82337d --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMStoreImpl.scala @@ -0,0 +1,8 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMStore +import vct.col.ast.ops.LLVMStoreOps + +trait LLVMStoreImpl[G] extends LLVMStoreOps[G] { + this: LLVMStore[G] => +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMStructValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMStructValueImpl.scala new file mode 100644 index 0000000000..a37d6ab04e --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMStructValueImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{LLVMStructValue, Type} +import vct.col.ast.ops.LLVMStructValueOps +import vct.col.print._ + +trait LLVMStructValueImpl[G] extends LLVMStructValueOps[G] { + this: LLVMStructValue[G] => + override def t: Type[G] = structType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTArrayImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTArrayImpl.scala new file mode 100644 index 0000000000..fbceb6ba2b --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTArrayImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTArray +import vct.col.ast.ops.LLVMTArrayOps +import vct.col.print._ + +trait LLVMTArrayImpl[G] extends LLVMTArrayOps[G] { + this: LLVMTArray[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTFunctionImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTFunctionImpl.scala new file mode 100644 index 0000000000..d96fa61d59 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTFunctionImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTFunction +import vct.col.ast.ops.LLVMTFunctionOps +import vct.col.print._ + +trait LLVMTFunctionImpl[G] extends LLVMTFunctionOps[G] { + this: LLVMTFunction[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTIntImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTIntImpl.scala new file mode 100644 index 0000000000..697c024544 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTIntImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTInt +import vct.col.ast.ops.LLVMTIntOps +import vct.col.print._ + +trait LLVMTIntImpl[G] extends LLVMTIntOps[G] { + this: LLVMTInt[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTMetadataImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTMetadataImpl.scala new file mode 100644 index 0000000000..bbf522bc87 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTMetadataImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTMetadata +import vct.col.ast.ops.LLVMTMetadataOps + +trait LLVMTMetadataImpl[G] extends LLVMTMetadataOps[G] { + this: LLVMTMetadata[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTPointerImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTPointerImpl.scala new file mode 100644 index 0000000000..770fa9295c --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTPointerImpl.scala @@ -0,0 +1,9 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTPointer +import vct.col.ast.ops.LLVMTPointerOps + +trait LLVMTPointerImpl[G] extends LLVMTPointerOps[G] { + this: LLVMTPointer[G] => + +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTStructImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTStructImpl.scala new file mode 100644 index 0000000000..cb839186b9 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTStructImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTStruct +import vct.col.ast.ops.LLVMTStructOps +import vct.col.print._ + +trait LLVMTStructImpl[G] extends LLVMTStructOps[G] { + this: LLVMTStruct[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTVectorImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTVectorImpl.scala new file mode 100644 index 0000000000..6bc89d8b85 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTVectorImpl.scala @@ -0,0 +1,10 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.LLVMTVector +import vct.col.ast.ops.LLVMTVectorOps +import vct.col.print._ + +trait LLVMTVectorImpl[G] extends LLVMTVectorOps[G] { + this: LLVMTVector[G] => + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMTruncateImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMTruncateImpl.scala new file mode 100644 index 0000000000..25344cf63a --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMTruncateImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{LLVMTruncate, Type} +import vct.col.ast.ops.LLVMTruncateOps +import vct.col.print._ + +trait LLVMTruncateImpl[G] extends LLVMTruncateOps[G] { + this: LLVMTruncate[G] => + override def t: Type[G] = outputType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMVectorValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMVectorValueImpl.scala new file mode 100644 index 0000000000..3661272542 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMVectorValueImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMVectorValue} +import vct.col.print._ +import vct.col.ast.ops.LLVMVectorValueOps + +trait LLVMVectorValueImpl[G] extends LLVMVectorValueOps[G] { + this: LLVMVectorValue[G] => + override def t: Type[G] = vectorType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMZeroExtendImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMZeroExtendImpl.scala new file mode 100644 index 0000000000..eca0bfddc0 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMZeroExtendImpl.scala @@ -0,0 +1,11 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{LLVMZeroExtend, Type} +import vct.col.ast.ops.LLVMZeroExtendOps +import vct.col.print._ + +trait LLVMZeroExtendImpl[G] extends LLVMZeroExtendOps[G] { + this: LLVMZeroExtend[G] => + override def t: Type[G] = outputType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LLVMZeroedAggregateValueImpl.scala b/src/col/vct/col/ast/lang/llvm/LLVMZeroedAggregateValueImpl.scala new file mode 100644 index 0000000000..e8217e0c40 --- /dev/null +++ b/src/col/vct/col/ast/lang/llvm/LLVMZeroedAggregateValueImpl.scala @@ -0,0 +1,12 @@ +package vct.col.ast.lang.llvm + +import vct.col.ast.{Type, LLVMZeroedAggregateValue} +import vct.col.ast.ops.LLVMZeroedAggregateValueOps +import vct.col.print._ + +trait LLVMZeroedAggregateValueImpl[G] extends LLVMZeroedAggregateValueOps[G] { + this: LLVMZeroedAggregateValue[G] => + override def value: Unit = () + override def t: Type[G] = aggregateType + // override def layout(implicit ctx: Ctx): Doc = ??? +} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmExprImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmExprImpl.scala deleted file mode 100644 index 6b4c7524e8..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmExprImpl.scala +++ /dev/null @@ -1,7 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.LlvmExpr -trait LlvmExprImpl[G] { - this: LlvmExpr[G] => - -} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmFunctionContractImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmFunctionContractImpl.scala deleted file mode 100644 index 48c8828248..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmFunctionContractImpl.scala +++ /dev/null @@ -1,9 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.LlvmFunctionContract -import vct.col.ast.ops.{LlvmFunctionContractOps, LlvmFunctionContractFamilyOps} - -trait LlvmFunctionContractImpl[G] - extends LlvmFunctionContractOps[G] with LlvmFunctionContractFamilyOps[G] { - this: LlvmFunctionContract[G] => -} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmFunctionDefinitionImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmFunctionDefinitionImpl.scala deleted file mode 100644 index 89b836798c..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmFunctionDefinitionImpl.scala +++ /dev/null @@ -1,16 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.declaration.category.ApplicableImpl -import vct.col.ast.{Declaration, LlvmFunctionDefinition, Statement} -import vct.col.ast.util.Declarator -import vct.col.ast.ops.LlvmFunctionDefinitionOps - -trait LlvmFunctionDefinitionImpl[G] - extends Declarator[G] - with ApplicableImpl[G] - with LlvmFunctionDefinitionOps[G] { - this: LlvmFunctionDefinition[G] => - override def declarations: Seq[Declaration[G]] = args - - override def body: Option[Statement[G]] = Some(functionBody) -} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmGlobalImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmGlobalImpl.scala deleted file mode 100644 index 3a92e81e9e..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmGlobalImpl.scala +++ /dev/null @@ -1,12 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.LlvmGlobal -import vct.col.print.{Ctx, Doc, Text} -import vct.col.ast.ops.LlvmGlobalOps - -trait LlvmGlobalImpl[G] extends LlvmGlobalOps[G] { - this: LlvmGlobal[G] => - - override def layout(implicit ctx: Ctx): Doc = Text(value) - -} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmLoopContractImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmLoopContractImpl.scala deleted file mode 100644 index 95f2c492c5..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmLoopContractImpl.scala +++ /dev/null @@ -1,9 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.LlvmLoopContract -import vct.col.ast.ops.LlvmLoopContractFamilyOps - -trait LlvmLoopContractImpl[G] extends LlvmLoopContractFamilyOps[G] { - this: LlvmLoopContract[G] => - -} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmLoopImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmLoopImpl.scala deleted file mode 100644 index 29b2aca394..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmLoopImpl.scala +++ /dev/null @@ -1,9 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.LlvmLoop -import vct.col.ast.ops.LlvmLoopOps - -trait LlvmLoopImpl[G] extends LlvmLoopOps[G] { - this: LlvmLoop[G] => - -} diff --git a/src/col/vct/col/ast/lang/llvm/LlvmLoopInvariantImpl.scala b/src/col/vct/col/ast/lang/llvm/LlvmLoopInvariantImpl.scala deleted file mode 100644 index 30f26a31b1..0000000000 --- a/src/col/vct/col/ast/lang/llvm/LlvmLoopInvariantImpl.scala +++ /dev/null @@ -1,9 +0,0 @@ -package vct.col.ast.lang.llvm - -import vct.col.ast.LlvmLoopInvariant -import vct.col.ast.ops.LlvmLoopInvariantOps - -trait LlvmLoopInvariantImpl[G] extends LlvmLoopInvariantOps[G] { - this: LlvmLoopInvariant[G] => - -} diff --git a/src/col/vct/col/ast/statement/exceptional/ReturnImpl.scala b/src/col/vct/col/ast/statement/exceptional/ReturnImpl.scala index c0a39fd96e..f260c33f03 100644 --- a/src/col/vct/col/ast/statement/exceptional/ReturnImpl.scala +++ b/src/col/vct/col/ast/statement/exceptional/ReturnImpl.scala @@ -13,7 +13,7 @@ trait ReturnImpl[G] extends ExceptionalStatementImpl[G] with ReturnOps[G] { _: InstanceOperatorMethod[G] => () case _: JavaMethod[G] | _: CFunctionDefinition[G] | - _: CPPFunctionDefinition[G] | _: LlvmFunctionDefinition[G] => + _: CPPFunctionDefinition[G] | _: LLVMFunctionDefinition[G] => () case _: BipTransition[G] | _: BipGuard[G] | _: BipOutgoingData[G] => () } diff --git a/src/col/vct/col/resolve/Resolve.scala b/src/col/vct/col/resolve/Resolve.scala index 1bd8310820..4c3f8ec18f 100644 --- a/src/col/vct/col/resolve/Resolve.scala +++ b/src/col/vct/col/resolve/Resolve.scala @@ -29,6 +29,8 @@ import vct.col.resolve.lang.JavaAnnotationData.{ BipTransition, } import vct.col.rewrite.InitialGeneration +import vct.col.util.AstBuildHelpers.{ExprBuildHelpers, VarBuildHelpers} +import vct.col.util.Substitute import vct.result.VerificationError.{Unreachable, UserError} import scala.collection.immutable.{AbstractSeq, LinearSeq} @@ -42,11 +44,14 @@ case object Resolve { trait SpecContractParser { def parse[G]( - input: LlvmFunctionContract[G], + input: LLVMFunctionContract[G], o: Origin, ): ApplicableContract[G] - def parse[G](input: LlvmGlobal[G], o: Origin): Seq[GlobalDeclaration[G]] + def parse[G]( + input: LLVMGlobalSpecification[G], + o: Origin, + ): Seq[GlobalDeclaration[G]] } def extractLiteral(e: Expr[_]): Option[String] = @@ -66,12 +71,14 @@ case object Resolve { case class MalformedBipAnnotation(n: Node[_], err: String) extends UserError { override def code: String = "badBipAnnotation" + override def text: String = n.o.messageInContext(s"Malformed JavaBIP annotation: $err") } case class UnexpectedComplicatedExpression(e: Expr[_]) extends UserError { override def code: String = "unexpectedComplicatedExpression" + override def text: String = e.o.messageInContext( "This expression must either be a string literal or trivially resolve to one" @@ -95,8 +102,10 @@ case object Resolve { case object ResolveTypes { sealed trait JavaClassPathEntry + case object JavaClassPathEntry { case object SourcePackageRoot extends JavaClassPathEntry + case class Path(root: java.nio.file.Path) extends JavaClassPathEntry } @@ -290,8 +299,9 @@ case object ResolveReferences extends LazyLogging { program: Program[G], jp: SpecExprParser, lsp: SpecContractParser, + importedDeclarations: Seq[GlobalDeclaration[G]], ): Seq[CheckError] = { - resolve(program, ReferenceResolutionContext[G](jp, lsp)) + resolve(program, ReferenceResolutionContext[G](jp, lsp, importedDeclarations)) } def resolve[G]( @@ -338,7 +348,7 @@ case object ResolveReferences extends LazyLogging { Right(ctx.copy(inGpuKernel = true)) case p: Program[G] => p.declarations.foreach { - case glob: LlvmGlobal[G] => + case glob: LLVMGlobalSpecification[G] => val decls = ctx.llvmSpecParser.parse(glob, glob.o) glob.data = Some(decls) case _ => @@ -539,10 +549,10 @@ case object ResolveReferences extends LazyLogging { CPP.paramsFromDeclarator(func.declarator) ++ scanLabels(func.body) ++ func.contract.givenArgs ++ func.contract.yieldsArgs ) - case func: LlvmFunctionDefinition[G] => - ctx.copy(currentResult = Some(RefLlvmFunctionDefinition(func))) - case func: LlvmSpecFunction[G] => - ctx.copy(currentResult = Some(RefLlvmSpecFunction(func))) + case func: LLVMFunctionDefinition[G] => + ctx.copy(currentResult = Some(RefLLVMFunctionDefinition(func))) + case func: LLVMSpecFunction[G] => + ctx.copy(currentResult = Some(RefLLVMSpecFunction(func))) .declare(func.args) case par: ParStatement[G] => ctx.declare(scanBlocks(par.impl).map(_.decl)) case Scope(locals, body) => @@ -1099,20 +1109,55 @@ case object ResolveReferences extends LazyLogging { ) => portName.data = Some((cls, getLit(name))) - case contract: LlvmFunctionContract[G] => + case contract: LLVMFunctionContract[G] => + implicit val o: Origin = contract.o + val llvmFunction = + ctx.currentResult.get.asInstanceOf[RefLLVMFunctionDefinition[G]].decl val applicableContract = ctx.llvmSpecParser.parse(contract, contract.o) - contract.data = Some(applicableContract) - resolve(applicableContract, ctx) - case local: LlvmLocal[G] => + val importedDecl = ctx.importedDeclarations.find { + case procedure: Procedure[G] => + contract.name == procedure.o.get[SourceName].name + } + if (importedDecl.isDefined) { + val importedProcedure = importedDecl.get.asInstanceOf[Procedure[G]] + val importedContract = importedProcedure.contract + val substitute = Substitute[G]( + ((Result[G](importedProcedure.ref) -> AmbiguousResult[G]()) +: + importedProcedure.args.zipWithIndex.map { case (l, idx) => + Local[G](l.ref) -> Local[G](llvmFunction.args(idx).ref) + }).toMap + ) + val substitutedContract = substitute.dispatch(importedContract) + contract.data = Some( + ApplicableContract[G]( + SplitAccountedPredicate( + applicableContract.requires, + substitutedContract.requires, + ), + SplitAccountedPredicate( + applicableContract.ensures, + substitutedContract.ensures, + ), + applicableContract.contextEverywhere &* + substitutedContract.contextEverywhere, + applicableContract.signals ++ substitutedContract.signals, + applicableContract.givenArgs ++ substitutedContract.givenArgs, + applicableContract.yieldsArgs ++ substitutedContract.yieldsArgs, + applicableContract.decreases.orElse(substitutedContract.decreases), + )(contract.blame) + ) + } else { contract.data = Some(applicableContract) } + resolve(contract.data.get, ctx) + case local: LLVMLocal[G] => local.ref = ctx.currentResult.get match { - case RefLlvmFunctionDefinition(decl) => + case RefLLVMFunctionDefinition(decl) => decl.contract.variableRefs .find(ref => ref._1 == local.name) match { case Some(ref) => Some(ref._2) case None => throw NoSuchNameError("local", local.name, local) } - case RefLlvmSpecFunction(_) => + case RefLLVMSpecFunction(_) => Some( Spec.findLocal(local.name, ctx) .getOrElse(throw NoSuchNameError("local", local.name, local)) @@ -1120,13 +1165,14 @@ case object ResolveReferences extends LazyLogging { ) case _ => None } - case inv: LlvmAmbiguousFunctionInvocation[G] => + case inv: LLVMAmbiguousFunctionInvocation[G] => inv.ref = LLVM.findCallable(inv.name, ctx) match { case Some(callable) => Some(callable.ref) case None => throw NoSuchNameError("function", inv.name, inv) } - case glob: LlvmGlobal[G] => glob.data.get.foreach(resolve(_, ctx)) + case glob: LLVMGlobalSpecification[G] => + glob.data.get.foreach(resolve(_, ctx)) case comm: PVLCommunicate[G] => /* Endpoint contexts for communicate are resolved early, because otherwise \sender, \receiver, \msg cannot be typed. */ diff --git a/src/col/vct/col/resolve/ctx/ReferenceResolutionContext.scala b/src/col/vct/col/resolve/ctx/ReferenceResolutionContext.scala index 8a7e0c2a3e..db2e9ca2f9 100644 --- a/src/col/vct/col/resolve/ctx/ReferenceResolutionContext.scala +++ b/src/col/vct/col/resolve/ctx/ReferenceResolutionContext.scala @@ -12,6 +12,7 @@ import scala.collection.mutable case class ReferenceResolutionContext[G]( javaParser: SpecExprParser, llvmSpecParser: SpecContractParser, + importedDeclarations: Seq[GlobalDeclaration[G]], stack: Seq[Seq[Referrable[G]]] = Nil, topLevelJavaDeref: Option[JavaDeref[G]] = None, externallyLoadedElements: mutable.ArrayBuffer[GlobalDeclaration[G]] = diff --git a/src/col/vct/col/resolve/ctx/Referrable.scala b/src/col/vct/col/resolve/ctx/Referrable.scala index b146df4d06..c3eabe891d 100644 --- a/src/col/vct/col/resolve/ctx/Referrable.scala +++ b/src/col/vct/col/resolve/ctx/Referrable.scala @@ -92,25 +92,10 @@ sealed trait Referrable[G] { case RefProverType(decl) => Referrable.originName(decl) case RefProverFunction(decl) => Referrable.originName(decl) case RefJavaBipGuard(decl) => Referrable.originName(decl) - case RefLlvmFunctionDefinition(decl) => Referrable.originName(decl) - case RefLlvmGlobal(decl, i) => Referrable.originName(decl.data.get(i)) - case RefLlvmSpecFunction(decl) => Referrable.originName(decl) - case RefBipComponent(decl) => Referrable.originName(decl) - case RefBipGlue(decl) => "" - case RefBipGuard(decl) => Referrable.originName(decl) - case RefBipIncomingData(decl) => Referrable.originName(decl) - case RefBipOutgoingData(decl) => Referrable.originName(decl) - case RefBipPort(decl) => Referrable.originName(decl) - case RefBipPortSynchronization(decl) => "" - case RefBipStatePredicate(decl) => Referrable.originName(decl) - case RefBipTransition(decl) => Referrable.originName(decl) - case RefBipTransitionSynchronization(decl) => "" - case RefBipConstructor(decl) => Referrable.originName(decl) - case RefHeapVariable(decl) => Referrable.originName(decl) - case RefPVLEndpoint(decl) => decl.name - case RefPVLChoreography(decl) => decl.name - case RefPVLChorRun(_) => "" - + case RefLLVMFunctionDefinition(decl) => Referrable.originName(decl) + case RefLLVMGlobalSpecification(decl, i) => Referrable.originName(decl) + case RefLLVMGlobalVariable(decl) => Referrable.originName(decl) + case RefLLVMSpecFunction(decl) => Referrable.originName(decl) case RefJavaBipGlueContainer() => "" case PVLBuiltinInstanceMethod(_) => "" case BuiltinField(_) => "" @@ -201,13 +186,15 @@ case object Referrable { case decl: PVLConstructor[G] => RefPVLConstructor(decl) case decl: Choreography[G] => RefChoreography(decl) case decl: Endpoint[G] => RefEndpoint(decl) - case decl: LlvmFunctionDefinition[G] => RefLlvmFunctionDefinition(decl) - case decl: LlvmGlobal[G] => + case decl: LLVMFunctionDefinition[G] => RefLLVMFunctionDefinition(decl) + case decl: LLVMGlobalSpecification[G] => decl.data match { - case Some(data) => return data.indices.map(RefLlvmGlobal(decl, _)) - case None => RefLlvmGlobal(decl, -1) + case Some(data) => + return data.indices.map(RefLLVMGlobalSpecification(decl, _)) + case None => RefLLVMGlobalSpecification(decl, -1) } - case decl: LlvmSpecFunction[G] => RefLlvmSpecFunction(decl) + case decl: LLVMSpecFunction[G] => RefLLVMSpecFunction(decl) + case decl: LLVMGlobalVariable[G] => RefLLVMGlobalVariable(decl) case decl: ProverType[G] => RefProverType(decl) case decl: ProverFunction[G] => RefProverFunction(decl) case decl: JavaBipGlueContainer[G] => RefJavaBipGlueContainer() @@ -282,7 +269,7 @@ sealed trait JavaInvocationTarget[G] extends Referrable[G] sealed trait CInvocationTarget[G] extends Referrable[G] sealed trait CPPInvocationTarget[G] extends Referrable[G] sealed trait PVLInvocationTarget[G] extends Referrable[G] -sealed trait LlvmInvocationTarget[G] extends Referrable[G] +sealed trait LLVMInvocationTarget[G] extends Referrable[G] sealed trait SpecInvocationTarget[G] extends JavaInvocationTarget[G] with CNameTarget[G] @@ -292,7 +279,7 @@ sealed trait SpecInvocationTarget[G] with CPPDerefTarget[G] with CPPInvocationTarget[G] with PVLInvocationTarget[G] - with LlvmInvocationTarget[G] + with LLVMInvocationTarget[G] sealed trait ThisTarget[G] extends Referrable[G] @@ -454,9 +441,14 @@ case class RefJavaBipGuard[G](decl: JavaMethod[G]) extends Referrable[G] with JavaNameTarget[G] case class RefJavaBipGlueContainer[G]() extends Referrable[G] // Bip glue jobs are not actually referrable -case class RefLlvmFunctionDefinition[G](decl: LlvmFunctionDefinition[G]) - extends Referrable[G] with LlvmInvocationTarget[G] with ResultTarget[G] -case class RefLlvmGlobal[G](decl: LlvmGlobal[G], idx: Int) extends Referrable[G] +case class RefLLVMFunctionDefinition[G](decl: LLVMFunctionDefinition[G]) + extends Referrable[G] with LLVMInvocationTarget[G] with ResultTarget[G] +case class RefLLVMGlobalSpecification[G]( + decl: LLVMGlobalSpecification[G], + idx: Int, +) extends Referrable[G] +case class RefLLVMGlobalVariable[G](decl: LLVMGlobalVariable[G]) + extends Referrable[G] case class RefBipComponent[G](decl: BipComponent[G]) extends Referrable[G] case class RefBipGlue[G](decl: BipGlue[G]) extends Referrable[G] case class RefBipGuard[G](decl: BipGuard[G]) extends Referrable[G] @@ -478,9 +470,8 @@ case class RefPVLEndpoint[G](decl: PVLEndpoint[G]) case class RefPVLChoreography[G](decl: PVLChoreography[G]) extends Referrable[G] with ThisTarget[G] case class RefPVLChorRun[G](decl: PVLChorRun[G]) extends Referrable[G] - -case class RefLlvmSpecFunction[G](decl: LlvmSpecFunction[G]) - extends Referrable[G] with LlvmInvocationTarget[G] with ResultTarget[G] +case class RefLLVMSpecFunction[G](decl: LLVMSpecFunction[G]) + extends Referrable[G] with LLVMInvocationTarget[G] with ResultTarget[G] case class RefChoreography[G](decl: Choreography[G]) extends Referrable[G] with ThisTarget[G] case class RefEndpoint[G](decl: Endpoint[G]) extends Referrable[G] diff --git a/src/col/vct/col/resolve/lang/LLVM.scala b/src/col/vct/col/resolve/lang/LLVM.scala index e010a9aaec..f81a8bbfbf 100644 --- a/src/col/vct/col/resolve/lang/LLVM.scala +++ b/src/col/vct/col/resolve/lang/LLVM.scala @@ -10,12 +10,12 @@ object LLVM { def findCallable[G]( name: String, ctx: ReferenceResolutionContext[G], - ): Option[LlvmCallable[G]] = { + ): Option[LLVMCallable[G]] = { // look in context val callable = ctx.stack.flatten.map { - case RefLlvmGlobal(decl, i) => + case RefLLVMGlobalSpecification(decl, i) => decl.data.get(i) match { - case f: LlvmSpecFunction[G] if f.name == name => Some(f) + case f: LLVMSpecFunction[G] if f.name == name => Some(f) case _ => None } case _ => None @@ -25,7 +25,7 @@ object LLVM { case Some(callable) => Some(callable) case None => ctx.currentResult.get match { - case RefLlvmFunctionDefinition(decl) => + case RefLLVMFunctionDefinition(decl) => decl.contract.invokableRefs.find(ref => ref._1 == name) match { case Some(ref) => Some(ref._2.decl) case None => None diff --git a/src/col/vct/col/serialize/SerializeOrigin.scala b/src/col/vct/col/serialize/SerializeOrigin.scala index 86e479728c..bcee9d6735 100644 --- a/src/col/vct/col/serialize/SerializeOrigin.scala +++ b/src/col/vct/col/serialize/SerializeOrigin.scala @@ -54,7 +54,7 @@ case class DeserializedContext( (context, tail) override protected def inlineContextHere( tail: Origin, - compress: Boolean, + compress: Boolean = true, ): (String, Origin) = (inlineContext, tail) override protected def shortPositionHere(tail: Origin): (String, Origin) = (shortPosition, tail) diff --git a/src/col/vct/col/typerules/CoercingRewriter.scala b/src/col/vct/col/typerules/CoercingRewriter.scala index baf88034cf..b7d62063bf 100644 --- a/src/col/vct/col/typerules/CoercingRewriter.scala +++ b/src/col/vct/col/typerules/CoercingRewriter.scala @@ -301,6 +301,10 @@ abstract class CoercingRewriter[Pre <: Generation]() case CoerceCIntCFloat(_) => e case CoerceCIntInt() => e case CoerceCFloatFloat(_, _) => e + + case CoerceLLVMIntInt() => e + case CoerceLLVMPointer(_, _) => e + case CoerceLLVMArray(_, _) => e } } @@ -349,8 +353,9 @@ abstract class CoercingRewriter[Pre <: Generation]() case node: BipGlueAccepts[Pre] => node case node: BipGlueDataWire[Pre] => node case node: BipTransitionSignature[Pre] => node - case node: LlvmFunctionContract[Pre] => node - case node: LlvmLoopContract[Pre] => node + case node: LLVMFunctionContract[Pre] => node + case node: LLVMLoopContract[Pre] => node + case node: LLVMMemoryOrdering[Pre] => node case node: ProverLanguage[Pre] => node case node: SmtlibFunctionSymbol[Pre] => node case node: ChorRun[Pre] => node @@ -543,6 +548,15 @@ abstract class CoercingRewriter[Pre <: Generation]() (ApplyCoercion(e, coercion)(coercionOrigin(e)), t) case None => throw IncoercibleText(e, s"pointer") } + def llvmPointer( + e: Expr[Pre], + innerType: Type[Pre], + ): (Expr[Pre], TPointer[Pre]) = + CoercionUtils.getAnyLLVMPointerCoercion(e.t, innerType) match { + case Some((coercion, t)) => + (ApplyCoercion(e, coercion)(coercionOrigin(e)), t) + case None => throw IncoercibleText(e, s"llvm pointer of $innerType") + } def matrix(e: Expr[Pre]): (Expr[Pre], TMatrix[Pre]) = CoercionUtils.getAnyMatrixCoercion(e.t) match { case Some((coercion, t)) => @@ -1648,15 +1662,15 @@ abstract class CoercingRewriter[Pre <: Generation]() coerceYields(yields, inv), )(inv.blame) ) - case inv @ LlvmFunctionInvocation(ref, args, givenMap, yields) => - LlvmFunctionInvocation(ref, args, givenMap, yields)(inv.blame) - case inv @ LlvmAmbiguousFunctionInvocation( + case inv @ LLVMFunctionInvocation(ref, args, givenMap, yields) => + LLVMFunctionInvocation(ref, args, givenMap, yields)(inv.blame) + case inv @ LLVMAmbiguousFunctionInvocation( name, args, givenMap, yields, ) => - LlvmAmbiguousFunctionInvocation(name, args, givenMap, yields)(inv.blame) + LLVMAmbiguousFunctionInvocation(name, args, givenMap, yields)(inv.blame) case ProcessApply(process, args) => ProcessApply(process, coerceArgs(args, process.decl)) case ProcessChoice(left, right) => @@ -2127,13 +2141,35 @@ abstract class CoercingRewriter[Pre <: Generation]() Z3TransitiveClosure(ref, coerceArgs(args, ref.ref.decl)) case localIncoming: BipLocalIncomingData[Pre] => localIncoming case glue: JavaBipGlue[Pre] => glue - case LlvmLocal(name) => e case PVLSender() => e case PVLReceiver() => e case PVLMessage() => e case Sender(_) => e case Receiver(_) => e case Message(_) => e + case LLVMLocal(name) => e + case LLVMAllocA(allocationType, numElements) => e + case LLVMLoad(loadType, p, ordering) => + LLVMLoad(loadType, llvmPointer(p, loadType)._1, ordering) + case LLVMGetElementPointer(structureType, resultType, pointer, indices) => + LLVMGetElementPointer( + structureType, + resultType, + llvmPointer(pointer, structureType)._1, + indices, + ) + case LLVMSignExtend(inputType, outputType, value) => e + case LLVMZeroExtend(inputType, outputType, value) => e + case LLVMTruncate(inputType, outputType, value) => e + case LLVMIntegerValue(value, integerType) => e + case LLVMPointerValue(value) => e + case LLVMFunctionPointerValue(value) => e + case LLVMStructValue(value, structType) => e + case LLVMArrayValue(value, arrayType) => e + case LLVMRawArrayValue(value, arrayType) => e + case LLVMVectorValue(value, vectorType) => e + case LLVMRawVectorValue(value, vectorType) => e + case LLVMZeroedAggregateValue(aggregateType) => e } } @@ -2240,8 +2276,10 @@ abstract class CoercingRewriter[Pre <: Generation]() case l @ Lock(obj) => Lock(cls(obj))(l.blame) case Loop(init, cond, update, contract, body) => Loop(init, bool(cond), update, contract, body) - case LlvmLoop(cond, contract, body) => - LlvmLoop(bool(cond), contract, body) + case LLVMLoop(cond, contract, body) => + LLVMLoop(bool(cond), contract, body) + case LLVMStore(value, p, ordering) => + LLVMStore(value, llvmPointer(p, value.t)._1, ordering) case ModelDo(model, perm, after, action, impl) => ModelDo(model, rat(perm), after, action, impl) case n @ Notify(obj) => Notify(cls(obj))(n.blame) @@ -2507,11 +2545,11 @@ abstract class CoercingRewriter[Pre <: Generation]() case glue: BipGlue[Pre] => glue case synchronization: BipPortSynchronization[Pre] => synchronization case synchronization: BipTransitionSynchronization[Pre] => synchronization - case definition: LlvmFunctionDefinition[Pre] => definition + case definition: LLVMFunctionDefinition[Pre] => definition case typ: ProverType[Pre] => typ case func: ProverFunction[Pre] => func - case function: LlvmSpecFunction[Pre] => - new LlvmSpecFunction[Pre]( + case function: LLVMSpecFunction[Pre] => + new LLVMSpecFunction[Pre]( function.name, function.returnType, function.args, @@ -2521,7 +2559,8 @@ abstract class CoercingRewriter[Pre <: Generation]() function.inline, function.threadLocal, )(function.blame) - case glob: LlvmGlobal[Pre] => glob + case glob: LLVMGlobalSpecification[Pre] => glob + case glob: LLVMGlobalVariable[Pre] => glob case endpoint: PVLEndpoint[Pre] => endpoint case seqProg: PVLChoreography[Pre] => seqProg case seqRun: PVLChorRun[Pre] => seqRun @@ -2922,8 +2961,9 @@ abstract class CoercingRewriter[Pre <: Generation]() def coerce(node: JavaBipGlueElement[Pre]): JavaBipGlueElement[Pre] = node def coerce(node: JavaBipGlueName[Pre]): JavaBipGlueName[Pre] = node - def coerce(node: LlvmFunctionContract[Pre]): LlvmFunctionContract[Pre] = node - def coerce(node: LlvmLoopContract[Pre]): LlvmLoopContract[Pre] = node + def coerce(node: LLVMFunctionContract[Pre]): LLVMFunctionContract[Pre] = node + def coerce(node: LLVMLoopContract[Pre]): LLVMLoopContract[Pre] = node + def coerce(node: LLVMMemoryOrdering[Pre]): LLVMMemoryOrdering[Pre] = node def coerce(node: ProverLanguage[Pre]): ProverLanguage[Pre] = node def coerce(node: SmtlibFunctionSymbol[Pre]): SmtlibFunctionSymbol[Pre] = node diff --git a/src/col/vct/col/typerules/CoercionUtils.scala b/src/col/vct/col/typerules/CoercionUtils.scala index 47295af0af..dcffe8c925 100644 --- a/src/col/vct/col/typerules/CoercionUtils.scala +++ b/src/col/vct/col/typerules/CoercionUtils.scala @@ -6,6 +6,8 @@ import vct.col.origin.{DiagnosticOrigin, Origin} import vct.col.resolve.lang.{C, CPP} import vct.col.resolve.lang.CPP.getBaseTypeFromSpecs +import scala.annotation.tailrec + case object CoercionUtils { private implicit val o: Origin = DiagnosticOrigin @@ -123,6 +125,8 @@ case object CoercionUtils { case (TNull(), TAnyClass()) => CoerceNullAnyClass() case (TNull(), TPointer(target)) => CoerceNullPointer(target) case (TNull(), CTPointer(target)) => CoerceNullPointer(target) + case (TNull(), LLVMTPointer(Some(target))) => CoerceNullPointer(target) + case (TNull(), LLVMTPointer(None)) => CoerceNullPointer(TAny()) case (TNull(), TEnum(target)) => CoerceNullEnum(target) case (CTArray(_, innerType), TArray(element)) if element == innerType => @@ -193,6 +197,7 @@ case object CoercionUtils { CoerceCFloatFloat(coercedCFloat, target), )) case (TCInt(), TInt()) => CoerceCIntInt() + case (LLVMTInt(_), TInt()) => CoerceLLVMIntInt() case (TBoundedInt(gte, lt), TFraction()) if gte >= 1 && lt <= 2 => CoerceBoundIntFrac() @@ -300,6 +305,26 @@ case object CoercionUtils { case None => return None } + // TODO: Back and forth should not be needed... + case (LLVMTPointer(Some(_)), LLVMTPointer(None)) => + CoerceIdentity(LLVMTPointer(None)) + case (LLVMTPointer(None), LLVMTPointer(Some(innerType))) => + CoerceIdentity(LLVMTPointer(Some(innerType))) + case (TPointer(_), LLVMTPointer(None)) => + CoerceIdentity(LLVMTPointer(None)) + case (LLVMTPointer(None), TPointer(innerType)) => + CoerceLLVMPointer(None, innerType) + case ( + LLVMTPointer(Some(LLVMTArray(numElements, elementType))), + TPointer(innerType), + ) if numElements > 0 => + getAnyCoercion(elementType, innerType).getOrElse(return None) + case (LLVMTPointer(Some(leftInner)), TPointer(rightInner)) => + getAnyCoercion(leftInner, rightInner).getOrElse(return None) + + case (TPointer(TAny()), TPointer(any)) => CoerceIdentity(TPointer(any)) + case (TPointer(any), TPointer(TAny())) => CoerceIdentity(TPointer(any)) + // Something with TVar? // Unsafe coercions @@ -436,12 +461,54 @@ case object CoercionUtils { case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyPointerCoercion) case t: CPPTArray[G] => Some((CoerceCPPArrayPointer(t.innerType), TPointer(t.innerType))) + case LLVMTPointer(None) => + Some((CoerceIdentity(source), TPointer[G](TAnyValue()))) + case LLVMTPointer(Some(innerType)) => + Some((CoerceIdentity(source), TPointer(innerType))) + case LLVMTArray(numElements, innerType) if numElements > 0 => + Some((CoerceIdentity(source), TPointer(innerType))) case _: TNull[G] => val t = TPointer[G](TAnyValue()) Some((CoerceNullPointer(t), t)) case _ => None } + @tailrec + def firstElementIsType[G](aggregate: Type[G], innerType: Type[G]): Boolean = + aggregate match { + case aggregate if getAnyCoercion(aggregate, innerType).isDefined => true + case clazz: TClass[G] => + firstElementIsType( + clazz.cls.decl.declarations.head.asInstanceOf[InstanceField[G]].t, + innerType, + ) + case TArray(element) => firstElementIsType(element, innerType) + case LLVMTStruct(_, _, elements) => + firstElementIsType(elements.head, innerType) + case LLVMTArray(numElements, elementType) => + numElements > 0 && firstElementIsType(elementType, innerType) + case LLVMTVector(_, _) => false // TODO: Should this be possible? + case _ => false + } + + def getAnyLLVMPointerCoercion[G]( + source: Type[G], + innerType: Type[G], + ): Option[(Coercion[G], TPointer[G])] = + source match { + case LLVMTPointer(None) => + Some((CoerceLLVMPointer(None, innerType), TPointer[G](innerType))) + case LLVMTPointer(Some(t)) if firstElementIsType(t, innerType) => + Some(CoerceLLVMPointer(Some(t), innerType), TPointer[G](innerType)) + case TPointer(TAny()) => + Some((CoerceLLVMPointer(None, innerType), TPointer[G](innerType))) + case TPointer(t) if firstElementIsType(t, innerType) => + Some(CoerceLLVMPointer(Some(t), innerType), TPointer[G](innerType)) + case _: TNull[G] => + Some((CoerceLLVMPointer(None, innerType), TPointer[G](innerType))) + case _ => None + } + def getAnyCArrayCoercion[G]( source: Type[G] ): Option[(Coercion[G], CTArray[G])] = @@ -479,6 +546,21 @@ case object CoercionUtils { .asInstanceOf[TArray[G]], )) case t: TArray[G] => Some((CoerceIdentity(source), t)) + case t: LLVMTArray[G] => { + val t2 = TArray[G](t.elementType) + Some(CoerceLLVMArray(t, t2), t2) + } + case LLVMTPointer(None) => + Some(CoerceIdentity(source), TArray[G](TAnyValue())) + case LLVMTPointer(Some(t)) => + getAnyArrayCoercion(t) match { + case Some(inner) => + Some( + CoercionSequence(Seq(inner._1, CoerceIdentity(source))), + inner._2, + ) + case None => None + } case _: TNull[G] => val t = TArray[G](TAnyValue()) Some((CoerceNullArray(t), t)) diff --git a/src/col/vct/col/typerules/Types.scala b/src/col/vct/col/typerules/Types.scala index c06bdb2e45..118485dbe5 100644 --- a/src/col/vct/col/typerules/Types.scala +++ b/src/col/vct/col/typerules/Types.scala @@ -91,6 +91,9 @@ object Types { case (TBoundedInt(leftGte, leftLt), TBoundedInt(rightGte, rightLt)) => TBoundedInt(leftGte.min(rightGte), leftLt.max(rightLt)) + case (LLVMTInt(leftWidth), LLVMTInt(rightWidth)) => + LLVMTInt(leftWidth.max(rightWidth)) + // Unrelated types below rational are simply a rational case (left, right) if TRational().superTypeOf(left) && TRational().superTypeOf(right) => diff --git a/src/col/vct/col/util/AstBuildHelpers.scala b/src/col/vct/col/util/AstBuildHelpers.scala index 0618c8caaa..925cbd876a 100644 --- a/src/col/vct/col/util/AstBuildHelpers.scala +++ b/src/col/vct/col/util/AstBuildHelpers.scala @@ -126,7 +126,7 @@ object AstBuildHelpers { case function: ADTFunction[Pre] => function.rewrite(args = args) case process: ModelProcess[Pre] => process.rewrite(args = args) case action: ModelAction[Pre] => action.rewrite(args = args) - case llvm: LlvmFunctionDefinition[Pre] => llvm.rewrite(args = args) + case llvm: LLVMFunctionDefinition[Pre] => llvm.rewrite(args = args) case prover: ProverFunction[Pre] => prover.rewrite(args = args) } } @@ -185,7 +185,7 @@ object AstBuildHelpers { inline = Some(inline), contract = contract, ) - case function: LlvmSpecFunction[Pre] => + case function: LLVMSpecFunction[Pre] => function.rewrite( args = args, returnType = returnType, @@ -319,7 +319,7 @@ object AstBuildHelpers { threadLocal = Some(threadLocal), blame = blame, ) - case function: LlvmSpecFunction[Pre] => + case function: LLVMSpecFunction[Pre] => function.rewrite( returnType = returnType, args = args, @@ -366,7 +366,7 @@ object AstBuildHelpers { apply match { case inv: ADTFunctionInvocation[Pre] => inv.rewrite(args = args) case inv: ProverFunctionInvocation[Pre] => inv.rewrite(args = args) - case inv: LlvmFunctionInvocation[Pre] => inv.rewrite(args = args) + case inv: LLVMFunctionInvocation[Pre] => inv.rewrite(args = args) case apply: ApplyAnyPredicate[Pre] => new ApplyAnyPredicateBuildHelpers(apply).rewrite(args = args) case inv: Invocation[Pre] => diff --git a/src/llvm/include/Origin/ContextDeriver.h b/src/llvm/include/Origin/ContextDeriver.h index 7f1cf1decd..2f26945c1d 100644 --- a/src/llvm/include/Origin/ContextDeriver.h +++ b/src/llvm/include/Origin/ContextDeriver.h @@ -1,35 +1,41 @@ -#ifndef VCLLVM_CONTEXTDERIVER_H -#define VCLLVM_CONTEXTDERIVER_H +#ifndef PALLAS_CONTEXTDERIVER_H +#define PALLAS_CONTEXTDERIVER_H #include /** - * Generators for VerCors origin objects context fields for various LLVM Value types. + * Generators for VerCors origin objects context fields for various LLVM Value + * types. * - * For more info on VerCors origins see: https://github.com/utwente-fmt/vercors/discussions/884 + * For more info on VerCors origins see: + * https://github.com/utwente-fmt/vercors/discussions/884 */ -namespace llvm2Col { - // module derivers - std::string deriveModuleContext(llvm::Module &llvmModule); +namespace llvm2col { +// module derivers +std::string deriveModuleContext(llvm::Module &llvmModule); - // function derivers - std::string deriveFunctionContext(llvm::Function &llvmFunction); +// function derivers +std::string deriveFunctionContext(llvm::Function &llvmFunction); - // block derivers - std::string deriveLabelContext(llvm::BasicBlock &llvmBlock); +// block derivers +std::string deriveLabelContext(llvm::BasicBlock &llvmBlock); - std::string deriveBlockContext(llvm::BasicBlock &llvmBlock); +std::string deriveBlockContext(llvm::BasicBlock &llvmBlock); - // instruction derivers - std::string deriveSurroundingInstructionContext(llvm::Instruction &llvmInstruction); +// instruction derivers +std::string +deriveSurroundingInstructionContext(llvm::Instruction &llvmInstruction); - std::string deriveInstructionContext(llvm::Instruction &llvmInstruction); +std::string deriveInstructionContext(llvm::Instruction &llvmInstruction); - std::string deriveInstructionLhs(llvm::Instruction &llvmInstruction); +std::string +deriveGlobalVariableContext(llvm::GlobalVariable &llvmGlobalVariable); - std::string deriveInstructionRhs(llvm::Instruction &llvmInstruction); +std::string deriveInstructionLhs(llvm::Instruction &llvmInstruction); - // operand derivers - std::string deriveOperandContext(llvm::Value &llvmOperand); -} -#endif //VCLLVM_CONTEXTDERIVER_H +std::string deriveInstructionRhs(llvm::Instruction &llvmInstruction); + +// operand derivers +std::string deriveOperandContext(llvm::Value &llvmOperand); +} // namespace llvm2col +#endif // PALLAS_CONTEXTDERIVER_H diff --git a/src/llvm/include/Origin/OriginProvider.h b/src/llvm/include/Origin/OriginProvider.h index 2dd6067535..e11c079662 100644 --- a/src/llvm/include/Origin/OriginProvider.h +++ b/src/llvm/include/Origin/OriginProvider.h @@ -1,46 +1,64 @@ -#ifndef VCLLVM_ORIGINPROVIDER_H -#define VCLLVM_ORIGINPROVIDER_H +#ifndef PALLAS_ORIGINPROVIDER_H +#define PALLAS_ORIGINPROVIDER_H -#include -#include #include "vct/col/ast/Origin.pb.h" +#include +#include /** * Generators for VerCors origin objects for various LLVM Value types. * - * For more info on VerCors origins see: https://github.com/utwente-fmt/vercors/discussions/884 + * For more info on VerCors origins see: + * https://github.com/utwente-fmt/vercors/discussions/884 */ -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; + +col::Origin *generateProgramOrigin(llvm::Module &llvmModule); + +col::Origin *generateFuncDefOrigin(llvm::Function &llvmFunction); + +col::Origin *generateFunctionContractOrigin(llvm::Function &llvmFunction, + const std::string &contract); - col::Origin *generateProgramOrigin(llvm::Module &llvmModule); +col::Origin *generateGlobalValOrigin(llvm::Module &llvmModule, + const std::string &globVal); - col::Origin *generateFuncDefOrigin(llvm::Function &llvmFunction); +col::Origin *generateArgumentOrigin(llvm::Argument &llvmArgument); - col::Origin *generateFunctionContractOrigin(llvm::Function &llvmFunction, const std::string& contract); +col::Origin *generateBlockOrigin(llvm::BasicBlock &llvmBlock); - col::Origin *generateGlobalValOrigin(llvm::Module &llvmModule, const std::string &globVal); +col::Origin *generateLabelOrigin(llvm::BasicBlock &llvmBlock); - col::Origin *generateArgumentOrigin(llvm::Argument &llvmArgument); +col::Origin *generateSingleStatementOrigin(llvm::Instruction &llvmInstruction); - col::Origin *generateBlockOrigin(llvm::BasicBlock &llvmBlock); +col::Origin *generateAssignTargetOrigin(llvm::Instruction &llvmInstruction); - col::Origin *generateLabelOrigin(llvm::BasicBlock &llvmBlock); +col::Origin *generateBinExprOrigin(llvm::Instruction &llvmInstruction); - col::Origin *generateSingleStatementOrigin(llvm::Instruction &llvmInstruction); +col::Origin *generateFunctionCallOrigin(llvm::CallInst &callInstruction); - col::Origin *generateAssignTargetOrigin(llvm::Instruction &llvmInstruction); +col::Origin *generateOperandOrigin(llvm::Instruction &llvmInstruction, + llvm::Value &llvmOperand); - col::Origin *generateBinExprOrigin(llvm::Instruction &llvmInstruction); +col::Origin * +generateGlobalVariableOrigin(llvm::Module &llvmModule, + llvm::GlobalVariable &llvmGlobalVariable); - col::Origin *generateFunctionCallOrigin(llvm::CallInst &callInstruction); +col::Origin *generateGlobalVariableInitializerOrigin( + llvm::Module &llvmModule, llvm::GlobalVariable &llvmGlobalVariable, + llvm::Value &llvmInitializer); - col::Origin *generateOperandOrigin(llvm::Instruction &llvmInstruction, llvm::Value &llvmOperand); +col::Origin *generateVoidOperandOrigin(llvm::Instruction &llvmInstruction); - col::Origin *generateTypeOrigin(llvm::Type &llvmType); +col::Origin *generateTypeOrigin(llvm::Type &llvmType); -} -#endif //VCLLVM_ORIGINPROVIDER_H +col::Origin *generateMemoryOrderingOrigin(llvm::AtomicOrdering &llvmOrdering); +std::string extractShortPosition(const col::Origin &origin); +col::Origin *deepenOperandOrigin(const col::Origin &origin, + llvm::Value &llvmOperand); +} // namespace llvm2col +#endif // PALLAS_ORIGINPROVIDER_H diff --git a/src/llvm/include/Origin/PreferredNameDeriver.h b/src/llvm/include/Origin/PreferredNameDeriver.h index 3b6c7f938d..3de8fd7fcb 100644 --- a/src/llvm/include/Origin/PreferredNameDeriver.h +++ b/src/llvm/include/Origin/PreferredNameDeriver.h @@ -1,18 +1,23 @@ -#ifndef VCLLVM_PREFERREDNAMEDERIVER_H -#define VCLLVM_PREFERREDNAMEDERIVER_H +#ifndef PALLAS_PREFERREDNAMEDERIVER_H +#define PALLAS_PREFERREDNAMEDERIVER_H #include +#include /** - * Generators for VerCors origin objects preferredName fields for various LLVM Value types. + * Generators for VerCors origin objects preferredName fields for various LLVM + * Value types. * - * For more info on VerCors origins see: https://github.com/utwente-fmt/vercors/discussions/884 + * For more info on VerCors origins see: + * https://github.com/utwente-fmt/vercors/discussions/884 */ -namespace llvm2Col { - std::string deriveOperandPreferredName(llvm::Value &llvmOperand); +namespace llvm2col { +std::string deriveOperandPreferredName(llvm::Value &llvmOperand); - std::string deriveTypePreferredName(llvm::Type &llvmType); +std::string deriveTypePreferredName(llvm::Type &llvmType); - std::string deriveArgumentPreferredName(llvm::Argument &llvmArgument); +std::string +deriveMemoryOrderingPreferredName(llvm::AtomicOrdering &llvmOrdering); -} -#endif //VCLLVM_PREFERREDNAMEDERIVER_H +std::string deriveArgumentPreferredName(llvm::Argument &llvmArgument); +} // namespace llvm2col +#endif // PALLAS_PREFERREDNAMEDERIVER_H diff --git a/src/llvm/include/Origin/ShortPositionDeriver.h b/src/llvm/include/Origin/ShortPositionDeriver.h index 4ef8fe7c1f..ee1efaf8b4 100644 --- a/src/llvm/include/Origin/ShortPositionDeriver.h +++ b/src/llvm/include/Origin/ShortPositionDeriver.h @@ -1,25 +1,29 @@ -#ifndef VCLLVM_SHORTPOSITIONDERIVER_H -#define VCLLVM_SHORTPOSITIONDERIVER_H +#ifndef PALLAS_SHORTPOSITIONDERIVER_H +#define PALLAS_SHORTPOSITIONDERIVER_H #include /** - * Generators for VerCors origin objects shortPosition fields for various LLVM Value types. + * Generators for VerCors origin objects shortPosition fields for various LLVM + * Value types. * - * It generates a path from the highest level abstraction to the lowest in order of Module -> Function -> Block -> Instruction. + * It generates a path from the highest level abstraction to the lowest in order + * of Module -> Function -> Block -> Instruction. * - * Each abstraction level calls its parent generator to generate its path (e.g. deriveBlockShortPosition calls - * deriveFunctionShortPosition and deriveInstructionShortPosition calls deriveBlockShortPosition) + * Each abstraction level calls its parent generator to generate its path (e.g. + * deriveBlockShortPosition calls deriveFunctionShortPosition and + * deriveInstructionShortPosition calls deriveBlockShortPosition) * - * For more info on VerCors origins see: https://github.com/utwente-fmt/vercors/discussions/884 + * For more info on VerCors origins see: + * https://github.com/utwente-fmt/vercors/discussions/884 */ -namespace llvm2Col { - std::string deriveModuleShortPosition(llvm::Module &llvmModule); +namespace llvm2col { +std::string deriveModuleShortPosition(llvm::Module &llvmModule); - std::string deriveFunctionShortPosition(llvm::Function &llvmFunction); +std::string deriveFunctionShortPosition(llvm::Function &llvmFunction); - std::string deriveBlockShortPosition(llvm::BasicBlock &llvmBlock); +std::string deriveBlockShortPosition(llvm::BasicBlock &llvmBlock); - std::string deriveInstructionShortPosition(llvm::Instruction &llvmInstruction); -} -#endif //VCLLVM_SHORTPOSITIONDERIVER_H +std::string deriveInstructionShortPosition(llvm::Instruction &llvmInstruction); +} // namespace llvm2col +#endif // PALLAS_SHORTPOSITIONDERIVER_H diff --git a/src/llvm/include/Passes/Function/FunctionBodyTransformer.h b/src/llvm/include/Passes/Function/FunctionBodyTransformer.h index 8c6b9309a1..3cc962b394 100644 --- a/src/llvm/include/Passes/Function/FunctionBodyTransformer.h +++ b/src/llvm/include/Passes/Function/FunctionBodyTransformer.h @@ -1,162 +1,176 @@ -#ifndef VCLLVM_FUNCTIONBODYTRANSFORMER_H -#define VCLLVM_FUNCTIONBODYTRANSFORMER_H +#ifndef PALLAS_FUNCTIONBODYTRANSFORMER_H +#define PALLAS_FUNCTIONBODYTRANSFORMER_H #include "vct/col/ast/col.pb.h" #include #include "FunctionDeclarer.h" +#include "vct/col/ast/col.pb.h" +/** + * The FunctionBodyTransformer that transforms LLVM blocks and instructions into + * suitable VerCors COL abstractions. + */ +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; + +struct LabeledColBlock { + col::Label &label; + col::Block █ +}; + /** - * The FunctionBodyTransformer that transforms LLVM blocks and instructions into suitable VerCors COL abstractions. + * The FunctionCursor is a stateful utility class to transform a LLVM function + * body to a COL function body. */ -namespace vcllvm { - using namespace llvm; - namespace col = vct::col::ast; +class FunctionCursor { + friend class FunctionBodyTransformerPass; + + private: + col::Scope &functionScope; + + col::Block &functionBody; + + llvm::Function &llvmFunction; + + /// Gives access to all other analysis passes ran by pallas as well as + /// existing LLVM analysis passes (i.e. loop analysis). + llvm::FunctionAnalysisManager &FAM; + + /// Most LLVM instructions are transformed to a COL assignment to a COL + /// variable. The resulting end product is a 1-to-1 mapping from and LLVM + /// Value to a COL variable. The generic LLVM Value was chosen to also + /// include function arguments in the lut. + std::unordered_map variableMap; + + /// All LLVM blocks mapped 1-to-1 to a COL block. This mapping is not direct + /// in the sense that it uses the intermediate LabeledColBlock struct which + /// contains both the COL label and COL block associated to the LLVM block + std::unordered_map + llvmBlock2LabeledColBlock; + + /// set of all COL blocks that have been completed. Completed meaning all + /// instructions of the corresponding LLVM block have been transformed. This + /// excludes possible future phi node back transformations. + std::set completedColBlocks; + + /// Almost always when adding a variable to the variableMap, some extra + /// processing is required which is why this method is private as to not + /// accidentally use it outside the functionCursor + void addVariableMapEntry(llvm::Value &llvmValue, col::Variable &colVar); + + public: + explicit FunctionCursor(col::Scope &functionScope, col::Block &functionBody, + llvm::Function &llvmFunction, + llvm::FunctionAnalysisManager &FAM); + + const col::Scope &getFunctionScope(); + + /** + * declares variable in the function scope + * @param llvmInstruction + * @return the created variable declaration + */ + col::Variable &declareVariable(Instruction &llvmInstruction, + Type *llvmPointerType = nullptr); + + /** + * Functionality is twofold: + *
    + *
  1. Creates a variable declaration in the function scope (declare + * variable)
  2. Creates an assignment in the provided colBlock
  3. + *
+ * @param llvmInstruction + * @param colBlock + * @return The created col assignment + */ + col::Assign & + createAssignmentAndDeclaration(Instruction &llvmInstruction, + col::Block &colBlock, + Type *llvmPointerType = nullptr); - struct LabeledColBlock { - col::Label &label; - col::Block █ - }; + /** + * Creates an assignment in the provided colBlock referencing the provided + * variable declaration + * + * @param llvmInstruction + * @param colBlock + * @param varDecl + * @return the created col assignment + */ + col::Assign &createAssignment(Instruction &llvmInstruction, + col::Block &colBlock, col::Variable &varDecl); + + col::Variable &getVariableMapEntry(llvm::Value &llvmValue, bool inPhiNode); + + /** + * In many cases during transformation, it is not possible to derive whether + * a COL block has yet been mapped and initialised. This is why we have a + * get or set method which does the following"
  • If a mapping between + * the given LLVM block and a COL block already exists, return the COL + * block
  • Else, initalise a new COL block in the buffer, add it to + * the llvmBlock2LabeledColBlock lut and return the newly created COL + * block
  • + *
+ * + * @param llvmBlock + * @return A LabeledColBlock struct to which this llvmBlock is mapped to. + */ + LabeledColBlock & + getOrSetLLVMBlock2LabeledColBlockEntry(BasicBlock &llvmBlock); + + llvm::FunctionAnalysisManager &getFunctionAnalysisManager(); + + /** + * Indicates whether a LLVM block has been visited (i.e. whether a mapping + * exists to a COL block). Note that does not mean that it has been fully + * transformed. For that see the isComplete + * + * @param llvmBlock + * @return + */ + bool isVisited(llvm::BasicBlock &llvmBlock); + + /** + * Mark COL Block as complete by adding it to the completedColBlocks set. + * @param llvmBlock + */ + void complete(col::Block &colBlock); + + /** + * Indicates whether an llvmBlock has been fully transformed (excluding + * possible phi node back transformations). Any completed block is also + * visited. + * @return true if block is in the completedColBlocks set, false otherwise. + */ + bool isComplete(col::Block &colBlock); + + LoopInfo &getLoopInfo(); + + LoopInfo &getLoopInfo(llvm::Function &otherLLVMFunction); + + /** + * Retrieve the FunctionDeclarerPass analysis result from the function this + * FunctionCursor is associated with by querying the + * FunctionAnalysisManager. + * @return + */ + FDResult &getFDResult(); /** - * The FunctionCursor is a stateful utility class to transform a LLVM function body to a COL function body. + * Retrieve the FunctionDeclarerPass analysis result from a function in the + * current program by querying the FunctionAnalysisManager. + * @param otherLLVMFunction + * @return */ - class FunctionCursor { - friend class FunctionBodyTransformerPass; - - private: - col::Scope &functionScope; - - col::Block &functionBody; - - llvm::Function &llvmFunction; - - /// Gives access to all other analysis passes ran by vcllvm as well as existing LLVM analysis passes (i.e. loop - /// analysis). - llvm::FunctionAnalysisManager &FAM; - - /// Most LLVM instructions are transformed to a COL assignment to a COL variable. The resulting end product is - /// a 1-to-1 mapping from and LLVM Value to a COL variable. The generic LLVM Value was chosen to also include - /// function arguments in the lut. - std::unordered_map variableMap; - - /// All LLVM blocks mapped 1-to-1 to a COL block. This mapping is not direct in the sense that it uses the - /// intermediate LabeledColBlock struct which contains both the COL label and COL block associated to the LLVM - /// block - std::unordered_map llvmBlock2LabeledColBlock; - - /// set of all COL blocks that have been completed. Completed meaning all instructions of the corresponding LLVM - /// block have been transformed. This excludes possible future phi node back transformations. - std::set completedColBlocks; - - /// Almost always when adding a variable to the variableMap, some extra processing is required which is why this - /// method is private as to not accidentally use it outside the functionCursor - void addVariableMapEntry(llvm::Value &llvmValue, col::Variable &colVar); - - public: - explicit FunctionCursor(col::Scope &functionScope, - col::Block &functionBody, - llvm::Function &llvmFunction, - llvm::FunctionAnalysisManager &FAM); - - const col::Scope &getFunctionScope(); - - /** - * declares variable in the function scope - * @param llvmInstruction - * @return the created variable declaration - */ - col::Variable &declareVariable(Instruction &llvmInstruction); - - /** - * Functionality is twofold: - *
    - *
  1. Creates a variable declaration in the function scope (declare variable)
  2. - *
  3. Creates an assignment in the provided colBlock
  4. - *
- * @param llvmInstruction - * @param colBlock - * @return The created col assignment - */ - col::Assign &createAssignmentAndDeclaration(Instruction &llvmInstruction, col::Block &colBlock); - - /** - * Creates an assignment in the provided colBlock referencing the provided variable declaration - * - * @param llvmInstruction - * @param colBlock - * @param varDecl - * @return the created col assignment - */ - col::Assign &createAssignment(Instruction &llvmInstruction, col::Block &colBlock, col::Variable &varDecl); - - col::Variable &getVariableMapEntry(llvm::Value &llvmValue); - - /** - * In many cases during transformation, it is not possible to derive whether a COL block has yet been mapped and - * initialised. This is why we have a get or set method which does the following" - *
    - *
  • If a mapping between the given LLVM block and a COL block already exists, return the COL block
  • - *
  • Else, initalise a new COL block in the buffer, add it to the llvmBlock2LabeledColBlock lut and return - * the newly created COL block
  • - *
- * - * @param llvmBlock - * @return A LabeledColBlock struct to which this llvmBlock is mapped to. - */ - LabeledColBlock &getOrSetLlvmBlock2LabeledColBlockEntry(BasicBlock &llvmBlock); - - /** - * Indicates whether a LLVM block has been visited (i.e. whether a mapping exists to a COL block). - * Note that does not mean that it has been fully transformed. For that see the isComplete - * - * @param llvmBlock - * @return - */ - bool isVisited(llvm::BasicBlock &llvmBlock); - - /** - * Mark COL Block as complete by adding it to the completedColBlocks set. - * @param llvmBlock - */ - void complete(col::Block &colBlock); - - /** - * Indicates whether an llvmBlock has been fully transformed (excluding possible phi node back transformations). - * Any completed block is also visited. - * @return true if block is in the completedColBlocks set, false otherwise. - */ - bool isComplete(col::Block &colBlock); - - LoopInfo &getLoopInfo(); - - LoopInfo &getLoopInfo(llvm::Function &otherLlvmFunction); - - /** - * Retrieve the FunctionDeclarerPass analysis result from the function this FunctionCursor is associated with by - * querying the FunctionAnalysisManager. - * @return - */ - FDResult &getFDResult(); - - /** - * Retrieve the FunctionDeclarerPass analysis result from a function in the current program by querying - * the FunctionAnalysisManager. - * @param otherLlvmFunction - * @return - */ - FDResult &getFDResult(llvm::Function &otherLlvmFunction); - - }; - - class FunctionBodyTransformerPass : public PassInfoMixin { - private: - std::shared_ptr pProgram; - - public: - explicit FunctionBodyTransformerPass(std::shared_ptr pProgram); - - PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); - }; -} -#endif //VCLLVM_FUNCTIONBODYTRANSFORMER_H + FDResult &getFDResult(llvm::Function &otherLLVMFunction); +}; + +class FunctionBodyTransformerPass + : public PassInfoMixin { + public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} // namespace pallas +#endif // PALLAS_FUNCTIONBODYTRANSFORMER_H diff --git a/src/llvm/include/Passes/Function/FunctionContractDeclarer.h b/src/llvm/include/Passes/Function/FunctionContractDeclarer.h index e6ac3d28a7..07ef66ff2e 100644 --- a/src/llvm/include/Passes/Function/FunctionContractDeclarer.h +++ b/src/llvm/include/Passes/Function/FunctionContractDeclarer.h @@ -1,68 +1,70 @@ -#ifndef VCLLVM_FUNCTIONCONTRACTDECLARER_H -#define VCLLVM_FUNCTIONCONTRACTDECLARER_H +#ifndef PALLAS_FUNCTIONCONTRACTDECLARER_H +#define PALLAS_FUNCTIONCONTRACTDECLARER_H #include "vct/col/ast/col.pb.h" #include /** - * Pass that adds an LLVMFunctionContract to its corresponding LLVMFunctionDefinition in the presence - * of a contract metadata node. The resulting FDCResult class can be used by a FunctionAnalysisManager to access the - * created contract and add named references to the contract (e.g. map functions arguments string representations to COL - * variables representing these same arguments). + * Pass that adds an LlvmfunctionContract to its corresponding + * LlvmfunctionDefinition in the presence of a contract metadata node. The + * resulting FDCResult class can be used by a FunctionAnalysisManager to access + * the created contract and add named references to the contract (e.g. map + * functions arguments string representations to COL variables representing + * these same arguments). * - * The pass is twofold: it has an analysis pass (FunctionContractDeclarer) that merely creates objects in the buffer and - * adds them to the associated result object. This way, the result object of this pass can be queried by other passes in - * order to retrieve the relevant COL nodes associated to this LLVM function. + * The pass is twofold: it has an analysis pass (FunctionContractDeclarer) that + * merely creates objects in the buffer and adds them to the associated result + * object. This way, the result object of this pass can be queried by other + * passes in order to retrieve the relevant COL nodes associated to this LLVM + * function. * - * The second pass is a regular function pass (FunctionContractDeclarerPass) that finishes the transformation started by - * the FunctionContractDeclarer analysis pass. + * The second pass is a regular function pass (FunctionContractDeclarerPass) + * that finishes the transformation started by the FunctionContractDeclarer + * analysis pass. */ -namespace vcllvm { - using namespace llvm; - namespace col = vct::col::ast; +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; - class FDCResult { - private: - col::LlvmFunctionContract &associatedColFuncContract; - public: - explicit FDCResult(col::LlvmFunctionContract &colFuncContract); +class FDCResult { + private: + col::LlvmFunctionContract &associatedColFuncContract; - col::LlvmFunctionContract &getAssociatedColFuncContract(); - }; + public: + explicit FDCResult(col::LlvmFunctionContract &colFuncContract); - class FunctionContractDeclarer : public AnalysisInfoMixin { - friend AnalysisInfoMixin; - static AnalysisKey Key; - private: - std::shared_ptr pProgram; - public: - using Result = FDCResult; + col::LlvmFunctionContract &getAssociatedColFuncContract(); +}; - explicit FunctionContractDeclarer(std::shared_ptr pProgram); +class FunctionContractDeclarer + : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; - /** - * Merely creates a COL LlvmFunctionDefinition object in the buffer and sets it in a FDCResult object. - * @param F - * @param FAM - * @return - */ - Result run(Function &F, FunctionAnalysisManager &FAM); - }; + public: + using Result = FDCResult; - class FunctionContractDeclarerPass : public AnalysisInfoMixin { - private: - std::shared_ptr pProgram; - public: - explicit FunctionContractDeclarerPass(std::shared_ptr pProgram); + /** + * Merely creates a COL LlvmfunctionDefinition object in the buffer and sets + * it in a FDCResult object. + * @param F + * @param FAM + * @return + */ + Result run(Function &F, FunctionAnalysisManager &FAM); +}; - /** - * Retrieves the LlvmFunctionDefinition object in the buffer from the FDCResult object and sets the origin and - * string value of the contract. - * @param F - * @param FAM - * @return - */ - PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); - }; -} -#endif //VCLLVM_FUNCTIONCONTRACTDECLARER_H +class FunctionContractDeclarerPass + : public AnalysisInfoMixin { + public: + /** + * Retrieves the LlvmfunctionDefinition object in the buffer from the + * FDCResult object and sets the origin and string value of the contract. + * @param F + * @param FAM + * @return + */ + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} // namespace pallas +#endif // PALLAS_FUNCTIONCONTRACTDECLARER_H diff --git a/src/llvm/include/Passes/Function/FunctionDeclarer.h b/src/llvm/include/Passes/Function/FunctionDeclarer.h index eeb5fc4666..002c5d64d6 100644 --- a/src/llvm/include/Passes/Function/FunctionDeclarer.h +++ b/src/llvm/include/Passes/Function/FunctionDeclarer.h @@ -1,96 +1,95 @@ -#ifndef VCLLVM_FUNCTIONDECLARER_H -#define VCLLVM_FUNCTIONDECLARER_H +#ifndef PALLAS_FUNCTIONDECLARER_H +#define PALLAS_FUNCTIONDECLARER_H #include "vct/col/ast/col.pb.h" #include /** - * Pass that creates a signature for a LLVMFunctionDefinition in COL and exposes an FDResult object that - * binds the the LLVM IR Function to a LLVMFunctionDefinition COL object. The actual function implementation is + * Pass that creates a signature for a LlvmfunctionDefinition in COL and exposes + * an FDResult object that binds the the LLVM IR Function to a + * LlvmfunctionDefinition COL object. The actual function implementation is * transformed by the FunctionBodyTransformer pass. * - * The pass is twofold: it has an analysis pass (FunctionDeclarer) that merely creates objects in the buffer and adds - * them to the associated result object. This way, the result object of this pass can be queried by other passes in order - * to retrieve the relevant COL nodes associated to this LLVM function. + * The pass is twofold: it has an analysis pass (FunctionDeclarer) that merely + * creates objects in the buffer and adds them to the associated result object. + * This way, the result object of this pass can be queried by other passes in + * order to retrieve the relevant COL nodes associated to this LLVM function. * - * The second pass is a regular function pass (FunctionDeclarerPass) that finishes the transformation started by the - * FunctionDeclarer analysis pass. + * The second pass is a regular function pass (FunctionDeclarerPass) that + * finishes the transformation started by the FunctionDeclarer analysis pass. */ -namespace vcllvm { - using namespace llvm; - namespace col = vct::col::ast; - - /// wrapper struct for a COL scope and block. Intended use is the block to be declared in the scope. - struct ColScopedFuncBody { - col::Scope *scope; - col::Block *block; - }; - - class FDResult { - friend class FunctionDeclarer; - - private: - col::LlvmFunctionDefinition &associatedColFuncDef; - ColScopedFuncBody associatedScopedColFuncBody; - int64_t functionId; - /// contains the 1-to-1 mapping from LLVM function arguments to COL variables that are used as function - /// arguments. - std::unordered_map funcArgMap; - - void addFuncArgMapEntry(llvm::Argument &llvmArg, col::Variable &colArg); - - public: - explicit FDResult(col::LlvmFunctionDefinition &colFuncDef, - ColScopedFuncBody associatedScopedColFuncBody, - int64_t functionId); - - col::LlvmFunctionDefinition &getAssociatedColFuncDef(); - - ColScopedFuncBody getAssociatedScopedColFuncBody(); - - col::Variable &getFuncArgMapEntry(llvm::Argument &arg); - - int64_t &getFunctionId(); - }; - - class FunctionDeclarer : public AnalysisInfoMixin { - friend AnalysisInfoMixin; - static AnalysisKey Key; - private: - std::shared_ptr pProgram; - public: - using Result = FDResult; - - explicit FunctionDeclarer(std::shared_ptr pProgram); - - /** - * Creates a COL LlvmFunctionDefinition in the buffer, including a function scope and body and their origins. - * It maps the corresponding LLVM Function to the created COL LlvmFunctionDefinition. - * - * Additionally, it creates the function arguments (COL variables) in the buffer and maps the corresponding - * LLVM arguments to the created COL arguments. - * - * @param F - * @param FAM - * @return - */ - Result run(Function &F, FunctionAnalysisManager &FAM); - - }; - - class FunctionDeclarerPass : public AnalysisInfoMixin { - private: - std::shared_ptr pProgram; - public: - explicit FunctionDeclarerPass(std::shared_ptr pProgram); - /** - * Completes the function definition transformation by adding a return type to the COL LLVMFunctionDefinition - * - * @param F - * @param FAM - * @return - */ - PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); - }; -} -#endif //VCLLVM_FUNCTIONDECLARER_H \ No newline at end of file +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; + +/// wrapper struct for a COL scope and block. Intended use is the block to be +/// declared in the scope. +struct ColScopedFuncBody { + col::Scope *scope; + col::Block *block; +}; + +class FDResult { + friend class FunctionDeclarer; + + private: + col::LlvmFunctionDefinition &associatedColFuncDef; + ColScopedFuncBody associatedScopedColFuncBody; + int64_t functionId; + /// contains the 1-to-1 mapping from LLVM function arguments to COL + /// variables that are used as function arguments. + std::unordered_map funcArgMap; + + void addFuncArgMapEntry(llvm::Argument &llvmArg, col::Variable &colArg); + + public: + explicit FDResult(col::LlvmFunctionDefinition &colFuncDef, + ColScopedFuncBody associatedScopedColFuncBody, + int64_t functionId); + + col::LlvmFunctionDefinition &getAssociatedColFuncDef(); + + ColScopedFuncBody getAssociatedScopedColFuncBody(); + + col::Variable &getFuncArgMapEntry(llvm::Argument &arg); + + int64_t &getFunctionId(); +}; + +class FunctionDeclarer : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; + + public: + using Result = FDResult; + + /** + * Creates a COL LlvmfunctionDefinition in the buffer, including a function + * scope and body and their origins. It maps the corresponding LLVM Function + * to the created COL LlvmfunctionDefinition. + * + * Additionally, it creates the function arguments (COL variables) in the + * buffer and maps the corresponding LLVM arguments to the created COL + * arguments. + * + * @param F + * @param FAM + * @return + */ + Result run(Function &F, FunctionAnalysisManager &FAM); +}; + +class FunctionDeclarerPass : public AnalysisInfoMixin { + public: + /** + * Completes the function definition transformation by adding a return type + * to the COL LlvmfunctionDefinition + * + * @param F + * @param FAM + * @return + */ + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} // namespace pallas +#endif // PALLAS_FUNCTIONDECLARER_H diff --git a/src/llvm/include/Passes/Function/PureAssigner.h b/src/llvm/include/Passes/Function/PureAssigner.h index 6cd8797b72..a41e01bbe1 100644 --- a/src/llvm/include/Passes/Function/PureAssigner.h +++ b/src/llvm/include/Passes/Function/PureAssigner.h @@ -1,28 +1,19 @@ -#ifndef VCLLVM_PUREASSIGNER_H -#define VCLLVM_PUREASSIGNER_H +#ifndef PALLAS_PUREASSIGNER_H +#define PALLAS_PUREASSIGNER_H #include "vct/col/ast/col.pb.h" #include /** - * The PureAssignerPass checks if a LLVM function is pure (i.e. whether the !VC.pure metadata node is set) + * The PureAssignerPass checks if a LLVM function is pure (i.e. whether the + * !VC.pure metadata node is set) */ -namespace vcllvm { - using namespace llvm; - namespace col = vct::col::ast; +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; - class PureAssignerPass : public PassInfoMixin { - private: - std::shared_ptr pProgram; - public: - explicit PureAssignerPass(std::shared_ptr pProgram); - - PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); - }; - /** - * Helper function to generate errors generated by this Pass - * @param F - * @param explanation - */ - void reportError(Function &F, const std::string &explanation); -} -#endif //VCLLVM_PUREASSIGNER_H +class PureAssignerPass : public PassInfoMixin { + public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} // namespace pallas +#endif // PALLAS_PUREASSIGNER_H diff --git a/src/llvm/include/Passes/Module/GlobalVariableDeclarer.h b/src/llvm/include/Passes/Module/GlobalVariableDeclarer.h new file mode 100644 index 0000000000..5ba3e66cb2 --- /dev/null +++ b/src/llvm/include/Passes/Module/GlobalVariableDeclarer.h @@ -0,0 +1,17 @@ +#ifndef PALLAS_GLOBALVARIABLEDECLARER_H +#define PALLAS_GLOBALVARIABLEDECLARER_H + +#include "vct/col/ast/col.pb.h" +#include + +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; + +class GlobalVariableDeclarerPass + : public AnalysisInfoMixin { + public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +}; +} // namespace pallas +#endif // PALLAS_GLOBALVARIABLEDECLARER_H diff --git a/src/llvm/include/Passes/Module/ModuleSpecCollector.h b/src/llvm/include/Passes/Module/ModuleSpecCollector.h index c95bce722d..5131b6b37d 100644 --- a/src/llvm/include/Passes/Module/ModuleSpecCollector.h +++ b/src/llvm/include/Passes/Module/ModuleSpecCollector.h @@ -1,23 +1,21 @@ -#ifndef VCLLVM_MODULESPECCOLLECTOR_H -#define VCLLVM_MODULESPECCOLLECTOR_H +#ifndef PALLAS_MODULESPECCOLLECTOR_H +#define PALLAS_MODULESPECCOLLECTOR_H #include "vct/col/ast/col.pb.h" #include /** - * Pass that adds global specifications (i.e. not related to a loop or function) to the AST as unparsed strings. It's - * VerCors job to parse the string into any global declaration as if it were in a spec comment. + * Pass that adds global specifications (i.e. not related to a loop or function) + * to the AST as unparsed strings. It's VerCors job to parse the string into any + * global declaration as if it were in a spec comment. */ -namespace vcllvm { - using namespace llvm; - namespace col = vct::col::ast; +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; - class ModuleSpecCollectorPass : public AnalysisInfoMixin { - private: - std::shared_ptr pProgram; - public: - explicit ModuleSpecCollectorPass(std::shared_ptr pProgram); - - PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); - }; -} -#endif //VCLLVM_MODULESPECCOLLECTOR_H +class ModuleSpecCollectorPass + : public AnalysisInfoMixin { + public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +}; +} // namespace pallas +#endif // PALLAS_MODULESPECCOLLECTOR_H diff --git a/src/llvm/include/Passes/Module/ProtobufPrinter.h b/src/llvm/include/Passes/Module/ProtobufPrinter.h new file mode 100644 index 0000000000..538b6f74f0 --- /dev/null +++ b/src/llvm/include/Passes/Module/ProtobufPrinter.h @@ -0,0 +1,16 @@ +#ifndef PALLAS_PROTOBUFPRINTER_H +#define PALLAS_PROTOBUFPRINTER_H + +#include "vct/col/ast/col.pb.h" +#include + +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; + +class ProtobufPrinter : public AnalysisInfoMixin { + public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +}; +} // namespace pallas +#endif // PALLAS_PROTOBUFPRINTER_H diff --git a/src/llvm/include/Passes/Module/RootContainer.h b/src/llvm/include/Passes/Module/RootContainer.h new file mode 100644 index 0000000000..52806fac84 --- /dev/null +++ b/src/llvm/include/Passes/Module/RootContainer.h @@ -0,0 +1,28 @@ +#ifndef PALLAS_ROOTCONTAINER_H +#define PALLAS_ROOTCONTAINER_H + +#include "vct/col/ast/col.pb.h" +#include + +namespace pallas { +using namespace llvm; +namespace col = vct::col::ast; + +class ProgramWrapper { + public: + std::shared_ptr program; + bool invalidate(Module &M, const PreservedAnalyses &PA, + ModuleAnalysisManager::Invalidator &); +}; + +class RootContainer : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; + + public: + using Result = ProgramWrapper; + + Result run(Module &M, ModuleAnalysisManager &MAM); +}; +} // namespace pallas +#endif // PALLAS_ROOTCONTAINER_H diff --git a/src/llvm/include/Transform/BlockTransform.h b/src/llvm/include/Transform/BlockTransform.h index e250d96b77..d0215de03a 100644 --- a/src/llvm/include/Transform/BlockTransform.h +++ b/src/llvm/include/Transform/BlockTransform.h @@ -1,52 +1,54 @@ -#ifndef VCLLVM_BLOCKTRANSFORM_H -#define VCLLVM_BLOCKTRANSFORM_H +#ifndef PALLAS_BLOCKTRANSFORM_H +#define PALLAS_BLOCKTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - /** - * Entry point for each block transformation. It performs the following steps: - *
    - *
  1. Create or fetch the corresponding labeled col block from the function cursor
  2. - *
  3. Check if all predecessor blocks have been visited yet, otherwise, return
  4. - *
  5. If block turns out to be a loop header, hand over control to the transformLoop function. - * Else, transform instructions of the block
  6. - *
- * - * Note: The transformTermOp function will take care of subsequent blocks recursively - * @param functionCursor - * @param llvmBlock - */ - void transformLlvmBlock(llvm::BasicBlock &llvmBlock, vcllvm::FunctionCursor &functionCursor); +/** + * Entry point for each block transformation. It performs the following steps: + *
    + *
  1. Create or fetch the corresponding labeled col block from the function + * cursor
  2. Check if all predecessor blocks have been visited yet, + * otherwise, return
  3. If block turns out to be a loop header, hand over + * control to the transformLoop function. Else, transform + * instructions of the block
  4. + *
+ * + * Note: The transformTermOp function will take care of subsequent + * blocks recursively + * @param functionCursor + * @param llvmBlock + */ +void transformLLVMBlock(llvm::BasicBlock &llvmBlock, + pallas::FunctionCursor &functionCursor); - /** - * Unimplemented - * @param llvmBlock - * @param functionCursor - */ - void transformLoop(llvm::BasicBlock &llvmBlock, vcllvm::FunctionCursor &functionCursor); +/** + * Unimplemented + * @param llvmBlock + * @param functionCursor + */ +void transformLoop(llvm::BasicBlock &llvmBlock, + pallas::FunctionCursor &functionCursor); - /** - * Instructions are split up in their separate LLVM categories and transformed by their respective transformer. - * These are: - *
    - *
  1. Binary operators
  2. - *
  3. Casting operators
  4. - *
  5. Funclet pad operators
  6. - *
  7. Memory operators
  8. - *
  9. Terminal operators
  10. - *
  11. Unary operators
  12. - *
- * @param funcCursor - * @param llvmInstruction - * @param colBodyBlock - */ - void transformInstruction(vcllvm::FunctionCursor &funcCursor, - llvm::Instruction &llvmInstruction, - col::Block &colBodyBlock); - - void reportUnsupportedOperatorError(const std::string &source, llvm::Instruction &llvmInstruction); -} -#endif //VCLLVM_BLOCKTRANSFORM_H +/** + * Instructions are split up in their separate LLVM categories and transformed + * by their respective transformer. These are:
  1. Binary operators
  2. + *
  3. Casting operators
  4. + *
  5. Funclet pad operators
  6. + *
  7. Memory operators
  8. + *
  9. Terminal operators
  10. + *
  11. Unary operators
  12. + *
+ * @param funcCursor + * @param llvmInstruction + * @param colBodyBlock + */ +void transformInstruction(pallas::FunctionCursor &funcCursor, + llvm::Instruction &llvmInstruction, + col::Block &colBodyBlock); +void reportUnsupportedOperatorError(const std::string &source, + llvm::Instruction &llvmInstruction); +} // namespace llvm2col +#endif // PALLAS_BLOCKTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/BinaryOpTransform.h b/src/llvm/include/Transform/Instruction/BinaryOpTransform.h index 59f2989ed2..8e965b2bfa 100644 --- a/src/llvm/include/Transform/Instruction/BinaryOpTransform.h +++ b/src/llvm/include/Transform/Instruction/BinaryOpTransform.h @@ -1,15 +1,13 @@ -#ifndef VCLLVM_BINARYOPTRANSFORM_H -#define VCLLVM_BINARYOPTRANSFORM_H +#ifndef PALLAS_BINARYOPTRANSFORM_H +#define PALLAS_BINARYOPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; +void transformBinaryOp(llvm::Instruction &llvmInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); - void transformBinaryOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); - -} -#endif //VCLLVM_BINARYOPTRANSFORM_H +} // namespace llvm2col +#endif // PALLAS_BINARYOPTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/CastOpTransform.h b/src/llvm/include/Transform/Instruction/CastOpTransform.h index c42dbdeac8..b69d436e43 100644 --- a/src/llvm/include/Transform/Instruction/CastOpTransform.h +++ b/src/llvm/include/Transform/Instruction/CastOpTransform.h @@ -1,12 +1,20 @@ -#ifndef VCLLVM_CASTOPTRANSFORM_H -#define VCLLVM_CASTOPTRANSFORM_H +#ifndef PALLAS_CASTOPTRANSFORM_H +#define PALLAS_CASTOPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - void convertCastOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); -} -#endif //VCLLVM_CASTOPTRANSFORM_H +void transformCastOp(llvm::Instruction &llvmInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformSExt(llvm::SExtInst &sextInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformZExt(llvm::ZExtInst &sextInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformTrunc(llvm::TruncInst &truncInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +} // namespace llvm2col +#endif // PALLAS_CASTOPTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/FuncletPadOpTransform.h b/src/llvm/include/Transform/Instruction/FuncletPadOpTransform.h index c6bc303977..ae810415b1 100644 --- a/src/llvm/include/Transform/Instruction/FuncletPadOpTransform.h +++ b/src/llvm/include/Transform/Instruction/FuncletPadOpTransform.h @@ -1,12 +1,12 @@ -#ifndef VCLLVM_FUNCLETPADOPTRANSFORM_H -#define VCLLVM_FUNCLETPADOPTRANSFORM_H +#ifndef PALLAS_FUNCLETPADOPTRANSFORM_H +#define PALLAS_FUNCLETPADOPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - void transformFuncletPadOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); -} -#endif //VCLLVM_FUNCLETPADOPTRANSFORM_H +void transformFuncletPadOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +} // namespace llvm2col +#endif // PALLAS_FUNCLETPADOPTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/MemoryOpTransform.h b/src/llvm/include/Transform/Instruction/MemoryOpTransform.h index eb8d274db7..71707639f0 100644 --- a/src/llvm/include/Transform/Instruction/MemoryOpTransform.h +++ b/src/llvm/include/Transform/Instruction/MemoryOpTransform.h @@ -1,12 +1,27 @@ -#ifndef VCLLVM_MEMORYOPTRANSFORM_H -#define VCLLVM_MEMORYOPTRANSFORM_H +#ifndef PALLAS_MEMORYOPTRANSFORM_H +#define PALLAS_MEMORYOPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - void transformMemoryOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); -} -#endif //VCLLVM_MEMORYOPTRANSFORM_H +void transformMemoryOp(llvm::Instruction &llvmInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformAllocA(llvm::AllocaInst &allocAInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformAtomicOrdering(llvm::AtomicOrdering ordering, + col::LlvmMemoryOrdering *colOrdering); + +void transformLoad(llvm::LoadInst &loadInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformStore(llvm::StoreInst &storeInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); + +void transformGetElementPtr(llvm::GetElementPtrInst &gepInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +} // namespace llvm2col +#endif // PALLAS_MEMORYOPTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/OtherOpTransform.h b/src/llvm/include/Transform/Instruction/OtherOpTransform.h index 0ab0519ce0..cd86314fab 100644 --- a/src/llvm/include/Transform/Instruction/OtherOpTransform.h +++ b/src/llvm/include/Transform/Instruction/OtherOpTransform.h @@ -1,38 +1,39 @@ -#ifndef VCLLVM_OTHEROPTRANSFORM_H -#define VCLLVM_OTHEROPTRANSFORM_H +#ifndef PALLAS_OTHEROPTRANSFORM_H +#define PALLAS_OTHEROPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - void transformOtherOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); - /** - * Phi nodes get transformed retroactively by creating a variable declaration and retroactively assign the variable - * in each originating COL block of each phi pair. - * @param phiInstruction - * @param funcCursor - */ - void transformPhi(llvm::PHINode &phiInstruction, vcllvm::FunctionCursor &funcCursor); +void transformOtherOp(llvm::Instruction &llvmInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +/** + * Phi nodes get transformed retroactively by creating a variable declaration + * and retroactively assign the variable in each originating COL block of each + * phi pair. + * @param phiInstruction + * @param funcCursor + */ +void transformPhi(llvm::PHINode &phiInstruction, + pallas::FunctionCursor &funcCursor); - void transformICmp(llvm::ICmpInst &icmpInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); - /** - * Transforms the common part of all compare instructions (the argument pair). Currently only used by transformIcmp - * but could also be used in the future by for example an FCMP transformation. - * @param cmpInstruction - * @param colCompareExpr - * @param funcCursor - */ - void transformCmpExpr(llvm::CmpInst &cmpInstruction, - auto &colCompareExpr, - vcllvm::FunctionCursor &funcCursor); +void transformICmp(llvm::ICmpInst &icmpInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +/** + * Transforms the common part of all compare instructions (the argument pair). + * Currently only used by transformIcmp but could also be used in the future by + * for example an FCMP transformation. + * @param cmpInstruction + * @param colCompareExpr + * @param funcCursor + */ +void transformCmpExpr(llvm::CmpInst &cmpInstruction, auto &colCompareExpr, + pallas::FunctionCursor &funcCursor); - void transformCallExpr(llvm::CallInst &callInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); -} +void transformCallExpr(llvm::CallInst &callInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); -#endif //VCLLVM_OTHEROPTRANSFORM_H +bool checkCallSupport(llvm::CallInst &callInstruction); +} // namespace llvm2col + +#endif // PALLAS_OTHEROPTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/TermOpTransform.h b/src/llvm/include/Transform/Instruction/TermOpTransform.h index b9fec00303..8f3eb03d2a 100644 --- a/src/llvm/include/Transform/Instruction/TermOpTransform.h +++ b/src/llvm/include/Transform/Instruction/TermOpTransform.h @@ -1,25 +1,23 @@ -#ifndef VCLLVM_TERMOPTRANSFORM_H -#define VCLLVM_TERMOPTRANSFORM_H +#ifndef PALLAS_TERMOPTRANSFORM_H +#define PALLAS_TERMOPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - void transformTermOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); +void transformTermOp(llvm::Instruction &llvmInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); - void transformRet(llvm::ReturnInst &llvmRetInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); +void transformRet(llvm::ReturnInst &llvmRetInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); - void transformConditionalBranch(llvm::BranchInst &llvmBrInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); +void transformConditionalBranch(llvm::BranchInst &llvmBrInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor); - void transformUnConditionalBranch(llvm::BranchInst &llvmBrInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); -} -#endif //VCLLVM_TERMOPTRANSFORM_H +void transformUnConditionalBranch(llvm::BranchInst &llvmBrInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +} // namespace llvm2col +#endif // PALLAS_TERMOPTRANSFORM_H diff --git a/src/llvm/include/Transform/Instruction/UnaryOpTransform.h b/src/llvm/include/Transform/Instruction/UnaryOpTransform.h index 03dac632fe..2995eb075f 100644 --- a/src/llvm/include/Transform/Instruction/UnaryOpTransform.h +++ b/src/llvm/include/Transform/Instruction/UnaryOpTransform.h @@ -1,13 +1,12 @@ -#ifndef VCLLVM_UNARYOPTRANSFORM_H -#define VCLLVM_UNARYOPTRANSFORM_H +#ifndef PALLAS_UNARYOPTRANSFORM_H +#define PALLAS_UNARYOPTRANSFORM_H #include "Passes/Function/FunctionBodyTransformer.h" -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - void transformUnaryOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor); -} -#endif //VCLLVM_UNARYOPTRANSFORM_H \ No newline at end of file +void transformUnaryOp(llvm::Instruction &llvmInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor); +} // namespace llvm2col +#endif // PALLAS_UNARYOPTRANSFORM_H diff --git a/src/llvm/include/Transform/Transform.h b/src/llvm/include/Transform/Transform.h index 52addb856a..4506aa4a97 100644 --- a/src/llvm/include/Transform/Transform.h +++ b/src/llvm/include/Transform/Transform.h @@ -1,82 +1,87 @@ -#ifndef VCLLVM_TRANSFORM_H -#define VCLLVM_TRANSFORM_H +#ifndef PALLAS_TRANSFORM_H +#define PALLAS_TRANSFORM_H -#include "Passes/Function/FunctionBodyTransformer.h" #include "Origin/OriginProvider.h" +#include "Passes/Function/FunctionBodyTransformer.h" /** * General helper functions for transformations */ -namespace llvm2Col { - namespace col = vct::col::ast; +namespace llvm2col { +namespace col = vct::col::ast; - // type transformers - void transformAndSetType(llvm::Type &llvmType, col::Type &colType); +// type transformers +void transformAndSetPointerType(llvm::Type &llvmType, col::Type &colType); - /** - * ATTEMPTS to convert any integer constant to a BigInt representation. - * @param apInt - * @param colIntegerValue - */ - void transformAndSetIntegerValue(llvm::APInt &apInt, col::IntegerValue &colIntegerValue); +void transformAndSetType(llvm::Type &llvmType, col::Type &colType); - /** - * Transforms and set LLVM expression in the buffer which in practice are either constants (e.g. 0, 0.1, false etc..) - * or variables (i.e. LLVM Values) (e.g. %3, %variable) - * @param functionCursor - * @param llvmInstruction - * @param llvmOperand - * @param colExpr - */ - void transformAndSetExpr(vcllvm::FunctionCursor &functionCursor, llvm::Instruction &llvmInstruction, - llvm::Value &llvmOperand, col::Expr &colExpr); - /** - * Used by TransformAndSetExpr - * @param llvmInstruction - * @param llvmConstant - * @param colExpr - */ - void transformAndSetConstExpr(llvm::Instruction &llvmInstruction, llvm::Constant &llvmConstant, col::Expr &colExpr); +/** + * ATTEMPTS to convert any integer constant to a BigInt representation. + * @param apInt + * @param colIntegerValue + */ +void transformAndSetBigInt(llvm::APInt &apInt, col::BigInt &bigInt); + +/** + * Transforms and set LLVM expression in the buffer which in practice are either + * constants (e.g. 0, 0.1, false etc..) or variables (i.e. LLVM Values) (e.g. + * %3, %variable) + * @param functionCursor + * @param llvmInstruction + * @param llvmOperand + * @param colExpr + */ +void transformAndSetExpr(pallas::FunctionCursor &functionCursor, + llvm::Instruction &llvmInstruction, + llvm::Value &llvmOperand, col::Expr &colExpr); +/** + * Used by TransformAndSetExpr + * @param llvmInstruction + * @param llvmConstant + * @param colExpr + */ +void transformAndSetConstExpr(llvm::FunctionAnalysisManager &FAM, + col::Origin *origin, llvm::Constant &llvmConstant, + col::Expr &colExpr); - /** - * Used by TransformAndSetExpr - * @param functionCursor - * @param llvmInstruction - * @param llvmOperand - * @param colExpr - */ - void transformAndSetVarExpr(vcllvm::FunctionCursor &functionCursor, llvm::Instruction &llvmInstruction, - llvm::Value &llvmOperand, col::Expr &colExpr); - template - void transformBinExpr(llvm::Instruction &llvmInstruction, - ColBinExpr &colBinExpr, - vcllvm::FunctionCursor &funcCursor) { - // set origin of entire expression - colBinExpr.set_allocated_origin(generateBinExprOrigin(llvmInstruction)); - // transform left operand - col::Expr *lExpr = colBinExpr.mutable_left(); - llvm2Col::transformAndSetExpr( - funcCursor, llvmInstruction, *llvmInstruction.getOperand(0), - *lExpr); - // transform right operand - col::Expr *rExpr = colBinExpr.mutable_right(); - llvm2Col::transformAndSetExpr( - funcCursor, llvmInstruction, *llvmInstruction.getOperand(1), - *rExpr); - } +/** + * Used by TransformAndSetExpr + * @param functionCursor + * @param llvmInstruction + * @param llvmOperand + * @param colExpr + */ +void transformAndSetVarExpr(pallas::FunctionCursor &functionCursor, + col::Origin *origin, bool inPhiNode, + llvm::Value &llvmOperand, col::Expr &colExpr); +template +void transformBinExpr(llvm::Instruction &llvmInstruction, + ColBinExpr &colBinExpr, + pallas::FunctionCursor &funcCursor) { + // set origin of entire expression + colBinExpr.set_allocated_origin(generateBinExprOrigin(llvmInstruction)); + // transform left operand + col::Expr *lExpr = colBinExpr.mutable_left(); + llvm2col::transformAndSetExpr(funcCursor, llvmInstruction, + *llvmInstruction.getOperand(0), *lExpr); + // transform right operand + col::Expr *rExpr = colBinExpr.mutable_right(); + llvm2col::transformAndSetExpr(funcCursor, llvmInstruction, + *llvmInstruction.getOperand(1), *rExpr); +} - template - int64_t setColNodeId(IDNode &idNode) { - auto id = reinterpret_cast(idNode); - idNode->set_id(id); - return id; - } - /** - * Returns a string representation of any LLVM value as it would be displayed in human readable LLVM IR - * @param llvmValue - * @return - */ - std::string getValueName(llvm::Value &llvmValue); +template int64_t setColNodeId(IDNode &idNode) { + auto id = reinterpret_cast(idNode); + idNode->set_id(id); + return id; } -#endif //VCLLVM_TRANSFORM_H +/** + * Returns a string representation of any LLVM value as it would be displayed in + * human readable LLVM IR + * @param llvmValue + * @return + */ +std::string getValueName(llvm::Value &llvmValue); +} // namespace llvm2col +#endif // PALLAS_TRANSFORM_H diff --git a/src/llvm/include/Util/Constants.h b/src/llvm/include/Util/Constants.h index 09ef619a5b..2556aa5b53 100644 --- a/src/llvm/include/Util/Constants.h +++ b/src/llvm/include/Util/Constants.h @@ -1,15 +1,15 @@ -#ifndef VCLLVM_CONSTANTS_H -#define VCLLVM_CONSTANTS_H +#ifndef PALLAS_CONSTANTS_H +#define PALLAS_CONSTANTS_H #include /** * Useful string constants to use for searching out metadata nodes */ -namespace vcllvm::constants { - const std::string VC_PREFIX = "VC."; +namespace pallas::constants { +const std::string VC_PREFIX = "VC."; - const std::string METADATA_PURE_KEYWORD = VC_PREFIX + "pure"; - const std::string METADATA_CONTRACT_KEYWORD = VC_PREFIX + "contract"; - const std::string METADATA_GLOBAL_KEYWORD = VC_PREFIX + "global"; -} +const std::string METADATA_PURE_KEYWORD = VC_PREFIX + "pure"; +const std::string METADATA_CONTRACT_KEYWORD = VC_PREFIX + "contract"; +const std::string METADATA_GLOBAL_KEYWORD = VC_PREFIX + "global"; +} // namespace pallas::constants -#endif //VCLLVM_CONSTANTS_H +#endif // PALLAS_CONSTANTS_H diff --git a/src/llvm/include/Util/Exceptions.h b/src/llvm/include/Util/Exceptions.h index ecfcf14bb2..ec6df5217e 100644 --- a/src/llvm/include/Util/Exceptions.h +++ b/src/llvm/include/Util/Exceptions.h @@ -1,36 +1,75 @@ -#ifndef VCLLVM_EXCEPTIONS_H -#define VCLLVM_EXCEPTIONS_H +#ifndef PALLAS_EXCEPTIONS_H +#define PALLAS_EXCEPTIONS_H #include +#include /** - * Error handler for VCLLVM. Contains exception types and a static ErrorReporter class to which errors can be added from - * anywhere in the program. Before attempting to serialize the buffer, VCLLVM will check for errors. If there are errors, - * VCLLVM will present them and aboard the program. + * Error handler for pallas. Contains exception types and a static ErrorReporter + * class to which errors can be added from anywhere in the program. Before + * attempting to serialize the buffer, pallas will check for errors. If there + * are errors, pallas will present them and aboard the program. */ -namespace vcllvm { - struct UnsupportedTypeException : public std::exception { - [[nodiscard]] const char * what() const noexcept override; - }; +namespace pallas { +struct UnsupportedTypeException : public std::exception { + UnsupportedTypeException(const llvm::Type &); - class ErrorReporter { - private: - static u_int32_t errorCount; + [[nodiscard]] const char *what() const noexcept; - static void addError(const std::string &source, const std::string &message, const std::string &origin); + private: + std::string str; +}; - public: - static void addError(const std::string &source, const std::string &message, llvm::Module &llvmModule); +class ErrorReporter { + private: + static u_int32_t errorCount; + static u_int32_t warningCount; - static void addError(const std::string &source, const std::string &message, llvm::Function &llvmFunction); + public: + static void addError(const std::string &source, const std::string &message); - static void addError(const std::string &source, const std::string &message, llvm::BasicBlock &llvmBlock); + static void addError(const std::string &source, const std::string &message, + const std::string &origin); - static void addError(const std::string &source, const std::string &message, llvm::Instruction &llvmInstruction); + static void addError(const std::string &source, const std::string &message, + llvm::Module &llvmModule); - static bool hasErrors(); + static void addError(const std::string &source, const std::string &message, + llvm::Function &llvmFunction); - static u_int32_t getErrorCount(); - }; -} -#endif //VCLLVM_EXCEPTIONS_H + static void addError(const std::string &source, const std::string &message, + llvm::BasicBlock &llvmBlock); + + static void addError(const std::string &source, const std::string &message, + llvm::Instruction &llvmInstruction); + + static void addWarning(const std::string &source, + const std::string &message); + + static void addWarning(const std::string &source, + const std::string &message, + const std::string &origin); + + static void addWarning(const std::string &source, + const std::string &message, + llvm::Module &llvmModule); + + static void addWarning(const std::string &source, + const std::string &message, + llvm::Function &llvmFunction); + + static void addWarning(const std::string &source, + const std::string &message, + llvm::BasicBlock &llvmBlock); + + static void addWarning(const std::string &source, + const std::string &message, + llvm::Instruction &llvmInstruction); + + static bool hasErrors(); + + static u_int32_t getErrorCount(); + static u_int32_t getWarningCount(); +}; +} // namespace pallas +#endif // PALLAS_EXCEPTIONS_H diff --git a/src/llvm/lib/Origin/ContextDeriver.cpp b/src/llvm/lib/Origin/ContextDeriver.cpp new file mode 100644 index 0000000000..b838e0d4c9 --- /dev/null +++ b/src/llvm/lib/Origin/ContextDeriver.cpp @@ -0,0 +1,81 @@ +#include "Origin/ContextDeriver.h" + +#include +#include + +// module derivers +std::string llvm2col::deriveModuleContext(llvm::Module &llvmModule) { + std::string context; + llvm::raw_string_ostream(context) << llvmModule; + return context; +} + +// function derivers +std::string llvm2col::deriveFunctionContext(llvm::Function &llvmFunction) { + std::string context; + llvm::raw_string_ostream(context) << llvmFunction; + return context; +} + +// block derivers +std::string llvm2col::deriveLabelContext(llvm::BasicBlock &llvmBlock) { + if (llvmBlock.isEntryBlock()) { + return ""; + } + std::string fullContext; + llvm::raw_string_ostream(fullContext) << llvmBlock; + return fullContext.substr(0, fullContext.find(':') + 1); +} + +std::string llvm2col::deriveBlockContext(llvm::BasicBlock &llvmBlock) { + std::string context; + llvm::raw_string_ostream(context) << llvmBlock; + return context; +} + +// instruction derivers +std::string llvm2col::deriveSurroundingInstructionContext( + llvm::Instruction &llvmInstruction) { + std::string context; + if (llvmInstruction.getPrevNode() != nullptr) { + llvm::raw_string_ostream(context) + << *llvmInstruction.getPrevNode() << '\n'; + } + llvm::raw_string_ostream(context) << llvmInstruction; + if (llvmInstruction.getNextNode() != nullptr) { + llvm::raw_string_ostream(context) << '\n' + << *llvmInstruction.getNextNode(); + } + return context; +} + +std::string +llvm2col::deriveInstructionContext(llvm::Instruction &llvmInstruction) { + std::string context; + llvm::raw_string_ostream(context) << llvmInstruction; + return context; +} + +std::string llvm2col::deriveGlobalVariableContext( + llvm::GlobalVariable &llvmGlobalVariable) { + std::string context; + llvm::raw_string_ostream(context) << llvmGlobalVariable; + return context; +} + +std::string llvm2col::deriveInstructionLhs(llvm::Instruction &llvmInstruction) { + std::string fullContext = deriveInstructionContext(llvmInstruction); + return fullContext.substr(0, fullContext.find('=')); +} + +std::string llvm2col::deriveInstructionRhs(llvm::Instruction &llvmInstruction) { + std::string fullContext = deriveInstructionContext(llvmInstruction); + return fullContext.substr(fullContext.find('=') + 1); +} + +std::string llvm2col::deriveOperandContext(llvm::Value &llvmOperand) { + std::string context; + llvm::raw_string_ostream contextStream = llvm::raw_string_ostream(context); + llvmOperand.printAsOperand(contextStream, false); + return context; +} diff --git a/src/llvm/lib/Origin/OriginProvider.cpp b/src/llvm/lib/Origin/OriginProvider.cpp new file mode 100644 index 0000000000..21bea6dbfb --- /dev/null +++ b/src/llvm/lib/Origin/OriginProvider.cpp @@ -0,0 +1,343 @@ +#include "Origin/OriginProvider.h" + +#include + +#include "Origin/ContextDeriver.h" +#include "Origin/PreferredNameDeriver.h" +#include "Origin/ShortPositionDeriver.h" + +namespace col = vct::col::ast; + +col::Origin *llvm2col::generateProgramOrigin(llvm::Module &llvmModule) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name("program:" + llvmModule.getName().str()); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveModuleContext(llvmModule)); + context->set_inline_context(deriveModuleContext(llvmModule)); + context->set_short_position(deriveModuleShortPosition(llvmModule)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateFuncDefOrigin(llvm::Function &llvmFunction) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name(llvmFunction.getName().str()); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveFunctionContext(llvmFunction)); + context->set_inline_context(deriveFunctionContext(llvmFunction)); + context->set_short_position(deriveFunctionShortPosition(llvmFunction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin * +llvm2col::generateFunctionContractOrigin(llvm::Function &llvmFunction, + const std::string &contract) { + col::Origin *origin = new col::Origin(); + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(contract); + context->set_inline_context(contract); + context->set_short_position(deriveFunctionShortPosition(llvmFunction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateGlobalValOrigin(llvm::Module &llvmModule, + const std::string &globVal) { + col::Origin *origin = new col::Origin(); + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(globVal); + context->set_inline_context(globVal); + context->set_short_position(deriveModuleShortPosition(llvmModule)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateArgumentOrigin(llvm::Argument &llvmArgument) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name( + deriveArgumentPreferredName(llvmArgument)); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveFunctionContext(*llvmArgument.getParent())); + context->set_inline_context( + deriveFunctionContext(*llvmArgument.getParent())); + context->set_short_position( + deriveFunctionShortPosition(*llvmArgument.getParent())); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateBlockOrigin(llvm::BasicBlock &llvmBlock) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name("block"); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveBlockContext(llvmBlock)); + context->set_inline_context(deriveBlockContext(llvmBlock)); + context->set_short_position(deriveBlockShortPosition(llvmBlock)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateLabelOrigin(llvm::BasicBlock &llvmBlock) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name("label"); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveLabelContext(llvmBlock)); + context->set_inline_context(deriveLabelContext(llvmBlock)); + context->set_short_position(deriveBlockShortPosition(llvmBlock)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin * +llvm2col::generateSingleStatementOrigin(llvm::Instruction &llvmInstruction) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name( + deriveOperandPreferredName(llvmInstruction)); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveSurroundingInstructionContext(llvmInstruction)); + context->set_inline_context(deriveInstructionContext(llvmInstruction)); + context->set_short_position( + deriveInstructionShortPosition(llvmInstruction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin * +llvm2col::generateAssignTargetOrigin(llvm::Instruction &llvmInstruction) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name("var"); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveInstructionContext(llvmInstruction)); + context->set_inline_context(deriveInstructionLhs(llvmInstruction)); + context->set_short_position( + deriveInstructionShortPosition(llvmInstruction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin * +llvm2col::generateBinExprOrigin(llvm::Instruction &llvmInstruction) { + col::Origin *origin = new col::Origin(); + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveSurroundingInstructionContext(llvmInstruction)); + context->set_inline_context(deriveInstructionContext(llvmInstruction)); + context->set_short_position( + deriveInstructionShortPosition(llvmInstruction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin * +llvm2col::generateFunctionCallOrigin(llvm::CallInst &callInstruction) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name( + callInstruction.getCalledFunction()->getName().str()); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveSurroundingInstructionContext(callInstruction)); + context->set_inline_context(deriveInstructionRhs(callInstruction)); + context->set_short_position( + deriveInstructionShortPosition(callInstruction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateOperandOrigin(llvm::Instruction &llvmInstruction, + llvm::Value &llvmOperand) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name(deriveOperandPreferredName(llvmOperand)); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveInstructionContext(llvmInstruction)); + context->set_inline_context(deriveOperandContext(llvmOperand)); + context->set_short_position( + deriveInstructionShortPosition(llvmInstruction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateGlobalVariableOrigin( + llvm::Module &llvmModule, llvm::GlobalVariable &llvmGlobalVariable) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name(llvmGlobalVariable.getName().str()); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveGlobalVariableContext(llvmGlobalVariable)); + context->set_inline_context("unknown"); + context->set_short_position(deriveModuleShortPosition(llvmModule)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateGlobalVariableInitializerOrigin( + llvm::Module &llvmModule, llvm::GlobalVariable &llvmGlobalVariable, + llvm::Value &llvmInitializer) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name( + deriveOperandPreferredName(llvmInitializer)); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveGlobalVariableContext(llvmGlobalVariable)); + context->set_inline_context(deriveOperandContext(llvmInitializer)); + context->set_short_position(deriveModuleShortPosition(llvmModule)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin * +llvm2col::generateVoidOperandOrigin(llvm::Instruction &llvmInstruction) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name("void"); + preferredNameContent->set_allocated_preferred_name(preferredName); + + col::OriginContent *contextContent = origin->add_content(); + col::Context *context = new col::Context(); + context->set_context(deriveInstructionContext(llvmInstruction)); + context->set_inline_context("void"); + context->set_short_position( + deriveInstructionShortPosition(llvmInstruction)); + contextContent->set_allocated_context(context); + + return origin; +} + +col::Origin *llvm2col::generateTypeOrigin(llvm::Type &llvmType) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name(deriveTypePreferredName(llvmType)); + preferredNameContent->set_allocated_preferred_name(preferredName); + + return origin; +} + +col::Origin * +llvm2col::generateMemoryOrderingOrigin(llvm::AtomicOrdering &llvmOrdering) { + col::Origin *origin = new col::Origin(); + col::OriginContent *preferredNameContent = origin->add_content(); + col::PreferredName *preferredName = new col::PreferredName(); + preferredName->add_preferred_name( + deriveMemoryOrderingPreferredName(llvmOrdering)); + preferredNameContent->set_allocated_preferred_name(preferredName); + + return origin; +} + +std::string llvm2col::extractShortPosition(const col::Origin &origin) { + for (const col::OriginContent &content : origin.content()) { + if (content.has_context()) { + return content.context().short_position(); + } + } + return "unknown"; +} + +col::Origin *llvm2col::deepenOperandOrigin(const col::Origin &origin, + llvm::Value &llvmOperand) { + col::Origin *newOrigin = new col::Origin(origin); + + bool foundName = false; + bool foundContext = false; + for (col::OriginContent &content : *newOrigin->mutable_content()) { + if (content.has_preferred_name()) { + col::PreferredName *preferredName = + content.mutable_preferred_name(); + preferredName->clear_preferred_name(); + preferredName->add_preferred_name( + deriveOperandPreferredName(llvmOperand)); + foundName = true; + } else if (content.has_context()) { + content.mutable_context()->set_inline_context( + deriveOperandContext(llvmOperand)); + foundContext = true; + } + } + + if (!foundName) { + col::PreferredName *preferredName = + newOrigin->add_content()->mutable_preferred_name(); + preferredName->clear_preferred_name(); + preferredName->add_preferred_name( + deriveOperandPreferredName(llvmOperand)); + } + + if (!foundContext) { + col::Context *context = newOrigin->add_content()->mutable_context(); + context->set_context("unknown"); + context->set_inline_context(deriveOperandContext(llvmOperand)); + context->set_short_position("unknown"); + } + + return newOrigin; +} diff --git a/src/llvm/lib/Origin/PreferredNameDeriver.cpp b/src/llvm/lib/Origin/PreferredNameDeriver.cpp new file mode 100644 index 0000000000..bd0301f8f7 --- /dev/null +++ b/src/llvm/lib/Origin/PreferredNameDeriver.cpp @@ -0,0 +1,102 @@ +#include "Origin/PreferredNameDeriver.h" + +#include +#include +#include + +std::string llvm2col::deriveOperandPreferredName(llvm::Value &llvmOperand) { + if (!llvmOperand.getName().empty()) + return std::string(llvmOperand.getName()); + std::string preferredName; + llvm::raw_string_ostream preferredNameStream = + llvm::raw_string_ostream(preferredName); + preferredNameStream << (llvm::isa(llvmOperand) ? "const_" + + : "var_"); + + llvmOperand.printAsOperand(preferredNameStream, false); + return preferredName; +} + +std::string llvm2col::deriveTypePreferredName(llvm::Type &llvmType) { + std::string prefix = "t_"; + switch (llvmType.getTypeID()) { + case llvm::Type::HalfTyID: + return prefix + "half"; + case llvm::Type::BFloatTyID: + return prefix + "bfloat"; + case llvm::Type::FloatTyID: + return prefix + "float"; + case llvm::Type::DoubleTyID: + return prefix + "double"; + case llvm::Type::X86_FP80TyID: + return prefix + "x86fp80"; + case llvm::Type::FP128TyID: + return prefix + "fp128"; + case llvm::Type::PPC_FP128TyID: + return prefix + "ppcfp128"; + case llvm::Type::VoidTyID: + return prefix + "void"; + case llvm::Type::LabelTyID: + return prefix + "label"; + case llvm::Type::MetadataTyID: + return prefix + "metadata"; + case llvm::Type::X86_MMXTyID: + return prefix + "x86mmx"; + case llvm::Type::X86_AMXTyID: + return prefix + "x86amx"; + case llvm::Type::TokenTyID: + return prefix + "token"; + case llvm::Type::IntegerTyID: + return prefix + + (llvmType.getIntegerBitWidth() == 1 ? "boolean" : "integer"); + case llvm::Type::FunctionTyID: + return prefix + "function"; + case llvm::Type::PointerTyID: + return prefix + "ptr"; + case llvm::Type::StructTyID: + return prefix + "struct"; + case llvm::Type::ArrayTyID: + return prefix + "array"; + case llvm::Type::FixedVectorTyID: + return prefix + "fixedvector"; + case llvm::Type::ScalableVectorTyID: + return prefix + "scalevector"; + case llvm::Type::TypedPointerTyID: + return prefix + "typedptr"; + case llvm::Type::TargetExtTyID: + return prefix + "targetext"; + } + return "UNKNOWN"; +} + +std::string llvm2col::deriveMemoryOrderingPreferredName( + llvm::AtomicOrdering &llvmOrdering) { + switch (llvmOrdering) { + case llvm::AtomicOrdering::NotAtomic: + return "NotAtomic"; + case llvm::AtomicOrdering::Unordered: + return "Unordered"; + case llvm::AtomicOrdering::Monotonic: + return "Monotonic"; + case llvm::AtomicOrdering::Acquire: + return "Acquire"; + case llvm::AtomicOrdering::Release: + return "Release"; + case llvm::AtomicOrdering::AcquireRelease: + return "AcquireRelease"; + case llvm::AtomicOrdering::SequentiallyConsistent: + return "SequentiallyConsistent"; + } + return "UNKNOWN"; +} + +std::string +llvm2col::deriveArgumentPreferredName(llvm::Argument &llvmArgument) { + std::string preferredName; + llvm::raw_string_ostream preferredNameStream = + llvm::raw_string_ostream(preferredName); + preferredNameStream << "arg_"; + llvmArgument.printAsOperand(preferredNameStream, false); + return preferredName; +} diff --git a/src/llvm/lib/Origin/ShortPositionDeriver.cpp b/src/llvm/lib/Origin/ShortPositionDeriver.cpp new file mode 100644 index 0000000000..ff5faf775e --- /dev/null +++ b/src/llvm/lib/Origin/ShortPositionDeriver.cpp @@ -0,0 +1,49 @@ +#include "Origin/ShortPositionDeriver.h" +#include "Origin/ContextDeriver.h" + +const std::string POSITION_POINTER = "\n\t -> "; + +std::string llvm2col::deriveModuleShortPosition(llvm::Module &llvmModule) { + return "file " + llvmModule.getSourceFileName(); +} + +std::string +llvm2col::deriveFunctionShortPosition(llvm::Function &llvmFunction) { + std::string functionPosition = + deriveModuleShortPosition(*llvmFunction.getParent()); + llvm::raw_string_ostream functionPosStream = + llvm::raw_string_ostream(functionPosition); + functionPosStream << POSITION_POINTER << "function "; + llvmFunction.printAsOperand(functionPosStream, false); + return functionPosition; +} + +std::string llvm2col::deriveBlockShortPosition(llvm::BasicBlock &llvmBlock) { + std::string blockPosition = + deriveFunctionShortPosition(*llvmBlock.getParent()); + llvm::raw_string_ostream blockPosStream = + llvm::raw_string_ostream(blockPosition); + blockPosStream << POSITION_POINTER << "block "; + llvmBlock.printAsOperand(blockPosStream, false); + blockPosStream << (llvmBlock.isEntryBlock() ? " (entryblock)" : ""); + return blockPosition; +} + +std::string +llvm2col::deriveInstructionShortPosition(llvm::Instruction &llvmInstruction) { + std::string instructionPosition = + deriveBlockShortPosition(*llvmInstruction.getParent()); + llvm::raw_string_ostream instructionPosStream = + llvm::raw_string_ostream(instructionPosition); + int pos = 0; + llvm::BasicBlock *bb = llvmInstruction.getParent(); + for (auto &I : *bb) { + pos++; + if (&I == &llvmInstruction) { + break; + } + } + instructionPosStream << POSITION_POINTER << "instruction #" << pos << " (" + << deriveInstructionContext(llvmInstruction) << ')'; + return instructionPosition; +} diff --git a/src/llvm/lib/Passes/Function/FunctionBodyTransformer.cpp b/src/llvm/lib/Passes/Function/FunctionBodyTransformer.cpp new file mode 100644 index 0000000000..215d9ae74e --- /dev/null +++ b/src/llvm/lib/Passes/Function/FunctionBodyTransformer.cpp @@ -0,0 +1,185 @@ +#include "Passes/Function/FunctionBodyTransformer.h" + +#include "Origin/OriginProvider.h" +#include "Passes/Function/FunctionContractDeclarer.h" +#include "Passes/Function/FunctionDeclarer.h" +#include "Transform/BlockTransform.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" +#include + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Function::FunctionBodyTransformer"; + +FunctionCursor::FunctionCursor(col::Scope &functionScope, + col::Block &functionBody, + llvm::Function &llvmFunction, + llvm::FunctionAnalysisManager &FAM) + : functionScope(functionScope), functionBody(functionBody), + llvmFunction(llvmFunction), FAM(FAM) {} + +const col::Scope &FunctionCursor::getFunctionScope() { return functionScope; } + +void FunctionCursor::addVariableMapEntry(Value &llvmValue, + col::Variable &colVar) { + variableMap.insert({&llvmValue, &colVar}); + // add reference to reference lut of function contract + col::Tuple2_String_Ref_VctColAstVariable *ref = + FAM.getResult(llvmFunction) + .getAssociatedColFuncContract() + .add_variable_refs(); + ref->set_v1(llvm2col::getValueName(llvmValue)); + ref->mutable_v2()->set_id(colVar.id()); +} + +col::Variable &FunctionCursor::getVariableMapEntry(Value &llvmValue, + bool inPhiNode) { + if (auto variablePair = variableMap.find(&llvmValue); + variablePair != variableMap.end()) { + return *variablePair->second; + } else { + if (!inPhiNode) { + std::string str; + llvm::raw_string_ostream output(str); + output << "Use of undeclared variable: '" << llvmValue << "'"; + ErrorReporter::addError(SOURCE_LOC, str); + } + + col::Variable *colVar = new col::Variable(); + addVariableMapEntry(llvmValue, *colVar); + return *colVar; + } +} + +bool FunctionCursor::isVisited(BasicBlock &llvmBlock) { + return llvmBlock2LabeledColBlock.contains(&llvmBlock); +} + +void FunctionCursor::complete(col::Block &colBlock) { + completedColBlocks.insert(&colBlock); +} +bool FunctionCursor::isComplete(col::Block &colBlock) { + return completedColBlocks.contains(&colBlock); +} + +LabeledColBlock & +FunctionCursor::getOrSetLLVMBlock2LabeledColBlockEntry(BasicBlock &llvmBlock) { + if (!llvmBlock2LabeledColBlock.contains(&llvmBlock)) { + // create label in buffer + col::Label *label = functionBody.add_statements()->mutable_label(); + // set label origin + label->set_allocated_origin(llvm2col::generateLabelOrigin(llvmBlock)); + // create label declaration in buffer + col::LabelDecl *labelDecl = label->mutable_decl(); + // set label decl origin + labelDecl->set_allocated_origin( + llvm2col::generateLabelOrigin(llvmBlock)); + // set label decl id + llvm2col::setColNodeId(labelDecl); + // create block inside label statement + col::Block *block = label->mutable_stat()->mutable_block(); + // set block origin + block->set_allocated_origin(llvm2col::generateBlockOrigin(llvmBlock)); + // add labeled block to the block2block lut + LabeledColBlock labeledColBlock = {*label, *block}; + llvmBlock2LabeledColBlock.insert({&llvmBlock, labeledColBlock}); + } + return llvmBlock2LabeledColBlock.at(&llvmBlock); +} + +LoopInfo &FunctionCursor::getLoopInfo() { + return FAM.getResult(llvmFunction); +} + +LoopInfo &FunctionCursor::getLoopInfo(Function &otherLLVMFunction) { + return FAM.getResult(otherLLVMFunction); +} + +FDResult &FunctionCursor::getFDResult() { + return FAM.getResult(llvmFunction); +} + +FDResult &FunctionCursor::getFDResult(Function &otherLLVMFunction) { + return FAM.getResult(otherLLVMFunction); +} + +col::Variable &FunctionCursor::declareVariable(Instruction &llvmInstruction, + Type *llvmPointerType) { + // create declaration in buffer + col::Variable *varDecl = functionScope.add_locals(); + // set type of declaration + try { + if (llvmPointerType == nullptr) { + llvm2col::transformAndSetType(*llvmInstruction.getType(), + *varDecl->mutable_t()); + } else { + llvm2col::transformAndSetPointerType(*llvmPointerType, + *varDecl->mutable_t()); + } + } catch (pallas::UnsupportedTypeException &e) { + std::stringstream errorStream; + errorStream << e.what() << " in variable declaration."; + ErrorReporter::addError(SOURCE_LOC, errorStream.str(), llvmInstruction); + } + // set id + llvm2col::setColNodeId(varDecl); + // set origin + varDecl->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(llvmInstruction)); + // add to the variable lut + this->addVariableMapEntry(llvmInstruction, *varDecl); + return *varDecl; +} + +col::Assign &FunctionCursor::createAssignmentAndDeclaration( + Instruction &llvmInstruction, col::Block &colBlock, Type *llvmPointerType) { + col::Variable &varDecl = declareVariable(llvmInstruction, llvmPointerType); + return createAssignment(llvmInstruction, colBlock, varDecl); +} + +col::Assign &FunctionCursor::createAssignment(Instruction &llvmInstruction, + col::Block &colBlock, + col::Variable &varDecl) { + col::Assign *assignment = colBlock.add_statements()->mutable_assign(); + assignment->set_allocated_blame(new col::Blame()); + assignment->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(llvmInstruction)); + // create local target in buffer and set origin + col::Local *colLocal = assignment->mutable_target()->mutable_local(); + colLocal->set_allocated_origin( + llvm2col::generateAssignTargetOrigin(llvmInstruction)); + // set target to refer to var decl + colLocal->mutable_ref()->set_id(varDecl.id()); + if (isComplete(colBlock)) { + // if the colBlock is completed, the assignment will be inserted after + // the goto/branch statement this can occur due to e.g. phi nodes back + // tracking assignments in their origin blocks. therefore we need to + // swap the last two elements of the block (i.e. the goto statement and + // the newest assignment) + int lastIndex = colBlock.statements_size() - 1; + colBlock.mutable_statements()->SwapElements(lastIndex, lastIndex - 1); + } + return *assignment; +} + +llvm::FunctionAnalysisManager &FunctionCursor::getFunctionAnalysisManager() { + return FAM; +} + +PreservedAnalyses +FunctionBodyTransformerPass::run(Function &F, FunctionAnalysisManager &FAM) { + ColScopedFuncBody scopedFuncBody = + FAM.getResult(F).getAssociatedScopedColFuncBody(); + FunctionCursor funcCursor = + FunctionCursor(*scopedFuncBody.scope, *scopedFuncBody.block, F, FAM); + // add function arguments to the variableMap + for (auto &A : F.args()) { + funcCursor.addVariableMapEntry( + A, FAM.getResult(F).getFuncArgMapEntry(A)); + } + // start recursive block code gen with basic block + llvm::BasicBlock &entryBlock = F.getEntryBlock(); + llvm2col::transformLLVMBlock(entryBlock, funcCursor); + return PreservedAnalyses::all(); +} +} // namespace pallas diff --git a/src/llvm/lib/Passes/Function/FunctionContractDeclarer.cpp b/src/llvm/lib/Passes/Function/FunctionContractDeclarer.cpp new file mode 100644 index 0000000000..f97ca35cfe --- /dev/null +++ b/src/llvm/lib/Passes/Function/FunctionContractDeclarer.cpp @@ -0,0 +1,87 @@ +#include "Passes/Function/FunctionContractDeclarer.h" + +#include "Origin/OriginProvider.h" +#include "Passes/Function/FunctionDeclarer.h" +#include "Util/Constants.h" +#include "Util/Exceptions.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Function::FunctionContractDeclarer"; + +using namespace llvm; + +/* + * Function Contract Declarer Result + */ + +FDCResult::FDCResult(vct::col::ast::LlvmFunctionContract &colFuncContract) + : associatedColFuncContract(colFuncContract) {} + +col::LlvmFunctionContract &FDCResult::getAssociatedColFuncContract() { + return associatedColFuncContract; +} + +/* + * Function Contract Declarer (Analysis) + */ + +AnalysisKey FunctionContractDeclarer::Key; + +FunctionContractDeclarer::Result +FunctionContractDeclarer::run(Function &F, FunctionAnalysisManager &FAM) { + // fetch relevant function from the Function Declarer + FDResult fdResult = FAM.getResult(F); + col::LlvmFunctionDefinition &colFunction = + fdResult.getAssociatedColFuncDef(); + // set a contract in the buffer as well as make and return a result object + return FDCResult(*colFunction.mutable_contract()); +} + +/* + * Function Contract Declarer Pass + */ +PreservedAnalyses +FunctionContractDeclarerPass::run(Function &F, FunctionAnalysisManager &FAM) { + // get col contract + FDCResult result = FAM.getResult(F); + col::LlvmFunctionContract &colContract = + result.getAssociatedColFuncContract(); + colContract.set_allocated_blame(new col::Blame()); + colContract.set_name(F.getName()); + // check if contract keyword is present + if (!F.hasMetadata(pallas::constants::METADATA_CONTRACT_KEYWORD)) { + // set contract to a tautology + colContract.set_value("requires true;"); + colContract.set_allocated_origin(new col::Origin()); + return PreservedAnalyses::all(); + } + // concatenate all contract lines with new lines + MDNode *contractMDNode = + F.getMetadata(pallas::constants::METADATA_CONTRACT_KEYWORD); + std::stringstream contractStream; + for (u_int32_t i = 0; i < contractMDNode->getNumOperands(); i++) { + auto contractLine = dyn_cast(contractMDNode->getOperand(i)); + if (contractLine == nullptr) { + std::stringstream errorStream; + errorStream << "Unable to cast contract metadata node #" << i + 1 + << "to string type"; + pallas::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); + break; + } + contractStream << contractLine->getString().str() << '\n'; + } + colContract.set_value(contractStream.str()); + colContract.set_allocated_origin( + llvm2col::generateFunctionContractOrigin(F, contractStream.str())); + // add all callable functions to the contracts invokables + for (auto &moduleF : F.getParent()->functions()) { + std::string fName = '@' + moduleF.getName().str(); + int64_t fId = FAM.getResult(moduleF).getFunctionId(); + col::Tuple2_String_Ref_VctColAstLlvmCallable *invokeRef = + colContract.add_invokable_refs(); + invokeRef->set_v1(fName); + invokeRef->mutable_v2()->set_id(fId); + } + return PreservedAnalyses::all(); +} +} // namespace pallas diff --git a/src/llvm/lib/Passes/Function/FunctionDeclarer.cpp b/src/llvm/lib/Passes/Function/FunctionDeclarer.cpp new file mode 100644 index 0000000000..ce692455a2 --- /dev/null +++ b/src/llvm/lib/Passes/Function/FunctionDeclarer.cpp @@ -0,0 +1,137 @@ +#include "Passes/Function/FunctionDeclarer.h" + +#include "Origin/OriginProvider.h" +#include "Passes/Module/RootContainer.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Function::FunctionDeclarer"; +using namespace llvm; + +/** + * Checks function definition for unsupported features that might change + * semantics and adds warning if this is the case. + * @param llvmFunction: the function to be checked + */ +void checkFunctionSupport(llvm::Function &llvmFunction) { + // TODO add syntax support checks that change the semantics of the program + // to function definitions + // TODO see: https://releases.llvm.org/15.0.0/docs/LangRef.html#functions +} + +/* + * Function Declarer Result + */ + +FDResult::FDResult(col::LlvmFunctionDefinition &colFuncDef, + ColScopedFuncBody associatedScopedColFuncBody, + int64_t functionId) + : associatedColFuncDef(colFuncDef), + associatedScopedColFuncBody(associatedScopedColFuncBody), + functionId(functionId) {} + +col::LlvmFunctionDefinition &FDResult::getAssociatedColFuncDef() { + return associatedColFuncDef; +} + +ColScopedFuncBody FDResult::getAssociatedScopedColFuncBody() { + return associatedScopedColFuncBody; +} + +void FDResult::addFuncArgMapEntry(Argument &llvmArg, col::Variable &colArg) { + funcArgMap.insert({&llvmArg, &colArg}); +} + +col::Variable &FDResult::getFuncArgMapEntry(Argument &arg) { + return *funcArgMap.at(&arg); +} + +int64_t &FDResult::getFunctionId() { return functionId; } + +/* + * Function Declarer (Analysis) + */ +AnalysisKey FunctionDeclarer::Key; + +FDResult FunctionDeclarer::run(Function &F, FunctionAnalysisManager &FAM) { + auto MAM = FAM.getResult(F); + auto pProgram = MAM.getCachedResult(*F.getParent())->program; + checkFunctionSupport(F); + // create llvmFuncDef declaration in buffer + col::GlobalDeclaration *llvmFuncDefDecl = pProgram->add_declarations(); + // generate id + col::LlvmFunctionDefinition *llvmFuncDef = + llvmFuncDefDecl->mutable_llvm_function_definition(); + int64_t functionId = llvm2col::setColNodeId(llvmFuncDef); + // add body block + scope + origin + llvmFuncDef->set_allocated_blame(new col::Blame()); + // set origin + llvmFuncDef->set_allocated_origin(llvm2col::generateFuncDefOrigin(F)); + ColScopedFuncBody funcScopedBody{}; + if (!F.isDeclaration()) { + funcScopedBody.scope = + llvmFuncDef->mutable_function_body()->mutable_scope(); + funcScopedBody.scope->set_allocated_origin( + llvm2col::generateFuncDefOrigin(F)); + funcScopedBody.block = + funcScopedBody.scope->mutable_body()->mutable_block(); + funcScopedBody.block->set_allocated_origin( + llvm2col::generateFuncDefOrigin(F)); + } + FDResult result = FDResult(*llvmFuncDef, funcScopedBody, functionId); + // set args (if present) + for (llvm::Argument &llvmArg : F.args()) { + // set in buffer + col::Variable *colArg = llvmFuncDef->add_args(); + // set origin + colArg->set_allocated_origin(llvm2col::generateArgumentOrigin(llvmArg)); + llvm2col::setColNodeId(colArg); + try { + llvm2col::transformAndSetType(*llvmArg.getType(), + *colArg->mutable_t()); + } catch (pallas::UnsupportedTypeException &e) { + std::stringstream errorStream; + errorStream << e.what() << " in argument #" << llvmArg.getArgNo(); + pallas::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); + } + // add args mapping to result + result.addFuncArgMapEntry(llvmArg, *colArg); + } + llvmFuncDef->set_allocated_blame(new col::Blame()); + // complete the function declaration in proto buffer + // set return type in protobuf of function + try { + llvm2col::transformAndSetType(*F.getReturnType(), + *llvmFuncDef->mutable_return_type()); + } catch (pallas::UnsupportedTypeException &e) { + std::stringstream errorStream; + errorStream << e.what() << " in return signature"; + pallas::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); + } + + if (F.isDeclaration()) { + // Defined outside of this module so we don't know if it's pure or what + // its contract is + col::LlvmFunctionContract *colContract = + llvmFuncDef->mutable_contract(); + colContract->set_allocated_blame(new col::Blame()); + colContract->set_value("requires true;"); + colContract->set_name(F.getName()); + colContract->set_allocated_origin(new col::Origin()); + + llvmFuncDef->set_pure(false); + } + return result; +} + +/* + * Function Declarer Pass + */ +PreservedAnalyses FunctionDeclarerPass::run(Function &F, + FunctionAnalysisManager &FAM) { + FDResult result = FAM.getResult(F); + // Just makes sure we analyse every function + return PreservedAnalyses::all(); +} +} // namespace pallas diff --git a/src/llvm/lib/Passes/Function/PureAssigner.cpp b/src/llvm/lib/Passes/Function/PureAssigner.cpp new file mode 100644 index 0000000000..46b0415de7 --- /dev/null +++ b/src/llvm/lib/Passes/Function/PureAssigner.cpp @@ -0,0 +1,59 @@ +#include "Passes/Function/PureAssigner.h" + +#include "Passes/Function/FunctionDeclarer.h" +#include "Util/Constants.h" +#include "Util/Exceptions.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Function::PureAssigner"; + +using namespace llvm; + +/** + * Helper function to generate errors generated by this Pass + * @param F + * @param explanation + */ +static void reportError(Function &F, const std::string &explanation) { + std::stringstream errorStream; + errorStream << "Malformed Metadata node of type \"" + << pallas::constants::METADATA_PURE_KEYWORD + << "\":" << explanation; + pallas::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); +} + +PreservedAnalyses PureAssignerPass::run(Function &F, + FunctionAnalysisManager &FAM) { + std::ostringstream errorStream; + FDResult result = FAM.getResult(F); + col::LlvmFunctionDefinition &colFunction = result.getAssociatedColFuncDef(); + // check if pure keyword is present, else assume unpure function + if (!F.hasMetadata(pallas::constants::METADATA_PURE_KEYWORD)) { + colFunction.set_pure(false); + return PreservedAnalyses::all(); + } + // check if the 'pure' metadata has only 1 operand, else exit with error + MDNode *pureMDNode = + F.getMetadata(pallas::constants::METADATA_PURE_KEYWORD); + if (pureMDNode->getNumOperands() != 1) { + errorStream << "Expected 1 argument but got " + << pureMDNode->getNumOperands(); + reportError(F, errorStream.str()); + return PreservedAnalyses::all(); + } + // check if the only operand is of type 'i1', else exit with error + auto *pureMDValue = cast(pureMDNode->getOperand(0)); + if (!pureMDValue->getType()->isIntegerTy(1)) { + errorStream << "MD node type must be of type \"i1\""; + reportError(F, errorStream.str()); + return PreservedAnalyses::all(); + } + // attempt down cast to ConstantInt (which shouldn't fail given previous + // checks) + bool purity = + cast(pureMDValue)->getValue()->isOneValue(); + colFunction.set_pure(purity); + return PreservedAnalyses::all(); +} + +} // namespace pallas diff --git a/src/llvm/lib/Passes/Module/GlobalVariableDeclarer.cpp b/src/llvm/lib/Passes/Module/GlobalVariableDeclarer.cpp new file mode 100644 index 0000000000..e79f351909 --- /dev/null +++ b/src/llvm/lib/Passes/Module/GlobalVariableDeclarer.cpp @@ -0,0 +1,49 @@ +#include "Passes/Module/GlobalVariableDeclarer.h" +#include "Passes/Module/RootContainer.h" +#include "Transform/Transform.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Module::GlobalVariableDeclarer"; + +using namespace llvm; + +PreservedAnalyses GlobalVariableDeclarerPass::run(Module &M, + ModuleAnalysisManager &MAM) { + auto pProgram = MAM.getResult(M).program; + + for (auto &global : M.globals()) { + col::GlobalDeclaration *globDecl = pProgram->add_declarations(); + col::LlvmGlobalVariable *colGlobal = + globDecl->mutable_llvm_global_variable(); + + llvm2col::transformAndSetType(*global.getType(), + *colGlobal->mutable_variable_type()); + if (global.hasInitializer()) { + llvm2col::transformAndSetConstExpr( + MAM.getResult(M) + .getManager(), + llvm2col::generateGlobalVariableInitializerOrigin( + M, global, *global.getInitializer()), + *global.getInitializer(), *colGlobal->mutable_value()); + + llvm2col::transformAndSetType(*global.getInitializer()->getType(), + *colGlobal->mutable_variable_type()); + } else { + // We don't know more about the type because we don't have an + // initializer + // TODO: This breaks the assumption that the type of the global + // declaration type is the inner type of the pointer. We should + // instead set the type to be TAny maybe? + llvm2col::transformAndSetType(*global.getType(), + *colGlobal->mutable_variable_type()); + } + colGlobal->set_constant(global.isConstant()); + colGlobal->set_allocated_origin( + llvm2col::generateGlobalVariableOrigin(M, global)); + colGlobal->set_id(reinterpret_cast(&global)); + } + + return PreservedAnalyses::all(); +} + +} // namespace pallas diff --git a/src/llvm/lib/Passes/Module/ModuleSpecCollector.cpp b/src/llvm/lib/Passes/Module/ModuleSpecCollector.cpp new file mode 100644 index 0000000000..c5e1ced8b5 --- /dev/null +++ b/src/llvm/lib/Passes/Module/ModuleSpecCollector.cpp @@ -0,0 +1,46 @@ +#include "Passes/Module/ModuleSpecCollector.h" +#include "Origin/OriginProvider.h" +#include "Passes/Module/RootContainer.h" +#include "Transform/Transform.h" +#include "Util/Constants.h" +#include "Util/Exceptions.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Module::ModuleSpecCollector"; + +using namespace llvm; + +PreservedAnalyses ModuleSpecCollectorPass::run(Module &M, + ModuleAnalysisManager &MAM) { + auto pProgram = MAM.getResult(M).program; + NamedMDNode *globalMDNode = + M.getNamedMetadata(pallas::constants::METADATA_GLOBAL_KEYWORD); + if (globalMDNode == nullptr) { + return PreservedAnalyses::all(); + } + for (u_int32_t i = 0; i < globalMDNode->getNumOperands(); i++) { + for (u_int32_t j = 0; j < globalMDNode->getOperand(i)->getNumOperands(); + j++) { + auto globVal = + dyn_cast(globalMDNode->getOperand(i)->getOperand(j)); + if (globVal == nullptr) { + std::stringstream errorStream; + errorStream << "Unable to cast global metadata node #" << i + 1 + << "to string type"; + pallas::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), + M); + break; + } + col::GlobalDeclaration *globDecl = pProgram->add_declarations(); + col::LlvmGlobalSpecification *colGlobal = + globDecl->mutable_llvm_global_specification(); + llvm2col::setColNodeId(colGlobal); + colGlobal->set_value(globVal->getString().str()); + colGlobal->set_allocated_origin(llvm2col::generateGlobalValOrigin( + M, globVal->getString().str())); + } + } + return PreservedAnalyses::all(); +} + +} // namespace pallas diff --git a/src/llvm/lib/Passes/Module/ProtobufPrinter.cpp b/src/llvm/lib/Passes/Module/ProtobufPrinter.cpp new file mode 100644 index 0000000000..c2f083a3ad --- /dev/null +++ b/src/llvm/lib/Passes/Module/ProtobufPrinter.cpp @@ -0,0 +1,30 @@ +#include "Passes/Module/ProtobufPrinter.h" +#include "Passes/Module/RootContainer.h" +#include "Util/Exceptions.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Module::ProtobufPrinter"; + +using namespace llvm; + +PreservedAnalyses ProtobufPrinter::run(Module &M, ModuleAnalysisManager &MAM) { + if (ErrorReporter::hasErrors()) { + llvm::errs() << "[ERROR] [pallas] Conversion failed with " + << ErrorReporter::getWarningCount() << " warnings and " + << ErrorReporter::getErrorCount() << " errors\n"; + } else { + llvm::errs() << "[INFO] [pallas] Conversion succeeded with " + << ErrorReporter::getWarningCount() << "warnings\n"; + } + auto pProgram = MAM.getResult(M).program; + if (pProgram->IsInitialized()) { + std::cout << pProgram->SerializeAsString(); + } else { + llvm::errs() << "[ERROR] [pallas] Internal error, invalid protobuf " + "construction\n"; + pProgram->CheckInitialized(); + } + return PreservedAnalyses::all(); +} + +} // namespace pallas diff --git a/src/llvm/lib/Passes/Module/RootContainer.cpp b/src/llvm/lib/Passes/Module/RootContainer.cpp new file mode 100644 index 0000000000..774fe9b669 --- /dev/null +++ b/src/llvm/lib/Passes/Module/RootContainer.cpp @@ -0,0 +1,26 @@ +#include "Passes/Module/RootContainer.h" + +#include "Origin/OriginProvider.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +namespace pallas { +const std::string SOURCE_LOC = "Passes::Module::RootContainer"; +using namespace llvm; + +bool ProgramWrapper::invalidate(Module &M, const PreservedAnalyses &PA, + ModuleAnalysisManager::Invalidator &) { + return !PA.getChecker().preservedWhenStateless(); +} + +AnalysisKey RootContainer::Key; + +ProgramWrapper RootContainer::run(Module &M, ModuleAnalysisManager &MAM) { + auto pProgram = std::make_shared(); + // set program origin + pProgram->set_allocated_origin(llvm2col::generateProgramOrigin(M)); + pProgram->set_allocated_blame(new col::Blame()); + + return ProgramWrapper{pProgram}; +} +} // namespace pallas diff --git a/src/llvm/lib/Plugin.cpp b/src/llvm/lib/Plugin.cpp new file mode 100644 index 0000000000..2495dd6b54 --- /dev/null +++ b/src/llvm/lib/Plugin.cpp @@ -0,0 +1,69 @@ +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" + +#include "Passes/Function/FunctionBodyTransformer.h" +#include "Passes/Function/FunctionContractDeclarer.h" +#include "Passes/Function/FunctionDeclarer.h" +#include "Passes/Function/PureAssigner.h" +#include "Passes/Module/GlobalVariableDeclarer.h" +#include "Passes/Module/ModuleSpecCollector.h" +#include "Passes/Module/ProtobufPrinter.h" +#include "Passes/Module/RootContainer.h" + +using namespace llvm; + +llvm::PassPluginLibraryInfo getPallasPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "Pallas", LLVM_VERSION_STRING, + [](PassBuilder &PB) { + PB.registerAnalysisRegistrationCallback( + [](llvm::ModuleAnalysisManager &MAM) { + MAM.registerPass( + [&] { return pallas::RootContainer(); }); + }); + PB.registerAnalysisRegistrationCallback( + [](llvm::FunctionAnalysisManager &FAM) { + FAM.registerPass( + [&] { return pallas::FunctionDeclarer(); }); + FAM.registerPass( + [&] { return pallas::FunctionContractDeclarer(); }); + }); + PB.registerPipelineParsingCallback( + [](StringRef Name, llvm::ModulePassManager &MPM, + ArrayRef) { + if (Name == "pallas-collect-module-spec") { + MPM.addPass(pallas::ModuleSpecCollectorPass()); + return true; + } else if (Name == "pallas-declare-variables") { + MPM.addPass(pallas::GlobalVariableDeclarerPass()); + return true; + } else if (Name == "pallas-print-protobuf") { + MPM.addPass(pallas::ProtobufPrinter()); + return true; + } + return false; + }); + PB.registerPipelineParsingCallback( + [](StringRef Name, llvm::FunctionPassManager &FPM, + ArrayRef) { + if (Name == "pallas-declare-function") { + FPM.addPass(pallas::FunctionDeclarerPass()); + return true; + } else if (Name == "pallas-assign-pure") { + FPM.addPass(pallas::PureAssignerPass()); + return true; + } else if (Name == "pallas-declare-function-contract") { + FPM.addPass(pallas::FunctionContractDeclarerPass()); + return true; + } else if (Name == "pallas-transform-function-body") { + FPM.addPass(pallas::FunctionBodyTransformerPass()); + return true; + } + return false; + }); + }}; +} + +extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo +llvmGetPassPluginInfo() { + return getPallasPluginInfo(); +} diff --git a/src/llvm/lib/Transform/BlockTransform.cpp b/src/llvm/lib/Transform/BlockTransform.cpp new file mode 100644 index 0000000000..c32a1c05c7 --- /dev/null +++ b/src/llvm/lib/Transform/BlockTransform.cpp @@ -0,0 +1,77 @@ +#include "Transform/BlockTransform.h" + +#include "Transform/Instruction/BinaryOpTransform.h" +#include "Transform/Instruction/CastOpTransform.h" +#include "Transform/Instruction/FuncletPadOpTransform.h" +#include "Transform/Instruction/MemoryOpTransform.h" +#include "Transform/Instruction/OtherOpTransform.h" +#include "Transform/Instruction/TermOpTransform.h" +#include "Transform/Instruction/UnaryOpTransform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::BlockTransform"; + +void llvm2col::transformLLVMBlock(llvm::BasicBlock &llvmBlock, + pallas::FunctionCursor &functionCursor) { + if (functionCursor.isVisited(llvmBlock)) + return; + col::Block &colBlock = + functionCursor.getOrSetLLVMBlock2LabeledColBlockEntry(llvmBlock).block; + /* for (auto *B : llvm::predecessors(&llvmBlock)) { */ + /* if (!functionCursor.isVisited(*B)) */ + /* return; */ + /* } */ + /* if (functionCursor.getLoopInfo().isLoopHeader(&llvmBlock)) { */ + /* transformLoop(llvmBlock, functionCursor); */ + /* return; */ + /* } */ + for (auto &I : llvmBlock) { + transformInstruction(functionCursor, I, colBlock); + } + functionCursor.complete(colBlock); +} + +void llvm2col::transformInstruction(pallas::FunctionCursor &funcCursor, + llvm::Instruction &llvmInstruction, + col::Block &colBodyBlock) { + u_int32_t opCode = llvmInstruction.getOpcode(); + if (llvm::Instruction::TermOpsBegin <= opCode && + opCode < llvm::Instruction::TermOpsEnd) { + llvm2col::transformTermOp(llvmInstruction, colBodyBlock, funcCursor); + } else if (llvm::Instruction::BinaryOpsBegin <= opCode && + opCode < llvm::Instruction::BinaryOpsEnd) { + llvm2col::transformBinaryOp(llvmInstruction, colBodyBlock, funcCursor); + } else if (llvm::Instruction::UnaryOpsBegin <= opCode && + opCode < llvm::Instruction::UnaryOpsEnd) { + llvm2col::transformUnaryOp(llvmInstruction, colBodyBlock, funcCursor); + } else if (llvm::Instruction::MemoryOpsBegin <= opCode && + opCode < llvm::Instruction::MemoryOpsEnd) { + llvm2col::transformMemoryOp(llvmInstruction, colBodyBlock, funcCursor); + } else if (llvm::Instruction::CastOpsBegin <= opCode && + opCode < llvm::Instruction::CastOpsEnd) { + llvm2col::transformCastOp(llvmInstruction, colBodyBlock, funcCursor); + } else if (llvm::Instruction::FuncletPadOpsBegin <= opCode && + opCode < llvm::Instruction::FuncletPadOpsEnd) { + llvm2col::transformFuncletPadOp(llvmInstruction, colBodyBlock, + funcCursor); + } else if (llvm::Instruction::OtherOpsBegin <= opCode && + opCode < llvm::Instruction::OtherOpsEnd) { + llvm2col::transformOtherOp(llvmInstruction, colBodyBlock, funcCursor); + } else { + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); + } +} + +void llvm2col::transformLoop(llvm::BasicBlock &llvmBlock, + pallas::FunctionCursor &functionCursor) { + pallas::ErrorReporter::addError(SOURCE_LOC, "Unsupported loop detected", + llvmBlock); +} + +void llvm2col::reportUnsupportedOperatorError( + const std::string &source, llvm::Instruction &llvmInstruction) { + std::stringstream errorStream; + errorStream << "Unsupported operator \"" << llvmInstruction.getOpcodeName() + << '"'; + pallas::ErrorReporter::addError(source, errorStream.str(), llvmInstruction); +} diff --git a/src/llvm/lib/Transform/Instruction/BinaryOpTransform.cpp b/src/llvm/lib/Transform/Instruction/BinaryOpTransform.cpp new file mode 100644 index 0000000000..de070a21e2 --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/BinaryOpTransform.cpp @@ -0,0 +1,82 @@ +#include "Transform/Instruction/BinaryOpTransform.h" + +#include "Origin/OriginProvider.h" +#include "Transform/BlockTransform.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::Instruction::BinaryOp"; + +void llvm2col::transformBinaryOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Assign &assignment = + funcCursor.createAssignmentAndDeclaration(llvmInstruction, colBlock); + switch (llvm::Instruction::BinaryOps(llvmInstruction.getOpcode())) { + case llvm::Instruction::Add: { + col::Plus &expr = *assignment.mutable_value()->mutable_plus(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::Sub: { + col::Minus &expr = *assignment.mutable_value()->mutable_minus(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::Mul: { + col::Mult &expr = *assignment.mutable_value()->mutable_mult(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::SDiv: + case llvm::Instruction::UDiv: { + // XXX: There is an assumption here that signed and unsigned division + // are equal + if (llvmInstruction.isExact()) { + // XXX (Alexander): I'm not sure why we wouldn't support exact + // division because it seems to me that it is simply a promise used + // by optimisations that the right operand divides the left exactly + /* pallas::ErrorReporter::addError( */ + /* SOURCE_LOC, "Exact division not supported", llvmInstruction); + */ + } + col::FloorDiv &expr = *assignment.mutable_value()->mutable_floor_div(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + // TODO: All of these are currently bitwise operators, verify that works + // correctly when operating on booleans in VerCors + case llvm::Instruction::And: { + col::BitAnd &expr = *assignment.mutable_value()->mutable_bit_and(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::Or: { + col::BitOr &expr = *assignment.mutable_value()->mutable_bit_or(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::Xor: { + col::BitXor &expr = *assignment.mutable_value()->mutable_bit_xor(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::Shl: { + col::BitShl &expr = *assignment.mutable_value()->mutable_bit_shl(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::LShr: { + col::BitUShr &expr = *assignment.mutable_value()->mutable_bit_u_shr(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + case llvm::Instruction::AShr: { + col::BitShr &expr = *assignment.mutable_value()->mutable_bit_shr(); + transformBinExpr(llvmInstruction, expr, funcCursor); + break; + } + default: + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); + } +} diff --git a/src/llvm/lib/Transform/Instruction/CastOpTransform.cpp b/src/llvm/lib/Transform/Instruction/CastOpTransform.cpp new file mode 100644 index 0000000000..3e4a987231 --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/CastOpTransform.cpp @@ -0,0 +1,87 @@ +#include "Transform/Instruction/CastOpTransform.h" + +#include "Transform/BlockTransform.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::Instruction::CastOp"; +void llvm2col::transformCastOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + switch (llvm::Instruction::CastOps(llvmInstruction.getOpcode())) { + case llvm::Instruction::SExt: + transformSExt(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::ZExt: + transformZExt(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::Trunc: + transformTrunc(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + default: + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); + } +} + +void llvm2col::transformSExt(llvm::SExtInst &sextInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Assign &assignment = + funcCursor.createAssignmentAndDeclaration(sextInstruction, colBlock); + col::Expr *sextExpr = assignment.mutable_value(); + col::LlvmSignExtend *sext = sextExpr->mutable_llvm_sign_extend(); + sext->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(sextInstruction)); + llvm2col::transformAndSetType(*sextInstruction.getSrcTy(), + *sext->mutable_input_type()); + llvm2col::transformAndSetType(*sextInstruction.getDestTy(), + *sext->mutable_output_type()); + // TODO: Surely there must be a better way to access this operand than + // getOperand(0) + llvm2col::transformAndSetExpr(funcCursor, sextInstruction, + *sextInstruction.getOperand(0), + *sext->mutable_value()); +} + +void llvm2col::transformZExt(llvm::ZExtInst &zextInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Assign &assignment = + funcCursor.createAssignmentAndDeclaration(zextInstruction, colBlock); + col::Expr *zextExpr = assignment.mutable_value(); + col::LlvmSignExtend *zext = zextExpr->mutable_llvm_sign_extend(); + zext->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(zextInstruction)); + llvm2col::transformAndSetType(*zextInstruction.getSrcTy(), + *zext->mutable_input_type()); + llvm2col::transformAndSetType(*zextInstruction.getDestTy(), + *zext->mutable_output_type()); + // TODO: Surely there must be a better way to access this operand than + // getOperand(0) + llvm2col::transformAndSetExpr(funcCursor, zextInstruction, + *zextInstruction.getOperand(0), + *zext->mutable_value()); +} + +void llvm2col::transformTrunc(llvm::TruncInst &truncInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Assign &assignment = + funcCursor.createAssignmentAndDeclaration(truncInstruction, colBlock); + col::Expr *truncExpr = assignment.mutable_value(); + col::LlvmSignExtend *trunc = truncExpr->mutable_llvm_sign_extend(); + trunc->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(truncInstruction)); + llvm2col::transformAndSetType(*truncInstruction.getSrcTy(), + *trunc->mutable_input_type()); + llvm2col::transformAndSetType(*truncInstruction.getDestTy(), + *trunc->mutable_output_type()); + // TODO: Surely there must be a better way to access this operand than + // getOperand(0) + llvm2col::transformAndSetExpr(funcCursor, truncInstruction, + *truncInstruction.getOperand(0), + *trunc->mutable_value()); +} diff --git a/src/llvm/lib/Transform/Instruction/FuncletPadOpTransform.cpp b/src/llvm/lib/Transform/Instruction/FuncletPadOpTransform.cpp new file mode 100644 index 0000000000..104b71d3cf --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/FuncletPadOpTransform.cpp @@ -0,0 +1,13 @@ +#include "Transform/Instruction/FuncletPadOpTransform.h" + +#include "Transform/BlockTransform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::Instruction::FuncletPadOp"; + +void llvm2col::transformFuncletPadOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + // TODO stub + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); +} diff --git a/src/llvm/lib/Transform/Instruction/MemoryOpTransform.cpp b/src/llvm/lib/Transform/Instruction/MemoryOpTransform.cpp new file mode 100644 index 0000000000..ac8e3511ee --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/MemoryOpTransform.cpp @@ -0,0 +1,149 @@ +#include "Transform/Instruction/MemoryOpTransform.h" + +#include "Origin/OriginProvider.h" +#include "Transform/BlockTransform.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::Instruction::MemoryOp"; + +void llvm2col::transformMemoryOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + switch (llvm::Instruction::MemoryOps(llvmInstruction.getOpcode())) { + case llvm::Instruction::Alloca: + transformAllocA(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::Load: + transformLoad(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::Store: + transformStore(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::GetElementPtr: + transformGetElementPtr( + llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + default: + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); + } +} + +void llvm2col::transformAllocA(llvm::AllocaInst &allocAInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Assign &assignment = funcCursor.createAssignmentAndDeclaration( + allocAInstruction, colBlock, + /* pointer type*/ allocAInstruction.getAllocatedType()); + col::Expr *allocAExpr = assignment.mutable_value(); + col::LlvmAllocA *allocA = allocAExpr->mutable_llvm_alloc_a(); + allocA->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(allocAInstruction)); + llvm2col::transformAndSetType(*allocAInstruction.getAllocatedType(), + *allocA->mutable_allocation_type()); + llvm2col::transformAndSetExpr(funcCursor, allocAInstruction, + *allocAInstruction.getArraySize(), + *allocA->mutable_num_elements()); +} + +void llvm2col::transformAtomicOrdering(llvm::AtomicOrdering ordering, + col::LlvmMemoryOrdering *colOrdering) { + switch (ordering) { + case llvm::AtomicOrdering::NotAtomic: + colOrdering->mutable_llvm_memory_not_atomic()->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + case llvm::AtomicOrdering::Unordered: + colOrdering->mutable_llvm_memory_unordered()->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + case llvm::AtomicOrdering::Monotonic: + colOrdering->mutable_llvm_memory_monotonic()->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + case llvm::AtomicOrdering::Acquire: + colOrdering->mutable_llvm_memory_acquire()->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + case llvm::AtomicOrdering::Release: + colOrdering->mutable_llvm_memory_release()->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + case llvm::AtomicOrdering::AcquireRelease: + colOrdering->mutable_llvm_memory_acquire_release() + ->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + case llvm::AtomicOrdering::SequentiallyConsistent: + colOrdering->mutable_llvm_memory_sequentially_consistent() + ->set_allocated_origin( + llvm2col::generateMemoryOrderingOrigin(ordering)); + break; + } +} + +void llvm2col::transformLoad(llvm::LoadInst &loadInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + // We are not storing isVolatile and getAlign + col::Assign &assignment = + funcCursor.createAssignmentAndDeclaration(loadInstruction, colBlock); + col::Expr *loadExpr = assignment.mutable_value(); + col::LlvmLoad *load = loadExpr->mutable_llvm_load(); + load->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(loadInstruction)); + llvm::errs() << "Working on " << loadInstruction << " has type " + << *loadInstruction.getType() << "\n"; + llvm2col::transformAndSetType(*loadInstruction.getType(), + *load->mutable_load_type()); + llvm2col::transformAndSetExpr(funcCursor, loadInstruction, + *loadInstruction.getPointerOperand(), + *load->mutable_pointer()); + llvm2col::transformAtomicOrdering(loadInstruction.getOrdering(), + load->mutable_ordering()); +} + +void llvm2col::transformStore(llvm::StoreInst &storeInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + // We are not storing isVolatile and getAlign + col::LlvmStore *store = colBlock.add_statements()->mutable_llvm_store(); + store->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(storeInstruction)); + llvm2col::transformAndSetExpr(funcCursor, storeInstruction, + *storeInstruction.getValueOperand(), + *store->mutable_value()); + llvm2col::transformAndSetExpr(funcCursor, storeInstruction, + *storeInstruction.getPointerOperand(), + *store->mutable_pointer()); + llvm2col::transformAtomicOrdering(storeInstruction.getOrdering(), + store->mutable_ordering()); +} + +void llvm2col::transformGetElementPtr(llvm::GetElementPtrInst &gepInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + + col::Assign &assignment = funcCursor.createAssignmentAndDeclaration( + gepInstruction, colBlock, gepInstruction.getResultElementType()); + col::Expr *gepExpr = assignment.mutable_value(); + col::LlvmGetElementPointer *gep = + gepExpr->mutable_llvm_get_element_pointer(); + gep->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(gepInstruction)); + llvm2col::transformAndSetType(*gepInstruction.getSourceElementType(), + *gep->mutable_structure_type()); + llvm2col::transformAndSetType(*gepInstruction.getResultElementType(), + *gep->mutable_result_type()); + llvm2col::transformAndSetExpr(funcCursor, gepInstruction, + *gepInstruction.getPointerOperand(), + *gep->mutable_pointer()); + for (auto &index : gepInstruction.indices()) { + llvm2col::transformAndSetExpr(funcCursor, gepInstruction, *index.get(), + *gep->add_indices()); + } +} diff --git a/src/llvm/lib/Transform/Instruction/OtherOpTransform.cpp b/src/llvm/lib/Transform/Instruction/OtherOpTransform.cpp new file mode 100644 index 0000000000..81453faa62 --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/OtherOpTransform.cpp @@ -0,0 +1,190 @@ +#include "Transform/Instruction/OtherOpTransform.h" +#include + +#include "Transform/BlockTransform.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::Instruction::OtherOp"; + +void llvm2col::transformOtherOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + switch (llvm::Instruction::OtherOps(llvmInstruction.getOpcode())) { + case llvm::Instruction::PHI: + transformPhi(llvm::cast(llvmInstruction), funcCursor); + break; + case llvm::Instruction::ICmp: + transformICmp(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::Call: + transformCallExpr(llvm::cast(llvmInstruction), colBlock, + funcCursor); + break; + default: + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); + } +} + +void llvm2col::transformPhi(llvm::PHINode &phiInstruction, + pallas::FunctionCursor &funcCursor) { + col::Variable &varDecl = funcCursor.declareVariable(phiInstruction); + for (auto &B : phiInstruction.blocks()) { + // add assignment of the variable to target block + col::Block &targetBlock = + funcCursor.getOrSetLLVMBlock2LabeledColBlockEntry(*B).block; + col::Assign &assignment = + funcCursor.createAssignment(phiInstruction, targetBlock, varDecl); + // assign correct value by looking at the value-block pair of phi + // instruction. + col::Expr *value = assignment.mutable_value(); + llvm2col::transformAndSetExpr( + funcCursor, phiInstruction, + *phiInstruction.getIncomingValueForBlock(B), *value); + } +} + +void llvm2col::transformICmp(llvm::ICmpInst &icmpInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + // we only support integer comparison + if (not icmpInstruction.getOperand(0)->getType()->isIntegerTy()) { + pallas::ErrorReporter::addError(SOURCE_LOC, "Unsupported compare type", + icmpInstruction); + return; + } + col::Assign &assignment = + funcCursor.createAssignmentAndDeclaration(icmpInstruction, colBlock); + switch (llvm::ICmpInst::Predicate(icmpInstruction.getPredicate())) { + case llvm::CmpInst::ICMP_EQ: { + col::Eq &eq = *assignment.mutable_value()->mutable_eq(); + transformCmpExpr(icmpInstruction, eq, funcCursor); + break; + } + case llvm::CmpInst::ICMP_NE: { + col::Neq &neq = *assignment.mutable_value()->mutable_neq(); + transformCmpExpr(icmpInstruction, neq, funcCursor); + break; + } + case llvm::CmpInst::ICMP_SGT: + case llvm::CmpInst::ICMP_UGT: { + col::Greater > = *assignment.mutable_value()->mutable_greater(); + transformCmpExpr(icmpInstruction, gt, funcCursor); + break; + } + case llvm::CmpInst::ICMP_SGE: + case llvm::CmpInst::ICMP_UGE: { + col::GreaterEq &geq = *assignment.mutable_value()->mutable_greater_eq(); + transformCmpExpr(icmpInstruction, geq, funcCursor); + break; + } + case llvm::CmpInst::ICMP_SLT: + case llvm::CmpInst::ICMP_ULT: { + col::Less < = *assignment.mutable_value()->mutable_less(); + transformCmpExpr(icmpInstruction, lt, funcCursor); + break; + } + case llvm::CmpInst::ICMP_SLE: + case llvm::CmpInst::ICMP_ULE: { + col::LessEq &leq = *assignment.mutable_value()->mutable_less_eq(); + transformCmpExpr(icmpInstruction, leq, funcCursor); + break; + } + default: + pallas::ErrorReporter::addError(SOURCE_LOC, "Unknown ICMP predicate", + icmpInstruction); + } +} + +void llvm2col::transformCmpExpr(llvm::CmpInst &cmpInstruction, + auto &colCompareExpr, + pallas::FunctionCursor &funcCursor) { + transformBinExpr(cmpInstruction, colCompareExpr, funcCursor); +} + +bool llvm2col::checkCallSupport(llvm::CallInst &callInstruction) { + if (callInstruction.isIndirectCall()) { + pallas::ErrorReporter::addError( + SOURCE_LOC, "Indirect calls are not supported", callInstruction); + return false; + } + // tail recursion + if (callInstruction.isMustTailCall()) { + pallas::ErrorReporter::addError(SOURCE_LOC, + "Tail call optimization not supported", + callInstruction); + return false; + } + // fast math + if (callInstruction.getFastMathFlags().any()) { + pallas::ErrorReporter::addError(SOURCE_LOC, "Fast math not supported", + callInstruction); + return false; + } + // return attributes + for (auto &A : callInstruction.getAttributes().getRetAttrs()) { + // TODO: Deal with these most of them do not affect the semantics we + // care about so we could ignore them + std::stringstream errorStream; + errorStream << "Return attribute \"" << A.getAsString() + << "\" not supported"; + pallas::ErrorReporter::addWarning(SOURCE_LOC, errorStream.str(), + callInstruction); + return true; + } + // address space is platform dependent (unlikely to change semantics) + // function attributes are just extra compiler information (no semanatic + // changes) + + // operand bundles + if (callInstruction.hasOperandBundles()) { + pallas::ErrorReporter::addError( + SOURCE_LOC, "Operand bundles not supported", callInstruction); + return false; + } + + return true; +} + +void llvm2col::transformCallExpr(llvm::CallInst &callInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + if (!checkCallSupport(callInstruction) || + callInstruction.getCalledFunction() == nullptr) + return; + + if (callInstruction.getCalledFunction()->isIntrinsic()) { + // TODO: Deal with intrinsic functions + return; + } + // allocate expression to host the function call in advance + col::Expr *functionCallExpr; + // if void function add an eval expression + if (callInstruction.getType()->isVoidTy()) { + col::Eval *eval = colBlock.add_statements()->mutable_eval(); + eval->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(callInstruction)); + functionCallExpr = eval->mutable_expr(); + } else { // else create an assignment + col::Assign &assignment = funcCursor.createAssignmentAndDeclaration( + callInstruction, colBlock); + functionCallExpr = assignment.mutable_value(); + } + // create actual invocation + col::LlvmFunctionInvocation *invocation = + functionCallExpr->mutable_llvm_function_invocation(); + invocation->set_allocated_blame(new col::Blame()); + // set origin + invocation->set_allocated_origin( + llvm2col::generateFunctionCallOrigin(callInstruction)); + // set function reference + invocation->mutable_ref()->set_id( + funcCursor.getFDResult(*callInstruction.getCalledFunction()) + .getFunctionId()); + // process function arguments + for (auto &A : callInstruction.args()) { + llvm2col::transformAndSetExpr(funcCursor, callInstruction, *A, + *invocation->add_args()); + } +} diff --git a/src/llvm/lib/Transform/Instruction/TermOpTransform.cpp b/src/llvm/lib/Transform/Instruction/TermOpTransform.cpp new file mode 100644 index 0000000000..66ec7d8565 --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/TermOpTransform.cpp @@ -0,0 +1,141 @@ +#include "Transform/Instruction/TermOpTransform.h" + +#include "Origin/OriginProvider.h" +#include "Transform/BlockTransform.h" +#include "Transform/Transform.h" +#include "Util/Exceptions.h" + +const std::string SOURCE_LOC = "Transform::Instruction::TermOp"; + +void llvm2col::transformTermOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + switch (llvm::Instruction::TermOps(llvmInstruction.getOpcode())) { + case llvm::Instruction::Ret: + transformRet(cast(llvmInstruction), colBlock, + funcCursor); + break; + case llvm::Instruction::Br: { + auto &llvmBranchInst = cast(llvmInstruction); + llvmBranchInst.isConditional() + ? transformConditionalBranch(llvmBranchInst, colBlock, funcCursor) + : transformUnConditionalBranch(llvmBranchInst, colBlock, + funcCursor); + break; + } + default: + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); + break; + } +} + +void llvm2col::transformRet(llvm::ReturnInst &llvmRetInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Return *returnStatement = colBlock.add_statements()->mutable_return_(); + returnStatement->set_allocated_origin( + generateSingleStatementOrigin(llvmRetInstruction)); + + col::Expr *returnExpr = returnStatement->mutable_result(); + if (llvmRetInstruction.getReturnValue() == nullptr) { + returnExpr->mutable_void_()->set_allocated_origin( + generateVoidOperandOrigin(llvmRetInstruction)); + } else { + llvm2col::transformAndSetExpr(funcCursor, llvmRetInstruction, + *llvmRetInstruction.getReturnValue(), + *returnExpr); + } +} + +void llvm2col::transformConditionalBranch(llvm::BranchInst &llvmBrInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + col::Branch *colBranch = colBlock.add_statements()->mutable_branch(); + colBranch->set_allocated_origin( + generateSingleStatementOrigin(llvmBrInstruction)); + // pre-declare completion because the final branch statement is already + // present + funcCursor.complete(colBlock); + // true branch + col::Tuple2_VctColAstExpr_VctColAstStatement *colTrueBranch = + colBranch->add_branches(); + // set conditional + transformAndSetExpr(funcCursor, llvmBrInstruction, + *llvmBrInstruction.getCondition(), + *colTrueBranch->mutable_v1()); + // get or pre-generate target labeled block + /* + * I hear you think, why query the 2nd operand? wouldn't that be the false + * branch i.e the else branch? While any logical implementation of getting + * operands would give the operands in order, the branch instruction is no + * ordinary instruction. For you see to get the branch argument we use the + * 0th index (so far so good), for the true evaluation of the branch + * instruction we use the 2nd index (uhhh okay, we might be skipping an + * index?) and the false evaluation of the branch instruction we use the 1st + * index (WHAT!?!?) + * + * Visualized: + * br i1 %var, label %yay, label %nay + * 0 2 1 + * + * Just smile and wave, don't question LLVM. + */ + auto *llvmTrueBlock = + cast(llvmBrInstruction.getOperand(2)); + // transform llvm true block + transformLLVMBlock(*llvmTrueBlock, funcCursor); + pallas::LabeledColBlock labeledTrueColBlock = + funcCursor.getOrSetLLVMBlock2LabeledColBlockEntry(*llvmTrueBlock); + // goto statement to true block + col::Goto *trueGoto = colTrueBranch->mutable_v2()->mutable_goto_(); + trueGoto->mutable_lbl()->set_id(labeledTrueColBlock.label.decl().id()); + // set origin for goto to true block + trueGoto->set_allocated_origin( + generateSingleStatementOrigin(llvmBrInstruction)); + + // false branch + col::Tuple2_VctColAstExpr_VctColAstStatement *colFalseBranch = + colBranch->add_branches(); + // set conditional (which is a true constant as else == else if(true))) + col::BooleanValue *elseCondition = + colFalseBranch->mutable_v1()->mutable_boolean_value(); + elseCondition->set_value(true); + // set origin of else condition + elseCondition->set_allocated_origin(generateOperandOrigin( + llvmBrInstruction, *llvmBrInstruction.getCondition())); + // get llvm block targeted by the llvm branch + auto *llvmFalseBlock = + cast(llvmBrInstruction.getOperand(1)); + // transform llvm falseBlock + transformLLVMBlock(*llvmFalseBlock, funcCursor); + // get or pre-generate target labeled block + pallas::LabeledColBlock labeledFalseColBlock = + funcCursor.getOrSetLLVMBlock2LabeledColBlockEntry(*llvmFalseBlock); + // goto statement to false block + col::Goto *falseGoto = colFalseBranch->mutable_v2()->mutable_goto_(); + falseGoto->mutable_lbl()->set_id(labeledFalseColBlock.label.decl().id()); + // set origin for goto to false block + falseGoto->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(llvmBrInstruction)); +} + +void llvm2col::transformUnConditionalBranch( + llvm::BranchInst &llvmBrInstruction, col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + // get llvm target block + auto *llvmTargetBlock = + cast(llvmBrInstruction.getOperand(0)); + // transform llvm targetBlock + transformLLVMBlock(*llvmTargetBlock, funcCursor); + // get or pre generate target labeled block + pallas::LabeledColBlock labeledColBlock = + funcCursor.getOrSetLLVMBlock2LabeledColBlockEntry(*llvmTargetBlock); + // create goto to target labeled block + col::Goto *colGoto = colBlock.add_statements()->mutable_goto_(); + colGoto->mutable_lbl()->set_id(labeledColBlock.label.decl().id()); + // set origin of goto statement + colGoto->set_allocated_origin( + llvm2col::generateSingleStatementOrigin(llvmBrInstruction)); + // pre-declare completion because the final goto is already present + funcCursor.complete(colBlock); +} diff --git a/src/llvm/lib/Transform/Instruction/UnaryOpTransform.cpp b/src/llvm/lib/Transform/Instruction/UnaryOpTransform.cpp new file mode 100644 index 0000000000..a3e25de8a7 --- /dev/null +++ b/src/llvm/lib/Transform/Instruction/UnaryOpTransform.cpp @@ -0,0 +1,10 @@ +#include "Transform/Instruction/UnaryOpTransform.h" +#include "Transform/BlockTransform.h" + +const std::string SOURCE_LOC = "Transform::Instruction::UnaryOp"; +void llvm2col::transformUnaryOp(llvm::Instruction &llvmInstruction, + col::Block &colBlock, + pallas::FunctionCursor &funcCursor) { + // TODO stub + reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); +} diff --git a/src/llvm/lib/Transform/Transform.cpp b/src/llvm/lib/Transform/Transform.cpp new file mode 100644 index 0000000000..c908cc9b91 --- /dev/null +++ b/src/llvm/lib/Transform/Transform.cpp @@ -0,0 +1,306 @@ +#include "Transform/Transform.h" + +#include +#include + +#include "Origin/OriginProvider.h" +#include "Passes/Function/FunctionBodyTransformer.h" +#include "Util/Exceptions.h" + +/** + * Utility function that converts LLVM types to col types + * @param type + */ +const std::string SOURCE_LOC = "Transform::Transform"; + +namespace col = vct::col::ast; + +void llvm2col::transformAndSetPointerType(llvm::Type &llvmType, + col::Type &colType) { + col::LlvmtPointer *pointerType = colType.mutable_llvmt_pointer(); + pointerType->set_allocated_origin(generateTypeOrigin(llvmType)); + llvm2col::transformAndSetType(llvmType, *pointerType->mutable_inner_type()); +} + +void llvm2col::transformAndSetType(llvm::Type &llvmType, col::Type &colType) { + switch (llvmType.getTypeID()) { + case llvm::Type::IntegerTyID: + if (llvmType.getIntegerBitWidth() == 1) { + colType.mutable_t_bool()->set_allocated_origin( + generateTypeOrigin(llvmType)); + } else { + col::LlvmtInt *colInt = colType.mutable_llvmt_int(); + colInt->set_bit_width(llvmType.getIntegerBitWidth()); + colInt->set_allocated_origin(generateTypeOrigin(llvmType)); + } + break; + case llvm::Type::VoidTyID: + colType.mutable_t_void()->set_allocated_origin( + generateTypeOrigin(llvmType)); + break; + case llvm::Type::PointerTyID: + colType.mutable_llvmt_pointer()->set_allocated_origin( + generateTypeOrigin(llvmType)); + break; + case llvm::Type::MetadataTyID: + colType.mutable_llvmt_metadata()->set_allocated_origin( + generateTypeOrigin(llvmType)); + break; + case llvm::Type::StructTyID: { + llvm::StructType &structType = llvm::cast(llvmType); + col::LlvmtStruct *colStruct = colType.mutable_llvmt_struct(); + colStruct->set_allocated_origin(generateTypeOrigin(llvmType)); + if (!structType.isLiteral()) { + // TODO: Instead of storing the name do we want keep only a single + // instance of the col::LLVMTStruct per non-literal struct type? + // XXX: This name can be the empty string for unnamed types, and it + // won't be set for literal types + colStruct->set_name(structType.getName().str()); + } + colStruct->set_packed(structType.isPacked()); + for (llvm::Type *element : structType.elements()) { + llvm2col::transformAndSetType(*element, *colStruct->add_elements()); + } + break; + } + case llvm::Type::ArrayTyID: { + llvm::ArrayType &arrayType = llvm::cast(llvmType); + col::LlvmtArray *colArray = colType.mutable_llvmt_array(); + colArray->set_allocated_origin(generateTypeOrigin(llvmType)); + llvm2col::transformAndSetType(*arrayType.getElementType(), + *colArray->mutable_element_type()); + colArray->set_num_elements(arrayType.getNumElements()); + break; + } + case llvm::Type::FixedVectorTyID: + case llvm::Type::ScalableVectorTyID: { + llvm::VectorType &vectorType = llvm::cast(llvmType); + col::LlvmtVector *colVector = colType.mutable_llvmt_vector(); + colVector->set_allocated_origin(generateTypeOrigin(llvmType)); + llvm2col::transformAndSetType(*vectorType.getElementType(), + *colVector->mutable_element_type()); + colVector->set_num_elements( + vectorType.getElementCount().getKnownMinValue()); + break; + } + + default: + throw pallas::UnsupportedTypeException(llvmType); + } +} + +void llvm2col::transformAndSetExpr(pallas::FunctionCursor &functionCursor, + llvm::Instruction &llvmInstruction, + llvm::Value &llvmOperand, + col::Expr &colExpr) { + col::Origin *origin = generateOperandOrigin(llvmInstruction, llvmOperand); + if (llvm::isa(llvmOperand)) { + transformAndSetConstExpr( + functionCursor.getFunctionAnalysisManager(), origin, + llvm::cast(llvmOperand), colExpr); + } else { + transformAndSetVarExpr(functionCursor, origin, + llvmInstruction.getOpcode() == + llvm::Instruction::PHI, + llvmOperand, colExpr); + } +} + +void llvm2col::transformAndSetVarExpr(pallas::FunctionCursor &functionCursor, + col::Origin *origin, bool inPhiNode, + llvm::Value &llvmOperand, + col::Expr &colExpr) { + col::Variable colVar = + functionCursor.getVariableMapEntry(llvmOperand, inPhiNode); + col::Local *colLocal = colExpr.mutable_local(); + colLocal->set_allocated_origin(origin); + colLocal->mutable_ref()->set_id(colVar.id()); +} + +void llvm2col::transformAndSetConstExpr(llvm::FunctionAnalysisManager &FAM, + col::Origin *origin, + llvm::Constant &llvmConstant, + col::Expr &colExpr) { + if (llvm::isa(llvmConstant)) { + col::LlvmZeroedAggregateValue *colZero = + colExpr.mutable_llvm_zeroed_aggregate_value(); + + colZero->set_allocated_origin(origin); + llvm2col::transformAndSetType(*llvmConstant.getType(), + *colZero->mutable_aggregate_type()); + return; + } + llvm::Type *constType = llvmConstant.getType(); + switch (llvmConstant.getType()->getTypeID()) { + case llvm::Type::IntegerTyID: + if (constType->getIntegerBitWidth() == 1) { + col::BooleanValue *boolValue = colExpr.mutable_boolean_value(); + boolValue->set_allocated_origin(origin); + boolValue->set_value(llvmConstant.isOneValue()); + } else { + col::LlvmIntegerValue *integerValue = + colExpr.mutable_llvm_integer_value(); + integerValue->set_allocated_origin(origin); + llvm::APInt apInt = llvmConstant.getUniqueInteger(); + transformAndSetBigInt(apInt, *integerValue->mutable_value()); + col::LlvmtInt *colInt = + integerValue->mutable_integer_type()->mutable_llvmt_int(); + colInt->set_bit_width(constType->getIntegerBitWidth()); + colInt->set_allocated_origin(generateTypeOrigin(*constType)); + } + break; + case llvm::Type::PointerTyID: { + // Can't be a function since we caught that in transformAndSetExpr + llvm::Value *stripped = llvmConstant.stripPointerCastsAndAliases(); + if (llvm::isa(stripped)) { + col::LlvmFunctionPointerValue *funcPointer = + colExpr.mutable_llvm_function_pointer_value(); + funcPointer->set_allocated_origin(origin); + funcPointer->mutable_value()->set_id( + FAM.getResult( + llvm::cast(*stripped)) + .getAssociatedColFuncDef() + .id()); + } else if (llvm::isa(stripped)) { + // XXX: To avoid having a map of GlobalVariables to their COL nodes + // we break with the convention and use the memory location of the + // LLVM value instead of the memory location of the COL node as the + // id + auto id = reinterpret_cast(stripped); + col::LlvmPointerValue *pointer = + colExpr.mutable_llvm_pointer_value(); + pointer->set_allocated_origin(origin); + pointer->mutable_value()->set_id(id); + } else if (llvm::isa(stripped)) { + col::Null *pointer = colExpr.mutable_null(); + pointer->set_allocated_origin(origin); + } else { + std::string errCtx; + llvm::raw_string_ostream(errCtx) << llvmConstant; + std::stringstream errorStream; + errorStream << "Unknown constant pointer '" << errCtx << "' " + << llvm::isa(stripped) << ", " + << llvm::isa(stripped) << ", " + << llvm::isa(stripped) << ", " + << llvm::isa(stripped) << ", " + << llvm::isa(stripped) << ", " + << llvm::isa(stripped); + pallas::ErrorReporter::addError( + SOURCE_LOC, errorStream.str(), + llvm2col::extractShortPosition(*origin)); + } + break; + } + case llvm::Type::StructTyID: { + llvm::ConstantStruct &llvmStruct = + llvm::cast(llvmConstant); + col::LlvmStructValue *colStruct = colExpr.mutable_llvm_struct_value(); + + for (auto &operand : llvmStruct.operands()) { + llvm2col::transformAndSetConstExpr( + FAM, llvm2col::deepenOperandOrigin(*origin, *operand.get()), + llvm::cast(*operand.get()), + *colStruct->add_value()); + } + colStruct->set_allocated_origin(origin); + llvm2col::transformAndSetType(*llvmStruct.getType(), + *colStruct->mutable_struct_type()); + + break; + } + case llvm::Type::ArrayTyID: { + if (llvm::isa(llvmConstant)) { + llvm::ConstantArray &llvmArray = + llvm::cast(llvmConstant); + col::LlvmArrayValue *colArray = colExpr.mutable_llvm_array_value(); + + for (auto &operand : llvmArray.operands()) { + llvm2col::transformAndSetConstExpr( + FAM, llvm2col::deepenOperandOrigin(*origin, *operand.get()), + llvm::cast(*operand.get()), + *colArray->add_value()); + } + colArray->set_allocated_origin(origin); + llvm2col::transformAndSetType(*llvmArray.getType(), + *colArray->mutable_array_type()); + } else { + llvm::ConstantDataArray &llvmArray = + llvm::cast(llvmConstant); + col::LlvmRawArrayValue *colArray = + colExpr.mutable_llvm_raw_array_value(); + + // TODO: This is not a very useful format. Ideally we detect the + // type and get elements individually as integers or floats or + // something + colArray->set_value(llvmArray.getRawDataValues().str()); + colArray->set_allocated_origin(origin); + llvm::errs() << "Array constant " << llvmArray << " has type " + << *llvmArray.getType() << "\n"; + llvm2col::transformAndSetType(*llvmArray.getType(), + *colArray->mutable_array_type()); + } + + break; + } + case llvm::Type::FixedVectorTyID: { + if (llvm::isa(llvmConstant)) { + llvm::ConstantVector &llvmVector = + llvm::cast(llvmConstant); + col::LlvmVectorValue *colVector = + colExpr.mutable_llvm_vector_value(); + + for (auto &operand : llvmVector.operands()) { + llvm2col::transformAndSetConstExpr( + FAM, llvm2col::deepenOperandOrigin(*origin, *operand.get()), + llvm::cast(*operand.get()), + *colVector->add_value()); + } + colVector->set_allocated_origin(origin); + llvm2col::transformAndSetType(*llvmVector.getType(), + *colVector->mutable_vector_type()); + } else { + llvm::ConstantDataVector &llvmVector = + llvm::cast(llvmConstant); + col::LlvmRawVectorValue *colVector = + colExpr.mutable_llvm_raw_vector_value(); + + // TODO: This is not a very useful format. Ideally we detect the + // type and get elements individually as integers or floats or + // something + colVector->set_value(llvmVector.getRawDataValues().str()); + colVector->set_allocated_origin(origin); + llvm2col::transformAndSetType(*llvmVector.getType(), + *colVector->mutable_vector_type()); + } + + break; + } + default: + std::string errCtx; + llvm::raw_string_ostream(errCtx) << llvmConstant; + std::stringstream errorStream; + errorStream << "Unknown constant '" << errCtx << "' of type '" + << constType->getTypeID() << "'"; + pallas::ErrorReporter::addError( + SOURCE_LOC, errorStream.str(), + llvm2col::extractShortPosition(*origin)); + } +} + +void llvm2col::transformAndSetBigInt(llvm::APInt &apInt, col::BigInt &bigInt) { + // TODO works for "small" signed and unsigned numbers, may break for values + // >=2^64 + llvm::APInt byteSwapped = apInt.byteSwap(); + std::vector byteVector; + for (uint32_t i = 0; i < byteSwapped.getNumWords(); i++) { + byteVector.push_back(byteSwapped.getRawData()[i]); + } + bigInt.set_data(byteVector.data(), apInt.getBitWidth() / 8); +} + +std::string llvm2col::getValueName(llvm::Value &llvmValue) { + std::string name; + llvm::raw_string_ostream contextStream = llvm::raw_string_ostream(name); + llvmValue.printAsOperand(contextStream, false); + return name; +} diff --git a/src/llvm/lib/Util/Exceptions.cpp b/src/llvm/lib/Util/Exceptions.cpp new file mode 100644 index 0000000000..9b14d2e251 --- /dev/null +++ b/src/llvm/lib/Util/Exceptions.cpp @@ -0,0 +1,109 @@ +#include "Util/Exceptions.h" +#include "Origin/ShortPositionDeriver.h" + +#include +#include +#include +#include + +namespace pallas { +UnsupportedTypeException::UnsupportedTypeException(const llvm::Type &type) { + llvm::raw_string_ostream output(str); + output << "Type '" << type << "' not supported"; +} + +[[nodiscard]] const char *UnsupportedTypeException::what() const noexcept { + return str.c_str(); +} + +u_int32_t ErrorReporter::errorCount; +u_int32_t ErrorReporter::warningCount; + +void ErrorReporter::addError(const std::string &source, + const std::string &message) { + llvm::errs() << "[ERROR] [pallas] [" << source << "] " << message << "\n\n"; + ErrorReporter::errorCount++; +} + +void ErrorReporter::addError(const std::string &source, + const std::string &message, + const std::string &origin) { + llvm::errs() << "[ERROR] [pallas] [" << source << "] " << message + << " @\n " << origin << "\n\n"; + ErrorReporter::errorCount++; +} + +void ErrorReporter::addError(const std::string &source, + const std::string &message, + llvm::Module &llvmModule) { + addError(source, message, llvm2col::deriveModuleShortPosition(llvmModule)); +} + +void ErrorReporter::addError(const std::string &source, + const std::string &message, + llvm::Function &llvmFunction) { + addError(source, message, + llvm2col::deriveFunctionShortPosition(llvmFunction)); +} + +void ErrorReporter::addError(const std::string &source, + const std::string &message, + llvm::BasicBlock &llvmBlock) { + addError(source, message, llvm2col::deriveBlockShortPosition(llvmBlock)); +} + +void ErrorReporter::addError(const std::string &source, + const std::string &message, + llvm::Instruction &llvmInstruction) { + addError(source, message, + llvm2col::deriveInstructionShortPosition(llvmInstruction)); +} + +void ErrorReporter::addWarning(const std::string &source, + const std::string &message) { + llvm::errs() << "[WARN] [pallas] [" << source << "] " << message << "\n\n"; + ErrorReporter::warningCount++; +} + +void ErrorReporter::addWarning(const std::string &source, + const std::string &message, + const std::string &origin) { + llvm::errs() << "[WARN] [pallas] [" << source << "] " << message << " @\n " + << origin << "\n\n"; + ErrorReporter::warningCount++; +} + +void ErrorReporter::addWarning(const std::string &source, + const std::string &message, + llvm::Module &llvmModule) { + addWarning(source, message, + llvm2col::deriveModuleShortPosition(llvmModule)); +} + +void ErrorReporter::addWarning(const std::string &source, + const std::string &message, + llvm::Function &llvmFunction) { + addWarning(source, message, + llvm2col::deriveFunctionShortPosition(llvmFunction)); +} + +void ErrorReporter::addWarning(const std::string &source, + const std::string &message, + llvm::BasicBlock &llvmBlock) { + addWarning(source, message, llvm2col::deriveBlockShortPosition(llvmBlock)); +} + +void ErrorReporter::addWarning(const std::string &source, + const std::string &message, + llvm::Instruction &llvmInstruction) { + addWarning(source, message, + llvm2col::deriveInstructionShortPosition(llvmInstruction)); +} + +bool ErrorReporter::hasErrors() { return ErrorReporter::errorCount > 0; } + +u_int32_t ErrorReporter::getErrorCount() { return ErrorReporter::errorCount; } +u_int32_t ErrorReporter::getWarningCount() { + return ErrorReporter::warningCount; +} +} // namespace pallas diff --git a/src/llvm/lib/origin/ContextDeriver.cpp b/src/llvm/lib/origin/ContextDeriver.cpp deleted file mode 100644 index c731ba9348..0000000000 --- a/src/llvm/lib/origin/ContextDeriver.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "Origin/ContextDeriver.h" - -#include -#include - -namespace llvm2Col { - // module derivers - std::string deriveModuleContext(llvm::Module &llvmModule) { - std::string context; - llvm::raw_string_ostream(context) << llvmModule; - return context; - } - - // function derivers - std::string deriveFunctionContext(llvm::Function &llvmFunction) { - std::string context; - llvm::raw_string_ostream(context) << llvmFunction; - return context; - } - - // block derivers - - std::string deriveLabelContext(llvm::BasicBlock &llvmBlock) { - if (llvmBlock.isEntryBlock()) { - return ""; - } - std::string fullContext; - llvm::raw_string_ostream(fullContext) << llvmBlock; - return fullContext.substr(0, fullContext.find(':') + 1); - } - - std::string deriveBlockContext(llvm::BasicBlock &llvmBlock) { - std::string context; - llvm::raw_string_ostream(context) << llvmBlock; - return context; - } - - // instruction derivers - - std::string deriveSurroundingInstructionContext(llvm::Instruction &llvmInstruction) { - std::string context; - if (llvmInstruction.getPrevNode() != nullptr) { - llvm::raw_string_ostream(context) << *llvmInstruction.getPrevNode() << '\n'; - } - llvm::raw_string_ostream(context) << llvmInstruction; - if (llvmInstruction.getNextNode() != nullptr) { - llvm::raw_string_ostream(context) << '\n' << *llvmInstruction.getNextNode(); - } - return context; - } - - std::string deriveInstructionContext(llvm::Instruction &llvmInstruction) { - std::string context; - llvm::raw_string_ostream(context) << llvmInstruction; - return context; - } - - std::string deriveInstructionLhs(llvm::Instruction &llvmInstruction) { - std::string fullContext = deriveInstructionContext(llvmInstruction); - return fullContext.substr(0, fullContext.find('=')); - } - - std::string deriveInstructionRhs(llvm::Instruction &llvmInstruction) { - std::string fullContext = deriveInstructionContext(llvmInstruction); - return fullContext.substr(fullContext.find('=') + 1); - } - - std::string deriveOperandContext(llvm::Value &llvmOperand) { - std::string context; - llvm::raw_string_ostream contextStream = llvm::raw_string_ostream(context); - llvmOperand.printAsOperand(contextStream, false); - return context; - } -} \ No newline at end of file diff --git a/src/llvm/lib/origin/OriginProvider.cpp b/src/llvm/lib/origin/OriginProvider.cpp deleted file mode 100644 index 248967860a..0000000000 --- a/src/llvm/lib/origin/OriginProvider.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "Origin/OriginProvider.h" - -#include - -#include "Origin/PreferredNameDeriver.h" -#include "Origin/ContextDeriver.h" -#include "Origin/ShortPositionDeriver.h" - -namespace llvm2Col { - col::Origin *generateProgramOrigin(llvm::Module &llvmModule) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name("program:" + llvmModule.getName().str()); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveModuleContext(llvmModule)); - context->set_inline_context(deriveModuleContext(llvmModule)); - context->set_short_position(deriveModuleShortPosition(llvmModule)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateFuncDefOrigin(llvm::Function &llvmFunction) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name(llvmFunction.getName().str()); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveFunctionContext(llvmFunction)); - context->set_inline_context(deriveFunctionContext(llvmFunction)); - context->set_short_position(deriveFunctionShortPosition(llvmFunction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateFunctionContractOrigin(llvm::Function &llvmFunction, const std::string& contract) { - col::Origin *origin = new col::Origin(); - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(contract); - context->set_inline_context(contract); - context->set_short_position(deriveFunctionShortPosition(llvmFunction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateGlobalValOrigin(llvm::Module &llvmModule, const std::string &globVal) { - col::Origin *origin = new col::Origin(); - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(globVal); - context->set_inline_context(globVal); - context->set_short_position(deriveModuleShortPosition(llvmModule)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateArgumentOrigin(llvm::Argument &llvmArgument) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name(deriveArgumentPreferredName(llvmArgument)); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveFunctionContext(*llvmArgument.getParent())); - context->set_inline_context(deriveFunctionContext(*llvmArgument.getParent())); - context->set_short_position(deriveFunctionShortPosition(*llvmArgument.getParent())); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateBlockOrigin(llvm::BasicBlock &llvmBlock) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name("block"); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveBlockContext(llvmBlock)); - context->set_inline_context(deriveBlockContext(llvmBlock)); - context->set_short_position(deriveBlockShortPosition(llvmBlock)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateLabelOrigin(llvm::BasicBlock &llvmBlock) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name("label"); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveLabelContext(llvmBlock)); - context->set_inline_context(deriveLabelContext(llvmBlock)); - context->set_short_position(deriveBlockShortPosition(llvmBlock)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateSingleStatementOrigin(llvm::Instruction &llvmInstruction) { - col::Origin *origin = new col::Origin(); - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveSurroundingInstructionContext(llvmInstruction)); - context->set_inline_context(deriveInstructionContext(llvmInstruction)); - context->set_short_position(deriveInstructionShortPosition(llvmInstruction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateAssignTargetOrigin(llvm::Instruction &llvmInstruction) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name("var"); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveInstructionContext(llvmInstruction)); - context->set_inline_context(deriveInstructionLhs(llvmInstruction)); - context->set_short_position(deriveInstructionShortPosition(llvmInstruction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateBinExprOrigin(llvm::Instruction &llvmInstruction) { - col::Origin *origin = new col::Origin(); - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveSurroundingInstructionContext(llvmInstruction)); - context->set_inline_context(deriveInstructionContext(llvmInstruction)); - context->set_short_position(deriveInstructionShortPosition(llvmInstruction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateFunctionCallOrigin(llvm::CallInst &callInstruction) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name(callInstruction.getCalledFunction()->getName().str()); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveSurroundingInstructionContext(callInstruction)); - context->set_inline_context(deriveInstructionRhs(callInstruction)); - context->set_short_position(deriveInstructionShortPosition(callInstruction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateOperandOrigin(llvm::Instruction &llvmInstruction, llvm::Value &llvmOperand) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name(deriveOperandPreferredName(llvmOperand)); - preferredNameContent->set_allocated_preferred_name(preferredName); - - col::OriginContent *contextContent = origin->add_content(); - col::Context *context = new col::Context(); - context->set_context(deriveInstructionContext(llvmInstruction)); - context->set_inline_context(deriveOperandContext(llvmOperand)); - context->set_short_position(deriveInstructionShortPosition(llvmInstruction)); - contextContent->set_allocated_context(context); - - origin->CheckInitialized(); - return origin; - } - - col::Origin *generateTypeOrigin(llvm::Type &llvmType) { - col::Origin *origin = new col::Origin(); - col::OriginContent *preferredNameContent = origin->add_content(); - col::PreferredName *preferredName = new col::PreferredName(); - preferredName->add_preferred_name(deriveTypePreferredName(llvmType)); - preferredNameContent->set_allocated_preferred_name(preferredName); - - origin->CheckInitialized(); - return origin; - } -} diff --git a/src/llvm/lib/origin/PreferredNameDeriver.cpp b/src/llvm/lib/origin/PreferredNameDeriver.cpp deleted file mode 100644 index 94717208f5..0000000000 --- a/src/llvm/lib/origin/PreferredNameDeriver.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "Origin/PreferredNameDeriver.h" - -#include -#include -#include - -namespace llvm2Col { - std::string deriveOperandPreferredName(llvm::Value &llvmOperand) { - std::string preferredName; - llvm::raw_string_ostream preferredNameStream = llvm::raw_string_ostream(preferredName); - preferredNameStream << (llvm::isa(llvmOperand) ? "const_" : "var_"); - llvmOperand.printAsOperand(preferredNameStream, false); - return preferredName; - } - - std::string deriveTypePreferredName(llvm::Type &llvmType) { - std::string prefix = "t_"; - switch(llvmType.getTypeID()) { - case llvm::Type::HalfTyID: - return prefix + "half"; - case llvm::Type::BFloatTyID: - return prefix + "bfloat"; - case llvm::Type::FloatTyID: - return prefix + "float"; - case llvm::Type::DoubleTyID: - return prefix + "double"; - case llvm::Type::X86_FP80TyID: - return prefix + "x86fp80"; - case llvm::Type::FP128TyID: - return prefix + "fp128"; - case llvm::Type::PPC_FP128TyID: - return prefix + "ppcfp128"; - case llvm::Type::VoidTyID: - return prefix + "void"; - case llvm::Type::LabelTyID: - return prefix + "label"; - case llvm::Type::MetadataTyID: - return prefix + "metadata"; - case llvm::Type::X86_MMXTyID: - return prefix + "x86mmx"; - case llvm::Type::X86_AMXTyID: - return prefix + "x86amx"; - case llvm::Type::TokenTyID: - return prefix + "token"; - case llvm::Type::IntegerTyID: - return prefix + (llvmType.getIntegerBitWidth() == 1 ? "boolean" : "integer"); - case llvm::Type::FunctionTyID: - return prefix + "function"; - case llvm::Type::PointerTyID: - return prefix + "ptr"; - case llvm::Type::StructTyID: - return prefix + "struct"; - case llvm::Type::ArrayTyID: - return prefix + "array"; - case llvm::Type::FixedVectorTyID: - return prefix + "fixedvector"; - case llvm::Type::ScalableVectorTyID: - return prefix + "scalevector"; - } - } - std::string deriveArgumentPreferredName(llvm::Argument &llvmArgument) { - std::string preferredName; - llvm::raw_string_ostream preferredNameStream = llvm::raw_string_ostream(preferredName); - preferredNameStream << "arg_"; - llvmArgument.printAsOperand(preferredNameStream, false); - return preferredName; - } - -} \ No newline at end of file diff --git a/src/llvm/lib/origin/ShortPositionDeriver.cpp b/src/llvm/lib/origin/ShortPositionDeriver.cpp deleted file mode 100644 index 5438d15886..0000000000 --- a/src/llvm/lib/origin/ShortPositionDeriver.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "Origin/ShortPositionDeriver.h" -#include "Origin/ContextDeriver.h" - -namespace llvm2Col { - const std::string POSITION_POINTER = "\n\t -> "; - - std::string deriveModuleShortPosition(llvm::Module &llvmModule) { - return "file " + llvmModule.getSourceFileName(); - } - - std::string deriveFunctionShortPosition(llvm::Function &llvmFunction) { - std::string functionPosition = deriveModuleShortPosition(*llvmFunction.getParent()); - llvm::raw_string_ostream functionPosStream = llvm::raw_string_ostream(functionPosition); - functionPosStream << POSITION_POINTER << "function "; - llvmFunction.printAsOperand(functionPosStream, false); - return functionPosition; - } - - std::string deriveBlockShortPosition(llvm::BasicBlock &llvmBlock) { - std::string blockPosition = deriveFunctionShortPosition(*llvmBlock.getParent()); - llvm::raw_string_ostream blockPosStream = llvm::raw_string_ostream(blockPosition); - blockPosStream << POSITION_POINTER << "block "; - llvmBlock.printAsOperand(blockPosStream, false); - blockPosStream << (llvmBlock.isEntryBlock() ? " (entryblock)" : ""); - return blockPosition; - } - - std::string deriveInstructionShortPosition(llvm::Instruction &llvmInstruction) { - std::string instructionPosition = deriveBlockShortPosition(*llvmInstruction.getParent()); - llvm::raw_string_ostream instructionPosStream = llvm::raw_string_ostream(instructionPosition); - int pos = 0; - llvm::BasicBlock *bb = llvmInstruction.getParent(); - for (auto &I: *bb) { - pos++; - if (&I == &llvmInstruction) { - break; - } - } - instructionPosStream << POSITION_POINTER << "instruction #" << pos << " (" - << deriveInstructionContext(llvmInstruction) << ')'; - return instructionPosition; - } -} \ No newline at end of file diff --git a/src/llvm/lib/passes/Function/FunctionBodyTransformer.cpp b/src/llvm/lib/passes/Function/FunctionBodyTransformer.cpp deleted file mode 100644 index 3b27a2394c..0000000000 --- a/src/llvm/lib/passes/Function/FunctionBodyTransformer.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "Passes/Function/FunctionBodyTransformer.h" -#include "Passes/Function/FunctionContractDeclarer.h" -#include - -#include "Passes/Function/FunctionDeclarer.h" -#include "Transform/BlockTransform.h" -#include "Transform/Transform.h" -#include "Origin/OriginProvider.h" -#include "Util/Exceptions.h" - - -namespace vcllvm { - const std::string SOURCE_LOC = "Passes::Function::FunctionBodyTransformer"; - - FunctionCursor::FunctionCursor(col::Scope &functionScope, - col::Block &functionBody, - llvm::Function &llvmFunction, - llvm::FunctionAnalysisManager &FAM) : - functionScope(functionScope), functionBody(functionBody), llvmFunction(llvmFunction), FAM(FAM) {} - - const col::Scope &FunctionCursor::getFunctionScope() { - return functionScope; - } - - void FunctionCursor::addVariableMapEntry(Value &llvmValue, col::Variable &colVar) { - variableMap.insert({&llvmValue, &colVar}); - // add reference to reference lut of function contract - col::Tuple2_String_Ref_VctColAstVariable *ref = FAM.getResult(llvmFunction).getAssociatedColFuncContract().add_variable_refs(); - ref->set_v1(llvm2Col::getValueName(llvmValue)); - ref->mutable_v2()->set_id(colVar.id()); - } - - col::Variable &FunctionCursor::getVariableMapEntry(Value &llvmValue) { - return *variableMap.at(&llvmValue); - } - - bool FunctionCursor::isVisited(BasicBlock &llvmBlock) { - return llvmBlock2LabeledColBlock.contains(&llvmBlock); - } - - void FunctionCursor::complete(col::Block &colBlock) { - completedColBlocks.insert(&colBlock); - } - bool FunctionCursor::isComplete(col::Block &colBlock) { - return completedColBlocks.contains(&colBlock); - } - - LabeledColBlock &FunctionCursor::getOrSetLlvmBlock2LabeledColBlockEntry(BasicBlock &llvmBlock) { - if (!llvmBlock2LabeledColBlock.contains(&llvmBlock)) { - // create label in buffer - col::Label *label = functionBody.add_statements()->mutable_label(); - // set label origin - label->set_allocated_origin(llvm2Col::generateLabelOrigin(llvmBlock)); - // create label declaration in buffer - col::LabelDecl *labelDecl = label->mutable_decl(); - // set label decl origin - labelDecl->set_allocated_origin(llvm2Col::generateLabelOrigin(llvmBlock)); - // set label decl id - llvm2Col::setColNodeId(labelDecl); - // create block inside label statement - col::Block *block = label->mutable_stat()->mutable_block(); - // set block origin - block->set_allocated_origin(llvm2Col::generateBlockOrigin(llvmBlock)); - // add labeled block to the block2block lut - LabeledColBlock labeledColBlock = {*label, *block}; - llvmBlock2LabeledColBlock.insert({&llvmBlock, labeledColBlock}); - } - return llvmBlock2LabeledColBlock.at(&llvmBlock); - } - - LoopInfo &FunctionCursor::getLoopInfo() { - return FAM.getResult(llvmFunction); - } - - LoopInfo &FunctionCursor::getLoopInfo(Function &otherLlvmFunction) { - return FAM.getResult(otherLlvmFunction); - } - - FDResult &FunctionCursor::getFDResult() { - return FAM.getResult(llvmFunction); - } - - FDResult &FunctionCursor::getFDResult(Function &otherLlvmFunction) { - return FAM.getResult(otherLlvmFunction); - } - - col::Variable &FunctionCursor::declareVariable(Instruction &llvmInstruction) { - // create declaration in buffer - col::Variable *varDecl = functionScope.add_locals(); - // set type of declaration - try { - llvm2Col::transformAndSetType(*llvmInstruction.getType(), *varDecl->mutable_t()); - } catch (vcllvm::UnsupportedTypeException &e) { - std::stringstream errorStream; - errorStream << e.what() << " in variable declaration."; - ErrorReporter::addError(SOURCE_LOC, errorStream.str(), llvmInstruction); - } - // set id - llvm2Col::setColNodeId(varDecl); - // set origin - varDecl->set_allocated_origin(llvm2Col::generateSingleStatementOrigin(llvmInstruction)); - // add to the variable lut - this->addVariableMapEntry(llvmInstruction, *varDecl); - return *varDecl; - } - - col::Assign &FunctionCursor::createAssignmentAndDeclaration(Instruction &llvmInstruction, col::Block &colBlock) { - col::Variable &varDecl = declareVariable(llvmInstruction); - return createAssignment(llvmInstruction, colBlock, varDecl); - } - - col::Assign &FunctionCursor::createAssignment(Instruction &llvmInstruction, - col::Block &colBlock, - col::Variable &varDecl) { - col::Assign *assignment = colBlock.add_statements()->mutable_assign(); - assignment->set_allocated_origin(llvm2Col::generateSingleStatementOrigin(llvmInstruction)); - assignment->set_allocated_blame(new col::Blame()); - // create local target in buffer and set origin - col::Local *colLocal = assignment->mutable_target()->mutable_local(); - colLocal->set_allocated_origin(llvm2Col::generateAssignTargetOrigin(llvmInstruction)); - // set target to refer to var decl - colLocal->mutable_ref()->set_id(varDecl.id()); - if(isComplete(colBlock)) { - // if the colBlock is completed, the assignment will be inserted after the goto/branch statement - // this can occur due to e.g. phi nodes back tracking assignments in their origin blocks. - // therefore we need to swap the last two elements of the block - // (i.e. the goto statement and the newest assignment) - int lastIndex = colBlock.statements_size() - 1; - colBlock.mutable_statements()->SwapElements(lastIndex, lastIndex - 1); - } - return *assignment; - } - - FunctionBodyTransformerPass::FunctionBodyTransformerPass(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - PreservedAnalyses FunctionBodyTransformerPass::run(Function &F, FunctionAnalysisManager &FAM) { - ColScopedFuncBody scopedFuncBody = FAM.getResult(F).getAssociatedScopedColFuncBody(); - FunctionCursor funcCursor = FunctionCursor(*scopedFuncBody.scope, *scopedFuncBody.block, F, FAM); - // add function arguments to the variableMap - for (auto &A: F.args()) { - funcCursor.addVariableMapEntry(A, FAM.getResult(F).getFuncArgMapEntry(A)); - } - // start recursive block code gen with basic block - llvm::BasicBlock &entryBlock = F.getEntryBlock(); - llvm2Col::transformLlvmBlock(entryBlock, funcCursor); - return PreservedAnalyses::all(); - } -} diff --git a/src/llvm/lib/passes/Function/FunctionContractDeclarer.cpp b/src/llvm/lib/passes/Function/FunctionContractDeclarer.cpp deleted file mode 100644 index 1e03aa54ce..0000000000 --- a/src/llvm/lib/passes/Function/FunctionContractDeclarer.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "Passes/Function/FunctionContractDeclarer.h" -#include - -#include "Passes/Function/FunctionDeclarer.h" -#include "Util/Constants.h" -#include "Util/Exceptions.h" -#include "Origin/OriginProvider.h" - - -namespace vcllvm { - const std::string SOURCE_LOC = "Passes::Function::FunctionContractDeclarer"; - - using namespace llvm; - - /* - * Function Contract Declarer Result - */ - - FDCResult::FDCResult(vct::col::ast::LlvmFunctionContract &colFuncContract) : - associatedColFuncContract(colFuncContract) {} - - col::LlvmFunctionContract &FDCResult::getAssociatedColFuncContract() { - return associatedColFuncContract; - } - - /* - * Function Contract Declarer (Analysis) - */ - - AnalysisKey FunctionContractDeclarer::Key; - - - FunctionContractDeclarer::FunctionContractDeclarer(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - FunctionContractDeclarer::Result FunctionContractDeclarer::run(Function &F, FunctionAnalysisManager &FAM) { - // fetch relevant function from the Function Declarer - FDResult fdResult = FAM.getResult(F); - col::LlvmFunctionDefinition &colFunction = fdResult.getAssociatedColFuncDef(); - // set a contract in the buffer as well as make and return a result object - return FDCResult(*colFunction.mutable_contract()); - } - - /* - * Function Contract Declarer Pass - */ - - FunctionContractDeclarerPass::FunctionContractDeclarerPass(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - PreservedAnalyses FunctionContractDeclarerPass::run(Function &F, FunctionAnalysisManager &FAM) { - // get col contract - FDCResult result = FAM.getResult(F); - col::LlvmFunctionContract &colContract = result.getAssociatedColFuncContract(); - colContract.set_allocated_blame(new col::Blame()); - // check if contract keyword is present - if (!F.hasMetadata(vcllvm::constants::METADATA_CONTRACT_KEYWORD)) { - // set contract to a tautology - colContract.set_value("requires true;"); - colContract.set_allocated_origin(new col::Origin()); - return PreservedAnalyses::all(); - } - // concatenate all contract lines with new lines - MDNode *contractMDNode = F.getMetadata(vcllvm::constants::METADATA_CONTRACT_KEYWORD); - std::stringstream contractStream; - for (u_int32_t i = 0; i < contractMDNode->getNumOperands(); i++) { - auto contractLine = dyn_cast(contractMDNode->getOperand(i)); - if (contractLine == nullptr) { - std::stringstream errorStream; - errorStream << "Unable to cast contract metadata node #" << i + 1 << "to string type"; - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); - break; - } - contractStream << contractLine->getString().str() << '\n'; - } - colContract.set_value(contractStream.str()); - colContract.set_allocated_origin(llvm2Col::generateFunctionContractOrigin(F, contractStream.str())); - // add all callable functions to the contracts invokables - for(auto &moduleF : F.getParent()->functions()) { - std::string fName = '@' + moduleF.getName().str(); - int64_t fId = FAM.getResult(moduleF).getFunctionId(); - col::Tuple2_String_Ref_VctColAstLlvmCallable *invokeRef = colContract.add_invokable_refs(); - invokeRef->set_v1(fName); - invokeRef->mutable_v2()->set_id(fId); - invokeRef->CheckInitialized(); - } - colContract.CheckInitialized(); - return PreservedAnalyses::all(); - } -} diff --git a/src/llvm/lib/passes/Function/FunctionDeclarer.cpp b/src/llvm/lib/passes/Function/FunctionDeclarer.cpp deleted file mode 100644 index 82173404a6..0000000000 --- a/src/llvm/lib/passes/Function/FunctionDeclarer.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include "Passes/Function/FunctionDeclarer.h" - -#include "Transform/Transform.h" -#include "Origin/OriginProvider.h" -#include "Util/Exceptions.h" - - -namespace vcllvm { - const std::string SOURCE_LOC = "Passes::Function::FunctionDeclarer"; - using namespace llvm; - - /** - * Checks function definition for unsupported features that might change semantics and - * adds warning if this is the case. - * @param llvmFunction: the function to be checked - */ - void checkFunctionSupport(llvm::Function &llvmFunction) { - // TODO add syntax support checks that change the semantics of the program to function definitions - // TODO see: https://releases.llvm.org/15.0.0/docs/LangRef.html#functions - } - - /* - * Function Declarer Result - */ - - FDResult::FDResult(col::LlvmFunctionDefinition &colFuncDef, - ColScopedFuncBody associatedScopedColFuncBody, - int64_t functionId) : - associatedColFuncDef(colFuncDef), - associatedScopedColFuncBody(associatedScopedColFuncBody), - functionId(functionId) {} - - col::LlvmFunctionDefinition &FDResult::getAssociatedColFuncDef() { - return associatedColFuncDef; - } - - ColScopedFuncBody FDResult::getAssociatedScopedColFuncBody() { - return associatedScopedColFuncBody; - } - - void FDResult::addFuncArgMapEntry(Argument &llvmArg, col::Variable &colArg) { - funcArgMap.insert({&llvmArg, &colArg}); - } - - col::Variable &FDResult::getFuncArgMapEntry(Argument &arg) { - return *funcArgMap.at(&arg); - } - - int64_t &FDResult::getFunctionId() { - return functionId; - } - - - /* - * Function Declarer (Analysis) - */ - AnalysisKey FunctionDeclarer::Key; - - FunctionDeclarer::FunctionDeclarer(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - FDResult FunctionDeclarer::run(Function &F, FunctionAnalysisManager &FAM) { - checkFunctionSupport(F); - // create llvmFuncDef declaration in buffer - col::GlobalDeclaration *llvmFuncDefDecl = pProgram->add_declarations(); - // generate id - col::LlvmFunctionDefinition *llvmFuncDef = llvmFuncDefDecl->mutable_llvm_function_definition(); - int64_t functionId = llvm2Col::setColNodeId(llvmFuncDef); - // add body block + scope + origin - // set origin - llvmFuncDef->set_allocated_origin(llvm2Col::generateFuncDefOrigin(F)); - llvmFuncDef->set_allocated_blame(new col::Blame()); - ColScopedFuncBody funcScopedBody{}; - funcScopedBody.scope = llvmFuncDef->mutable_function_body()->mutable_scope(); - funcScopedBody.scope->set_allocated_origin(llvm2Col::generateFuncDefOrigin(F)); - funcScopedBody.block = funcScopedBody.scope->mutable_body()->mutable_block(); - funcScopedBody.block->set_allocated_origin(llvm2Col::generateFuncDefOrigin(F)); - FDResult result = FDResult(*llvmFuncDef, funcScopedBody, functionId); - // set args (if present) - for (llvm::Argument &llvmArg: F.args()) { - // set in buffer - col::Variable *colArg = llvmFuncDef->add_args(); - // set origin - colArg->set_allocated_origin(llvm2Col::generateArgumentOrigin(llvmArg)); - llvm2Col::setColNodeId(colArg); - try { - llvm2Col::transformAndSetType(*llvmArg.getType(), *colArg->mutable_t()); - } catch (vcllvm::UnsupportedTypeException &e) { - std::stringstream errorStream; - errorStream << e.what() << " in argument #" << llvmArg.getArgNo(); - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); - } - // add args mapping to result - result.addFuncArgMapEntry(llvmArg, *colArg); - } - return result; - } - - /* - * Function Declarer Pass - */ - FunctionDeclarerPass::FunctionDeclarerPass(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - PreservedAnalyses FunctionDeclarerPass::run(Function &F, FunctionAnalysisManager &FAM) { - FDResult result = FAM.getResult(F); - col::LlvmFunctionDefinition &colFunction = result.getAssociatedColFuncDef(); - // complete the function declaration in proto buffer - // set return type in protobuf of function - try { - llvm2Col::transformAndSetType(*F.getReturnType(), *colFunction.mutable_return_type()); - } catch (vcllvm::UnsupportedTypeException &e) { - std::stringstream errorStream; - errorStream << e.what() << " in return signature"; - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); - } - return PreservedAnalyses::all(); - } -} diff --git a/src/llvm/lib/passes/Function/PureAssigner.cpp b/src/llvm/lib/passes/Function/PureAssigner.cpp deleted file mode 100644 index a4378dfc56..0000000000 --- a/src/llvm/lib/passes/Function/PureAssigner.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Passes/Function/PureAssigner.h" - -#include "Passes/Function/FunctionDeclarer.h" -#include "Util/Constants.h" -#include "Util/Exceptions.h" - -namespace vcllvm { - const std::string SOURCE_LOC = "Passes::Function::PureAssigner"; - - using namespace llvm; - - PureAssignerPass::PureAssignerPass(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - PreservedAnalyses PureAssignerPass::run(Function &F, FunctionAnalysisManager &FAM) { - std::ostringstream errorStream; - FDResult result = FAM.getResult(F); - col::LlvmFunctionDefinition &colFunction = result.getAssociatedColFuncDef(); - // check if pure keyword is present, else assume unpure function - if (!F.hasMetadata(vcllvm::constants::METADATA_PURE_KEYWORD)) { - colFunction.set_pure(false); - return PreservedAnalyses::all(); - } - // check if the 'pure' metadata has only 1 operand, else exit with error - MDNode *pureMDNode = F.getMetadata(vcllvm::constants::METADATA_PURE_KEYWORD); - if (pureMDNode->getNumOperands() != 1) { - errorStream << "Expected 1 argument but got " << pureMDNode->getNumOperands(); - reportError(F, errorStream.str()); - return PreservedAnalyses::all(); - } - // check if the only operand is of type 'i1', else exit with error - auto *pureMDValue = cast(pureMDNode->getOperand(0)); - if (!pureMDValue->getType()->isIntegerTy(1)) { - errorStream << "MD node type must be of type \"i1\""; - reportError(F, errorStream.str()); - return PreservedAnalyses::all(); - } - // attempt down cast to ConstantInt (which shouldn't fail given previous checks) - bool purity = cast(pureMDValue)->getValue()->isOneValue(); - colFunction.set_pure(purity); - return PreservedAnalyses::all(); - } - - void reportError(Function &F, const std::string &explanation) { - std::stringstream errorStream; - errorStream << "Malformed Metadata node of type \"" << vcllvm::constants::METADATA_PURE_KEYWORD - << "\":" << explanation; - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), F); - } -} \ No newline at end of file diff --git a/src/llvm/lib/passes/Module/ModuleSpecCollector.cpp b/src/llvm/lib/passes/Module/ModuleSpecCollector.cpp deleted file mode 100644 index b523972560..0000000000 --- a/src/llvm/lib/passes/Module/ModuleSpecCollector.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Passes/Module/ModuleSpecCollector.h" -#include -#include "Util/Constants.h" -#include "Util/Exceptions.h" -#include "Origin/OriginProvider.h" -#include "Transform/Transform.h" - -namespace vcllvm { - const std::string SOURCE_LOC = "Passes::Module::GlobalSpecCollector"; - - using namespace llvm; - - ModuleSpecCollectorPass::ModuleSpecCollectorPass(std::shared_ptr pProgram) : - pProgram(std::move(pProgram)) {} - - PreservedAnalyses ModuleSpecCollectorPass::run(Module &M, ModuleAnalysisManager &MAM) { - NamedMDNode *globalMDNode = M.getNamedMetadata(vcllvm::constants::METADATA_GLOBAL_KEYWORD); - if(globalMDNode == nullptr) { - return PreservedAnalyses::all(); - } - for (u_int32_t i = 0; i < globalMDNode->getNumOperands(); i++) { - for (u_int32_t j = 0; j < globalMDNode->getOperand(i)->getNumOperands(); j++) { - auto globVal = dyn_cast(globalMDNode->getOperand(i)->getOperand(j)); - if (globVal == nullptr) { - std::stringstream errorStream; - errorStream << "Unable to cast global metadata node #" << i + 1 << "to string type"; - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), M); - break; - } - col::GlobalDeclaration *globDecl = pProgram->add_declarations(); - col::LlvmGlobal *colGlobal = globDecl->mutable_llvm_global(); - llvm2Col::setColNodeId(colGlobal); - colGlobal->set_value(globVal->getString().str()); - colGlobal->set_allocated_origin(llvm2Col::generateGlobalValOrigin(M, globVal->getString().str())); - } - } - return PreservedAnalyses::all(); - } - -} \ No newline at end of file diff --git a/src/llvm/lib/transform/BlockTransform.cpp b/src/llvm/lib/transform/BlockTransform.cpp deleted file mode 100644 index d0cf7564da..0000000000 --- a/src/llvm/lib/transform/BlockTransform.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "Transform/BlockTransform.h" - -#include "Transform/Instruction/TermOpTransform.h" -#include "Transform/Instruction/BinaryOpTransform.h" -#include "Transform/Instruction/UnaryOpTransform.h" -#include "Transform/Instruction/MemoryOpTransform.h" -#include "Transform/Instruction/FuncletPadOpTransform.h" -#include "Transform/Instruction/OtherOpTransform.h" -#include "Util/Exceptions.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::BlockTransform"; - - void transformLlvmBlock(llvm::BasicBlock &llvmBlock, vcllvm::FunctionCursor &functionCursor) { - col::Block &colBlock = functionCursor.getOrSetLlvmBlock2LabeledColBlockEntry(llvmBlock).block; - for (auto *B: llvm::predecessors(&llvmBlock)) { - if (!functionCursor.isVisited(*B)) return; - } - if (functionCursor.getLoopInfo().isLoopHeader(&llvmBlock)) { - transformLoop(llvmBlock, functionCursor); - return; - } - for (auto &I: llvmBlock) { - transformInstruction(functionCursor, I, colBlock); - } - functionCursor.complete(colBlock); - } - - void transformInstruction(vcllvm::FunctionCursor &funcCursor, - llvm::Instruction &llvmInstruction, - col::Block &colBodyBlock) { - u_int32_t opCode = llvmInstruction.getOpcode(); - if (llvm::Instruction::TermOpsBegin <= opCode && opCode < llvm::Instruction::TermOpsEnd) { - llvm2Col::transformTermOp(llvmInstruction, colBodyBlock, funcCursor); - } else if (llvm::Instruction::BinaryOpsBegin <= opCode && opCode < llvm::Instruction::BinaryOpsEnd) { - llvm2Col::transformBinaryOp(llvmInstruction, colBodyBlock, funcCursor); - } else if (llvm::Instruction::UnaryOpsBegin <= opCode && opCode < llvm::Instruction::UnaryOpsEnd) { - llvm2Col::transformUnaryOp(llvmInstruction, colBodyBlock, funcCursor); - } else if (llvm::Instruction::MemoryOpsBegin <= opCode && opCode < llvm::Instruction::MemoryOpsEnd) { - llvm2Col::transformMemoryOp(llvmInstruction, colBodyBlock, funcCursor); - } else if (llvm::Instruction::FuncletPadOpsBegin <= opCode && opCode < llvm::Instruction::FuncletPadOpsEnd) { - llvm2Col::transformFuncletPadOp(llvmInstruction, colBodyBlock, funcCursor); - } else if (llvm::Instruction::OtherOpsBegin <= opCode && opCode < llvm::Instruction::OtherOpsEnd) { - llvm2Col::transformOtherOp(llvmInstruction, colBodyBlock, funcCursor); - } else { - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } - } - - void transformLoop(llvm::BasicBlock &llvmBlock, vcllvm::FunctionCursor &functionCursor) { - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Unsupported loop detected", llvmBlock); - } - - void reportUnsupportedOperatorError(const std::string &source, llvm::Instruction &llvmInstruction) { - std::stringstream errorStream; - errorStream << "Unsupported operator \"" << llvmInstruction.getOpcodeName() << '"'; - vcllvm::ErrorReporter::addError(source, errorStream.str(), llvmInstruction); - } -} diff --git a/src/llvm/lib/transform/Instruction/BinaryOpTransform.cpp b/src/llvm/lib/transform/Instruction/BinaryOpTransform.cpp deleted file mode 100644 index ac9684dc57..0000000000 --- a/src/llvm/lib/transform/Instruction/BinaryOpTransform.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "Transform/Instruction/BinaryOpTransform.h" - - -#include "Transform/Transform.h" -#include "Transform/BlockTransform.h" -#include "Origin/OriginProvider.h" -#include "Util/Exceptions.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::BinaryOp"; - - void transformBinaryOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - col::Assign &assignment = funcCursor.createAssignmentAndDeclaration(llvmInstruction, colBlock); - switch (llvm::Instruction::BinaryOps(llvmInstruction.getOpcode())) { - case llvm::Instruction::Add: { - col::Plus &expr = *assignment.mutable_value()->mutable_plus(); - transformBinExpr(llvmInstruction, expr, funcCursor); - break; - } - case llvm::Instruction::Sub: { - col::Minus &expr = *assignment.mutable_value()->mutable_minus(); - transformBinExpr(llvmInstruction, expr, funcCursor); - break; - } - case llvm::Instruction::Mul: { - col::Mult &expr = *assignment.mutable_value()->mutable_mult(); - transformBinExpr(llvmInstruction, expr, funcCursor); - break; - } - case llvm::Instruction::SDiv: - case llvm::Instruction::UDiv: { - if(llvmInstruction.isExact()) { - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Exact division not supported", llvmInstruction); - } - col::FloorDiv &expr = *assignment.mutable_value()->mutable_floor_div(); - expr.set_allocated_blame(new col::Blame()); - transformBinExpr(llvmInstruction, expr, funcCursor); - break; - } - default: - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } - } -} diff --git a/src/llvm/lib/transform/Instruction/CastOpTransform.cpp b/src/llvm/lib/transform/Instruction/CastOpTransform.cpp deleted file mode 100644 index 60d4cae7c9..0000000000 --- a/src/llvm/lib/transform/Instruction/CastOpTransform.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Transform/Instruction/CastOpTransform.h" - -#include "Transform/BlockTransform.h" -#include "Util/Exceptions.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::CastOp"; - void convertCastOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - //TODO stub - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } -} \ No newline at end of file diff --git a/src/llvm/lib/transform/Instruction/FuncletPadOpTransform.cpp b/src/llvm/lib/transform/Instruction/FuncletPadOpTransform.cpp deleted file mode 100644 index bc0ebf77ef..0000000000 --- a/src/llvm/lib/transform/Instruction/FuncletPadOpTransform.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Transform/Instruction/FuncletPadOpTransform.h" - -#include "Transform/BlockTransform.h" -#include "Util/Exceptions.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::FuncletPadOp"; - - void transformFuncletPadOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - //TODO stub - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } -} \ No newline at end of file diff --git a/src/llvm/lib/transform/Instruction/MemoryOpTransform.cpp b/src/llvm/lib/transform/Instruction/MemoryOpTransform.cpp deleted file mode 100644 index d4d9f64a68..0000000000 --- a/src/llvm/lib/transform/Instruction/MemoryOpTransform.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Transform/Instruction/MemoryOpTransform.h" - -#include "Transform/BlockTransform.h" -#include "Util/Exceptions.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::MemoryOp"; - - void transformMemoryOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - //TODO stub - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } -} \ No newline at end of file diff --git a/src/llvm/lib/transform/Instruction/OtherOpTransform.cpp b/src/llvm/lib/transform/Instruction/OtherOpTransform.cpp deleted file mode 100644 index a07112ff48..0000000000 --- a/src/llvm/lib/transform/Instruction/OtherOpTransform.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include -#include "Transform/Instruction/OtherOpTransform.h" - -#include "Transform/BlockTransform.h" -#include "Transform/Transform.h" -#include "Util/Exceptions.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::OtherOp"; - - void transformOtherOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - switch (llvm::Instruction::OtherOps(llvmInstruction.getOpcode())) { - case llvm::Instruction::PHI: - transformPhi(llvm::cast(llvmInstruction), funcCursor); - break; - case llvm::Instruction::ICmp: - transformICmp(llvm::cast(llvmInstruction), colBlock, funcCursor); - break; - case llvm::Instruction::Call: - transformCallExpr(llvm::cast(llvmInstruction), colBlock, funcCursor); - break; - default: - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } - } - - void transformPhi(llvm::PHINode &phiInstruction, - vcllvm::FunctionCursor &funcCursor) { - col::Variable &varDecl = funcCursor.declareVariable(phiInstruction); - for (auto &B: phiInstruction.blocks()) { - // add assignment of the variable to target block - col::Block &targetBlock = funcCursor.getOrSetLlvmBlock2LabeledColBlockEntry(*B).block; - col::Assign &assignment = funcCursor.createAssignment(phiInstruction, targetBlock, varDecl); - // assign correct value by looking at the value-block pair of phi instruction. - col::Expr *value = assignment.mutable_value(); - llvm2Col::transformAndSetExpr(funcCursor, phiInstruction, - *phiInstruction.getIncomingValueForBlock(B), *value); - } - } - - void transformICmp(llvm::ICmpInst &icmpInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - // we only support integer comparison - if (not icmpInstruction.getOperand(0)->getType()->isIntegerTy()) { - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Unsupported compare type", icmpInstruction); - return; - } - col::Assign &assignment = funcCursor.createAssignmentAndDeclaration(icmpInstruction, colBlock); - switch (llvm::ICmpInst::Predicate(icmpInstruction.getPredicate())) { - case llvm::CmpInst::ICMP_EQ: { - col::Eq &eq = *assignment.mutable_value()->mutable_eq(); - transformCmpExpr(icmpInstruction, eq, funcCursor); - break; - } - case llvm::CmpInst::ICMP_NE: { - col::Neq &neq = *assignment.mutable_value()->mutable_neq(); - transformCmpExpr(icmpInstruction, neq, funcCursor); - break; - } - case llvm::CmpInst::ICMP_SGT: - case llvm::CmpInst::ICMP_UGT: { - col::Greater > = *assignment.mutable_value()->mutable_greater(); - transformCmpExpr(icmpInstruction, gt, funcCursor); - break; - } - case llvm::CmpInst::ICMP_SGE: - case llvm::CmpInst::ICMP_UGE: { - col::GreaterEq &geq = *assignment.mutable_value()->mutable_greater_eq(); - transformCmpExpr(icmpInstruction, geq, funcCursor); - break; - } - case llvm::CmpInst::ICMP_SLT: - case llvm::CmpInst::ICMP_ULT: { - col::Less < = *assignment.mutable_value()->mutable_less(); - transformCmpExpr(icmpInstruction, lt, funcCursor); - break; - } - case llvm::CmpInst::ICMP_SLE: - case llvm::CmpInst::ICMP_ULE: { - col::LessEq &leq = *assignment.mutable_value()->mutable_less_eq(); - transformCmpExpr(icmpInstruction, leq, funcCursor); - break; - } - default: - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Unknown ICMP predicate", icmpInstruction); - } - } - - void transformCmpExpr(llvm::CmpInst &cmpInstruction, - auto &colCompareExpr, - vcllvm::FunctionCursor &funcCursor) { - transformBinExpr(cmpInstruction, colCompareExpr, funcCursor); - } - - void checkCallSupport(llvm::CallInst &callInstruction) { - // tail recursion - if (callInstruction.isMustTailCall() || callInstruction.isNoTailCall()) { - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Tail call optimization not supported", callInstruction); - } - // fast math - if (callInstruction.getFastMathFlags().any()) { - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Fast math not supported", callInstruction); - } - // return attributes - for (auto &A: callInstruction.getAttributes().getRetAttrs()) { - std::stringstream errorStream; - errorStream << "Return attribute \"" << A.getAsString() << "\" not supported"; - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), callInstruction); - } - // address space is platform dependent (unlikely to change semantics) - // function attributes are just extra compiler information (no semanatic changes) - - // operand bundles - if (callInstruction.hasOperandBundles()) { - vcllvm::ErrorReporter::addError(SOURCE_LOC, "Operand bundles not supported", callInstruction); - } - } - - void transformCallExpr(llvm::CallInst &callInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - checkCallSupport(callInstruction); - // allocate expression to host the function call in advance - col::Expr *functionCallExpr; - // if void function add an eval expression - if (callInstruction.getType()->isVoidTy()) { - col::Eval *eval = colBlock.add_statements()->mutable_eval(); - eval->set_allocated_origin(llvm2Col::generateSingleStatementOrigin(callInstruction)); - functionCallExpr = eval->mutable_expr(); - } else { // else create an assignment - col::Assign &assignment = funcCursor.createAssignmentAndDeclaration(callInstruction, colBlock); - functionCallExpr = assignment.mutable_value(); - } - // create actual invocation - col::LlvmFunctionInvocation *invocation = functionCallExpr->mutable_llvm_function_invocation(); - // set origin - invocation->set_allocated_origin(llvm2Col::generateFunctionCallOrigin(callInstruction)); - invocation->set_allocated_blame(new col::Blame()); - // set function reference - invocation->mutable_ref()->set_id( - funcCursor.getFDResult(*callInstruction.getCalledFunction()).getFunctionId() - ); - // process function arguments - for (auto &A: callInstruction.args()) { - llvm2Col::transformAndSetExpr(funcCursor, callInstruction, *A, *invocation->add_args()); - } - } -} diff --git a/src/llvm/lib/transform/Instruction/TermOpTransform.cpp b/src/llvm/lib/transform/Instruction/TermOpTransform.cpp deleted file mode 100644 index 752885052f..0000000000 --- a/src/llvm/lib/transform/Instruction/TermOpTransform.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "Transform/Instruction/TermOpTransform.h" - -#include "Transform/Transform.h" -#include "Transform/BlockTransform.h" -#include "Util/Exceptions.h" -#include "Origin/OriginProvider.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::TermOp"; - - - void transformTermOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - switch (llvm::Instruction::TermOps(llvmInstruction.getOpcode())) { - case llvm::Instruction::Ret: - transformRet(cast(llvmInstruction), colBlock, funcCursor); - break; - case llvm::Instruction::Br: { - auto &llvmBranchInst = cast(llvmInstruction); - llvmBranchInst.isConditional() ? transformConditionalBranch(llvmBranchInst, colBlock, funcCursor) - : transformUnConditionalBranch(llvmBranchInst, colBlock, funcCursor); - break; - } - default: - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - break; - } - } - - void transformRet(llvm::ReturnInst &llvmRetInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - col::Return *returnStatement = colBlock.add_statements()->mutable_return_(); - returnStatement->set_allocated_origin(generateSingleStatementOrigin(llvmRetInstruction)); - col::Expr *returnExpr = returnStatement->mutable_result(); - llvm2Col::transformAndSetExpr( - funcCursor, - llvmRetInstruction, - *llvmRetInstruction.getReturnValue(), - *returnExpr); - } - - void transformConditionalBranch(llvm::BranchInst &llvmBrInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - col::Branch *colBranch = colBlock.add_statements()->mutable_branch(); - colBranch->set_allocated_origin(generateSingleStatementOrigin(llvmBrInstruction)); - // pre-declare completion because the final branch statement is already present - funcCursor.complete(colBlock); - // true branch - col::Tuple2_VctColAstExpr_VctColAstStatement *colTrueBranch = colBranch->add_branches(); - // set conditional - transformAndSetExpr(funcCursor, - llvmBrInstruction, - *llvmBrInstruction.getCondition(), - *colTrueBranch->mutable_v1()); - // get or pre-generate target labeled block - /* - * I hear you think, why query the 2nd operand? wouldn't that be the false branch i.e the else branch? - * While any logical implementation of getting operands would give the operands in order, the branch instruction - * is no ordinary instruction. For you see to get the branch argument we use the 0th index (so far so good), for the true evaluation - * of the branch instruction we use the 2nd index (uhhh okay, we might be skipping an index?) and the false evaluation of the - * branch instruction we use the 1st index (WHAT!?!?) - * - * Visualized: - * br i1 %var, label %yay, label %nay - * 0 2 1 - * - * Just smile and wave, don't question LLVM. - */ - auto *llvmTrueBlock = cast(llvmBrInstruction.getOperand(2)); - vcllvm::LabeledColBlock labeledTrueColBlock = funcCursor.getOrSetLlvmBlock2LabeledColBlockEntry(*llvmTrueBlock); - // goto statement to true block - col::Goto *trueGoto = colTrueBranch->mutable_v2()->mutable_goto_(); - trueGoto->mutable_lbl()->set_id(labeledTrueColBlock.label.decl().id()); - // set origin for goto to true block - trueGoto->set_allocated_origin(generateSingleStatementOrigin(llvmBrInstruction)); - // transform llvm true block - transformLlvmBlock(*llvmTrueBlock, funcCursor); - - // false branch - col::Tuple2_VctColAstExpr_VctColAstStatement *colFalseBranch = colBranch->add_branches(); - // set conditional (which is a true constant as else == else if(true))) - col::BooleanValue *elseCondition = colFalseBranch->mutable_v1()->mutable_boolean_value(); - elseCondition->set_value(true); - // set origin of else condition - elseCondition->set_allocated_origin(generateOperandOrigin(llvmBrInstruction, *llvmBrInstruction.getCondition())); - // get llvm block targeted by the llvm branch - auto *llvmFalseBlock = cast(llvmBrInstruction.getOperand(1)); - // get or pre-generate target labeled block - vcllvm::LabeledColBlock labeledFalseColBlock = funcCursor.getOrSetLlvmBlock2LabeledColBlockEntry( - *llvmFalseBlock); - // goto statement to false block - col::Goto *falseGoto = colFalseBranch->mutable_v2()->mutable_goto_(); - falseGoto->mutable_lbl()->set_id(labeledFalseColBlock.label.decl().id()); - // set origin for goto to false block - falseGoto->set_allocated_origin(llvm2Col::generateSingleStatementOrigin(llvmBrInstruction)); - // transform llvm falseBlock - transformLlvmBlock(*llvmFalseBlock, funcCursor); - } - - void transformUnConditionalBranch(llvm::BranchInst &llvmBrInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - // get llvm target block - auto *llvmTargetBlock = cast(llvmBrInstruction.getOperand(0)); - // get or pre generate target labeled block - vcllvm::LabeledColBlock labeledColBlock = funcCursor.getOrSetLlvmBlock2LabeledColBlockEntry(*llvmTargetBlock); - // create goto to target labeled block - col::Goto *colGoto = colBlock.add_statements()->mutable_goto_(); - colGoto->mutable_lbl()->set_id(labeledColBlock.label.decl().id()); - // set origin of goto statement - colGoto->set_allocated_origin(llvm2Col::generateSingleStatementOrigin(llvmBrInstruction)); - // pre-declare completion because the final goto is already present - funcCursor.complete(colBlock); - // transform llvm targetBlock - transformLlvmBlock(*llvmTargetBlock, funcCursor); - } -} \ No newline at end of file diff --git a/src/llvm/lib/transform/Instruction/UnaryOpTransform.cpp b/src/llvm/lib/transform/Instruction/UnaryOpTransform.cpp deleted file mode 100644 index 321819bfd3..0000000000 --- a/src/llvm/lib/transform/Instruction/UnaryOpTransform.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "Transform/Instruction/UnaryOpTransform.h" -#include "Transform/BlockTransform.h" - -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Instruction::UnaryOp"; - void transformUnaryOp(llvm::Instruction &llvmInstruction, - col::Block &colBlock, - vcllvm::FunctionCursor &funcCursor) { - //TODO stub - reportUnsupportedOperatorError(SOURCE_LOC, llvmInstruction); - } -} \ No newline at end of file diff --git a/src/llvm/lib/transform/Transform.cpp b/src/llvm/lib/transform/Transform.cpp deleted file mode 100644 index e1ceb0817d..0000000000 --- a/src/llvm/lib/transform/Transform.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "Passes/Function/FunctionBodyTransformer.h" -#include "Transform/Transform.h" - -#include -#include - -#include "Util/Exceptions.h" -#include "Origin/OriginProvider.h" - - - - -/** - * Utility function that converts LLVM types to col types - * @param type - */ -namespace llvm2Col { - const std::string SOURCE_LOC = "Transform::Transform"; - - namespace col = vct::col::ast; - - void transformAndSetType(llvm::Type &llvmType, - col::Type &colType) { - switch (llvmType.getTypeID()) { - case llvm::Type::IntegerTyID: - if (llvmType.getIntegerBitWidth() == 1) { - colType.mutable_t_bool()->set_allocated_origin(generateTypeOrigin(llvmType)); - } else { - colType.mutable_t_int()->set_allocated_origin(generateTypeOrigin(llvmType)); - } - break; - default: - throw vcllvm::UnsupportedTypeException(); - } - } - - - void transformAndSetExpr(vcllvm::FunctionCursor &functionCursor, - llvm::Instruction &llvmInstruction, - llvm::Value &llvmOperand, - col::Expr &colExpr) { - if (llvm::isa(llvmOperand)) { - transformAndSetConstExpr(llvmInstruction, llvm::cast(llvmOperand), colExpr); - } else { - transformAndSetVarExpr(functionCursor, llvmInstruction, llvmOperand, colExpr); - } - } - - void transformAndSetVarExpr(vcllvm::FunctionCursor &functionCursor, - llvm::Instruction &llvmInstruction, - llvm::Value &llvmOperand, - col::Expr &colExpr) { - col::Variable colVar = functionCursor.getVariableMapEntry(llvmOperand); - col::Local *colLocal = colExpr.mutable_local(); - colLocal->set_allocated_origin(generateOperandOrigin(llvmInstruction, llvmOperand)); - colLocal->mutable_ref()->set_id(colVar.id()); - } - - void transformAndSetConstExpr(llvm::Instruction &llvmInstruction, - llvm::Constant &llvmConstant, - col::Expr &colExpr) { - llvm::Type *constType = llvmConstant.getType(); - switch (llvmConstant.getType()->getTypeID()) { - case llvm::Type::IntegerTyID: - if (constType->getIntegerBitWidth() == 1) { - col::BooleanValue *boolValue = colExpr.mutable_boolean_value(); - boolValue->set_allocated_origin(generateOperandOrigin(llvmInstruction, llvmConstant)); - boolValue->set_value(llvmConstant.isOneValue()); - } else { - col::IntegerValue *integerValue = colExpr.mutable_integer_value(); - integerValue->set_allocated_origin(generateOperandOrigin(llvmInstruction, llvmConstant)); - llvm::APInt apInt = llvmConstant.getUniqueInteger(); - transformAndSetIntegerValue(apInt, *integerValue); - } - break; - default: - std::string errCtx; - llvm::raw_string_ostream(errCtx) << llvmConstant; - std::stringstream errorStream; - errorStream << "Unknown constant \"" << errCtx << '\"'; - vcllvm::ErrorReporter::addError(SOURCE_LOC, errorStream.str(), llvmInstruction); - } - } - - void transformAndSetIntegerValue(llvm::APInt &apInt, col::IntegerValue &colIntegerValue) { - // TODO works for "small" signed and unsigned numbers, may break for values >=2^64 - llvm::APInt byteSwapped = apInt.byteSwap(); - std::vector byteVector; - for (uint32_t i = 0; i < byteSwapped.getNumWords(); i++) { - byteVector.push_back(byteSwapped.getRawData()[i]); - } - colIntegerValue.mutable_value()->set_data(byteVector.data(), apInt.getBitWidth() / 8); - } - - std::string getValueName(llvm::Value &llvmValue) { - std::string name; - llvm::raw_string_ostream contextStream = llvm::raw_string_ostream(name); - llvmValue.printAsOperand(contextStream, false); - return name; - } -} \ No newline at end of file diff --git a/src/llvm/lib/util/Exceptions.cpp b/src/llvm/lib/util/Exceptions.cpp deleted file mode 100644 index 32ff59d7ac..0000000000 --- a/src/llvm/lib/util/Exceptions.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "Util/Exceptions.h" -#include "Origin/ShortPositionDeriver.h" - - -#include -#include -#include - -namespace vcllvm { - [[nodiscard]] const char *UnsupportedTypeException::what() const noexcept { - return "Type not supported"; - } - - u_int32_t ErrorReporter::errorCount; - - void ErrorReporter::addError(const std::string &source, const std::string &message, const std::string &origin) { - llvm::errs() << "[VCLLVM] [" << source << "] " << message << " @\n " << origin << "\n\n"; - ErrorReporter::errorCount++; - } - - void ErrorReporter::addError(const std::string &source, - const std::string &message, - llvm::Module &llvmModule) { - addError(source, message, llvm2Col::deriveModuleShortPosition(llvmModule)); - } - - void ErrorReporter::addError(const std::string &source, - const std::string &message, - llvm::Function &llvmFunction) { - addError(source, message, llvm2Col::deriveFunctionShortPosition(llvmFunction)); - } - - void ErrorReporter::addError(const std::string &source, - const std::string &message, - llvm::BasicBlock &llvmBlock) { - addError(source, message, llvm2Col::deriveBlockShortPosition(llvmBlock)); - } - - void ErrorReporter::addError(const std::string &source, - const std::string &message, - llvm::Instruction &llvmInstruction) { - addError(source, message, llvm2Col::deriveInstructionShortPosition(llvmInstruction)); - } - - bool ErrorReporter::hasErrors() { - return ErrorReporter::errorCount > 0; - } - - u_int32_t ErrorReporter::getErrorCount() { - return ErrorReporter::errorCount; - } -} \ No newline at end of file diff --git a/src/llvm/tools/vcllvm/VCLLVM.cpp b/src/llvm/tools/vcllvm/VCLLVM.cpp deleted file mode 100644 index af755ba71f..0000000000 --- a/src/llvm/tools/vcllvm/VCLLVM.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "vct/col/ast/col.pb.h" -#include "Passes/Function/FunctionBodyTransformer.h" -#include "Passes/Function/FunctionContractDeclarer.h" -#include "Passes/Function/PureAssigner.h" -#include "Passes/Module/ModuleSpecCollector.h" - -#include -#include -#include -#include - -#include "Passes/Function/FunctionDeclarer.h" - -#include "Transform/Transform.h" -#include "Origin/OriginProvider.h" - -#include "Util/Exceptions.h" - -#include -#include - -namespace col = vct::col::ast; - -col::Program sampleCol(bool returnBool) { - col::Program program = col::Program(); - - // class - col::GlobalDeclaration *classDeclaration = program.add_declarations(); - col::VctClass *vctClass = classDeclaration->mutable_vct_class(); - llvm2Col::setColNodeId(vctClass); - col::BooleanValue *lockInvariant = vctClass->mutable_intrinsic_lock_invariant()->mutable_boolean_value(); - lockInvariant->set_value(true); - // class>method - col::ClassDeclaration *methodDeclaration = vctClass->add_decls(); - col::InstanceMethod *method = methodDeclaration->mutable_instance_method(); - llvm2Col::setColNodeId(method); - // class>method>return_type - method->mutable_return_type()->mutable_t_bool(); - // class>method>body - col::Block *body = method->mutable_body()->mutable_scope()->mutable_body()->mutable_block(); - col::Return *returnStatement = body->add_statements()->mutable_return_(); - col::BooleanValue *returnValue = returnStatement->mutable_result()->mutable_boolean_value(); - returnValue->set_value(returnBool); - // class>method>inline - method->set_inline_(false); - // class>method>pure - method->set_pure(false); - // class>method>contract - col::ApplicableContract *contract = method->mutable_contract(); - // class>method>contract>precondition - col::UnitAccountedPredicate *precondition = contract->mutable_requires_()->mutable_unit_accounted_predicate(); - col::BooleanValue *prePred = precondition->mutable_pred()->mutable_boolean_value(); - prePred->set_value(true); - // class>method>contract>postcondition - col::UnitAccountedPredicate *postcondition = contract->mutable_ensures()->mutable_unit_accounted_predicate(); - col::Ref *postRefResult = postcondition->mutable_pred()->mutable_result()->mutable_applicable(); - postRefResult->set_id(method->id()); - // class>method>contract>context_everywhere - col::BooleanValue *contextEverywhere = contract->mutable_context_everywhere()->mutable_boolean_value(); - contextEverywhere->set_value(true); - return program; -} - -static vcllvm::cl::opt inputFileName{"", - vcllvm::cl::desc{"Module to analyze"}, - vcllvm::cl::value_desc{"IR filename"}, - vcllvm::cl::Positional}; -static vcllvm::cl::opt testCol{"sample-col", - vcllvm::cl::desc{"Output a sample col buffer with verdict PASS"}}; - -static vcllvm::cl::opt incorrectTestCol{"sample-col-wrong", - vcllvm::cl::desc{"Output a sample col buffer with verdict FAIL"}}; - -static vcllvm::cl::opt humanReadableOutput{"human-readable", - vcllvm::cl::desc{"Output COL buffer in human readable format"}}; - -int main(int argc, char **argv) { - vcllvm::cl::ParseCommandLineOptions(argc, argv); - // sample mode - if (testCol.getValue() || incorrectTestCol.getValue()) { - std::cout << sampleCol(testCol.getValue()).SerializeAsString(); - std::cout.flush(); - return EXIT_SUCCESS; - } - // parse mode - if (inputFileName.empty()) { - vcllvm::errs() << "no input file given\n"; - return EXIT_FAILURE; - } - vcllvm::LLVMContext context; - vcllvm::SMDiagnostic smDiag; - auto pModule = parseIRFile(inputFileName, smDiag, context); - if (!pModule) { - smDiag.print(inputFileName.c_str(), vcllvm::errs()); - return EXIT_FAILURE; - } - pModule->setSourceFileName(inputFileName); - vcllvm::Module *module = pModule.release(); - auto pProgram = std::make_shared(); - // set program origin - pProgram->set_allocated_origin(llvm2Col::generateProgramOrigin(*module)); - pProgram->set_allocated_blame(new col::Blame()); - // Create the analysis managers. - vcllvm::LoopAnalysisManager LAM; - vcllvm::FunctionAnalysisManager FAM; - vcllvm::CGSCCAnalysisManager CGAM; - vcllvm::ModuleAnalysisManager MAM; - FAM.registerPass([&] { return vcllvm::FunctionDeclarer(pProgram); }); - FAM.registerPass([&] { return vcllvm::FunctionContractDeclarer(pProgram); }); - // Create the new pass manager builder. - // Take a look at the PassBuilder constructor parameters for more - // customization, e.g. specifying a TargetMachine or various debugging - // options. - vcllvm::PassBuilder PB; - // Register all the basic analyses with the managers. - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - - vcllvm::LoopPassManager LPM; - - vcllvm::FunctionPassManager FPM; - FPM.addPass(vcllvm::FunctionDeclarerPass(pProgram)); - FPM.addPass(vcllvm::PureAssignerPass(pProgram)); - FPM.addPass(vcllvm::FunctionContractDeclarerPass(pProgram)); - FPM.addPass(vcllvm::FunctionBodyTransformerPass(pProgram)); - vcllvm::ModulePassManager MPM; - MPM.addPass(vcllvm::ModuleSpecCollectorPass(pProgram)); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - MPM.run(*module, MAM); - if (vcllvm::ErrorReporter::hasErrors()) { - vcllvm::errs() << "While processing \"" << inputFileName << "\" VCLLVM has encountered " - << vcllvm::ErrorReporter::getErrorCount() << " error(s).\n" - << "Exiting with failure code...\n"; - return EXIT_FAILURE; - } - if (humanReadableOutput.getValue()) { - llvm::errs() << pProgram->DebugString(); - } else { - std::cout << pProgram->SerializeAsString(); - } - return EXIT_SUCCESS; -} diff --git a/src/main/vct/main/stages/Parsing.scala b/src/main/vct/main/stages/Parsing.scala index 3e8317ce40..77e01baaad 100644 --- a/src/main/vct/main/stages/Parsing.scala +++ b/src/main/vct/main/stages/Parsing.scala @@ -133,7 +133,7 @@ case class Parsing[G <: Generation]( case Language.SystemC => new ColSystemCParser(Resources.getSystemCConfig) case Language.LLVM => - ColLLVMParser(debugOptions, blameProvider, Resources.getVCLLVM) + ColLLVMParser(debugOptions, blameProvider, Resources.getPallas) } parser.parse[G](readable) diff --git a/src/main/vct/main/stages/Resolution.scala b/src/main/vct/main/stages/Resolution.scala index 64aa310b13..afa2ff5c63 100644 --- a/src/main/vct/main/stages/Resolution.scala +++ b/src/main/vct/main/stages/Resolution.scala @@ -9,8 +9,8 @@ import vct.col.ast.{ CGlobalDeclaration, Expr, GlobalDeclaration, - LlvmFunctionContract, - LlvmGlobal, + LLVMFunctionContract, + LLVMGlobalSpecification, Program, Refute, Verification, @@ -27,7 +27,7 @@ import vct.col.origin.{ ReadableOrigin, } import vct.col.resolve.{Resolve, ResolveReferences, ResolveTypes} -import vct.col.rewrite.Generation +import vct.col.rewrite.{Generation, Rewritten} import vct.col.rewrite.bip.IsolateBipGlue import vct.rewrite.lang.{LangSpecificToCol, LangTypesToCol} import vct.importer.JavaLibraryLoader @@ -36,7 +36,7 @@ import vct.options.Options import vct.options.types.ClassPathEntry import vct.parsers.debug.DebugOptions import vct.parsers.err.FileNotFound -import vct.parsers.parser.{ColJavaParser, ColLLVMParser} +import vct.parsers.parser.{ColJavaParser, ColLLVMContractParser, ColPVLParser} import vct.parsers.transform.BlameProvider import vct.parsers.{ParseResult, parser} import vct.resources.Resources @@ -67,6 +67,14 @@ case object Resolution { case ClassPathEntry.SourcePath(root) => ResolveTypes.JavaClassPathEntry.Path(root) }, + if (options.contractImportFile.isDefined) { + val res = ColPVLParser(options.getParserDebugOptions, blameProvider) + .parse[G]( + options.contractImportFile.get, + Origin(Seq(ReadableOrigin(options.contractImportFile.get))), + ) + res.decls + } else { Seq() }, options.veymontGeneratePermissions, options.devVeymontAllowAssign, ) @@ -84,7 +92,7 @@ case class MyLocalJavaParser( ) extends Resolve.SpecExprParser { override def parse[G](input: String, o: Origin): Expr[G] = { val sr = LiteralReadable("", input) - val cjp = parser.ColJavaParser(debugOptions, blameProvider) + val cjp = ColJavaParser(debugOptions, blameProvider) val x = cjp.parseExpr[G](sr) if (x._2.nonEmpty) { throw SpecExprParseError("...") } x._1 @@ -96,17 +104,17 @@ case class MyLocalLLVMSpecParser( debugOptions: DebugOptions, ) extends Resolve.SpecContractParser { override def parse[G]( - input: LlvmFunctionContract[G], + input: LLVMFunctionContract[G], o: Origin, ): ApplicableContract[G] = - parser.ColLLVMContractParser(debugOptions, blameProvider) + ColLLVMContractParser(debugOptions, blameProvider) .parseFunctionContract[G](new StringReader(input.value), o)._1 override def parse[G]( - input: LlvmGlobal[G], + input: LLVMGlobalSpecification[G], o: Origin, ): Seq[GlobalDeclaration[G]] = - parser.ColLLVMContractParser(debugOptions, blameProvider) + ColLLVMContractParser(debugOptions, blameProvider) .parseReader[G](new StringReader(input.value), o).decls } @@ -117,6 +125,7 @@ case class Resolution[G <: Generation]( ResolveTypes.JavaClassPathEntry.Path(Resources.getJrePath), ResolveTypes.JavaClassPathEntry.SourcePackageRoot, ), + importedDeclarations: Seq[GlobalDeclaration[G]] = Seq(), veymontGeneratePermissions: Boolean = false, veymontAllowAssign: Boolean = false, ) extends Stage[ParseResult[G], Verification[_ <: Generation]] @@ -138,17 +147,26 @@ case class Resolution[G <: Generation]( val joinedProgram = Program(isolatedBipProgram.declarations ++ extraDecls)(blameProvider()) val typedProgram = LangTypesToCol().dispatch(joinedProgram) - ResolveReferences.resolve( - typedProgram, - MyLocalJavaParser(blameProvider, parserDebugOptions), - MyLocalLLVMSpecParser(blameProvider, parserDebugOptions), - ) match { + val javaParser = MyLocalJavaParser(blameProvider, parserDebugOptions) + val llvmParser = MyLocalLLVMSpecParser(blameProvider, parserDebugOptions) + val typedImports = + if (importedDeclarations.isEmpty) { Seq() } + else { + val ast = LangTypesToCol() + .dispatch(Program(importedDeclarations)(blameProvider())) + ResolveReferences.resolve(ast, javaParser, llvmParser, Seq()) + LangSpecificToCol(veymontGeneratePermissions, veymontAllowAssign, Seq()) + .dispatch(ast).asInstanceOf[Program[Rewritten[G]]].declarations + } + ResolveReferences + .resolve(typedProgram, javaParser, llvmParser, typedImports) match { case Nil => // ok case some => throw InputResolutionError(some) } val resolvedProgram = LangSpecificToCol( veymontGeneratePermissions, veymontAllowAssign, + typedImports, ).dispatch(typedProgram) resolvedProgram.check match { case Nil => // ok diff --git a/src/main/vct/main/stages/Transformation.scala b/src/main/vct/main/stages/Transformation.scala index 36fab123a0..f49cf1cd7b 100644 --- a/src/main/vct/main/stages/Transformation.scala +++ b/src/main/vct/main/stages/Transformation.scala @@ -35,6 +35,7 @@ import vct.rewrite.{ HeapVariableToRef, MonomorphizeClass, SmtlibToProverTypes, + VariableToPointer, } import vct.rewrite.lang.ReplaceSYCLTypes import vct.rewrite.veymont.{ @@ -325,6 +326,7 @@ case class SilverTransformation( EncodeString, // Encode spec string as seq EncodeChar, CollectLocalDeclarations, // all decls in Scope + VariableToPointer, // should happen before ParBlockEncoder so it can distinguish between variables which can and can't altered in a parallel block DesugarPermissionOperators, // no PointsTo, \pointer, etc. ReadToValue, // resolve wildcard into fractional permission TrivialAddrOf, diff --git a/src/main/vct/options/Options.scala b/src/main/vct/options/Options.scala index 79e522f5e8..d5cd459ee0 100644 --- a/src/main/vct/options/Options.scala +++ b/src/main/vct/options/Options.scala @@ -295,6 +295,9 @@ case object Options { opt[Path]("path-c-preprocessor").valueName("") .action((path, c) => c.copy(cPreprocessorPath = path)) .text("Set the location of the C preprocessor binary"), + opt[PathOrStd]("contract-import-file").valueName("") + .action((path, c) => c.copy(contractImportFile = Some(path))) + .text("Load function contracts from the specified file"), note(""), note("VeyMont Mode"), opt[Unit]("veymont").action((_, c) => c.copy(mode = Mode.VeyMont)).text( @@ -448,6 +451,9 @@ case class Options( // Control flow graph options cfgOutput: Path = null, + + // Pallas options + contractImportFile: Option[PathOrStd] = None, ) { def getParserDebugOptions: vct.parsers.debug.DebugOptions = vct.parsers.debug.DebugOptions( diff --git a/src/main/vct/resources/Resources.scala b/src/main/vct/resources/Resources.scala index 86fbb5e3a3..43508dce57 100644 --- a/src/main/vct/resources/Resources.scala +++ b/src/main/vct/resources/Resources.scala @@ -16,5 +16,5 @@ case object Resources { def getCPPcPath: Path = Paths.get("clang++") def getSystemCConfig: Path = getResource("/systemc/config") def getVeymontPath: Path = getResource("/veymont") - def getVCLLVM: Path = getResource("/vcllvm") + def getPallas: Path = getResource("/pallas") } diff --git a/src/parsers/antlr4/LangPVLLexer.g4 b/src/parsers/antlr4/LangPVLLexer.g4 index 4bd41d3d30..f6ddf942ee 100644 --- a/src/parsers/antlr4/LangPVLLexer.g4 +++ b/src/parsers/antlr4/LangPVLLexer.g4 @@ -45,6 +45,7 @@ PERCENT: '%'; INC: '++'; DEC: '--'; CONS: '::'; +AMPERSAND: '&'; ENUM: 'enum'; CLASS: 'class'; diff --git a/src/parsers/antlr4/LangPVLParser.g4 b/src/parsers/antlr4/LangPVLParser.g4 index cbf9a06ae2..b72c0e47b3 100644 --- a/src/parsers/antlr4/LangPVLParser.g4 +++ b/src/parsers/antlr4/LangPVLParser.g4 @@ -131,6 +131,8 @@ seqAddExpr unaryExpr : '!' unaryExpr | '-' unaryExpr + | '*' unaryExpr + | '&' unaryExpr | valPrefix unaryExpr | newExpr ; diff --git a/src/parsers/vct/parsers/parser/ColLLVMParser.scala b/src/parsers/vct/parsers/parser/ColLLVMParser.scala index 98d65c25ef..510c2d015a 100644 --- a/src/parsers/vct/parsers/parser/ColLLVMParser.scala +++ b/src/parsers/vct/parsers/parser/ColLLVMParser.scala @@ -1,18 +1,21 @@ package vct.parsers.parser +import com.google.protobuf.InvalidProtocolBufferException import com.typesafe.scalalogging.LazyLogging import hre.io.Readable import org.antlr.v4.runtime.{CharStream, CommonTokenStream} import vct.antlr4.generated.{LLVMSpecParser, LangLLVMSpecLexer} -import vct.col.ast.Deserialize import vct.col.ast.serialize.Program +import vct.col.ast.{Declaration, Deserialize, LLVMFunctionDefinition} import vct.col.origin.{ExpectedError, Origin} +import vct.col.ref.Ref +import vct.parsers.transform.{BlameProvider, LLVMContractToCol, OriginProvider} +import vct.result.VerificationError.{SystemError, Unreachable, UserError} +import vct.parsers.{Parser, ParseResult} import vct.parsers.debug.DebugOptions -import vct.parsers.transform.{BlameProvider, LLVMContractToCol} -import vct.parsers.{ParseResult, Parser} -import vct.result.VerificationError.{Unreachable, UserError} import java.io.{IOException, Reader} +import java.nio.file.Path import java.nio.charset.StandardCharsets import java.nio.file.Path import scala.util.{Failure, Using} @@ -20,26 +23,38 @@ import scala.util.{Failure, Using} case class ColLLVMParser( debugOptions: DebugOptions, blameProvider: BlameProvider, - vcllvm: Path, + pallas: Path, ) extends Parser with LazyLogging { - case class LLVMParseError(fileName: String, errorCode: Int, error: String) - extends UserError { + private case class LLVMParseError( + fileName: String, + errorCode: Int, + error: String, + ) extends UserError { override def code: String = "LLVMParseError" override def text: String = - s"[ERROR] Parsing file $fileName failed with exit code $errorCode:\n$error" + messageContext( + s"[ERROR] Parsing file $fileName failed with exit code $errorCode:\n$error" + ) } override def parse[G]( readable: Readable, baseOrigin: Origin = Origin(Nil), ): ParseResult[G] = { - if (vcllvm == null) { + if (pallas == null) { throw Unreachable( - "The COLLVMParser needs to be provided with the path to vcllvm to parse LLVM-IR files" + "The ColLLVMParser needs to be provided with the path to pallas to parse LLVM-IR files" ) } - val command = Seq(vcllvm.toString, readable.fileName) + val command = Seq( + "opt-17", + s"--load-pass-plugin=$pallas", + "--passes=module(pallas-declare-variables,pallas-collect-module-spec),function(pallas-declare-function,pallas-assign-pure,pallas-declare-function-contract,pallas-transform-function-body),module(pallas-print-protobuf)", + readable.fileName, + "--disable-output", + ) + val process = new ProcessBuilder(command: _*).start() val protoProgram = @@ -51,7 +66,7 @@ case class ColLLVMParser( new String( process.getErrorStream.readAllBytes(), StandardCharsets.UTF_8, - ), + ).indent(8), )) }.get @@ -63,7 +78,7 @@ case class ColLLVMParser( new String( process.getErrorStream.readAllBytes(), StandardCharsets.UTF_8, - ), + ).indent(8), ) } diff --git a/src/parsers/vct/parsers/transform/LLVMContractToCol.scala b/src/parsers/vct/parsers/transform/LLVMContractToCol.scala index dfd50a7640..b714a0ed9e 100644 --- a/src/parsers/vct/parsers/transform/LLVMContractToCol.scala +++ b/src/parsers/vct/parsers/transform/LLVMContractToCol.scala @@ -23,7 +23,7 @@ case class LLVMContractToCol[G]( ) extends ToCol(baseOrigin, blameProvider, errors) { def local(ctx: ParserRuleContext, name: String): Expr[G] = - LlvmLocal(name)(blame(ctx))(origin(ctx)) + LLVMLocal(name)(blame(ctx))(origin(ctx)) def createVariable( ctx: ParserRuleContext, @@ -145,7 +145,7 @@ case class LLVMContractToCol[G]( callOp match { case CallInstruction0(_, id, _, exprList, _) => val args: Seq[Expr[G]] = convert(exprList) - LlvmAmbiguousFunctionInvocation(id, args, Nil, Nil)(blame(callOp)) + LLVMAmbiguousFunctionInvocation(id, args, Nil, Nil)(blame(callOp)) } def convert(implicit binOp: BinOpInstructionContext): Expr[G] = @@ -547,7 +547,7 @@ case class LLVMContractToCol[G]( modifiers.foreach(convert(_, modifierCollector)) val namedOrigin = origin(decl).sourceName(convert(name)) - new LlvmSpecFunction( + new LLVMSpecFunction( convert(name), convert(t), args.map(convert(_)).getOrElse(Nil), diff --git a/src/parsers/vct/parsers/transform/PVLToCol.scala b/src/parsers/vct/parsers/transform/PVLToCol.scala index 5e9d424fa6..8bffdc7610 100644 --- a/src/parsers/vct/parsers/transform/PVLToCol.scala +++ b/src/parsers/vct/parsers/transform/PVLToCol.scala @@ -408,8 +408,10 @@ case class PVLToCol[G]( expr match { case UnaryExpr0(_, inner) => Not(convert(inner)) case UnaryExpr1(_, inner) => UMinus(convert(inner)) - case UnaryExpr2(op, inner) => convert(expr, op, convert(inner)) - case UnaryExpr3(inner) => convert(inner) + case UnaryExpr2(_, inner) => DerefPointer(convert(inner))(blame(expr)) + case UnaryExpr3(_, inner) => AddrOf(convert(inner)) + case UnaryExpr4(op, inner) => convert(expr, op, convert(inner)) + case UnaryExpr5(inner) => convert(inner) } def convert(implicit expr: NewExprContext): Expr[G] = diff --git a/src/rewrite/vct/rewrite/ClassToRef.scala b/src/rewrite/vct/rewrite/ClassToRef.scala index 32cfe554f9..3b089691cb 100644 --- a/src/rewrite/vct/rewrite/ClassToRef.scala +++ b/src/rewrite/vct/rewrite/ClassToRef.scala @@ -460,9 +460,9 @@ case class ClassToRef[Pre <: Generation]() extends Rewriter[Pre] { "Instance operator methods are already compiled away", Some(method), ) - case function: LlvmSpecFunction[Pre] => + case function: LLVMSpecFunction[Pre] => throw ExcludedByPassOrder( - "Llvm spec functions are already compiled away", + "LLVM spec functions are already compiled away", Some(function), ) } diff --git a/src/rewrite/vct/rewrite/DesugarPermissionOperators.scala b/src/rewrite/vct/rewrite/DesugarPermissionOperators.scala index d0957ff8da..e00bc3ae21 100644 --- a/src/rewrite/vct/rewrite/DesugarPermissionOperators.scala +++ b/src/rewrite/vct/rewrite/DesugarPermissionOperators.scala @@ -171,7 +171,7 @@ case class DesugarPermissionOperators[Pre <: Generation]() )(FramedPtrOffset), dispatch(perm), ) - case other => rewriteDefault(other) + case other => other.rewriteDefault() } } } diff --git a/src/rewrite/vct/rewrite/EncodeCurrentThread.scala b/src/rewrite/vct/rewrite/EncodeCurrentThread.scala index ade6107c58..32f3e7b8f7 100644 --- a/src/rewrite/vct/rewrite/EncodeCurrentThread.scala +++ b/src/rewrite/vct/rewrite/EncodeCurrentThread.scala @@ -51,7 +51,7 @@ case class EncodeCurrentThread[Pre <: Generation]() extends Rewriter[Pre] { // PB: although a pure method will become a function, it should really be possible to mark a pure method as thread // local. case m: AbstractMethod[Pre] => !m.pure - case m: LlvmFunctionDefinition[Pre] => !m.pure + case m: LLVMFunctionDefinition[Pre] => !m.pure case _: ADTFunction[Pre] => false case _: ProverFunction[Pre] => false diff --git a/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala b/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala index 0b344f2a41..128f34291c 100644 --- a/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala +++ b/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala @@ -433,15 +433,14 @@ case class ResolveExpressionSideEffects[Pre <: Generation]() case proof: FramedProof[Pre] => rewriteDefault(proof) case extract: Extract[Pre] => rewriteDefault(extract) case branch: IndetBranch[Pre] => rewriteDefault(branch) - case LlvmLoop(cond, contract, body) => + case LLVMLoop(cond, contract, body) => evaluateOne(cond) match { case (Nil, Nil, cond) => - LlvmLoop(cond, dispatch(contract), dispatch(body)) + LLVMLoop(cond, dispatch(contract), dispatch(body)) case (variables, sideEffects, cond) => val break = new LabelDecl[Post]()(BreakOrigin) - Block(Seq( - LlvmLoop( + LLVMLoop( tt, dispatch(contract), Block(Seq( @@ -471,6 +470,7 @@ case class ResolveExpressionSideEffects[Pre <: Generation]() case _: CStatement[Pre] => throw ExtraNode case _: CPPStatement[Pre] => throw ExtraNode case _: JavaStatement[Pre] => throw ExtraNode + case _: LLVMStatement[Pre] => throw ExtraNode } } diff --git a/src/rewrite/vct/rewrite/TrivialAddrOf.scala b/src/rewrite/vct/rewrite/TrivialAddrOf.scala index edc400f193..1162ff3d92 100644 --- a/src/rewrite/vct/rewrite/TrivialAddrOf.scala +++ b/src/rewrite/vct/rewrite/TrivialAddrOf.scala @@ -32,11 +32,16 @@ case object TrivialAddrOf extends RewriterBuilder { case class TrivialAddrOf[Pre <: Generation]() extends Rewriter[Pre] { override def dispatch(e: Expr[Pre]): Expr[Post] = e match { + case DerefPointer(PointerAdd(AddrOf(pointer), offset)) + if offset.isInstanceOf[ConstantInt[Pre]] && + offset.asInstanceOf[ConstantInt[Pre]].value.signum == 0 => + dispatch(pointer) case AddrOf(DerefPointer(p)) => dispatch(p) case AddrOf(sub @ PointerSubscript(p, i)) => PointerAdd(dispatch(p), dispatch(i))(SubscriptErrorAddError(sub))(e.o) + case AddrOf(other) if other.t.isInstanceOf[TClass[Pre]] => dispatch(other) case AddrOf(other) => throw UnsupportedLocation(other) case assign @ PreAssignExpression(target, AddrOf(value)) if value.t.isInstanceOf[TClass[Pre]] => @@ -55,7 +60,7 @@ case class TrivialAddrOf[Pre <: Generation]() extends Rewriter[Pre] { newValue, )(assign.blame) With(newPointer, newAssign) - case other => rewriteDefault(other) + case other => other.rewriteDefault() } override def dispatch(s: Statement[Pre]): Statement[Post] = @@ -77,7 +82,7 @@ case class TrivialAddrOf[Pre <: Generation]() extends Rewriter[Pre] { newValue, )(assign.blame) Block(Seq(newPointer, newAssign)) - case other => rewriteDefault(other) + case other => other.rewriteDefault() } // TODO: AddressOff needs a more structured approach. Now you could assign a local structure to a pointer, and that pointer diff --git a/src/rewrite/vct/rewrite/VariableToPointer.scala b/src/rewrite/vct/rewrite/VariableToPointer.scala new file mode 100644 index 0000000000..ad46a37086 --- /dev/null +++ b/src/rewrite/vct/rewrite/VariableToPointer.scala @@ -0,0 +1,213 @@ +package vct.rewrite + +import vct.col.ast._ +import vct.col.ref._ +import vct.col.origin._ +import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder, Rewritten} +import vct.col.util.AstBuildHelpers._ +import vct.col.util.SuccessionMap +import vct.result.VerificationError.UserError + +import scala.collection.mutable + +case object VariableToPointer extends RewriterBuilder { + override def key: String = "variableToPointer" + + override def desc: String = + "Translate every local and field to a pointer such that it can have its address taken" + + case class UnsupportedAddrOf(loc: Expr[_]) extends UserError { + override def code: String = "unsupportedAddrOf" + + override def text: String = + loc.o.messageInContext( + "Taking an address of this expression is not supported" + ) + } +} + +case class VariableToPointer[Pre <: Generation]() extends Rewriter[Pre] { + + import VariableToPointer._ + + val addressedSet: mutable.Set[Node[Pre]] = new mutable.HashSet[Node[Pre]]() + val heapVariableMap: SuccessionMap[HeapVariable[Pre], HeapVariable[Post]] = + SuccessionMap() + val variableMap: SuccessionMap[Variable[Pre], Variable[Post]] = + SuccessionMap() + val fieldMap: SuccessionMap[InstanceField[Pre], InstanceField[Post]] = + SuccessionMap() + + override def dispatch(program: Program[Pre]): Program[Rewritten[Pre]] = { + addressedSet.addAll(program.collect { + case AddrOf(Local(Ref(v))) if !v.t.isInstanceOf[TClass[Pre]] => v + case AddrOf(DerefHeapVariable(Ref(v))) + if !v.t.isInstanceOf[TClass[Pre]] => + v + case AddrOf(Deref(_, Ref(f))) if !f.t.isInstanceOf[TClass[Pre]] => f + }) + super.dispatch(program) + } + + override def dispatch(decl: Declaration[Pre]): Unit = + decl match { + case v: HeapVariable[Pre] if addressedSet.contains(v) => + heapVariableMap(v) = globalDeclarations + .declare(new HeapVariable(TPointer(dispatch(v.t)))(v.o)) + case v: Variable[Pre] if addressedSet.contains(v) => + variableMap(v) = variables + .declare(new Variable(TPointer(dispatch(v.t)))(v.o)) + case f: InstanceField[Pre] if addressedSet.contains(f) => + fieldMap(f) = classDeclarations.declare( + new InstanceField( + TPointer(dispatch(f.t)), + f.flags.map { it => dispatch(it) }, + )(f.o) + ) + case other => allScopes.anySucceed(other, other.rewriteDefault()) + } + + override def dispatch(stat: Statement[Pre]): Statement[Post] = { + implicit val o: Origin = stat.o + stat match { + case s: Scope[Pre] => + s.rewrite( + locals = variables.dispatch(s.locals), + body = Block(s.locals.filter { local => addressedSet.contains(local) } + .map { local => + implicit val o: Origin = local.o + Assign( + Local[Post](variableMap.ref(local)), + NewPointerArray( + variableMap(local).t.asPointer.get.element, + const(1), + )(PanicBlame("Size is > 0")), + )(PanicBlame("Initialisation should always succeed")) + } ++ Seq(dispatch(s.body))), + ) + case i @ Instantiate(cls, out) => + Block(Seq(i.rewriteDefault()) ++ cls.decl.declarations.flatMap { + case f: InstanceField[Pre] => + if (f.t.asClass.isDefined) { + Seq( + Assign( + Deref[Post](dispatch(out), fieldMap.ref(f))(PanicBlame( + "Initialisation should always succeed" + )), + NewPointerArray( + fieldMap(f).t.asPointer.get.element, + const(1), + )(PanicBlame("Size is > 0")), + )(PanicBlame("Initialisation should always succeed")), + Assign( + PointerSubscript( + Deref[Post](dispatch(out), fieldMap.ref(f))(PanicBlame( + "Initialisation should always succeed" + )), + const[Post](0), + )(PanicBlame("Size is > 0")), + dispatch(NewObject[Pre](f.t.asClass.get.cls)), + )(PanicBlame("Initialisation should always succeed")), + ) + } else if (addressedSet.contains(f)) { + Seq( + Assign( + Deref[Post](dispatch(out), fieldMap.ref(f))(PanicBlame( + "Initialisation should always succeed" + )), + NewPointerArray( + fieldMap(f).t.asPointer.get.element, + const(1), + )(PanicBlame("Size is > 0")), + )(PanicBlame("Initialisation should always succeed")) + ) + } else { Seq() } + case _ => Seq() + }) + case other => other.rewriteDefault() + } + } + + override def dispatch(expr: Expr[Pre]): Expr[Post] = { + implicit val o: Origin = expr.o + expr match { + case deref @ DerefHeapVariable(Ref(v)) if addressedSet.contains(v) => + DerefPointer( + DerefHeapVariable[Post](heapVariableMap.ref(v))(deref.blame) + )(PanicBlame("Should always be accessible")) + case Local(Ref(v)) if addressedSet.contains(v) => + DerefPointer(Local[Post](variableMap.ref(v)))(PanicBlame( + "Should always be accessible" + )) + case deref @ Deref(obj, Ref(f)) if addressedSet.contains(f) => + DerefPointer(Deref[Post](dispatch(obj), fieldMap.ref(f))(deref.blame))( + PanicBlame("Should always be accessible") + ) + case newObject @ NewObject(Ref(cls)) => + val obj = new Variable[Post](TClass(succ(cls), Seq())) + ScopedExpr( + Seq(obj), + With( + Block( + Seq(assignLocal(obj.get, newObject.rewriteDefault())) ++ + cls.declarations.flatMap { + case f: InstanceField[Pre] => + if (f.t.asClass.isDefined) { + Seq( + Assign( + Deref[Post](obj.get, anySucc(f))(PanicBlame( + "Initialisation should always succeed" + )), + dispatch(NewObject[Pre](f.t.asClass.get.cls)), + )(PanicBlame("Initialisation should always succeed")) + ) + } else if (addressedSet.contains(f)) { + Seq( + Assign( + Deref[Post](obj.get, fieldMap.ref(f))(PanicBlame( + "Initialisation should always succeed" + )), + NewPointerArray( + fieldMap(f).t.asPointer.get.element, + const(1), + )(PanicBlame("Size is > 0")), + )(PanicBlame("Initialisation should always succeed")) + ) + } else { Seq() } + case _ => Seq() + } + ), + obj.get, + ), + ) + case other => other.rewriteDefault() + } + } + + override def dispatch(loc: Location[Pre]): Location[Post] = { + implicit val o: Origin = loc.o + loc match { + case HeapVariableLocation(Ref(v)) if addressedSet.contains(v) => + PointerLocation( + DerefHeapVariable[Post](heapVariableMap.ref(v))(PanicBlame( + "Should always be accessible" + )) + )(PanicBlame("Should always be accessible")) + case FieldLocation(obj, Ref(f)) if addressedSet.contains(f) => + PointerLocation(Deref[Post](dispatch(obj), fieldMap.ref(f))(PanicBlame( + "Should always be accessible" + )))(PanicBlame("Should always be accessible")) + case PointerLocation( + AddrOf(Deref(obj, Ref(f))) + ) /* if addressedSet.contains(f) always true */ => + FieldLocation[Post](dispatch(obj), fieldMap.ref(f)) + case PointerLocation( + AddrOf(DerefHeapVariable(Ref(v))) + ) /* if addressedSet.contains(v) always true */ => + HeapVariableLocation[Post](heapVariableMap.ref(v)) + case PointerLocation(AddrOf(local @ Local(_))) => + throw UnsupportedAddrOf(local) + case other => other.rewriteDefault() + } + } +} diff --git a/src/rewrite/vct/rewrite/lang/LangLLVMToCol.scala b/src/rewrite/vct/rewrite/lang/LangLLVMToCol.scala index 162774a74c..b776df0767 100644 --- a/src/rewrite/vct/rewrite/lang/LangLLVMToCol.scala +++ b/src/rewrite/vct/rewrite/lang/LangLLVMToCol.scala @@ -2,71 +2,139 @@ package vct.rewrite.lang import com.typesafe.scalalogging.LazyLogging import vct.col.ast._ -import vct.col.origin.Origin -import vct.col.ref.{LazyRef, Ref} -import vct.col.resolve.ctx.RefLlvmFunctionDefinition +import vct.col.origin.{Origin, PanicBlame, SourceName} +import vct.col.ref.{DirectRef, LazyRef, Ref} +import vct.col.resolve.ctx.RefLLVMFunctionDefinition import vct.col.rewrite.{Generation, Rewritten} +import vct.col.util.AstBuildHelpers.{VarBuildHelpers, assignLocal, const, tt} import vct.col.util.{CurrentProgramContext, SuccessionMap} -import vct.result.VerificationError.SystemError -import vct.rewrite.lang.LangLLVMToCol.UnexpectedLlvmNode +import vct.result.VerificationError.{SystemError, UserError} + +import scala.collection.mutable case object LangLLVMToCol { - case class UnexpectedLlvmNode(node: Node[_]) extends SystemError { + case class UnexpectedLLVMNode(node: Node[_]) extends SystemError { override def text: String = context[CurrentProgramContext].map(_.highlight(node)).getOrElse(node.o) .messageInContext( "VerCors assumes this node does not occur here in llvm input." ) } + + case class NonConstantStructIndex(origin: Origin) extends UserError { + override def code: String = "nonConstantStructIndex" + + override def text: String = + origin.messageInContext( + s"This struct indexing operation (getelementptr) uses a non-constant struct index which we do not support." + ) + } } case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends LazyLogging { + + import LangLLVMToCol._ + type Post = Rewritten[Pre] implicit val implicitRewriter: AbstractRewriter[Pre, Post] = rw private val llvmFunctionMap - : SuccessionMap[LlvmFunctionDefinition[Pre], Procedure[Post]] = + : SuccessionMap[LLVMFunctionDefinition[Pre], Procedure[Post]] = SuccessionMap() private val specFunctionMap - : SuccessionMap[LlvmSpecFunction[Pre], Function[Post]] = SuccessionMap() + : SuccessionMap[LLVMSpecFunction[Pre], Function[Post]] = SuccessionMap() + private val globalVariableMap + : SuccessionMap[LLVMGlobalVariable[Pre], HeapVariable[Post]] = + SuccessionMap() + private val structMap: SuccessionMap[LLVMTStruct[Pre], Class[Post]] = + SuccessionMap() + private val structFieldMap + : SuccessionMap[(LLVMTStruct[Pre], Int), InstanceField[Post]] = + SuccessionMap() - def rewriteLocal(local: LlvmLocal[Pre]): Expr[Post] = { + private val globalVariableTypeGuesses + : mutable.HashMap[LLVMGlobalVariable[Pre], mutable.HashSet[Type[Pre]]] = + mutable.HashMap() + private val structFieldTypeGuesses + : mutable.HashMap[(LLVMTStruct[Pre], Int), mutable.HashSet[Type[Pre]]] = + mutable.HashMap() + private val localTypeGuesses + : mutable.HashMap[Variable[Pre], mutable.HashSet[Type[Pre]]] = mutable + .HashMap() + + def rewriteLocal(local: LLVMLocal[Pre]): Expr[Post] = { implicit val o: Origin = local.o Local(rw.succ(local.ref.get.decl)) } - def rewriteFunctionDef(func: LlvmFunctionDefinition[Pre]): Unit = { + def rewriteFunctionDef(func: LLVMFunctionDefinition[Pre]): Unit = { implicit val o: Origin = func.o + val importedDecl = rw.importedDeclarations.find { + case procedure: Procedure[Pre] => + func.contract.name == procedure.o.get[SourceName].name + } val procedure = rw.labelDecls.scope { - rw.globalDeclarations.declare( + rw.globalDeclarations.declare(if (importedDecl.isDefined) { + val importedProcedure = importedDecl.get.asInstanceOf[Procedure[Pre]] + val newArgs = importedProcedure.args.map { it => it.rewriteDefault() } + new Procedure[Post]( + returnType = rw.dispatch(importedProcedure.returnType), + args = + rw.variables.collect { + func.args.zip(newArgs).foreach { case (a, b) => + rw.variables.succeed(a, b) + } + }._1, + outArgs = Nil, + typeArgs = Nil, + body = + func.functionBody match { + case None => None + case Some(functionBody) => + if (func.pure) + Some(GotoEliminator(functionBody match { + case scope: Scope[Pre] => scope; + case other => throw UnexpectedLLVMNode(other) + }).eliminate()) + else + Some(rw.dispatch(functionBody)) + }, + contract = rw.dispatch(func.contract.data.get), + pure = func.pure, + )(func.blame) + } else { new Procedure[Post]( returnType = rw.dispatch(func.returnType), args = rw.variables.collect { func.args.foreach(rw.dispatch) }._1, outArgs = Nil, typeArgs = Nil, body = - if (func.pure) - Some(GotoEliminator(func.functionBody match { - case scope: Scope[Pre] => scope; - case other => throw UnexpectedLlvmNode(other) - }).eliminate()) - else - Some(rw.dispatch(func.functionBody)), + func.functionBody match { + case None => None + case Some(functionBody) => + if (func.pure) + Some(GotoEliminator(functionBody match { + case scope: Scope[Pre] => scope; + case other => throw UnexpectedLLVMNode(other) + }).eliminate()) + else + Some(rw.dispatch(functionBody)) + }, contract = rw.dispatch(func.contract.data.get), pure = func.pure, )(func.blame) - ) + }) } llvmFunctionMap.update(func, procedure) } def rewriteAmbiguousFunctionInvocation( - inv: LlvmAmbiguousFunctionInvocation[Pre] + inv: LLVMAmbiguousFunctionInvocation[Pre] ): Invocation[Post] = { implicit val o: Origin = inv.o inv.ref.get.decl match { - case func: LlvmFunctionDefinition[Pre] => + case func: LLVMFunctionDefinition[Pre] => new ProcedureInvocation[Post]( ref = new LazyRef[Post, Procedure[Post]](llvmFunctionMap(func)), args = inv.args.map(rw.dispatch), @@ -79,7 +147,7 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) outArgs = Seq.empty, typeArgs = Seq.empty, )(inv.blame) - case func: LlvmSpecFunction[Pre] => + case func: LLVMSpecFunction[Pre] => new FunctionInvocation[Post]( ref = new LazyRef[Post, Function[Post]](specFunctionMap(func)), args = inv.args.map(rw.dispatch), @@ -96,7 +164,7 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) } def rewriteFunctionInvocation( - inv: LlvmFunctionInvocation[Pre] + inv: LLVMFunctionInvocation[Pre] ): ProcedureInvocation[Post] = { implicit val o: Origin = inv.o new ProcedureInvocation[Post]( @@ -113,11 +181,11 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) )(inv.blame) } - def rewriteGlobal(decl: LlvmGlobal[Pre]): Unit = { + def rewriteGlobal(decl: LLVMGlobalSpecification[Pre]): Unit = { implicit val o: Origin = decl.o decl.data.get.foreach { decl => rw.globalDeclarations.declare(decl match { - case function: LlvmSpecFunction[Pre] => + case function: LLVMSpecFunction[Pre] => val rwFunction = new Function[Post]( rw.dispatch(function.returnType), @@ -134,12 +202,328 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) )(function.blame) specFunctionMap.update(function, rwFunction) rwFunction - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) }) } } - def result(ref: RefLlvmFunctionDefinition[Pre])( + def rewriteFunctionPointer( + pointer: LLVMFunctionPointerValue[Pre] + ): LLVMFunctionPointerValue[Post] = { + implicit val o: Origin = pointer.o + new LLVMFunctionPointerValue[Post](value = + new LazyRef[Post, GlobalDeclaration[Post]](llvmFunctionMap( + pointer.value.decl.asInstanceOf[LLVMFunctionDefinition[Pre]] + )) + ) + } + + def rewriteStruct(t: LLVMTStruct[Pre]): Unit = { + val LLVMTStruct(name, packed, elements) = t + val newStruct = + new Class[Post]( + Seq(), + rw.classDeclarations.collect { + elements.zipWithIndex.foreach { case (fieldType, idx) => + structFieldMap((t, idx)) = + new InstanceField(rw.dispatch(fieldType), flags = Nil)( + fieldType.o + ) + rw.classDeclarations.declare(structFieldMap((t, idx))) + } + }._1, + Seq(), + tt[Post], + )(t.o) + + rw.globalDeclarations.declare(newStruct) + structMap(t) = newStruct + } + + def rewriteGlobalVariable(decl: LLVMGlobalVariable[Pre]): Unit = { + // TODO: Handle the initializer + // TODO: Include array and vector bounds somehow + decl.variableType match { + case struct: LLVMTStruct[Pre] => { + rewriteStruct(struct) + globalVariableMap.update( + decl, + rw.globalDeclarations.declare( + new HeapVariable[Post]( + new TClass[Post]( + new DirectRef[Post, Class[Post]](structMap(struct)), + Seq(), + )(struct.o) + )(decl.o) + ), + ) + } + case array: LLVMTArray[Pre] => { + globalVariableMap.update( + decl, + rw.globalDeclarations.declare( + new HeapVariable[Post]( + new TPointer[Post](rw.dispatch(array.elementType))(array.o) + )(decl.o) + ), + ) + } + case vector: LLVMTVector[Pre] => { + globalVariableMap.update( + decl, + rw.globalDeclarations.declare( + new HeapVariable[Post]( + new TPointer[Post](rw.dispatch(vector.elementType))(vector.o) + )(decl.o) + ), + ) + } + case _ => { ??? } + } + } + + def rewritePointerChain( + pointer: Expr[Post], + t: Type[Pre], + indices: Seq[Expr[Pre]], + )(implicit o: Origin): Expr[Post] = { + if (indices.isEmpty) { return pointer } + t match { + case struct: LLVMTStruct[Pre] => { + if (!structMap.contains(struct)) { rewriteStruct(struct) } + indices.head match { + case value: LLVMIntegerValue[Pre] => + rewritePointerChain( + Deref[Post]( + pointer, + structFieldMap.ref((struct, value.value.intValue)), + )(o), + struct.elements(value.value.intValue), + indices.tail, + ) + case value: IntegerValue[Pre] => + rewritePointerChain( + Deref[Post]( + pointer, + structFieldMap.ref((struct, value.value.intValue)), + )(o), + struct.elements(value.value.intValue), + indices.tail, + ) + case _ => throw NonConstantStructIndex(o) + } + } + case array: LLVMTArray[Pre] => ??? + case vector: LLVMTVector[Pre] => ??? + } + } + + def derefUntil( + pointer: Expr[Post], + currentType: Type[Pre], + untilType: Type[Pre], + ): (Expr[Post], Type[Pre]) = { + implicit val o: Origin = pointer.o + currentType match { + case _ if currentType == untilType => (AddrOf(pointer), currentType) + case LLVMTPointer(None) => (pointer, LLVMTPointer[Pre](Some(untilType))) + case LLVMTPointer(Some(inner)) if inner == untilType => + (pointer, currentType) + case LLVMTPointer(Some(LLVMTArray(numElements, elementType))) => { + val (expr, inner) = derefUntil( + PointerSubscript[Post]( + DerefPointer(pointer)(pointer.o), + IntegerValue(BigInt(0)), + )(pointer.o), + elementType, + untilType, + ) + (expr, LLVMTPointer[Pre](Some(LLVMTArray(numElements, inner)))) + } + case LLVMTArray(numElements, elementType) => { + val (expr, inner) = derefUntil( + PointerSubscript[Post](pointer, IntegerValue(BigInt(0)))(pointer.o), + elementType, + untilType, + ) + (expr, LLVMTArray[Pre](numElements, inner)) + } + case LLVMTPointer(Some(LLVMTVector(numElements, elementType))) => { + val (expr, inner) = derefUntil( + PointerSubscript[Post]( + DerefPointer(pointer)(pointer.o), + IntegerValue(BigInt(0)), + )(pointer.o), + elementType, + untilType, + ) + (expr, LLVMTPointer[Pre](Some(LLVMTVector(numElements, inner)))) + } + case LLVMTVector(numElements, elementType) => { + val (expr, inner) = derefUntil( + PointerSubscript[Post](pointer, IntegerValue(BigInt(0)))(pointer.o), + elementType, + untilType, + ) + (expr, LLVMTVector[Pre](numElements, inner)) + } + case LLVMTPointer(Some(struct @ LLVMTStruct(name, packed, elements))) => { + val (expr, inner) = derefUntil( + Deref[Post]( + DerefPointer(pointer)(pointer.o), + structFieldMap.ref((struct, 0)), + )(pointer.o), + elements.head, + untilType, + ) + ( + expr, + LLVMTPointer[Pre](Some( + LLVMTStruct(name, packed, inner +: elements.tail) + )), + ) + } + case struct @ LLVMTStruct(name, packed, elements) => { + val (expr, inner) = derefUntil( + Deref[Post](pointer, structFieldMap.ref((struct, 0)))(pointer.o), + elements.head, + untilType, + ) + (expr, LLVMTStruct[Pre](name, packed, inner +: elements.tail)) + } + } + } + + def rewriteGetElementPointer(gep: LLVMGetElementPointer[Pre]): Expr[Post] = { + implicit val o: Origin = gep.o + val t = gep.structureType + t match { + case struct: LLVMTStruct[Pre] => { + // TODO: We don't support variables in GEP yet and this just assumes all the indices are integer constants + // TODO: Use an actual Blame + + // Acquire the actual struct through a PointerAdd + // TODO: Can we somehow wrap the rw.dispatch(gep.pointer) to add the known type structureType? + gep.pointer.t match { + case LLVMTPointer(None) => + val structPointer = + DerefPointer( + PointerAdd( + rw.dispatch(gep.pointer), + rw.dispatch(gep.indices.head), + )(o) + )(o) + AddrOf(rewritePointerChain(structPointer, struct, gep.indices.tail)) + case LLVMTPointer(Some(inner)) if inner == t => + val structPointer = + DerefPointer( + PointerAdd( + rw.dispatch(gep.pointer), + rw.dispatch(gep.indices.head), + )(o) + )(o) + AddrOf(rewritePointerChain(structPointer, struct, gep.indices.tail)) + case LLVMTPointer(Some(_)) => + val (pointer, inferredType) = derefUntil( + rw.dispatch(gep.pointer), + gep.pointer.t, + t, + ) + addTypeGuess(gep.pointer, inferredType) + val structPointer = + DerefPointer( + PointerAdd(pointer, rw.dispatch(gep.indices.head))(o) + )(o) + val ret = AddrOf( + rewritePointerChain(structPointer, struct, gep.indices.tail) + ) + ret + } + } + case array: LLVMTArray[Pre] => ??? + case vector: LLVMTVector[Pre] => ??? + } + // Deref might not be the correct thing to use here since technically the pointer is only dereferenced in the load or store instruction + } + + def rewriteStore(store: LLVMStore[Pre]): Statement[Post] = { + implicit val o: Origin = store.o + val (pointer, inferredType) = derefUntil( + rw.dispatch(store.pointer), + store.pointer.t, + store.value.t, + ) + addTypeGuess(store.pointer, inferredType) + Assign(DerefPointer(pointer)(store.o), rw.dispatch(store.value))(store.o) + } + + def rewriteLoad(load: LLVMLoad[Pre]): Expr[Post] = { + val (pointer, inferredType) = derefUntil( + rw.dispatch(load.pointer), + load.pointer.t, + load.loadType, + ) + addTypeGuess(load.pointer, inferredType) + DerefPointer(pointer)(load.o)(load.o) + } + + def rewriteAllocA(alloc: LLVMAllocA[Pre]): Expr[Post] = { + implicit val o: Origin = alloc.o + val t = rw.dispatch(alloc.allocationType) + val v = new Variable[Post](TPointer(t))(alloc.o) + alloc.allocationType match { + case structType: LLVMTStruct[Pre] => + With( + Block(Seq( + LocalDecl(v), + assignLocal( + v.get, + NewPointerArray[Post]( + rw.dispatch(alloc.allocationType), + rw.dispatch(alloc.numElements), + )(PanicBlame("allocation should never fail")), + ), + Assign( + DerefPointer(v.get)(alloc.o), + NewObject[Post](structMap.ref(structType)), + )(PanicBlame("assignment should never fail")), + )), + v.get, + ) + case _ => + NewPointerArray[Post](t, rw.dispatch(alloc.numElements))(PanicBlame( + "allocation should never fail" + )) + } + } + + private def addTypeGuess(pointer: Expr[Pre], inferredType: Type[Pre]): Unit = + pointer match { + case Local(Ref(v)) => + localTypeGuesses.getOrElseUpdate(v, { mutable.HashSet() }) + .add(LLVMTPointer[Pre](Some(inferredType))) + case LLVMPointerValue(Ref(g)) => + globalVariableTypeGuesses.getOrElseUpdate( + g.asInstanceOf[LLVMGlobalVariable[Pre]], + { mutable.HashSet() }, + ).add(inferredType) + case it => { + println(it) + ??? + } + } + + def rewritePointerValue(pointer: LLVMPointerValue[Pre]): Expr[Post] = { + implicit val o: Origin = pointer.o + // Will be transformed by VariableToPointer pass + new AddrOf[Post]( + DerefHeapVariable[Post](globalVariableMap.ref( + pointer.value.decl.asInstanceOf[LLVMGlobalVariable[Pre]] + ))(pointer.o) + ) + } + + def result(ref: RefLLVMFunctionDefinition[Pre])( implicit o: Origin ): Expr[Post] = Result[Post](llvmFunctionMap.ref(ref.decl)) @@ -148,7 +532,7 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) effectively transforming the CFG into a tree. More efficient restructuring algorithms but this works for now. This of course only works for acyclic CFGs as otherwise replacement would be infinitely recursive. - Loop restructuring should be handled by VCLLVM as it has much more analytical and contextual information about + Loop restructuring should be handled by pallas as it has much more analytical and contextual information about the program. */ case class GotoEliminator(bodyScope: Scope[Pre]) extends LazyLogging { @@ -157,9 +541,9 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) case block: Block[Pre] => block.statements.map { case label: Label[Pre] => (label.decl, label) - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) }.toMap - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) } def eliminate(): Scope[Post] = { @@ -171,12 +555,12 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) case bodyBlock: Block[Pre] => Block[Post](bodyBlock.statements.head match { case label: Label[Pre] => Seq(eliminate(label)) - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) })(scope.body.o) - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) }, )(scope.o) - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) } } @@ -193,16 +577,16 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) case _: Return[Pre] => rw.dispatch(block) match { case block: Block[Post] => block - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) } case branch: Branch[Pre] => Block[Post]( block.statements.dropRight(1).map(rw.dispatch) :+ eliminate(branch) ) - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) } - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) } } @@ -213,10 +597,27 @@ case class LangLLVMToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) rw.dispatch(bs._1), bs._2 match { case goto: Goto[Pre] => eliminate(labelDeclMap(goto.lbl.decl)) - case other => throw UnexpectedLlvmNode(other) + case other => throw UnexpectedLLVMNode(other) }, ) )) } } + + def structType(t: LLVMTStruct[Pre]): Type[Post] = { + val targetClass = new LazyRef[Post, Class[Post]](structMap(t)) + TClass[Post](targetClass, Seq())(t.o) + } + + def pointerType(t: LLVMTPointer[Pre]): Type[Post] = + t.innerType match { + case Some(innerType) => TPointer[Post](rw.dispatch(innerType))(t.o) + case None => TPointer[Post](TAny())(t.o) + } + + def arrayType(t: LLVMTArray[Pre]): Type[Post] = + TPointer(rw.dispatch(t.elementType))(t.o) + + def vectorType(t: LLVMTVector[Pre]): Type[Post] = + TPointer(rw.dispatch(t.elementType))(t.o) } diff --git a/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala b/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala index 213997930e..b1b3fd9802 100644 --- a/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala +++ b/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala @@ -13,6 +13,7 @@ import vct.col.rewrite.{ Rewriter, RewriterBuilderArg, RewriterBuilderArg2, + Rewritten, } import vct.result.VerificationError.UserError import vct.rewrite.lang.LangSpecificToCol.NotAValue @@ -22,6 +23,12 @@ case object LangSpecificToCol extends RewriterBuilderArg2[Boolean, Boolean] { override def desc: String = "Translate language-specific constructs to a common subset of nodes." + override def apply[Pre <: Generation]( + veymontGeneratePermissions: Boolean, + veymontAllowAssign: Boolean, + ): AbstractRewriter[Pre, _ <: Generation] = + LangSpecificToCol(veymontGeneratePermissions, veymontAllowAssign, Seq()) + def ThisVar(): Origin = Origin(Seq(PreferredName(Seq("this")), LabelContext("constructor this"))) @@ -35,6 +42,7 @@ case object LangSpecificToCol extends RewriterBuilderArg2[Boolean, Boolean] { case class LangSpecificToCol[Pre <: Generation]( veymontGeneratePermissions: Boolean = false, veymontAllowAssign: Boolean = false, + importedDeclarations: Seq[GlobalDeclaration[Pre]] = Seq(), ) extends Rewriter[Pre] with LazyLogging { val java: LangJavaToCol[Pre] = LangJavaToCol(this) val bip: LangBipToCol[Pre] = LangBipToCol(this) @@ -194,8 +202,9 @@ case class LangSpecificToCol[Pre <: Generation]( cpp.storeIfSYCLFunction(func) } - case func: LlvmFunctionDefinition[Pre] => llvm.rewriteFunctionDef(func) - case global: LlvmGlobal[Pre] => llvm.rewriteGlobal(global) + case func: LLVMFunctionDefinition[Pre] => llvm.rewriteFunctionDef(func) + case global: LLVMGlobalSpecification[Pre] => llvm.rewriteGlobal(global) + case global: LLVMGlobalVariable[Pre] => llvm.rewriteGlobalVariable(global) case cls: Class[Pre] => currentClass.having(cls) { @@ -265,6 +274,7 @@ case class LangSpecificToCol[Pre <: Generation]( rewriteDefault(unfold) } + case store: LLVMStore[Pre] => llvm.rewriteStore(store) case other => rewriteDefault(other) } @@ -281,7 +291,7 @@ case class LangSpecificToCol[Pre <: Generation]( case ref: RefCGlobalDeclaration[Pre] => c.result(ref) case ref: RefCPPFunctionDefinition[Pre] => cpp.result(ref) case ref: RefCPPGlobalDeclaration[Pre] => cpp.result(ref) - case ref: RefLlvmFunctionDefinition[Pre] => llvm.result(ref) + case ref: RefLLVMFunctionDefinition[Pre] => llvm.result(ref) case RefFunction(decl) => Result[Post](anySucc(decl)) case RefProcedure(decl) => Result[Post](anySucc(decl)) case RefJavaMethod(decl) => Result[Post](java.javaMethod.ref(decl)) @@ -290,7 +300,7 @@ case class LangSpecificToCol[Pre <: Generation]( case RefInstanceMethod(decl) => Result[Post](anySucc(decl)) case RefInstanceOperatorFunction(decl) => Result[Post](anySucc(decl)) case RefInstanceOperatorMethod(decl) => Result[Post](anySucc(decl)) - case RefLlvmSpecFunction(decl) => Result[Post](anySucc(decl)) + case RefLLVMSpecFunction(decl) => Result[Post](anySucc(decl)) } case diz @ AmbiguousThis() => currentThis.top @@ -381,11 +391,18 @@ case class LangSpecificToCol[Pre <: Generation]( silver.adtInvocation(inv) case map: SilverUntypedNonemptyLiteralMap[Pre] => silver.nonemptyMap(map) - case inv: LlvmFunctionInvocation[Pre] => + case inv: LLVMFunctionInvocation[Pre] => llvm.rewriteFunctionInvocation(inv) - case inv: LlvmAmbiguousFunctionInvocation[Pre] => + case inv: LLVMAmbiguousFunctionInvocation[Pre] => llvm.rewriteAmbiguousFunctionInvocation(inv) - case local: LlvmLocal[Pre] => llvm.rewriteLocal(local) + case local: LLVMLocal[Pre] => llvm.rewriteLocal(local) + case pointer: LLVMFunctionPointerValue[Pre] => + llvm.rewriteFunctionPointer(pointer) + case pointer: LLVMPointerValue[Pre] => llvm.rewritePointerValue(pointer) + case gep: LLVMGetElementPointer[Pre] => llvm.rewriteGetElementPointer(gep) + case load: LLVMLoad[Pre] => llvm.rewriteLoad(load) + case alloc: LLVMAllocA[Pre] => llvm.rewriteAllocA(alloc) + case int: LLVMIntegerValue[Pre] => IntegerValue(int.value)(int.o) case other => rewriteDefault(other) } @@ -398,6 +415,15 @@ case class LangSpecificToCol[Pre <: Generation]( case t: TOpenCLVector[Pre] => c.vectorType(t) case t: CTArray[Pre] => c.arrayType(t) case t: CTStruct[Pre] => c.structType(t) + case t: LLVMTInt[Pre] => TInt()(t.o) + case t: LLVMTStruct[Pre] => llvm.structType(t) + case t: LLVMTPointer[Pre] => llvm.pointerType(t) + case t: LLVMTArray[Pre] => llvm.arrayType(t) + case t: LLVMTVector[Pre] => llvm.vectorType(t) + case t: LLVMTMetadata[Pre] => + TInt()( + t.o + ) // TODO: Ignore these by just assuming they're integers... or could we do TVoid? case t: CPPTArray[Pre] => cpp.arrayType(t) case other => rewriteDefault(other) }