Mercurial > projects > ldc
changeset 11:d3ee9efe20e2 trunk
[svn r15] * Fixed a bunch problems with virtual calls. Seems I did some rather poor testing.
* Now 50/51 tests compile.
* Added a simple runalltests.d scripts that should be run with 'gdmd -run runalltests.d' - LLVMDC will not compile it yet.
author | lindquist |
---|---|
date | Tue, 02 Oct 2007 05:10:18 +0200 |
parents | c0f2c47e5034 |
children | ee302fe07296 |
files | dmd/declaration.h dmd/func.c dmd/mars.c dmd/mtype.c dmd/mtype.h gen/arrays.c gen/arrays.h gen/elem.c gen/elem.h gen/toir.c gen/tollvm.c gen/tollvm.h gen/toobj.c lib/llvmdcore.bc lphobos/llvm/intrinsic.d runalltests.d test/classes6.d test/classes7.d tester.sh |
diffstat | 19 files changed, 205 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/dmd/declaration.h Mon Oct 01 23:32:29 2007 +0200 +++ b/dmd/declaration.h Tue Oct 02 05:10:18 2007 +0200 @@ -509,6 +509,8 @@ int cvMember(unsigned char *p); FuncDeclaration *isFuncDeclaration() { return this; } + + bool llvmQueued; }; struct FuncAliasDeclaration : FuncDeclaration
--- a/dmd/func.c Mon Oct 01 23:32:29 2007 +0200 +++ b/dmd/func.c Tue Oct 02 05:10:18 2007 +0200 @@ -73,6 +73,7 @@ nrvo_can = 1; nrvo_var = NULL; shidden = NULL; + llvmQueued = false; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
--- a/dmd/mars.c Mon Oct 01 23:32:29 2007 +0200 +++ b/dmd/mars.c Tue Oct 02 05:10:18 2007 +0200 @@ -349,7 +349,7 @@ global.params.Dversion = 1; else if (strcmp(p + 1, "w") == 0) global.params.warnings = 1; - else if (strcmp(p + 1, "O") == 0) + else if (p[1] == 'O') { global.params.optimize = 1; if (p[2] != 0) {
--- a/dmd/mtype.c Mon Oct 01 23:32:29 2007 +0200 +++ b/dmd/mtype.c Tue Oct 02 05:10:18 2007 +0200 @@ -114,7 +114,7 @@ this->arrayof = NULL; this->vtinfo = NULL; this->ctype = NULL; - this->llvmType = 0; + this->llvmType = NULL; } Type *Type::syntaxCopy()
--- a/dmd/mtype.h Mon Oct 01 23:32:29 2007 +0200 +++ b/dmd/mtype.h Tue Oct 02 05:10:18 2007 +0200 @@ -250,7 +250,7 @@ virtual type *toCParamtype(); virtual Symbol *toSymbol(); - llvm::Type* llvmType; + const llvm::Type* llvmType; // For eliminating dynamic_cast virtual TypeBasic *isTypeBasic();
--- a/gen/arrays.c Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/arrays.c Tue Oct 02 05:10:18 2007 +0200 @@ -19,7 +19,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::StructType* LLVM_DtoArrayType(Type* t) +const llvm::StructType* LLVM_DtoArrayType(Type* t) { assert(t->next); const llvm::Type* at = LLVM_DtoType(t->next); @@ -51,7 +51,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t) +const llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t) { if (t->llvmType) return llvm::cast<llvm::ArrayType>(t->llvmType); @@ -63,7 +63,7 @@ TypeSArray* tsa = (TypeSArray*)t; assert(tsa->dim->type->isintegral()); - llvm::ArrayType* arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger()); + const llvm::ArrayType* arrty = llvm::ArrayType::get(at,tsa->dim->toUInteger()); tsa->llvmType = arrty; return arrty; @@ -298,7 +298,7 @@ inits[i] = v; } - llvm::ArrayType* arrty = LLVM_DtoStaticArrayType(t); + const llvm::ArrayType* arrty = LLVM_DtoStaticArrayType(t); return llvm::ConstantArray::get(arrty, inits); }
--- a/gen/arrays.h Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/arrays.h Tue Oct 02 05:10:18 2007 +0200 @@ -1,9 +1,9 @@ #ifndef LLVMC_GEN_ARRAYS_H #define LLVMC_GEN_ARRAYS_H -llvm::StructType* LLVM_DtoArrayType(Type* t); +const llvm::StructType* LLVM_DtoArrayType(Type* t); -llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t); +const llvm::ArrayType* LLVM_DtoStaticArrayType(Type* t); llvm::Value* LLVM_DtoNullArray(llvm::Value* v);
--- a/gen/elem.c Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/elem.c Tue Oct 02 05:10:18 2007 +0200 @@ -17,6 +17,7 @@ type = NONE; inplace = false; field = false; + callconv = (unsigned)-1; vardecl = 0; funcdecl = 0;
--- a/gen/elem.h Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/elem.h Tue Oct 02 05:10:18 2007 +0200 @@ -31,6 +31,7 @@ int type; bool inplace; bool field; + unsigned callconv; VarDeclaration* vardecl; FuncDeclaration* funcdecl;
--- a/gen/toir.c Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/toir.c Tue Oct 02 05:10:18 2007 +0200 @@ -954,6 +954,8 @@ // set calling convention if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic)) || delegateCall) call->setCallingConv(LLVM_DtoCallingConv(dlink)); + else if (fn->callconv != (unsigned)-1) + call->setCallingConv(fn->callconv); delete fn; return e; @@ -1253,7 +1255,7 @@ funcval = LLVM_DtoGEP(funcval, zero, vtblidx, "tmp", p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); assert(funcval->getType() == fdecl->llvmValue->getType()); - //funcval = new llvm::BitCastInst(funcval, fdecl->llvmValue->getType(), "tmp", p->scopebb()); + e->callconv = LLVM_DtoCallingConv(fdecl->linkage); } e->val = funcval; e->type = elem::VAL;
--- a/gen/tollvm.c Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/tollvm.c Tue Oct 02 05:10:18 2007 +0200 @@ -159,7 +159,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam) +const llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam) { TypeFunction* f = (TypeFunction*)t; @@ -203,7 +203,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl) +const llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl) { TypeFunction* f = (TypeFunction*)fdecl->type; assert(f != 0); @@ -309,7 +309,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::StructType* LLVM_DtoDelegateType(Type* t) +const llvm::StructType* LLVM_DtoDelegateType(Type* t) { const llvm::Type* i8ptr = llvm::PointerType::get(llvm::Type::Int8Ty); const llvm::Type* func = LLVM_DtoFunctionType(t->next, i8ptr); @@ -323,7 +323,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -llvm::Type* LLVM_DtoStructType(Type* t) +const llvm::Type* LLVM_DtoStructType(Type* t) { assert(0); std::vector<const llvm::Type*> types; @@ -763,26 +763,40 @@ void LLVM_DtoInitClass(TypeClass* tc, llvm::Value* dst) { - assert(tc->llvmInit); - assert(dst->getType() == tc->llvmInit->getType()); assert(gIR); assert(tc->llvmType); - uint64_t n = gTargetData->getTypeSize(tc->llvmType); - llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); + uint64_t size_t_size = gTargetData->getTypeSize(LLVM_DtoSize_t()); + uint64_t n = gTargetData->getTypeSize(tc->llvmType) - size_t_size; - llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); - llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb()); + // set vtable field + llvm::Value* vtblvar = LLVM_DtoGEPi(dst,0,0,"tmp",gIR->scopebb()); + assert(tc->sym->llvmVtbl); + new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb()); + + // copy the static initializer + if (n > 0) { + assert(tc->llvmInit); + assert(dst->getType() == tc->llvmInit->getType()); + + llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); - llvm::Function* fn = LLVM_DeclareMemCpy32(); - std::vector<llvm::Value*> llargs; - llargs.resize(4); - llargs[0] = dstarr; - llargs[1] = srcarr; - llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); - llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); + dstarr = LLVM_DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb()); + + llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb()); + srcarr = LLVM_DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb()); - new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + llvm::Function* fn = LLVM_DeclareMemCpy32(); + std::vector<llvm::Value*> llargs; + llargs.resize(4); + llargs[0] = dstarr; + llargs[1] = srcarr; + llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); + llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); + + new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -825,14 +839,19 @@ return _init; } +////////////////////////////////////////////////////////////////////////////////////////// + llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const std::string& var, llvm::BasicBlock* bb) { std::vector<llvm::Value*> v(2); v[0] = i0; v[1] = i1; + Logger::cout() << "DtoGEP: " << *ptr << '\n'; return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb); } +////////////////////////////////////////////////////////////////////////////////////////// + llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb) { size_t n = src.size(); @@ -847,9 +866,32 @@ return new llvm::GetElementPtrInst(ptr, dst.begin(), dst.end(), var, bb); } +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i, const std::string& var, llvm::BasicBlock* bb) +{ + return new llvm::GetElementPtrInst(ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false), var, bb); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb) +{ + std::vector<llvm::Value*> v(2); + v[0] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i0, false); + v[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i1, false); + return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb); +} + +////////////////////////////////////////////////////////////////////////////////////////// + llvm::Function* LLVM_DtoDeclareFunction(FuncDeclaration* fdecl) { + TypeFunction* f = (TypeFunction*)fdecl->type; + assert(f != 0); + if (fdecl->llvmValue != 0) { + assert(llvm::isa<llvm::Function>(fdecl->llvmValue)); return llvm::cast<llvm::Function>(fdecl->llvmValue); } @@ -863,9 +905,7 @@ } // construct function - TypeFunction* f = (TypeFunction*)fdecl->type; - assert(f != 0); - llvm::FunctionType* functype = (f->llvmType == 0) ? LLVM_DtoFunctionType(fdecl) : llvm::cast<llvm::FunctionType>(f->llvmType); + const llvm::FunctionType* functype = (f->llvmType == 0) ? LLVM_DtoFunctionType(fdecl) : llvm::cast<llvm::FunctionType>(f->llvmType); // mangled name char* mangled_name = (fdecl->llvmInternal == LLVMintrinsic) ? fdecl->llvmInternal1 : fdecl->mangle(); @@ -881,6 +921,7 @@ fdecl->llvmValue = func; f->llvmType = functype; + assert(llvm::isa<llvm::FunctionType>(f->llvmType)); if (fdecl->isMain()) { gIR->mainFunc = func;
--- a/gen/tollvm.h Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/tollvm.h Tue Oct 02 05:10:18 2007 +0200 @@ -4,16 +4,16 @@ const llvm::Type* LLVM_DtoType(Type* t); -llvm::Type* LLVM_DtoStructType(Type* t); +const llvm::Type* LLVM_DtoStructType(Type* t); llvm::Value* LLVM_DtoStructZeroInit(TypeStruct* t, llvm::Value* v); llvm::Value* LLVM_DtoStructCopy(TypeStruct* t, llvm::Value* dst, llvm::Value* src); llvm::Constant* LLVM_DtoStructInitializer(StructInitializer* si); -llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam = 0); -llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl); +const llvm::FunctionType* LLVM_DtoFunctionType(Type* t, const llvm::Type* thisparam = 0); +const llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl); llvm::Function* LLVM_DtoDeclareFunction(FuncDeclaration* fdecl); -llvm::StructType* LLVM_DtoDelegateType(Type* t); +const llvm::StructType* LLVM_DtoDelegateType(Type* t); llvm::Value* LLVM_DtoNullDelegate(llvm::Value* v); llvm::Value* LLVM_DtoDelegateCopy(llvm::Value* dst, llvm::Value* src); @@ -39,5 +39,7 @@ llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const std::string& var, llvm::BasicBlock* bb); llvm::Value* LLVM_DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb); +llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, const std::string& var, llvm::BasicBlock* bb); +llvm::Value* LLVM_DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb); #include "enums.h"
--- a/gen/toobj.c Mon Oct 01 23:32:29 2007 +0200 +++ b/gen/toobj.c Tue Oct 02 05:10:18 2007 +0200 @@ -80,18 +80,21 @@ delete gTargetData; gTargetData = 0; + // emit the llvm main function if necessary + if (ir.emitMain) { + LLVM_DtoMain(); + } + // verify the llvm std::string verifyErr; + Logger::println("Verifying module..."); if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) { error("%s", verifyErr.c_str()); fatal(); } - - // emit the llvm main function if necessary - if (ir.emitMain) { - LLVM_DtoMain(); - } + else + Logger::println("Verification passed!"); // run passes // TODO @@ -386,6 +389,7 @@ if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { fd->toObjFile(); + assert(fd->llvmValue); llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); sinits.push_back(c); sinits_ty.push_back(c->getType()); @@ -437,17 +441,11 @@ assert(svtblVar != 0); gIR->topstruct().inits[0] = svtblVar; - //assert(tk == gIR->topstruct().size()); - #ifndef LLVMD_NO_LOGGER - Logger::cout() << *structtype << '\n'; - //for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) - // Logger::cout() << *gIR->topstruct().inits[k] << '\n'; - #endif _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits); assert(_init); std::string initname(mangle()); initname.append("__initZ"); - Logger::cout() << *_init << '\n'; + //Logger::cout() << *_init << '\n'; llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, 0, initname, gIR->module); ts->llvmInit = initvar; if (define_vtable) { @@ -616,27 +614,33 @@ llvm::Function* func = LLVM_DtoDeclareFunction(this); if (!gIR->queueClassMethods.empty() && gIR->queueClassMethods.back()) { - Logger::println("queueing %s", toChars()); - assert(!gIR->classmethods.empty()); - gIR->classmethods.back().push_back(this); + if (!llvmQueued) { + Logger::println("queueing %s", toChars()); + assert(!gIR->classmethods.empty()); + gIR->classmethods.back().push_back(this); + llvmQueued = true; + } return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete } TypeFunction* f = (TypeFunction*)type; - llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(f->llvmType); + assert(f->llvmType); + const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0)); // only members of the current module maybe be defined if (getModule() == gIR->dmodule) { + llvmDModule = gIR->dmodule; + bool allow_fbody = true; // handle static constructor / destructor if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) { const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1); //Logger::cout() << "static ctor type: " << *sctor_type << '\n'; - + llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue); //Logger::cout() << "static ctor func: " << *sctor_func << '\n'; - + llvm::Constant* sctor_init = 0; if (llvmInternal == LLVMnull) { @@ -648,10 +652,9 @@ { sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1); } - + //Logger::cout() << "static ctor init: " << *sctor_init << '\n'; - - + // output the llvm.global_ctors array const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array"; llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module); @@ -660,6 +663,9 @@ // function definition if (allow_fbody && fbody != 0) { + // first make absolutely sure the type is up to date + f->llvmType = llvmValue->getType()->getContainedType(0); + if (isMain()) gIR->emitMain = true; @@ -672,10 +678,10 @@ //assert(gIR->scopes.empty()); gIR->scopes.push_back(irs); - + // create alloca point f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); - + // output function body fbody->toIR(gIR); @@ -686,7 +692,7 @@ //new llvm::BranchInst(irs.end, irs.begin); new llvm::ReturnInst(gIR->scopebb()); } - + // erase alloca point f->llvmAllocaPoint->eraseFromParent(); f->llvmAllocaPoint = 0; @@ -710,8 +716,4 @@ } } } - - llvmDModule = gIR->dmodule; - - Logger::println("FuncDeclaration done\n"); }
--- a/lphobos/llvm/intrinsic.d Mon Oct 01 23:32:29 2007 +0200 +++ b/lphobos/llvm/intrinsic.d Tue Oct 02 05:10:18 2007 +0200 @@ -29,10 +29,10 @@ pragma(LLVM_internal, "intrinsic", "llvm.prefetch") void llvm_prefetch(void* ptr, uint rw, uint locality); +*/ pragma(LLVM_internal, "intrinsic", "llvm.readcyclecounter") - ulong llvm_readcyclecounter(); -*/ + ulong readcyclecounter(); // standard C intrinsics pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i32")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runalltests.d Tue Oct 02 05:10:18 2007 +0200 @@ -0,0 +1,33 @@ +module runalltests; + +import std.file; +import std.path; +import std.process; +import std.stdio; + +int main(string[] args) { + string[] good; + string[] bad; + + auto contents = listdir("test", "*.d"); + foreach(c; contents) { + if (system("./tester.sh "~getName(c)~" ll") != 0) { + bad ~= c; + } + else { + good ~= c; + } + } + + int ret = 0; + if (bad.length > 0) { + writefln(bad.length, '/', contents.length, " tests failed:"); + foreach(b; bad) { + writefln(" ",b); + } + ret = 1; + } + + writefln(good.length, '/', contents.length, " tests passed"); + return ret; +}
--- a/test/classes6.d Mon Oct 01 23:32:29 2007 +0200 +++ b/test/classes6.d Tue Oct 02 05:10:18 2007 +0200 @@ -4,12 +4,34 @@ { void f() { - printf("hello world\n"); + printf("world\n"); + } +} + +class D : C +{ + void f() + { + printf("moon\n"); } } + +extern(C) +{ + void srand(uint seed); + int rand(); +} + +import llvm.intrinsic; + void main() { - scope c = new C; + C c; + srand(readcyclecounter()); + if (rand() % 2) + c = new C; + else + c = new D; c.f(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/classes7.d Tue Oct 02 05:10:18 2007 +0200 @@ -0,0 +1,21 @@ +module classes7; + +class C +{ + int i=0; + void f() + { + i=42; + } + void g() + { + f(); + } +} + +void main() +{ + scope c = new C; + c.g(); + assert(c.i == 43); +}
--- a/tester.sh Mon Oct 01 23:32:29 2007 +0200 +++ b/tester.sh Tue Oct 02 05:10:18 2007 +0200 @@ -6,24 +6,30 @@ fi if [ "$2" = "ll" ]; then - make && llvmdc $1 -Itest -odtest -c && llvm-dis -f $1.bc && cat $1.ll exit $? +elif [ "$2" = "llopt" ]; then + llvmdc $1 -Itest -odtest -c && + opt -f -o=$1.bc -std-compile-opts $1.bc && + llvm-dis -f $1.bc && + cat $1.ll + exit $? elif [ "$2" = "run" ]; then - make && llvmdc $1 -Itest -odtest -of$1 && $1 exit $? elif [ "$2" = "c" ]; then - make && llvmdc $1 -Itest -odtest -c exit $? elif [ "$2" = "gdb" ]; then - make && gdb --args llvmdc $1 -Itest -odtest '-c' exit $? +elif [ "$2" = "gdbrun" ]; then + llvmdc $1 -Itest -odtest '-c' && + gdb $1 + exit $? else echo "bad command or filename" fi