[code generation] added constraints checking
This commit is contained in:
@@ -28,7 +28,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned *get_param(ir::value *value);
|
unsigned *get_param(ir::value *value);
|
||||||
bool check_constraints(std::map<ir::value*, std::string>& errors);
|
bool check_constraints(ir::module &fn, std::map<ir::value *, std::vector<std::string>> &errors);
|
||||||
void run(ir::module &mod);
|
void run(ir::module &mod);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
#include "ir/function.h"
|
#include "ir/function.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
namespace tdl{
|
namespace tdl{
|
||||||
namespace codegen{
|
namespace codegen{
|
||||||
|
|
||||||
@@ -83,80 +84,73 @@ void tune::run(ir::module &mod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tune::check_constraints(std::map<ir::value *, std::string> &errors) {
|
bool tune::check_constraints(ir::module &mod, std::map<ir::value *, std::vector<std::string>> &errors) {
|
||||||
|
for(ir::function *fn: mod.get_function_list()){
|
||||||
|
/* grids */
|
||||||
|
auto get_tile_gt1_dim = [&](ir::value *v){
|
||||||
|
unsigned result = 0;
|
||||||
|
for(unsigned shape: v->get_type()->get_tile_shapes()) {
|
||||||
|
result += (shape > 1)?shape:0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
using std::to_string;
|
||||||
|
std::map<unsigned*, ir::instruction*> references;
|
||||||
|
for(ir::basic_block *block: fn->blocks())
|
||||||
|
for(ir::instruction *i: block->get_inst_list()){
|
||||||
|
if(!i->get_type()->is_tile_ty())
|
||||||
|
continue;
|
||||||
|
for(auto ¶m: params_.at(i)){
|
||||||
|
if(*param.second == 1)
|
||||||
|
continue;
|
||||||
|
ir::instruction *&r = references[param.second];
|
||||||
|
if(!r && get_tile_gt1_dim(i) > get_tile_gt1_dim(r))
|
||||||
|
r = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// extract unique instructions in order
|
||||||
|
std::vector<ir::instruction*> grids;
|
||||||
|
for(auto &ref: references)
|
||||||
|
if(std::find(grids.begin(), grids.end(), ref.second) == grids.end())
|
||||||
|
grids.push_back(ref.second);
|
||||||
|
|
||||||
return true;
|
// number of warps
|
||||||
|
int num_warps = 1;
|
||||||
|
for(size_t k = 0; k < grids.front()->get_type()->get_tile_shapes().size(); k++)
|
||||||
|
num_warps *= *params_[grids.front()]["p2.d" + to_string(k)];
|
||||||
|
// check constraints
|
||||||
|
for(ir::instruction *i: grids){
|
||||||
|
ir::type *ty = i->get_type();
|
||||||
|
const auto &shapes = ty->get_tile_shapes();
|
||||||
|
// for each dimension, the product of layout components
|
||||||
|
// must device the shape
|
||||||
|
for(size_t k = 0; k < shapes.size(); k++) {
|
||||||
|
std::string strk = to_string(k);
|
||||||
|
unsigned *s0 = params_[i]["p0.d" + strk];
|
||||||
|
unsigned *s1 = params_[i]["p1.d" + strk];
|
||||||
|
unsigned *s2 = params_[i]["p2.d" + strk];
|
||||||
|
unsigned multiple = (*s0)*(*s1)*(*s2);
|
||||||
|
if(shapes[k] % multiple != 0)
|
||||||
|
errors[i].push_back("for dim " + strk + ": shape (" + to_string(shapes[k]) + ")"
|
||||||
|
" is not a multiple of layout (" + to_string(multiple) + ")");
|
||||||
|
}
|
||||||
|
// the number of thread per warp must be 32
|
||||||
|
int num_threads = 1;
|
||||||
|
for(size_t k = 0; k < shapes.size(); k++)
|
||||||
|
num_threads *= *params_[i]["p1.d" + to_string(k)];
|
||||||
|
if(num_threads != 32)
|
||||||
|
errors[i].push_back("number of threads per warp (" + to_string(num_threads) + ") must be 32");
|
||||||
|
// The number of warps required by the layout is the same
|
||||||
|
// for all tiles in the function
|
||||||
|
int required_num_warps = 1;
|
||||||
|
for(size_t k = 0; k < shapes.size(); k++)
|
||||||
|
required_num_warps *= *params_[i]["p2.d" + to_string(k)];
|
||||||
|
if(required_num_warps != num_warps)
|
||||||
|
errors[i].push_back("number of warps (" + to_string(required_num_warps) + ") must be " + to_string(num_warps));
|
||||||
|
}
|
||||||
|
return errors.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//bool TLVMAddTunerConstraints::runOnFunction(Function &F) {
|
|
||||||
// LLVMContext &Ctx = F.getContext();
|
|
||||||
|
|
||||||
// DenseMap<MDNode*, Instruction*> Refs;
|
|
||||||
// for(Function::iterator::value_type &BB: F)
|
|
||||||
// for(Instruction &I : BB)
|
|
||||||
// if(isTLVMValue(&I)){
|
|
||||||
// SmallVector<std::pair<unsigned, MDNode*>, 4> MDs;
|
|
||||||
// I.getAllMetadata(MDs);
|
|
||||||
// for(auto &X: MDs){
|
|
||||||
// if(MDRead(X.second)==1)
|
|
||||||
// continue;
|
|
||||||
// Instruction *&Ref = Refs[X.second];
|
|
||||||
// if(!Ref || getNumGT1Dim(I) > getNumGT1Dim(*Ref))
|
|
||||||
// Ref = &I;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// SmallVector<Instruction*, 4> Grids;
|
|
||||||
// for(auto &R: Refs)
|
|
||||||
// if(std::find(Grids.begin(), Grids.end(), R.second) == Grids.end())
|
|
||||||
// Grids.push_back(R.second);
|
|
||||||
|
|
||||||
|
|
||||||
// Instruction *FirstTile = Grids.front();
|
|
||||||
// for(Instruction *I: Grids){
|
|
||||||
// Type *Ty = I->getType();
|
|
||||||
// size_t NumDim = Ty->getTileNumDimensions();
|
|
||||||
|
|
||||||
// // For each dimension, the product of layout components
|
|
||||||
// // must divide shape
|
|
||||||
// for(size_t K = 0; K < NumDim; K++){
|
|
||||||
// unsigned Shape = MDRead(I->getMetadata("nvvm.param.shape.d" + itostr(K)));
|
|
||||||
// unsigned S0 = MDRead(I->getMetadata("nvvm.param.layout.p0.d" + itostr(K)));
|
|
||||||
// unsigned S1 = MDRead(I->getMetadata("nvvm.param.layout.p1.d" + itostr(K)));
|
|
||||||
// unsigned S2 = MDRead(I->getMetadata("nvvm.param.layout.p2.d" + itostr(K)));
|
|
||||||
// bool Constraint = Shape % (S0*S1*S2)== 0;
|
|
||||||
// Constant *Cst = Constraint?ConstantInt::getTrue(Ctx):ConstantInt::getFalse(Ctx);
|
|
||||||
// I->setMetadata("nvvm.constraint.shape.d" + itostr(K), MDNode::get(Ctx, ConstantAsMetadata::get(Cst)));
|
|
||||||
// };
|
|
||||||
// // The number of threads per warp is 32
|
|
||||||
// {
|
|
||||||
// int NumThreads = 1;
|
|
||||||
// for(size_t K = 0; K < NumDim; K++){
|
|
||||||
// unsigned PC = MDRead(I->getMetadata("nvvm.param.layout.p1.d" + itostr(K)));
|
|
||||||
// NumThreads *= PC;
|
|
||||||
// }
|
|
||||||
// bool Constraint = NumThreads==32;
|
|
||||||
// Constant *Cst = Constraint?ConstantInt::getTrue(Ctx):ConstantInt::getFalse(Ctx);
|
|
||||||
// I->setMetadata("nvvm.constraint.threads", MDNode::get(Ctx, ConstantAsMetadata::get(Cst)));
|
|
||||||
// }
|
|
||||||
// // The number of warps required by the layout is the same
|
|
||||||
// // for all tiles in the function
|
|
||||||
// {
|
|
||||||
// int NumWarps = 1;
|
|
||||||
// int RefNumWarps = 1;
|
|
||||||
// for(size_t K = 0; K < NumDim; K++){
|
|
||||||
// unsigned PC = MDRead(I->getMetadata("nvvm.param.layout.p2.d" + itostr(K)));
|
|
||||||
// unsigned PR = MDRead(FirstTile->getMetadata("nvvm.param.layout.p2.d" + itostr(K)));
|
|
||||||
// NumWarps *= PC;
|
|
||||||
// RefNumWarps *= PR;
|
|
||||||
// }
|
|
||||||
// bool Constraint = NumWarps==RefNumWarps;
|
|
||||||
// Constant *Cst = Constraint?ConstantInt::getTrue(Ctx):ConstantInt::getFalse(Ctx);
|
|
||||||
// I->setMetadata("nvvm.constraint.warps", MDNode::get(Ctx, ConstantAsMetadata::get(Cst)));
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user