#!/bin/bash : <<'````````bash' # Programming Exercise 3: Generating LLVM-IR This is the continuation of hw2. You can continue from your own code or use the parser from the website as starting point. ## Implementation Generate a single (valid) LLVM-IR module from an AST and print it to standard output. For parameters and register-variables, construct SSA yourself/explicitly using the algorithm discussed in the lecture (Braun et al. 2013); for auto-variables, simply place `alloca`s in the entry block (why there?). Use `getelementptr` for subscripts. Declare external functions as required. Language semantics are described in the specification in hw2. Run the LLVM verifier to ensure your generated IR is valid (C++: `assert(!llvm::verifyModule(*mod, &llvm::errs()));`). Your submission must use the LLVM API (C++ or C) directly. In addition, the code should be human-readable and have minimal dependencies besides compiler, standard library, LLVM, and your parser. Use LLVM 19, 20, or 21. You might find these links helpful (as always, only parts of each page are actually relevant): - https://llvm.org/docs/LangRef.html - https://www.llvm.org/docs/ProgrammersManual.html (this also contains documentation on LLVM's custom data structures, which you might find useful, too) - https://llvm.org/doxygen/classllvm_1_1IRBuilder.html (and other Doxygen pages) ## Command Line Interface usage: ./bc1 (-a|-c|-l) program_file B compiler. Exit with non-zero status code on invalid input. -a: print AST as S-Expressions. -c: syntax/semantic check only (build AST nonetheless). No output other than the exit code. -l: emit LLVM-IR. program_file: file that contains the input program Note that `program_file` is not necessarily a regular file, but can also be a pipe as used in the tests below, where you cannot determine the input size without reading it. You can add extra options, e.g., to control optimizations or for debugging, but do not assign `-i`, `-r`, and `-S`, which will be used in subsequent homework. ## Example Program phis(a, b){ a = a + b; if (a > b + b) { register c = 1; while (a > 0) a = a - c; } else { a = b + b; } return a; } deadcode(a, b, c) { if (a) return a; else return b; return c; } shortcircuit() { return fnA() && fnB() || fnC(); } undef() { return; } main(argc, argv) { auto f1 = 44629835118; printf(&f1, argc); while (argc) { puts(argv[0]); argv = &argv[1]; argc = argc - 1; } return 0; } ## Analysis (write answers as comment in your code) Can you reuse information from previous semantic analysis about variable scopes to improve the performance of your implementation? Is there obvious potential for IR optimizations? Pipe the output to llc (or use the code snippet below) and check whether the machine code matches your expectation. ## Submission - Submission deadline: 2025-11-19 23:59 - Submit using `curl --data-binary "@" 'https://db.in.tum.de/teaching/ws2526/codegen/submit.py?hw=3&matrno='` ````````bash set -euo pipefail FAILED=0 testcase_ec() { if ./bc1 -l "$3" | lli; s="${PIPESTATUS[@]}"; [ "$s" != "0 $2" ]; \ then echo "FAILED: $1 (got [$s] expected [0 $2])"; FAILED=1; fi; } testcase_chk() { ./bc1 -l "$2" | "${@:3}" || { echo "FAILED: $1"; FAILED=1; }; } testcase_run_chk() { ./bc1 -l "$2" | lli | "${@:3}" || { echo "FAILED: $1"; FAILED=1; }; } CXX=clang++ CXXFLAGS="-O3 -Wall -Wextra -std=c++20 $(llvm-config --cppflags --ldflags | tr '\n' ' ')" \ LDLIBS="$(llvm-config --libs)" make bc1 # testcase_ec checks the return status. 1 is used by lli, thus prohibited. testcase_ec "return 1" 0 <(echo "main(){return 0;}") testcase_ec "return 2" 10 <(echo "main(){return 10;}") testcase_ec "return 3" 10 <(echo "main(){return 10;return 0;}") # NB: this is a flaky test testcase_ec "return 4" 1 <(echo "main(argc){return argc;}") testcase_ec "return 5" 2 <(echo "main(){return 4294967298;}") # Test important operators: binary +/-, unary -/!. testcase_ec "neg 1" 255 <(echo "main(){return -1;}") testcase_ec "inv neg 1" 0 <(echo "main(){return ~(-1);}") testcase_ec "neg inv 1" 2 <(echo "main(){return -(~1);}") testcase_ec "neg inv 2" 3 <(echo "main(){return -~2;}") testcase_ec "inv 2" 253 <(echo "main(){return ~2;}") testcase_ec "not 1" 0 <(echo "main(){return !1;}") testcase_ec "not 2" 0 <(echo "main(){return !2;}") testcase_ec "not -1" 0 <(echo "main(){return !-1;}") testcase_ec "not not 1" 0 <(echo "main(){return !!0;}") testcase_ec "not not 2" 2 <(echo "main(){return 1+!!2;}") testcase_ec "add 1" 0 <(echo "main(){return 1+(-1);}") testcase_ec "add 2" 4 <(echo "main(){return 2+1+1;}") testcase_ec "sub 1" 0 <(echo "main(){return 1-1;}") testcase_ec "eq 1" 2 <(echo "main(){return (1==1)+1;}") testcase_ec "eq 2" 11 <(echo "main(){return 10+((1==1)-(1==2));}") testcase_ec "eq 3" 12 <(echo "main(){return 10+((1==1)+(1==1));}") # Test some basic operators with a non-constant operand. testcase_ec "sub argc 1" 255 <(echo "main(argc){return 0-argc;}") testcase_ec "sub argc 2" 255 <(echo "main(argc){return -argc;}") testcase_ec "sub argc 3" 0 <(echo "main(argc){return 1-argc;}") testcase_ec "add argc 1" 3 <(echo "main(argc){return argc+2;}") testcase_ec "add argc 2" 3 <(echo "main(argc){return argc+4294967298;}") testcase_ec "inv argc 1" 254 <(echo "main(argc){return ~argc;}") testcase_ec "eq argc 1" 255 <(echo "main(argc){return -(argc==1);}") testcase_ec "eq argc 2" 0 <(echo "main(argc){return -(argc==2);}") # Test function calls. testcase_ec "call 1" 0 <(echo "fn(){return 0;}main(){return fn();}") testcase_ec "call 2" 2 <(echo "fn(){return 1;}main(){return fn()+fn();}") testcase_ec "call 3" 9 <(echo "main(){return fn(1);}fn(a){return 10-a;}") testcase_ec "call 4" 0 <(echo "main(){return fn(1,2,3);}fn(a,b,c){return a+b-c;}") testcase_ec "call 5" 0 <(echo "f(){return;}main(){f();return 0;}") testcase_ec "call 6" 13 <(echo "f(x){return x+1;}main(){return f(1==1)+f(10);}") testcase_ec "call 7" 15 <(echo "f(a,b,c,d,e,f,g,h){return g+h;}main(){return f(1,2,3,4,5,6,7,8);}") testcase_ec "call 8" 115 <(echo "f(a,b,c,d,e,f,g,h,i,j,k){return g+h+i+k;}main(){return f(1,2,3,4,5,6,7,8,20,40,80);}") testcase_ec "call 9" 99 <(echo "f(a,b,c,d,e,f,g,h,i,j,k){register l=a+b;register m=c+d;register n=e+f;register o=g+h;register p=i+j;register q=k+l;return a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q;}main(){return f(1,2,3,4,5,6,7,8,20,40,80);}") # Test auto, addrof, and subscript testcase_ec "auto 0" 0 <(echo "main(){auto x=0;return x;}") testcase_ec "auto 1" 8 <(echo "main(){auto x=2;auto y=x=4;return x+y;}") testcase_ec "auto 2" 4 <(echo "main(){auto x=2;register y=&x;y[0]=4;return x;}") testcase_ec "auto 3" 22 <(echo "func(a){a[0]=22;}main(){auto a=1;func(&a);return a;}") testcase_ec "auto 4" 4 <(echo "main(){auto x=2;x=4;return x;}") testcase_ec "auto 5" 5 <(echo "main(){auto x=2;register y=&x;y[0]=4;x=x+1;return x;}") testcase_chk "auto alloca" <(echo "main(){auto x=2;auto y=x=4;return x+y;}") grep -q alloca testcase_chk "auto has no phi" <(echo "f(a){auto x=0;if(a>0)x=a+2;else x=a+1;return x;}") not grep -q phi testcase_ec "addrof 1" 0 <(echo "main(){auto x=0;(&x)[2@2]=1;(&x)[1@1]=1;return x!=4294967552;}") testcase_ec "addrof 2" 0 <(echo "main(){auto x=0;auto y=&x;return &x-y!=0;}") testcase_ec "addrof 3" 8 <(echo "main(){auto x=1234;auto y=&x[1];return y-x;}") testcase_ec "addrof 4" 4 <(echo "main(){auto x=1234;auto y=&x[1@4];return y-x;}") testcase_ec "addrof 5" 2 <(echo "main(){auto x=1234;auto y=&x[1@2];return y-x;}") testcase_ec "addrof 6" 2 <(echo "main(){auto x=1234;auto y=&x[-1@2];return x-y;}") testcase_ec "addrof 7" 3 <(echo "main(){auto x=3;auto p=&x-8;return p[1];}") testcase_ec "addrof 8" 2 <(echo "main(){auto x=516;auto p=&x;return p[1@1];}") testcase_ec "addrof 9" 4 <(echo "main(){auto x=516;auto p=&x;return p[0@1];}") testcase_ec "addrof 10" 10 <(echo "main(){auto x=516;auto p=&x+10;return p-&x;}") testcase_ec "addrof 11" 10 <(echo "main(){auto x=516;auto p=10+&x;return p-&x;}") testcase_ec "addrof 12" 246 <(echo "main(){auto x=516;auto p=10+&x;return &x-p;}") testcase_ec "addrof 13" 10 <(echo "main(){auto x=516;auto p=(&x+&x)+10;return p-&x-&x;}") testcase_ec "addrof 14" 12 <(echo "main(){auto x=12;register p=&x;auto q=p[0];x=0;return q;}") testcase_ec "addrof 15" 2 <(echo "main(){auto x=254;register p=(&x)[0@1];x=0;return -p;}") testcase_ec "sext 1" 0 <(echo "main(){auto x=128;auto p=&x;return p[0@1]+128;}") testcase_ec "sext 2" 0 <(echo "main(){auto x=128;auto p=&x;return p[0@1]>0;}") testcase_ec "sext 3" 0 <(echo "main(){auto x=32768;auto p=&x;return p[0@2]>0;}") testcase_ec "sext 4" 0 <(echo "main(){auto x=32767;auto p=&x;return p[0@2]<0;}") testcase_ec "sext 5" 0 <(echo "main(){auto x=2147483648;auto p=&x;return p[0@4]>0;}") testcase_ec "sext 6" 0 <(echo "main(){auto x=2147483647;auto p=&x;return p[0@4]<0;}") testcase_ec "addrof call 1" 4 <(echo "f(x){x[0]=x[0]+3;}main(){auto x=1;f(&x);return x;}") testcase_ec "addrof call 2" 7 <(echo "f(x){x[0]=x[0]+3;}main(){auto x=1;auto y=&x;f(&x);f(y);return x;}") testcase_ec "addrof call 3" 7 <(echo "f(x){x[0]=x[0]+3;}main(){auto x=1;register y=&x;f(&x);f(y);return x;}") # Test if. testcase_ec "if 1" 10 <(echo "main(){if(1)return 10;return 20;}") testcase_ec "if 2" 10 <(echo "main(){if(4)return 10;else return 20;}") testcase_ec "if 3" 20 <(echo "main(){if(0)return 10;return 20;}") testcase_ec "if 4" 20 <(echo "main(){if(0)return 10;else return 20;}") testcase_ec "if 5" 10 <(echo "main(){if(1)return 10;return 20;return 30;}") testcase_ec "if 6" 10 <(echo "main(){if(2)return 10;else return 20;return 30;}") testcase_ec "if 7" 20 <(echo "main(){if(!2)return 10;else return 20;}") testcase_ec "if 8" 20 <(echo "main(){if(~-1)return 10;else return 20;}") testcase_ec "if 9" 10 <(echo "main(){if(1==1)return 10;else return 20;}") testcase_ec "if 10" 20 <(echo "main(){if(1!=1)return 10;else return 20;}") testcase_ec "if 11" 20 <(echo "main(){if(1!=1)return;else return 20;}") testcase_ec "if 12" 20 <(echo "main(){if(1)return 20;else return;}") testcase_ec "if 13" 20 <(echo "main(){if(1)return 20;return;}") testcase_ec "if argc 1" 10 <(echo "main(argc){if(argc<2)return 10;else return 0;}") testcase_ec "if argc 2" 0 <(echo "main(argc){if(argc>2)return 10;else return 0;}") testcase_ec "if argc 3" 10 <(echo "main(argc){if(argc==1)return 10;else return 0;}") testcase_ec "if argc 4" 0 <(echo "main(argc){if(argc==2)return 10;else return 0;}") testcase_ec "if argc 5" 0 <(echo "main(argc){if(argc!=1)return 10;else return 0;}") testcase_ec "if argc 6" 10 <(echo "main(argc){if(argc!=2)return 10;else return 0;}") testcase_ec "if auto 1" 5 <(echo "main(){auto x=4;if(x==4)x=5;else x=7;return x;}") testcase_ec "if auto 2" 7 <(echo "main(){auto x=4;if(x!=4)x=5;else x=7;return x;}") testcase_ec "if auto 3" 15 <(echo "main(){auto x=4;if(x==4)x=5;else return x;return x+10;}") testcase_ec "if auto 4" 4 <(echo "main(){auto x=4;if(x!=4)x=5;else return x;return x+10;}") testcase_ec "if auto 5" 5 <(echo "main(){auto x=4;if(x==4)return 5;else x=7;return x;}") testcase_ec "if auto 6" 7 <(echo "main(){auto x=4;if(x!=4)return 5;else x=7;return x;}") testcase_ec "if auto 7" 5 <(echo "main(){auto x=4;if(x==4)return 5;else return x;}") testcase_ec "if auto 8" 4 <(echo "main(){auto x=4;if(x!=4)return 5;else return x;}") # Test register (PHI nodes) (shallow tests, could definitly be expanded to cover more corner cases). testcase_chk "reg has phi" <(echo "f(a){register x=0;if(a>0)x=a+2;else x=a+1;return x;}") grep -q phi testcase_chk "reg has no alloca" <(echo "f(a){register x=0;if(a>0)x=a+2;else x=a+1;return x;}") not grep -q alloca testcase_ec "reg 1" 10 <(echo "main(){register x=0;register y=10;if(y==10)x=y;return x;}") testcase_ec "reg 2" 10 <(echo "main(){register x=0;register y=10;if(y==10)x=y;else x=5;return x;}") testcase_ec "reg 3" 5 <(echo "main(){register x=0;register y=10;if(y!=10)x=y;else x=5;return x;}") testcase_ec "reg 4" 0 <(echo "main(){register y=6;while(y){y=y-1;}return y;}") testcase_ec "reg 5" 15 <(echo "main(){register x=0;register y=5;while(y){x=x+y;y=y-1;}return x;}") testcase_ec "reg 6" 25 <(echo "main(){register a=10;register x=0;register y=5;while(y){x=x+y;y=y-1;}return a+x;}") testcase_ec "reg 7" 16 <(echo "main(){register a=10;register x=0;register y=5;while(y){x=x+y;y=y-1;a=1;}return a+x;}") testcase_ec "reg 8" 6 <(echo "main(){register a=1;register x=0;register y=5;while(y){x=x+a;y=y-a;}return a+x;}") testcase_ec "reg 9" 10 <(echo "phis(a, b){a = a + b;if (a > b + b) {register c = 1;while (a > 0)a = a - c;} else {a = b + b;}return a;}main(){return phis(3,5);}") testcase_ec "reg 10" 0 <(echo "phis(a, b){a = a + b;if (a > b + b) {register c = 1;while (a > 0)a = a - c;} else {a = b + b;}return a;}main(){return phis(5,3);}") testcase_ec "if reg 1" 5 <(echo "main(){register x=4;if(x==4)x=5;else x=7;return x;}") testcase_ec "if reg 2" 7 <(echo "main(){register x=4;if(x!=4)x=5;else x=7;return x;}") testcase_ec "if reg 3" 15 <(echo "main(){register x=4;if(x==4)x=5;else return x;return x+10;}") testcase_ec "if reg 4" 4 <(echo "main(){register x=4;if(x!=4)x=5;else return x;return x+10;}") testcase_ec "if reg 5" 5 <(echo "main(){register x=4;if(x==4)return 5;else x=7;return x;}") testcase_ec "if reg 6" 7 <(echo "main(){register x=4;if(x!=4)return 5;else x=7;return x;}") testcase_ec "if reg 7" 5 <(echo "main(){register x=4;if(x==4)return 5;else return x;}") testcase_ec "if reg 8" 4 <(echo "main(){register x=4;if(x!=4)return 5;else return x;}") testcase_ec "while reg 1" 2 <(echo "f(x){register a=1;register b=0;while(x){x=x-1;register t=a;a=b;b=t;}return a+a+b+b+b+b;}main(){return f(12);}") testcase_ec "while reg 2" 4 <(echo "f(x){register a=1;register b=0;while(x){x=x-1;register t=a;a=b;b=t;}return a+a+b+b+b+b;}main(){return f(13);}") # Test || and &&. testcase_ec "oror 1" 2 <(echo "f(a){a[0]=a[0]+2;return 1;}g(a){a[0]=a[0]+4;return 0;}main(){auto a=0;f(&a)||g(&a);return a;}") testcase_ec "oror 2" 6 <(echo "f(a){a[0]=a[0]+2;return 0;}g(a){a[0]=a[0]+4;return 0;}main(){auto a=0;f(&a)||g(&a);return a;}") testcase_ec "oror 3" 10 <(echo "f(){return 0;}g(){return 0;}main(){return 10+(f()||g());}") testcase_ec "oror 4" 11 <(echo "f(){return 1;}g(){return 0;}main(){return 10+(f()||g());}") testcase_ec "oror 5" 11 <(echo "f(){return 0;}g(){return 1;}main(){return 10+(f()||g());}") testcase_ec "oror 6" 11 <(echo "f(){return 1;}g(){return 1;}main(){return 10+(f()||g());}") testcase_ec "andand 1" 6 <(echo "f(a){a[0]=a[0]+2;return 1;}g(a){a[0]=a[0]+4;return 0;}main(){auto a=0;f(&a)&&g(&a);return a;}") testcase_ec "andand 2" 2 <(echo "f(a){a[0]=a[0]+2;return 0;}g(a){a[0]=a[0]+4;return 0;}main(){auto a=0;f(&a)&&g(&a);return a;}") testcase_ec "andand 3" 10 <(echo "f(){return 0;}g(){return 0;}main(){return 10+(f()&&g());}") testcase_ec "andand 4" 10 <(echo "f(){return 1;}g(){return 0;}main(){return 10+(f()&&g());}") testcase_ec "andand 5" 10 <(echo "f(){return 0;}g(){return 1;}main(){return 10+(f()&&g());}") testcase_ec "andand 6" 11 <(echo "f(){return 1;}g(){return 1;}main(){return 10+(f()&&g());}") # Test assignment side-effect, with auto testcase_ec "if oror 1" 4 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(0,0,0);}") testcase_ec "if oror 2" 2 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(0,0,1);}") testcase_ec "if oror 3" 4 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(0,1,0);}") testcase_ec "if oror 4" 2 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(0,1,1);}") testcase_ec "if oror 5" 4 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(1,0,0);}") testcase_ec "if oror 6" 2 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(1,0,1);}") testcase_ec "if oror 7" 2 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(1,1,0);}") testcase_ec "if oror 8" 2 <(echo "f(a,b,c){if((a&&b)||c)return 2;else return 4;}main(){return f(1,1,1);}") testcase_ec "if assign 1" 22 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,0,0);}") testcase_ec "if assign 2" 22 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,0,1);}") testcase_ec "if assign 3" 22 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,1,0);}") testcase_ec "if assign 4" 22 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,1,1);}") testcase_ec "if assign 5" 20 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,0,0);}") testcase_ec "if assign 6" 20 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,0,1);}") testcase_ec "if assign 7" 11 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,1,0);}") testcase_ec "if assign 8" 15 <(echo "f(a,b,c){auto x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,1,1);}") # Test while testcase_ec "while 1" 5 <(echo "main(){while(0){return 1;}return 5;}") testcase_ec "while 2" 0 <(echo "main(){auto x=1;while(x){x=0;}return x;}") testcase_ec "while 3" 10 <(echo "main(){while(1){return 10;}return 5;}") testcase_ec "while 4" 4 <(echo "main(){while(1){if(1)return 4;else return 11;}return 5;}") testcase_ec "while 5" 4 <(echo "main(){while(1){if(1)return 4;}return 5;}") # Test assignment side-effect, with register testcase_ec "if assign reg 1" 22 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,0,0);}") testcase_ec "if assign reg 2" 22 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,0,1);}") testcase_ec "if assign reg 3" 22 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,1,0);}") testcase_ec "if assign reg 4" 22 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(0,1,1);}") testcase_ec "if assign reg 5" 20 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,0,0);}") testcase_ec "if assign reg 6" 20 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,0,1);}") testcase_ec "if assign reg 7" 11 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,1,0);}") testcase_ec "if assign reg 8" 15 <(echo "f(a,b,c){register x=2;if((a&&(x=b))&&(x=x+c+c+c+c))return 10+x;else return 20+x;}main(){return f(1,1,1);}") # Test assignment side-effect, with parameter testcase_ec "if assign param 1" 20 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(0,0,0);}") testcase_ec "if assign param 2" 20 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(0,0,1);}") testcase_ec "if assign param 3" 20 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(0,1,0);}") testcase_ec "if assign param 4" 20 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(0,1,1);}") testcase_ec "if assign param 5" 20 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(1,0,0);}") testcase_ec "if assign param 6" 20 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(1,0,1);}") testcase_ec "if assign param 7" 12 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(1,1,0);}") testcase_ec "if assign param 8" 16 <(echo "f(a,b,c){if((a&&(a=b))&&(a=2+c+c+c+c))return 10+a;else return 20+a;}main(){return f(1,1,1);}") testcase_ec "shadow 1" 3 <(echo "f(a,b){if(a<10){register a=a+b;return a;}else{auto b=b;return &b[1]-&b;}}main(){return f(1,2);}") testcase_ec "shadow 2" 2 <(echo "f(a,b){if(a<10){register a=a+b;return a;}else{auto b=b;return (&b)[0];}}main(){return f(10,2);}") # Calling external functions works testcase_ec "malloc free" 123 <(echo "main(){register x=malloc(8);x[0]=123;return freeread(x);}freeread(p){register r=p[0];free(p);return r;}") testcase_run_chk "puts" <(echo "main(){auto x=36762444129608;puts(&x);return 0;}") cmp - <(echo "Hello!") testcase_run_chk "printf" <(echo "main(argc,argv){auto f1=44629835118;printf(&f1,argc);while(argc){puts(argv[0]);argv=&argv[1];argc=argc-1;}return 0;}") cmp - <(echo -e "n=1\n-") # One auto variable shouldn't cause a stack overflow... testcase_ec "allocaloop" 0 <(echo "allocaloop(x){while(x){auto y=x;x=x-1;}}main(){allocaloop(10000000);return 0;}") # If multiplication and right shift are implemented: testcase_run_chk "mandelbrot" <(cat <> 28; } // 4.28 fix-point multiplication main(argc, argv) { register imax = 32; register scale = 0; if (argc > 1) imax = atol(argv[1]); if (argc > 2) scale = atol(argv[2]); register im = -352321536; // -(2<<28)+(22<<23) == -1.3125 while (im < 352321537) { // <= -1.3125 register re = -536870912; // -(2<<28) == -2.0 while (re < 268435456) { // (2<<28)-(64<<22) == 1.0 register i = 0; register reZ = re; register imZ = im; while (i < imax && mul(reZ, reZ) + mul(imZ, imZ) < 1073741825) { // <= 4.0 register reim = mul(reZ, imZ); reZ = mul(reZ, reZ) - mul(imZ, imZ) + re; imZ = reim + reim + im; i = i + 1; } if (i > 26 || !(i < imax)) putchar(32 + 10 * (i < imax)); else putchar(65 + i); re = re + (8388608 >> scale); // (4<<28)/128 == 1.0/32 } putchar(10); im = im + (16777216 >> scale); // (4<<28)/64 == 1.0/16 } return 0; } EOF ) cmp - <(base64 -d <