Closed ytgui closed 5 years ago
namespace {
class Hello : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid
Hello() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
dbgs() << "Function: ";
dbgs() << F.getName() << "\n";
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
I.dump();
}
}
dbgs() << "----------\n";
return false;
}
private:
void printType(Type *Ty) {}
};
}
char Hello::ID = 0;
static RegisterPass<Hello> X("hello", "Hello World Pass");
bool runOnFunction(Function &F) {
SmallVector<Instruction *, 16> WorkList;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (isa<IntrinsicInst>(&I)) {
WorkList.push_back(&I);
}
}
}
bool Changed = false;
while (not WorkList.empty()) {
Instruction *I = WorkList.pop_back_val();
if (matchStInt32To16(I)) {
Changed |= hackStInt32To16(I);
} else if (matchLdInt16To32(I)) {
Changed |= hackLdInt16To32(I);
}
}
return Changed;
}
bool matchStInt32To16(Instruction *I) const {
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
if (II->getIntrinsicID() != Intrinsic::xxxxxxx_st_iuav) {
return false;
}
Instruction *Child0 = dyn_cast<Instruction>(I->getOperand(0));
if (Child0->getOpcode() != Instruction::Trunc) {
return false;
}
if (not Child0->getType()->isIntegerTy()) {
return false;
}
if (Child0->getType()->getIntegerBitWidth() != 16) {
return false;
}
return true;
}
bool hackStInt32To16(Instruction *I) const {
// -----
// %res = i32 xxx
// %value = trunc i32 res to i16
// %offset = mul i32 %_3_, 2
// call void @llvm.xxxxxx.st.iuav.i16(i16 value, i32 offset, i32 desc)
// -----
Function *F = I->getFunction();
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
// Child0 is value
Instruction *Child0 = dyn_cast<Instruction>(I->getOperand(0));
// Child1 is offset
Value *Child1 = I->getOperand(1);
// Child2 is constant
Value *Child2 = I->getOperand(2);
// build offset and mask
IRBuilder<> Builder(I);
ConstantInt *Const2 = Builder.getInt32(2);
ConstantInt *Const8 = Builder.getInt32(8);
Value *Div4 = Builder.CreateLShr(Child1, Const2);
Value *Mul4 = Builder.CreateShl(Div4, Const2);
Value *Mod4 = Builder.CreateSub(Child1, Mul4);
Value *Shift = Builder.CreateMul(Mod4, Const8);
Value *RMask = Builder.CreateLShr(Builder.getInt32(0xffff0000), Shift);
// read with mask
llvm::Function *LD0 = llvm::Intrinsic::getDeclaration(
F->getParent(), llvm::Intrinsic::xxxxxxx_ld_iuav, Builder.getInt32Ty());
Value *Res0 = Builder.CreateCall(LD0, {Mul4, Child2});
Res0 = Builder.CreateAnd(Res0, RMask);
// write
llvm::Function *ST0 = llvm::Intrinsic::getDeclaration(
F->getParent(), II->getIntrinsicID(), Builder.getInt32Ty());
Value *Val0 = Builder.CreateShl(Child0->getOperand(0), Shift);
Builder.CreateCall(ST0, {Builder.CreateOr(Res0, Val0), Mul4, Child2});
// erase
I->eraseFromParent();
return true;
}