This machine mirrors various open-source projects.
20 Gbit/s uplink.
If there are any issues or you want another project mirrored, please contact
mirror-service -=AT=- netcologne DOT de !
00001 //===-- codegen/BoundsEmitter.cpp ----------------------------- -*- C++ -*-===// 00002 // 00003 // This file is distributed under the MIT license. See LICENSE.txt for details. 00004 // 00005 // Copyright (C) 2009, Stephen Wilson 00006 // 00007 //===----------------------------------------------------------------------===// 00008 00009 #include "CGContext.h" 00010 #include "CodeGenRoutine.h" 00011 #include "BoundsEmitter.h" 00012 #include "comma/ast/AggExpr.h" 00013 00014 using namespace comma; 00015 using llvm::dyn_cast; 00016 using llvm::cast; 00017 using llvm::isa; 00018 00019 namespace { 00020 00023 llvm::Value *synthBounds(llvm::IRBuilder<> &Builder, 00024 const llvm::StructType *boundTy, 00025 llvm::Value *lower, llvm::Value *upper) 00026 { 00027 // If both the bounds are constants, build a constant structure. 00028 if (isa<llvm::Constant>(lower) && isa<llvm::Constant>(upper)) { 00029 std::vector<llvm::Constant*> elts; 00030 elts.push_back(cast<llvm::Constant>(lower)); 00031 elts.push_back(cast<llvm::Constant>(upper)); 00032 return llvm::ConstantStruct::get(boundTy, elts); 00033 } 00034 00035 // Otherwise, populate an an undef object with the bounds. 00036 llvm::Value *bounds = llvm::UndefValue::get(boundTy); 00037 bounds = Builder.CreateInsertValue(bounds, lower, 0); 00038 bounds = Builder.CreateInsertValue(bounds, upper, 1); 00039 return bounds; 00040 } 00041 00042 } // end anonymous namespace. 00043 00044 00045 BoundsEmitter::BoundsEmitter(CodeGenRoutine &CGR) 00046 : CGR(CGR), 00047 CG(CGR.getCodeGen()), 00048 CGT(CGR.getCGC().getCGT()) { } 00049 00050 const llvm::StructType *BoundsEmitter::getType(const ArrayType *arrTy) 00051 { 00052 return CGT.lowerArrayBounds(arrTy); 00053 } 00054 00055 llvm::Value *BoundsEmitter::synthScalarBounds(llvm::IRBuilder<> &Builder, 00056 const DiscreteType *type) 00057 { 00058 LUPair LU = getScalarBounds(Builder, type); 00059 llvm::Value *lower = LU.first; 00060 llvm::Value *upper = LU.second; 00061 const llvm::StructType *boundTy = CGT.lowerScalarBounds(type); 00062 return synthBounds(Builder, boundTy, lower, upper); 00063 } 00064 00065 BoundsEmitter::LUPair 00066 BoundsEmitter::getScalarBounds(llvm::IRBuilder<> &Builder, 00067 const DiscreteType *type) 00068 { 00069 LUPair LU; 00070 00071 if (const Range *range = type->getConstraint()) { 00072 if (range->isStatic()) 00073 LU = getRange(Builder, range); 00074 else { 00075 // Try to lookup the bounds for this type in the current frame. If 00076 // the lookup fails, evaluate the bounds an associate the result 00077 // with the type. 00078 SRFrame *frame = CGR.getSRFrame(); 00079 llvm::Value *bounds = frame->lookup(type, activation::Bounds); 00080 00081 if (!bounds) { 00082 bounds = synthRange(Builder, range); 00083 frame->associate(type, activation::Bounds, bounds); 00084 } 00085 LU.first = getLowerBound(Builder, bounds, 0); 00086 LU.second = getUpperBound(Builder, bounds, 0); 00087 } 00088 } 00089 else { 00090 const llvm::Type *loweredTy = CGT.lowerType(type); 00091 llvm::APInt bound; 00092 00093 type->getLowerLimit(bound); 00094 LU.first = llvm::ConstantInt::get(loweredTy, bound); 00095 00096 type->getUpperLimit(bound); 00097 LU.second = llvm::ConstantInt::get(loweredTy, bound); 00098 } 00099 00100 return LU; 00101 } 00102 00103 llvm::Value *BoundsEmitter::getLowerBound(llvm::IRBuilder<> &Builder, 00104 const DiscreteType *type) 00105 { 00106 if (type->isConstrained()) 00107 return getLowerBound(Builder, type->getConstraint()); 00108 00109 const llvm::Type *loweredTy = CGT.lowerType(type); 00110 llvm::APInt bound; 00111 00112 type->getLowerLimit(bound); 00113 return llvm::ConstantInt::get(loweredTy, bound); 00114 } 00115 00116 llvm::Value *BoundsEmitter::getUpperBound(llvm::IRBuilder<> &Builder, 00117 const DiscreteType *type) 00118 { 00119 if (type->isConstrained()) 00120 return getUpperBound(Builder, type->getConstraint()); 00121 00122 const llvm::Type *loweredTy = CGT.lowerType(type); 00123 llvm::APInt bound; 00124 00125 type->getUpperLimit(bound); 00126 return llvm::ConstantInt::get(loweredTy, bound); 00127 } 00128 00129 llvm::Value *BoundsEmitter::getLowerBound(llvm::IRBuilder<> &Builder, 00130 const Range *range) 00131 { 00132 const llvm::Type *elemTy = CGT.lowerType(range->getType()); 00133 00134 if (range->hasStaticLowerBound()) { 00135 const llvm::APInt &bound = range->getStaticLowerBound(); 00136 return llvm::ConstantInt::get(elemTy, bound); 00137 } 00138 else { 00139 Expr *expr = const_cast<Expr*>(range->getLowerBound()); 00140 return CGR.emitValue(expr).first(); 00141 } 00142 } 00143 00144 llvm::Value *BoundsEmitter::getUpperBound(llvm::IRBuilder<> &Builder, 00145 const Range *range) 00146 { 00147 const llvm::Type *elemTy = CGT.lowerType(range->getType()); 00148 00149 if (range->hasStaticUpperBound()) { 00150 const llvm::APInt &bound = range->getStaticUpperBound(); 00151 return llvm::ConstantInt::get(elemTy, bound); 00152 } 00153 else { 00154 Expr *expr = const_cast<Expr*>(range->getUpperBound()); 00155 return CGR.emitValue(expr).first(); 00156 } 00157 } 00158 00159 llvm::Value *BoundsEmitter::synthRange(llvm::IRBuilder<> &Builder, 00160 const Range *range) 00161 { 00162 llvm::Value *lower = getLowerBound(Builder, range); 00163 llvm::Value *upper = getUpperBound(Builder, range); 00164 const llvm::StructType *boundTy = CGT.lowerRange(range); 00165 return synthBounds(Builder, boundTy, lower, upper); 00166 } 00167 00168 llvm::Value *BoundsEmitter::synthRange(llvm::IRBuilder<> &Builder, 00169 llvm::Value *lower, llvm::Value *upper) 00170 { 00171 std::vector<const llvm::Type*> elts; 00172 const llvm::IntegerType *limitTy; 00173 limitTy = cast<llvm::IntegerType>(lower->getType()); 00174 assert(limitTy == upper->getType() && "Inconsitent types for range!"); 00175 00176 // FIXME: Perhaps CGT should provide this type for consistency. 00177 elts.push_back(limitTy); 00178 elts.push_back(limitTy); 00179 return synthBounds(Builder, CG.getStructTy(elts), lower, upper); 00180 } 00181 00182 BoundsEmitter::LUPair BoundsEmitter::getRange(llvm::IRBuilder<> &Builder, 00183 const Range *range) 00184 { 00185 llvm::Value *lower = getLowerBound(Builder, range); 00186 llvm::Value *upper = getUpperBound(Builder, range); 00187 return LUPair(lower, upper); 00188 } 00189 00190 llvm::Value *BoundsEmitter::computeBoundLength(llvm::IRBuilder<> &Builder, 00191 llvm::Value *bounds, 00192 unsigned index) 00193 { 00194 llvm::Value *lower = getLowerBound(Builder, bounds, index); 00195 llvm::Value *upper = getUpperBound(Builder, bounds, index); 00196 00197 // FIXME: We always return the length of an array as an i32. The main 00198 // motivation for this choice is that LLVM alloca's are currently restricted 00199 // to this size (though this might change). Since the bounds may be of a 00200 // wider type, we need to generate checks that the following calculations do 00201 // not overflow. 00202 const llvm::IntegerType *boundTy; 00203 const llvm::IntegerType *i32Ty; 00204 00205 boundTy = cast<llvm::IntegerType>(lower->getType()); 00206 i32Ty = CG.getInt32Ty(); 00207 00208 if (boundTy->getBitWidth() < 32) { 00209 lower = Builder.CreateSExt(lower, i32Ty); 00210 upper = Builder.CreateSExt(upper, i32Ty); 00211 } 00212 else if (boundTy->getBitWidth() > 32) { 00213 lower = Builder.CreateTrunc(lower, i32Ty); 00214 upper = Builder.CreateTrunc(upper, i32Ty); 00215 } 00216 00217 llvm::Value *size = Builder.CreateSub(upper, lower); 00218 llvm::Value *one = llvm::ConstantInt::get(size->getType(), 1); 00219 return Builder.CreateAdd(size, one); 00220 } 00221 00222 llvm::Value *BoundsEmitter::computeTotalBoundLength(llvm::IRBuilder<> &Builder, 00223 llvm::Value *bounds) 00224 { 00225 const llvm::StructType *strTy; 00226 const llvm::IntegerType *sumTy; 00227 llvm::Value *length; 00228 unsigned numElts; 00229 00230 // FIXME: Perhaps we should forgo the load and GEP instead. 00231 if (!bounds->getType()->isAggregateType()) 00232 bounds = Builder.CreateLoad(bounds); 00233 00234 strTy = cast<llvm::StructType>(bounds->getType()); 00235 sumTy = CG.getInt32Ty(); 00236 00237 length = llvm::ConstantInt::get(sumTy, int64_t(0)); 00238 numElts = strTy->getNumElements() / 2; 00239 00240 for (unsigned idx = 0; idx < numElts; ++idx) { 00241 llvm::Value *partial = computeBoundLength(Builder, bounds, idx); 00242 length = Builder.CreateAdd(length, partial); 00243 } 00244 return length; 00245 } 00246 00247 llvm::Value *BoundsEmitter::computeIsNull(llvm::IRBuilder<> &Builder, 00248 llvm::Value *bounds, unsigned index) 00249 { 00250 llvm::Value *lower = getLowerBound(Builder, bounds, index); 00251 llvm::Value *upper = getUpperBound(Builder, bounds, index); 00252 return Builder.CreateICmpSLT(upper, lower); 00253 } 00254 00255 llvm::Value *BoundsEmitter::synthArrayBounds(llvm::IRBuilder<> &Builder, 00256 ArrayType *arrTy) 00257 { 00258 if (arrTy->isStaticallyConstrained()) 00259 return synthStaticArrayBounds(Builder, arrTy); 00260 00261 // Build a first-class struct to hold the bound data. 00262 const llvm::StructType *boundsTy = getType(arrTy); 00263 llvm::Value *bounds = llvm::UndefValue::get(boundsTy); 00264 00265 for (unsigned i = 0; i < arrTy->getRank(); ++i) { 00266 DiscreteType *idxTy = arrTy->getIndexType(i); 00267 LUPair LU = getScalarBounds(Builder, idxTy); 00268 00269 bounds = Builder.CreateInsertValue(bounds, LU.first, 2*i); 00270 bounds = Builder.CreateInsertValue(bounds, LU.second, 2*i + 1); 00271 } 00272 return bounds; 00273 } 00274 00275 llvm::Constant * 00276 BoundsEmitter::synthStaticArrayBounds(llvm::IRBuilder<> &Builder, 00277 ArrayType *arrTy) 00278 { 00279 const llvm::StructType *boundsTy = getType(arrTy); 00280 std::vector<llvm::Constant*> bounds; 00281 00282 for (unsigned i = 0; i < arrTy->getRank(); ++i) { 00283 DiscreteType *idxTy = arrTy->getIndexType(i); 00284 Range *range = idxTy->getConstraint(); 00285 00286 assert(idxTy->isStaticallyConstrained()); 00287 const llvm::APInt &lower = range->getStaticLowerBound(); 00288 const llvm::APInt &upper = range->getStaticUpperBound(); 00289 const llvm::Type *eltTy = boundsTy->getElementType(i); 00290 bounds.push_back(llvm::ConstantInt::get(eltTy, lower)); 00291 bounds.push_back(llvm::ConstantInt::get(eltTy, upper)); 00292 } 00293 llvm::Constant *data = llvm::ConstantStruct::get(boundsTy, bounds); 00294 return data; 00295 } 00296 00297 llvm::Value *BoundsEmitter::synthAggregateBounds(llvm::IRBuilder<> &Builder, 00298 AggregateExpr *agg, 00299 llvm::Value *dst) 00300 { 00301 assert(agg->isPurelyPositional() && 00302 "Cannot codegen bounds for this type of aggregate!"); 00303 00304 llvm::Value *bounds = 0; 00305 ArrayType *arrTy = cast<ArrayType>(agg->getType()); 00306 00307 if (arrTy->isStaticallyConstrained()) 00308 bounds = synthStaticArrayBounds(Builder, arrTy); 00309 else { 00310 // The index type for the aggregate is unconstrained. 00311 llvm::APInt bound; 00312 std::vector<llvm::Constant*> boundValues; 00313 DiscreteType *idxTy = arrTy->getIndexType(0); 00314 llvm::LLVMContext &context = CG.getLLVMContext(); 00315 00316 assert(!agg->hasOthers() && 00317 "Cannot codegen bounds for dynamic aggregates with others!"); 00318 00319 // The lower bound is derived directly from the index type. 00320 if (Range *range = idxTy->getConstraint()) { 00321 assert(range->isStatic() && "Cannot codegen dynamic ranges."); 00322 bound = range->getStaticLowerBound(); 00323 boundValues.push_back(llvm::ConstantInt::get(context, bound)); 00324 } 00325 else { 00326 idxTy->getLowerLimit(bound); 00327 boundValues.push_back(llvm::ConstantInt::get(context, bound)); 00328 } 00329 00330 // The upper bound is the sum of the lower bound and the length of the 00331 // aggregate, minus one. 00332 llvm::APInt length(bound.getBitWidth(), agg->numPositionalComponents()); 00333 bound += --length; 00334 boundValues.push_back(llvm::ConstantInt::get(context, bound)); 00335 00336 // Obtain a constant structure object corresponding to the computed 00337 // bounds. 00338 const llvm::StructType *boundsTy = getType(arrTy); 00339 bounds = llvm::ConstantStruct::get(boundsTy, boundValues); 00340 } 00341 00342 if (dst) 00343 Builder.CreateStore(bounds, dst); 00344 return bounds; 00345 }