Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Live Variable Analysis #27

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
8 changes: 7 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ ci/docker/Dockerfile
ci/docker/Dockerfile.base
ci/build-image.sh

integration-test/output
integration-test/output
net-ssa-cli/obj
net-ssa-lib/obj
unit-tests/obj
net-ssa-cli/bin
net-ssa-lib/bin
unit-tests/bin
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ jobs:
sudo ./ci/install-lit.sh
sudo ./ci/install-llvm.sh
sudo ./ci/install-mono.sh
dotnet tool install -g dotnet-repl
- name: Build Souffle programs from scratch
run: |
cd $GITHUB_WORKSPACE/souffle && rm -r bin/ && ./build-all-with-docker.sh
Expand Down Expand Up @@ -145,7 +146,7 @@ jobs:
dotnet test --verbosity normal
- name: Generate nuget packages
run: |
./ci/nuget-pack.sh "${{ steps.gitversion.outputs.AssemblySemVer }}" "${{ steps.gitversion.outputs.AssemblySemVer }}" "${{ steps.gitversion.outputs.InformationalVersion }}" "${{ steps.gitversion.outputs.AssemblySemVer }}"
./ci/nuget-pack.sh "${{ steps.gitversion.outputs.AssemblySemVer }}" "${{ steps.gitversion.outputs.AssemblySemVer }}" "${{ steps.gitversion.outputs.InformationalVersion }}" "${{ steps.gitversion.outputs.AssemblySemVer }}" "build/bin/net-ssa/package"
dotnet nuget push build/bin/net-ssa/package/net-ssa-lib.${{ steps.gitversion.outputs.NuGetVersionV2 }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

mirror:
Expand Down
16 changes: 16 additions & 0 deletions ci/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
set -e

CURRENT_DIR=$(dirname "$(readlink -f "$0")")

pushd $CURRENT_DIR/..

rm -rf net-ssa-cli/obj net-ssa-lib/obj unit-test/obj net-ssa-cli/bin net-ssa-lib/bin unit-test/bin

dotnet clean
rm -rf /tmp/build

dotnet build
./ci/nuget-pack.sh "0.0.0" "0.0.0" "0.0.0" "0.0.0" "/tmp/build/bin/net-ssa/package"

popd
4 changes: 3 additions & 1 deletion ci/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
ARG BASE_IMAGE
FROM ${BASE_IMAGE}

ENV PATH="$PATH:/home/ubuntu/.dotnet/tools"

COPY --chown=ubuntu:mygroup . ${NET_SSA_SRC_DIR}

RUN dotnet build && \
RUN ./ci/build.sh && \
dotnet test --verbosity normal && \
lit ./integration-test -vv
4 changes: 3 additions & 1 deletion ci/docker/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ COPY --chown=ubuntu:mygroup ./ci/ ${NET_SSA_SRC_DIR}/ci
RUN sudo ${NET_SSA_SRC_DIR}/ci/install-souffle.sh && \
sudo ${NET_SSA_SRC_DIR}/ci/install-lit.sh && \
sudo ${NET_SSA_SRC_DIR}/ci/install-llvm.sh && \
sudo ${NET_SSA_SRC_DIR}/ci/install-mono.sh
sudo ${NET_SSA_SRC_DIR}/ci/install-mono.sh && \
dotnet tool install -g dotnet-repl

ENV PATH="$PATH:/home/ubuntu/.dotnet/tools"

WORKDIR ${NET_SSA_SRC_DIR}
3 changes: 2 additions & 1 deletion ci/nuget-pack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ VERSION=$1
ASSEMBLY_VERSION=$2
INFORMATIONAL_VERSION=$3
PACKAGE_VERSION=$4
OUTPUT_DIR=$5

pushd $CURRENT_DIR/..

dotnet pack net-ssa.sln -o:build/bin/net-ssa/package --include-symbols --include-source /p:Version=$VERSION /p:AssemblyVersion=$ASSEMBLY_VERSION /p:InformationalVersion=$INFORMATIONAL_VERSION /p:PackageVersion=$PACKAGE_VERSION
dotnet pack net-ssa.sln -o:$OUTPUT_DIR --include-symbols --include-source /p:Version=$VERSION /p:AssemblyVersion=$ASSEMBLY_VERSION /p:InformationalVersion=$INFORMATIONAL_VERSION /p:PackageVersion=$PACKAGE_VERSION

popd
3 changes: 2 additions & 1 deletion integration-test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def _get_llvm_bindir():
config.test_build_root = os.path.join(config.test_source_root, "output")
if not os.path.exists(config.test_build_root):
os.mkdir(config.test_build_root)
config.test_exec_root = config.test_build_root

config.substitutions.append(('%mono', config.mono_bin))
config.substitutions.append(('%mcs', config.mcs_bin))
Expand All @@ -60,7 +61,7 @@ def _get_llvm_bindir():
config.substitutions.append(('%FileCheck', os.path.join(config.llvm_bin_dir, "FileCheck")))
config.substitutions.append(('%test-resources-dir', os.path.join(config.my_src_root, "test-resources")))

env_vars = {'DOTNET_ROOT'}
env_vars = {'DOTNET_ROOT', 'HOME'}
for e in env_vars:
if e in os.environ:
config.environment[e] = os.environ[e]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
class HelloWorld
{
static void Main()
{
for (int i=0; i < 10; i++){
Console.WriteLine(i);
}
}
}
88 changes: 88 additions & 0 deletions integration-test/net-ssa-lib/live-variables/test0/test.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// RUN: %mcs -out:%T/Test.dll %S/program.cs.exclude
// RUN: (export BINARY_PATH=%T/Test.dll && dotnet repl --output-path %t.trx --run %s --exit-after-run)

#i "nuget:/tmp/build/bin/net-ssa/package"
#r "nuget: net-ssa-lib, 0.0.0"
#r "nuget: Mono.Cecil, 0.11.3"
#r "nuget: NUnit, 3.12.0"

using System;
using System.Collections.Generic;

using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;

using NetSsa.Analyses;
using NetSsa.Instructions;

using NUnit.Framework;
using System.Linq;

public static String GetRegisters(IList<Register> registers, BitArray liveVariables){
String result = "";
for (int i=0; i < liveVariables.Length; i++){
if (liveVariables[i]){
result += registers[i].Name + " ";
}
}
return result.Trim();
}

AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(Environment.GetEnvironmentVariable("BINARY_PATH"));

var method = assembly.MainModule.GetType("HelloWorld").GetMethods().First();
Mono.Cecil.Cil.MethodBody body = method.Body;
IRBody irBody = Unstacker.Compute(body);
ControlFlowGraph cfg = new ControlFlowGraph(irBody);
LiveVariableAnalysis lva = new LiveVariableAnalysis(cfg);
lva.Flow();

/*
L_0000: label
L_0001: nop
L_0002: s0 = ldc.i4.0
L_0003: l0 = stloc.0 [s0] -- s0
L_0004: br L_000c
L_0005: label
L_0006: s0 = ldloc.0 [l0]
L_0007: call System.Void System.Console::WriteLine(System.Int32) [s0] -- s0
L_0008: s0 = ldloc.0 [l0]
L_0009: s1 = ldc.i4.1 ---- [s0]
L_000a: s0 = add [s0, s1] --- [s0, s1]
L_000b: l0 = stloc.0 [s0] --- [s0]
L_000c: label
L_000d: s0 = ldloc.0 [l0]
L_000e: s1 = ldc.i4.s 10 ---- [s0]
L_000f: blt L_0005 [s0, s1] -- s0 s1
L_0010: label
L_0011: ret
*/

Assert.AreEqual(irBody.Instructions.Count, 0x12);

Dictionary<int, string> results = new Dictionary<int, string>()
{
{ 0x0, "" },
{ 0x1, "" },
{ 0x2, "" },
{ 0x3, "s0" },
{ 0x4, "" },
{ 0x5, "" },
{ 0x6, "" },
{ 0x7, "s0" },
{ 0x8, "" },
{ 0x9, "s0" },
{ 0xa, "s0 s1" },
{ 0xb, "s0" },
{ 0xc, "" },
{ 0xd, "" },
{ 0xe, "s0" },
{ 0xf, "s0 s1" },
{ 0x10, "" },
{ 0x11, "" },
};

for (int i=0; i < 0x12; i++){
Assert.AreEqual(results[i], GetRegisters(irBody.Registers, lva.IN[irBody.Instructions.ElementAt(i)]), i.ToString("x"));
}
76 changes: 76 additions & 0 deletions net-ssa-lib/analyses/DataFlowAnalysis.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System.Collections.Generic;
using NetSsa.Instructions;
using System.Linq;

namespace NetSsa.Analyses
{
public abstract class BackwardsDataFlowAnalysis<Data>
{
public BackwardsDataFlowAnalysis(ControlFlowGraph cfg){
this.cfg = cfg;
this.irBody = cfg.IRBody;
}

protected ControlFlowGraph cfg;
protected IRBody irBody;

protected abstract Data Meet(Data a, Data b); // This is expected to create a copy of the input data
protected virtual Data MeetSuccessors(TacInstruction leader){
IList<TacInstruction> successors = cfg.BasicBlockSuccessors(leader);
Data result = IN[successors[0]];
for (int i = 1; i < successors.Count; i++){
result = Meet(result, IN[successors[i]]);
}
return result;
}

protected abstract Data Gen(TacInstruction leader);
protected abstract Data Kill(TacInstruction leader);
protected abstract bool TransferInstruction(TacInstruction instruction, Data incomingData);

protected virtual void Transfer(TacInstruction leader, Data incomingData, ref bool changed){
IList<TacInstruction> instructions = cfg.BasicBlockInstructions(leader).ToList();

bool currentChanged = TransferInstruction(instructions[instructions.Count-1], incomingData);
for (int i=instructions.Count-2; i >= 0; i--){
currentChanged = currentChanged || TransferInstruction(instructions[i], IN[instructions[i+1]]);
}

changed = currentChanged;
}

protected abstract Data InitBasicBlock(TacInstruction leader);

public IDictionary<TacInstruction, Data> IN = new Dictionary<TacInstruction, Data>();
public IDictionary<TacInstruction, Data> OUT = new Dictionary<TacInstruction, Data>();

protected virtual IEnumerable<TacInstruction> GetExitBasicBlocks(){
foreach (TacInstruction leader in cfg.Leaders()){
if (cfg.BasicBlockSuccessors(leader).Count == 0){
yield return leader;
}
}
}

protected void InitializeBasicBlocks(){
foreach (TacInstruction leader in cfg.Leaders()){
foreach (TacInstruction instruction in cfg.BasicBlockInstructions(leader)){
IN[instruction] = InitBasicBlock(leader);
}
}
}

public void Flow(){
InitializeBasicBlocks();
bool inChanged;
do {
inChanged = false;
foreach (TacInstruction leader in cfg.Leaders().Except(GetExitBasicBlocks())){
OUT[leader] = MeetSuccessors(leader);
Transfer(leader, OUT[leader], ref inChanged);
}
} while (inChanged);
}
}

}
81 changes: 81 additions & 0 deletions net-ssa-lib/analyses/LiveVariableAnalysis.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Collections.Generic;
using System.Collections;
using System;
using NetSsa.Instructions;
using System.Linq;

namespace NetSsa.Analyses{
public class LiveVariableAnalysis : BackwardsDataFlowAnalysis<BitArray> {
public LiveVariableAnalysis(ControlFlowGraph cfg) : base(cfg) {}

private int NumberOfRegisters(){
return irBody.Registers.Count;
}

// TO-DO: Find faster implementation
private int RegisterIndex(Register register){
return irBody.Registers.IndexOf(register);
}

// TO-DO: Find faster implementation
private bool AreEqual(BitArray a, BitArray b) {
if (a.Length != b.Length){
return false;
}

for (int i=0; i < a.Length; i++){
if (a[i] != b[i]){
return false;
}
}

return true;
}

protected override BitArray Meet(BitArray a, BitArray b) {
return a.Or(b);
}

protected override BitArray Gen(TacInstruction instruction) {
BitArray result = new BitArray(NumberOfRegisters());
foreach (int index in instruction.Operands.OfType<Register>().Select(r => RegisterIndex(r))){
result.Set(index, true);
}

return result;
}

protected override BitArray Kill(TacInstruction instruction) {
BitArray result = new BitArray(NumberOfRegisters());

if (instruction.Result is Register){
result.Set(RegisterIndex((Register)instruction.Result), true);
}

return result;
}

protected override bool TransferInstruction(TacInstruction instruction, BitArray incomingData){
BitArray gen = Gen(instruction);
BitArray kill = Kill(instruction);

// The difference of two sets S T is computed by
// complementing the bit vector of T, and then taking the logical AND of that
// complement, with the bit vector for S.

BitArray newValue = gen.Or(kill.Not().And(incomingData));

BitArray old = IN[instruction];
if (AreEqual(old, newValue)){
return false;
} else {
IN[instruction] = newValue;
return true;
}
}

protected override BitArray InitBasicBlock(TacInstruction leader){
return new BitArray(NumberOfRegisters());
}
}
}
Loading