Mercurial > projects > ldc
comparison gen/toir.cpp @ 414:ac1fcc138e42
Fixed issue with internal real representation, incorrect for non x86-32 architectures.
Cleaned up CallExp::toElem, moved implementation to tocall.cpp providing a single procedure to call arbitrary D functions fairly easily.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 28 Jul 2008 02:11:34 +0200 |
parents | 0e6b4d65d3f8 |
children | fa91b03d9cd7 |
comparison
equal
deleted
inserted
replaced
413:1a9bdbd4ac60 | 414:ac1fcc138e42 |
---|---|
849 return res; | 849 return res; |
850 } | 850 } |
851 | 851 |
852 ////////////////////////////////////////////////////////////////////////////////////////// | 852 ////////////////////////////////////////////////////////////////////////////////////////// |
853 | 853 |
854 // TODO: the method below could really use a cleanup/splitup | |
855 | |
856 DValue* CallExp::toElem(IRState* p) | 854 DValue* CallExp::toElem(IRState* p) |
857 { | 855 { |
858 Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars()); | 856 Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars()); |
859 LOG_SCOPE; | 857 LOG_SCOPE; |
860 | 858 |
861 DValue* fn = e1->toElem(p); | 859 // get the callee value |
862 | 860 DValue* fnval = e1->toElem(p); |
863 TypeFunction* tf = 0; | 861 |
864 Type* e1type = DtoDType(e1->type); | 862 // get func value if any |
865 | 863 DFuncValue* dfnval = fnval->isFunc(); |
866 bool delegateCall = false; | 864 |
867 LINK dlink = LINKd; | 865 // handle magic intrinsics (mapping to instructions) |
868 | |
869 // hidden struct return parameter handling | |
870 bool retinptr = false; | |
871 | |
872 // regular functions | |
873 if (e1type->ty == Tfunction) { | |
874 tf = (TypeFunction*)e1type; | |
875 if (tf->llvmRetInPtr) { | |
876 retinptr = true; | |
877 } | |
878 dlink = tf->linkage; | |
879 } | |
880 | |
881 // delegates | |
882 else if (e1type->ty == Tdelegate) { | |
883 Logger::println("delegateTy = %s\n", e1type->toChars()); | |
884 assert(e1type->next->ty == Tfunction); | |
885 tf = (TypeFunction*)e1type->next; | |
886 if (tf->llvmRetInPtr) { | |
887 retinptr = true; | |
888 } | |
889 dlink = tf->linkage; | |
890 delegateCall = true; | |
891 } | |
892 | |
893 // invalid | |
894 else { | |
895 assert(tf); | |
896 } | |
897 | |
898 // handling of special intrinsics | |
899 bool va_magic = false; | |
900 bool va_intrinsic = false; | 866 bool va_intrinsic = false; |
901 DFuncValue* dfv = fn->isFunc(); | 867 if (dfnval && dfnval->func) |
902 if (dfv && dfv->func) { | 868 { |
903 FuncDeclaration* fndecl = dfv->func; | 869 FuncDeclaration* fndecl = dfnval->func; |
904 // vararg intrinsic | |
905 if (fndecl->llvmInternal == LLVMva_intrinsic) { | |
906 va_magic = true; | |
907 va_intrinsic = true; | |
908 } | |
909 // va_start instruction | 870 // va_start instruction |
910 else if (fndecl->llvmInternal == LLVMva_start) { | 871 if (fndecl->llvmInternal == LLVMva_start) { |
911 va_magic = true; | 872 // TODO |
873 assert(0 && "va_start not yet implemented"); | |
912 } | 874 } |
913 // va_arg instruction | 875 // va_arg instruction |
914 else if (fndecl->llvmInternal == LLVMva_arg) { | 876 else if (fndecl->llvmInternal == LLVMva_arg) { |
915 //Argument* fnarg = Argument::getNth(tf->parameters, 0); | 877 return DtoVaArg(loc, type, (Expression*)arguments->data[0]); |
916 Expression* exp = (Expression*)arguments->data[0]; | 878 } |
917 DValue* expelem = exp->toElem(p); | 879 // C alloca |
918 Type* t = DtoDType(type); | |
919 const LLType* llt = DtoType(type); | |
920 if (DtoIsPassedByRef(t)) | |
921 llt = getPtrToType(llt); | |
922 // TODO | |
923 // issue a warning for broken va_arg instruction. | |
924 if (strcmp(global.params.llvmArch, "x86") != 0) { | |
925 warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars()); | |
926 } | |
927 // done | |
928 return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp")); | |
929 } | |
930 // alloca | |
931 else if (fndecl->llvmInternal == LLVMalloca) { | 880 else if (fndecl->llvmInternal == LLVMalloca) { |
932 //Argument* fnarg = Argument::getNth(tf->parameters, 0); | |
933 Expression* exp = (Expression*)arguments->data[0]; | 881 Expression* exp = (Expression*)arguments->data[0]; |
934 DValue* expv = exp->toElem(p); | 882 DValue* expv = exp->toElem(p); |
935 if (expv->getType()->toBasetype()->ty != Tint32) | 883 if (expv->getType()->toBasetype()->ty != Tint32) |
936 expv = DtoCast(loc, expv, Type::tint32); | 884 expv = DtoCast(loc, expv, Type::tint32); |
937 LLValue* alloc = new llvm::AllocaInst(LLType::Int8Ty, expv->getRVal(), "alloca", p->scopebb()); | 885 return new DImValue(type, gIR->ir->CreateAlloca(LLType::Int8Ty, expv->getRVal(), ".alloca")); |
938 // done | 886 } |
939 return new DImValue(type, alloc); | 887 } |
940 } | 888 |
941 } | 889 return DtoCallFunction(type, fnval, arguments); |
942 | |
943 // args | |
944 size_t n = arguments->dim; | |
945 DFuncValue* dfn = fn->isFunc(); | |
946 if (dfn && dfn->func && dfn->func->llvmInternal == LLVMva_start) | |
947 n = 1; | |
948 if (delegateCall || (dfn && dfn->vthis)) n++; | |
949 if (retinptr) n++; | |
950 if (tf->linkage == LINKd && tf->varargs == 1) n+=2; | |
951 if (dfn && dfn->func && dfn->func->isNested()) n++; | |
952 | |
953 LLValue* funcval = fn->getRVal(); | |
954 assert(funcval != 0); | |
955 std::vector<LLValue*> llargs(n, 0); | |
956 | |
957 const LLFunctionType* llfnty = 0; | |
958 | |
959 // TODO: review the stuff below, using the llvm type to choose seem like a bad idea. the D type should be used. | |
960 // | |
961 // normal function call | |
962 if (llvm::isa<LLFunctionType>(funcval->getType())) { | |
963 llfnty = llvm::cast<LLFunctionType>(funcval->getType()); | |
964 } | |
965 // pointer to something | |
966 else if (isaPointer(funcval->getType())) { | |
967 // pointer to function pointer - I think this not really supposed to happen, but does :/ | |
968 // seems like sometimes we get a func* other times a func** | |
969 if (isaPointer(funcval->getType()->getContainedType(0))) { | |
970 funcval = DtoLoad(funcval); | |
971 } | |
972 // function pointer | |
973 if (llvm::isa<LLFunctionType>(funcval->getType()->getContainedType(0))) { | |
974 //Logger::cout() << "function pointer type:\n" << *funcval << '\n'; | |
975 llfnty = llvm::cast<LLFunctionType>(funcval->getType()->getContainedType(0)); | |
976 } | |
977 // struct pointer - delegate | |
978 else if (isaStruct(funcval->getType()->getContainedType(0))) { | |
979 funcval = DtoGEPi(funcval,0,1); | |
980 funcval = DtoLoad(funcval); | |
981 const LLType* ty = funcval->getType()->getContainedType(0); | |
982 llfnty = llvm::cast<LLFunctionType>(ty); | |
983 } | |
984 // unknown | |
985 else { | |
986 Logger::cout() << "what kind of pointer are we calling? : " << *funcval->getType() << '\n'; | |
987 } | |
988 } | |
989 else { | |
990 Logger::cout() << "what are we calling? : " << *funcval << '\n'; | |
991 } | |
992 assert(llfnty); | |
993 //Logger::cout() << "Function LLVM type: " << *llfnty << '\n'; | |
994 | |
995 // argument handling | |
996 LLFunctionType::param_iterator argiter = llfnty->param_begin(); | |
997 int j = 0; | |
998 | |
999 // attrs | |
1000 llvm::PAListPtr palist; | |
1001 | |
1002 // hidden struct return arguments | |
1003 // TODO: use sret param attr | |
1004 if (retinptr) { | |
1005 llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint()); | |
1006 ++j; | |
1007 ++argiter; | |
1008 } | |
1009 | |
1010 // this arguments | |
1011 if (dfn && dfn->vthis) { | |
1012 Logger::cout() << "This Call" << '\n';// func val:" << *funcval << '\n'; | |
1013 if (dfn->vthis->getType() != argiter->get()) { | |
1014 //Logger::cout() << "value: " << *dfn->vthis << " totype: " << *argiter->get() << '\n'; | |
1015 llargs[j] = DtoBitCast(dfn->vthis, argiter->get()); | |
1016 } | |
1017 else { | |
1018 llargs[j] = dfn->vthis; | |
1019 } | |
1020 ++j; | |
1021 ++argiter; | |
1022 } | |
1023 // delegate context arguments | |
1024 else if (delegateCall) { | |
1025 Logger::println("Delegate Call"); | |
1026 LLValue* contextptr = DtoGEPi(fn->getRVal(),0,0); | |
1027 llargs[j] = DtoLoad(contextptr); | |
1028 ++j; | |
1029 ++argiter; | |
1030 } | |
1031 // nested call | |
1032 else if (dfn && dfn->func && dfn->func->isNested()) { | |
1033 Logger::println("Nested Call"); | |
1034 LLValue* contextptr = DtoNestedContext(dfn->func->toParent2()->isFuncDeclaration()); | |
1035 if (!contextptr) | |
1036 contextptr = llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty)); | |
1037 llargs[j] = DtoBitCast(contextptr, getPtrToType(LLType::Int8Ty)); | |
1038 ++j; | |
1039 ++argiter; | |
1040 } | |
1041 | |
1042 // va arg function special argument passing | |
1043 if (va_magic) | |
1044 { | |
1045 size_t n = va_intrinsic ? arguments->dim : 1; | |
1046 for (int i=0; i<n; i++,j++) | |
1047 { | |
1048 Argument* fnarg = Argument::getNth(tf->parameters, i); | |
1049 Expression* exp = (Expression*)arguments->data[i]; | |
1050 DValue* expelem = exp->toElem(p); | |
1051 llargs[j] = DtoBitCast(expelem->getLVal(), getPtrToType(LLType::Int8Ty)); | |
1052 } | |
1053 } | |
1054 // d variadic function | |
1055 else if (tf->linkage == LINKd && tf->varargs == 1) | |
1056 { | |
1057 Logger::println("doing d-style variadic arguments"); | |
1058 | |
1059 size_t nimplicit = j; | |
1060 | |
1061 std::vector<const LLType*> vtypes; | |
1062 | |
1063 // number of non variadic args | |
1064 int begin = tf->parameters->dim; | |
1065 Logger::println("num non vararg params = %d", begin); | |
1066 | |
1067 // build struct with argument types | |
1068 for (int i=begin; i<arguments->dim; i++) | |
1069 { | |
1070 Argument* argu = Argument::getNth(tf->parameters, i); | |
1071 Expression* argexp = (Expression*)arguments->data[i]; | |
1072 vtypes.push_back(DtoType(argexp->type)); | |
1073 size_t sz = getABITypeSize(vtypes.back()); | |
1074 if (sz < PTRSIZE) | |
1075 vtypes.back() = DtoSize_t(); | |
1076 } | |
1077 const LLStructType* vtype = LLStructType::get(vtypes); | |
1078 Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n'; | |
1079 LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint()); | |
1080 | |
1081 // store arguments in the struct | |
1082 for (int i=begin,k=0; i<arguments->dim; i++,k++) | |
1083 { | |
1084 Expression* argexp = (Expression*)arguments->data[i]; | |
1085 if (global.params.llvmAnnotate) | |
1086 DtoAnnotation(argexp->toChars()); | |
1087 LLValue* argdst = DtoGEPi(mem,0,k); | |
1088 argdst = DtoBitCast(argdst, getPtrToType(DtoType(argexp->type))); | |
1089 DtoVariadicArgument(argexp, argdst); | |
1090 } | |
1091 | |
1092 // build type info array | |
1093 assert(Type::typeinfo->ir.irStruct->constInit); | |
1094 const LLType* typeinfotype = DtoType(Type::typeinfo->type); | |
1095 const LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements()); | |
1096 | |
1097 llvm::GlobalVariable* typeinfomem = | |
1098 new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module); | |
1099 Logger::cout() << "_arguments storage: " << *typeinfomem << '\n'; | |
1100 | |
1101 std::vector<LLConstant*> vtypeinfos; | |
1102 for (int i=begin,k=0; i<arguments->dim; i++,k++) | |
1103 { | |
1104 Expression* argexp = (Expression*)arguments->data[i]; | |
1105 vtypeinfos.push_back(DtoTypeInfoOf(argexp->type)); | |
1106 } | |
1107 | |
1108 // apply initializer | |
1109 LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos); | |
1110 typeinfomem->setInitializer(tiinits); | |
1111 | |
1112 // put data in d-array | |
1113 std::vector<LLConstant*> pinits; | |
1114 pinits.push_back(DtoConstSize_t(vtype->getNumElements())); | |
1115 pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype))); | |
1116 const LLType* tiarrty = llfnty->getParamType(j)->getContainedType(0); | |
1117 tiinits = llvm::ConstantStruct::get(pinits); | |
1118 LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty, | |
1119 true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module); | |
1120 | |
1121 // specify arguments | |
1122 llargs[j] = typeinfoarrayparam;; | |
1123 j++; | |
1124 llargs[j] = p->ir->CreateBitCast(mem, getPtrToType(LLType::Int8Ty), "tmp"); | |
1125 j++; | |
1126 | |
1127 // pass non variadic args | |
1128 for (int i=0; i<begin; i++) | |
1129 { | |
1130 Argument* fnarg = Argument::getNth(tf->parameters, i); | |
1131 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); | |
1132 llargs[j] = argval->getRVal(); | |
1133 | |
1134 if (fnarg->llvmByVal) | |
1135 palist = palist.addAttr(j, llvm::ParamAttr::ByVal); | |
1136 | |
1137 j++; | |
1138 } | |
1139 | |
1140 // make sure arg vector has the right size | |
1141 llargs.resize(nimplicit+begin+2); | |
1142 } | |
1143 // normal function call | |
1144 else | |
1145 { | |
1146 Logger::println("doing normal arguments"); | |
1147 for (int i=0; i<arguments->dim; i++,j++) { | |
1148 Argument* fnarg = Argument::getNth(tf->parameters, i); | |
1149 if (global.params.llvmAnnotate) | |
1150 DtoAnnotation(((Expression*)arguments->data[i])->toChars()); | |
1151 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); | |
1152 llargs[j] = argval->getRVal(); | |
1153 if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) { | |
1154 llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); | |
1155 } | |
1156 | |
1157 if (fnarg && fnarg->llvmByVal) | |
1158 palist = palist.addAttr(j+1, llvm::ParamAttr::ByVal); | |
1159 } | |
1160 } | |
1161 | |
1162 #if 0 | |
1163 Logger::println("%d params passed", n); | |
1164 for (int i=0; i<llargs.size(); ++i) { | |
1165 assert(llargs[i]); | |
1166 Logger::cout() << "arg["<<i<<"] = " << *llargs[i] << '\n'; | |
1167 } | |
1168 #endif | |
1169 | |
1170 // void returns cannot not be named | |
1171 const char* varname = ""; | |
1172 if (llfnty->getReturnType() != LLType::VoidTy) | |
1173 varname = "tmp"; | |
1174 | |
1175 //Logger::cout() << "Calling: " << *funcval << '\n'; | |
1176 | |
1177 // call the function | |
1178 CallOrInvoke* call = gIR->CreateCallOrInvoke(funcval, llargs.begin(), llargs.end(), varname); | |
1179 | |
1180 LLValue* retllval = (retinptr) ? llargs[0] : call->get(); | |
1181 | |
1182 // if the type of retllval is abstract, refine to concrete | |
1183 if(retllval->getType()->isAbstract()) | |
1184 retllval = DtoBitCast(retllval, getPtrToType(DtoType(type)), "retval"); | |
1185 | |
1186 // set calling convention | |
1187 if (dfn && dfn->func) { | |
1188 int li = dfn->func->llvmInternal; | |
1189 if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) { | |
1190 call->setCallingConv(DtoCallingConv(dlink)); | |
1191 } | |
1192 } | |
1193 else { | |
1194 call->setCallingConv(DtoCallingConv(dlink)); | |
1195 } | |
1196 | |
1197 // param attrs | |
1198 call->setParamAttrs(palist); | |
1199 | |
1200 return new DImValue(type, retllval, false); | |
1201 } | 890 } |
1202 | 891 |
1203 ////////////////////////////////////////////////////////////////////////////////////////// | 892 ////////////////////////////////////////////////////////////////////////////////////////// |
1204 | 893 |
1205 DValue* CastExp::toElem(IRState* p) | 894 DValue* CastExp::toElem(IRState* p) |