@@ -566,34 +566,75 @@ LLVM_VALUE ExprBinaryOpNode::codegen(LLVM_BUILDER Builder) LLVM_BODY {
566566 LLVM_VALUE op1 = pv.first ;
567567 LLVM_VALUE op2 = pv.second ;
568568
569- switch (_op) {
570- case ' +' :
571- return Builder.CreateFAdd (op1, op2);
572- case ' -' :
573- return Builder.CreateFSub (op1, op2);
574- case ' *' :
575- return Builder.CreateFMul (op1, op2);
576- case ' /' :
577- return Builder.CreateFDiv (op1, op2);
578- case ' %' : {
579- // niceMod() from v1: b==0 ? 0 : a-floor(a/b)*b
580- LLVM_VALUE a = op1, b = op2;
581- LLVM_VALUE aOverB = Builder.CreateFDiv (a, b);
582- Function *floorFun = Intrinsic::getDeclaration (llvm_getModule (Builder), Intrinsic::floor, op1->getType ());
583- LLVM_VALUE normal = Builder.CreateFSub (a, Builder.CreateFMul (Builder.CreateCall (floorFun, {aOverB}), b));
584- Constant *zero = ConstantFP::get (op1->getType (), 0.0 );
585- return Builder.CreateSelect (Builder.CreateFCmpOEQ (zero, op1), zero, normal);
586- }
587- case ' ^' : {
588- // TODO: make external function reference work with interpreter, libffi
589- // TODO: needed for MCJIT??
590- // TODO: is the above not already done?!
591- std::vector<Type *> arg_type;
592- arg_type.push_back (op1->getType ());
593- Function *fun = Intrinsic::getDeclaration (llvm_getModule (Builder), Intrinsic::pow, arg_type);
594- std::vector<LLVM_VALUE> ops = {op1, op2};
595- return Builder.CreateCall (fun, ops);
569+ const bool isString = child (0 )->type ().isString ();
570+
571+ if (isString == false ) {
572+ switch (_op) {
573+ case ' +' :
574+ return Builder.CreateFAdd (op1, op2);
575+ case ' -' :
576+ return Builder.CreateFSub (op1, op2);
577+ case ' *' :
578+ return Builder.CreateFMul (op1, op2);
579+ case ' /' :
580+ return Builder.CreateFDiv (op1, op2);
581+ case ' %' : {
582+ // niceMod() from v1: b==0 ? 0 : a-floor(a/b)*b
583+ LLVM_VALUE a = op1, b = op2;
584+ LLVM_VALUE aOverB = Builder.CreateFDiv (a, b);
585+ Function *floorFun = Intrinsic::getDeclaration (llvm_getModule (Builder), Intrinsic::floor, op1->getType ());
586+ LLVM_VALUE normal = Builder.CreateFSub (a, Builder.CreateFMul (Builder.CreateCall (floorFun, {aOverB}), b));
587+ Constant *zero = ConstantFP::get (op1->getType (), 0.0 );
588+ return Builder.CreateSelect (Builder.CreateFCmpOEQ (zero, op1), zero, normal);
589+ }
590+ case ' ^' : {
591+ // TODO: make external function reference work with interpreter, libffi
592+ // TODO: needed for MCJIT??
593+ // TODO: is the above not already done?!
594+ std::vector<Type *> arg_type;
595+ arg_type.push_back (op1->getType ());
596+ Function *fun = Intrinsic::getDeclaration (llvm_getModule (Builder), Intrinsic::pow, arg_type);
597+ std::vector<LLVM_VALUE> ops = {op1, op2};
598+ return Builder.CreateCall (fun, ops);
599+ }
596600 }
601+ } else {
602+ // precompute a few things
603+ LLVMContext &context = Builder.getContext ();
604+ Module *module = llvm_getModule (Builder);
605+ PointerType *i8PtrPtrTy = PointerType::getUnqual (Type::getInt8PtrTy (context));
606+ Type *i32Ty = Type::getInt32Ty (context);
607+ Function *strlen = module ->getFunction (" strlen" );
608+ Function *malloc = module ->getFunction (" malloc" );
609+ Function *free = module ->getFunction (" free" );
610+ Function *memset = module ->getFunction (" memset" );
611+ Function *strcat = module ->getFunction (" strcat" );
612+
613+ // do magic (see the pseudo C code on the comments at the end
614+ // of each LLVM instruction)
615+
616+ // compute the length of the operand strings
617+ LLVM_VALUE len1 = Builder.CreateCall (strlen, { op1 }); // len1 = strlen(op1);
618+ LLVM_VALUE len2 = Builder.CreateCall (strlen, { op2 }); // len2 = strlen(op2);
619+ LLVM_VALUE len = Builder.CreateAdd (len1, len2); // len = len1 + len2;
620+
621+ // allocate and clear memory
622+ LLVM_VALUE alloc = Builder.CreateCall (malloc, { len }); // alloc = malloc(len1 + len2);
623+ LLVM_VALUE zero = ConstantInt::get (i32Ty, 0 ); // zero = 0;
624+ Builder.CreateCall (memset, { alloc, zero, len }); // memset(alloc, zero, len);
625+
626+ // concatenate operand strings into output string
627+ Builder.CreateCall (strcat, { alloc, op1 }); // strcat(alloc, op1);
628+ LLVM_VALUE newAlloc = Builder.CreateGEP (nullptr , alloc, len1); // newAlloc = alloc + len1
629+ Builder.CreateCall (strcat, { newAlloc, op2 }); // strcat(alloc, op2);
630+
631+ // store the address in the node's _out member so that it will be
632+ // cleaned up when the expression is destroyed.
633+ APInt outAddr = APInt (64 , (uint64_t )&_out);
634+ LLVM_VALUE out = Constant::getIntegerValue (i8PtrPtrTy, outAddr); // out = &_out;
635+ Builder.CreateCall (free, { Builder.CreateLoad (out) }); // free(*out);
636+ Builder.CreateStore (alloc, out); // *out = alloc
637+ return alloc;
597638 }
598639
599640 assert (false && " unexpected op" );
0 commit comments