Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Builds

on: [push, pull_request]
env:
llvm: 17
llvm: 19

jobs:
nix-build:
Expand All @@ -13,7 +13,7 @@ jobs:
- name: Build using nix
run: nix build
- name: Run built Diffkemp
run: result/bin/diffkemp --help
run: nix develop --command result/bin/diffkemp --help

local-build:
runs-on: ubuntu-22.04
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
llvm: [12, 13, 14, 15, 16, 17, 18]
llvm: [12, 13, 14, 15, 16, 17, 18, 19]
env:
- CC: gcc
CXX: g++
asan: [OFF]
regression-tests: [true]

include:
- llvm: 18
- llvm: 19
env:
CC: clang
CXX: clang++
asan: OFF
regression-tests: true

- llvm: 18
- llvm: 19
env:
CC: gcc
CXX: g++
Expand Down
14 changes: 14 additions & 0 deletions diffkemp/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from argparse import ArgumentParser, ArgumentTypeError, SUPPRESS
from diffkemp.building.build_kernel import build_kernel
from diffkemp.compare import compare
from diffkemp.utils import get_llvm_version
from diffkemp.simpll.library import get_llvm_build_version
import diffkemp.diffkemp
import diffkemp.viewer
import os
Expand Down Expand Up @@ -219,6 +221,18 @@ def make_argument_parser():

def run_from_cli():
"""Main method to run the tool."""

llvm_version = get_llvm_version()
build_llvm_version = get_llvm_build_version().major
if llvm_version != build_llvm_version:
raise RuntimeError(
"Incompatible LLVM versions: DiffKemp was built with"
"{} and the installed version is {}".format(
build_llvm_version,
llvm_version
)
)

ap = make_argument_parser()
args = ap.parse_args()
if args.verbose or args.debug:
Expand Down
8 changes: 7 additions & 1 deletion diffkemp/llvm_ir/optimiser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Functions for optimizations of LLVM IR."""
from diffkemp.utils import get_opt_command
from diffkemp.utils import get_llvm_version
from subprocess import check_call, CalledProcessError
import os

Expand All @@ -14,7 +15,12 @@ def opt_llvm(llvm_file):
Run basic simplification passes and -constmerge to remove
duplicate constants that might have come from linked files.
"""
passes = [("lowerswitch", "function"),
if get_llvm_version() < 19:
lower_switch_pass_name = "lowerswitch"
else:
lower_switch_pass_name = "lower-switch"

passes = [(lower_switch_pass_name, "function"),
("mem2reg", "function"),
("loop-simplify", "function"),
("simplifycfg", "function"),
Expand Down
2 changes: 1 addition & 1 deletion diffkemp/simpll/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
#ifndef DIFFKEMP_SIMPLL_CONFIG_H
#define DIFFKEMP_SIMPLL_CONFIG_H

#include "llvm/Support/CommandLine.h"
#include <llvm/IR/Module.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/SourceMgr.h>

#define DEBUG_SIMPLL "debug-simpll"
Expand Down
13 changes: 7 additions & 6 deletions diffkemp/simpll/DifferentialFunctionComparator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ int DifferentialFunctionComparator::cmpGEPs(const GEPOperator *GEPL,

if (MemberNameL == DI->StructFieldNames.end()
|| MemberNameR == DI->StructFieldNames.end()
|| !MemberNameL->second.equals(MemberNameR->second))
|| !(MemberNameL->second == MemberNameR->second))
if (int Res = cmpValues(idxL->get(), idxR->get()))
RETURN_WITH_LOG(Res);

Expand Down Expand Up @@ -516,11 +516,12 @@ int DifferentialFunctionComparator::cmpAllocs(const CallInst *CL,
RETURN_WITH_LOG(1);

// If the next instruction is a bitcast, compare its type instead
const Value *ValL =
isa<BitCastInst>(CL->getNextNode()) ? CL->getNextNode() : CL;
const Value *ValR =
isa<BitCastInst>(CR->getNextNode()) ? CR->getNextNode() : CR;

const auto *nextInstL = CL->getNextNode();
const auto *nextInstR = CR->getNextNode();
const bool isNextInstBitcastL = nextInstL && isa<BitCastInst>(nextInstL);
const bool isNextInstBitcastR = nextInstR && isa<BitCastInst>(nextInstR);
const Value *ValL = isNextInstBitcastL ? nextInstL : CL;
const Value *ValR = isNextInstBitcastR ? nextInstR : CR;
// Retrieve type names and sizes
TypeInfo TypeInfoL =
getPointeeStructTypeInfo(ValL, &LayoutL, FnL->getName());
Expand Down
2 changes: 1 addition & 1 deletion diffkemp/simpll/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
#ifndef DIFFKEMP_SIMPLL_LOGGER_H
#define DIFFKEMP_SIMPLL_LOGGER_H

#include <Config.h>
#include "Config.h"
#include <llvm/IR/Type.h>
#include <llvm/IR/Value.h>
#include <llvm/Support/Debug.h>
Expand Down
2 changes: 2 additions & 0 deletions diffkemp/simpll/SimpLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "Output.h"
#include "Utils.h"

#include <llvm/Support/ManagedStatic.h>

using namespace llvm;

// Command line options
Expand Down
146 changes: 124 additions & 22 deletions diffkemp/simpll/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <iostream>
#include <llvm/Analysis/AliasAnalysis.h>
#include <llvm/BinaryFormat/Dwarf.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/Instruction.h>
Expand Down Expand Up @@ -404,6 +405,60 @@ void findAndReplace(std::string &input, std::string find, std::string replace) {
}
}

#if LLVM_VERSION_MAJOR >= 19

const Instruction *getConstExprAsInstruction(const ConstantExpr *CEx) {
SmallVector<Value *, 4> ValueOperands(CEx->op_begin(), CEx->op_end());
ArrayRef<Value *> Ops(ValueOperands);

switch (CEx->getOpcode()) {
case Instruction::Trunc:
#if LLVM_VERSION_MAJOR >= 21
case Instruction::PtrToAddr:
#endif
case Instruction::PtrToInt:
case Instruction::IntToPtr:
case Instruction::BitCast:
case Instruction::AddrSpaceCast:
return CastInst::Create((Instruction::CastOps)CEx->getOpcode(),
Ops[0],
CEx->getType(),
"");
case Instruction::InsertElement:
return InsertElementInst::Create(Ops[0], Ops[1], Ops[2], "");
case Instruction::ExtractElement:
return ExtractElementInst::Create(Ops[0], Ops[1], "");
case Instruction::ShuffleVector:
return new ShuffleVectorInst(Ops[0], Ops[1], CEx->getShuffleMask(), "");

case Instruction::GetElementPtr: {
const auto *GO = cast<GEPOperator>(CEx);
return GetElementPtrInst::Create(GO->getSourceElementType(),
Ops[0],
Ops.slice(1),
GO->getNoWrapFlags(),
"");
}
default:
assert(CEx->getNumOperands() == 2 && "Must be binary operator?");
BinaryOperator *BO = BinaryOperator::Create(
(Instruction::BinaryOps)CEx->getOpcode(), Ops[0], Ops[1], "");
if (isa<OverflowingBinaryOperator>(BO)) {
BO->setHasNoUnsignedWrap(
CEx->getRawSubclassOptionalData()
& OverflowingBinaryOperator::NoUnsignedWrap);
BO->setHasNoSignedWrap(CEx->getRawSubclassOptionalData()
& OverflowingBinaryOperator::NoSignedWrap);
}
if (isa<PossiblyExactOperator>(BO))
BO->setIsExact(CEx->getRawSubclassOptionalData()
& PossiblyExactOperator::IsExact);
return BO;
}
}

#else

/// Convert constant expression to instruction. (Copied from LLVM and modified
/// to work outside the ConstantExpr class; otherwise the function is the same,
/// the only purpose of copying the function is making it work on constant
Expand Down Expand Up @@ -478,6 +533,8 @@ const Instruction *getConstExprAsInstruction(const ConstantExpr *CEx) {
}
}

#endif

/// Generates human-readable C-like identifier for type.
std::string getIdentifierForType(Type *Ty) {
if (auto STy = dyn_cast<StructType>(Ty)) {
Expand Down Expand Up @@ -635,38 +692,73 @@ std::string getIdentifierForValue(
return "<unknown>";
}

/// Retrieve information about a structured type being pointed to by a value.
/// Note: There are two completely different approaches used. Up to LLVM 14,
/// type information can be obtained directly from the value. Since LLVM 15,
/// type information is obtained from calls to debug intrinsics. It is necessary
/// to provide current function name to use the correct debug intrinsic call
/// (there can be multiple different ones).
TypeInfo getPointeeStructTypeInfo(const Value *Val,
const DataLayout *Layout,
[[maybe_unused]] const StringRef &FunName) {
#if LLVM_VERSION_MAJOR >= 15
(void)Layout;
// Look for the type of the value in debug intrinsics
SmallVector<DbgValueInst *> DbgValues;
findDbgValues(DbgValues, const_cast<Value *>(Val));
#if LLVM_VERSION_MAJOR >= 19

/// Returns the debug type of the given Value based on the provided scope
/// (function name). Returns nullptr if the type cannot be determined.
/// In LLVM 19, debug records were introduced. Both debug intrinsics and
/// records are searched to find the type.
DIType *getDbgTypeForValue(const Value *Val, const StringRef &FunName) {
SmallVector<DbgValueInst *> DbgIntrinsics;
SmallVector<DbgVariableRecord *> DbgRecords;
findDbgValues(DbgIntrinsics, const_cast<Value *>(Val), &DbgRecords);
for (auto &Dbg : DbgRecords) {
auto scopeName =
Dbg->getVariable()->getScope()->getSubprogram()->getName();
if (scopeName == FunName) {
return Dbg->getVariable()->getType();
}
}
// If type was not found in debug records, search in debug intrinsics.
for (auto &Dbg : DbgIntrinsics) {
auto scopeName =
Dbg->getVariable()->getScope()->getSubprogram()->getName();
if (scopeName == FunName) {
return Dbg->getVariable()->getType();
}
}
return nullptr;
}

#elif LLVM_VERSION_MAJOR >= 15

/// Returns the debug type of the given Value based on the provided scope
/// (function name). Returns nullptr if the type cannot be determined.
/// The type of the value is determined using debug intrinsics.
DIType *getDbgTypeForValue(const Value *Val, const StringRef &FunName) {
SmallVector<DbgValueInst *> DbgIntrinsics;
findDbgValues(DbgIntrinsics, const_cast<Value *>(Val));
// There can be potentially multiple different dbg info for the same
// value. It is necessary to find the one belonging to the current function.
// The other dbg info can belong to called functions where the value could
// be provided as (void *) and therefore does not have to contain necessary
// information about the pointee type.
DbgValueInst *DbgValue = nullptr;
for (auto &Dbg : DbgValues) {
for (auto &Dbg : DbgIntrinsics) {
auto scopeName =
Dbg->getVariable()->getScope()->getSubprogram()->getName();
if (scopeName == FunName) {
DbgValue = Dbg;
break;
return Dbg->getVariable()->getType();
}
}
if (!DbgValue)
return nullptr;
}

#endif

#if LLVM_VERSION_MAJOR >= 15

/// Retrieve information about a structured type being pointed to by a value.
/// Type information is obtained from calls to debug intrinsics/records. It is
/// necessary to provide current function name to use the correct debug
/// intrinsic call (there can be multiple different ones). The data layout
/// parameter is unused.
TypeInfo getPointeeStructTypeInfo(const Value *Val,
[[maybe_unused]] const DataLayout *Layout,
const StringRef &FunName) {
auto *Ty = getDbgTypeForValue(Val, FunName);
if (!Ty) {
return {"", 0};
const DIType *Ty = DbgValue->getVariable()->getType();
}

// Check if it is a pointer type (derived type)
const DIDerivedType *PtrTy = dyn_cast<DIDerivedType>(Ty);
Expand Down Expand Up @@ -705,7 +797,16 @@ TypeInfo getPointeeStructTypeInfo(const Value *Val,
}

return {typeName, StrTy->getSizeInBits() / 8};
#else
}

#else /* LLVM_VERSION_MAJOR < 15 */

/// Retrieve information about a structured type being pointed to by a value.
/// Type information can be obtained directly from the value and data layout,
/// the function name is unused.
TypeInfo getPointeeStructTypeInfo(const Value *Val,
const DataLayout *Layout,
[[maybe_unused]] const StringRef &FunName) {
// Get the type of the value
Type *Ty = Val->getType();

Expand All @@ -719,9 +820,10 @@ TypeInfo getPointeeStructTypeInfo(const Value *Val,
return {"", 0};

return {StrTy->getName(), Layout->getTypeStoreSize(StrTy)};
#endif
}

#endif /* LLVM_VERSION_MAJOR < 15 */

/// Retrieves the type of the value based on its C source code expression.
const DIType *getCSourceIdentifierType(std::string expr,
const Function *Parent,
Expand Down
9 changes: 9 additions & 0 deletions diffkemp/simpll/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Python interface for the SimpLL library.
"""
from diffkemp.simpll.simpll_lib import ffi, lib
import collections


def _ptrarray_to_list(ptrarray):
Expand Down Expand Up @@ -156,3 +157,11 @@ def get_child(self, sysctl_name):

def get_data(self, sysctl_name):
return self._get_global_variable(sysctl_name, lib.getData)


def get_llvm_build_version():
Version = collections.namedtuple("Version", ["major", "minor", "patch"])
version = ffi.new("int[3]")

lib.getLlvmBuildVersion(version)
return Version(version[0], version[1], version[2])
11 changes: 10 additions & 1 deletion diffkemp/simpll/library/FFI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
#include "library/DiffKempUtils.h"
#include "library/SysctlTable.h"
#include "passes/CalledFunctionsAnalysis.h"
#include <cstring>

#include <llvm/Support/ManagedStatic.h>
#include <llvm/Transforms/Utils/Cloning.h>

#include <cstring>
#include <unordered_map>

/// Map to store LLVMContext objects for modules.
Expand Down Expand Up @@ -323,5 +326,11 @@ void preprocessModuleC(void *Mod, struct builtin_patterns PatternsC) {
preprocessModule(*LLVMMod, nullptr, nullptr, Patterns);
}

void getLlvmBuildVersion(int *out) {
out[0] = LLVM_VERSION_MAJOR;
out[1] = LLVM_VERSION_MINOR;
out[2] = LLVM_VERSION_PATCH;
}

void shutdownSimpLL() { llvm_shutdown(); }
} // extern "C"
Loading