mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-26 23:24:34 +00:00
Add support for custom names for library functions in TargetLibraryInfo. Add a custom name for fwrite and fputs on x86-32 OSX. Make SimplifyLibCalls honor the custom
names for fwrite and fputs. Fixes <rdar://problem/9815881>. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@144876 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -11,6 +11,7 @@
|
|||||||
#define LLVM_TARGET_TARGETLIBRARYINFO_H
|
#define LLVM_TARGET_TARGETLIBRARYINFO_H
|
||||||
|
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class Triple;
|
class Triple;
|
||||||
@ -37,7 +38,14 @@ namespace llvm {
|
|||||||
|
|
||||||
/// int fiprintf(FILE *stream, const char *format, ...);
|
/// int fiprintf(FILE *stream, const char *format, ...);
|
||||||
fiprintf,
|
fiprintf,
|
||||||
|
|
||||||
|
// size_t fwrite(const void *ptr, size_t size, size_t nitems,
|
||||||
|
// FILE *stream);
|
||||||
|
fwrite,
|
||||||
|
|
||||||
|
// int fputs(const char *s, FILE *stream);
|
||||||
|
fputs,
|
||||||
|
|
||||||
NumLibFuncs
|
NumLibFuncs
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -46,7 +54,23 @@ namespace llvm {
|
|||||||
/// library functions are available for the current target, and allows a
|
/// library functions are available for the current target, and allows a
|
||||||
/// frontend to disable optimizations through -fno-builtin etc.
|
/// frontend to disable optimizations through -fno-builtin etc.
|
||||||
class TargetLibraryInfo : public ImmutablePass {
|
class TargetLibraryInfo : public ImmutablePass {
|
||||||
unsigned char AvailableArray[(LibFunc::NumLibFuncs+7)/8];
|
unsigned char AvailableArray[(LibFunc::NumLibFuncs+3)/4];
|
||||||
|
llvm::DenseMap<unsigned, std::string> CustomNames;
|
||||||
|
static const char* StandardNames[LibFunc::NumLibFuncs];
|
||||||
|
|
||||||
|
enum AvailabilityState {
|
||||||
|
StandardName = 3, // (memset to all ones)
|
||||||
|
CustomName = 1,
|
||||||
|
Unavailable = 0 // (memset to all zeros)
|
||||||
|
};
|
||||||
|
void setState(LibFunc::Func F, AvailabilityState State) {
|
||||||
|
AvailableArray[F/4] &= ~(3 << 2*(F&3));
|
||||||
|
AvailableArray[F/4] |= State << 2*(F&3);
|
||||||
|
}
|
||||||
|
AvailabilityState getState(LibFunc::Func F) const {
|
||||||
|
return static_cast<AvailabilityState>((AvailableArray[F/4] >> 2*(F&3)) & 3);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
TargetLibraryInfo();
|
TargetLibraryInfo();
|
||||||
@ -56,19 +80,39 @@ public:
|
|||||||
/// has - This function is used by optimizations that want to match on or form
|
/// has - This function is used by optimizations that want to match on or form
|
||||||
/// a given library function.
|
/// a given library function.
|
||||||
bool has(LibFunc::Func F) const {
|
bool has(LibFunc::Func F) const {
|
||||||
return (AvailableArray[F/8] & (1 << (F&7))) != 0;
|
return getState(F) != Unavailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef getName(LibFunc::Func F) const {
|
||||||
|
AvailabilityState State = getState(F);
|
||||||
|
if (State == Unavailable)
|
||||||
|
return StringRef();
|
||||||
|
if (State == StandardName)
|
||||||
|
return StandardNames[F];
|
||||||
|
assert(State == CustomName);
|
||||||
|
return CustomNames.find(F)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// setUnavailable - this can be used by whatever sets up TargetLibraryInfo to
|
/// setUnavailable - this can be used by whatever sets up TargetLibraryInfo to
|
||||||
/// ban use of specific library functions.
|
/// ban use of specific library functions.
|
||||||
void setUnavailable(LibFunc::Func F) {
|
void setUnavailable(LibFunc::Func F) {
|
||||||
AvailableArray[F/8] &= ~(1 << (F&7));
|
setState(F, Unavailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAvailable(LibFunc::Func F) {
|
void setAvailable(LibFunc::Func F) {
|
||||||
AvailableArray[F/8] |= 1 << (F&7);
|
setState(F, StandardName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAvailableWithName(LibFunc::Func F, StringRef Name) {
|
||||||
|
if (StandardNames[F] != Name) {
|
||||||
|
setState(F, CustomName);
|
||||||
|
CustomNames[F] = Name;
|
||||||
|
assert(CustomNames.find(F) != CustomNames.end());
|
||||||
|
} else {
|
||||||
|
setState(F, StandardName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// disableAllFunctions - This disables all builtins, which is used for
|
/// disableAllFunctions - This disables all builtins, which is used for
|
||||||
/// options like -fno-builtin.
|
/// options like -fno-builtin.
|
||||||
void disableAllFunctions();
|
void disableAllFunctions();
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
class Value;
|
class Value;
|
||||||
class TargetData;
|
class TargetData;
|
||||||
|
class TargetLibraryInfo;
|
||||||
|
|
||||||
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
|
||||||
Value *CastToCStr(Value *V, IRBuilder<> &B);
|
Value *CastToCStr(Value *V, IRBuilder<> &B);
|
||||||
@ -86,12 +87,13 @@ namespace llvm {
|
|||||||
|
|
||||||
/// EmitFPutS - Emit a call to the puts function. Str is required to be a
|
/// EmitFPutS - Emit a call to the puts function. Str is required to be a
|
||||||
/// pointer and File is a pointer to FILE.
|
/// pointer and File is a pointer to FILE.
|
||||||
void EmitFPutS(Value *Str, Value *File, IRBuilder<> &B, const TargetData *TD);
|
void EmitFPutS(Value *Str, Value *File, IRBuilder<> &B, const TargetData *TD,
|
||||||
|
const TargetLibraryInfo *TLI);
|
||||||
|
|
||||||
/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
|
/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
|
||||||
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
||||||
void EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B,
|
void EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B,
|
||||||
const TargetData *TD);
|
const TargetData *TD, const TargetLibraryInfo *TLI);
|
||||||
|
|
||||||
/// SimplifyFortifiedLibCalls - Helper class for folding checked library
|
/// SimplifyFortifiedLibCalls - Helper class for folding checked library
|
||||||
/// calls (e.g. __strcpy_chk) into their unchecked counterparts.
|
/// calls (e.g. __strcpy_chk) into their unchecked counterparts.
|
||||||
|
@ -20,6 +20,19 @@ INITIALIZE_PASS(TargetLibraryInfo, "targetlibinfo",
|
|||||||
"Target Library Information", false, true)
|
"Target Library Information", false, true)
|
||||||
char TargetLibraryInfo::ID = 0;
|
char TargetLibraryInfo::ID = 0;
|
||||||
|
|
||||||
|
const char* TargetLibraryInfo::StandardNames[LibFunc::NumLibFuncs] =
|
||||||
|
{
|
||||||
|
"memset",
|
||||||
|
"memcpy",
|
||||||
|
"memmove",
|
||||||
|
"memset_pattern16",
|
||||||
|
"iprintf",
|
||||||
|
"siprintf",
|
||||||
|
"fiprintf",
|
||||||
|
"fwrite",
|
||||||
|
"fputs"
|
||||||
|
};
|
||||||
|
|
||||||
/// initialize - Initialize the set of available library functions based on the
|
/// initialize - Initialize the set of available library functions based on the
|
||||||
/// specified target triple. This should be carefully written so that a missing
|
/// specified target triple. This should be carefully written so that a missing
|
||||||
/// target triple gets a sane set of defaults.
|
/// target triple gets a sane set of defaults.
|
||||||
@ -38,6 +51,17 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T) {
|
|||||||
TLI.setUnavailable(LibFunc::memset_pattern16);
|
TLI.setUnavailable(LibFunc::memset_pattern16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (T.isMacOSX() && T.getArch() == Triple::x86 &&
|
||||||
|
!T.isMacOSXVersionLT(10, 7)) {
|
||||||
|
// x86-32 OSX has a scheme where fwrite and fputs (and some other functions
|
||||||
|
// we don't care about) have two versions; on recent OSX, the one we want
|
||||||
|
// has a $UNIX2003 suffix. The two implementations are identical except
|
||||||
|
// for the return value in some edge cases. However, we don't want to
|
||||||
|
// generate code that depends on the old symbols.
|
||||||
|
TLI.setAvailableWithName(LibFunc::fwrite, "fwrite$UNIX2003");
|
||||||
|
TLI.setAvailableWithName(LibFunc::fputs, "fputs$UNIX2003");
|
||||||
|
}
|
||||||
|
|
||||||
// iprintf and friends are only available on XCore and TCE.
|
// iprintf and friends are only available on XCore and TCE.
|
||||||
if (T.getArch() != Triple::xcore && T.getArch() != Triple::tce) {
|
if (T.getArch() != Triple::xcore && T.getArch() != Triple::tce) {
|
||||||
TLI.setUnavailable(LibFunc::iprintf);
|
TLI.setUnavailable(LibFunc::iprintf);
|
||||||
@ -64,6 +88,7 @@ TargetLibraryInfo::TargetLibraryInfo(const Triple &T) : ImmutablePass(ID) {
|
|||||||
TargetLibraryInfo::TargetLibraryInfo(const TargetLibraryInfo &TLI)
|
TargetLibraryInfo::TargetLibraryInfo(const TargetLibraryInfo &TLI)
|
||||||
: ImmutablePass(ID) {
|
: ImmutablePass(ID) {
|
||||||
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
|
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
|
||||||
|
CustomNames = TLI.CustomNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1323,7 +1323,7 @@ struct FPutsOpt : public LibCallOptimization {
|
|||||||
if (!Len) return 0;
|
if (!Len) return 0;
|
||||||
EmitFWrite(CI->getArgOperand(0),
|
EmitFWrite(CI->getArgOperand(0),
|
||||||
ConstantInt::get(TD->getIntPtrType(*Context), Len-1),
|
ConstantInt::get(TD->getIntPtrType(*Context), Len-1),
|
||||||
CI->getArgOperand(1), B, TD);
|
CI->getArgOperand(1), B, TD, TLI);
|
||||||
return CI; // Known to have no uses (see above).
|
return CI; // Known to have no uses (see above).
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1351,7 +1351,7 @@ struct FPrintFOpt : public LibCallOptimization {
|
|||||||
EmitFWrite(CI->getArgOperand(1),
|
EmitFWrite(CI->getArgOperand(1),
|
||||||
ConstantInt::get(TD->getIntPtrType(*Context),
|
ConstantInt::get(TD->getIntPtrType(*Context),
|
||||||
FormatStr.size()),
|
FormatStr.size()),
|
||||||
CI->getArgOperand(0), B, TD);
|
CI->getArgOperand(0), B, TD, TLI);
|
||||||
return ConstantInt::get(CI->getType(), FormatStr.size());
|
return ConstantInt::get(CI->getType(), FormatStr.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1373,7 +1373,7 @@ struct FPrintFOpt : public LibCallOptimization {
|
|||||||
// fprintf(F, "%s", str) --> fputs(str, F)
|
// fprintf(F, "%s", str) --> fputs(str, F)
|
||||||
if (!CI->getArgOperand(2)->getType()->isPointerTy() || !CI->use_empty())
|
if (!CI->getArgOperand(2)->getType()->isPointerTy() || !CI->use_empty())
|
||||||
return 0;
|
return 0;
|
||||||
EmitFPutS(CI->getArgOperand(2), CI->getArgOperand(0), B, TD);
|
EmitFPutS(CI->getArgOperand(2), CI->getArgOperand(0), B, TD, TLI);
|
||||||
return CI;
|
return CI;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1469,6 +1469,7 @@ namespace {
|
|||||||
SimplifyLibCalls() : FunctionPass(ID), StrCpy(false), StrCpyChk(true) {
|
SimplifyLibCalls() : FunctionPass(ID), StrCpy(false), StrCpyChk(true) {
|
||||||
initializeSimplifyLibCallsPass(*PassRegistry::getPassRegistry());
|
initializeSimplifyLibCallsPass(*PassRegistry::getPassRegistry());
|
||||||
}
|
}
|
||||||
|
void AddOpt(LibFunc::Func F, LibCallOptimization* Opt);
|
||||||
void InitOptimizations();
|
void InitOptimizations();
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F);
|
||||||
|
|
||||||
@ -1499,6 +1500,11 @@ FunctionPass *llvm::createSimplifyLibCallsPass() {
|
|||||||
return new SimplifyLibCalls();
|
return new SimplifyLibCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimplifyLibCalls::AddOpt(LibFunc::Func F, LibCallOptimization* Opt) {
|
||||||
|
if (TLI->has(F))
|
||||||
|
Optimizations[TLI->getName(F)] = Opt;
|
||||||
|
}
|
||||||
|
|
||||||
/// Optimizations - Populate the Optimizations map with all the optimizations
|
/// Optimizations - Populate the Optimizations map with all the optimizations
|
||||||
/// we know.
|
/// we know.
|
||||||
void SimplifyLibCalls::InitOptimizations() {
|
void SimplifyLibCalls::InitOptimizations() {
|
||||||
@ -1524,9 +1530,9 @@ void SimplifyLibCalls::InitOptimizations() {
|
|||||||
Optimizations["strcspn"] = &StrCSpn;
|
Optimizations["strcspn"] = &StrCSpn;
|
||||||
Optimizations["strstr"] = &StrStr;
|
Optimizations["strstr"] = &StrStr;
|
||||||
Optimizations["memcmp"] = &MemCmp;
|
Optimizations["memcmp"] = &MemCmp;
|
||||||
if (TLI->has(LibFunc::memcpy)) Optimizations["memcpy"] = &MemCpy;
|
AddOpt(LibFunc::memcpy, &MemCpy);
|
||||||
Optimizations["memmove"] = &MemMove;
|
Optimizations["memmove"] = &MemMove;
|
||||||
if (TLI->has(LibFunc::memset)) Optimizations["memset"] = &MemSet;
|
AddOpt(LibFunc::memset, &MemSet);
|
||||||
|
|
||||||
// _chk variants of String and Memory LibCall Optimizations.
|
// _chk variants of String and Memory LibCall Optimizations.
|
||||||
Optimizations["__strcpy_chk"] = &StrCpyChk;
|
Optimizations["__strcpy_chk"] = &StrCpyChk;
|
||||||
@ -1579,8 +1585,8 @@ void SimplifyLibCalls::InitOptimizations() {
|
|||||||
// Formatting and IO Optimizations
|
// Formatting and IO Optimizations
|
||||||
Optimizations["sprintf"] = &SPrintF;
|
Optimizations["sprintf"] = &SPrintF;
|
||||||
Optimizations["printf"] = &PrintF;
|
Optimizations["printf"] = &PrintF;
|
||||||
Optimizations["fwrite"] = &FWrite;
|
AddOpt(LibFunc::fwrite, &FWrite);
|
||||||
Optimizations["fputs"] = &FPuts;
|
AddOpt(LibFunc::fputs, &FPuts);
|
||||||
Optimizations["fprintf"] = &FPrintF;
|
Optimizations["fprintf"] = &FPrintF;
|
||||||
Optimizations["puts"] = &Puts;
|
Optimizations["puts"] = &Puts;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#include "llvm/Module.h"
|
#include "llvm/Module.h"
|
||||||
#include "llvm/Support/IRBuilder.h"
|
#include "llvm/Support/IRBuilder.h"
|
||||||
#include "llvm/Target/TargetData.h"
|
#include "llvm/Target/TargetData.h"
|
||||||
|
#include "llvm/Target/TargetLibraryInfo.h"
|
||||||
|
#include "llvm/LLVMContext.h"
|
||||||
|
#include "llvm/Intrinsics.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
@ -297,20 +300,21 @@ void llvm::EmitFPutC(Value *Char, Value *File, IRBuilder<> &B,
|
|||||||
/// EmitFPutS - Emit a call to the puts function. Str is required to be a
|
/// EmitFPutS - Emit a call to the puts function. Str is required to be a
|
||||||
/// pointer and File is a pointer to FILE.
|
/// pointer and File is a pointer to FILE.
|
||||||
void llvm::EmitFPutS(Value *Str, Value *File, IRBuilder<> &B,
|
void llvm::EmitFPutS(Value *Str, Value *File, IRBuilder<> &B,
|
||||||
const TargetData *TD) {
|
const TargetData *TD, const TargetLibraryInfo *TLI) {
|
||||||
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
||||||
AttributeWithIndex AWI[3];
|
AttributeWithIndex AWI[3];
|
||||||
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
||||||
AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture);
|
AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture);
|
||||||
AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
||||||
|
StringRef FPutsName = TLI->getName(LibFunc::fputs);
|
||||||
Constant *F;
|
Constant *F;
|
||||||
if (File->getType()->isPointerTy())
|
if (File->getType()->isPointerTy())
|
||||||
F = M->getOrInsertFunction("fputs", AttrListPtr::get(AWI, 3),
|
F = M->getOrInsertFunction(FPutsName, AttrListPtr::get(AWI, 3),
|
||||||
B.getInt32Ty(),
|
B.getInt32Ty(),
|
||||||
B.getInt8PtrTy(),
|
B.getInt8PtrTy(),
|
||||||
File->getType(), NULL);
|
File->getType(), NULL);
|
||||||
else
|
else
|
||||||
F = M->getOrInsertFunction("fputs", B.getInt32Ty(),
|
F = M->getOrInsertFunction(FPutsName, B.getInt32Ty(),
|
||||||
B.getInt8PtrTy(),
|
B.getInt8PtrTy(),
|
||||||
File->getType(), NULL);
|
File->getType(), NULL);
|
||||||
CallInst *CI = B.CreateCall2(F, CastToCStr(Str, B), File, "fputs");
|
CallInst *CI = B.CreateCall2(F, CastToCStr(Str, B), File, "fputs");
|
||||||
@ -322,23 +326,25 @@ void llvm::EmitFPutS(Value *Str, Value *File, IRBuilder<> &B,
|
|||||||
/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
|
/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
|
||||||
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
|
||||||
void llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File,
|
void llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File,
|
||||||
IRBuilder<> &B, const TargetData *TD) {
|
IRBuilder<> &B, const TargetData *TD,
|
||||||
|
const TargetLibraryInfo *TLI) {
|
||||||
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
||||||
AttributeWithIndex AWI[3];
|
AttributeWithIndex AWI[3];
|
||||||
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
|
||||||
AWI[1] = AttributeWithIndex::get(4, Attribute::NoCapture);
|
AWI[1] = AttributeWithIndex::get(4, Attribute::NoCapture);
|
||||||
AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
|
||||||
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
||||||
|
StringRef FWriteName = TLI->getName(LibFunc::fwrite);
|
||||||
Constant *F;
|
Constant *F;
|
||||||
if (File->getType()->isPointerTy())
|
if (File->getType()->isPointerTy())
|
||||||
F = M->getOrInsertFunction("fwrite", AttrListPtr::get(AWI, 3),
|
F = M->getOrInsertFunction(FWriteName, AttrListPtr::get(AWI, 3),
|
||||||
TD->getIntPtrType(Context),
|
TD->getIntPtrType(Context),
|
||||||
B.getInt8PtrTy(),
|
B.getInt8PtrTy(),
|
||||||
TD->getIntPtrType(Context),
|
TD->getIntPtrType(Context),
|
||||||
TD->getIntPtrType(Context),
|
TD->getIntPtrType(Context),
|
||||||
File->getType(), NULL);
|
File->getType(), NULL);
|
||||||
else
|
else
|
||||||
F = M->getOrInsertFunction("fwrite", TD->getIntPtrType(Context),
|
F = M->getOrInsertFunction(FWriteName, TD->getIntPtrType(Context),
|
||||||
B.getInt8PtrTy(),
|
B.getInt8PtrTy(),
|
||||||
TD->getIntPtrType(Context),
|
TD->getIntPtrType(Context),
|
||||||
TD->getIntPtrType(Context),
|
TD->getIntPtrType(Context),
|
||||||
|
30
test/Transforms/SimplifyLibCalls/osx-names.ll
Normal file
30
test/Transforms/SimplifyLibCalls/osx-names.ll
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
|
||||||
|
; <rdar://problem/9815881>
|
||||||
|
; On OSX x86-32, fwrite and fputs aren't called fwrite and fputs.
|
||||||
|
; Make sure we use the correct names.
|
||||||
|
|
||||||
|
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128"
|
||||||
|
target triple = "i386-apple-macosx10.7.2"
|
||||||
|
|
||||||
|
%struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 }
|
||||||
|
%struct.__sbuf = type { i8*, i32 }
|
||||||
|
%struct.__sFILEX = type opaque
|
||||||
|
|
||||||
|
@.str = private unnamed_addr constant [13 x i8] c"Hello world\0A\00", align 1
|
||||||
|
@.str2 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
|
||||||
|
|
||||||
|
define void @test1(%struct.__sFILE* %stream) nounwind {
|
||||||
|
; CHECK: define void @test1
|
||||||
|
; CHECK: call i32 @"fwrite$UNIX2003"
|
||||||
|
%call = tail call i32 (%struct.__sFILE*, i8*, ...)* @fprintf(%struct.__sFILE* %stream, i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0)) nounwind
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @test2(%struct.__sFILE* %stream, i8* %str) nounwind ssp {
|
||||||
|
; CHECK: define void @test2
|
||||||
|
; CHECK: call i32 @"fputs$UNIX2003"
|
||||||
|
%call = tail call i32 (%struct.__sFILE*, i8*, ...)* @fprintf(%struct.__sFILE* %stream, i8* getelementptr inbounds ([3 x i8]* @.str2, i32 0, i32 0), i8* %str) nounwind
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @fprintf(%struct.__sFILE*, i8*, ...) nounwind
|
Reference in New Issue
Block a user