mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
Change CastToCStr to take a pointer instead of a reference.
Fix some miscompilations in fprintf optimizer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35753 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
31102896e5
commit
3492cda48f
@ -393,7 +393,7 @@ namespace {
|
|||||||
// Forward declare utility functions.
|
// Forward declare utility functions.
|
||||||
static bool GetConstantStringInfo(Value *V, ConstantArray *&Array,
|
static bool GetConstantStringInfo(Value *V, ConstantArray *&Array,
|
||||||
uint64_t &Length, uint64_t &StartIdx);
|
uint64_t &Length, uint64_t &StartIdx);
|
||||||
static Value *CastToCStr(Value *V, Instruction &IP);
|
static Value *CastToCStr(Value *V, Instruction *IP);
|
||||||
|
|
||||||
/// This LibCallOptimization will find instances of a call to "exit" that occurs
|
/// This LibCallOptimization will find instances of a call to "exit" that occurs
|
||||||
/// within the "main" function and change it to a simple "ret" instruction with
|
/// within the "main" function and change it to a simple "ret" instruction with
|
||||||
@ -1228,7 +1228,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// printf("%s\n",str) -> puts(str)
|
// printf("%s\n",str) -> puts(str)
|
||||||
new CallInst(SLC.get_puts(), CastToCStr(CI->getOperand(2), *CI),
|
new CallInst(SLC.get_puts(), CastToCStr(CI->getOperand(2), CI),
|
||||||
CI->getName(), CI);
|
CI->getName(), CI);
|
||||||
return ReplaceCallWith(CI, 0);
|
return ReplaceCallWith(CI, 0);
|
||||||
}
|
}
|
||||||
@ -1262,104 +1262,98 @@ public:
|
|||||||
"Number of 'fprintf' calls simplified") {}
|
"Number of 'fprintf' calls simplified") {}
|
||||||
|
|
||||||
/// @brief Make sure that the "fprintf" function has the right prototype
|
/// @brief Make sure that the "fprintf" function has the right prototype
|
||||||
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
||||||
// Just make sure this has at least 2 arguments
|
const FunctionType *FT = F->getFunctionType();
|
||||||
return (f->arg_size() >= 2);
|
return FT->getNumParams() == 2 && // two fixed arguments.
|
||||||
|
FT->getParamType(1) == PointerType::get(Type::Int8Ty) &&
|
||||||
|
isa<PointerType>(FT->getParamType(0)) &&
|
||||||
|
isa<IntegerType>(FT->getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Perform the fprintf optimization.
|
/// @brief Perform the fprintf optimization.
|
||||||
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
||||||
// If the call has more than 3 operands, we can't optimize it
|
// If the call has more than 3 operands, we can't optimize it
|
||||||
if (ci->getNumOperands() > 4 || ci->getNumOperands() <= 2)
|
if (CI->getNumOperands() != 3 && CI->getNumOperands() != 4)
|
||||||
return false;
|
|
||||||
|
|
||||||
// If the result of the fprintf call is used, none of these optimizations
|
|
||||||
// can be made.
|
|
||||||
if (!ci->use_empty())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// All the optimizations depend on the length of the second argument and the
|
// All the optimizations depend on the length of the second argument and the
|
||||||
// fact that it is a constant string array. Check that now
|
// fact that it is a constant string array. Check that now
|
||||||
uint64_t len, StartIdx;
|
uint64_t FormatLen, FormatStartIdx;
|
||||||
ConstantArray* CA = 0;
|
ConstantArray *CA = 0;
|
||||||
if (!GetConstantStringInfo(ci->getOperand(2), CA, len, StartIdx))
|
if (!GetConstantStringInfo(CI->getOperand(2), CA, FormatLen,FormatStartIdx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ci->getNumOperands() == 3) {
|
// IF fthis is just a format string, turn it into fwrite.
|
||||||
|
if (CI->getNumOperands() == 3) {
|
||||||
|
if (!CA->isCString()) return false;
|
||||||
|
|
||||||
// Make sure there's no % in the constant array
|
// Make sure there's no % in the constant array
|
||||||
for (unsigned i = 0; i < len; ++i) {
|
std::string S = CA->getAsString();
|
||||||
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(i))) {
|
|
||||||
// Check for the null terminator
|
for (unsigned i = FormatStartIdx, e = S.size(); i != e; ++i)
|
||||||
if (CI->getZExtValue() == '%')
|
if (S[i] == '%')
|
||||||
return false; // we found end of string
|
return false; // we found a format specifier
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fprintf(file,fmt) -> fwrite(fmt,strlen(fmt),file)
|
// fprintf(file,fmt) -> fwrite(fmt,strlen(fmt),file)
|
||||||
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
const Type *FILEty = CI->getOperand(1)->getType();
|
||||||
|
|
||||||
// Make sure that the fprintf() and fwrite() functions both take the
|
Value *FWriteArgs[] = {
|
||||||
// same type of char pointer.
|
CI->getOperand(2),
|
||||||
if (ci->getOperand(2)->getType() != PointerType::get(Type::Int8Ty))
|
ConstantInt::get(SLC.getIntPtrType(), FormatLen),
|
||||||
return false;
|
ConstantInt::get(SLC.getIntPtrType(), 1),
|
||||||
|
CI->getOperand(1)
|
||||||
Value* args[4] = {
|
|
||||||
ci->getOperand(2),
|
|
||||||
ConstantInt::get(SLC.getIntPtrType(),len),
|
|
||||||
ConstantInt::get(SLC.getIntPtrType(),1),
|
|
||||||
ci->getOperand(1)
|
|
||||||
};
|
};
|
||||||
new CallInst(SLC.get_fwrite(FILEptr_type), args, 4, ci->getName(), ci);
|
new CallInst(SLC.get_fwrite(FILEty), FWriteArgs, 4, CI->getName(), CI);
|
||||||
return ReplaceCallWith(ci, ConstantInt::get(Type::Int32Ty,len));
|
return ReplaceCallWith(CI, ConstantInt::get(CI->getType(), FormatLen));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The remaining optimizations require the format string to be length 2
|
// The remaining optimizations require the format string to be length 2:
|
||||||
// "%s" or "%c".
|
// "%s" or "%c".
|
||||||
if (len != 2)
|
if (FormatLen != 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The first character has to be a %
|
// The first character has to be a % for us to handle it.
|
||||||
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(0)))
|
if (cast<ConstantInt>(CA->getOperand(FormatStartIdx))->getZExtValue() !='%')
|
||||||
if (CI->getZExtValue() != '%')
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Get the second character and switch on its value
|
// Get the second character and switch on its value
|
||||||
ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(1));
|
switch(cast<ConstantInt>(CA->getOperand(FormatStartIdx+1))->getZExtValue()){
|
||||||
switch (CI->getZExtValue()) {
|
case 'c': {
|
||||||
case 's': {
|
// fprintf(file,"%c",c) -> fputc(c,file)
|
||||||
uint64_t len, StartIdx;
|
const Type *FILETy = CI->getOperand(1)->getType();
|
||||||
ConstantArray* CA = 0;
|
Value *C = CastInst::createZExtOrBitCast(CI->getOperand(3), Type::Int32Ty,
|
||||||
if (GetConstantStringInfo(ci->getOperand(3), CA, len, StartIdx)) {
|
CI->getName()+".int", CI);
|
||||||
// fprintf(file,"%s",str) -> fwrite(str,strlen(str),1,file)
|
new CallInst(SLC.get_fputc(FILETy), C, CI->getOperand(1), "", CI);
|
||||||
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
return ReplaceCallWith(CI, ConstantInt::get(CI->getType(), 1));
|
||||||
Value* args[4] = {
|
}
|
||||||
CastToCStr(ci->getOperand(3), *ci),
|
case 's': {
|
||||||
ConstantInt::get(SLC.getIntPtrType(), len),
|
const Type *FILETy = CI->getOperand(1)->getType();
|
||||||
ConstantInt::get(SLC.getIntPtrType(), 1),
|
uint64_t LitStrLen, LitStartIdx;
|
||||||
ci->getOperand(1)
|
ConstantArray *CA = 0;
|
||||||
};
|
if (GetConstantStringInfo(CI->getOperand(3), CA, LitStrLen, LitStartIdx)){
|
||||||
new CallInst(SLC.get_fwrite(FILEptr_type), args, 4,ci->getName(), ci);
|
// fprintf(file,"%s",str) -> fwrite(str,strlen(str),1,file)
|
||||||
return ReplaceCallWith(ci, ConstantInt::get(Type::Int32Ty, len));
|
Value *FWriteArgs[] = {
|
||||||
}
|
CastToCStr(CI->getOperand(3), CI),
|
||||||
// fprintf(file,"%s",str) -> fputs(str,file)
|
ConstantInt::get(SLC.getIntPtrType(), LitStrLen),
|
||||||
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
ConstantInt::get(SLC.getIntPtrType(), 1),
|
||||||
new CallInst(SLC.get_fputs(FILEptr_type),
|
CI->getOperand(1)
|
||||||
CastToCStr(ci->getOperand(3), *ci),
|
};
|
||||||
ci->getOperand(1), ci->getName(),ci);
|
new CallInst(SLC.get_fwrite(FILETy), FWriteArgs, 4, CI->getName(), CI);
|
||||||
return ReplaceCallWith(ci, ConstantInt::get(Type::Int32Ty,len));
|
return ReplaceCallWith(CI, ConstantInt::get(Type::Int32Ty, LitStrLen));
|
||||||
}
|
}
|
||||||
case 'c': {
|
|
||||||
// fprintf(file,"%c",c) -> fputc(c,file)
|
// If the result of the fprintf call is used, we can't do this.
|
||||||
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
// TODO: we could insert a strlen call.
|
||||||
CastInst* cast = CastInst::createSExtOrBitCast(
|
if (!CI->use_empty())
|
||||||
ci->getOperand(3), Type::Int32Ty, CI->getName()+".int", ci);
|
|
||||||
new CallInst(SLC.get_fputc(FILEptr_type), cast,ci->getOperand(1),"",ci);
|
|
||||||
return ReplaceCallWith(ci, ConstantInt::get(Type::Int32Ty,1));
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// fprintf(file,"%s",str) -> fputs(str,file)
|
||||||
|
new CallInst(SLC.get_fputs(FILETy), CastToCStr(CI->getOperand(3), CI),
|
||||||
|
CI->getOperand(1), CI->getName(), CI);
|
||||||
|
return ReplaceCallWith(CI, 0);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} FPrintFOptimizer;
|
} FPrintFOptimizer;
|
||||||
@ -1441,7 +1435,7 @@ public:
|
|||||||
case 's': {
|
case 's': {
|
||||||
// sprintf(dest,"%s",str) -> llvm.memcpy(dest, str, strlen(str)+1, 1)
|
// sprintf(dest,"%s",str) -> llvm.memcpy(dest, str, strlen(str)+1, 1)
|
||||||
Value *Len = new CallInst(SLC.get_strlen(),
|
Value *Len = new CallInst(SLC.get_strlen(),
|
||||||
CastToCStr(ci->getOperand(3), *ci),
|
CastToCStr(ci->getOperand(3), ci),
|
||||||
ci->getOperand(3)->getName()+".len", ci);
|
ci->getOperand(3)->getName()+".len", ci);
|
||||||
Value *Len1 = BinaryOperator::createAdd(Len,
|
Value *Len1 = BinaryOperator::createAdd(Len,
|
||||||
ConstantInt::get(Len->getType(), 1),
|
ConstantInt::get(Len->getType(), 1),
|
||||||
@ -1450,8 +1444,8 @@ public:
|
|||||||
Len1 = CastInst::createIntegerCast(Len1, SLC.getIntPtrType(), false,
|
Len1 = CastInst::createIntegerCast(Len1, SLC.getIntPtrType(), false,
|
||||||
Len1->getName(), ci);
|
Len1->getName(), ci);
|
||||||
Value *args[4] = {
|
Value *args[4] = {
|
||||||
CastToCStr(ci->getOperand(1), *ci),
|
CastToCStr(ci->getOperand(1), ci),
|
||||||
CastToCStr(ci->getOperand(3), *ci),
|
CastToCStr(ci->getOperand(3), ci),
|
||||||
Len1,
|
Len1,
|
||||||
ConstantInt::get(Type::Int32Ty,1)
|
ConstantInt::get(Type::Int32Ty,1)
|
||||||
};
|
};
|
||||||
@ -1946,12 +1940,12 @@ static bool GetConstantStringInfo(Value *V, ConstantArray *&Array,
|
|||||||
/// CastToCStr - Return V if it is an sbyte*, otherwise cast it to sbyte*,
|
/// CastToCStr - Return V if it is an sbyte*, otherwise cast it to sbyte*,
|
||||||
/// inserting the cast before IP, and return the cast.
|
/// inserting the cast before IP, and return the cast.
|
||||||
/// @brief Cast a value to a "C" string.
|
/// @brief Cast a value to a "C" string.
|
||||||
static Value *CastToCStr(Value *V, Instruction &IP) {
|
static Value *CastToCStr(Value *V, Instruction *IP) {
|
||||||
assert(isa<PointerType>(V->getType()) &&
|
assert(isa<PointerType>(V->getType()) &&
|
||||||
"Can't cast non-pointer type to C string type");
|
"Can't cast non-pointer type to C string type");
|
||||||
const Type *SBPTy = PointerType::get(Type::Int8Ty);
|
const Type *SBPTy = PointerType::get(Type::Int8Ty);
|
||||||
if (V->getType() != SBPTy)
|
if (V->getType() != SBPTy)
|
||||||
return new BitCastInst(V, SBPTy, V->getName(), &IP);
|
return new BitCastInst(V, SBPTy, V->getName(), IP);
|
||||||
return V;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user