#include "llvm/SymbolTable.h"
#include "llvm/Intrinsics.h"
#include "llvm/IntrinsicInst.h"
+#include "llvm/InlineAsm.h"
#include "llvm/Analysis/ConstantsScanner.h"
#include "llvm/Analysis/FindUsedTypes.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Target/TargetMachineRegistry.h"
+#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
/// module to a C translation unit.
class CWriter : public FunctionPass, public InstVisitor<CWriter> {
std::ostream &Out;
- DefaultIntrinsicLowering IL;
+ IntrinsicLowering IL;
Mangler *Mang;
LoopInfo *LI;
const Module *TheModule;
+ const TargetAsmInfo* TAsm;
std::map<const Type *, std::string> TypeNames;
std::map<const ConstantFP *, unsigned> FPConstantMap;
public:
- CWriter(std::ostream &o) : Out(o) {}
+ CWriter(std::ostream &o) : Out(o), TAsm(0) {}
virtual const char *getPassName() const { return "C backend"; }
const PointerType *Ty);
void writeOperand(Value *Operand);
+ void writeOperandRaw(Value *Operand);
void writeOperandInternal(Value *Operand);
+ void writeOperandWithCast(Value* Operand, unsigned Opcode);
+ bool writeInstructionCast(const Instruction &I);
private :
+ std::string InterpretASMConstraint(InlineAsm::ConstraintInfo& c);
+
void lowerIntrinsics(Function &F);
void printModule(Module *M);
void printBasicBlock(BasicBlock *BB);
void printLoop(Loop *L);
+ void printCast(unsigned opcode, const Type *SrcTy, const Type *DstTy);
void printConstant(Constant *CPV);
+ void printConstantWithCast(Constant *CPV, unsigned Opcode);
+ bool printConstExprCast(const ConstantExpr *CE);
void printConstantArray(ConstantArray *CPA);
void printConstantPacked(ConstantPacked *CP);
// Don't inline a load across a store or other bad things!
return false;
+ // Must not be used in inline asm
+ if (I.hasOneUse() && isInlineAsm(*I.use_back())) return false;
+
// Only inline instruction it it's use is in the same BB as the inst.
return I.getParent() == cast<Instruction>(I.use_back())->getParent();
}
return 0;
return AI;
}
-
+
+ // isInlineAsm - Check if the instruction is a call to an inline asm chunk
+ static bool isInlineAsm(const Instruction& I) {
+ if (isa<CallInst>(&I) && isa<InlineAsm>(I.getOperand(0)))
+ return true;
+ return false;
+ }
+
// Instruction visitation functions
friend class InstVisitor<CWriter>;
void visitCastInst (CastInst &I);
void visitSelectInst(SelectInst &I);
void visitCallInst (CallInst &I);
+ void visitInlineAsm(CallInst &I);
void visitShiftInst(ShiftInst &I) { visitBinaryOperator(I); }
void visitMallocInst(MallocInst &I);
// only deal in IEEE FP).
//
static bool isFPCSafeToPrint(const ConstantFP *CFP) {
-#if HAVE_PRINTF_A
+#if HAVE_PRINTF_A && ENABLE_CBE_PRINTF_A
char Buffer[100];
sprintf(Buffer, "%a", CFP->getValue());
#endif
}
+/// Print out the casting for a cast operation. This does the double casting
+/// necessary for conversion to the destination type, if necessary.
+/// @returns true if a closing paren is necessary
+/// @brief Print a cast
+void CWriter::printCast(unsigned opc, const Type *SrcTy, const Type *DstTy) {
+ Out << '(';
+ printType(Out, DstTy);
+ Out << ')';
+ switch (opc) {
+ case Instruction::UIToFP:
+ case Instruction::ZExt:
+ if (SrcTy->isSigned()) {
+ Out << '(';
+ printType(Out, SrcTy->getUnsignedVersion());
+ Out << ')';
+ }
+ break;
+ case Instruction::SIToFP:
+ case Instruction::SExt:
+ if (SrcTy->isUnsigned()) {
+ Out << '(';
+ printType(Out, SrcTy->getSignedVersion());
+ Out << ')';
+ }
+ break;
+ case Instruction::IntToPtr:
+ case Instruction::PtrToInt:
+ // Avoid "cast to pointer from integer of different size" warnings
+ Out << "(unsigned long)";
+ break;
+ case Instruction::Trunc:
+ case Instruction::BitCast:
+ case Instruction::FPExt:
+ case Instruction::FPTrunc:
+ case Instruction::FPToSI:
+ case Instruction::FPToUI:
+ default:
+ break;
+ }
+}
+
// printConstant - The LLVM Constant to C Constant converter.
void CWriter::printConstant(Constant *CPV) {
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CPV)) {
switch (CE->getOpcode()) {
- case Instruction::Cast:
- Out << "((";
- printType(Out, CPV->getType());
- Out << ')';
+ case Instruction::Trunc:
+ case Instruction::ZExt:
+ case Instruction::SExt:
+ case Instruction::FPTrunc:
+ case Instruction::FPExt:
+ case Instruction::UIToFP:
+ case Instruction::SIToFP:
+ case Instruction::FPToUI:
+ case Instruction::FPToSI:
+ case Instruction::PtrToInt:
+ case Instruction::IntToPtr:
+ case Instruction::BitCast:
+ Out << "(";
+ printCast(CE->getOpcode(), CE->getOperand(0)->getType(), CE->getType());
+ if (CE->getOpcode() == Instruction::SExt &&
+ CE->getOperand(0)->getType() == Type::BoolTy) {
+ // Make sure we really sext from bool here by subtracting from 0
+ Out << "0-";
+ }
printConstant(CE->getOperand(0));
+ if (CE->getType() == Type::BoolTy &&
+ (CE->getOpcode() == Instruction::Trunc ||
+ CE->getOpcode() == Instruction::FPToUI ||
+ CE->getOpcode() == Instruction::FPToSI ||
+ CE->getOpcode() == Instruction::PtrToInt)) {
+ // Make sure we really truncate to bool here by anding with 1
+ Out << "&1u";
+ }
Out << ')';
return;
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
- case Instruction::Div:
- case Instruction::Rem:
+ case Instruction::SDiv:
+ case Instruction::UDiv:
+ case Instruction::FDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ case Instruction::FRem:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
case Instruction::SetGT:
case Instruction::SetGE:
case Instruction::Shl:
- case Instruction::Shr:
+ case Instruction::LShr:
+ case Instruction::AShr:
+ {
Out << '(';
- printConstant(CE->getOperand(0));
+ bool NeedsClosingParens = printConstExprCast(CE);
+ printConstantWithCast(CE->getOperand(0), CE->getOpcode());
switch (CE->getOpcode()) {
case Instruction::Add: Out << " + "; break;
case Instruction::Sub: Out << " - "; break;
case Instruction::Mul: Out << " * "; break;
- case Instruction::Div: Out << " / "; break;
- case Instruction::Rem: Out << " % "; break;
+ case Instruction::URem:
+ case Instruction::SRem:
+ case Instruction::FRem: Out << " % "; break;
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::FDiv: Out << " / "; break;
case Instruction::And: Out << " & "; break;
case Instruction::Or: Out << " | "; break;
case Instruction::Xor: Out << " ^ "; break;
case Instruction::SetGT: Out << " > "; break;
case Instruction::SetGE: Out << " >= "; break;
case Instruction::Shl: Out << " << "; break;
- case Instruction::Shr: Out << " >> "; break;
+ case Instruction::LShr:
+ case Instruction::AShr: Out << " >> "; break;
default: assert(0 && "Illegal opcode here!");
}
- printConstant(CE->getOperand(1));
+ printConstantWithCast(CE->getOperand(1), CE->getOpcode());
+ if (NeedsClosingParens)
+ Out << "))";
Out << ')';
return;
+ }
default:
std::cerr << "CWriter Error: Unhandled constant expression: "
// The prefix for a quiet NaN is 0x7FF8. For a signalling NaN,
// it's 0x7ff4.
const unsigned long QuietNaN = 0x7ff8UL;
- const unsigned long SignalNaN = 0x7ff4UL;
+ //const unsigned long SignalNaN = 0x7ff4UL;
// We need to grab the first part of the FP #
char Buffer[100];
<< " /*inf*/ ";
} else {
std::string Num;
-#if HAVE_PRINTF_A
+#if HAVE_PRINTF_A && ENABLE_CBE_PRINTF_A
// Print out the constant as a floating point number.
char Buffer[100];
sprintf(Buffer, "%a", FPC->getValue());
}
}
+// Some constant expressions need to be casted back to the original types
+// because their operands were casted to the expected type. This function takes
+// care of detecting that case and printing the cast for the ConstantExpr.
+bool CWriter::printConstExprCast(const ConstantExpr* CE) {
+ bool NeedsExplicitCast = false;
+ const Type *Ty = CE->getOperand(0)->getType();
+ switch (CE->getOpcode()) {
+ case Instruction::LShr:
+ case Instruction::URem:
+ case Instruction::UDiv:
+ NeedsExplicitCast = Ty->isSigned(); break;
+ case Instruction::AShr:
+ case Instruction::SRem:
+ case Instruction::SDiv:
+ NeedsExplicitCast = Ty->isUnsigned(); break;
+ case Instruction::ZExt:
+ case Instruction::SExt:
+ case Instruction::Trunc:
+ case Instruction::FPTrunc:
+ case Instruction::FPExt:
+ case Instruction::UIToFP:
+ case Instruction::SIToFP:
+ case Instruction::FPToUI:
+ case Instruction::FPToSI:
+ case Instruction::PtrToInt:
+ case Instruction::IntToPtr:
+ case Instruction::BitCast:
+ Ty = CE->getType();
+ NeedsExplicitCast = true;
+ break;
+ default: break;
+ }
+ if (NeedsExplicitCast) {
+ Out << "((";
+ printType(Out, Ty);
+ Out << ")(";
+ }
+ return NeedsExplicitCast;
+}
+
+// Print a constant assuming that it is the operand for a given Opcode. The
+// opcodes that care about sign need to cast their operands to the expected
+// type before the operation proceeds. This function does the casting.
+void CWriter::printConstantWithCast(Constant* CPV, unsigned Opcode) {
+
+ // Extract the operand's type, we'll need it.
+ const Type* OpTy = CPV->getType();
+
+ // Indicate whether to do the cast or not.
+ bool shouldCast = false;
+
+ // Based on the Opcode for which this Constant is being written, determine
+ // the new type to which the operand should be casted by setting the value
+ // of OpTy. If we change OpTy, also set shouldCast to true so it gets
+ // casted below.
+ switch (Opcode) {
+ default:
+ // for most instructions, it doesn't matter
+ break;
+ case Instruction::LShr:
+ case Instruction::UDiv:
+ case Instruction::URem:
+ // For UDiv/URem get correct type
+ if (OpTy->isSigned()) {
+ OpTy = OpTy->getUnsignedVersion();
+ shouldCast = true;
+ }
+ break;
+ case Instruction::AShr:
+ case Instruction::SDiv:
+ case Instruction::SRem:
+ // For SDiv/SRem get correct type
+ if (OpTy->isUnsigned()) {
+ OpTy = OpTy->getSignedVersion();
+ shouldCast = true;
+ }
+ break;
+ }
+
+ // Write out the casted constant if we should, otherwise just write the
+ // operand.
+ if (shouldCast) {
+ Out << "((";
+ printType(Out, OpTy);
+ Out << ")";
+ printConstant(CPV);
+ Out << ")";
+ } else
+ writeOperand(CPV);
+
+}
+
void CWriter::writeOperandInternal(Value *Operand) {
if (Instruction *I = dyn_cast<Instruction>(Operand))
if (isInlinableInst(*I) && !isDirectAlloca(I)) {
}
}
+void CWriter::writeOperandRaw(Value *Operand) {
+ Constant* CPV = dyn_cast<Constant>(Operand);
+ if (CPV && !isa<GlobalValue>(CPV)) {
+ printConstant(CPV);
+ } else {
+ Out << Mang->getValueName(Operand);
+ }
+}
+
void CWriter::writeOperand(Value *Operand) {
if (isa<GlobalVariable>(Operand) || isDirectAlloca(Operand))
- Out << "(&"; // Global variables are references as their addresses by llvm
+ Out << "(&"; // Global variables are referenced as their addresses by llvm
writeOperandInternal(Operand);
Out << ')';
}
+// Some instructions need to have their result value casted back to the
+// original types because their operands were casted to the expected type.
+// This function takes care of detecting that case and printing the cast
+// for the Instruction.
+bool CWriter::writeInstructionCast(const Instruction &I) {
+ bool NeedsExplicitCast = false;
+ const Type *Ty = I.getOperand(0)->getType();
+ switch (I.getOpcode()) {
+ case Instruction::LShr:
+ case Instruction::URem:
+ case Instruction::UDiv:
+ NeedsExplicitCast = Ty->isSigned(); break;
+ case Instruction::AShr:
+ case Instruction::SRem:
+ case Instruction::SDiv:
+ NeedsExplicitCast = Ty->isUnsigned(); break;
+ case Instruction::ZExt:
+ case Instruction::SExt:
+ case Instruction::Trunc:
+ case Instruction::FPTrunc:
+ case Instruction::FPExt:
+ case Instruction::UIToFP:
+ case Instruction::SIToFP:
+ case Instruction::FPToUI:
+ case Instruction::FPToSI:
+ case Instruction::PtrToInt:
+ case Instruction::IntToPtr:
+ case Instruction::BitCast:
+ Ty = I.getType();
+ NeedsExplicitCast = true;
+ break;
+ default: break;
+ }
+ if (NeedsExplicitCast) {
+ Out << "((";
+ printType(Out, Ty);
+ Out << ")(";
+ }
+ return NeedsExplicitCast;
+}
+
+// Write the operand with a cast to another type based on the Opcode being used.
+// This will be used in cases where an instruction has specific type
+// requirements (usually signedness) for its operands.
+void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) {
+
+ // Extract the operand's type, we'll need it.
+ const Type* OpTy = Operand->getType();
+
+ // Indicate whether to do the cast or not.
+ bool shouldCast = false;
+
+ // Based on the Opcode for which this Operand is being written, determine
+ // the new type to which the operand should be casted by setting the value
+ // of OpTy. If we change OpTy, also set shouldCast to true.
+ switch (Opcode) {
+ default:
+ // for most instructions, it doesn't matter
+ break;
+ case Instruction::LShr:
+ case Instruction::UDiv:
+ case Instruction::URem:
+ // For UDiv to have unsigned operands
+ if (OpTy->isSigned()) {
+ OpTy = OpTy->getUnsignedVersion();
+ shouldCast = true;
+ }
+ break;
+ case Instruction::AShr:
+ case Instruction::SDiv:
+ case Instruction::SRem:
+ if (OpTy->isUnsigned()) {
+ OpTy = OpTy->getSignedVersion();
+ shouldCast = true;
+ }
+ break;
+ }
+
+ // Write out the casted operand if we should, otherwise just write the
+ // operand.
+ if (shouldCast) {
+ Out << "((";
+ printType(Out, OpTy);
+ Out << ")";
+ writeOperand(Operand);
+ Out << ")";
+ } else
+ writeOperand(Operand);
+
+}
+
// generateCompilerSpecificCode - This is where we add conditional compilation
// directives to cater to specific compilers as need be.
//
return; // Found a null terminator, exit printing.
Constant *FP = CS->getOperand(1);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
- if (CE->getOpcode() == Instruction::Cast)
+ if (CE->isCast())
FP = CE->getOperand(0);
if (Function *F = dyn_cast<Function>(FP))
StaticTors.insert(F);
for (BasicBlock::iterator II = BB->begin(), E = --BB->end(); II != E;
++II) {
if (!isInlinableInst(*II) && !isDirectAlloca(II)) {
- if (II->getType() != Type::VoidTy)
+ if (II->getType() != Type::VoidTy && !isInlineAsm(*II))
outputLValue(II);
else
Out << " ";
Out << "-(";
writeOperand(BinaryOperator::getNegArgument(cast<BinaryOperator>(&I)));
Out << ")";
- } else if (I.getOpcode() == Instruction::Rem &&
- I.getType()->isFloatingPoint()) {
+ } else if (I.getOpcode() == Instruction::FRem) {
// Output a call to fmod/fmodf instead of emitting a%b
if (I.getType() == Type::FloatTy)
Out << "fmodf(";
writeOperand(I.getOperand(1));
Out << ")";
} else {
- writeOperand(I.getOperand(0));
+
+ // Write out the cast of the instruction's value back to the proper type
+ // if necessary.
+ bool NeedsClosingParens = writeInstructionCast(I);
+
+ // Certain instructions require the operand to be forced to a specific type
+ // so we use writeOperandWithCast here instead of writeOperand. Similarly
+ // below for operand 1
+ writeOperandWithCast(I.getOperand(0), I.getOpcode());
switch (I.getOpcode()) {
case Instruction::Add: Out << " + "; break;
case Instruction::Sub: Out << " - "; break;
case Instruction::Mul: Out << '*'; break;
- case Instruction::Div: Out << '/'; break;
- case Instruction::Rem: Out << '%'; break;
+ case Instruction::URem:
+ case Instruction::SRem:
+ case Instruction::FRem: Out << '%'; break;
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::FDiv: Out << '/'; break;
case Instruction::And: Out << " & "; break;
case Instruction::Or: Out << " | "; break;
case Instruction::Xor: Out << " ^ "; break;
case Instruction::SetLT: Out << " < "; break;
case Instruction::SetGT: Out << " > "; break;
case Instruction::Shl : Out << " << "; break;
- case Instruction::Shr : Out << " >> "; break;
+ case Instruction::LShr:
+ case Instruction::AShr: Out << " >> "; break;
default: std::cerr << "Invalid operator type!" << I; abort();
}
- writeOperand(I.getOperand(1));
+ writeOperandWithCast(I.getOperand(1), I.getOpcode());
+ if (NeedsClosingParens)
+ Out << "))";
}
if (needsCast) {
}
void CWriter::visitCastInst(CastInst &I) {
- if (I.getType() == Type::BoolTy) {
- Out << '(';
- writeOperand(I.getOperand(0));
- Out << " != 0)";
- return;
- }
+ const Type *DstTy = I.getType();
+ const Type *SrcTy = I.getOperand(0)->getType();
Out << '(';
- printType(Out, I.getType());
- Out << ')';
- if (isa<PointerType>(I.getType())&&I.getOperand(0)->getType()->isIntegral() ||
- isa<PointerType>(I.getOperand(0)->getType())&&I.getType()->isIntegral()) {
- // Avoid "cast to pointer from integer of different size" warnings
- Out << "(long)";
+ printCast(I.getOpcode(), SrcTy, DstTy);
+ if (I.getOpcode() == Instruction::SExt && SrcTy == Type::BoolTy) {
+ // Make sure we really get a sext from bool by subtracing the bool from 0
+ Out << "0-";
}
-
writeOperand(I.getOperand(0));
+ if (DstTy == Type::BoolTy &&
+ (I.getOpcode() == Instruction::Trunc ||
+ I.getOpcode() == Instruction::FPToUI ||
+ I.getOpcode() == Instruction::FPToSI ||
+ I.getOpcode() == Instruction::PtrToInt)) {
+ // Make sure we really get a trunc to bool by anding the operand with 1
+ Out << "&1u";
+ }
+ Out << ')';
}
void CWriter::visitSelectInst(SelectInst &I) {
void CWriter::visitCallInst(CallInst &I) {
+ //check if we have inline asm
+ if (isInlineAsm(I)) {
+ visitInlineAsm(I);
+ return;
+ }
+
bool WroteCallee = false;
// Handle intrinsic function calls first...
// match exactly.
//
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Callee))
- if (CE->getOpcode() == Instruction::Cast)
+ if (CE->isCast())
if (Function *RF = dyn_cast<Function>(CE->getOperand(0))) {
NeedsCast = true;
Callee = RF;
Out << ')';
}
+
+//This converts the llvm constraint string to something gcc is expecting.
+//TODO: work out platform independent constraints and factor those out
+// of the per target tables
+// handle multiple constraint codes
+std::string CWriter::InterpretASMConstraint(InlineAsm::ConstraintInfo& c) {
+
+ assert(c.Codes.size() == 1 && "Too many asm constraint codes to handle");
+
+ //catch numeric constraints
+ if (c.Codes[0].find_first_not_of("0123456789") >= c.Codes[0].size())
+ return c.Codes[0];
+
+ const char** table = 0;
+
+ //Grab the translation table from TargetAsmInfo if it exists
+ if (!TAsm) {
+ std::string E;
+ const TargetMachineRegistry::Entry* Match =
+ TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, E);
+ if (Match) {
+ //Per platform Target Machines don't exist, so create it
+ // this must be done only once
+ const TargetMachine* TM = Match->CtorFn(*TheModule, "");
+ TAsm = TM->getTargetAsmInfo();
+ }
+ }
+ if (TAsm)
+ table = TAsm->getAsmCBE();
+
+ //Search the translation table if it exists
+ for (int i = 0; table && table[i]; i += 2)
+ if (c.Codes[0] == table[i])
+ return table[i+1];
+
+ assert(0 && "Unknown Asm Constraint");
+ return "";
+}
+
+//TODO: import logic from AsmPrinter.cpp
+static std::string gccifyAsm(std::string asmstr) {
+ for (std::string::size_type i = 0; i != asmstr.size(); ++i)
+ if (asmstr[i] == '\n')
+ asmstr.replace(i, 1, "\\n");
+ else if (asmstr[i] == '\t')
+ asmstr.replace(i, 1, "\\t");
+ else if (asmstr[i] == '$') {
+ if (asmstr[i + 1] == '{') {
+ std::string::size_type a = asmstr.find_first_of(':', i + 1);
+ std::string::size_type b = asmstr.find_first_of('}', i + 1);
+ std::string n = "%" +
+ asmstr.substr(a + 1, b - a - 1) +
+ asmstr.substr(i + 2, a - i - 2);
+ asmstr.replace(i, b - i + 1, n);
+ i += n.size() - 1;
+ } else
+ asmstr.replace(i, 1, "%");
+ }
+ else if (asmstr[i] == '%')//grr
+ { asmstr.replace(i, 1, "%%"); ++i;}
+
+ return asmstr;
+}
+
+//TODO: assumptions about what consume arguments from the call are likely wrong
+// handle communitivity
+void CWriter::visitInlineAsm(CallInst &CI) {
+ InlineAsm* as = cast<InlineAsm>(CI.getOperand(0));
+ std::vector<InlineAsm::ConstraintInfo> Constraints = as->ParseConstraints();
+ std::vector<std::pair<std::string, Value*> > Input;
+ std::vector<std::pair<std::string, Value*> > Output;
+ std::string Clobber;
+ int count = CI.getType() == Type::VoidTy ? 1 : 0;
+ for (std::vector<InlineAsm::ConstraintInfo>::iterator I = Constraints.begin(),
+ E = Constraints.end(); I != E; ++I) {
+ assert(I->Codes.size() == 1 && "Too many asm constraint codes to handle");
+ std::string c =
+ InterpretASMConstraint(*I);
+ switch(I->Type) {
+ default:
+ assert(0 && "Unknown asm constraint");
+ break;
+ case InlineAsm::isInput: {
+ if (c.size()) {
+ Input.push_back(std::make_pair(c, count ? CI.getOperand(count) : &CI));
+ ++count; //consume arg
+ }
+ break;
+ }
+ case InlineAsm::isOutput: {
+ if (c.size()) {
+ Output.push_back(std::make_pair("="+((I->isEarlyClobber ? "&" : "")+c),
+ count ? CI.getOperand(count) : &CI));
+ ++count; //consume arg
+ }
+ break;
+ }
+ case InlineAsm::isClobber: {
+ if (c.size())
+ Clobber += ",\"" + c + "\"";
+ break;
+ }
+ }
+ }
+
+ //fix up the asm string for gcc
+ std::string asmstr = gccifyAsm(as->getAsmString());
+
+ Out << "__asm__ volatile (\"" << asmstr << "\"\n";
+ Out << " :";
+ for (std::vector<std::pair<std::string, Value*> >::iterator I = Output.begin(),
+ E = Output.end(); I != E; ++I) {
+ Out << "\"" << I->first << "\"(";
+ writeOperandRaw(I->second);
+ Out << ")";
+ if (I + 1 != E)
+ Out << ",";
+ }
+ Out << "\n :";
+ for (std::vector<std::pair<std::string, Value*> >::iterator I = Input.begin(),
+ E = Input.end(); I != E; ++I) {
+ Out << "\"" << I->first << "\"(";
+ writeOperandRaw(I->second);
+ Out << ")";
+ if (I + 1 != E)
+ Out << ",";
+ }
+ Out << "\n :" << Clobber.substr(1) << ")\n";
+}
+
void CWriter::visitMallocInst(MallocInst &I) {
assert(0 && "lowerallocations pass didn't work!");
}
gep_type_iterator E) {
bool HasImplicitAddress = false;
// If accessing a global value with no indexing, avoid *(&GV) syndrome
- if (GlobalValue *V = dyn_cast<GlobalValue>(Ptr)) {
+ if (isa<GlobalValue>(Ptr)) {
HasImplicitAddress = true;
} else if (isDirectAlloca(Ptr)) {
HasImplicitAddress = true;