diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 889d9a4..20a3ae8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,26 +21,24 @@ jobs:
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- - name: Get next version from TestPyPI
+ - name: Get next version from PyPI
id: get_next_version
run: |
PACKAGE="pysvf"
- INDEX_URL="https://test.pypi.org/pypi/$PACKAGE/json"
-
+ INDEX_URL="https://pypi.org/pypi/$PACKAGE/json"
+
echo "Querying $INDEX_URL ..."
- VERSIONS=$(curl -s "$INDEX_URL" | jq -r '.releases | keys[]' | grep -E '^1\.0\.0\.[0-9]+$')
-
+ VERSIONS=$(curl -s "$INDEX_URL" | jq -r '.releases | keys[]' | grep -E '^1\.0\.0\.[0-9]+$' || true)
+
if [ -z "$VERSIONS" ]; then
- LAST_VERSION="1.0.0.0"
+ NEXT_VERSION="1.0.0.0"
else
LAST_VERSION=$(echo "$VERSIONS" | sort -V | tail -n 1)
+ echo "Last version: $LAST_VERSION"
+ NEXT_VERSION=$(echo "$LAST_VERSION" | awk -F. '{$NF+=1; print $1 "." $2 "." $3 "." $4}')
fi
-
- echo "Last version: $LAST_VERSION"
-
- NEXT_VERSION=$(echo "$LAST_VERSION" | awk -F. '{$NF+=1; print $1 "." $2 "." $3 "." $4}')
+
echo "Next version: $NEXT_VERSION"
-
echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT
stubtest:
@@ -200,14 +198,13 @@ jobs:
echo "Built wheel files:"
ls -lh dist/
- - name: Publish to TestPyPI
+ - name: Publish to PyPI
env:
TWINE_USERNAME: __token__
- TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: |
cd SVF-Python
- pip install twine
- twine upload --repository testpypi dist/* --verbose
+ twine upload dist/* --verbose
- name: Upload Python wheels
uses: actions/upload-artifact@v4
diff --git a/README.md b/README.md
index 3650cb4..1b147cd 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@
## News
+* Pysvf is now available on [PyPI](https://pypi.org/project/pysvf/). The previous Test PyPI distribution is no longer maintained.
+* Thanks to [mgree](https://github.com/mgree) for contributing the `FunObjVar::getSourceLoc` binding ([#46](https://github.com/SVF-tools/SVF-Python/pull/46)).
* SVF-Python now supports MTA bindings and more pointer analysis strategies(AndersenWaveDiff, AndersenBase, and Steensgaard bindings). (Thank [JoelYYoung](https://github.com/JoelYYoung) for his help!).
## 1. Introduction
@@ -12,17 +14,17 @@
Pysvf can be installed in two ways:
-### Method 1: Install via pip (Test PyPI)
+### Method 1: Install via pip
#### Requirements
-- Python 3.8 - 3.11
+- Python 3.8 - 3.12
- OS: Linux X86-64, Linux Arm64, MacOS
#### Install Command
```bash
-python3 -m pip install -i https://test.pypi.org/simple/ pysvf
+pip install pysvf
````
### Method 2: Build from Source
diff --git a/demo/icfg.ipynb b/demo/icfg.ipynb
index 08da047..191642f 100644
--- a/demo/icfg.ipynb
+++ b/demo/icfg.ipynb
@@ -693,12 +693,12 @@
"| | `getLHSVarID` | Get the ID of the LHS variable of the load statement |\n",
"| | `getRHSVar` | Get the RHS variable of the load statement |\n",
"| | `getRHSVarID` | Get the ID of the RHS variable of the load statement |\n",
- "| `CallPE` | `getCallSite` | Get the call site |\n",
- "| | `getLHSVar` | Get the LHS variable of the call PE |\n",
- "| | `getLHSVarID` | Get the ID of the LHS variable of the call PE |\n",
- "| | `getRHSVar` | Get the RHS variable of the call PE |\n",
- "| | `getRHSVarID` | Get the ID of the RHS variable of the call PE |\n",
- "| | `getFunEntryICFGNode` | Get the function entry ICFG node |\n",
+ "| `CallPE` | `getFunEntryICFGNode` | Get the function entry ICFG node |\n",
+ "| (MultiOpndStmt) | `getOpCallICFGNode(idx)` | Get the CallICFGNode of the i-th operand |\n",
+ "| | `getOpCallICFGNodes` | Get all call site ICFGNodes |\n",
+ "| | `getRes` | Get the result variable (formal parameter) |\n",
+ "| | `getOpVar(idx)` | Get the i-th operand variable (actual parameter) |\n",
+ "| | `getOpVarNum` | Get the number of operands |\n",
"| `RetPE` | `getCallSite` | Get the call site |\n",
"| | `getLHSVar` | Get the LHS variable of the return PE |\n",
"| | `getLHSVarID` | Get the ID of the LHS variable of the return PE |\n",
@@ -809,12 +809,12 @@
"| | `getLHSVarID` | Get the ID of the LHS variable of the load statement |\n",
"| | `getRHSVar` | Get the RHS variable of the load statement |\n",
"| | `getRHSVarID` | Get the ID of the RHS variable of the load statement |\n",
- "| `CallPE` | `getCallSite` | Get the call site |\n",
- "| | `getLHSVar` | Get the LHS variable of the call PE |\n",
- "| | `getLHSVarID` | Get the ID of the LHS variable of the call PE |\n",
- "| | `getRHSVar` | Get the RHS variable of the call PE |\n",
- "| | `getRHSVarID` | Get the ID of the RHS variable of the call PE |\n",
- "| | `getFunEntryICFGNode` | Get the function entry ICFG node |\n",
+ "| `CallPE` | `getFunEntryICFGNode` | Get the function entry ICFG node |\n",
+ "| (MultiOpndStmt) | `getOpCallICFGNode(idx)` | Get the CallICFGNode of the i-th operand |\n",
+ "| | `getOpCallICFGNodes` | Get all call site ICFGNodes |\n",
+ "| | `getRes` | Get the result variable (formal parameter) |\n",
+ "| | `getOpVar(idx)` | Get the i-th operand variable (actual parameter) |\n",
+ "| | `getOpVarNum` | Get the number of operands |\n",
"| `RetPE` | `getCallSite` | Get the call site |\n",
"| | `getLHSVar` | Get the LHS variable of the return PE |\n",
"| | `getLHSVarID` | Get the ID of the LHS variable of the return PE |\n",
@@ -980,12 +980,12 @@
"| | `getLHSVarID` | Get the ID of the LHS variable of the load statement |\n",
"| | `getRHSVar` | Get the RHS variable of the load statement |\n",
"| | `getRHSVarID` | Get the ID of the RHS variable of the load statement |\n",
- "| `CallPE` | `getCallSite` | Get the call site |\n",
- "| | `getLHSVar` | Get the LHS variable of the call PE |\n",
- "| | `getLHSVarID` | Get the ID of the LHS variable of the call PE |\n",
- "| | `getRHSVar` | Get the RHS variable of the call PE |\n",
- "| | `getRHSVarID` | Get the ID of the RHS variable of the call PE |\n",
- "| | `getFunEntryICFGNode` | Get the function entry ICFG node |\n",
+ "| `CallPE` | `getFunEntryICFGNode` | Get the function entry ICFG node |\n",
+ "| (MultiOpndStmt) | `getOpCallICFGNode(idx)` | Get the CallICFGNode of the i-th operand |\n",
+ "| | `getOpCallICFGNodes` | Get all call site ICFGNodes |\n",
+ "| | `getRes` | Get the result variable (formal parameter) |\n",
+ "| | `getOpVar(idx)` | Get the i-th operand variable (actual parameter) |\n",
+ "| | `getOpVarNum` | Get the number of operands |\n",
"| `RetPE` | `getCallSite` | Get the call site |\n",
"| | `getLHSVar` | Get the LHS variable of the return PE |\n",
"| | `getLHSVarID` | Get the ID of the LHS variable of the return PE |\n",
@@ -1044,213 +1044,7 @@
},
"collapsed": false
},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "CopyStmt: lhs_var=DummyValVar ID: 1, rhs_var=ConstNullPtrValVar ID: 0\n",
- " ptr null { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 5\n",
- " i8 37 { constant data }, rhs_var=ConstIntObjVar ID: 6\n",
- " i8 37 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 7\n",
- " i8 100 { constant data }, rhs_var=ConstIntObjVar ID: 8\n",
- " i8 100 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 9\n",
- " i8 10 { constant data }, rhs_var=ConstIntObjVar ID: 10\n",
- " i8 10 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 11\n",
- " i8 0 { constant data }, rhs_var=ConstIntObjVar ID: 12\n",
- " i8 0 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 48\n",
- " i32 3 { constant data }, rhs_var=ConstIntObjVar ID: 49\n",
- " i32 3 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 45\n",
- " i64 1 { constant data }, rhs_var=ConstIntObjVar ID: 46\n",
- " i64 1 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 42\n",
- " i32 5 { constant data }, rhs_var=ConstIntObjVar ID: 43\n",
- " i32 5 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 39\n",
- " i64 0 { constant data }, rhs_var=ConstIntObjVar ID: 40\n",
- " i64 0 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 55\n",
- " i32 1 { constant data }, rhs_var=ConstIntObjVar ID: 56\n",
- " i32 1 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 21\n",
- " i32 0 { constant data }, rhs_var=ConstIntObjVar ID: 22\n",
- " i32 0 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 60\n",
- " i1 false { constant data }, rhs_var=ConstIntObjVar ID: 61\n",
- " i1 false { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 36\n",
- " i64 8 { constant data }, rhs_var=ConstIntObjVar ID: 37\n",
- " i64 8 { constant data }\n",
- "AddrStmt: lhs_var=ConstIntValVar ID: 62\n",
- " i1 true { constant data }, rhs_var=ConstIntObjVar ID: 63\n",
- " i1 true { constant data }\n",
- "AddrStmt: lhs_var=GlobalValVar ID: 4\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalObjVar ID: 13\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n",
- "GepStmt: lhs_var=GepValVar ID: 86 with offset_0\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n",
- "StoreStmt: lhs_var=GepValVar ID: 86 with offset_0\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 5\n",
- " i8 37 { constant data }\n",
- "GepStmt: lhs_var=GepValVar ID: 87 with offset_1\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n",
- "StoreStmt: lhs_var=GepValVar ID: 87 with offset_1\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 7\n",
- " i8 100 { constant data }\n",
- "GepStmt: lhs_var=GepValVar ID: 88 with offset_2\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n",
- "StoreStmt: lhs_var=GepValVar ID: 88 with offset_2\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 9\n",
- " i8 10 { constant data }\n",
- "GepStmt: lhs_var=GepValVar ID: 89 with offset_3\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n",
- "StoreStmt: lhs_var=GepValVar ID: 89 with offset_3\n",
- " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 11\n",
- " i8 0 { constant data }\n",
- "AddrStmt: lhs_var=FunValVar ID: 14\n",
- "add_or_sub, rhs_var=FunObjVar ID: 15 (base object)\n",
- "add_or_sub\n",
- "AddrStmt: lhs_var=FunValVar ID: 31\n",
- "main, rhs_var=FunObjVar ID: 32 (base object)\n",
- "main\n",
- "AddrStmt: lhs_var=FunValVar ID: 67\n",
- "__memcpy_chk, rhs_var=FunObjVar ID: 68 (base object)\n",
- "__memcpy_chk\n",
- "AddrStmt: lhs_var=FunValVar ID: 64\n",
- "llvm.objectsize.i64.p0, rhs_var=FunObjVar ID: 65 (base object)\n",
- "llvm.objectsize.i64.p0\n",
- "AddrStmt: lhs_var=FunValVar ID: 70\n",
- "printf, rhs_var=FunObjVar ID: 71 (base object)\n",
- "printf\n",
- "PhiStmt: res_var=RetValPN ID: 16 unique return node for function add_or_sub, op_var_num=1\n",
- "PhiStmt: res_var=RetValPN ID: 33 unique return node for function main, op_var_num=1\n",
- "CmpStmt: predicate=33, res=ValVar ID: 20\n",
- " %tobool = icmp ne i32 %flag, 0 , op_var0=ArgValVar ID: 19\n",
- " i32 %flag { 2nd arg add_or_sub }, op_var1=ConstIntValVar ID: 21\n",
- " i32 0 { constant data }\n",
- "BranchStmt: successors=[(, 1), (, 0)], condition=ValVar ID: 20\n",
- " %tobool = icmp ne i32 %flag, 0 \n",
- "BinaryOPStmt: opcode=13, res=ValVar ID: 24\n",
- " %add = add nsw i32 %a, %b , op_var_0=ArgValVar ID: 17\n",
- " i32 %a { 0th arg add_or_sub }, op_var_1=ArgValVar ID: 18\n",
- " i32 %b { 1st arg add_or_sub }\n",
- "BinaryOPStmt: opcode=15, res=ValVar ID: 27\n",
- " %sub = sub nsw i32 %a, %b , op_var_0=ArgValVar ID: 17\n",
- " i32 %a { 0th arg add_or_sub }, op_var_1=ArgValVar ID: 18\n",
- " i32 %b { 1st arg add_or_sub }\n",
- "BranchStmt: successors=[(, 1)], condition=ConstNullPtrValVar ID: 0\n",
- " ptr null { constant data }\n",
- "BranchStmt: successors=[(, 1)], condition=ConstNullPtrValVar ID: 0\n",
- " ptr null { constant data }\n",
- "PhiStmt: res_var=ValVar ID: 29\n",
- " %result.0 = phi i32 [ %add, %if.then ], [ %sub, %if.else ] , op_var_num=2\n",
- "AddrStmt: lhs_var=ValVar ID: 34\n",
- " %0 = alloca i8, i64 8, align 8 , rhs_var=StackObjVar ID: 35\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "GepStmt: lhs_var=ValVar ID: 38\n",
- " %arrayidx = getelementptr inbounds i32, ptr %0, i64 0 , rhs_var=ValVar ID: 34\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "StoreStmt: lhs_var=ValVar ID: 38\n",
- " %arrayidx = getelementptr inbounds i32, ptr %0, i64 0 , rhs_var=ConstIntValVar ID: 42\n",
- " i32 5 { constant data }\n",
- "GepStmt: lhs_var=ValVar ID: 44\n",
- " %arrayidx1 = getelementptr inbounds i32, ptr %0, i64 1 , rhs_var=ValVar ID: 34\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "StoreStmt: lhs_var=ValVar ID: 44\n",
- " %arrayidx1 = getelementptr inbounds i32, ptr %0, i64 1 , rhs_var=ConstIntValVar ID: 48\n",
- " i32 3 { constant data }\n",
- "GepStmt: lhs_var=ValVar ID: 50\n",
- " %arrayidx2 = getelementptr inbounds i32, ptr %0, i64 0 , rhs_var=ValVar ID: 34\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "LoadStmt: lhs_var=ValVar ID: 51\n",
- " %1 = load i32, ptr %arrayidx2, align 4 , rhs_var=ValVar ID: 50\n",
- " %arrayidx2 = getelementptr inbounds i32, ptr %0, i64 0 \n",
- "GepStmt: lhs_var=ValVar ID: 52\n",
- " %arrayidx3 = getelementptr inbounds i32, ptr %0, i64 1 , rhs_var=ValVar ID: 34\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "LoadStmt: lhs_var=ValVar ID: 53\n",
- " %2 = load i32, ptr %arrayidx3, align 4 , rhs_var=ValVar ID: 52\n",
- " %arrayidx3 = getelementptr inbounds i32, ptr %0, i64 1 \n",
- "CallPE: callsite=CallICFGNode22 {fun: main}\n",
- "CallPE: [Var17 <-- Var51]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var18 <-- Var53]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var19 <-- Var55]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- ", lhs_var=ArgValVar ID: 17\n",
- " i32 %a { 0th arg add_or_sub }, rhs_var=ValVar ID: 51\n",
- " %1 = load i32, ptr %arrayidx2, align 4 \n",
- "CallPE: callsite=CallICFGNode22 {fun: main}\n",
- "CallPE: [Var17 <-- Var51]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var18 <-- Var53]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var19 <-- Var55]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- ", lhs_var=ArgValVar ID: 18\n",
- " i32 %b { 1st arg add_or_sub }, rhs_var=ValVar ID: 53\n",
- " %2 = load i32, ptr %arrayidx3, align 4 \n",
- "CallPE: callsite=CallICFGNode22 {fun: main}\n",
- "CallPE: [Var17 <-- Var51]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var18 <-- Var53]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var19 <-- Var55]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- ", lhs_var=ArgValVar ID: 19\n",
- " i32 %flag { 2nd arg add_or_sub }, rhs_var=ConstIntValVar ID: 55\n",
- " i32 1 { constant data }\n",
- "RetPE: callsite=CallICFGNode22 {fun: main}\n",
- "CallPE: [Var17 <-- Var51]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var18 <-- Var53]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- "CallPE: [Var19 <-- Var55]\t\n",
- "ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n",
- ", lhs_var=ValVar ID: 54\n",
- " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) , rhs_var=RetValPN ID: 16 unique return node for function add_or_sub\n",
- "AddrStmt: lhs_var=ValVar ID: 57\n",
- " %3 = alloca i8, i64 8, align 8 , rhs_var=StackObjVar ID: 58\n",
- " %3 = alloca i8, i64 8, align 8 \n",
- "GepStmt: lhs_var=GepValVar ID: 90 with offset_0\n",
- " %3 = alloca i8, i64 8, align 8 , rhs_var=ValVar ID: 57\n",
- " %3 = alloca i8, i64 8, align 8 \n",
- "GepStmt: lhs_var=GepValVar ID: 91 with offset_0\n",
- " %0 = alloca i8, i64 8, align 8 , rhs_var=ValVar ID: 34\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "LoadStmt: lhs_var=DummyValVar ID: 92, rhs_var=GepValVar ID: 91 with offset_0\n",
- " %0 = alloca i8, i64 8, align 8 \n",
- "StoreStmt: lhs_var=GepValVar ID: 90 with offset_0\n",
- " %3 = alloca i8, i64 8, align 8 , rhs_var=DummyValVar ID: 92\n",
- "CopyStmt: lhs_var=ValVar ID: 66\n",
- " %call4 = call ptr @__memcpy_chk(ptr noundef %3, ptr noundef %0, i64 noundef 8, i64 noundef %4) #4 , rhs_var=ValVar ID: 57\n",
- " %3 = alloca i8, i64 8, align 8 \n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"for node in cfg.getNodes():\n",
" for stmt in node.getSVFStmts():\n",
@@ -1274,7 +1068,7 @@
" print(\"StoreStmt: lhs_var={}, rhs_var={}\".format(store_stmt.getLHSVar(), store_stmt.getRHSVar()))\n",
" elif isinstance(stmt, pysvf.CallPE):\n",
" call_pe = stmt.asCallPE()\n",
- " print(\"CallPE: callsite={}, lhs_var={}, rhs_var={}\".format(call_pe.getCallSite(), call_pe.getLHSVar(), call_pe.getRHSVar()))\n",
+ " print(\"CallPE: entry={}, res={}, num_opnds={}\".format(call_pe.getFunEntryICFGNode(), call_pe.getRes(), call_pe.getOpVarNum()))\n",
" elif isinstance(stmt, pysvf.RetPE):\n",
" ret_pe = stmt.asRetPE()\n",
" print(\"RetPE: callsite={}, lhs_var={}, rhs_var={}\".format(ret_pe.getCallSite(), ret_pe.getLHSVar(), ret_pe.getRHSVar()))\n",
diff --git a/demo/pag.ipynb b/demo/pag.ipynb
index 8077696..fddf2a8 100644
--- a/demo/pag.ipynb
+++ b/demo/pag.ipynb
@@ -36,7 +36,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-28T11:45:40.163290Z",
@@ -44,21 +44,8 @@
},
"collapsed": false
},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Looking in indexes: https://test.pypi.org/simple/\r\n",
- "Requirement already satisfied: pysvf in /Users/z5489735/PycharmProjects/Amei/.venv/lib/python3.9/site-packages (0.0.0)\r\n"
- ]
- }
- ],
- "source": [
- "# bash install pip install pysvf from testpypi\n",
- "\n",
- "!pip install pysvf --index-url https://test.pypi.org/simple/"
- ]
+ "outputs": [],
+ "source": "# Install pysvf from PyPI\n\n!pip install pysvf"
},
{
"cell_type": "code",
@@ -656,4 +643,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
-}
+}
\ No newline at end of file
diff --git a/pybind/SVFIR.cpp b/pybind/SVFIR.cpp
index 6ef2b46..84bf9af 100644
--- a/pybind/SVFIR.cpp
+++ b/pybind/SVFIR.cpp
@@ -120,11 +120,6 @@ void bind_svf_stmt(py::module& m) {
py::class_(m, "LoadStmt");
- py::class_(m, "CallPE")
- .def("getCallSite", &CallPE::getCallSite, "Get the call site")
- .def("getFunEntryICFGNode", &CallPE::getFunEntryICFGNode, py::return_value_policy::reference,
- "Get the function entry ICFG node");
-
py::class_(m, "RetPE")
.def("getCallSite", &RetPE::getCallSite, "Get the call site")
.def("getFunExitICFGNode", &RetPE::getFunExitICFGNode, py::return_value_policy::reference,
@@ -155,6 +150,14 @@ void bind_svf_stmt(py::module& m) {
return py::make_iterator(stmt.opVarBegin(), stmt.opVerEnd());
}, py::keep_alive<0, 1>()); // Keep the iterator alive while iterating
+ py::class_(m, "CallPE")
+ .def("getOpCallICFGNode", &CallPE::getOpCallICFGNode, py::return_value_policy::reference,
+ "Get the CallICFGNode of the i-th operand")
+ .def("getOpCallICFGNodes", &CallPE::getOpCallICFGNodes, py::return_value_policy::reference,
+ "Get all call site ICFGNodes")
+ .def("getFunEntryICFGNode", &CallPE::getFunEntryICFGNode, py::return_value_policy::reference,
+ "Get the function entry ICFG node");
+
py::class_(m, "PhiStmt")
// TODO: may implement get_op_var and get_op_var_id
.def("getOpICFGNode", [](PhiStmt& stmt, int idx) { return stmt.getOpICFGNode(idx); },
diff --git a/pysvf/pysvf.pyi b/pysvf/pysvf.pyi
index a1447ad..bd0191a 100644
--- a/pysvf/pysvf.pyi
+++ b/pysvf/pysvf.pyi
@@ -486,12 +486,15 @@ class StoreStmt(AssignStmt):
class LoadStmt(AssignStmt):
...
-class CallPE(AssignStmt):
+class CallPE(MultiOpndStmt):
def __init__(self, *args, **kwargs) -> None: ...
"""Not intended for direct instantiation."""
-
- def getCallSite(self) -> "CallICFGNode": ...
- """Get the call site"""
+
+ def getOpCallICFGNode(self, op_idx: int) -> "CallICFGNode": ...
+ """Get the CallICFGNode of the i-th operand"""
+
+ def getOpCallICFGNodes(self) -> List["CallICFGNode"]: ...
+ """Get all call site ICFGNodes"""
def getFunEntryICFGNode(self) -> "FunEntryICFGNode": ...
"""Get the function entry ICFG node"""