virtual bool validate(const Type &ref, const Type &row) { return row.size() == ref.size(); }
void visit(TypeInfoStructDeclaration *d) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); if (global.params.is64bit) verifyStructSize(Type::typeinfostruct, 17 * Target::ptrsize); else verifyStructSize(Type::typeinfostruct, 15 * Target::ptrsize); dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0); // vtbl for TypeInfo_Struct dtsize_t(pdt, 0); // monitor assert(d->tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)d->tinfo; StructDeclaration *sd = tc->sym; if (!sd->members) return; /* Put out: * char[] name; * void[] init; * hash_t function(in void*) xtoHash; * bool function(in void*, in void*) xopEquals; * int function(in void*, in void*) xopCmp; * string function(const(void)*) xtoString; * StructFlags m_flags; * //xgetMembers; * xdtor; * xpostblit; * uint m_align; * version (X86_64) * TypeInfo m_arg1; * TypeInfo m_arg2; * xgetRTInfo */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtsize_t(pdt, namelen); dtabytes(pdt, 0, namelen + 1, name); // void[] init; dtsize_t(pdt, sd->structsize); // init.length if (sd->zeroInit) dtsize_t(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0); // init.ptr if (FuncDeclaration *fd = search_toHash(sd)) { dtxoff(pdt, fd->toSymbol(), 0); TypeFunction *tf = (TypeFunction *)fd->type; assert(tf->ty == Tfunction); /* I'm a little unsure this is the right way to do it. Perhaps a better * way would to automatically add these attributes to any struct member * function with the name "toHash". * So I'm leaving this here as an experiment for the moment. */ if (!tf->isnothrow || tf->trust == TRUSTsystem /*|| tf->purity == PUREimpure*/) warning(fd->loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf->toChars()); } else dtsize_t(pdt, 0); if (sd->xeq) dtxoff(pdt, sd->xeq->toSymbol(), 0); else dtsize_t(pdt, 0); if (sd->xcmp) dtxoff(pdt, sd->xcmp->toSymbol(), 0); else dtsize_t(pdt, 0); if (FuncDeclaration *fd = search_toString(sd)) { dtxoff(pdt, fd->toSymbol(), 0); } else dtsize_t(pdt, 0); // StructFlags m_flags; StructFlags::Type m_flags = 0; if (tc->hasPointers()) m_flags |= StructFlags::hasPointers; dtsize_t(pdt, m_flags); #if 0 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0); else dtsize_t(pdt, 0); // xgetMembers #endif // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0); else dtsize_t(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit && !(spostblit->storage_class & STCdisable)) dtxoff(pdt, spostblit->toSymbol(), 0); else dtsize_t(pdt, 0); // xpostblit // uint m_align; dtsize_t(pdt, tc->alignsize()); if (global.params.is64bit) { Type *t = sd->arg1type; for (int i = 0; i < 2; i++) { // m_argi if (t) { t->genTypeInfo(NULL); dtxoff(pdt, t->vtinfo->toSymbol(), 0); } else dtsize_t(pdt, 0); t = sd->arg2type; } } // xgetRTInfo if (sd->getRTInfo) sd->getRTInfo->toDt(pdt); else if (m_flags & StructFlags::hasPointers) dtsize_t(pdt, 1); else dtsize_t(pdt, 0); }
void source_name(Dsymbol *s) { char *name = s->ident->toChars(); TemplateInstance *ti = s->isTemplateInstance(); if (ti) { if (!substitute(ti->tempdecl)) { store(ti->tempdecl); name = ti->name->toChars(); buf.printf("%d%s", strlen(name), name); } buf.writeByte('I'); bool is_var_arg = false; for (size_t i = 0; i < ti->tiargs->dim; i++) { RootObject *o = (RootObject *)(*ti->tiargs)[i]; TemplateParameter *tp = NULL; TemplateValueParameter *tv = NULL; TemplateTupleParameter *tt = NULL; if (!is_var_arg) { TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); tp = (*td->parameters)[i]; tv = tp->isTemplateValueParameter(); tt = tp->isTemplateTupleParameter(); } /* * <template-arg> ::= <type> # type or template * ::= <expr-primary> # simple expressions */ if (tt) { buf.writeByte('I'); is_var_arg = true; tp = NULL; } if (tv) { // <expr-primary> ::= L <type> <value number> E # integer literal if (tv->valType->isintegral()) { Expression* e = isExpression(o); assert(e); buf.writeByte('L'); tv->valType->accept(this); if (tv->valType->isunsigned()) { buf.printf("%llu", e->toUInteger()); } else { dinteger_t val = e->toInteger(); if (val < 0) { val = -val; buf.writeByte('n'); } buf.printf("%lld", val); } buf.writeByte('E'); } else { s->error("ICE: C++ %s template value parameter is not supported", tv->valType->toChars()); assert(0); } } else if (!tp || tp->isTemplateTypeParameter()) { Type *t = isType(o); assert(t); t->accept(this); } else if (tp->isTemplateAliasParameter()) { Dsymbol* d = isDsymbol(o); Expression* e = isExpression(o); if (!d && !e) { s->error("ICE: %s is unsupported parameter for C++ template: (%s)", o->toChars()); assert(0); } if (d && d->isFuncDeclaration()) { bool is_nested = d->toParent() && !d->toParent()->isModule() && ((TypeFunction *)d->isFuncDeclaration()->type)->linkage == LINKcpp; if (is_nested) buf.writeByte('X'); buf.writeByte('L'); mangle_function(d->isFuncDeclaration()); buf.writeByte('E'); if (is_nested) buf.writeByte('E'); } else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration()) { VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration(); buf.writeByte('L'); mangle_variable(vd, true); buf.writeByte('E'); } else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember) { if (!substitute(d)) { cpp_mangle_name(d); store(d); } } else { s->error("ICE: %s is unsupported parameter for C++ template", o->toChars()); assert(0); } } else { s->error("ICE: C++ templates support only integral value , type parameters, alias templates and alias function parameters"); assert(0); } } if (is_var_arg) { buf.writeByte('E'); } buf.writeByte('E'); return; } else { buf.printf("%d%s", strlen(name), name); } }
/// ComputePHILiveOutRegInfo - Compute LiveOutInfo for a PHI's destination /// register based on the LiveOutInfo of its operands. void FunctionLoweringInfo::ComputePHILiveOutRegInfo(const PHINode *PN) { Type *Ty = PN->getType(); if (!Ty->isIntegerTy() || Ty->isVectorTy()) return; const TargetLowering *TLI = TM.getSubtargetImpl()->getTargetLowering(); SmallVector<EVT, 1> ValueVTs; ComputeValueVTs(*TLI, Ty, ValueVTs); assert(ValueVTs.size() == 1 && "PHIs with non-vector integer types should have a single VT."); EVT IntVT = ValueVTs[0]; if (TLI->getNumRegisters(PN->getContext(), IntVT) != 1) return; IntVT = TLI->getTypeToTransformTo(PN->getContext(), IntVT); unsigned BitWidth = IntVT.getSizeInBits(); unsigned DestReg = ValueMap[PN]; if (!TargetRegisterInfo::isVirtualRegister(DestReg)) return; LiveOutRegInfo.grow(DestReg); LiveOutInfo &DestLOI = LiveOutRegInfo[DestReg]; Value *V = PN->getIncomingValue(0); if (isa<UndefValue>(V) || isa<ConstantExpr>(V)) { DestLOI.NumSignBits = 1; APInt Zero(BitWidth, 0); DestLOI.KnownZero = Zero; DestLOI.KnownOne = Zero; return; } if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) { APInt Val = CI->getValue().zextOrTrunc(BitWidth); DestLOI.NumSignBits = Val.getNumSignBits(); DestLOI.KnownZero = ~Val; DestLOI.KnownOne = Val; } else { assert(ValueMap.count(V) && "V should have been placed in ValueMap when its" "CopyToReg node was created."); unsigned SrcReg = ValueMap[V]; if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) { DestLOI.IsValid = false; return; } const LiveOutInfo *SrcLOI = GetLiveOutRegInfo(SrcReg, BitWidth); if (!SrcLOI) { DestLOI.IsValid = false; return; } DestLOI = *SrcLOI; } assert(DestLOI.KnownZero.getBitWidth() == BitWidth && DestLOI.KnownOne.getBitWidth() == BitWidth && "Masks should have the same bit width as the type."); for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) { Value *V = PN->getIncomingValue(i); if (isa<UndefValue>(V) || isa<ConstantExpr>(V)) { DestLOI.NumSignBits = 1; APInt Zero(BitWidth, 0); DestLOI.KnownZero = Zero; DestLOI.KnownOne = Zero; return; } if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) { APInt Val = CI->getValue().zextOrTrunc(BitWidth); DestLOI.NumSignBits = std::min(DestLOI.NumSignBits, Val.getNumSignBits()); DestLOI.KnownZero &= ~Val; DestLOI.KnownOne &= Val; continue; } assert(ValueMap.count(V) && "V should have been placed in ValueMap when " "its CopyToReg node was created."); unsigned SrcReg = ValueMap[V]; if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) { DestLOI.IsValid = false; return; } const LiveOutInfo *SrcLOI = GetLiveOutRegInfo(SrcReg, BitWidth); if (!SrcLOI) { DestLOI.IsValid = false; return; } DestLOI.NumSignBits = std::min(DestLOI.NumSignBits, SrcLOI->NumSignBits); DestLOI.KnownZero &= SrcLOI->KnownZero; DestLOI.KnownOne &= SrcLOI->KnownOne; } }
llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, bool ismain) { if (Logger::enabled()) Logger::println("DtoFunctionType(%s)", type->toChars()); LOG_SCOPE // sanity check assert(type->ty == Tfunction); TypeFunction* f = (TypeFunction*)type; TargetABI* abi = (f->linkage == LINKintrinsic ? TargetABI::getIntrinsic() : gABI); // Tell the ABI we're resolving a new function type abi->newFunctionType(f); // Do not modify f->fty yet; this function may be called recursively if any // of the argument types refer to this type. IrFuncTy fty; // llvm idx counter size_t lidx = 0; // main needs a little special handling if (ismain) { fty.ret = new IrFuncTyArg(Type::tint32, false); } // sane return value else { Type* rt = f->next; unsigned a = 0; // sret return if (abi->returnInArg(f)) { fty.arg_sret = new IrFuncTyArg(rt, true, StructRet | NoAlias | NoCapture); rt = Type::tvoid; lidx++; } // sext/zext return else { Type *t = rt; #if DMDV2 if (f->isref) t = t->pointerTo(); #endif if (unsigned se = DtoShouldExtend(t)) a = se; } #if DMDV2 fty.ret = new IrFuncTyArg(rt, f->isref, a); #else fty.ret = new IrFuncTyArg(rt, false, a); #endif } lidx++; // member functions if (thistype) { fty.arg_this = new IrFuncTyArg(thistype, thistype->toBasetype()->ty == Tstruct); lidx++; } // and nested functions else if (nesttype) { fty.arg_nest = new IrFuncTyArg(nesttype, false); lidx++; } // vararg functions are special too if (f->varargs) { if (f->linkage == LINKd) { // d style with hidden args // 2 (array) is handled by the frontend if (f->varargs == 1) { // _arguments fty.arg_arguments = new IrFuncTyArg(Type::typeinfo->type->arrayOf(), false); lidx++; // _argptr fty.arg_argptr = new IrFuncTyArg(Type::tvoid->pointerTo(), false, NoAlias | NoCapture); lidx++; } } else if (f->linkage == LINKc) { fty.c_vararg = true; } else { type->error(0, "invalid linkage for variadic function"); fatal(); } } // if this _Dmain() doesn't have an argument, we force it to have one int nargs = Parameter::dim(f->parameters); if (ismain && nargs == 0) { Type* mainargs = Type::tchar->arrayOf()->arrayOf(); fty.args.push_back(new IrFuncTyArg(mainargs, false)); lidx++; } // add explicit parameters else for (int i = 0; i < nargs; i++) { // get argument Parameter* arg = Parameter::getNth(f->parameters, i); // reference semantics? ref, out and d1 static arrays are bool byref = arg->storageClass & (STCref|STCout); #if !SARRAYVALUE byref = byref || (arg->type->toBasetype()->ty == Tsarray); #endif Type* argtype = arg->type; unsigned a = 0; // handle lazy args if (arg->storageClass & STClazy) { Logger::println("lazy param"); TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd); TypeDelegate *ltd = new TypeDelegate(ltf); argtype = ltd; } // byval else if (abi->passByVal(byref ? argtype->pointerTo() : argtype)) { if (!byref) a |= llvm::Attribute::ByVal; byref = true; } // sext/zext else if (!byref) { a |= DtoShouldExtend(argtype); } fty.args.push_back(new IrFuncTyArg(argtype, byref, a)); lidx++; } // Now we can modify f->fty safely. f->fty = fty; // let the abi rewrite the types as necesary abi->rewriteFunctionType(f); // Tell the ABI we're done with this function type abi->doneWithFunctionType(); // build the function type std::vector<LLType*> argtypes; argtypes.reserve(lidx); if (f->fty.arg_sret) argtypes.push_back(f->fty.arg_sret->ltype); if (f->fty.arg_this) argtypes.push_back(f->fty.arg_this->ltype); if (f->fty.arg_nest) argtypes.push_back(f->fty.arg_nest->ltype); if (f->fty.arg_arguments) argtypes.push_back(f->fty.arg_arguments->ltype); if (f->fty.arg_argptr) argtypes.push_back(f->fty.arg_argptr->ltype); size_t beg = argtypes.size(); size_t nargs2 = f->fty.args.size(); for (size_t i = 0; i < nargs2; i++) { argtypes.push_back(f->fty.args[i]->ltype); } // reverse params? if (f->fty.reverseParams && nargs2 > 1) { std::reverse(argtypes.begin() + beg, argtypes.end()); } LLFunctionType* functype = LLFunctionType::get(f->fty.ret->ltype, argtypes, f->fty.c_vararg); Logger::cout() << "Final function type: " << *functype << "\n"; return functype; }
Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, DeclName Member, ConstraintLocator *locator, ArrayRef<TypeVariableType *> typeVars) : Kind(Kind), HasRestriction(false), HasFix(false), IsActive(false), RememberChoice(false), IsFavored(false), NumTypeVariables(typeVars.size()), Types { First, Second, Member }, Locator(locator) { switch (Kind) { case ConstraintKind::Bind: case ConstraintKind::Equal: case ConstraintKind::BindParam: case ConstraintKind::Subtype: case ConstraintKind::Conversion: case ConstraintKind::ExplicitConversion: case ConstraintKind::ArgumentConversion: case ConstraintKind::ArgumentTupleConversion: case ConstraintKind::OperatorArgumentTupleConversion: case ConstraintKind::OperatorArgumentConversion: case ConstraintKind::ConformsTo: case ConstraintKind::CheckedCast: case ConstraintKind::SelfObjectOfProtocol: case ConstraintKind::DynamicTypeOf: case ConstraintKind::OptionalObject: assert(!First.isNull()); assert(!Second.isNull()); assert(!Member && "Relational constraint cannot have a member"); break; case ConstraintKind::ApplicableFunction: assert(First->is<FunctionType>() && "The left-hand side type should be a function type"); assert(!Member && "Relational constraint cannot have a member"); break; case ConstraintKind::TypeMember: case ConstraintKind::ValueMember: case ConstraintKind::UnresolvedValueMember: assert(Member && "Member constraint has no member"); break; case ConstraintKind::Archetype: case ConstraintKind::Class: case ConstraintKind::BridgedToObjectiveC: assert(!Member && "Type property cannot have a member"); assert(Second.isNull() && "Type property with second type"); break; case ConstraintKind::Defaultable: assert(!First.isNull()); assert(!Second.isNull()); assert(!Member && "Defaultable constraint cannot have a member"); break; case ConstraintKind::BindOverload: llvm_unreachable("Wrong constructor for overload binding constraint"); case ConstraintKind::Disjunction: llvm_unreachable("Disjunction constraints should use create()"); } std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); }
string halide_type_to_tiramisu_type_str(Type type) { if (type.is_uint()) { if (type.bits() == 8) { return "tiramisu::p_uint8"; } else if (type.bits() == 16) { return "tiramisu::p_uint16"; } else if (type.bits() == 32) { return "tiramisu::p_uint32"; } else { return "tiramisu::p_uint64"; } } else if (type.is_int()) { if (type.bits() == 8) { return "tiramisu::p_int8"; } else if (type.bits() == 16) { return "tiramisu::p_int16"; } else if (type.bits() == 32) { return "tiramisu::p_int32"; } else { return "tiramisu::p_int64"; } } else if (type.is_float()) { if (type.bits() == 32) { return "tiramisu::p_float32"; } else if (type.bits() == 64) { return "tiramisu::p_float64"; } else { tiramisu::error("Floats other than 32 and 64 bits are not suppored in Tiramisu.", true); } } else if (type.is_bool()) { return "tiramisu::p_boolean"; } else { tiramisu::error("Halide type cannot be translated to Tiramisu type.", true); } return "tiramisu::p_none"; }
void TypeInfoStructDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); unsigned offset = Type::typeinfostruct->structsize; dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct dtsize_t(pdt, 0); // monitor assert(tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)tinfo; StructDeclaration *sd = tc->sym; /* Put out: * char[] name; * void[] init; * hash_t function(in void*) xtoHash; * bool function(in void*, in void*) xopEquals; * int function(in void*, in void*) xopCmp; * string function(const(void)*) xtoString; * uint m_flags; * xgetMembers; * xdtor; * xpostblit; * uint m_align; * version (X86_64) * TypeInfo m_arg1; * TypeInfo m_arg2; * * name[] */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtsize_t(pdt, namelen); //dtabytes(pdt, TYnptr, 0, namelen + 1, name); dtxoff(pdt, toSymbol(), offset, TYnptr); offset += namelen + 1; // void[] init; dtsize_t(pdt, sd->structsize); // init.length if (sd->zeroInit) dtsize_t(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr FuncDeclaration *fd; FuncDeclaration *fdx; Dsymbol *s; static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; /* const hash_t toHash(); */ tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash->mod = MODconst; tftohash = (TypeFunction *)tftohash->semantic(0, &sc); tftostring = new TypeFunction(NULL, Type::tchar->invariantOf()->arrayOf(), 0, LINKd); tftostring = (TypeFunction *)tftostring->semantic(0, &sc); } TypeFunction *tfcmpptr; { Scope sc; /* const int opCmp(ref const KeyType s); */ Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(0, &sc); } s = search_function(sd, Id::tohash); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftohash); if (fd) { dtxoff(pdt, fd->toSymbol(), 0, TYnptr); TypeFunction *tf = (TypeFunction *)fd->type; assert(tf->ty == Tfunction); if (global.params.warnings) { /* I'm a little unsure this is the right way to do it. Perhaps a better * way would to automatically add these attributes to any struct member * function with the name "toHash". * So I'm leaving this here as an experiment for the moment. */ if (!tf->isnothrow || tf->trust == TRUSTsystem /*|| tf->purity == PUREimpure*/) { warning(fd->loc, "toHash() must be declared as extern (D) uint toHash() const nothrow @safe, not %s", tf->toChars()); if (global.params.warnings == 1) global.errors++; } } } else { //fdx->error("must be declared as extern (D) uint toHash()"); dtsize_t(pdt, 0); } } else dtsize_t(pdt, 0); if (sd->xeq) dtxoff(pdt, sd->xeq->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); s = search_function(sd, Id::cmp); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { //printf("test1 %s, %s, %s\n", fdx->toChars(), fdx->type->toChars(), tfeqptr->toChars()); fd = fdx->overloadExactMatch(tfcmpptr); if (fd) { dtxoff(pdt, fd->toSymbol(), 0, TYnptr); //printf("test2\n"); } else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); s = search_function(sd, Id::tostring); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftostring); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) char[] toString()"); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); // uint m_flags; dtsize_t(pdt, tc->hasPointers()); #if DMDV2 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xgetMembers // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit && !(spostblit->storage_class & STCdisable)) dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xpostblit #endif // uint m_align; dtsize_t(pdt, tc->alignsize()); if (global.params.is64bit) { TypeTuple *tup = tc->toArgTypes(); assert(tup->arguments->dim <= 2); for (size_t i = 0; i < 2; i++) { if (i < tup->arguments->dim) { Type *targ = (tup->arguments->tdata()[i])->type; targ = targ->merge(); targ->getTypeInfo(NULL); dtxoff(pdt, targ->vtinfo->toSymbol(), 0, TYnptr); // m_argi } else dtsize_t(pdt, 0); // m_argi } } // name[] dtnbytes(pdt, namelen + 1, name); }
Expression *createTypeInfoArray(Scope *sc, Expression *exps[], unsigned dim) { #if 1 /* Get the corresponding TypeInfo_Tuple and * point at its elements[]. */ /* Create the TypeTuple corresponding to the types of args[] */ Parameters *args = new Parameters; args->setDim(dim); for (size_t i = 0; i < dim; i++) { Parameter *arg = new Parameter(STCin, exps[i]->type, NULL, NULL); args->tdata()[i] = arg; } TypeTuple *tup = new TypeTuple(args); Expression *e = tup->getTypeInfo(sc); e = e->optimize(WANTvalue); assert(e->op == TOKsymoff); // should be SymOffExp #if BREAKABI /* * Should just pass a reference to TypeInfo_Tuple instead, * but that would require existing code to be recompiled. * Source compatibility can be maintained by computing _arguments[] * at the start of the called function by offseting into the * TypeInfo_Tuple reference. */ #else // Advance to elements[] member of TypeInfo_Tuple SymOffExp *se = (SymOffExp *)e; se->offset += PTRSIZE + PTRSIZE; // Set type to TypeInfo[]* se->type = Type::typeinfo->type->arrayOf()->pointerTo(); // Indirect to get the _arguments[] value e = new PtrExp(0, se); e->type = se->type->next; #endif return e; #else /* Improvements: * 1) create an array literal instead, * as it would eliminate the extra dereference of loading the * static variable. */ ArrayInitializer *ai = new ArrayInitializer(0); VarDeclaration *v; Type *t; Expression *e; OutBuffer buf; Identifier *id; char *name; // Generate identifier for _arguments[] buf.writestring("_arguments_"); for (int i = 0; i < dim; i++) { t = exps[i]->type; t->toDecoBuffer(&buf); } buf.writeByte(0); id = Lexer::idPool((char *)buf.data); Module *m = sc->module; Dsymbol *s = m->symtab->lookup(id); if (s && s->parent == m) { // Use existing one v = s->isVarDeclaration(); assert(v); } else { // Generate new one for (int i = 0; i < dim; i++) { t = exps[i]->type; e = t->getTypeInfo(sc); ai->addInit(new IntegerExp(i), new ExpInitializer(0, e)); } t = Type::typeinfo->type->arrayOf(); ai->type = t; v = new VarDeclaration(0, t, id, ai); m->members->push(v); m->symtabInsert(v); sc = sc->push(); sc->linkage = LINKc; sc->stc = STCstatic | STCcomdat; ai->semantic(sc, t); v->semantic(sc); v->parent = m; sc = sc->pop(); } e = new VarExp(0, v); e = e->semantic(sc); return e; #endif }
bool TypeChecker::checkGenericArguments(DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner, GenericSignature *genericSig, ArrayRef<Type> genericArgs) { // Form the set of generic substitutions required TypeSubstitutionMap substitutions; auto genericParams = genericSig->getGenericParams(); unsigned count = 0; // If the type is nested inside a generic function, skip // substitutions from the outer context. unsigned start = (genericParams.size() - genericArgs.size()); for (auto gp : genericParams) { if (count >= start) { auto gpTy = gp->getCanonicalType()->castTo<GenericTypeParamType>(); substitutions[gpTy] = genericArgs[count - start]; } count++; } // The number of generic type arguments being bound must be equal to the // total number of generic parameters in the current generic type context. assert(count - start == genericArgs.size()); // Check each of the requirements. Module *module = dc->getParentModule(); for (const auto &req : genericSig->getRequirements()) { Type firstType = req.getFirstType().subst(module, substitutions, SubstFlags::IgnoreMissing); if (firstType.isNull()) { // Another requirement will fail later; just continue. continue; } Type secondType = req.getSecondType(); if (secondType) { secondType = secondType.subst(module, substitutions, SubstFlags::IgnoreMissing); if (secondType.isNull()) { // Another requirement will fail later; just continue. continue; } } switch (req.getKind()) { case RequirementKind::Conformance: { // Protocol conformance requirements. auto proto = secondType->castTo<ProtocolType>(); // FIXME: This should track whether this should result in a private // or non-private dependency. // FIXME: Do we really need "used" at this point? // FIXME: Poor location information. How much better can we do here? if (!conformsToProtocol(firstType, proto->getDecl(), dc, ConformanceCheckFlags::Used, nullptr, loc)) { return true; } continue; } case RequirementKind::Superclass: // Superclass requirements. if (!isSubtypeOf(firstType, secondType, dc)) { // FIXME: Poor source-location information. diagnose(loc, diag::type_does_not_inherit, owner, firstType, secondType); diagnose(noteLoc, diag::type_does_not_inherit_requirement, req.getFirstType(), req.getSecondType(), gatherGenericParamBindingsText( {req.getFirstType(), req.getSecondType()}, genericParams, substitutions)); return true; } continue; case RequirementKind::SameType: if (!firstType->isEqual(secondType)) { // FIXME: Better location info for both diagnostics. diagnose(loc, diag::types_not_equal, owner, firstType, secondType); diagnose(noteLoc, diag::types_not_equal_requirement, req.getFirstType(), req.getSecondType(), gatherGenericParamBindingsText( {req.getFirstType(), req.getSecondType()}, genericParams, substitutions)); return true; } continue; case RequirementKind::WitnessMarker: continue; } } return false; }
/// run - Start execution with the specified function and arguments. /// GenericValue JIT::runFunction(Function *F, const std::vector<GenericValue> &ArgValues) { assert(F && "Function *F was null at entry to run()"); void *FPtr = getPointerToFunction(F); assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); FunctionType *FTy = F->getFunctionType(); Type *RetTy = FTy->getReturnType(); assert((FTy->getNumParams() == ArgValues.size() || (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && "Wrong number of arguments passed into function!"); assert(FTy->getNumParams() == ArgValues.size() && "This doesn't support passing arguments through varargs (yet)!"); // Handle some common cases first. These cases correspond to common `main' // prototypes. if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { switch (ArgValues.size()) { case 3: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy() && FTy->getParamType(2)->isPointerTy()) { int (*PF)(int, char **, const char **) = (int(*)(int, char **, const char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]), (const char **)GVTOP(ArgValues[2]))); return rv; } break; case 2: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy()) { int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]))); return rv; } break; case 1: if (FTy->getParamType(0)->isIntegerTy(32)) { GenericValue rv; int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); return rv; } if (FTy->getParamType(0)->isPointerTy()) { GenericValue rv; int (*PF)(char *) = (int(*)(char *))(intptr_t)FPtr; rv.IntVal = APInt(32, PF((char*)GVTOP(ArgValues[0]))); return rv; } break; } } // Handle cases where no arguments are passed first. if (ArgValues.empty()) { GenericValue rv; switch (RetTy->getTypeID()) { default: llvm_unreachable("Unknown return type for function call!"); case Type::IntegerTyID: { unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); if (BitWidth == 1) rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); else if (BitWidth <= 8) rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); else if (BitWidth <= 16) rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); else if (BitWidth <= 32) rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); else if (BitWidth <= 64) rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); else llvm_unreachable("Integer types > 64 bits not supported"); return rv; } case Type::VoidTyID: rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); return rv; case Type::FloatTyID: rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); return rv; case Type::DoubleTyID: rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); return rv; case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: llvm_unreachable("long double not supported yet"); case Type::PointerTyID: return PTOGV(((void*(*)())(intptr_t)FPtr)()); } } // Okay, this is not one of our quick and easy cases. Because we don't have a // full FFI, we have to codegen a nullary stub function that just calls the // function we are interested in, passing in constants for all of the // arguments. Make this function and return. // First, create the function. FunctionType *STy=FunctionType::get(RetTy, false); Function *Stub = Function::Create(STy, Function::InternalLinkage, "", F->getParent()); // Insert a basic block. BasicBlock *StubBB = BasicBlock::Create(F->getContext(), "", Stub); // Convert all of the GenericValue arguments over to constants. Note that we // currently don't support varargs. SmallVector<Value*, 8> Args; for (unsigned i = 0, e = ArgValues.size(); i != e; ++i) { Constant *C = 0; Type *ArgTy = FTy->getParamType(i); const GenericValue &AV = ArgValues[i]; switch (ArgTy->getTypeID()) { default: llvm_unreachable("Unknown argument type for function call!"); case Type::IntegerTyID: C = ConstantInt::get(F->getContext(), AV.IntVal); break; case Type::FloatTyID: C = ConstantFP::get(F->getContext(), APFloat(AV.FloatVal)); break; case Type::DoubleTyID: C = ConstantFP::get(F->getContext(), APFloat(AV.DoubleVal)); break; case Type::PPC_FP128TyID: case Type::X86_FP80TyID: case Type::FP128TyID: C = ConstantFP::get(F->getContext(), APFloat(AV.IntVal)); break; case Type::PointerTyID: void *ArgPtr = GVTOP(AV); if (sizeof(void*) == 4) C = ConstantInt::get(Type::getInt32Ty(F->getContext()), (int)(intptr_t)ArgPtr); else C = ConstantInt::get(Type::getInt64Ty(F->getContext()), (intptr_t)ArgPtr); // Cast the integer to pointer C = ConstantExpr::getIntToPtr(C, ArgTy); break; } Args.push_back(C); } CallInst *TheCall = CallInst::Create(F, Args, "", StubBB); TheCall->setCallingConv(F->getCallingConv()); TheCall->setTailCall(); if (!TheCall->getType()->isVoidTy()) // Return result of the call. ReturnInst::Create(F->getContext(), TheCall, StubBB); else ReturnInst::Create(F->getContext(), StubBB); // Just return void. // Finally, call our nullary stub function. GenericValue Result = runFunction(Stub, std::vector<GenericValue>()); // Erase it, since no other function can have a reference to it. Stub->eraseFromParent(); // And return the result. return Result; }
Value* AMDGPUCodeGenPrepare::expandDivRem32(IRBuilder<> &Builder, BinaryOperator &I, Value *Num, Value *Den) const { Instruction::BinaryOps Opc = I.getOpcode(); assert(Opc == Instruction::URem || Opc == Instruction::UDiv || Opc == Instruction::SRem || Opc == Instruction::SDiv); FastMathFlags FMF; FMF.setFast(); Builder.setFastMathFlags(FMF); if (isa<Constant>(Den)) return nullptr; // Keep it for optimization bool IsDiv = Opc == Instruction::UDiv || Opc == Instruction::SDiv; bool IsSigned = Opc == Instruction::SRem || Opc == Instruction::SDiv; Type *Ty = Num->getType(); Type *I32Ty = Builder.getInt32Ty(); Type *F32Ty = Builder.getFloatTy(); if (Ty->getScalarSizeInBits() < 32) { if (IsSigned) { Num = Builder.CreateSExt(Num, I32Ty); Den = Builder.CreateSExt(Den, I32Ty); } else { Num = Builder.CreateZExt(Num, I32Ty); Den = Builder.CreateZExt(Den, I32Ty); } } if (Value *Res = expandDivRem24(Builder, I, Num, Den, IsDiv, IsSigned)) { Res = Builder.CreateTrunc(Res, Ty); return Res; } ConstantInt *Zero = Builder.getInt32(0); ConstantInt *One = Builder.getInt32(1); ConstantInt *MinusOne = Builder.getInt32(~0); Value *Sign = nullptr; if (IsSigned) { ConstantInt *K31 = Builder.getInt32(31); Value *LHSign = Builder.CreateAShr(Num, K31); Value *RHSign = Builder.CreateAShr(Den, K31); // Remainder sign is the same as LHS Sign = IsDiv ? Builder.CreateXor(LHSign, RHSign) : LHSign; Num = Builder.CreateAdd(Num, LHSign); Den = Builder.CreateAdd(Den, RHSign); Num = Builder.CreateXor(Num, LHSign); Den = Builder.CreateXor(Den, RHSign); } // RCP = URECIP(Den) = 2^32 / Den + e // e is rounding error. Value *DEN_F32 = Builder.CreateUIToFP(Den, F32Ty); Value *RCP_F32 = Builder.CreateFDiv(ConstantFP::get(F32Ty, 1.0), DEN_F32); Constant *UINT_MAX_PLUS_1 = ConstantFP::get(F32Ty, BitsToFloat(0x4f800000)); Value *RCP_SCALE = Builder.CreateFMul(RCP_F32, UINT_MAX_PLUS_1); Value *RCP = Builder.CreateFPToUI(RCP_SCALE, I32Ty); // RCP_LO, RCP_HI = mul(RCP, Den) */ Value *RCP_LO, *RCP_HI; std::tie(RCP_LO, RCP_HI) = getMul64(Builder, RCP, Den); // NEG_RCP_LO = -RCP_LO Value *NEG_RCP_LO = Builder.CreateNeg(RCP_LO); // ABS_RCP_LO = (RCP_HI == 0 ? NEG_RCP_LO : RCP_LO) Value *RCP_HI_0_CC = Builder.CreateICmpEQ(RCP_HI, Zero); Value *ABS_RCP_LO = Builder.CreateSelect(RCP_HI_0_CC, NEG_RCP_LO, RCP_LO); // Calculate the rounding error from the URECIP instruction // E = mulhu(ABS_RCP_LO, RCP) Value *E = getMulHu(Builder, ABS_RCP_LO, RCP); // RCP_A_E = RCP + E Value *RCP_A_E = Builder.CreateAdd(RCP, E); // RCP_S_E = RCP - E Value *RCP_S_E = Builder.CreateSub(RCP, E); // Tmp0 = (RCP_HI == 0 ? RCP_A_E : RCP_SUB_E) Value *Tmp0 = Builder.CreateSelect(RCP_HI_0_CC, RCP_A_E, RCP_S_E); // Quotient = mulhu(Tmp0, Num) Value *Quotient = getMulHu(Builder, Tmp0, Num); // Num_S_Remainder = Quotient * Den Value *Num_S_Remainder = Builder.CreateMul(Quotient, Den); // Remainder = Num - Num_S_Remainder Value *Remainder = Builder.CreateSub(Num, Num_S_Remainder); // Remainder_GE_Den = (Remainder >= Den ? -1 : 0) Value *Rem_GE_Den_CC = Builder.CreateICmpUGE(Remainder, Den); Value *Remainder_GE_Den = Builder.CreateSelect(Rem_GE_Den_CC, MinusOne, Zero); // Remainder_GE_Zero = (Num >= Num_S_Remainder ? -1 : 0) Value *Num_GE_Num_S_Rem_CC = Builder.CreateICmpUGE(Num, Num_S_Remainder); Value *Remainder_GE_Zero = Builder.CreateSelect(Num_GE_Num_S_Rem_CC, MinusOne, Zero); // Tmp1 = Remainder_GE_Den & Remainder_GE_Zero Value *Tmp1 = Builder.CreateAnd(Remainder_GE_Den, Remainder_GE_Zero); Value *Tmp1_0_CC = Builder.CreateICmpEQ(Tmp1, Zero); Value *Res; if (IsDiv) { // Quotient_A_One = Quotient + 1 Value *Quotient_A_One = Builder.CreateAdd(Quotient, One); // Quotient_S_One = Quotient - 1 Value *Quotient_S_One = Builder.CreateSub(Quotient, One); // Div = (Tmp1 == 0 ? Quotient : Quotient_A_One) Value *Div = Builder.CreateSelect(Tmp1_0_CC, Quotient, Quotient_A_One); // Div = (Remainder_GE_Zero == 0 ? Quotient_S_One : Div) Res = Builder.CreateSelect(Num_GE_Num_S_Rem_CC, Div, Quotient_S_One); } else { // Remainder_S_Den = Remainder - Den Value *Remainder_S_Den = Builder.CreateSub(Remainder, Den); // Remainder_A_Den = Remainder + Den Value *Remainder_A_Den = Builder.CreateAdd(Remainder, Den); // Rem = (Tmp1 == 0 ? Remainder : Remainder_S_Den) Value *Rem = Builder.CreateSelect(Tmp1_0_CC, Remainder, Remainder_S_Den); // Rem = (Remainder_GE_Zero == 0 ? Remainder_A_Den : Rem) Res = Builder.CreateSelect(Num_GE_Num_S_Rem_CC, Rem, Remainder_A_Den); } if (IsSigned) { Res = Builder.CreateXor(Res, Sign); Res = Builder.CreateSub(Res, Sign); } Res = Builder.CreateTrunc(Res, Ty); return Res; }
// Insert an intrinsic for fast fdiv for safe math situations where we can // reduce precision. Leave fdiv for situations where the generic node is // expected to be optimized. bool AMDGPUCodeGenPrepare::visitFDiv(BinaryOperator &FDiv) { Type *Ty = FDiv.getType(); if (!Ty->getScalarType()->isFloatTy()) return false; MDNode *FPMath = FDiv.getMetadata(LLVMContext::MD_fpmath); if (!FPMath) return false; const FPMathOperator *FPOp = cast<const FPMathOperator>(&FDiv); float ULP = FPOp->getFPAccuracy(); if (ULP < 2.5f) return false; FastMathFlags FMF = FPOp->getFastMathFlags(); bool UnsafeDiv = HasUnsafeFPMath || FMF.isFast() || FMF.allowReciprocal(); // With UnsafeDiv node will be optimized to just rcp and mul. if (UnsafeDiv) return false; IRBuilder<> Builder(FDiv.getParent(), std::next(FDiv.getIterator()), FPMath); Builder.setFastMathFlags(FMF); Builder.SetCurrentDebugLocation(FDiv.getDebugLoc()); Function *Decl = Intrinsic::getDeclaration(Mod, Intrinsic::amdgcn_fdiv_fast); Value *Num = FDiv.getOperand(0); Value *Den = FDiv.getOperand(1); Value *NewFDiv = nullptr; bool HasDenormals = ST->hasFP32Denormals(); if (VectorType *VT = dyn_cast<VectorType>(Ty)) { NewFDiv = UndefValue::get(VT); // FIXME: Doesn't do the right thing for cases where the vector is partially // constant. This works when the scalarizer pass is run first. for (unsigned I = 0, E = VT->getNumElements(); I != E; ++I) { Value *NumEltI = Builder.CreateExtractElement(Num, I); Value *DenEltI = Builder.CreateExtractElement(Den, I); Value *NewElt; if (shouldKeepFDivF32(NumEltI, UnsafeDiv, HasDenormals)) { NewElt = Builder.CreateFDiv(NumEltI, DenEltI); } else { NewElt = Builder.CreateCall(Decl, { NumEltI, DenEltI }); } NewFDiv = Builder.CreateInsertElement(NewFDiv, NewElt, I); } } else { if (!shouldKeepFDivF32(Num, UnsafeDiv, HasDenormals)) NewFDiv = Builder.CreateCall(Decl, { Num, Den }); } if (NewFDiv) { FDiv.replaceAllUsesWith(NewFDiv); NewFDiv->takeName(&FDiv); FDiv.eraseFromParent(); } return !!NewFDiv; }
void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func) { Type funcTy; Type initFuncTy; auto *sig = func->getGenericSignature(); if (auto fn = dyn_cast<FuncDecl>(func)) { funcTy = fn->getBodyResultTypeLoc().getType(); if (!funcTy) { funcTy = TupleType::getEmpty(Context); } else { funcTy = getResultType(*this, fn, funcTy); } } else if (auto ctor = dyn_cast<ConstructorDecl>(func)) { auto *dc = ctor->getDeclContext(); funcTy = dc->getSelfInterfaceType(); // Adjust result type for failability. if (ctor->getFailability() != OTK_None) funcTy = OptionalType::get(ctor->getFailability(), funcTy); initFuncTy = funcTy; } else { assert(isa<DestructorDecl>(func)); funcTy = TupleType::getEmpty(Context); } auto paramLists = func->getParameterLists(); SmallVector<ParameterList*, 4> storedParamLists; // FIXME: Destructors don't have the '()' pattern in their signature, so // paste it here. if (isa<DestructorDecl>(func)) { assert(paramLists.size() == 1 && "Only the self paramlist"); storedParamLists.push_back(paramLists[0]); storedParamLists.push_back(ParameterList::createEmpty(Context)); paramLists = storedParamLists; } bool hasSelf = func->getDeclContext()->isTypeContext(); for (unsigned i = 0, e = paramLists.size(); i != e; ++i) { Type argTy; Type initArgTy; Type selfTy; if (i == e-1 && hasSelf) { selfTy = func->computeInterfaceSelfType(/*isInitializingCtor=*/false); // Substitute in our own 'self' parameter. argTy = selfTy; if (initFuncTy) { initArgTy = func->computeInterfaceSelfType(/*isInitializingCtor=*/true); } } else { argTy = paramLists[e - i - 1]->getInterfaceType(func); if (initFuncTy) initArgTy = argTy; } // 'throws' only applies to the innermost function. AnyFunctionType::ExtInfo info; if (i == 0 && func->hasThrows()) info = info.withThrows(); assert(!argTy->hasArchetype()); assert(!funcTy->hasArchetype()); if (initFuncTy) assert(!initFuncTy->hasArchetype()); if (sig && i == e-1) { funcTy = GenericFunctionType::get(sig, argTy, funcTy, info); if (initFuncTy) initFuncTy = GenericFunctionType::get(sig, initArgTy, initFuncTy, info); } else { funcTy = FunctionType::get(argTy, funcTy, info); if (initFuncTy) initFuncTy = FunctionType::get(initArgTy, initFuncTy, info); } } // Record the interface type. func->setInterfaceType(funcTy); if (initFuncTy) cast<ConstructorDecl>(func)->setInitializerInterfaceType(initFuncTy); if (func->getGenericParams()) { // Collect all generic params referenced in parameter types, // return type or requirements. SmallPtrSet<GenericTypeParamDecl *, 4> referencedGenericParams; auto visitorFn = [&referencedGenericParams](Type t) { if (auto *paramTy = t->getAs<GenericTypeParamType>()) referencedGenericParams.insert(paramTy->getDecl()); }; funcTy->castTo<AnyFunctionType>()->getInput().visit(visitorFn); funcTy->castTo<AnyFunctionType>()->getResult().visit(visitorFn); auto requirements = sig->getRequirements(); for (auto req : requirements) { if (req.getKind() == RequirementKind::SameType) { // Same type requirements may allow for generic // inference, even if this generic parameter // is not mentioned in the function signature. // TODO: Make the test more precise. auto left = req.getFirstType(); auto right = req.getSecondType(); // For now consider any references inside requirements // as a possibility to infer the generic type. left.visit(visitorFn); right.visit(visitorFn); } } // Find the depth of the function's own generic parameters. unsigned fnGenericParamsDepth = func->getGenericParams()->getDepth(); // Check that every generic parameter type from the signature is // among referencedArchetypes. for (auto *genParam : sig->getGenericParams()) { auto *paramDecl = genParam->getDecl(); if (paramDecl->getDepth() != fnGenericParamsDepth) continue; if (!referencedGenericParams.count(paramDecl)) { // Produce an error that this generic parameter cannot be bound. diagnose(paramDecl->getLoc(), diag::unreferenced_generic_parameter, paramDecl->getNameStr()); func->setInvalid(); } } } }
/// InstCombineStoreToCast - Fold store V, (cast P) -> store (cast V), P /// when possible. This makes it generally easy to do alias analysis and/or /// SROA/mem2reg of the memory object. static Instruction *InstCombineStoreToCast(InstCombiner &IC, StoreInst &SI) { User *CI = cast<User>(SI.getOperand(1)); Value *CastOp = CI->getOperand(0); Type *DestPTy = CI->getType()->getPointerElementType(); PointerType *SrcTy = dyn_cast<PointerType>(CastOp->getType()); if (!SrcTy) return nullptr; Type *SrcPTy = SrcTy->getElementType(); if (!DestPTy->isIntegerTy() && !DestPTy->isPointerTy()) return nullptr; /// NewGEPIndices - If SrcPTy is an aggregate type, we can emit a "noop gep" /// to its first element. This allows us to handle things like: /// store i32 xxx, (bitcast {foo*, float}* %P to i32*) /// on 32-bit hosts. SmallVector<Value*, 4> NewGEPIndices; // If the source is an array, the code below will not succeed. Check to // see if a trivial 'gep P, 0, 0' will help matters. Only do this for // constants. if (SrcPTy->isArrayTy() || SrcPTy->isStructTy()) { // Index through pointer. Constant *Zero = Constant::getNullValue(Type::getInt32Ty(SI.getContext())); NewGEPIndices.push_back(Zero); while (1) { if (StructType *STy = dyn_cast<StructType>(SrcPTy)) { if (!STy->getNumElements()) /* Struct can be empty {} */ break; NewGEPIndices.push_back(Zero); SrcPTy = STy->getElementType(0); } else if (ArrayType *ATy = dyn_cast<ArrayType>(SrcPTy)) { NewGEPIndices.push_back(Zero); SrcPTy = ATy->getElementType(); } else { break; } } SrcTy = PointerType::get(SrcPTy, SrcTy->getAddressSpace()); } if (!SrcPTy->isIntegerTy() && !SrcPTy->isPointerTy()) return nullptr; // If the pointers point into different address spaces don't do the // transformation. if (SrcTy->getAddressSpace() != CI->getType()->getPointerAddressSpace()) return nullptr; // If the pointers point to values of different sizes don't do the // transformation. if (!IC.getDataLayout() || IC.getDataLayout()->getTypeSizeInBits(SrcPTy) != IC.getDataLayout()->getTypeSizeInBits(DestPTy)) return nullptr; // If the pointers point to pointers to different address spaces don't do the // transformation. It is not safe to introduce an addrspacecast instruction in // this case since, depending on the target, addrspacecast may not be a no-op // cast. if (SrcPTy->isPointerTy() && DestPTy->isPointerTy() && SrcPTy->getPointerAddressSpace() != DestPTy->getPointerAddressSpace()) return nullptr; // Okay, we are casting from one integer or pointer type to another of // the same size. Instead of casting the pointer before // the store, cast the value to be stored. Value *NewCast; Instruction::CastOps opcode = Instruction::BitCast; Type* CastSrcTy = DestPTy; Type* CastDstTy = SrcPTy; if (CastDstTy->isPointerTy()) { if (CastSrcTy->isIntegerTy()) opcode = Instruction::IntToPtr; } else if (CastDstTy->isIntegerTy()) { if (CastSrcTy->isPointerTy()) opcode = Instruction::PtrToInt; } // SIOp0 is a pointer to aggregate and this is a store to the first field, // emit a GEP to index into its first field. if (!NewGEPIndices.empty()) CastOp = IC.Builder->CreateInBoundsGEP(CastOp, NewGEPIndices); Value *SIOp0 = SI.getOperand(0); NewCast = IC.Builder->CreateCast(opcode, SIOp0, CastDstTy, SIOp0->getName()+".c"); SI.setOperand(0, NewCast); SI.setOperand(1, CastOp); return &SI; }
void analyzeClass(Type classType, Writer &writer){ auto eclass = classType.eclass; writer.writeEmojicodeChar(eclass->name); if(eclass->superclass){ writer.writeUInt16(eclass->superclass->index); } else { //If the eclass does not have a superclass the own index gets written writer.writeUInt16(eclass->index); } Scope objectScope(true); //Get the ID offset for this eclass by summing up all superclasses instance variable counts uint16_t offset = 0; for(Class *aClass = eclass->superclass; aClass != nullptr; aClass = aClass->superclass){ offset += aClass->instanceVariables.size(); } writer.writeUInt16(eclass->instanceVariables.size() + offset); //Number of methods inclusive superclass writer.writeUInt16(eclass->nextMethodVti); //Number of eclass methods inclusive superclass writer.writeUInt16(eclass->nextClassMethodVti); //Initializer inclusive superclass writer.writeByte(eclass->inheritsContructors ? 1 : 0); writer.writeUInt16(eclass->nextInitializerVti); writer.writeUInt16(eclass->methodList.size()); writer.writeUInt16(eclass->initializerList.size()); writer.writeUInt16(eclass->classMethodList.size()); for (auto var : eclass->instanceVariables) { CompilerVariable *cv = new CompilerVariable(var->type, offset++, 1, false); cv->variable = var; objectScope.setLocalVariable(var->name, cv); } pushScope(&objectScope); for (auto method : eclass->methodList) { StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*method, writer, classType); } for (auto initializer : eclass->initializerList) { StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*initializer, writer, classType, false, initializer); } popScope(); for (auto classMethod : eclass->classMethodList) { StaticFunctionAnalyzer::writeAndAnalyzeProcedure(*classMethod, writer, classType, true); } if (eclass->instanceVariables.size() > 0 && eclass->initializerList.size() == 0) { auto str = classType.toString(typeNothingness, true); compilerWarning(eclass->classBegin, "Class %s defines %d instances variables but has no initializers.", str.c_str(), eclass->instanceVariables.size()); } writer.writeUInt16(eclass->protocols().size()); if (eclass->protocols().size() > 0) { auto biggestPlaceholder = writer.writePlaceholder<uint16_t>(); auto smallestPlaceholder = writer.writePlaceholder<uint16_t>(); uint_fast16_t smallestProtocolIndex = UINT_FAST16_MAX; uint_fast16_t biggestProtocolIndex = 0; for (auto protocol : eclass->protocols()) { writer.writeUInt16(protocol->index); if (protocol->index > biggestProtocolIndex) { biggestProtocolIndex = protocol->index; } if (protocol->index < smallestProtocolIndex) { smallestProtocolIndex = protocol->index; } writer.writeUInt16(protocol->methods().size()); for (auto method : protocol->methods()) { Method *clm = eclass->getMethod(method->name); if (clm == nullptr) { auto className = classType.toString(typeNothingness, true); auto protocolName = Type(protocol, false).toString(typeNothingness, true); ecCharToCharStack(method->name, ms); compilerError(eclass->classBegin, "Class %s does not agree to protocol %s: Method %s is missing.", className.c_str(), protocolName.c_str(), ms); } writer.writeUInt16(clm->vti); clm->checkPromises(method, "protocol definition", classType); } } biggestPlaceholder.write(biggestProtocolIndex); smallestPlaceholder.write(smallestProtocolIndex); } }
Type TypeConverter::getLoweredCBridgedType(AbstractionPattern pattern, Type t, bool canBridgeBool, bool bridgedCollectionsAreOptional) { auto clangTy = pattern.isClangType() ? pattern.getClangType() : nullptr; // Bridge Bool back to ObjC bool, unless the original Clang type was _Bool // or the Darwin Boolean type. auto nativeBoolTy = getBoolType(); if (nativeBoolTy && t->isEqual(nativeBoolTy)) { if (clangTy) { if (clangTy->isBooleanType()) return t; if (clangTy->isSpecificBuiltinType(clang::BuiltinType::UChar)) return getDarwinBooleanType(); } if (clangTy || canBridgeBool) return getObjCBoolType(); return t; } // Class metatypes bridge to ObjC metatypes. if (auto metaTy = t->getAs<MetatypeType>()) { if (metaTy->getInstanceType()->getClassOrBoundGenericClass()) { return MetatypeType::get(metaTy->getInstanceType(), MetatypeRepresentation::ObjC); } } // ObjC-compatible existential metatypes. if (auto metaTy = t->getAs<ExistentialMetatypeType>()) { if (metaTy->getInstanceType()->isObjCExistentialType()) { return ExistentialMetatypeType::get(metaTy->getInstanceType(), MetatypeRepresentation::ObjC); } } // `Any` can bridge to `AnyObject` (`id` in ObjC). if (t->isAny()) { return Context.getProtocol(KnownProtocolKind::AnyObject)->getDeclaredType(); } if (auto funTy = t->getAs<FunctionType>()) { switch (funTy->getExtInfo().getSILRepresentation()) { // Functions that are already represented as blocks or C function pointers // don't need bridging. case SILFunctionType::Representation::Block: case SILFunctionType::Representation::CFunctionPointer: case SILFunctionType::Representation::Thin: case SILFunctionType::Representation::Method: case SILFunctionType::Representation::ObjCMethod: case SILFunctionType::Representation::WitnessMethod: return t; case SILFunctionType::Representation::Thick: { // Thick functions (TODO: conditionally) get bridged to blocks. // This bridging is more powerful than usual block bridging, however, // so we use the ObjCMethod representation. Type newInput = getBridgedInputType(SILFunctionType::Representation::ObjCMethod, pattern.getFunctionInputType(), funTy->getInput()->getCanonicalType()); Type newResult = getBridgedResultType(SILFunctionType::Representation::ObjCMethod, pattern.getFunctionResultType(), funTy->getResult()->getCanonicalType(), /*non-optional*/false); return FunctionType::get(newInput, newResult, funTy->getExtInfo().withSILRepresentation( SILFunctionType::Representation::Block)); } } } auto foreignRepresentation = t->getForeignRepresentableIn(ForeignLanguage::ObjectiveC, M.TheSwiftModule); switch (foreignRepresentation.first) { case ForeignRepresentableKind::None: case ForeignRepresentableKind::Trivial: case ForeignRepresentableKind::Object: return t; case ForeignRepresentableKind::Bridged: case ForeignRepresentableKind::StaticBridged: { auto conformance = foreignRepresentation.second; assert(conformance && "Missing conformance?"); Type bridgedTy = ProtocolConformance::getTypeWitnessByName( t, conformance, M.getASTContext().Id_ObjectiveCType, nullptr); assert(bridgedTy && "Missing _ObjectiveCType witness?"); if (bridgedCollectionsAreOptional && clangTy) bridgedTy = OptionalType::get(bridgedTy); return bridgedTy; } case ForeignRepresentableKind::BridgedError: { auto nsErrorDecl = M.getASTContext().getNSErrorDecl(); assert(nsErrorDecl && "Cannot bridge when NSError isn't available"); return nsErrorDecl->getDeclaredInterfaceType(); } } return t; }
VersionRange AvailabilityInference::inferForType(Type t) { AvailabilityInferenceTypeWalker walker(t->getASTContext()); t.walk(walker); return walker.AvailableRange; }
bool HexagonGenExtract::convert(Instruction *In) { using namespace PatternMatch; Value *BF = 0; ConstantInt *CSL = 0, *CSR = 0, *CM = 0; BasicBlock *BB = In->getParent(); LLVMContext &Ctx = BB->getContext(); bool LogicalSR; // (and (shl (lshr x, #sr), #sl), #m) LogicalSR = true; bool Match = match(In, m_And(m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)), m_ConstantInt(CSL)), m_ConstantInt(CM))); if (!Match) { // (and (shl (ashr x, #sr), #sl), #m) LogicalSR = false; Match = match(In, m_And(m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)), m_ConstantInt(CSL)), m_ConstantInt(CM))); } if (!Match) { // (and (shl x, #sl), #m) LogicalSR = true; CSR = ConstantInt::get(Type::getInt32Ty(Ctx), 0); Match = match(In, m_And(m_Shl(m_Value(BF), m_ConstantInt(CSL)), m_ConstantInt(CM))); if (Match && NoSR0) return false; } if (!Match) { // (and (lshr x, #sr), #m) LogicalSR = true; CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0); Match = match(In, m_And(m_LShr(m_Value(BF), m_ConstantInt(CSR)), m_ConstantInt(CM))); } if (!Match) { // (and (ashr x, #sr), #m) LogicalSR = false; CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0); Match = match(In, m_And(m_AShr(m_Value(BF), m_ConstantInt(CSR)), m_ConstantInt(CM))); } if (!Match) { CM = 0; // (shl (lshr x, #sr), #sl) LogicalSR = true; Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)), m_ConstantInt(CSL))); } if (!Match) { CM = 0; // (shl (ashr x, #sr), #sl) LogicalSR = false; Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)), m_ConstantInt(CSL))); } if (!Match) return false; Type *Ty = BF->getType(); if (!Ty->isIntegerTy()) return false; unsigned BW = Ty->getPrimitiveSizeInBits(); if (BW != 32 && BW != 64) return false; uint32_t SR = CSR->getZExtValue(); uint32_t SL = CSL->getZExtValue(); if (!CM) { // If there was no and, and the shift left did not remove all potential // sign bits created by the shift right, then extractu cannot reproduce // this value. if (!LogicalSR && (SR > SL)) return false; APInt A = APInt(BW, ~0ULL).lshr(SR).shl(SL); CM = ConstantInt::get(Ctx, A); } // CM is the shifted-left mask. Shift it back right to remove the zero // bits on least-significant positions. APInt M = CM->getValue().lshr(SL); uint32_t T = M.countTrailingOnes(); // During the shifts some of the bits will be lost. Calculate how many // of the original value will remain after shift right and then left. uint32_t U = BW - std::max(SL, SR); // The width of the extracted field is the minimum of the original bits // that remain after the shifts and the number of contiguous 1s in the mask. uint32_t W = std::min(U, T); if (W == 0) return false; // Check if the extracted bits are contained within the mask that it is // and-ed with. The extract operation will copy these bits, and so the // mask cannot any holes in it that would clear any of the bits of the // extracted field. if (!LogicalSR) { // If the shift right was arithmetic, it could have included some 1 bits. // It is still ok to generate extract, but only if the mask eliminates // those bits (i.e. M does not have any bits set beyond U). APInt C = APInt::getHighBitsSet(BW, BW-U); if (M.intersects(C) || !APIntOps::isMask(W, M)) return false; } else { // Check if M starts with a contiguous sequence of W times 1 bits. Get // the low U bits of M (which eliminates the 0 bits shifted in on the // left), and check if the result is APInt's "mask": if (!APIntOps::isMask(W, M.getLoBits(U))) return false; } IRBuilder<> IRB(In); Intrinsic::ID IntId = (BW == 32) ? Intrinsic::hexagon_S2_extractu : Intrinsic::hexagon_S2_extractup; Module *Mod = BB->getParent()->getParent(); Value *ExtF = Intrinsic::getDeclaration(Mod, IntId); Value *NewIn = IRB.CreateCall(ExtF, {BF, IRB.getInt32(W), IRB.getInt32(SR)}); if (SL != 0) NewIn = IRB.CreateShl(NewIn, SL, CSL->getName()); In->replaceAllUsesWith(NewIn); return true; }
// This function replaces all global variables with new variables that have // trailing redzones. It also creates a function that poisons // redzones and inserts this function into llvm.global_ctors. bool AddressSanitizer::insertGlobalRedzones(Module &M) { SmallVector<GlobalVariable *, 16> GlobalsToChange; for (Module::GlobalListType::iterator G = M.getGlobalList().begin(), E = M.getGlobalList().end(); G != E; ++G) { Type *Ty = cast<PointerType>(G->getType())->getElementType(); DEBUG(dbgs() << "GLOBAL: " << *G); if (!Ty->isSized()) continue; if (!G->hasInitializer()) continue; // Touch only those globals that will not be defined in other modules. // Don't handle ODR type linkages since other modules may be built w/o asan. if (G->getLinkage() != GlobalVariable::ExternalLinkage && G->getLinkage() != GlobalVariable::PrivateLinkage && G->getLinkage() != GlobalVariable::InternalLinkage) continue; // Two problems with thread-locals: // - The address of the main thread's copy can't be computed at link-time. // - Need to poison all copies, not just the main thread's one. if (G->isThreadLocal()) continue; // For now, just ignore this Alloca if the alignment is large. if (G->getAlignment() > RedzoneSize) continue; // Ignore all the globals with the names starting with "\01L_OBJC_". // Many of those are put into the .cstring section. The linker compresses // that section by removing the spare \0s after the string terminator, so // our redzones get broken. if ((G->getName().find("\01L_OBJC_") == 0) || (G->getName().find("\01l_OBJC_") == 0)) { DEBUG(dbgs() << "Ignoring \\01L_OBJC_* global: " << *G); continue; } if (G->hasSection()) { StringRef Section(G->getSection()); // Ignore the globals from the __OBJC section. The ObjC runtime assumes // those conform to /usr/lib/objc/runtime.h, so we can't add redzones to // them. if ((Section.find("__OBJC,") == 0) || (Section.find("__DATA, __objc_") == 0)) { DEBUG(dbgs() << "Ignoring ObjC runtime global: " << *G); continue; } // See http://code.google.com/p/address-sanitizer/issues/detail?id=32 // Constant CFString instances are compiled in the following way: // -- the string buffer is emitted into // __TEXT,__cstring,cstring_literals // -- the constant NSConstantString structure referencing that buffer // is placed into __DATA,__cfstring // Therefore there's no point in placing redzones into __DATA,__cfstring. // Moreover, it causes the linker to crash on OS X 10.7 if (Section.find("__DATA,__cfstring") == 0) { DEBUG(dbgs() << "Ignoring CFString: " << *G); continue; } } GlobalsToChange.push_back(G); } size_t n = GlobalsToChange.size(); if (n == 0) return false; // A global is described by a structure // size_t beg; // size_t size; // size_t size_with_redzone; // const char *name; // We initialize an array of such structures and pass it to a run-time call. StructType *GlobalStructTy = StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, NULL); SmallVector<Constant *, 16> Initializers(n); IRBuilder<> IRB(CtorInsertBefore); for (size_t i = 0; i < n; i++) { GlobalVariable *G = GlobalsToChange[i]; PointerType *PtrTy = cast<PointerType>(G->getType()); Type *Ty = PtrTy->getElementType(); uint64_t SizeInBytes = TD->getTypeAllocSize(Ty); uint64_t RightRedzoneSize = RedzoneSize + (RedzoneSize - (SizeInBytes % RedzoneSize)); Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize); StructType *NewTy = StructType::get(Ty, RightRedZoneTy, NULL); Constant *NewInitializer = ConstantStruct::get( NewTy, G->getInitializer(), Constant::getNullValue(RightRedZoneTy), NULL); SmallString<2048> DescriptionOfGlobal = G->getName(); DescriptionOfGlobal += " ("; DescriptionOfGlobal += M.getModuleIdentifier(); DescriptionOfGlobal += ")"; GlobalVariable *Name = createPrivateGlobalForString(M, DescriptionOfGlobal); // Create a new global variable with enough space for a redzone. GlobalVariable *NewGlobal = new GlobalVariable( M, NewTy, G->isConstant(), G->getLinkage(), NewInitializer, "", G, G->isThreadLocal()); NewGlobal->copyAttributesFrom(G); NewGlobal->setAlignment(RedzoneSize); Value *Indices2[2]; Indices2[0] = IRB.getInt32(0); Indices2[1] = IRB.getInt32(0); G->replaceAllUsesWith( ConstantExpr::getGetElementPtr(NewGlobal, Indices2, true)); NewGlobal->takeName(G); G->eraseFromParent(); Initializers[i] = ConstantStruct::get( GlobalStructTy, ConstantExpr::getPointerCast(NewGlobal, IntptrTy), ConstantInt::get(IntptrTy, SizeInBytes), ConstantInt::get(IntptrTy, SizeInBytes + RightRedzoneSize), ConstantExpr::getPointerCast(Name, IntptrTy), NULL); DEBUG(dbgs() << "NEW GLOBAL:\n" << *NewGlobal); } ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n); GlobalVariable *AllGlobals = new GlobalVariable( M, ArrayOfGlobalStructTy, false, GlobalVariable::PrivateLinkage, ConstantArray::get(ArrayOfGlobalStructTy, Initializers), ""); Function *AsanRegisterGlobals = cast<Function>(M.getOrInsertFunction( kAsanRegisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL)); AsanRegisterGlobals->setLinkage(Function::ExternalLinkage); IRB.CreateCall2(AsanRegisterGlobals, IRB.CreatePointerCast(AllGlobals, IntptrTy), ConstantInt::get(IntptrTy, n)); // We also need to unregister globals at the end, e.g. when a shared library // gets closed. Function *AsanDtorFunction = Function::Create( FunctionType::get(Type::getVoidTy(*C), false), GlobalValue::InternalLinkage, kAsanModuleDtorName, &M); BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction); IRBuilder<> IRB_Dtor(ReturnInst::Create(*C, AsanDtorBB)); Function *AsanUnregisterGlobals = cast<Function>(M.getOrInsertFunction( kAsanUnregisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, NULL)); AsanUnregisterGlobals->setLinkage(Function::ExternalLinkage); IRB_Dtor.CreateCall2(AsanUnregisterGlobals, IRB.CreatePointerCast(AllGlobals, IntptrTy), ConstantInt::get(IntptrTy, n)); appendToGlobalDtors(M, AsanDtorFunction, kAsanCtorAndCtorPriority); DEBUG(dbgs() << M); return true; }
// FIXME: Merge with llvm::isConsecutiveAccess bool Vectorizer::isConsecutiveAccess(Value *A, Value *B) { Value *PtrA = getLoadStorePointerOperand(A); Value *PtrB = getLoadStorePointerOperand(B); unsigned ASA = getPointerAddressSpace(A); unsigned ASB = getPointerAddressSpace(B); // Check that the address spaces match and that the pointers are valid. if (!PtrA || !PtrB || (ASA != ASB)) return false; // Make sure that A and B are different pointers of the same size type. unsigned PtrBitWidth = DL.getPointerSizeInBits(ASA); Type *PtrATy = PtrA->getType()->getPointerElementType(); Type *PtrBTy = PtrB->getType()->getPointerElementType(); if (PtrA == PtrB || PtrATy->isVectorTy() != PtrBTy->isVectorTy() || DL.getTypeStoreSize(PtrATy) != DL.getTypeStoreSize(PtrBTy) || DL.getTypeStoreSize(PtrATy->getScalarType()) != DL.getTypeStoreSize(PtrBTy->getScalarType())) return false; APInt Size(PtrBitWidth, DL.getTypeStoreSize(PtrATy)); unsigned IdxWidth = DL.getIndexSizeInBits(ASA); APInt OffsetA(IdxWidth, 0), OffsetB(IdxWidth, 0); PtrA = PtrA->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetA); PtrB = PtrB->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetB); APInt OffsetDelta = OffsetB - OffsetA; // Check if they are based on the same pointer. That makes the offsets // sufficient. if (PtrA == PtrB) return OffsetDelta == Size; // Compute the necessary base pointer delta to have the necessary final delta // equal to the size. APInt BaseDelta = Size - OffsetDelta; // Compute the distance with SCEV between the base pointers. const SCEV *PtrSCEVA = SE.getSCEV(PtrA); const SCEV *PtrSCEVB = SE.getSCEV(PtrB); const SCEV *C = SE.getConstant(BaseDelta); const SCEV *X = SE.getAddExpr(PtrSCEVA, C); if (X == PtrSCEVB) return true; // Sometimes even this doesn't work, because SCEV can't always see through // patterns that look like (gep (ext (add (shl X, C1), C2))). Try checking // things the hard way. // Look through GEPs after checking they're the same except for the last // index. GetElementPtrInst *GEPA = getSourceGEP(A); GetElementPtrInst *GEPB = getSourceGEP(B); if (!GEPA || !GEPB || GEPA->getNumOperands() != GEPB->getNumOperands()) return false; unsigned FinalIndex = GEPA->getNumOperands() - 1; for (unsigned i = 0; i < FinalIndex; i++) if (GEPA->getOperand(i) != GEPB->getOperand(i)) return false; Instruction *OpA = dyn_cast<Instruction>(GEPA->getOperand(FinalIndex)); Instruction *OpB = dyn_cast<Instruction>(GEPB->getOperand(FinalIndex)); if (!OpA || !OpB || OpA->getOpcode() != OpB->getOpcode() || OpA->getType() != OpB->getType()) return false; // Only look through a ZExt/SExt. if (!isa<SExtInst>(OpA) && !isa<ZExtInst>(OpA)) return false; bool Signed = isa<SExtInst>(OpA); OpA = dyn_cast<Instruction>(OpA->getOperand(0)); OpB = dyn_cast<Instruction>(OpB->getOperand(0)); if (!OpA || !OpB || OpA->getType() != OpB->getType()) return false; // Now we need to prove that adding 1 to OpA won't overflow. bool Safe = false; // First attempt: if OpB is an add with NSW/NUW, and OpB is 1 added to OpA, // we're okay. if (OpB->getOpcode() == Instruction::Add && isa<ConstantInt>(OpB->getOperand(1)) && cast<ConstantInt>(OpB->getOperand(1))->getSExtValue() > 0) { if (Signed) Safe = cast<BinaryOperator>(OpB)->hasNoSignedWrap(); else Safe = cast<BinaryOperator>(OpB)->hasNoUnsignedWrap(); } unsigned BitWidth = OpA->getType()->getScalarSizeInBits(); // Second attempt: // If any bits are known to be zero other than the sign bit in OpA, we can // add 1 to it while guaranteeing no overflow of any sort. if (!Safe) { KnownBits Known(BitWidth); computeKnownBits(OpA, Known, DL, 0, nullptr, OpA, &DT); if (Known.countMaxTrailingOnes() < (BitWidth - 1)) Safe = true; } if (!Safe) return false; const SCEV *OffsetSCEVA = SE.getSCEV(OpA); const SCEV *OffsetSCEVB = SE.getSCEV(OpB); const SCEV *One = SE.getConstant(APInt(BitWidth, 1)); const SCEV *X2 = SE.getAddExpr(OffsetSCEVA, One); return X2 == OffsetSCEVB; }
void Component:: supports (Type& c, EdgeDispatcherBase& d) { iterate_and_traverse (c.supports_begin (), c.supports_end (), d); }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && ident != Id::identifier) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } size_t dim = args ? args->dim : 0; Declaration *d; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((*args)[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ { Dsymbol *s = getDsymbol((*args)[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; if (ident == Id::isArithmetic) { ISTYPE(t->isintegral() || t->isfloating()) } else if (ident == Id::isFloating) { ISTYPE(t->isfloating()) } else if (ident == Id::isIntegral) { ISTYPE(t->isintegral()) } else if (ident == Id::isScalar) { ISTYPE(t->isscalar()) } else if (ident == Id::isUnsigned) { ISTYPE(t->isunsigned()) } else if (ident == Id::isAssociativeArray) { ISTYPE(t->toBasetype()->ty == Taarray) } else if (ident == Id::isStaticArray) { ISTYPE(t->toBasetype()->ty == Tsarray) } else if (ident == Id::isAbstractClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) } else if (ident == Id::isFinalClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) } else if (ident == Id::isPOD) { if (dim != 1) goto Ldimerror; Object *o = (*args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { error("type expected as second argument of __traits %s instead of %s", ident->toChars(), o->toChars()); goto Lfalse; } if (t->toBasetype()->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)t->toBasetype())->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (ident == Id::isNested) { if (dim != 1) goto Ldimerror; Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (ident == Id::isAbstractFunction) { FuncDeclaration *f; ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) }
void LinearScan::computePreColoringHint() { m_preColoringHint.clear(); IRInstruction* inst = nextNative(); if (inst == nullptr) { return; } Opcode opc = inst->op(); using NativeCalls::CallMap; using NativeCalls::ArgType; if (CallMap::hasInfo(opc)) { unsigned reg = 0; for (auto const& arg : CallMap::info(opc).args) { switch (arg.type) { case ArgType::SSA: m_preColoringHint.add(inst->src(arg.ival), 0, reg++); break; case ArgType::TV: case ArgType::MemberKeyS: case ArgType::MemberKeyIS: m_preColoringHint.add(inst->src(arg.ival), 0, reg++); m_preColoringHint.add(inst->src(arg.ival), 1, reg++); break; case ArgType::ExtraImm: case ArgType::Imm: break; } } return; } // For instructions that want to hint a continuous increasing range // of sources to a continuous increasing range of argument // registers. auto normalHint = [&](int count, int srcBase, int argBase) { for (int i = 0; i < count; ++i) { m_preColoringHint.add(inst->src(i + srcBase), 0, i + argBase); } }; switch (opc) { case LdFunc: m_preColoringHint.add(inst->src(0), 0, 1); break; case NativeImpl: m_preColoringHint.add(inst->src(1), 0, 0); break; case Concat: { Type lType = inst->src(0)->type(); Type rType = inst->src(1)->type(); if ((lType.isString() && rType.isString()) || (lType.isString() && rType == Type::Int) || (lType == Type::Int && rType.isString())) { m_preColoringHint.add(inst->src(0), 0, 0); m_preColoringHint.add(inst->src(1), 0, 1); } else { m_preColoringHint.add(inst->src(0), 0, 1); m_preColoringHint.add(inst->src(1), 0, 3); } } break; case AKExists: normalHint(2, 0, 0); break; case Eq: case Neq: case Same: case NSame: { auto src1 = inst->src(0); auto src2 = inst->src(1); auto type1 = src1->type(); auto type2 = src2->type(); if ((type1.isArray() && type2.isArray()) || (type1.isString() && type2.isString()) || (type1.isString() && !src1->isConst()) || ((type1 == Type::Obj || type1 == Type::Res) && (type2 == Type::Obj || type2 == Type::Res))) { m_preColoringHint.add(src1, 0, 0); m_preColoringHint.add(src2, 0, 1); } } break; case IterInit: case WIterInit: { m_preColoringHint.add(inst->src(0), 0, 1); } break; case LdSSwitchDestFast: normalHint(1, 0, 0); break; case LdSSwitchDestSlow: normalHint(1, 0, 0); break; case LdGblAddr: normalHint(1, 0, 0); break; case LdClsPropAddr: normalHint(3, 0, 0); break; case LdCls: m_preColoringHint.add(inst->src(0), 0, 1); break; case BoxPtr: normalHint(1, 0, 0); break; default: break; } }
GenericValue MCJIT::runFunction(Function *F, const std::vector<GenericValue> &ArgValues) { assert(F && "Function *F was null at entry to run()"); void *FPtr = getPointerToFunction(F); assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); FunctionType *FTy = F->getFunctionType(); Type *RetTy = FTy->getReturnType(); assert((FTy->getNumParams() == ArgValues.size() || (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && "Wrong number of arguments passed into function!"); assert(FTy->getNumParams() == ArgValues.size() && "This doesn't support passing arguments through varargs (yet)!"); // Handle some common cases first. These cases correspond to common `main' // prototypes. if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { switch (ArgValues.size()) { case 3: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy() && FTy->getParamType(2)->isPointerTy()) { int (*PF)(int, char **, const char **) = (int(*)(int, char **, const char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]), (const char **)GVTOP(ArgValues[2]))); return rv; } break; case 2: if (FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isPointerTy()) { int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; // Call the function. GenericValue rv; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), (char **)GVTOP(ArgValues[1]))); return rv; } break; case 1: if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy(32)) { GenericValue rv; int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); return rv; } break; } } // Handle cases where no arguments are passed first. if (ArgValues.empty()) { GenericValue rv; switch (RetTy->getTypeID()) { default: llvm_unreachable("Unknown return type for function call!"); case Type::IntegerTyID: { unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); if (BitWidth == 1) rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); else if (BitWidth <= 8) rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); else if (BitWidth <= 16) rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); else if (BitWidth <= 32) rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); else if (BitWidth <= 64) rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); else llvm_unreachable("Integer types > 64 bits not supported"); return rv; } case Type::VoidTyID: rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); return rv; case Type::FloatTyID: rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); return rv; case Type::DoubleTyID: rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); return rv; case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: llvm_unreachable("long double not supported yet"); case Type::PointerTyID: return PTOGV(((void*(*)())(intptr_t)FPtr)()); } } llvm_unreachable("Full-featured argument passing not supported yet!"); }
/* * Returns whether a type is generic enough to try hoisting a * prediction in order to specialize it. */ bool typeSufficientlyGeneric(Type t) { return t.needsReg(); }
Expression *createTypeInfoArray(Scope *sc, Expression *exps[], size_t dim) { #if 1 /* * Pass a reference to the TypeInfo_Tuple corresponding to the types of the * arguments. Source compatibility is maintained by computing _arguments[] * at the start of the called function by offseting into the TypeInfo_Tuple * reference. */ Parameters *args = Parameters_create(); args->setDim(dim); for (size_t i = 0; i < dim; i++) { Parameter *arg = Parameter::create(STCin, exps[i]->type, NULL, NULL); (*args)[i] = arg; } TypeTuple *tup = TypeTuple::create(args); Expression *e = tup->getTypeInfo(sc); e = e->optimize(WANTvalue); assert(e->op == TOKsymoff); // should be SymOffExp return e; #else /* Improvements: * 1) create an array literal instead, * as it would eliminate the extra dereference of loading the * static variable. */ ArrayInitializer *ai = new ArrayInitializer(0); VarDeclaration *v; Type *t; Expression *e; OutBuffer buf; Identifier *id; char *name; // Generate identifier for _arguments[] buf.writestring("_arguments_"); for (int i = 0; i < dim; i++) { t = exps[i]->type; t->toDecoBuffer(&buf); } buf.writeByte(0); id = Lexer::idPool((char *)buf.data); Module *m = sc->module; Dsymbol *s = m->symtab->lookup(id); if (s && s->parent == m) { // Use existing one v = s->isVarDeclaration(); assert(v); } else { // Generate new one for (int i = 0; i < dim; i++) { t = exps[i]->type; e = t->getTypeInfo(sc); ai->addInit(new IntegerExp(i), new ExpInitializer(Loc(), e)); } t = Type::typeinfo->type->arrayOf(); ai->type = t; v = new VarDeclaration(0, t, id, ai); v->storage_class |= STCtemp; m->members->push(v); m->symtabInsert(v); sc = sc->push(); sc->linkage = LINKc; sc->stc = STCstatic | STCcomdat; ai->semantic(sc, t); v->semantic(sc); v->parent = m; sc = sc->pop(); } e = VarExp::create(Loc(), v); e = e->semantic(sc); return e; #endif }
void CodeGenerator::emitTypeTest(Type type, Loc typeSrc, Loc dataSrc, JmpFn doJcc) { assert(!type.subtypeOf(Type::Cls)); if (type.equals(Type::Gen)) { return; } // You can't compare against memory. Load the type into scratch. m_as. Ldrb (rAsm.W(), typeSrc); ConditionCode cc; if (type.isString()) { // Note: ARM can actually do better here; it has a fused test-and-branch // instruction. The way this code is factored makes it difficult to use, // though; the jump instruction will be written by some other code. m_as. Tst (rAsm.W(), KindOfStringBit); cc = CC_NE; } else if (type.equals(Type::UncountedInit)) { m_as. Tst (rAsm.W(), KindOfUncountedInitBit); cc = CC_NE; } else if (type.equals(Type::Uncounted)) { m_as. Cmp (rAsm.W(), KindOfRefCountThreshold); cc = CC_LE; } else if (type.equals(Type::Cell)) { m_as. Cmp (rAsm.W(), KindOfRef); cc = CC_L; } else { assert(type.isKnownDataType()); DataType dataType = type.toDataType(); assert(dataType == KindOfRef || (dataType >= KindOfUninit && dataType <= KindOfResource)); m_as. Cmp (rAsm.W(), dataType); cc = CC_E; } doJcc(cc); if (type.strictSubtypeOf(Type::Obj) || type.strictSubtypeOf(Type::Res)) { assert(type.getClass()->attrs() & AttrFinal); m_as. Ldr (rAsm, dataSrc); m_as. Ldr (rAsm, rAsm[ObjectData::getVMClassOffset()]); m_as. Cmp (rAsm, reinterpret_cast<int64_t>(type.getClass())); doJcc(CC_E); } else if (type.subtypeOf(Type::Arr) && type.hasArrayKind()) { m_as. Ldr (rAsm, dataSrc); m_as. Ldrb (rAsm.W(), rAsm[ArrayData::offsetofKind()]); m_as. Cmp (rAsm.W(), type.getArrayKind()); doJcc(CC_E); } }
/// WriteTypeTable - Write out the type table for a module. static void WriteTypeTable(const NaClValueEnumerator &VE, NaClBitstreamWriter &Stream) { DEBUG(dbgs() << "-> WriteTypeTable\n"); const NaClValueEnumerator::TypeList &TypeList = VE.getTypes(); Stream.EnterSubblock(naclbitc::TYPE_BLOCK_ID_NEW, TYPE_MAX_ABBREV); SmallVector<uint64_t, 64> TypeVals; // Abbrev for TYPE_CODE_FUNCTION. NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::TYPE_CODE_FUNCTION)); Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // isvararg Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); Abbv->Add(NaClBitCodeAbbrevOp(TypeIdEncoding, TypeIdNumBits)); if (TYPE_FUNCTION_ABBREV != Stream.EmitAbbrev(Abbv)) llvm_unreachable("Unexpected abbrev ordering!"); // Emit an entry count so the reader can reserve space. TypeVals.push_back(TypeList.size()); Stream.EmitRecord(naclbitc::TYPE_CODE_NUMENTRY, TypeVals); TypeVals.clear(); // Loop over all of the types, emitting each in turn. for (unsigned i = 0, e = TypeList.size(); i != e; ++i) { Type *T = TypeList[i]; int AbbrevToUse = 0; unsigned Code = 0; switch (T->getTypeID()) { default: llvm_unreachable("Unknown type!"); case Type::VoidTyID: Code = naclbitc::TYPE_CODE_VOID; break; case Type::FloatTyID: Code = naclbitc::TYPE_CODE_FLOAT; break; case Type::DoubleTyID: Code = naclbitc::TYPE_CODE_DOUBLE; break; case Type::IntegerTyID: // INTEGER: [width] Code = naclbitc::TYPE_CODE_INTEGER; TypeVals.push_back(cast<IntegerType>(T)->getBitWidth()); break; case Type::VectorTyID: { VectorType *VT = cast<VectorType>(T); // VECTOR [numelts, eltty] Code = naclbitc::TYPE_CODE_VECTOR; TypeVals.push_back(VT->getNumElements()); TypeVals.push_back(VE.getTypeID(VT->getElementType())); break; } case Type::FunctionTyID: { FunctionType *FT = cast<FunctionType>(T); // FUNCTION: [isvararg, retty, paramty x N] Code = naclbitc::TYPE_CODE_FUNCTION; TypeVals.push_back(FT->isVarArg()); TypeVals.push_back(VE.getTypeID(FT->getReturnType())); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) TypeVals.push_back(VE.getTypeID(FT->getParamType(i))); AbbrevToUse = TYPE_FUNCTION_ABBREV; break; } case Type::StructTyID: report_fatal_error("Struct types are not supported in PNaCl bitcode"); case Type::ArrayTyID: report_fatal_error("Array types are not supported in PNaCl bitcode"); } // Emit the finished record. Stream.EmitRecord(Code, TypeVals, AbbrevToUse); TypeVals.clear(); } Stream.ExitBlock(); DEBUG(dbgs() << "<- WriteTypeTable\n"); }
virtual void reset(Type &row) { for (typename Type::iterator current = row.begin(), end = row.end(); current != end; ++current) *current = typename Type::value_type(); }