Mercurial > projects > ldc
comparison gen/toir.cpp @ 215:a58d8f4b84df trunk
[svn r231] Changed: warnings are no longer treated as an error.
Added some comments and cleaned up CallExp::toElem a tiny bit.
Fixed: struct literals always reported inplace assignment even if they allocated a temporary.
Fixed: passing stuff to a D-style vararg which did inplace assignment was generated suboptimal code.
author | lindquist |
---|---|
date | Tue, 03 Jun 2008 13:51:09 +0200 |
parents | 7816aafeea3c |
children | 0806379a5eca |
comparison
equal
deleted
inserted
replaced
214:629cfc1e7b77 | 215:a58d8f4b84df |
---|---|
865 return l; | 865 return l; |
866 } | 866 } |
867 | 867 |
868 ////////////////////////////////////////////////////////////////////////////////////////// | 868 ////////////////////////////////////////////////////////////////////////////////////////// |
869 | 869 |
870 // TODO: the method below could really use a cleanup/splitup | |
871 | |
870 DValue* CallExp::toElem(IRState* p) | 872 DValue* CallExp::toElem(IRState* p) |
871 { | 873 { |
872 Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars()); | 874 Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars()); |
873 LOG_SCOPE; | 875 LOG_SCOPE; |
874 | 876 |
909 // invalid | 911 // invalid |
910 else { | 912 else { |
911 assert(tf); | 913 assert(tf); |
912 } | 914 } |
913 | 915 |
914 // magic stuff | 916 // handling of special intrinsics |
915 bool va_magic = false; | 917 bool va_magic = false; |
916 bool va_intrinsic = false; | 918 bool va_intrinsic = false; |
917 DFuncValue* dfv = fn->isFunc(); | 919 DFuncValue* dfv = fn->isFunc(); |
918 if (dfv && dfv->func) { | 920 if (dfv && dfv->func) { |
919 FuncDeclaration* fndecl = dfv->func; | 921 FuncDeclaration* fndecl = dfv->func; |
922 // vararg intrinsic | |
920 if (fndecl->llvmInternal == LLVMva_intrinsic) { | 923 if (fndecl->llvmInternal == LLVMva_intrinsic) { |
921 va_magic = true; | 924 va_magic = true; |
922 va_intrinsic = true; | 925 va_intrinsic = true; |
923 } | 926 } |
927 // va_start instruction | |
924 else if (fndecl->llvmInternal == LLVMva_start) { | 928 else if (fndecl->llvmInternal == LLVMva_start) { |
925 va_magic = true; | 929 va_magic = true; |
926 } | 930 } |
931 // va_arg instruction | |
927 else if (fndecl->llvmInternal == LLVMva_arg) { | 932 else if (fndecl->llvmInternal == LLVMva_arg) { |
928 //Argument* fnarg = Argument::getNth(tf->parameters, 0); | 933 //Argument* fnarg = Argument::getNth(tf->parameters, 0); |
929 Expression* exp = (Expression*)arguments->data[0]; | 934 Expression* exp = (Expression*)arguments->data[0]; |
930 DValue* expelem = exp->toElem(p); | 935 DValue* expelem = exp->toElem(p); |
931 Type* t = DtoDType(type); | 936 Type* t = DtoDType(type); |
932 const LLType* llt = DtoType(type); | 937 const LLType* llt = DtoType(type); |
933 if (DtoIsPassedByRef(t)) | 938 if (DtoIsPassedByRef(t)) |
934 llt = getPtrToType(llt); | 939 llt = getPtrToType(llt); |
935 // TODO | 940 // TODO |
941 // issue a warning for broken va_arg instruction. | |
936 if (strcmp(global.params.llvmArch, "x86") != 0) { | 942 if (strcmp(global.params.llvmArch, "x86") != 0) { |
937 warning("%s: va_arg for C variadic functions is broken for anything but x86", loc.toChars()); | 943 warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars()); |
938 } | 944 } |
945 // done | |
939 return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp")); | 946 return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp")); |
940 } | 947 } |
948 // alloca | |
941 else if (fndecl->llvmInternal == LLVMalloca) { | 949 else if (fndecl->llvmInternal == LLVMalloca) { |
942 //Argument* fnarg = Argument::getNth(tf->parameters, 0); | 950 //Argument* fnarg = Argument::getNth(tf->parameters, 0); |
943 Expression* exp = (Expression*)arguments->data[0]; | 951 Expression* exp = (Expression*)arguments->data[0]; |
944 DValue* expv = exp->toElem(p); | 952 DValue* expv = exp->toElem(p); |
945 if (expv->getType()->toBasetype()->ty != Tint32) | 953 if (expv->getType()->toBasetype()->ty != Tint32) |
946 expv = DtoCast(expv, Type::tint32); | 954 expv = DtoCast(expv, Type::tint32); |
947 LLValue* alloc = new llvm::AllocaInst(llvm::Type::Int8Ty, expv->getRVal(), "alloca", p->scopebb()); | 955 LLValue* alloc = new llvm::AllocaInst(llvm::Type::Int8Ty, expv->getRVal(), "alloca", p->scopebb()); |
956 // done | |
948 return new DImValue(type, alloc); | 957 return new DImValue(type, alloc); |
949 } | 958 } |
950 } | 959 } |
951 | 960 |
952 // args | 961 // args |
963 assert(funcval != 0); | 972 assert(funcval != 0); |
964 std::vector<LLValue*> llargs(n, 0); | 973 std::vector<LLValue*> llargs(n, 0); |
965 | 974 |
966 const llvm::FunctionType* llfnty = 0; | 975 const llvm::FunctionType* llfnty = 0; |
967 | 976 |
977 // TODO: review the stuff below, using the llvm type to choose seem like a bad idea. the D type should be used. | |
978 // | |
968 // normal function call | 979 // normal function call |
969 if (llvm::isa<llvm::FunctionType>(funcval->getType())) { | 980 if (llvm::isa<llvm::FunctionType>(funcval->getType())) { |
970 llfnty = llvm::cast<llvm::FunctionType>(funcval->getType()); | 981 llfnty = llvm::cast<llvm::FunctionType>(funcval->getType()); |
971 } | 982 } |
972 // pointer to something | 983 // pointer to something |
1080 Expression* exp = (Expression*)arguments->data[i]; | 1091 Expression* exp = (Expression*)arguments->data[i]; |
1081 DValue* expelem = exp->toElem(p); | 1092 DValue* expelem = exp->toElem(p); |
1082 llargs[j] = DtoBitCast(expelem->getLVal(), getPtrToType(llvm::Type::Int8Ty)); | 1093 llargs[j] = DtoBitCast(expelem->getLVal(), getPtrToType(llvm::Type::Int8Ty)); |
1083 } | 1094 } |
1084 } | 1095 } |
1085 // regular arguments | 1096 // d variadic function |
1097 else if (tf->linkage == LINKd && tf->varargs == 1) | |
1098 { | |
1099 Logger::println("doing d-style variadic arguments"); | |
1100 | |
1101 size_t nimplicit = j; | |
1102 | |
1103 std::vector<const LLType*> vtypes; | |
1104 | |
1105 // number of non variadic args | |
1106 int begin = tf->parameters->dim; | |
1107 Logger::println("num non vararg params = %d", begin); | |
1108 | |
1109 // build struct with argument types | |
1110 for (int i=begin; i<arguments->dim; i++) | |
1111 { | |
1112 Argument* argu = Argument::getNth(tf->parameters, i); | |
1113 Expression* argexp = (Expression*)arguments->data[i]; | |
1114 vtypes.push_back(DtoType(argexp->type)); | |
1115 } | |
1116 const llvm::StructType* vtype = llvm::StructType::get(vtypes); | |
1117 Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n'; | |
1118 LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint()); | |
1119 | |
1120 // store arguments in the struct | |
1121 for (int i=begin,k=0; i<arguments->dim; i++,k++) | |
1122 { | |
1123 Expression* argexp = (Expression*)arguments->data[i]; | |
1124 if (global.params.llvmAnnotate) | |
1125 DtoAnnotation(argexp->toChars()); | |
1126 DtoVariadicArgument(argexp, DtoGEPi(mem,0,k,"tmp")); | |
1127 } | |
1128 | |
1129 // build type info array | |
1130 assert(Type::typeinfo->ir.irStruct->constInit); | |
1131 const LLType* typeinfotype = DtoType(Type::typeinfo->type); | |
1132 const llvm::ArrayType* typeinfoarraytype = llvm::ArrayType::get(typeinfotype,vtype->getNumElements()); | |
1133 | |
1134 llvm::GlobalVariable* typeinfomem = | |
1135 new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module); | |
1136 Logger::cout() << "_arguments storage: " << *typeinfomem << '\n'; | |
1137 | |
1138 std::vector<LLConstant*> vtypeinfos; | |
1139 for (int i=begin,k=0; i<arguments->dim; i++,k++) | |
1140 { | |
1141 Expression* argexp = (Expression*)arguments->data[i]; | |
1142 vtypeinfos.push_back(DtoTypeInfoOf(argexp->type)); | |
1143 } | |
1144 | |
1145 // apply initializer | |
1146 LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos); | |
1147 typeinfomem->setInitializer(tiinits); | |
1148 | |
1149 // put data in d-array | |
1150 std::vector<LLConstant*> pinits; | |
1151 pinits.push_back(DtoConstSize_t(vtype->getNumElements())); | |
1152 pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype))); | |
1153 const LLType* tiarrty = llfnty->getParamType(j)->getContainedType(0); | |
1154 tiinits = llvm::ConstantStruct::get(pinits); | |
1155 LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty, | |
1156 true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module); | |
1157 | |
1158 // specify arguments | |
1159 llargs[j] = typeinfoarrayparam;; | |
1160 j++; | |
1161 llargs[j] = p->ir->CreateBitCast(mem, getPtrToType(llvm::Type::Int8Ty), "tmp"); | |
1162 j++; | |
1163 | |
1164 // pass non variadic args | |
1165 for (int i=0; i<begin; i++) | |
1166 { | |
1167 Argument* fnarg = Argument::getNth(tf->parameters, i); | |
1168 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); | |
1169 llargs[j] = argval->getRVal(); | |
1170 j++; | |
1171 } | |
1172 | |
1173 // make sure arg vector has the right size | |
1174 llargs.resize(nimplicit+begin+2); | |
1175 } | |
1176 // normal function call | |
1086 else | 1177 else |
1087 { | 1178 { |
1088 // d variadic function? | 1179 Logger::println("doing normal arguments"); |
1089 if (tf->linkage == LINKd && tf->varargs == 1) | 1180 for (int i=0; i<arguments->dim; i++,j++) { |
1090 { | 1181 Argument* fnarg = Argument::getNth(tf->parameters, i); |
1091 Logger::println("doing d-style variadic arguments"); | 1182 if (global.params.llvmAnnotate) |
1092 | 1183 DtoAnnotation(((Expression*)arguments->data[i])->toChars()); |
1093 size_t nimplicit = j; | 1184 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); |
1094 | 1185 llargs[j] = argval->getRVal(); |
1095 std::vector<const LLType*> vtypes; | 1186 if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) { |
1096 | 1187 llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); |
1097 // number of non variadic args | 1188 } |
1098 int begin = tf->parameters->dim; | 1189 |
1099 Logger::println("num non vararg params = %d", begin); | 1190 // this hack is necessary :/ |
1100 | 1191 if (dfn && dfn->func && dfn->func->runTimeHack) { |
1101 // build struct with argument types | 1192 if (llfnty->getParamType(j) != NULL) { |
1102 for (int i=begin; i<arguments->dim; i++) | 1193 if (llargs[j]->getType() != llfnty->getParamType(j)) { |
1103 { | 1194 Logger::println("llvmRunTimeHack==true - force casting argument"); |
1104 Argument* argu = Argument::getNth(tf->parameters, i); | 1195 Logger::cout() << "casting: " << *llargs[j] << " to type: " << *llfnty->getParamType(j) << '\n'; |
1105 Expression* argexp = (Expression*)arguments->data[i]; | 1196 llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); |
1106 vtypes.push_back(DtoType(argexp->type)); | |
1107 } | |
1108 const llvm::StructType* vtype = llvm::StructType::get(vtypes); | |
1109 Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n'; | |
1110 LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint()); | |
1111 | |
1112 // store arguments in the struct | |
1113 for (int i=begin,k=0; i<arguments->dim; i++,k++) | |
1114 { | |
1115 Expression* argexp = (Expression*)arguments->data[i]; | |
1116 if (global.params.llvmAnnotate) | |
1117 DtoAnnotation(argexp->toChars()); | |
1118 DtoVariadicArgument(argexp, DtoGEPi(mem,0,k,"tmp")); | |
1119 } | |
1120 | |
1121 // build type info array | |
1122 assert(Type::typeinfo->ir.irStruct->constInit); | |
1123 const LLType* typeinfotype = DtoType(Type::typeinfo->type); | |
1124 const llvm::ArrayType* typeinfoarraytype = llvm::ArrayType::get(typeinfotype,vtype->getNumElements()); | |
1125 | |
1126 llvm::GlobalVariable* typeinfomem = | |
1127 new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module); | |
1128 Logger::cout() << "_arguments storage: " << *typeinfomem << '\n'; | |
1129 | |
1130 std::vector<LLConstant*> vtypeinfos; | |
1131 for (int i=begin,k=0; i<arguments->dim; i++,k++) | |
1132 { | |
1133 Expression* argexp = (Expression*)arguments->data[i]; | |
1134 vtypeinfos.push_back(DtoTypeInfoOf(argexp->type)); | |
1135 } | |
1136 | |
1137 // apply initializer | |
1138 LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos); | |
1139 typeinfomem->setInitializer(tiinits); | |
1140 | |
1141 // put data in d-array | |
1142 std::vector<LLConstant*> pinits; | |
1143 pinits.push_back(DtoConstSize_t(vtype->getNumElements())); | |
1144 pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype))); | |
1145 const LLType* tiarrty = llfnty->getParamType(j)->getContainedType(0); | |
1146 tiinits = llvm::ConstantStruct::get(pinits); | |
1147 LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty, | |
1148 true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module); | |
1149 | |
1150 // specify arguments | |
1151 llargs[j] = typeinfoarrayparam;; | |
1152 j++; | |
1153 llargs[j] = p->ir->CreateBitCast(mem, getPtrToType(llvm::Type::Int8Ty), "tmp"); | |
1154 j++; | |
1155 | |
1156 // pass non variadic args | |
1157 for (int i=0; i<begin; i++) | |
1158 { | |
1159 Argument* fnarg = Argument::getNth(tf->parameters, i); | |
1160 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); | |
1161 llargs[j] = argval->getRVal(); | |
1162 j++; | |
1163 } | |
1164 | |
1165 // make sure arg vector has the right size | |
1166 llargs.resize(nimplicit+begin+2); | |
1167 } | |
1168 // normal function | |
1169 else { | |
1170 Logger::println("doing normal arguments"); | |
1171 for (int i=0; i<arguments->dim; i++,j++) { | |
1172 Argument* fnarg = Argument::getNth(tf->parameters, i); | |
1173 if (global.params.llvmAnnotate) | |
1174 DtoAnnotation(((Expression*)arguments->data[i])->toChars()); | |
1175 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); | |
1176 llargs[j] = argval->getRVal(); | |
1177 if (fnarg && llargs[j]->getType() != llfnty->getParamType(j)) { | |
1178 llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); | |
1179 } | |
1180 | |
1181 // this hack is necessary :/ | |
1182 if (dfn && dfn->func && dfn->func->runTimeHack) { | |
1183 if (llfnty->getParamType(j) != NULL) { | |
1184 if (llargs[j]->getType() != llfnty->getParamType(j)) { | |
1185 Logger::println("llvmRunTimeHack==true - force casting argument"); | |
1186 Logger::cout() << "casting: " << *llargs[j] << " to type: " << *llfnty->getParamType(j) << '\n'; | |
1187 llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); | |
1188 } | |
1189 } | 1197 } |
1190 } | 1198 } |
1191 } | 1199 } |
1192 } | 1200 } |
1193 } | 1201 } |
2718 | 2726 |
2719 LLValue* sptr; | 2727 LLValue* sptr; |
2720 const LLType* llt = DtoType(type); | 2728 const LLType* llt = DtoType(type); |
2721 | 2729 |
2722 LLValue* mem = 0; | 2730 LLValue* mem = 0; |
2731 bool isinplace = true; | |
2723 | 2732 |
2724 // temporary struct literal | 2733 // temporary struct literal |
2725 if (!p->topexp() || p->topexp()->e2 != this) | 2734 if (!p->topexp() || p->topexp()->e2 != this) |
2726 { | 2735 { |
2727 sptr = new llvm::AllocaInst(llt,"tmpstructliteral",p->topallocapoint()); | 2736 sptr = new llvm::AllocaInst(llt,"tmpstructliteral",p->topallocapoint()); |
2737 isinplace = false; | |
2728 } | 2738 } |
2729 // already has memory | 2739 // already has memory |
2730 else | 2740 else |
2731 { | 2741 { |
2732 assert(p->topexp()->e2 == this); | 2742 assert(p->topexp()->e2 == this); |
2775 DtoAssign(darrptr, ve); | 2785 DtoAssign(darrptr, ve); |
2776 | 2786 |
2777 j++; | 2787 j++; |
2778 } | 2788 } |
2779 | 2789 |
2780 return new DImValue(type, sptr, true); | 2790 return new DImValue(type, sptr, isinplace); |
2781 } | 2791 } |
2782 | 2792 |
2783 ////////////////////////////////////////////////////////////////////////////////////////// | 2793 ////////////////////////////////////////////////////////////////////////////////////////// |
2784 | 2794 |
2785 LLConstant* StructLiteralExp::toConstElem(IRState* p) | 2795 LLConstant* StructLiteralExp::toConstElem(IRState* p) |