~cypheon/rapid

3d95894c87e8b3b1229cd04013cf636d55d5d655 — Johann Rudloff 9 months ago f3b86d9
Remove unused subdirectory "llvm"
7 files changed, 0 insertions(+), 287 deletions(-)

M CMakeLists.txt
D llvm/.gitignore
D llvm/CMakeLists.txt
D llvm/Passes/LowerRapidIntrinsics.cpp
D llvm/lit.cfg
D llvm/lit.cfg.in
D llvm/test/lower_unboxing.ll
M CMakeLists.txt => CMakeLists.txt +0 -1
@@ 30,7 30,6 @@ configure_file("${rapidc_config_file}.in" "${rapidc_config_file}" @ONLY)

add_idris_package(rapidc rapidc.ipkg ${rapidc_source_files} ${rapidc_config_file})

add_subdirectory(llvm)
add_subdirectory(rts)

add_custom_target(rapidc_test

D llvm/.gitignore => llvm/.gitignore +0 -7
@@ 1,7 0,0 @@
.clangd
test/Output
/Makefile
cmake_install.cmake
cmake.lit.cfg
/librapid.so
*.plist

D llvm/CMakeLists.txt => llvm/CMakeLists.txt +0 -50
@@ 1,50 0,0 @@
cmake_minimum_required(VERSION 3.12)
project(RapidLLVMPasses)

find_package(LLVM REQUIRED CONFIG)
find_program(LLVMLIT NAMES lit llvm-lit llvm-lit10 llvm-lit11 llvm-lit12 REQUIRED)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")

include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})

if (${LLVM_ENABLE_RTTI})
else()
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif()

add_library(rapid MODULE Passes/LowerRapidIntrinsics.cpp)

set_property(TARGET rapid PROPERTY CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Allow undefined symbols
target_link_libraries(rapid
  "$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>")

add_custom_command(
  OUTPUT "${RAPID_SUPPORT_BINARIES}/rapid/librapid.so"
  COMMAND "cmake" ARGS "-E" copy_if_different $<TARGET_FILE:rapid> "${RAPID_SUPPORT_BINARIES}/rapid"
  DEPENDS rapid
  )

# workaround for older CMake version
if (${RAPID_SUPPORT_BINARIES} MATCHES .)
  add_custom_target(rapid_install_llvm_passes ALL
    DEPENDS "${RAPID_SUPPORT_BINARIES}/rapid/librapid.so"
    )
endif()

configure_file("lit.cfg.in" "cmake.lit.cfg")

add_custom_target(rapid_test_llvm_passes
                  COMMAND ${LLVMLIT} --config-prefix cmake.lit -v "${CMAKE_CURRENT_BINARY_DIR}"
                  WORKING_DIRECTORY .
                  DEPENDS rapid)

if (NOT TARGET test)
  add_custom_target(test)
endif()
add_dependencies(test rapid_test_llvm_passes)

D llvm/Passes/LowerRapidIntrinsics.cpp => llvm/Passes/LowerRapidIntrinsics.cpp +0 -165
@@ 1,165 0,0 @@
#include "llvm/Pass.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

using namespace llvm;

// The next function is a part of Julia. License is MIT: https://julialang.org/license
template<typename TIterator>
static void replaceInstruction(
    Instruction *oldInstruction,
    Value *newInstruction,
    TIterator &it)
{
    if (newInstruction != oldInstruction) {
        oldInstruction->replaceAllUsesWith(newInstruction);
        it = oldInstruction->eraseFromParent();
    }
    else {
        ++it;
    }
}


namespace {
struct LowerRapidIntrinsics : public PassInfoMixin<LowerRapidIntrinsics> {
  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
    runOnFunction(F);
    return PreservedAnalyses::none();
  }

  Value *lowerBoxint(CallInst *target, Function &F) {
    assert(target->getNumOperands() == 2);
    auto arg0 = target->getArgOperand(0);

    auto &ctx = target->getContext();

    IRBuilder<> builder(ctx);
    builder.SetInsertPoint(target);

    auto shifted = builder.CreateShl(arg0, ConstantInt::get(arg0->getType(), 1));
    auto tagged = builder.CreateOr(shifted, ConstantInt::get(arg0->getType(), 1));
    auto castToPtr = builder.CreateIntToPtr(tagged, PointerType::get(ctx, 2));
    auto castToAS1 = builder.CreateAddrSpaceCast(castToPtr, target->getType());
    return castToAS1;
  }


  Value *lowerUnboxint(CallInst *target, Function &F) {
    assert(target->getNumOperands() == 2);
    auto arg0 = target->getArgOperand(0);

    auto &ctx = target->getContext();

    IRBuilder<> builder(ctx);
    builder.SetInsertPoint(target);

    auto castToAS2 = builder.CreateAddrSpaceCast(arg0, PointerType::get(ctx, 2));
    auto castToInt = builder.CreatePtrToInt(castToAS2, Type::getInt64Ty(ctx));
    auto shifted = builder.CreateAShr(castToInt, ConstantInt::get(castToInt->getType(), 1));
    return shifted;
  }

  Value *lowerIsDirect(CallInst *target, Function &F) {
    assert(target->getNumOperands() == 2);
    auto arg0 = target->getArgOperand(0);

    auto &ctx = target->getContext();

    IRBuilder<> builder(ctx);
    builder.SetInsertPoint(target);

    auto castToAS2 = builder.CreateAddrSpaceCast(arg0, PointerType::get(ctx, 2));
    auto castToInt = builder.CreatePtrToInt(castToAS2, Type::getInt64Ty(ctx));
    auto masked = builder.CreateAnd(castToInt, ConstantInt::get(castToInt->getType(), 1));
    auto cmpEq1 = builder.CreateICmpEQ(masked, ConstantInt::get(castToInt->getType(), 1));
    return cmpEq1;
  }

  bool runOnFunction(Function &F) {
    auto &M = *F.getParent();
    Function *rapid_boxint = M.getFunction("llvm.rapid.boxint");
    Function *rapid_unboxint = M.getFunction("llvm.rapid.unboxint");
    Function *rapid_isdirect = M.getFunction("llvm.rapid.isdirect");

    for (BasicBlock &BB : F) {
      for (auto it = BB.begin(); it != BB.end();) {
        auto *CI = dyn_cast<CallInst>(&*it);
        if (!CI) {
          ++it;
          continue;
        }

        auto callee = CI->getCalledFunction();
        if (!callee) {
          ++it;
          continue;
        }

        if (callee == rapid_boxint) {
          //errs().write_escaped("found rapid.boxint") << '\n';
          replaceInstruction(CI, lowerBoxint(CI, F), it);
        } else if (callee == rapid_unboxint) {
          //errs().write_escaped("found rapid.unboxint") << '\n';
          replaceInstruction(CI, lowerUnboxint(CI, F), it);
        } else if (callee == rapid_isdirect) {
          //errs().write_escaped("found rapid.isdirect") << '\n';
          replaceInstruction(CI, lowerIsDirect(CI, F), it);
        } else {
          ++it;
        }
      }
    }

    return false;
  }
};

struct LowerRapidIntrinsicsLegacy : public FunctionPass {
  static char ID;
  LowerRapidIntrinsics ModernPass;
  LowerRapidIntrinsicsLegacy() : FunctionPass(ID) {}

  bool doInitialization(Module &M) override {
    return false;
  }

  bool runOnFunction(Function &F) override {
    return ModernPass.runOnFunction(F);
  }
};
}

// Register pass with the legacy pass manager
char LowerRapidIntrinsicsLegacy::ID = 0;
static RegisterPass<LowerRapidIntrinsicsLegacy> X("rapid-lower", "Lower Rapid Intrinsics",
                             false /* Only looks at CFG */,
                             false /* Analysis Pass */);

// Register pass with the new pass manager
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
  return {
    LLVM_PLUGIN_API_VERSION, "LowerRapidIntrinsics", "0.0.1",
    [](PassBuilder &PB) {
      PB.registerPipelineParsingCallback(
        [](StringRef Name, FunctionPassManager &FPM,
        ArrayRef<PassBuilder::PipelineElement>) {
          if(Name == "rapid-lower"){
            FPM.addPass(LowerRapidIntrinsics());
            return true;
          }
          return false;
        }
      );
    }
  };
}

D llvm/lit.cfg => llvm/lit.cfg +0 -8
@@ 1,8 0,0 @@
import lit.formats
import os

config.name = "rapid_it"
config.suffixes = [".ll"]
config.test_format = lit.formats.ShTest()
config.test_source_root = None
config.test_exec_root = None

D llvm/lit.cfg.in => llvm/lit.cfg.in +0 -8
@@ 1,8 0,0 @@
import lit.formats
import os

config.name = "rapid_it"
config.suffixes = [".ll"]
config.test_format = lit.formats.ShTest()
config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@/test"
config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@/test"

D llvm/test/lower_unboxing.ll => llvm/test/lower_unboxing.ll +0 -48
@@ 1,48 0,0 @@
; RUN: opt -load-pass-plugin=../librapid.so -passes=rapid-lower -S < %s | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128-ni:1"

%Object = type {
    i64 ; object header
  , [0 x i8*] ; payload
}

%ObjPtr = type ptr addrspace(1)

declare fastcc noalias %ObjPtr @llvm.rapid.boxint(i64) "gc-leaf-function" readnone nounwind
declare fastcc i64 @llvm.rapid.unboxint(%ObjPtr noalias nocapture nofree) "gc-leaf-function" readnone nounwind
declare fastcc i1 @llvm.rapid.isdirect(%ObjPtr noalias nocapture nofree) "gc-leaf-function" readnone nounwind

define fastcc %ObjPtr @test_box(i64 %val) {
; CHECK: @test_box
; CHECK: shl i64
; CHECK-NEXT: or i64
; CHECK-NEXT: inttoptr
; CHECK-NEXT: addrspacecast
; CHECK-NOT: @llvm.rapid.boxint
; CHECK: ret
  %box = call fastcc %ObjPtr @llvm.rapid.boxint(i64 %val)
  ret %ObjPtr %box
}

define fastcc i64 @test_unbox(%ObjPtr %p) {
; CHECK: @test_unbox
; CHECK: addrspacecast
; CHECK-NEXT: ptrtoint
; CHECK-NEXT: ashr i64
; CHECK-NOT: @llvm.rapid.unboxint
; CHECK: ret
  %int = call fastcc i64 @llvm.rapid.unboxint(%ObjPtr %p)
  ret i64 %int
}

define fastcc i1 @test_isdirect(%ObjPtr %p) {
; CHECK: @test_isdirect
; CHECK: addrspacecast
; CHECK-NEXT: ptrtoint
; CHECK-NEXT: and i64
; CHECK-NEXT: icmp eq i64
; CHECK-NOT: @llvm.rapid.isdirect
; CHECK: ret
  %direct = call fastcc i1 @llvm.rapid.isdirect(%ObjPtr %p)
  ret i1 %direct
}