From f3729aee72a60578738f0c2fddcca2831019f546 Mon Sep 17 00:00:00 2001 From: Nagi5Yeq Date: Mon, 1 Jun 2020 02:15:40 +0800 Subject: add a sha1 test, commandline improvement, limit target to x86 only --- .gitignore | 4 +- Lexer.l | 9 ---- TypeManager.cc | 20 +++++++- Version.cc | 15 +++--- Version.hh | 2 +- main.cc | 58 +++++++++++++++++------ t/sha1.pas | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ t/sha1_driver.c | 36 ++++++++++++++ 8 files changed, 257 insertions(+), 32 deletions(-) create mode 100644 t/sha1.pas create mode 100644 t/sha1_driver.c diff --git a/.gitignore b/.gitignore index 1304f0a..fac49c0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ out Parser.cc Lexer.cc Parser.hh -*.ll +t/* +!t/*.pas +!t/*.c diff --git a/Lexer.l b/Lexer.l index f2fdc9a..6679b75 100644 --- a/Lexer.l +++ b/Lexer.l @@ -11,13 +11,6 @@ using pcc::Parser; using pcc::Location; - -namespace pcc { - char ToLower(char c){ - return static_cast(std::tolower(static_cast(c))); - } -} - %} %option nodefault @@ -165,8 +158,6 @@ comment {comment1}|{comment2} } {identifier} { - char *name = new char[yyleng]; - std::transform(yytext, yytext+yyleng, name, pcc::ToLower); return Parser::make_IDENTIFIER(yytext, loc); } diff --git a/TypeManager.cc b/TypeManager.cc index 9c484e4..7402875 100644 --- a/TypeManager.cc +++ b/TypeManager.cc @@ -161,6 +161,24 @@ Value TypeManager::CreateCast(std::shared_ptr DstType, return builder->CreateSExtOrTrunc(v, DstType->GetLLVMType()); } } + + // array to pointer decay + std::shared_ptr SrcPointerType = + std::dynamic_pointer_cast(SrcType); + std::shared_ptr DstPointerType = + std::dynamic_pointer_cast(DstType); + if (SrcPointerType != nullptr && DstPointerType != nullptr) { + std::shared_ptr SrcInnerType = + std::dynamic_pointer_cast( + SrcPointerType->GetElementType()); + if (SrcInnerType->GetElementType() == + DstPointerType->GetElementType()) { + Value zero = + llvm::ConstantInt::get(PointerIndexType_->GetLLVMType(), 0); + Value indices[2] = {zero, zero}; + return builder->CreateInBoundsGEP(v, indices); + } + } Log(LogLevel::PCC_ERROR, "unsupported type casting from %s to %s", SrcType->GetCommonName(), DstType->GetCommonName()); return nullptr; @@ -214,7 +232,7 @@ std::shared_ptr std::shared_ptr TypeManager::CreateRecordType(const std::vector& members) { - std::string name = "record {"; + std::string name = "{"; std::vector::const_iterator MemberIt = members.cbegin(); name.append(std::get<1>(*MemberIt)->GetCommonName()); for (++MemberIt; MemberIt != members.cend(); ++MemberIt) { diff --git a/Version.cc b/Version.cc index 02e30e2..7bc9532 100644 --- a/Version.cc +++ b/Version.cc @@ -25,12 +25,15 @@ PCC_NORETURN void ShowVersion() { PCC_NORETURN void ShowHelp() { std::cerr << PCC_NAME " version " PCC_VERSION_STRING "\n" - << "Usage: " PCC_NAME " [-vVh] file...\n" - << " -v Verbose mode.\n" - " -vv Very verbose mode.\n" - " -V Show version and exit.\n" - " -h Show this help and exit.\n" - " -t Set target's triple." + << "Usage: " PCC_NAME " [-vVhiSc] file...\n" + << " -v Verbose mode.\n" + << " -vv Very verbose mode.\n" + << " -V Show version and exit.\n" + << " -h Show this help and exit.\n" + << " -i Generate LLVM IR (default behavior).\n" + << " -S Compile to assembly.\n" + << " -c Compile to object file.\n" + << " -o Specify output file name." << std::endl; std::exit(0); } diff --git a/Version.hh b/Version.hh index 5b3a7ff..f2f05a3 100644 --- a/Version.hh +++ b/Version.hh @@ -5,7 +5,7 @@ #include #define PCC_NAME "pcc" -#define PCC_VERSION_STRING "0.1.0" +#define PCC_VERSION_STRING "0.1.1" #ifndef PCC_OSNAME #define PCC_OSNAME "unknown platform" diff --git a/main.cc b/main.cc index a1ab94a..2ee9699 100644 --- a/main.cc +++ b/main.cc @@ -18,8 +18,9 @@ int main(int argc, char* argv[]) { int rv; int level = pcc::ToUnderlying(pcc::PCC_WARNING); - std::string triple = ""; - while ((rv = getopt(argc, argv, "vVht:")) != -1) { + std::string OutputFileName; + enum { IR, ASSEMBLY, OBJECT } CompileType = IR; + while ((rv = getopt(argc, argv, "vVhiSco:")) != -1) { switch (rv) { case 'v': level = (level == 0 ? 0 : level - 1); @@ -28,8 +29,18 @@ int main(int argc, char* argv[]) { pcc::ShowVersion(); case 'h': pcc::ShowHelp(); - case 't': - triple = optarg; + case 'i': + CompileType = IR; + break; + case 'S': + CompileType = ASSEMBLY; + break; + case 'c': + CompileType = OBJECT; + break; + case 'o': + OutputFileName = optarg; + break; default: pcc::Log(pcc::PCC_ERROR, "Unknown option \"%c\".", rv); pcc::ShowHelp(); @@ -39,9 +50,7 @@ int main(int argc, char* argv[]) { llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetAsmPrinter(); - if (triple.empty()) { - triple = llvm::sys::getDefaultTargetTriple(); - } + std::string triple = llvm::sys::getDefaultTargetTriple(); std::string error; const llvm::Target* target = llvm::TargetRegistry::lookupTarget(triple, error); @@ -61,6 +70,11 @@ int main(int argc, char* argv[]) { pcc::Log(pcc::PCC_ERROR, "No input file specified"); return -1; } + if (!OutputFileName.empty() && optind != argc - 1) { + pcc::Log(pcc::LogLevel::PCC_WARNING, + "more than one source file specified, the output file name " + "will be ignored"); + } for (int i = optind; i < argc; i++) { pcc::Driver driver(argv[i]); llvm::Module* module = driver.GetContext()->GetModule(); @@ -71,16 +85,32 @@ int main(int argc, char* argv[]) { if (root != nullptr) { root->CodeGen(); } - size_t PostfixPos = filename.rfind(".pas"); - std::string OutputFileName; - if (PostfixPos == std::string::npos) { - OutputFileName = filename + ".ll"; - } else { - OutputFileName = filename.substr(0, PostfixPos) + ".ll"; + if (OutputFileName.empty()) { + const char* postfixs[] = {".ll", ".s", ".o"}; + size_t PostfixPos = filename.rfind(".pas"); + if (PostfixPos == std::string::npos) { + OutputFileName = filename + postfixs[CompileType]; + } else { + OutputFileName = + filename.substr(0, PostfixPos) + postfixs[CompileType]; + } } std::error_code ErrorCode; llvm::raw_fd_ostream Output(OutputFileName, ErrorCode); - driver.GetContext()->GetModule()->print(Output, nullptr); + switch (CompileType) { + case IR: + module->print(Output, nullptr); + break; + case ASSEMBLY: + break; + case OBJECT: + break; + default: + break; + } + pcc::Log(pcc::LogLevel::PCC_INFO, "%s compiled to %s", argv[i], + OutputFileName.c_str()); + OutputFileName.clear(); } return 0; } diff --git a/t/sha1.pas b/t/sha1.pas new file mode 100644 index 0000000..35c9341 --- /dev/null +++ b/t/sha1.pas @@ -0,0 +1,145 @@ +program sha1; + +type + sha1_ctx = record + h:array [0..4] of integer; + bytes:integer; + buf:array [0..63] of char + end; + +extern memcpy(dst:^char; src:^char; len:integer):^char; + +extern memset(buf:^char; c:char; len:integer):^char; + +function sha1_init(ctx:^sha1_ctx):void; +begin + ctx^.h[0] := 0x67452301; + ctx^.h[1] := -0x10325477; + ctx^.h[2] := -0x67452302; + ctx^.h[3] := 0x10325476; + ctx^.h[4] := -0x3c2d1e10; + ctx^.bytes := 0; +end; + +function rol(bits:integer; x:integer):integer; +begin + rol := x shl bits or (x shr (32-bits) and not (-1 shl bits)) +end; + +function sha1_body(ctx:^sha1_ctx; data:^char; len:integer):^char; +var + f, k, temp, i, j:integer; + a, b, c, d, e:integer; + aa, bb, cc, dd, ee:integer; + p:^char; + w:array [0..79] of integer; +begin + p := data; + a := ctx^.h[0]; + b := ctx^.h[1]; + c := ctx^.h[2]; + d := ctx^.h[3]; + e := ctx^.h[4]; + repeat begin + aa := a; + bb := b; + cc := c; + dd := d; + ee := e; + for i := 0 to 15 do begin + w[i] := 0; + for j := 0 to 3 do + w[i] := (w[i] shl 8) or (p[i*4+j] and 0xff) + end; + for i := 16 to 79 do + w[i] := rol(1, w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]); + for i := 0 to 79 do begin + if i<20 then begin + f := (b and c) or ((not b) and d); + k := 0x5a827999 + end + else if i<40 then begin + f := b xor c xor d; + k := 0x6ed9eba1 + end + else if i<60 then begin + f := (b and c) or (b and d) or(c and d); + k := -0x70e44324 + end + else begin + f := b xor c xor d; + k := -0x359d3e2a + end; + temp := rol(5, a) + f + e + k + w[i]; + e := d; + d := c; + c := rol(30, b); + b := a; + a := temp + end; + a := a+aa; + b := b+bb; + c := c+cc; + d := d+dd; + e := e+ee; + p := p+64; + len := len-64 + end until len=0; + ctx^.h[0] := a; + ctx^.h[1] := b; + ctx^.h[2] := c; + ctx^.h[3] := d; + ctx^.h[4] := e; + sha1_body := p; +end; + +function sha1_update(ctx:^sha1_ctx; data:^char; len:integer):void; +var + used, free:integer; +begin + used := ctx^.bytes and 0x3f; + ctx^.bytes := ctx^.bytes+len; + if (used<>0) and (used+len<64) then + memcpy(@ctx^.buf[used], data, len) + else begin + if used<>0 then begin + free := 64-used; + memcpy(@ctx^.buf[used], data, free); + data := data+free; + len := len-free; + sha1_body(ctx, @ctx^.buf, 64) + end; + if len>=64 then begin + data := sha1_body(ctx, data, len and not 0x3f); + len := len and 0x3f + end; + memcpy(@ctx^.buf[0], data, len) + end +end; + +function sha1_final(md:^char; ctx:^sha1_ctx):void; +var + used, free:integer; + bits, i:integer; +begin + used := ctx^.bytes and 0x3f; + ctx^.buf[used] := 0x80; + used := used+1; + free := 64-used; + if free<8 then begin + memset(@ctx^.buf[used], 0, free); + sha1_body(ctx, @ctx^.buf, 64); + used := 0; + free := 64 + end; + memset(@ctx^.buf[used], 0, free-8); + bits := ctx^.bytes shl 3; + for i := 0 to 3 do + ctx^.buf[56+i] := 0; + for i := 4 to 7 do + ctx^.buf[i+56] := bits shr (8*(7-i)); + sha1_body(ctx, @ctx^.buf, 64); + for i := 0 to 19 do + md[i] := ctx^.h[i div 4] shr (8*(3-i mod 4)); +end; + diff --git a/t/sha1_driver.c b/t/sha1_driver.c new file mode 100644 index 0000000..212cbf8 --- /dev/null +++ b/t/sha1_driver.c @@ -0,0 +1,36 @@ +#include +#include + +typedef struct ctx_s { + int h[5]; + int bytes; + char buf[64]; +} ctx; + +void sha1_init(ctx*); +void sha1_update(ctx*, const char*, int); +void sha1_final(unsigned char*, ctx*); + +int main(int argc, char* argv[]) { + ctx c; + int i; + size_t len; + char buf[1024]; + unsigned char md[20]; + FILE* f; + + assert(argc == 2); + f = fopen(argv[1], "r"); + sha1_init(&c); + while (!feof(f)) { + len = fread(buf, 1, 1024, f); + sha1_update(&c, buf, (int) len); + } + sha1_final(md, &c); + for (i = 0; i < 20; i++) { + printf("%02x", md[i]); + } + putchar('\n'); + fclose(f); + return 0; +} -- cgit