You've already forked linux-packaging-mono
Rewrite with hard-coded offsets into the PE file format to discern if a binary is PE32 or PE32+, and then to determine if it contains a "CLR Data Directory" entry that looks valid. Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native binaries, and a random assortment of garbage files. Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
4567 lines
153 KiB
C++
4567 lines
153 KiB
C++
//===-- CBackend.cpp - Library for converting LLVM code to C --------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This library converts LLVM code to C code, compilable by GCC and other C
|
|
// compilers.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CBackend.h"
|
|
#include "llvm/Analysis/ValueTracking.h"
|
|
#include "llvm/IR/InstIterator.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/Host.h"
|
|
#include "llvm/CodeGen/TargetLowering.h"
|
|
#include "llvm/Config/config.h"
|
|
|
|
#if LLVM_VERSION_MAJOR == 7
|
|
#include "llvm/Transforms/Utils.h"
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
|
|
#include <iostream>
|
|
|
|
//#include "Graph.h"
|
|
//#include "PHINodePass.h"
|
|
|
|
//Jackson Korba 9/29/14
|
|
#ifndef DEBUG_TYPE
|
|
#define DEBUG_TYPE ""
|
|
#endif
|
|
//End Modification
|
|
|
|
// Some ms header decided to define setjmp as _setjmp, undo this for this file
|
|
// since we don't need it
|
|
#ifdef setjmp
|
|
#undef setjmp
|
|
#endif
|
|
using namespace llvm;
|
|
|
|
extern "C" void LLVMInitializeCBackendTarget() {
|
|
// Register the target.
|
|
RegisterTargetMachine<CTargetMachine> X(TheCBackendTarget);
|
|
}
|
|
|
|
char CWriter::ID = 0;
|
|
|
|
// extra (invalid) Ops tags for tracking unary ops as a special case of the available binary ops
|
|
enum UnaryOps {
|
|
BinaryNeg = Instruction::OtherOpsEnd + 1,
|
|
BinaryNot,
|
|
};
|
|
|
|
static bool isEmptyType(Type *Ty) {
|
|
if (StructType *STy = dyn_cast<StructType>(Ty))
|
|
return STy->getNumElements() == 0 ||
|
|
std::all_of(STy->element_begin(), STy->element_end(), [](Type *T){ return isEmptyType(T); });
|
|
if (VectorType *VTy = dyn_cast<VectorType>(Ty))
|
|
return VTy->getNumElements() == 0 ||
|
|
isEmptyType(VTy->getElementType());
|
|
if (ArrayType *ATy = dyn_cast<ArrayType>(Ty))
|
|
return ATy->getNumElements() == 0 ||
|
|
isEmptyType(ATy->getElementType());
|
|
return Ty->isVoidTy();
|
|
}
|
|
|
|
bool CWriter::isEmptyType(Type *Ty) const {
|
|
return ::isEmptyType(Ty);
|
|
}
|
|
|
|
/// isAddressExposed - Return true if the specified value's name needs to
|
|
/// have its address taken in order to get a C value of the correct type.
|
|
/// This happens for global variables, byval parameters, and direct allocas.
|
|
bool CWriter::isAddressExposed(Value *V) const {
|
|
if (Argument *A = dyn_cast<Argument>(V))
|
|
return ByValParams.count(A);
|
|
return isa<GlobalVariable>(V) || isDirectAlloca(V);
|
|
}
|
|
|
|
// isInlinableInst - Attempt to inline instructions into their uses to build
|
|
// trees as much as possible. To do this, we have to consistently decide
|
|
// what is acceptable to inline, so that variable declarations don't get
|
|
// printed and an extra copy of the expr is not emitted.
|
|
//
|
|
bool CWriter::isInlinableInst(Instruction &I) const {
|
|
// Always inline cmp instructions, even if they are shared by multiple
|
|
// expressions. GCC generates horrible code if we don't.
|
|
if (isa<CmpInst>(I))
|
|
return true;
|
|
|
|
// Must be an expression, must be used exactly once. If it is dead, we
|
|
// emit it inline where it would go.
|
|
if (isEmptyType(I.getType()) || !I.hasOneUse() ||
|
|
isa<TerminatorInst>(I) || isa<CallInst>(I) || isa<PHINode>(I) ||
|
|
isa<LoadInst>(I) || isa<VAArgInst>(I) || isa<InsertElementInst>(I) ||
|
|
isa<InsertValueInst>(I))
|
|
// Don't inline a load across a store or other bad things!
|
|
return false;
|
|
|
|
// Must not be used in inline asm, extractelement, or shufflevector.
|
|
if (I.hasOneUse()) {
|
|
Instruction &User = cast<Instruction>(*I.user_back());
|
|
if (isInlineAsm(User))
|
|
return false;
|
|
}
|
|
|
|
// Only inline instruction it if it's use is in the same BB as the inst.
|
|
return I.getParent() == cast<Instruction>(I.user_back())->getParent();
|
|
}
|
|
|
|
// isDirectAlloca - Define fixed sized allocas in the entry block as direct
|
|
// variables which are accessed with the & operator. This causes GCC to
|
|
// generate significantly better code than to emit alloca calls directly.
|
|
//
|
|
AllocaInst *CWriter::isDirectAlloca(Value *V) const {
|
|
AllocaInst *AI = dyn_cast<AllocaInst>(V);
|
|
if (!AI) return 0;
|
|
if (AI->isArrayAllocation())
|
|
return 0; // FIXME: we can also inline fixed size array allocas!
|
|
if (AI->getParent() != &AI->getParent()->getParent()->getEntryBlock())
|
|
return 0;
|
|
return AI;
|
|
}
|
|
|
|
// isInlineAsm - Check if the instruction is a call to an inline asm chunk.
|
|
bool CWriter::isInlineAsm(Instruction& I) const {
|
|
if (CallInst *CI = dyn_cast<CallInst>(&I))
|
|
return isa<InlineAsm>(CI->getCalledValue());
|
|
return false;
|
|
}
|
|
|
|
bool CWriter::runOnFunction(Function &F) {
|
|
// Do not codegen any 'available_externally' functions at all, they have
|
|
// definitions outside the translation unit.
|
|
if (F.hasAvailableExternallyLinkage())
|
|
return false;
|
|
|
|
LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
|
|
|
// Get rid of intrinsics we can't handle.
|
|
lowerIntrinsics(F);
|
|
|
|
// Output all floating point constants that cannot be printed accurately.
|
|
printFloatingPointConstants(F);
|
|
|
|
printFunction(F);
|
|
|
|
LI = NULL;
|
|
|
|
return true; // may have lowered an IntrinsicCall
|
|
}
|
|
|
|
static std::string CBEMangle(const std::string &S) {
|
|
std::string Result;
|
|
|
|
for (unsigned i = 0, e = S.size(); i != e; ++i)
|
|
if (isalnum(S[i]) || S[i] == '_') {
|
|
Result += S[i];
|
|
} else {
|
|
Result += '_';
|
|
Result += 'A'+(S[i]&15);
|
|
Result += 'A'+((S[i]>>4)&15);
|
|
Result += '_';
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
raw_ostream &
|
|
CWriter::printTypeString(raw_ostream &Out, Type *Ty, bool isSigned) {
|
|
if (StructType *ST = dyn_cast<StructType>(Ty)) {
|
|
assert(!isEmptyType(ST));
|
|
TypedefDeclTypes.insert(Ty);
|
|
|
|
if (!ST->isLiteral() && !ST->getName().empty())
|
|
return Out << "struct_" << CBEMangle(ST->getName());
|
|
|
|
unsigned &id = UnnamedStructIDs[ST];
|
|
if (id == 0)
|
|
id = ++NextAnonStructNumber;
|
|
return Out << "unnamed_" + utostr(id);
|
|
}
|
|
|
|
if (Ty->isPointerTy()) {
|
|
Out << "p";
|
|
return printTypeString(Out, Ty->getPointerElementType(), isSigned);
|
|
}
|
|
|
|
switch (Ty->getTypeID()) {
|
|
case Type::VoidTyID: return Out << "void";
|
|
case Type::IntegerTyID: {
|
|
unsigned NumBits = cast<IntegerType>(Ty)->getBitWidth();
|
|
if (NumBits == 1)
|
|
return Out << "bool";
|
|
else {
|
|
assert(NumBits <= 128 && "Bit widths > 128 not implemented yet");
|
|
return Out << (isSigned?"i":"u") << NumBits;
|
|
}
|
|
}
|
|
case Type::FloatTyID: return Out << "f32";
|
|
case Type::DoubleTyID: return Out << "f64";
|
|
case Type::X86_FP80TyID: return Out << "f80";
|
|
case Type::PPC_FP128TyID:
|
|
case Type::FP128TyID: return Out << "f128";
|
|
|
|
case Type::X86_MMXTyID:
|
|
return Out << (isSigned ? "i32y2" : "u32y2");
|
|
|
|
case Type::VectorTyID: {
|
|
TypedefDeclTypes.insert(Ty);
|
|
VectorType *VTy = cast<VectorType>(Ty);
|
|
assert(VTy->getNumElements() != 0);
|
|
printTypeString(Out, VTy->getElementType(), isSigned);
|
|
return Out << "x" << VTy->getNumElements();
|
|
}
|
|
|
|
case Type::ArrayTyID: {
|
|
TypedefDeclTypes.insert(Ty);
|
|
ArrayType *ATy = cast<ArrayType>(Ty);
|
|
assert(ATy->getNumElements() != 0);
|
|
printTypeString(Out, ATy->getElementType(), isSigned);
|
|
return Out << "a" << ATy->getNumElements();
|
|
}
|
|
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Unknown primitive type: " << *Ty << "\n";
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
}
|
|
|
|
std::string CWriter::getStructName(StructType *ST) {
|
|
assert(ST->getNumElements() != 0);
|
|
if (!ST->isLiteral() && !ST->getName().empty())
|
|
return "struct l_struct_" + CBEMangle(ST->getName().str());
|
|
|
|
unsigned &id = UnnamedStructIDs[ST];
|
|
if (id == 0)
|
|
id = ++NextAnonStructNumber;
|
|
return "struct l_unnamed_" + utostr(id);
|
|
}
|
|
|
|
std::string CWriter::getFunctionName(FunctionType *FT, std::pair<AttributeList, CallingConv::ID> PAL) {
|
|
unsigned &id = UnnamedFunctionIDs[std::make_pair(FT, PAL)];
|
|
if (id == 0)
|
|
id = ++NextFunctionNumber;
|
|
return "l_fptr_" + utostr(id);
|
|
}
|
|
|
|
std::string CWriter::getArrayName(ArrayType *AT) {
|
|
std::string astr;
|
|
raw_string_ostream ArrayInnards(astr);
|
|
// Arrays are wrapped in structs to allow them to have normal
|
|
// value semantics (avoiding the array "decay").
|
|
assert(!isEmptyType(AT));
|
|
printTypeName(ArrayInnards, AT->getElementType(), false);
|
|
return "struct l_array_" + utostr(AT->getNumElements()) + '_' + CBEMangle(ArrayInnards.str());
|
|
}
|
|
|
|
std::string CWriter::getVectorName(VectorType *VT, bool Aligned) {
|
|
std::string astr;
|
|
raw_string_ostream VectorInnards(astr);
|
|
// Vectors are handled like arrays
|
|
assert(!isEmptyType(VT));
|
|
if (Aligned)
|
|
Out << "__MSALIGN__(" << TD->getABITypeAlignment(VT) << ") ";
|
|
printTypeName(VectorInnards, VT->getElementType(), false);
|
|
return "struct l_vector_" + utostr(VT->getNumElements()) + '_' + CBEMangle(VectorInnards.str());
|
|
}
|
|
|
|
|
|
static const std::string getCmpPredicateName(CmpInst::Predicate P) {
|
|
switch (P) {
|
|
case FCmpInst::FCMP_FALSE: return "0";
|
|
case FCmpInst::FCMP_OEQ: return "oeq";
|
|
case FCmpInst::FCMP_OGT: return "ogt";
|
|
case FCmpInst::FCMP_OGE: return "oge";
|
|
case FCmpInst::FCMP_OLT: return "olt";
|
|
case FCmpInst::FCMP_OLE: return "ole";
|
|
case FCmpInst::FCMP_ONE: return "one";
|
|
case FCmpInst::FCMP_ORD: return "ord";
|
|
case FCmpInst::FCMP_UNO: return "uno";
|
|
case FCmpInst::FCMP_UEQ: return "ueq";
|
|
case FCmpInst::FCMP_UGT: return "ugt";
|
|
case FCmpInst::FCMP_UGE: return "uge";
|
|
case FCmpInst::FCMP_ULT: return "ult";
|
|
case FCmpInst::FCMP_ULE: return "ule";
|
|
case FCmpInst::FCMP_UNE: return "une";
|
|
case FCmpInst::FCMP_TRUE: return "1";
|
|
case ICmpInst::ICMP_EQ: return "eq";
|
|
case ICmpInst::ICMP_NE: return "ne";
|
|
case ICmpInst::ICMP_ULE: return "ule";
|
|
case ICmpInst::ICMP_SLE: return "sle";
|
|
case ICmpInst::ICMP_UGE: return "uge";
|
|
case ICmpInst::ICMP_SGE: return "sge";
|
|
case ICmpInst::ICMP_ULT: return "ult";
|
|
case ICmpInst::ICMP_SLT: return "slt";
|
|
case ICmpInst::ICMP_UGT: return "ugt";
|
|
case ICmpInst::ICMP_SGT: return "sgt";
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid icmp predicate!" << P;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
}
|
|
|
|
|
|
raw_ostream &
|
|
CWriter::printSimpleType(raw_ostream &Out, Type *Ty, bool isSigned) {
|
|
assert((Ty->isSingleValueType() || Ty->isVoidTy()) &&
|
|
"Invalid type for printSimpleType");
|
|
switch (Ty->getTypeID()) {
|
|
case Type::VoidTyID: return Out << "void";
|
|
case Type::IntegerTyID: {
|
|
unsigned NumBits = cast<IntegerType>(Ty)->getBitWidth();
|
|
if (NumBits == 1)
|
|
return Out << "bool";
|
|
else if (NumBits <= 8)
|
|
return Out << (isSigned?"int8_t":"uint8_t");
|
|
else if (NumBits <= 16)
|
|
return Out << (isSigned?"int16_t":"uint16_t");
|
|
else if (NumBits <= 32)
|
|
return Out << (isSigned?"int32_t":"uint32_t");
|
|
else if (NumBits <= 64)
|
|
return Out << (isSigned?"int64_t":"uint64_t");
|
|
else {
|
|
assert(NumBits <= 128 && "Bit widths > 128 not implemented yet");
|
|
return Out << (isSigned?"int128_t":"uint128_t");
|
|
}
|
|
}
|
|
case Type::FloatTyID: return Out << "float";
|
|
case Type::DoubleTyID: return Out << "double";
|
|
// Lacking emulation of FP80 on PPC, etc., we assume whichever of these is
|
|
// present matches host 'long double'.
|
|
case Type::X86_FP80TyID:
|
|
case Type::PPC_FP128TyID:
|
|
case Type::FP128TyID: return Out << "long double";
|
|
|
|
case Type::X86_MMXTyID:
|
|
return Out << (isSigned?"int32_t":"uint32_t") << " __attribute__((vector_size(8)))";
|
|
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Unknown primitive type: " << *Ty << "\n";
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
}
|
|
|
|
// Pass the Type* and the variable name and this prints out the variable
|
|
// declaration.
|
|
//
|
|
raw_ostream &CWriter::printTypeName(raw_ostream &Out, Type *Ty, bool isSigned, std::pair<AttributeList, CallingConv::ID> PAL) {
|
|
if (Ty->isSingleValueType() || Ty->isVoidTy()) {
|
|
if (!Ty->isPointerTy() && !Ty->isVectorTy())
|
|
return printSimpleType(Out, Ty, isSigned);
|
|
}
|
|
|
|
if (isEmptyType(Ty))
|
|
return Out << "void";
|
|
|
|
switch (Ty->getTypeID()) {
|
|
case Type::FunctionTyID: {
|
|
FunctionType *FTy = cast<FunctionType>(Ty);
|
|
return Out << getFunctionName(FTy, PAL);
|
|
}
|
|
case Type::StructTyID: {
|
|
TypedefDeclTypes.insert(Ty);
|
|
return Out << getStructName(cast<StructType>(Ty));
|
|
}
|
|
|
|
case Type::PointerTyID: {
|
|
Type *ElTy = Ty->getPointerElementType();
|
|
return printTypeName(Out, ElTy, false) << '*';
|
|
}
|
|
|
|
case Type::ArrayTyID: {
|
|
TypedefDeclTypes.insert(Ty);
|
|
return Out << getArrayName(cast<ArrayType>(Ty));
|
|
}
|
|
|
|
case Type::VectorTyID: {
|
|
TypedefDeclTypes.insert(Ty);
|
|
return Out << getVectorName(cast<VectorType>(Ty), true);
|
|
}
|
|
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Unexpected type: " << *Ty << "\n";
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
}
|
|
|
|
raw_ostream &CWriter::printTypeNameUnaligned(raw_ostream &Out, Type *Ty, bool isSigned) {
|
|
if (VectorType *VTy = dyn_cast<VectorType>(Ty)) {
|
|
// MSVC doesn't handle __declspec(align) on parameters,
|
|
// but we specify it for Vector (hoping the compiler will vectorize it)
|
|
// so we need to avoid it sometimes
|
|
TypedefDeclTypes.insert(VTy);
|
|
return Out << getVectorName(VTy, false);
|
|
}
|
|
return printTypeName(Out, Ty, isSigned);
|
|
}
|
|
|
|
raw_ostream &CWriter::printStructDeclaration(raw_ostream &Out, StructType *STy) {
|
|
if (STy->isPacked())
|
|
Out << "#ifdef _MSC_VER\n#pragma pack(push, 1)\n#endif\n";
|
|
Out << getStructName(STy) << " {\n";
|
|
unsigned Idx = 0;
|
|
for (StructType::element_iterator I = STy->element_begin(),
|
|
E = STy->element_end(); I != E; ++I, Idx++) {
|
|
Out << " ";
|
|
bool empty = isEmptyType(*I);
|
|
if (empty)
|
|
Out << "/* "; // skip zero-sized types
|
|
printTypeName(Out, *I, false) << " field" << utostr(Idx);
|
|
if (empty)
|
|
Out << " */"; // skip zero-sized types
|
|
else
|
|
Out << ";\n";
|
|
}
|
|
Out << '}';
|
|
if (STy->isPacked())
|
|
Out << " __attribute__ ((packed))";
|
|
Out << ";\n";
|
|
if (STy->isPacked())
|
|
Out << "#ifdef _MSC_VER\n#pragma pack(pop)\n#endif\n";
|
|
return Out;
|
|
}
|
|
|
|
raw_ostream &CWriter::printFunctionDeclaration(raw_ostream &Out, FunctionType *Ty,
|
|
std::pair<AttributeList, CallingConv::ID> PAL) {
|
|
Out << "typedef ";
|
|
printFunctionProto(Out, Ty, PAL, getFunctionName(Ty, PAL), NULL);
|
|
return Out << ";\n";
|
|
}
|
|
|
|
raw_ostream &CWriter::printFunctionProto(raw_ostream &Out, FunctionType *FTy,
|
|
std::pair<AttributeList, CallingConv::ID> Attrs,
|
|
const std::string &Name,
|
|
iterator_range<Function::arg_iterator> *ArgList) {
|
|
AttributeList &PAL = Attrs.first;
|
|
|
|
if (PAL.hasAttribute(AttributeList::FunctionIndex, Attribute::NoReturn))
|
|
Out << "__noreturn ";
|
|
|
|
// Should this function actually return a struct by-value?
|
|
bool isStructReturn = PAL.hasAttribute(1, Attribute::StructRet) ||
|
|
PAL.hasAttribute(2, Attribute::StructRet);
|
|
// Get the return type for the function.
|
|
Type *RetTy;
|
|
if (!isStructReturn)
|
|
RetTy = FTy->getReturnType();
|
|
else {
|
|
// If this is a struct-return function, print the struct-return type.
|
|
RetTy = cast<PointerType>(FTy->getParamType(0))->getElementType();
|
|
}
|
|
printTypeName(Out, RetTy,
|
|
/*isSigned=*/PAL.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt));
|
|
|
|
switch (Attrs.second) {
|
|
case CallingConv::C:
|
|
break;
|
|
case CallingConv::X86_StdCall:
|
|
Out << " __stdcall";
|
|
break;
|
|
case CallingConv::X86_FastCall:
|
|
Out << " __fastcall";
|
|
break;
|
|
case CallingConv::X86_ThisCall:
|
|
Out << " __thiscall";
|
|
break;
|
|
default:
|
|
assert(0 && "Encountered Unhandled Calling Convention");
|
|
break;
|
|
}
|
|
Out << ' ' << Name << '(';
|
|
|
|
unsigned Idx = 1;
|
|
bool PrintedArg = false;
|
|
FunctionType::param_iterator I = FTy->param_begin(), E = FTy->param_end();
|
|
Function::arg_iterator ArgName = ArgList ? ArgList->begin() : Function::arg_iterator();
|
|
|
|
// If this is a struct-return function, don't print the hidden
|
|
// struct-return argument.
|
|
if (isStructReturn) {
|
|
assert(I != E && "Invalid struct return function!");
|
|
++I;
|
|
++Idx;
|
|
if (ArgList) ++ArgName;
|
|
}
|
|
|
|
for (; I != E; ++I) {
|
|
Type *ArgTy = *I;
|
|
if (PAL.hasAttribute(Idx, Attribute::ByVal)) {
|
|
assert(ArgTy->isPointerTy());
|
|
ArgTy = cast<PointerType>(ArgTy)->getElementType();
|
|
}
|
|
if (PrintedArg)
|
|
Out << ", ";
|
|
printTypeNameUnaligned(Out, ArgTy,
|
|
/*isSigned=*/PAL.hasAttribute(Idx, Attribute::SExt));
|
|
PrintedArg = true;
|
|
++Idx;
|
|
if (ArgList) {
|
|
Out << ' ' << GetValueName(ArgName);
|
|
++ArgName;
|
|
}
|
|
}
|
|
|
|
if (FTy->isVarArg()) {
|
|
if (!PrintedArg) {
|
|
Out << "int"; //dummy argument for empty vaarg functs
|
|
if (ArgList) Out << " vararg_dummy_arg";
|
|
}
|
|
Out << ", ...";
|
|
} else if (!PrintedArg) {
|
|
Out << "void";
|
|
}
|
|
Out << ")";
|
|
return Out;
|
|
}
|
|
|
|
raw_ostream &CWriter::printArrayDeclaration(raw_ostream &Out, ArrayType *ATy) {
|
|
assert(!isEmptyType(ATy));
|
|
// Arrays are wrapped in structs to allow them to have normal
|
|
// value semantics (avoiding the array "decay").
|
|
Out << getArrayName(ATy) << " {\n ";
|
|
printTypeName(Out, ATy->getElementType());
|
|
Out << " array[" << utostr(ATy->getNumElements()) << "];\n};\n";
|
|
return Out;
|
|
}
|
|
|
|
raw_ostream &CWriter::printVectorDeclaration(raw_ostream &Out, VectorType *VTy) {
|
|
assert(!isEmptyType(VTy));
|
|
// Vectors are printed like arrays
|
|
Out << getVectorName(VTy, false) << " {\n ";
|
|
printTypeName(Out, VTy->getElementType());
|
|
Out << " vector[" << utostr(VTy->getNumElements()) << "];\n} __attribute__((aligned(" << TD->getABITypeAlignment(VTy) << ")));\n";
|
|
return Out;
|
|
}
|
|
|
|
void CWriter::printConstantArray(ConstantArray *CPA, enum OperandContext Context) {
|
|
printConstant(cast<Constant>(CPA->getOperand(0)), Context);
|
|
for (unsigned i = 1, e = CPA->getNumOperands(); i != e; ++i) {
|
|
Out << ", ";
|
|
printConstant(cast<Constant>(CPA->getOperand(i)), Context);
|
|
}
|
|
}
|
|
|
|
void CWriter::printConstantVector(ConstantVector *CP, enum OperandContext Context) {
|
|
printConstant(cast<Constant>(CP->getOperand(0)), Context);
|
|
for (unsigned i = 1, e = CP->getNumOperands(); i != e; ++i) {
|
|
Out << ", ";
|
|
printConstant(cast<Constant>(CP->getOperand(i)), Context);
|
|
}
|
|
}
|
|
|
|
void CWriter::printConstantDataSequential(ConstantDataSequential *CDS, enum OperandContext Context) {
|
|
printConstant(CDS->getElementAsConstant(0), Context);
|
|
for (unsigned i = 1, e = CDS->getNumElements(); i != e; ++i) {
|
|
Out << ", ";
|
|
printConstant(CDS->getElementAsConstant(i), Context);
|
|
}
|
|
}
|
|
|
|
bool CWriter::printConstantString(Constant *C, enum OperandContext Context) {
|
|
// As a special case, print the array as a string if it is an array of
|
|
// ubytes or an array of sbytes with positive values.
|
|
ConstantDataSequential *CDS = dyn_cast<ConstantDataSequential>(C);
|
|
if (!CDS || !CDS->isCString()) return false;
|
|
if (Context != ContextStatic) return false; // TODO
|
|
|
|
Out << "{ \"";
|
|
// Keep track of whether the last number was a hexadecimal escape.
|
|
bool LastWasHex = false;
|
|
|
|
StringRef Bytes = CDS->getAsString();
|
|
|
|
// Do not include the last character, which we know is null
|
|
for (unsigned i = 0, e = Bytes.size() - 1; i < e; ++i) {
|
|
unsigned char C = Bytes[i];
|
|
|
|
// Print it out literally if it is a printable character. The only thing
|
|
// to be careful about is when the last letter output was a hex escape
|
|
// code, in which case we have to be careful not to print out hex digits
|
|
// explicitly (the C compiler thinks it is a continuation of the previous
|
|
// character, sheesh...)
|
|
//
|
|
if (isprint(C) && (!LastWasHex || !isxdigit(C))) {
|
|
LastWasHex = false;
|
|
if (C == '"' || C == '\\')
|
|
Out << "\\" << (char)C;
|
|
else
|
|
Out << (char)C;
|
|
} else {
|
|
LastWasHex = false;
|
|
switch (C) {
|
|
case '\n': Out << "\\n"; break;
|
|
case '\t': Out << "\\t"; break;
|
|
case '\r': Out << "\\r"; break;
|
|
case '\v': Out << "\\v"; break;
|
|
case '\a': Out << "\\a"; break;
|
|
case '\"': Out << "\\\""; break;
|
|
case '\'': Out << "\\\'"; break;
|
|
default:
|
|
Out << "\\x";
|
|
Out << (char)(( C/16 < 10) ? ( C/16 +'0') : ( C/16 -10+'A'));
|
|
Out << (char)(((C&15) < 10) ? ((C&15)+'0') : ((C&15)-10+'A'));
|
|
LastWasHex = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Out << "\" }";
|
|
return true;
|
|
}
|
|
|
|
|
|
// isFPCSafeToPrint - Returns true if we may assume that CFP may be written out
|
|
// textually as a double (rather than as a reference to a stack-allocated
|
|
// variable). We decide this by converting CFP to a string and back into a
|
|
// double, and then checking whether the conversion results in a bit-equal
|
|
// double to the original value of CFP. This depends on us and the target C
|
|
// compiler agreeing on the conversion process (which is pretty likely since we
|
|
// only deal in IEEE FP).
|
|
//
|
|
|
|
// TODO copied from CppBackend, new code should use raw_ostream
|
|
static inline std::string ftostr(const APFloat& V) {
|
|
std::string Buf;
|
|
if (&V.getSemantics() == &APFloat::IEEEdouble()) {
|
|
raw_string_ostream(Buf) << V.convertToDouble();
|
|
return Buf;
|
|
} else if (&V.getSemantics() == &APFloat::IEEEsingle()) {
|
|
raw_string_ostream(Buf) << (double)V.convertToFloat();
|
|
return Buf;
|
|
}
|
|
return "<unknown format in ftostr>"; // error
|
|
}
|
|
|
|
static bool isFPCSafeToPrint(const ConstantFP *CFP) {
|
|
bool ignored;
|
|
// Do long doubles in hex for now.
|
|
if (CFP->getType() != Type::getFloatTy(CFP->getContext()) &&
|
|
CFP->getType() != Type::getDoubleTy(CFP->getContext()))
|
|
return false;
|
|
APFloat APF = APFloat(CFP->getValueAPF()); // copy
|
|
if (CFP->getType() == Type::getFloatTy(CFP->getContext()))
|
|
APF.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &ignored);
|
|
#if HAVE_PRINTF_A && ENABLE_CBE_PRINTF_A
|
|
char Buffer[100];
|
|
sprintf(Buffer, "%a", APF.convertToDouble());
|
|
if (!strncmp(Buffer, "0x", 2) ||
|
|
!strncmp(Buffer, "-0x", 3) ||
|
|
!strncmp(Buffer, "+0x", 3))
|
|
return APF.bitwiseIsEqual(APFloat(atof(Buffer)));
|
|
return false;
|
|
#else
|
|
std::string StrVal = ftostr(APF);
|
|
|
|
while (StrVal[0] == ' ')
|
|
StrVal.erase(StrVal.begin());
|
|
|
|
// Check to make sure that the stringized number is not some string like "Inf"
|
|
// or NaN. Check that the string matches the "[-+]?[0-9]" regex.
|
|
if ((StrVal[0] >= '0' && StrVal[0] <= '9') ||
|
|
((StrVal[0] == '-' || StrVal[0] == '+') &&
|
|
(StrVal[1] >= '0' && StrVal[1] <= '9')))
|
|
// Reparse stringized version!
|
|
return APF.bitwiseIsEqual(APFloat(atof(StrVal.c_str())));
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
/// Print out the casting for a cast operation. This does the double casting
|
|
/// necessary for conversion to the destination type, if necessary.
|
|
/// @brief Print a cast
|
|
void CWriter::printCast(unsigned opc, Type *SrcTy, Type *DstTy) {
|
|
// Print the destination type cast
|
|
switch (opc) {
|
|
case Instruction::UIToFP:
|
|
case Instruction::SIToFP:
|
|
case Instruction::IntToPtr:
|
|
case Instruction::Trunc:
|
|
case Instruction::BitCast:
|
|
case Instruction::FPExt:
|
|
case Instruction::FPTrunc: // For these the DstTy sign doesn't matter
|
|
Out << '(';
|
|
printTypeName(Out, DstTy);
|
|
Out << ')';
|
|
break;
|
|
case Instruction::ZExt:
|
|
case Instruction::PtrToInt:
|
|
case Instruction::FPToUI: // For these, make sure we get an unsigned dest
|
|
Out << '(';
|
|
printSimpleType(Out, DstTy, false);
|
|
Out << ')';
|
|
break;
|
|
case Instruction::SExt:
|
|
case Instruction::FPToSI: // For these, make sure we get a signed dest
|
|
Out << '(';
|
|
printSimpleType(Out, DstTy, true);
|
|
Out << ')';
|
|
break;
|
|
default:
|
|
llvm_unreachable("Invalid cast opcode");
|
|
}
|
|
|
|
// Print the source type cast
|
|
switch (opc) {
|
|
case Instruction::UIToFP:
|
|
case Instruction::ZExt:
|
|
Out << '(';
|
|
printSimpleType(Out, SrcTy, false);
|
|
Out << ')';
|
|
break;
|
|
case Instruction::SIToFP:
|
|
case Instruction::SExt:
|
|
Out << '(';
|
|
printSimpleType(Out, SrcTy, true);
|
|
Out << ')';
|
|
break;
|
|
case Instruction::IntToPtr:
|
|
case Instruction::PtrToInt:
|
|
// Avoid "cast to pointer from integer of different size" warnings
|
|
Out << "(uintptr_t)";
|
|
break;
|
|
case Instruction::Trunc:
|
|
case Instruction::BitCast:
|
|
case Instruction::FPExt:
|
|
case Instruction::FPTrunc:
|
|
case Instruction::FPToSI:
|
|
case Instruction::FPToUI:
|
|
break; // These don't need a source cast.
|
|
default:
|
|
llvm_unreachable("Invalid cast opcode");
|
|
}
|
|
}
|
|
|
|
// printConstant - The LLVM Constant to C Constant converter.
|
|
void CWriter::printConstant(Constant *CPV, enum OperandContext Context) {
|
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(CPV)) {
|
|
assert(CE->getType()->isIntegerTy() || CE->getType()->isFloatingPointTy() || CE->getType()->isPointerTy()); // TODO: VectorType are valid here, but not supported
|
|
switch (CE->getOpcode()) {
|
|
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::getInt1Ty(CPV->getContext())) {
|
|
// Make sure we really sext from bool here by subtracting from 0
|
|
Out << "0-";
|
|
}
|
|
printConstant(CE->getOperand(0), ContextCasted);
|
|
if (CE->getType() == Type::getInt1Ty(CPV->getContext()) &&
|
|
(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::GetElementPtr:
|
|
Out << "(";
|
|
printGEPExpression(CE->getOperand(0), gep_type_begin(CPV), gep_type_end(CPV));
|
|
Out << ")";
|
|
return;
|
|
case Instruction::Select:
|
|
Out << '(';
|
|
printConstant(CE->getOperand(0), ContextCasted);
|
|
Out << '?';
|
|
printConstant(CE->getOperand(1), ContextNormal);
|
|
Out << ':';
|
|
printConstant(CE->getOperand(2), ContextNormal);
|
|
Out << ')';
|
|
return;
|
|
case Instruction::Add:
|
|
case Instruction::FAdd:
|
|
case Instruction::Sub:
|
|
case Instruction::FSub:
|
|
case Instruction::Mul:
|
|
case Instruction::FMul:
|
|
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::ICmp:
|
|
case Instruction::Shl:
|
|
case Instruction::LShr:
|
|
case Instruction::AShr:
|
|
{
|
|
Out << '(';
|
|
bool NeedsClosingParens = printConstExprCast(CE);
|
|
printConstantWithCast(CE->getOperand(0), CE->getOpcode());
|
|
switch (CE->getOpcode()) {
|
|
case Instruction::Add:
|
|
case Instruction::FAdd: Out << " + "; break;
|
|
case Instruction::Sub:
|
|
case Instruction::FSub: Out << " - "; break;
|
|
case Instruction::Mul:
|
|
case Instruction::FMul: 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::Shl: Out << " << "; break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr: Out << " >> "; break;
|
|
case Instruction::ICmp:
|
|
switch (CE->getPredicate()) {
|
|
case ICmpInst::ICMP_EQ: Out << " == "; break;
|
|
case ICmpInst::ICMP_NE: Out << " != "; break;
|
|
case ICmpInst::ICMP_SLT:
|
|
case ICmpInst::ICMP_ULT: Out << " < "; break;
|
|
case ICmpInst::ICMP_SLE:
|
|
case ICmpInst::ICMP_ULE: Out << " <= "; break;
|
|
case ICmpInst::ICMP_SGT:
|
|
case ICmpInst::ICMP_UGT: Out << " > "; break;
|
|
case ICmpInst::ICMP_SGE:
|
|
case ICmpInst::ICMP_UGE: Out << " >= "; break;
|
|
default: llvm_unreachable("Illegal ICmp predicate");
|
|
}
|
|
break;
|
|
default: llvm_unreachable("Illegal opcode here!");
|
|
}
|
|
printConstantWithCast(CE->getOperand(1), CE->getOpcode());
|
|
if (NeedsClosingParens)
|
|
Out << "))";
|
|
Out << ')';
|
|
return;
|
|
}
|
|
case Instruction::FCmp: {
|
|
Out << '(';
|
|
bool NeedsClosingParens = printConstExprCast(CE);
|
|
if (CE->getPredicate() == FCmpInst::FCMP_FALSE)
|
|
Out << "0";
|
|
else if (CE->getPredicate() == FCmpInst::FCMP_TRUE)
|
|
Out << "1";
|
|
else {
|
|
Out << "llvm_fcmp_" << getCmpPredicateName((CmpInst::Predicate)CE->getPredicate()) << "(";
|
|
printConstant(CE->getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
printConstant(CE->getOperand(1), ContextCasted);
|
|
Out << ")";
|
|
}
|
|
if (NeedsClosingParens)
|
|
Out << "))";
|
|
Out << ')';
|
|
return;
|
|
}
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "CWriter Error: Unhandled constant expression: "
|
|
<< *CE << "\n";
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
} else if (isa<UndefValue>(CPV) && CPV->getType()->isSingleValueType()) {
|
|
if (CPV->getType()->isVectorTy()) {
|
|
if (Context == ContextStatic) {
|
|
Out << "{}";
|
|
return;
|
|
}
|
|
VectorType *VT = cast<VectorType>(CPV->getType());
|
|
assert(!isEmptyType(VT));
|
|
CtorDeclTypes.insert(VT);
|
|
Out << "/*undef*/llvm_ctor_";
|
|
printTypeString(Out, VT, false);
|
|
Out << "(";
|
|
Constant *Zero = Constant::getNullValue(VT->getElementType());
|
|
unsigned NumElts = VT->getNumElements();
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
|
if (i) Out << ", ";
|
|
printConstant(Zero, ContextCasted);
|
|
}
|
|
Out << ")";
|
|
|
|
} else {
|
|
Constant *Zero = Constant::getNullValue(CPV->getType());
|
|
Out << "/*UNDEF*/";
|
|
return printConstant(Zero, Context);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(CPV)) {
|
|
Type* Ty = CI->getType();
|
|
unsigned ActiveBits = CI->getValue().getMinSignedBits();
|
|
if (Ty == Type::getInt1Ty(CPV->getContext())) {
|
|
Out << (CI->getZExtValue() ? '1' : '0');
|
|
} else if (Context != ContextNormal &&
|
|
ActiveBits < 64 &&
|
|
Ty->getPrimitiveSizeInBits() < 64 &&
|
|
ActiveBits < Ty->getPrimitiveSizeInBits()) {
|
|
if (ActiveBits >= 32)
|
|
Out << "INT64_C(";
|
|
Out << CI->getSExtValue(); // most likely a shorter representation
|
|
if (ActiveBits >= 32)
|
|
Out << ")";
|
|
} else if (Ty->getPrimitiveSizeInBits() < 32 && Context == ContextNormal) {
|
|
Out << "((";
|
|
printSimpleType(Out, Ty, false) << ')';
|
|
if (CI->isMinValue(true))
|
|
Out << CI->getZExtValue() << 'u';
|
|
else
|
|
Out << CI->getSExtValue();
|
|
Out << ')';
|
|
} else if (Ty->getPrimitiveSizeInBits() <= 32) {
|
|
Out << CI->getZExtValue() << 'u';
|
|
} else if (Ty->getPrimitiveSizeInBits() <= 64) {
|
|
Out << "UINT64_C(" << CI->getZExtValue() << ")";
|
|
} else if (Ty->getPrimitiveSizeInBits() <= 128) {
|
|
const APInt &V = CI->getValue();
|
|
const APInt &Vlo = V.getLoBits(64);
|
|
const APInt &Vhi = V.getHiBits(64);
|
|
Out << (Context == ContextStatic ? "UINT128_C" : "llvm_ctor_u128");
|
|
Out << "(UINT64_C(" << Vhi.getZExtValue() << "), UINT64_C(" << Vlo.getZExtValue() << "))";
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch (CPV->getType()->getTypeID()) {
|
|
case Type::FloatTyID:
|
|
case Type::DoubleTyID:
|
|
case Type::X86_FP80TyID:
|
|
case Type::PPC_FP128TyID:
|
|
case Type::FP128TyID: {
|
|
ConstantFP *FPC = cast<ConstantFP>(CPV);
|
|
std::map<const ConstantFP*, unsigned>::iterator I = FPConstantMap.find(FPC);
|
|
if (I != FPConstantMap.end()) {
|
|
// Because of FP precision problems we must load from a stack allocated
|
|
// value that holds the value in hex.
|
|
Out << "(*(" << (FPC->getType() == Type::getFloatTy(CPV->getContext()) ?
|
|
"float" :
|
|
FPC->getType() == Type::getDoubleTy(CPV->getContext()) ?
|
|
"double" :
|
|
"long double")
|
|
<< "*)&FPConstant" << I->second << ')';
|
|
} else {
|
|
double V;
|
|
if (FPC->getType() == Type::getFloatTy(CPV->getContext()))
|
|
V = FPC->getValueAPF().convertToFloat();
|
|
else if (FPC->getType() == Type::getDoubleTy(CPV->getContext()))
|
|
V = FPC->getValueAPF().convertToDouble();
|
|
else {
|
|
// Long double. Convert the number to double, discarding precision.
|
|
// This is not awesome, but it at least makes the CBE output somewhat
|
|
// useful.
|
|
APFloat Tmp = FPC->getValueAPF();
|
|
bool LosesInfo;
|
|
Tmp.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &LosesInfo);
|
|
V = Tmp.convertToDouble();
|
|
}
|
|
|
|
if (std::isnan(V)) {
|
|
// The value is NaN
|
|
|
|
// FIXME the actual NaN bits should be emitted.
|
|
// 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;
|
|
|
|
// We need to grab the first part of the FP #
|
|
char Buffer[100];
|
|
|
|
uint64_t ll = DoubleToBits(V);
|
|
sprintf(Buffer, "0x%llx", static_cast<long long>(ll));
|
|
|
|
std::string Num(&Buffer[0], &Buffer[6]);
|
|
unsigned long Val = strtoul(Num.c_str(), 0, 16);
|
|
|
|
if (FPC->getType() == Type::getFloatTy(FPC->getContext()))
|
|
Out << "LLVM_NAN" << (Val == QuietNaN ? "" : "S") << "F(\""
|
|
<< Buffer << "\") /*nan*/ ";
|
|
else
|
|
Out << "LLVM_NAN" << (Val == QuietNaN ? "" : "S") << "(\""
|
|
<< Buffer << "\") /*nan*/ ";
|
|
} else if (std::isinf(V)) {
|
|
// The value is Inf
|
|
if (V < 0) Out << '-';
|
|
Out << "LLVM_INF" <<
|
|
(FPC->getType() == Type::getFloatTy(FPC->getContext()) ? "F" : "")
|
|
<< " /*inf*/ ";
|
|
} else {
|
|
std::string Num;
|
|
#if HAVE_PRINTF_A && ENABLE_CBE_PRINTF_A
|
|
// Print out the constant as a floating point number.
|
|
char Buffer[100];
|
|
sprintf(Buffer, "%a", V);
|
|
Num = Buffer;
|
|
#else
|
|
Num = ftostr(FPC->getValueAPF());
|
|
#endif
|
|
Out << Num;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Type::ArrayTyID: {
|
|
if (printConstantString(CPV, Context)) break;
|
|
ArrayType *AT = cast<ArrayType>(CPV->getType());
|
|
assert(AT->getNumElements() != 0 && !isEmptyType(AT));
|
|
if (Context != ContextStatic) {
|
|
CtorDeclTypes.insert(AT);
|
|
Out << "llvm_ctor_";
|
|
printTypeString(Out, AT, false);
|
|
Out << "(";
|
|
Context = ContextCasted;
|
|
} else {
|
|
Out << "{ { "; // Arrays are wrapped in struct types.
|
|
}
|
|
if (ConstantArray *CA = dyn_cast<ConstantArray>(CPV)) {
|
|
printConstantArray(CA, Context);
|
|
} else if (ConstantDataSequential *CDS =
|
|
dyn_cast<ConstantDataSequential>(CPV)) {
|
|
printConstantDataSequential(CDS, Context);
|
|
} else {
|
|
assert(isa<ConstantAggregateZero>(CPV) || isa<UndefValue>(CPV));
|
|
Constant *CZ = Constant::getNullValue(AT->getElementType());
|
|
printConstant(CZ, Context);
|
|
for (unsigned i = 1, e = AT->getNumElements(); i != e; ++i) {
|
|
Out << ", ";
|
|
printConstant(CZ, Context);
|
|
}
|
|
}
|
|
Out << (Context == ContextStatic ? " } }" : ")"); // Arrays are wrapped in struct types.
|
|
break;
|
|
}
|
|
|
|
case Type::VectorTyID: {
|
|
VectorType *VT = cast<VectorType>(CPV->getType());
|
|
assert(VT->getNumElements() != 0 && !isEmptyType(VT));
|
|
if (Context != ContextStatic) {
|
|
CtorDeclTypes.insert(VT);
|
|
Out << "llvm_ctor_";
|
|
printTypeString(Out, VT, false);
|
|
Out << "(";
|
|
Context = ContextCasted;
|
|
} else {
|
|
Out << "{ ";
|
|
}
|
|
if (ConstantVector *CV = dyn_cast<ConstantVector>(CPV)) {
|
|
printConstantVector(CV, Context);
|
|
} else if (ConstantDataSequential *CDS =
|
|
dyn_cast<ConstantDataSequential>(CPV)) {
|
|
printConstantDataSequential(CDS, Context);
|
|
} else {
|
|
assert(isa<ConstantAggregateZero>(CPV) || isa<UndefValue>(CPV));
|
|
Constant *CZ = Constant::getNullValue(VT->getElementType());
|
|
printConstant(CZ, Context);
|
|
for (unsigned i = 1, e = VT->getNumElements(); i != e; ++i) {
|
|
Out << ", ";
|
|
printConstant(CZ, Context);
|
|
}
|
|
}
|
|
Out << (Context == ContextStatic ? " }" : ")");
|
|
break;
|
|
}
|
|
|
|
case Type::StructTyID: {
|
|
StructType *ST = cast<StructType>(CPV->getType());
|
|
assert(!isEmptyType(ST));
|
|
if (Context != ContextStatic) {
|
|
CtorDeclTypes.insert(ST);
|
|
Out << "llvm_ctor_";
|
|
printTypeString(Out, ST, false);
|
|
Out << "(";
|
|
Context = ContextCasted;
|
|
} else {
|
|
Out << "{ ";
|
|
}
|
|
|
|
if (isa<ConstantAggregateZero>(CPV) || isa<UndefValue>(CPV)) {
|
|
bool printed = false;
|
|
for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
|
|
Type *ElTy = ST->getElementType(i);
|
|
if (isEmptyType(ElTy)) continue;
|
|
if (printed) Out << ", ";
|
|
printConstant(Constant::getNullValue(ElTy), Context);
|
|
printed = true;
|
|
}
|
|
assert(printed);
|
|
} else {
|
|
bool printed = false;
|
|
for (unsigned i = 0, e = CPV->getNumOperands(); i != e; ++i) {
|
|
Constant *C = cast<Constant>(CPV->getOperand(i));
|
|
if (isEmptyType(C->getType())) continue;
|
|
if (printed) Out << ", ";
|
|
printConstant(C, Context);
|
|
printed = true;
|
|
}
|
|
assert(printed);
|
|
}
|
|
Out << (Context == ContextStatic ? " }" : ")");
|
|
break;
|
|
}
|
|
|
|
case Type::PointerTyID:
|
|
if (isa<ConstantPointerNull>(CPV)) {
|
|
Out << "((";
|
|
printTypeName(Out, CPV->getType()); // sign doesn't matter
|
|
Out << ")/*NULL*/0)";
|
|
break;
|
|
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(CPV)) {
|
|
writeOperand(GV);
|
|
break;
|
|
}
|
|
// FALL THROUGH
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Unknown constant type: " << *CPV << "\n";
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
}
|
|
|
|
// 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(ConstantExpr* CE) {
|
|
bool NeedsExplicitCast = false;
|
|
Type *Ty = CE->getOperand(0)->getType();
|
|
bool TypeIsSigned = false;
|
|
switch (CE->getOpcode()) {
|
|
case Instruction::Add:
|
|
case Instruction::Sub:
|
|
case Instruction::Mul:
|
|
// We need to cast integer arithmetic so that it is always performed
|
|
// as unsigned, to avoid undefined behavior on overflow.
|
|
case Instruction::LShr:
|
|
case Instruction::URem:
|
|
case Instruction::UDiv: NeedsExplicitCast = true; break;
|
|
case Instruction::AShr:
|
|
case Instruction::SRem:
|
|
case Instruction::SDiv: NeedsExplicitCast = true; TypeIsSigned = true; break;
|
|
case Instruction::SExt:
|
|
Ty = CE->getType();
|
|
NeedsExplicitCast = true;
|
|
TypeIsSigned = true;
|
|
break;
|
|
case Instruction::ZExt:
|
|
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 << "((";
|
|
printTypeName(Out, Ty, TypeIsSigned); // not integer, sign doesn't matter
|
|
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.
|
|
Type* OpTy = CPV->getType();
|
|
assert(OpTy->isIntegerTy() || OpTy->isFloatingPointTy()); // TODO: VectorType are valid here, but not supported
|
|
|
|
// Indicate whether to do the cast or not.
|
|
bool shouldCast;
|
|
bool typeIsSigned;
|
|
opcodeNeedsCast(Opcode, shouldCast, typeIsSigned);
|
|
|
|
// Write out the casted constant if we should, otherwise just write the
|
|
// operand.
|
|
if (shouldCast) {
|
|
Out << "((";
|
|
printSimpleType(Out, OpTy, typeIsSigned);
|
|
Out << ")";
|
|
printConstant(CPV, ContextCasted);
|
|
Out << ")";
|
|
} else
|
|
printConstant(CPV, ContextCasted);
|
|
}
|
|
|
|
std::string CWriter::GetValueName(Value *Operand) {
|
|
|
|
// Resolve potential alias.
|
|
if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Operand)) {
|
|
Operand = GA->getAliasee();
|
|
}
|
|
|
|
std::string Name = Operand->getName();
|
|
if (Name.empty()) { // Assign unique names to local temporaries.
|
|
unsigned &No = AnonValueNumbers[Operand];
|
|
if (No == 0)
|
|
No = ++NextAnonValueNumber;
|
|
Name = "tmp__" + utostr(No);
|
|
}
|
|
|
|
// Mangle globals with the standard mangler interface for LLC compatibility.
|
|
if (isa<GlobalValue>(Operand)) {
|
|
return CBEMangle(Name);
|
|
}
|
|
|
|
std::string VarName;
|
|
VarName.reserve(Name.capacity());
|
|
|
|
for (std::string::iterator I = Name.begin(), E = Name.end();
|
|
I != E; ++I) {
|
|
unsigned char ch = *I;
|
|
|
|
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
|
|
(ch >= '0' && ch <= '9') || ch == '_')) {
|
|
char buffer[5];
|
|
sprintf(buffer, "_%x_", ch);
|
|
VarName += buffer;
|
|
} else
|
|
VarName += ch;
|
|
}
|
|
|
|
return "llvm_cbe_" + VarName;
|
|
}
|
|
|
|
/// writeInstComputationInline - Emit the computation for the specified
|
|
/// instruction inline, with no destination provided.
|
|
void CWriter::writeInstComputationInline(Instruction &I) {
|
|
// C can't handle non-power-of-two integer types
|
|
unsigned mask = 0;
|
|
Type *Ty = I.getType();
|
|
if (Ty->isIntegerTy()) {
|
|
IntegerType *ITy = static_cast<IntegerType*>(Ty);
|
|
if (!ITy->isPowerOf2ByteWidth())
|
|
mask = ITy->getBitMask();
|
|
}
|
|
|
|
// If this is a non-trivial bool computation, make sure to truncate down to
|
|
// a 1 bit value. This is important because we want "add i1 x, y" to return
|
|
// "0" when x and y are true, not "2" for example.
|
|
// Also truncate odd bit sizes
|
|
if (mask)
|
|
Out << "((";
|
|
|
|
visit(&I);
|
|
|
|
if (mask)
|
|
Out << ")&" << mask << ")";
|
|
}
|
|
|
|
|
|
void CWriter::writeOperandInternal(Value *Operand, enum OperandContext Context) {
|
|
if (Instruction *I = dyn_cast<Instruction>(Operand))
|
|
// Should we inline this instruction to build a tree?
|
|
if (isInlinableInst(*I) && !isDirectAlloca(I)) {
|
|
Out << '(';
|
|
writeInstComputationInline(*I);
|
|
Out << ')';
|
|
return;
|
|
}
|
|
|
|
Constant* CPV = dyn_cast<Constant>(Operand);
|
|
|
|
if (CPV && !isa<GlobalValue>(CPV))
|
|
printConstant(CPV, Context);
|
|
else
|
|
Out << GetValueName(Operand);
|
|
}
|
|
|
|
void CWriter::writeOperand(Value *Operand, enum OperandContext Context) {
|
|
bool isAddressImplicit = isAddressExposed(Operand);
|
|
if (isAddressImplicit)
|
|
Out << "(&"; // Global variables are referenced as their addresses by llvm
|
|
|
|
writeOperandInternal(Operand, Context);
|
|
|
|
if (isAddressImplicit)
|
|
Out << ')';
|
|
}
|
|
|
|
/// writeOperandDeref - Print the result of dereferencing the specified
|
|
/// operand with '*'. This is equivalent to printing '*' then using
|
|
/// writeOperand, but avoids excess syntax in some cases.
|
|
void CWriter::writeOperandDeref(Value *Operand) {
|
|
if (isAddressExposed(Operand)) {
|
|
// Already something with an address exposed.
|
|
writeOperandInternal(Operand);
|
|
} else {
|
|
Out << "*(";
|
|
writeOperand(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(Instruction &I) {
|
|
Type *Ty = I.getOperand(0)->getType();
|
|
switch (I.getOpcode()) {
|
|
case Instruction::Add:
|
|
case Instruction::Sub:
|
|
case Instruction::Mul:
|
|
// We need to cast integer arithmetic so that it is always performed
|
|
// as unsigned, to avoid undefined behavior on overflow.
|
|
case Instruction::LShr:
|
|
case Instruction::URem:
|
|
case Instruction::UDiv:
|
|
Out << "((";
|
|
printSimpleType(Out, Ty, false);
|
|
Out << ")(";
|
|
return true;
|
|
case Instruction::AShr:
|
|
case Instruction::SRem:
|
|
case Instruction::SDiv:
|
|
Out << "((";
|
|
printSimpleType(Out, Ty, true);
|
|
Out << ")(";
|
|
return true;
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// 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::opcodeNeedsCast(unsigned Opcode,
|
|
// Indicate whether to do the cast or not.
|
|
bool &shouldCast,
|
|
// Indicate whether the cast should be to a signed type or not.
|
|
bool &castIsSigned) {
|
|
|
|
// 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
|
|
shouldCast = false;
|
|
castIsSigned = false;
|
|
break;
|
|
case Instruction::Add:
|
|
case Instruction::Sub:
|
|
case Instruction::Mul:
|
|
// We need to cast integer arithmetic so that it is always performed
|
|
// as unsigned, to avoid undefined behavior on overflow.
|
|
case Instruction::LShr:
|
|
case Instruction::UDiv:
|
|
case Instruction::URem: // Cast to unsigned first
|
|
shouldCast = true;
|
|
castIsSigned = false;
|
|
break;
|
|
case Instruction::GetElementPtr:
|
|
case Instruction::AShr:
|
|
case Instruction::SDiv:
|
|
case Instruction::SRem: // Cast to signed first
|
|
shouldCast = true;
|
|
castIsSigned = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) {
|
|
// Write out the casted operand if we should, otherwise just write the
|
|
// operand.
|
|
|
|
// Extract the operand's type, we'll need it.
|
|
bool shouldCast;
|
|
bool castIsSigned;
|
|
opcodeNeedsCast(Opcode, shouldCast, castIsSigned);
|
|
|
|
Type* OpTy = Operand->getType();
|
|
if (shouldCast) {
|
|
Out << "((";
|
|
printSimpleType(Out, OpTy, castIsSigned);
|
|
Out << ")";
|
|
writeOperand(Operand, ContextCasted);
|
|
Out << ")";
|
|
} else
|
|
writeOperand(Operand, ContextCasted);
|
|
}
|
|
|
|
// Write the operand with a cast to another type based on the icmp predicate
|
|
// being used.
|
|
void CWriter::writeOperandWithCast(Value* Operand, ICmpInst &Cmp) {
|
|
// This has to do a cast to ensure the operand has the right signedness.
|
|
// Also, if the operand is a pointer, we make sure to cast to an integer when
|
|
// doing the comparison both for signedness and so that the C compiler doesn't
|
|
// optimize things like "p < NULL" to false (p may contain an integer value
|
|
// f.e.).
|
|
bool shouldCast = Cmp.isRelational();
|
|
|
|
// Write out the casted operand if we should, otherwise just write the
|
|
// operand.
|
|
if (!shouldCast) {
|
|
writeOperand(Operand);
|
|
return;
|
|
}
|
|
|
|
// Should this be a signed comparison? If so, convert to signed.
|
|
bool castIsSigned = Cmp.isSigned();
|
|
|
|
// If the operand was a pointer, convert to a large integer type.
|
|
Type* OpTy = Operand->getType();
|
|
if (OpTy->isPointerTy())
|
|
OpTy = TD->getIntPtrType(Operand->getContext());
|
|
|
|
Out << "((";
|
|
printSimpleType(Out, OpTy, castIsSigned);
|
|
Out << ")";
|
|
writeOperand(Operand);
|
|
Out << ")";
|
|
}
|
|
|
|
// generateCompilerSpecificCode - This is where we add conditional compilation
|
|
// directives to cater to specific compilers as need be.
|
|
//
|
|
static void generateCompilerSpecificCode(raw_ostream& Out,
|
|
const DataLayout *TD) {
|
|
// Alloca is hard to get, and we don't want to include stdlib.h here.
|
|
Out << "/* get a declaration for alloca */\n"
|
|
<< "#if defined(__CYGWIN__) || defined(__MINGW32__)\n"
|
|
<< "#define alloca(x) __builtin_alloca((x))\n"
|
|
<< "#define _alloca(x) __builtin_alloca((x))\n"
|
|
<< "#elif defined(__APPLE__)\n"
|
|
<< "extern void *__builtin_alloca(unsigned long);\n"
|
|
<< "#define alloca(x) __builtin_alloca(x)\n"
|
|
<< "#define longjmp _longjmp\n"
|
|
<< "#define setjmp _setjmp\n"
|
|
<< "#elif defined(__sun__)\n"
|
|
<< "#if defined(__sparcv9)\n"
|
|
<< "extern void *__builtin_alloca(unsigned long);\n"
|
|
<< "#else\n"
|
|
<< "extern void *__builtin_alloca(unsigned int);\n"
|
|
<< "#endif\n"
|
|
<< "#define alloca(x) __builtin_alloca(x)\n"
|
|
<< "#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__arm__)\n"
|
|
<< "#define alloca(x) __builtin_alloca(x)\n"
|
|
<< "#elif defined(_MSC_VER)\n"
|
|
<< "#define alloca(x) _alloca(x)\n"
|
|
<< "#else\n"
|
|
<< "#include <alloca.h>\n"
|
|
<< "#endif\n\n";
|
|
|
|
// On Mac OS X, "external weak" is spelled "__attribute__((weak_import))".
|
|
Out << "#if defined(__GNUC__) && defined(__APPLE_CC__)\n"
|
|
<< "#define __EXTERNAL_WEAK__ __attribute__((weak_import))\n"
|
|
<< "#elif defined(__GNUC__)\n"
|
|
<< "#define __EXTERNAL_WEAK__ __attribute__((weak))\n"
|
|
<< "#else\n"
|
|
<< "#define __EXTERNAL_WEAK__\n"
|
|
<< "#endif\n\n";
|
|
|
|
// For now, turn off the weak linkage attribute on Mac OS X. (See above.)
|
|
Out << "#if defined(__GNUC__) && defined(__APPLE_CC__)\n"
|
|
<< "#define __ATTRIBUTE_WEAK__\n"
|
|
<< "#elif defined(__GNUC__)\n"
|
|
<< "#define __ATTRIBUTE_WEAK__ __attribute__((weak))\n"
|
|
<< "#else\n"
|
|
<< "#define __ATTRIBUTE_WEAK__\n"
|
|
<< "#endif\n\n";
|
|
|
|
// Add hidden visibility support. FIXME: APPLE_CC?
|
|
Out << "#if defined(__GNUC__)\n"
|
|
<< "#define __HIDDEN__ __attribute__((visibility(\"hidden\")))\n"
|
|
<< "#endif\n\n";
|
|
|
|
// Define unaligned-load helper macro
|
|
Out << "#ifdef _MSC_VER\n";
|
|
Out << "#define __UNALIGNED_LOAD__(type, align, op) *((type __unaligned*)op)\n";
|
|
Out << "#else\n";
|
|
Out << "#define __UNALIGNED_LOAD__(type, align, op) ((struct { type data __attribute__((packed, aligned(align))); }*)op)->data\n";
|
|
Out << "#endif\n\n";
|
|
|
|
// Define unaligned-load helper macro
|
|
Out << "#ifdef _MSC_VER\n";
|
|
Out << "#define __MSALIGN__(X) __declspec(align(X))\n";
|
|
Out << "#else\n";
|
|
Out << "#define __MSALIGN__(X)\n";
|
|
Out << "#endif\n\n";
|
|
|
|
// Define compatibility macros to help msvc look more like gcc/clang
|
|
Out << "#ifdef _MSC_VER\n";
|
|
Out << "#define __builtin_unreachable() __assume(0)\n";
|
|
Out << "#define __noreturn __declspec(noreturn)\n";
|
|
Out << "#else\n";
|
|
Out << "#define __noreturn __attribute__((noreturn))\n";
|
|
Out << "#define __forceinline __attribute__((always_inline))\n";
|
|
Out << "#endif\n\n";
|
|
|
|
// Define NaN and Inf as GCC builtins if using GCC
|
|
// From the GCC documentation:
|
|
//
|
|
// double __builtin_nan (const char *str)
|
|
//
|
|
// This is an implementation of the ISO C99 function nan.
|
|
//
|
|
// Since ISO C99 defines this function in terms of strtod, which we do
|
|
// not implement, a description of the parsing is in order. The string is
|
|
// parsed as by strtol; that is, the base is recognized by leading 0 or
|
|
// 0x prefixes. The number parsed is placed in the significand such that
|
|
// the least significant bit of the number is at the least significant
|
|
// bit of the significand. The number is truncated to fit the significand
|
|
// field provided. The significand is forced to be a quiet NaN.
|
|
//
|
|
// This function, if given a string literal, is evaluated early enough
|
|
// that it is considered a compile-time constant.
|
|
//
|
|
// float __builtin_nanf (const char *str)
|
|
//
|
|
// Similar to __builtin_nan, except the return type is float.
|
|
//
|
|
// double __builtin_inf (void)
|
|
//
|
|
// Similar to __builtin_huge_val, except a warning is generated if the
|
|
// target floating-point format does not support infinities. This
|
|
// function is suitable for implementing the ISO C99 macro INFINITY.
|
|
//
|
|
// float __builtin_inff (void)
|
|
//
|
|
// Similar to __builtin_inf, except the return type is float.
|
|
Out << "#ifdef __GNUC__\n"
|
|
<< "#define LLVM_NAN(NanStr) __builtin_nan(NanStr) /* Double */\n"
|
|
<< "#define LLVM_NANF(NanStr) __builtin_nanf(NanStr) /* Float */\n"
|
|
//<< "#define LLVM_NANS(NanStr) __builtin_nans(NanStr) /* Double */\n"
|
|
//<< "#define LLVM_NANSF(NanStr) __builtin_nansf(NanStr) /* Float */\n"
|
|
<< "#define LLVM_INF __builtin_inf() /* Double */\n"
|
|
<< "#define LLVM_INFF __builtin_inff() /* Float */\n"
|
|
<< "#define LLVM_PREFETCH(addr,rw,locality) "
|
|
"__builtin_prefetch(addr,rw,locality)\n"
|
|
<< "#define __ATTRIBUTE_CTOR__ __attribute__((constructor))\n"
|
|
<< "#define __ATTRIBUTE_DTOR__ __attribute__((destructor))\n"
|
|
<< "#else\n"
|
|
<< "#define LLVM_NAN(NanStr) ((double)NAN) /* Double */\n"
|
|
<< "#define LLVM_NANF(NanStr) ((float)NAN)) /* Float */\n"
|
|
//<< "#define LLVM_NANS(NanStr) ((double)NAN) /* Double */\n"
|
|
//<< "#define LLVM_NANSF(NanStr) ((single)NAN) /* Float */\n"
|
|
<< "#define LLVM_INF ((double)INFINITY) /* Double */\n"
|
|
<< "#define LLVM_INFF ((float)INFINITY) /* Float */\n"
|
|
<< "#define LLVM_PREFETCH(addr,rw,locality) /* PREFETCH */\n"
|
|
<< "#define __ATTRIBUTE_CTOR__ \"__attribute__((constructor)) not supported on this compiler\"\n"
|
|
<< "#define __ATTRIBUTE_DTOR__ \"__attribute__((destructor)) not supported on this compiler\"\n"
|
|
<< "#endif\n\n";
|
|
|
|
Out << "#if !defined(__GNUC__) || __GNUC__ < 4 /* Old GCC's, or compilers not GCC */ \n"
|
|
<< "#define __builtin_stack_save() 0 /* not implemented */\n"
|
|
<< "#define __builtin_stack_restore(X) /* noop */\n"
|
|
<< "#endif\n\n";
|
|
|
|
// Output typedefs for 128-bit integers
|
|
Out << "#if defined(__GNUC__) && defined(__LP64__) /* 128-bit integer types */\n"
|
|
<< "typedef int __attribute__((mode(TI))) int128_t;\n"
|
|
<< "typedef unsigned __attribute__((mode(TI))) uint128_t;\n"
|
|
<< "#define UINT128_C(hi, lo) (((uint128_t)(hi) << 64) | (uint128_t)(lo))\n"
|
|
<< "static __forceinline uint128_t llvm_ctor_u128(uint64_t hi, uint64_t lo) {"
|
|
<< " return UINT128_C(hi, lo); }\n"
|
|
<< "static __forceinline bool llvm_icmp_eq_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l == r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_ne_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l != r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_ule_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l <= r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_sle_i128(int128_t l, int128_t r) {"
|
|
<< " return l <= r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_uge_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l >= r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_sge_i128(int128_t l, int128_t r) {"
|
|
<< " return l >= r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_ult_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l < r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_slt_i128(int128_t l, int128_t r) {"
|
|
<< " return l < r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_ugt_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l > r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_sgt_i128(int128_t l, int128_t r) {"
|
|
<< " return l > r; }\n"
|
|
|
|
<< "#else /* manual 128-bit types */\n"
|
|
// TODO: field order should be reversed for big-endian
|
|
<< "typedef struct { uint64_t lo; uint64_t hi; } uint128_t;\n"
|
|
<< "typedef uint128_t int128_t;\n"
|
|
<< "#define UINT128_C(hi, lo) {(lo), (hi)}\n" // only use in Static context
|
|
<< "static __forceinline uint128_t llvm_ctor_u128(uint64_t hi, uint64_t lo) {"
|
|
<< " uint128_t r; r.lo = lo; r.hi = hi; return r; }\n"
|
|
<< "static __forceinline bool llvm_icmp_eq_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l.hi == r.hi && l.lo == r.lo; }\n"
|
|
<< "static __forceinline bool llvm_icmp_ne_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l.hi != r.hi || l.lo != r.lo; }\n"
|
|
<< "static __forceinline bool llvm_icmp_ule_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l.hi < r.hi ? 1 : (l.hi == r.hi ? l.lo <= l.lo : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_sle_i128(int128_t l, int128_t r) {"
|
|
<< " return (int64_t)l.hi < (int64_t)r.hi ? 1 : (l.hi == r.hi ? (int64_t)l.lo <= (int64_t)l.lo : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_uge_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l.hi > r.hi ? 1 : (l.hi == r.hi ? l.lo >= l.hi : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_sge_i128(int128_t l, int128_t r) {"
|
|
<< " return (int64_t)l.hi > (int64_t)r.hi ? 1 : (l.hi == r.hi ? (int64_t)l.lo >= (int64_t)l.lo : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_ult_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l.hi < r.hi ? 1 : (l.hi == r.hi ? l.lo < l.hi : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_slt_i128(int128_t l, int128_t r) {"
|
|
<< " return (int64_t)l.hi < (int64_t)r.hi ? 1 : (l.hi == r.hi ? (int64_t)l.lo < (int64_t)l.lo : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_ugt_u128(uint128_t l, uint128_t r) {"
|
|
<< " return l.hi > r.hi ? 1 : (l.hi == r.hi ? l.lo > l.hi : 0); }\n"
|
|
<< "static __forceinline bool llvm_icmp_sgt_i128(int128_t l, int128_t r) {"
|
|
<< " return (int64_t)l.hi > (int64_t)r.hi ? 1 : (l.hi == r.hi ? (int64_t)l.lo > (int64_t)l.lo : 0); }\n"
|
|
<< "#define __emulate_i128\n"
|
|
<< "#endif\n\n";
|
|
|
|
// We output GCC specific attributes to preserve 'linkonce'ness on globals.
|
|
// If we aren't being compiled with GCC, just drop these attributes.
|
|
Out << "#ifdef _MSC_VER /* Can only support \"linkonce\" vars with GCC */\n"
|
|
<< "#define __attribute__(X)\n"
|
|
<< "#endif\n\n";
|
|
}
|
|
|
|
/// FindStaticTors - Given a static ctor/dtor list, unpack its contents into
|
|
/// the StaticTors set.
|
|
static void FindStaticTors(GlobalVariable *GV, std::set<Function*> &StaticTors){
|
|
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
|
if (!InitList) return;
|
|
|
|
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i)
|
|
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))){
|
|
if (CS->getNumOperands() != 2) return; // Not array of 2-element structs.
|
|
|
|
if (CS->getOperand(1)->isNullValue())
|
|
return; // Found a null terminator, exit printing.
|
|
Constant *FP = CS->getOperand(1);
|
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
|
if (CE->isCast())
|
|
FP = CE->getOperand(0);
|
|
if (Function *F = dyn_cast<Function>(FP))
|
|
StaticTors.insert(F);
|
|
}
|
|
}
|
|
|
|
enum SpecialGlobalClass {
|
|
NotSpecial = 0,
|
|
GlobalCtors, GlobalDtors,
|
|
NotPrinted
|
|
};
|
|
|
|
/// getGlobalVariableClass - If this is a global that is specially recognized
|
|
/// by LLVM, return a code that indicates how we should handle it.
|
|
static SpecialGlobalClass getGlobalVariableClass(GlobalVariable *GV) {
|
|
// If this is a global ctors/dtors list, handle it now.
|
|
if (GV->hasAppendingLinkage() && GV->use_empty()) {
|
|
if (GV->getName() == "llvm.global_ctors")
|
|
return GlobalCtors;
|
|
else if (GV->getName() == "llvm.global_dtors")
|
|
return GlobalDtors;
|
|
}
|
|
|
|
// Otherwise, if it is other metadata, don't print it. This catches things
|
|
// like debug information.
|
|
if (StringRef(GV->getSection()) == "llvm.metadata")
|
|
return NotPrinted;
|
|
|
|
return NotSpecial;
|
|
}
|
|
|
|
// PrintEscapedString - Print each character of the specified string, escaping
|
|
// it if it is not printable or if it is an escape char.
|
|
static void PrintEscapedString(const char *Str, unsigned Length,
|
|
raw_ostream &Out) {
|
|
for (unsigned i = 0; i != Length; ++i) {
|
|
unsigned char C = Str[i];
|
|
if (isprint(C) && C != '\\' && C != '"')
|
|
Out << C;
|
|
else if (C == '\\')
|
|
Out << "\\\\";
|
|
else if (C == '\"')
|
|
Out << "\\\"";
|
|
else if (C == '\t')
|
|
Out << "\\t";
|
|
else
|
|
Out << "\\x" << hexdigit(C >> 4) << hexdigit(C & 0x0F);
|
|
}
|
|
}
|
|
|
|
// PrintEscapedString - Print each character of the specified string, escaping
|
|
// it if it is not printable or if it is an escape char.
|
|
static void PrintEscapedString(const std::string &Str, raw_ostream &Out) {
|
|
PrintEscapedString(Str.c_str(), Str.size(), Out);
|
|
}
|
|
|
|
bool CWriter::doInitialization(Module &M) {
|
|
TheModule = &M;
|
|
|
|
TD = new DataLayout(&M);
|
|
IL = new IntrinsicLowering(*TD);
|
|
IL->AddPrototypes(M);
|
|
|
|
#if 0
|
|
std::string Triple = TheModule->getTargetTriple();
|
|
if (Triple.empty())
|
|
Triple = llvm::sys::getDefaultTargetTriple();
|
|
|
|
std::string E;
|
|
if (const Target *Match = TargetRegistry::lookupTarget(Triple, E))
|
|
TAsm = Match->createMCAsmInfo(Triple);
|
|
#endif
|
|
TAsm = new CBEMCAsmInfo();
|
|
MRI = new MCRegisterInfo();
|
|
TCtx = new MCContext(TAsm, MRI, NULL);
|
|
return false;
|
|
}
|
|
|
|
bool CWriter::doFinalization(Module &M) {
|
|
// Output all code to the file
|
|
std::string methods = Out.str();
|
|
_Out.clear();
|
|
generateHeader(M);
|
|
std::string header = Out.str();
|
|
_Out.clear();
|
|
FileOut << header << methods;
|
|
|
|
// Free memory...
|
|
delete IL;
|
|
delete TD;
|
|
delete TCtx;
|
|
delete TAsm;
|
|
delete MRI;
|
|
delete MOFI;
|
|
FPConstantMap.clear();
|
|
ByValParams.clear();
|
|
AnonValueNumbers.clear();
|
|
UnnamedStructIDs.clear();
|
|
UnnamedFunctionIDs.clear();
|
|
TypedefDeclTypes.clear();
|
|
SelectDeclTypes.clear();
|
|
CmpDeclTypes.clear();
|
|
CastOpDeclTypes.clear();
|
|
InlineOpDeclTypes.clear();
|
|
CtorDeclTypes.clear();
|
|
prototypesToGen.clear();
|
|
|
|
// reset all state
|
|
FPCounter = 0;
|
|
OpaqueCounter = 0;
|
|
NextAnonValueNumber = 0;
|
|
NextAnonStructNumber = 0;
|
|
NextFunctionNumber = 0;
|
|
return true; // may have lowered an IntrinsicCall
|
|
}
|
|
|
|
void CWriter::generateHeader(Module &M) {
|
|
// Keep track of which functions are static ctors/dtors so they can have
|
|
// an attribute added to their prototypes.
|
|
std::set<Function*> StaticCtors, StaticDtors;
|
|
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I) {
|
|
switch (getGlobalVariableClass(&*I)) {
|
|
default: break;
|
|
case GlobalCtors:
|
|
FindStaticTors(&*I, StaticCtors);
|
|
break;
|
|
case GlobalDtors:
|
|
FindStaticTors(&*I, StaticDtors);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// get declaration for alloca
|
|
Out << "/* Provide Declarations */\n";
|
|
Out << "#include <stdarg.h>\n"; // Varargs support
|
|
Out << "#include <setjmp.h>\n"; // Unwind support
|
|
Out << "#include <limits.h>\n"; // With overflow intrinsics support.
|
|
Out << "#include <stdint.h>\n"; // Sized integer support
|
|
Out << "#include <math.h>\n"; // definitions for some math functions and numeric constants
|
|
Out << "#include <APInt-C.h>\n"; // Implementations of many llvm intrinsics
|
|
// Provide a definition for `bool' if not compiling with a C++ compiler.
|
|
Out << "#ifndef __cplusplus\ntypedef unsigned char bool;\n#endif\n";
|
|
Out << "\n";
|
|
|
|
generateCompilerSpecificCode(Out, TD);
|
|
|
|
Out << "\n\n/* Support for floating point constants */\n"
|
|
<< "typedef uint64_t ConstantDoubleTy;\n"
|
|
<< "typedef uint32_t ConstantFloatTy;\n"
|
|
<< "typedef struct { uint64_t f1; uint16_t f2; "
|
|
"uint16_t pad[3]; } ConstantFP80Ty;\n"
|
|
// This is used for both kinds of 128-bit long double; meaning differs.
|
|
<< "typedef struct { uint64_t f1; uint64_t f2; }"
|
|
" ConstantFP128Ty;\n"
|
|
<< "\n\n/* Global Declarations */\n";
|
|
|
|
// First output all the declarations for the program, because C requires
|
|
// Functions & globals to be declared before they are used.
|
|
if (!M.getModuleInlineAsm().empty()) {
|
|
Out << "\n/* Module asm statements */\n"
|
|
<< "__asm__ (";
|
|
|
|
// Split the string into lines, to make it easier to read the .ll file.
|
|
std::string Asm = M.getModuleInlineAsm();
|
|
size_t CurPos = 0;
|
|
size_t NewLine = Asm.find_first_of('\n', CurPos);
|
|
while (NewLine != std::string::npos) {
|
|
// We found a newline, print the portion of the asm string from the
|
|
// last newline up to this newline.
|
|
Out << "\"";
|
|
PrintEscapedString(std::string(Asm.begin()+CurPos, Asm.begin()+NewLine),
|
|
Out);
|
|
Out << "\\n\"\n";
|
|
CurPos = NewLine+1;
|
|
NewLine = Asm.find_first_of('\n', CurPos);
|
|
}
|
|
Out << "\"";
|
|
PrintEscapedString(std::string(Asm.begin()+CurPos, Asm.end()), Out);
|
|
Out << "\");\n"
|
|
<< "/* End Module asm statements */\n";
|
|
}
|
|
|
|
// collect any remaining types
|
|
raw_null_ostream NullOut;
|
|
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I) {
|
|
// Ignore special globals, such as debug info.
|
|
if (getGlobalVariableClass(&*I))
|
|
continue;
|
|
printTypeName(NullOut, I->getType()->getElementType(), false);
|
|
}
|
|
printModuleTypes(Out);
|
|
|
|
// Global variable declarations...
|
|
if (!M.global_empty()) {
|
|
Out << "\n/* External Global Variable Declarations */\n";
|
|
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I) {
|
|
if (!I->isDeclaration() || isEmptyType(I->getType()->getPointerElementType()))
|
|
continue;
|
|
|
|
if (I->hasDLLImportStorageClass())
|
|
Out << "__declspec(dllimport) ";
|
|
else if (I->hasDLLExportStorageClass())
|
|
Out << "__declspec(dllexport) ";
|
|
|
|
if (I->hasExternalLinkage() || I->hasExternalWeakLinkage() ||
|
|
I->hasCommonLinkage())
|
|
Out << "extern ";
|
|
else
|
|
continue; // Internal Global
|
|
|
|
// Thread Local Storage
|
|
if (I->isThreadLocal())
|
|
Out << "__thread ";
|
|
|
|
Type *ElTy = I->getType()->getElementType();
|
|
unsigned Alignment = I->getAlignment();
|
|
bool IsOveraligned = Alignment &&
|
|
Alignment > TD->getABITypeAlignment(ElTy);
|
|
if (IsOveraligned)
|
|
Out << "__MSALIGN__(" << Alignment << ") ";
|
|
printTypeName(Out, ElTy, false) << ' ' << GetValueName(&*I);
|
|
if (IsOveraligned)
|
|
Out << " __attribute__((aligned(" << Alignment << ")))";
|
|
|
|
if (I->hasExternalWeakLinkage())
|
|
Out << " __EXTERNAL_WEAK__";
|
|
Out << ";\n";
|
|
}
|
|
}
|
|
|
|
// Function declarations
|
|
Out << "\n/* Function Declarations */\n";
|
|
|
|
// Store the intrinsics which will be declared/defined below.
|
|
SmallVector<Function*, 16> intrinsicsToDefine;
|
|
|
|
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
|
// Don't print declarations for intrinsic functions.
|
|
// Store the used intrinsics, which need to be explicitly defined.
|
|
if (I->isIntrinsic()) {
|
|
switch (I->getIntrinsicID()) {
|
|
default:
|
|
continue;
|
|
case Intrinsic::uadd_with_overflow:
|
|
case Intrinsic::sadd_with_overflow:
|
|
case Intrinsic::usub_with_overflow:
|
|
case Intrinsic::ssub_with_overflow:
|
|
case Intrinsic::umul_with_overflow:
|
|
case Intrinsic::smul_with_overflow:
|
|
case Intrinsic::bswap:
|
|
case Intrinsic::ceil:
|
|
case Intrinsic::ctlz:
|
|
case Intrinsic::ctpop:
|
|
case Intrinsic::cttz:
|
|
case Intrinsic::fabs:
|
|
case Intrinsic::floor:
|
|
case Intrinsic::fma:
|
|
case Intrinsic::fmuladd:
|
|
case Intrinsic::pow:
|
|
case Intrinsic::powi:
|
|
case Intrinsic::rint:
|
|
case Intrinsic::sqrt:
|
|
case Intrinsic::trunc:
|
|
intrinsicsToDefine.push_back(&*I);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Skip a few functions that have already been defined in headers
|
|
if (I->getName() == "setjmp" ||
|
|
I->getName() == "longjmp" ||
|
|
I->getName() == "_setjmp" ||
|
|
I->getName() == "siglongjmp" ||
|
|
I->getName() == "sigsetjmp" ||
|
|
I->getName() == "pow" ||
|
|
I->getName() == "powf" ||
|
|
I->getName() == "sqrt" ||
|
|
I->getName() == "sqrtf" ||
|
|
I->getName() == "trunc" ||
|
|
I->getName() == "truncf" ||
|
|
I->getName() == "rint" ||
|
|
I->getName() == "rintf" ||
|
|
I->getName() == "floor" ||
|
|
I->getName() == "floorf" ||
|
|
I->getName() == "ceil" ||
|
|
I->getName() == "ceilf" ||
|
|
I->getName() == "alloca" ||
|
|
I->getName() == "_alloca" ||
|
|
I->getName() == "_chkstk" ||
|
|
I->getName() == "__chkstk" ||
|
|
I->getName() == "___chkstk_ms")
|
|
continue;
|
|
|
|
if (I->hasDLLImportStorageClass())
|
|
Out << "__declspec(dllimport) ";
|
|
else if (I->hasDLLExportStorageClass())
|
|
Out << "__declspec(dllexport) ";
|
|
|
|
if (I->hasLocalLinkage())
|
|
Out << "static ";
|
|
if (I->hasExternalWeakLinkage())
|
|
Out << "extern ";
|
|
printFunctionProto(Out, &*I);
|
|
if (I->hasWeakLinkage() || I->hasLinkOnceLinkage())
|
|
Out << " __ATTRIBUTE_WEAK__";
|
|
if (I->hasExternalWeakLinkage())
|
|
Out << " __EXTERNAL_WEAK__";
|
|
if (StaticCtors.count(&*I))
|
|
Out << " __ATTRIBUTE_CTOR__";
|
|
if (StaticDtors.count(&*I))
|
|
Out << " __ATTRIBUTE_DTOR__";
|
|
if (I->hasHiddenVisibility())
|
|
Out << " __HIDDEN__";
|
|
|
|
if (I->hasName() && I->getName()[0] == 1)
|
|
Out << " __asm__ (\"" << I->getName().substr(1) << "\")";
|
|
|
|
Out << ";\n";
|
|
}
|
|
|
|
// Output the global variable definitions and contents...
|
|
if (!M.global_empty()) {
|
|
Out << "\n\n/* Global Variable Definitions and Initialization */\n";
|
|
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I) {
|
|
declareOneGlobalVariable(&*I);
|
|
}
|
|
}
|
|
|
|
// Alias declarations...
|
|
if (!M.alias_empty()) {
|
|
Out << "\n/* External Alias Declarations */\n";
|
|
for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
|
|
I != E; ++I) {
|
|
assert(!I->isDeclaration() && !isEmptyType(I->getType()->getPointerElementType()));
|
|
if (I->hasLocalLinkage())
|
|
continue; // Internal Global
|
|
|
|
if (I->hasDLLImportStorageClass())
|
|
Out << "__declspec(dllimport) ";
|
|
else if (I->hasDLLExportStorageClass())
|
|
Out << "__declspec(dllexport) ";
|
|
|
|
// Thread Local Storage
|
|
if (I->isThreadLocal())
|
|
Out << "__thread ";
|
|
|
|
Type *ElTy = I->getType()->getElementType();
|
|
unsigned Alignment = I->getAlignment();
|
|
bool IsOveraligned = Alignment &&
|
|
Alignment > TD->getABITypeAlignment(ElTy);
|
|
if (IsOveraligned)
|
|
Out << "__MSALIGN__(" << Alignment << ") ";
|
|
// GetValueName would resolve the alias, which is not what we want,
|
|
// so use getName directly instead (assuming that the Alias has a name...)
|
|
printTypeName(Out, ElTy, false) << " *" << I->getName();
|
|
if (IsOveraligned)
|
|
Out << " __attribute__((aligned(" << Alignment << ")))";
|
|
|
|
if (I->hasExternalWeakLinkage())
|
|
Out << " __EXTERNAL_WEAK__";
|
|
Out << " = ";
|
|
writeOperand(I->getAliasee(), ContextStatic);
|
|
Out << ";\n";
|
|
}
|
|
}
|
|
|
|
Out << "\n\n/* LLVM Intrinsic Builtin Function Bodies */\n";
|
|
|
|
// Emit some helper functions for dealing with FCMP instruction's
|
|
// predicates
|
|
Out << "static __forceinline int llvm_fcmp_ord(double X, double Y) { ";
|
|
Out << "return X == X && Y == Y; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_uno(double X, double Y) { ";
|
|
Out << "return X != X || Y != Y; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_ueq(double X, double Y) { ";
|
|
Out << "return X == Y || llvm_fcmp_uno(X, Y); }\n";
|
|
Out << "static __forceinline int llvm_fcmp_une(double X, double Y) { ";
|
|
Out << "return X != Y; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_ult(double X, double Y) { ";
|
|
Out << "return X < Y || llvm_fcmp_uno(X, Y); }\n";
|
|
Out << "static __forceinline int llvm_fcmp_ugt(double X, double Y) { ";
|
|
Out << "return X > Y || llvm_fcmp_uno(X, Y); }\n";
|
|
Out << "static __forceinline int llvm_fcmp_ule(double X, double Y) { ";
|
|
Out << "return X <= Y || llvm_fcmp_uno(X, Y); }\n";
|
|
Out << "static __forceinline int llvm_fcmp_uge(double X, double Y) { ";
|
|
Out << "return X >= Y || llvm_fcmp_uno(X, Y); }\n";
|
|
Out << "static __forceinline int llvm_fcmp_oeq(double X, double Y) { ";
|
|
Out << "return X == Y ; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_one(double X, double Y) { ";
|
|
Out << "return X != Y && llvm_fcmp_ord(X, Y); }\n";
|
|
Out << "static __forceinline int llvm_fcmp_olt(double X, double Y) { ";
|
|
Out << "return X < Y ; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_ogt(double X, double Y) { ";
|
|
Out << "return X > Y ; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_ole(double X, double Y) { ";
|
|
Out << "return X <= Y ; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_oge(double X, double Y) { ";
|
|
Out << "return X >= Y ; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_0(double X, double Y) { ";
|
|
Out << "return 0; }\n";
|
|
Out << "static __forceinline int llvm_fcmp_1(double X, double Y) { ";
|
|
Out << "return 1; }\n";
|
|
|
|
// Loop over all select operations
|
|
for (std::set<Type*>::iterator it = SelectDeclTypes.begin(), end = SelectDeclTypes.end();
|
|
it != end; ++it) {
|
|
// static __forceinline Rty llvm_select_u8x4(<bool x 4> condition, <u8 x 4> iftrue, <u8 x 4> ifnot) {
|
|
// Rty r = {
|
|
// condition[0] ? iftrue[0] : ifnot[0],
|
|
// condition[1] ? iftrue[1] : ifnot[1],
|
|
// condition[2] ? iftrue[2] : ifnot[2],
|
|
// condition[3] ? iftrue[3] : ifnot[3]
|
|
// };
|
|
// return r;
|
|
// }
|
|
Out << "static __forceinline ";
|
|
printTypeNameUnaligned(Out, *it, false);
|
|
Out << " llvm_select_";
|
|
printTypeString(Out, *it, false);
|
|
Out << "(";
|
|
if (isa<VectorType>(*it))
|
|
printTypeNameUnaligned(Out, VectorType::get(Type::getInt1Ty((*it)->getContext()), (*it)->getVectorNumElements()), false);
|
|
else
|
|
Out << "bool";
|
|
Out << " condition, ";
|
|
printTypeNameUnaligned(Out, *it, false);
|
|
Out << " iftrue, ";
|
|
printTypeNameUnaligned(Out, *it, false);
|
|
Out << " ifnot) {\n ";
|
|
printTypeNameUnaligned(Out, *it, false);
|
|
Out << " r;\n";
|
|
if (isa<VectorType>(*it)) {
|
|
unsigned n, l = (*it)->getVectorNumElements();
|
|
for (n = 0; n < l; n++) {
|
|
Out << " r.vector[" << n << "] = condition.vector[" << n << "] ? iftrue.vector[" << n << "] : ifnot.vector[" << n << "];\n";
|
|
}
|
|
}
|
|
else {
|
|
Out << " r = condition ? iftrue : ifnot;\n";
|
|
}
|
|
Out << " return r;\n}\n";
|
|
}
|
|
|
|
// Loop over all compare operations
|
|
for (std::set< std::pair<CmpInst::Predicate, VectorType*> >::iterator it = CmpDeclTypes.begin(), end = CmpDeclTypes.end();
|
|
it != end; ++it) {
|
|
// static __forceinline <bool x 4> llvm_icmp_ge_u8x4(<u8 x 4> l, <u8 x 4> r) {
|
|
// Rty c = {
|
|
// l[0] >= r[0],
|
|
// l[1] >= r[1],
|
|
// l[2] >= r[2],
|
|
// l[3] >= r[3],
|
|
// };
|
|
// return c;
|
|
// }
|
|
unsigned n, l = (*it).second->getVectorNumElements();
|
|
VectorType *RTy = VectorType::get(Type::getInt1Ty((*it).second->getContext()), l);
|
|
bool isSigned = CmpInst::isSigned((*it).first);
|
|
Out << "static __forceinline ";
|
|
printTypeName(Out, RTy, isSigned);
|
|
if (CmpInst::isFPPredicate((*it).first))
|
|
Out << " llvm_fcmp_";
|
|
else
|
|
Out << " llvm_icmp_";
|
|
Out << getCmpPredicateName((*it).first) << "_";
|
|
printTypeString(Out, (*it).second, isSigned);
|
|
Out << "(";
|
|
printTypeNameUnaligned(Out, (*it).second, isSigned);
|
|
Out << " l, ";
|
|
printTypeNameUnaligned(Out, (*it).second, isSigned);
|
|
Out << " r) {\n ";
|
|
printTypeName(Out, RTy, isSigned);
|
|
Out << " c;\n";
|
|
for (n = 0; n < l; n++) {
|
|
Out << " c.vector[" << n << "] = ";
|
|
if (CmpInst::isFPPredicate((*it).first)) {
|
|
Out << "llvm_fcmp_ " << getCmpPredicateName((*it).first) << "(l.vector[" << n << "], r.vector[" << n << "]);\n";
|
|
} else {
|
|
Out << "l.vector[" << n << "]";
|
|
switch ((*it).first) {
|
|
case CmpInst::ICMP_EQ: Out << " == "; break;
|
|
case CmpInst::ICMP_NE: Out << " != "; break;
|
|
case CmpInst::ICMP_ULE:
|
|
case CmpInst::ICMP_SLE: Out << " <= "; break;
|
|
case CmpInst::ICMP_UGE:
|
|
case CmpInst::ICMP_SGE: Out << " >= "; break;
|
|
case CmpInst::ICMP_ULT:
|
|
case CmpInst::ICMP_SLT: Out << " < "; break;
|
|
case CmpInst::ICMP_UGT:
|
|
case CmpInst::ICMP_SGT: Out << " > "; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid icmp predicate!" << (*it).first;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
Out << "r.vector[" << n << "];\n";
|
|
}
|
|
}
|
|
Out << " return c;\n}\n";
|
|
}
|
|
|
|
// Loop over all (vector) cast operations
|
|
for (std::set<std::pair<CastInst::CastOps, std::pair<Type*, Type*>>>::iterator it = CastOpDeclTypes.begin(), end = CastOpDeclTypes.end();
|
|
it != end; ++it) {
|
|
// static __forceinline <u32 x 4> llvm_ZExt_u8x4_u32x4(<u8 x 4> in) { // Src->isVector == Dst->isVector
|
|
// Rty out = {
|
|
// in[0],
|
|
// in[1],
|
|
// in[2],
|
|
// in[3]
|
|
// };
|
|
// return out;
|
|
// }
|
|
// static __forceinline u32 llvm_BitCast_u8x4_u32(<u8 x 4> in) { // Src->bitsSize == Dst->bitsSize
|
|
// union {
|
|
// <u8 x 4> in;
|
|
// u32 out;
|
|
// } cast;
|
|
// cast.in = in;
|
|
// return cast.out;
|
|
// }
|
|
CastInst::CastOps opcode = (*it).first;
|
|
Type *SrcTy = (*it).second.first;
|
|
Type *DstTy = (*it).second.second;
|
|
bool SrcSigned, DstSigned;
|
|
switch (opcode) {
|
|
default:
|
|
SrcSigned = false;
|
|
DstSigned = false;
|
|
case Instruction::SIToFP:
|
|
SrcSigned = true;
|
|
DstSigned = false;
|
|
case Instruction::FPToSI:
|
|
SrcSigned = false;
|
|
DstSigned = true;
|
|
case Instruction::SExt:
|
|
SrcSigned = true;
|
|
DstSigned = true;
|
|
}
|
|
|
|
Out << "static __forceinline ";
|
|
printTypeName(Out, DstTy, DstSigned);
|
|
Out << " llvm_" << Instruction::getOpcodeName(opcode) << "_";
|
|
printTypeString(Out, SrcTy, false);
|
|
Out << "_";
|
|
printTypeString(Out, DstTy, false);
|
|
Out << "(";
|
|
printTypeNameUnaligned(Out, SrcTy, SrcSigned);
|
|
Out << " in) {\n";
|
|
if (opcode == Instruction::BitCast) {
|
|
Out << " union {\n ";
|
|
printTypeName(Out, SrcTy, SrcSigned);
|
|
Out << " in;\n ";
|
|
printTypeName(Out, DstTy, DstSigned);
|
|
Out << " out;\n } cast;\n";
|
|
Out << " cast.in = in;\n return cast.out;\n}\n";
|
|
} else if (isa<VectorType>(DstTy)) {
|
|
Out << " ";
|
|
printTypeName(Out, DstTy, DstSigned);
|
|
Out << " out;\n";
|
|
unsigned n, l = DstTy->getVectorNumElements();
|
|
assert(SrcTy->getVectorNumElements() == l);
|
|
for (n = 0; n < l; n++) {
|
|
Out << " out.vector[" << n << "] = in.vector[" << n << "];\n";
|
|
}
|
|
Out << " return out;\n}\n";
|
|
} else {
|
|
Out << "#ifndef __emulate_i128\n";
|
|
// easy case first: compiler supports i128 natively
|
|
Out << " return in;\n";
|
|
Out << "#else\n";
|
|
Out << " ";
|
|
printTypeName(Out, DstTy, DstSigned);
|
|
Out << " out;\n";
|
|
Out << " LLVM";
|
|
switch (opcode) {
|
|
case Instruction::UIToFP: Out << "UItoFP"; break;
|
|
case Instruction::SIToFP: Out << "SItoFP"; break;
|
|
case Instruction::Trunc: Out << "Trunc"; break;
|
|
//case Instruction::FPExt:
|
|
//case Instruction::FPTrunc:
|
|
case Instruction::ZExt: Out << "ZExt"; break;
|
|
case Instruction::FPToUI: Out << "FPtoUI"; break;
|
|
case Instruction::SExt: Out << "SExt"; break;
|
|
case Instruction::FPToSI: Out << "FPtoSI"; break;
|
|
default:
|
|
llvm_unreachable("Invalid cast opcode for i128");
|
|
}
|
|
Out << "(" << SrcTy->getPrimitiveSizeInBits() << ", &in, "
|
|
<< DstTy->getPrimitiveSizeInBits() << ", &out);\n";
|
|
Out << " return out;\n";
|
|
Out << "#endif\n";
|
|
Out << "}\n";
|
|
}
|
|
}
|
|
|
|
// Loop over all simple vector operations
|
|
for (std::set<std::pair<unsigned, Type*>>::iterator it = InlineOpDeclTypes.begin(), end = InlineOpDeclTypes.end();
|
|
it != end; ++it) {
|
|
// static __forceinline <u32 x 4> llvm_BinOp_u32x4(<u32 x 4> a, <u32 x 4> b) {
|
|
// Rty r = {
|
|
// a[0] OP b[0],
|
|
// a[1] OP b[1],
|
|
// a[2] OP b[2],
|
|
// a[3] OP b[3],
|
|
// };
|
|
// return r;
|
|
// }
|
|
unsigned opcode = (*it).first;
|
|
Type *OpTy = (*it).second;
|
|
Type *ElemTy = isa<VectorType>(OpTy) ? OpTy->getVectorElementType() : OpTy;
|
|
bool shouldCast;
|
|
bool isSigned;
|
|
opcodeNeedsCast(opcode, shouldCast, isSigned);
|
|
|
|
Out << "static __forceinline ";
|
|
printTypeName(Out, OpTy);
|
|
if (opcode == BinaryNeg) {
|
|
Out << " llvm_neg_";
|
|
printTypeString(Out, OpTy, false);
|
|
Out << "(";
|
|
printTypeNameUnaligned(Out, OpTy, isSigned);
|
|
Out << " a) {\n ";
|
|
} else if (opcode == BinaryNot) {
|
|
Out << " llvm_not_";
|
|
printTypeString(Out, OpTy, false);
|
|
Out << "(";
|
|
printTypeNameUnaligned(Out, OpTy, isSigned);
|
|
Out << " a) {\n ";
|
|
} else {
|
|
Out << " llvm_" << Instruction::getOpcodeName(opcode) << "_";
|
|
printTypeString(Out, OpTy, false);
|
|
Out << "(";
|
|
printTypeNameUnaligned(Out, OpTy, isSigned);
|
|
Out << " a, ";
|
|
printTypeNameUnaligned(Out, OpTy, isSigned);
|
|
Out << " b) {\n ";
|
|
}
|
|
|
|
printTypeName(Out, OpTy);
|
|
// C can't handle non-power-of-two integer types
|
|
unsigned mask = 0;
|
|
if (ElemTy->isIntegerTy()) {
|
|
IntegerType *ITy = static_cast<IntegerType*>(ElemTy);
|
|
if (!ITy->isPowerOf2ByteWidth())
|
|
mask = ITy->getBitMask();
|
|
}
|
|
|
|
if (isa<VectorType>(OpTy)) {
|
|
Out << " r;\n";
|
|
unsigned n, l = OpTy->getVectorNumElements();
|
|
for (n = 0; n < l; n++) {
|
|
Out << " r.vector[" << n << "] = ";
|
|
if (mask)
|
|
Out << "(";
|
|
if (opcode == BinaryNeg) {
|
|
Out << "-a.vector[" << n << "]";
|
|
} else if (opcode == BinaryNot) {
|
|
Out << "~a.vector[" << n << "]";
|
|
} else if (opcode == Instruction::FRem) {
|
|
// Output a call to fmod/fmodf instead of emitting a%b
|
|
if (ElemTy->isFloatTy())
|
|
Out << "fmodf(a.vector[" << n << "], b.vector[" << n << "])";
|
|
else if (ElemTy->isDoubleTy())
|
|
Out << "fmod(a.vector[" << n << "], b.vector[" << n << "])";
|
|
else // all 3 flavors of long double
|
|
Out << "fmodl(a.vector[" << n << "], b.vector[" << n << "])";
|
|
} else {
|
|
Out << "a.vector[" << n << "]";
|
|
switch (opcode) {
|
|
case Instruction::Add:
|
|
case Instruction::FAdd: Out << " + "; break;
|
|
case Instruction::Sub:
|
|
case Instruction::FSub: Out << " - "; break;
|
|
case Instruction::Mul:
|
|
case Instruction::FMul: 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::Shl : Out << " << "; break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr: Out << " >> "; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid operator type!" << opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
Out << "b.vector[" << n << "]";
|
|
}
|
|
if (mask)
|
|
Out << ") & " << mask;
|
|
Out << ";\n";
|
|
}
|
|
|
|
} else if (OpTy->getPrimitiveSizeInBits() > 64) {
|
|
Out << " r;\n";
|
|
Out << "#ifndef __emulate_i128\n";
|
|
// easy case first: compiler supports i128 natively
|
|
Out << " r = ";
|
|
if (opcode == BinaryNeg) {
|
|
Out << "-a;\n";
|
|
} else if (opcode == BinaryNot) {
|
|
Out << "~a;\n";
|
|
} else {
|
|
Out << "a";
|
|
switch (opcode) {
|
|
case Instruction::Add: Out << " + "; break;
|
|
case Instruction::Sub: Out << " - "; break;
|
|
case Instruction::Mul: Out << " * "; break;
|
|
case Instruction::URem:
|
|
case Instruction::SRem: Out << " % "; break;
|
|
case Instruction::UDiv:
|
|
case Instruction::SDiv: Out << " / "; break;
|
|
case Instruction::And: Out << " & "; break;
|
|
case Instruction::Or: Out << " | "; break;
|
|
case Instruction::Xor: Out << " ^ "; break;
|
|
case Instruction::Shl: Out << " << "; break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr: Out << " >> "; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid operator type!" << opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
Out << "b;\n";
|
|
}
|
|
Out << "#else\n";
|
|
// emulated twos-complement i128 math
|
|
if (opcode == BinaryNeg) {
|
|
Out << " r.hi = ~a.hi;\n";
|
|
Out << " r.lo = ~a.lo + 1;\n";
|
|
Out << " if (r.lo == 0) r.hi += 1;\n"; // overflow: carry the one
|
|
} else if (opcode == BinaryNot) {
|
|
Out << " r.hi = ~a.hi;\n";
|
|
Out << " r.lo = ~a.lo;\n";
|
|
} else if (opcode == Instruction::And) {
|
|
Out << " r.hi = a.hi & b.hi;\n";
|
|
Out << " r.lo = a.lo & b.lo;\n";
|
|
} else if (opcode == Instruction::Or) {
|
|
Out << " r.hi = a.hi | b.hi;\n";
|
|
Out << " r.lo = a.lo | b.lo;\n";
|
|
} else if (opcode == Instruction::Xor) {
|
|
Out << " r.hi = a.hi ^ b.hi;\n";
|
|
Out << " r.lo = a.lo ^ b.lo;\n";
|
|
} else if (opcode == Instruction::Shl) { // reminder: undef behavior if b >= 128
|
|
Out << " if (b.lo >= 64) {\n";
|
|
Out << " r.hi = (a.lo << (b.lo - 64));\n";
|
|
Out << " r.lo = 0;\n";
|
|
Out << " } else if (b.lo == 0) {\n";
|
|
Out << " r.hi = a.hi;\n";
|
|
Out << " r.lo = a.lo;\n";
|
|
Out << " } else {\n";
|
|
Out << " r.hi = (a.hi << b.lo) | (a.lo >> (64 - b.lo));\n";
|
|
Out << " r.lo = a.lo << b.lo;\n";
|
|
Out << " }\n";
|
|
} else {
|
|
// everything that hasn't been manually implemented above
|
|
Out << " LLVM";
|
|
switch (opcode) {
|
|
//case BinaryNeg: Out << "Neg"; break;
|
|
//case BinaryNot: Out << "FlipAllBits"; break;
|
|
case Instruction::Add: Out << "Add"; break;
|
|
case Instruction::Sub: Out << "Sub"; break;
|
|
case Instruction::Mul: Out << "Mul"; break;
|
|
case Instruction::URem: Out << "URem"; break;
|
|
case Instruction::SRem: Out << "SRem"; break;
|
|
case Instruction::UDiv: Out << "UDiv"; break;
|
|
case Instruction::SDiv: Out << "SDiv"; break;
|
|
//case Instruction::And: Out << "And"; break;
|
|
//case Instruction::Or: Out << "Or"; break;
|
|
//case Instruction::Xor: Out << "Xor"; break;
|
|
//case Instruction::Shl: Out << "Shl"; break;
|
|
case Instruction::LShr: Out << "LShr"; break;
|
|
case Instruction::AShr: Out << "AShr"; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid operator type!" << opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
Out << "(16, &a, &b, &r);\n";
|
|
}
|
|
Out << "#endif\n";
|
|
|
|
} else {
|
|
Out << " r = ";
|
|
if (mask)
|
|
Out << "(";
|
|
if (opcode == BinaryNeg) {
|
|
Out << "-a";
|
|
} else if (opcode == BinaryNot) {
|
|
Out << "~a";
|
|
} else if (opcode == Instruction::FRem) {
|
|
// Output a call to fmod/fmodf instead of emitting a%b
|
|
if (ElemTy->isFloatTy())
|
|
Out << "fmodf(a, b)";
|
|
else if (ElemTy->isDoubleTy())
|
|
Out << "fmod(a, b)";
|
|
else // all 3 flavors of long double
|
|
Out << "fmodl(a, b)";
|
|
} else {
|
|
Out << "a";
|
|
switch (opcode) {
|
|
case Instruction::Add:
|
|
case Instruction::FAdd: Out << " + "; break;
|
|
case Instruction::Sub:
|
|
case Instruction::FSub: Out << " - "; break;
|
|
case Instruction::Mul:
|
|
case Instruction::FMul: 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::Shl : Out << " << "; break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr: Out << " >> "; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid operator type!" << opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
Out << "b";
|
|
if (mask)
|
|
Out << ") & " << mask;
|
|
}
|
|
Out << ";\n";
|
|
}
|
|
Out << " return r;\n}\n";
|
|
}
|
|
|
|
// Loop over all inline constructors
|
|
for (std::set<Type*>::iterator it = CtorDeclTypes.begin(), end = CtorDeclTypes.end();
|
|
it != end; ++it) {
|
|
// static __forceinline <u32 x 4> llvm_ctor_u32x4(u32 x1, u32 x2, u32 x3, u32 x4) {
|
|
// Rty r = {
|
|
// x1, x2, x3, x4
|
|
// };
|
|
// return r;
|
|
// }
|
|
Out << "static __forceinline ";
|
|
printTypeName(Out, *it);
|
|
Out << " llvm_ctor_";
|
|
printTypeString(Out, *it, false);
|
|
Out << "(";
|
|
StructType *STy = dyn_cast<StructType>(*it);
|
|
ArrayType *ATy = dyn_cast<ArrayType>(*it);
|
|
VectorType *VTy = dyn_cast<VectorType>(*it);
|
|
unsigned e = (STy ? STy->getNumElements() : (ATy ? ATy->getNumElements() : VTy->getNumElements()));
|
|
bool printed = false;
|
|
for (unsigned i = 0; i != e; ++i) {
|
|
Type *ElTy = STy ? STy->getElementType(i) : (*it)->getSequentialElementType();
|
|
if (isEmptyType(ElTy))
|
|
Out << " /* ";
|
|
else if (printed)
|
|
Out << ", ";
|
|
printTypeNameUnaligned(Out, ElTy);
|
|
Out << " x" << i;
|
|
if (isEmptyType(ElTy))
|
|
Out << " */";
|
|
else
|
|
printed = true;
|
|
}
|
|
Out << ") {\n ";
|
|
printTypeName(Out, *it);
|
|
Out << " r;";
|
|
for (unsigned i = 0; i != e; ++i) {
|
|
Type *ElTy = STy ? STy->getElementType(i) : (*it)->getSequentialElementType();
|
|
if (isEmptyType(ElTy))
|
|
continue;
|
|
if (STy)
|
|
Out << "\n r.field" << i << " = x" << i << ";";
|
|
else if (ATy)
|
|
Out << "\n r.array[" << i << "] = x" << i << ";";
|
|
else if (VTy)
|
|
Out << "\n r.vector[" << i << "] = x" << i << ";";
|
|
else
|
|
assert(0);
|
|
}
|
|
Out << "\n return r;\n}\n";
|
|
}
|
|
|
|
// Emit definitions of the intrinsics.
|
|
for (SmallVector<Function*, 16>::iterator
|
|
I = intrinsicsToDefine.begin(),
|
|
E = intrinsicsToDefine.end(); I != E; ++I) {
|
|
printIntrinsicDefinition(**I, Out);
|
|
}
|
|
|
|
if (!M.empty())
|
|
Out << "\n\n/* Function Bodies */\n";
|
|
}
|
|
|
|
void CWriter::declareOneGlobalVariable(GlobalVariable* I) {
|
|
if (I->isDeclaration() || isEmptyType(I->getType()->getPointerElementType()))
|
|
return;
|
|
|
|
// Ignore special globals, such as debug info.
|
|
if (getGlobalVariableClass(&*I))
|
|
return;
|
|
|
|
if (I->hasDLLImportStorageClass())
|
|
Out << "__declspec(dllimport) ";
|
|
else if (I->hasDLLExportStorageClass())
|
|
Out << "__declspec(dllexport) ";
|
|
|
|
if (I->hasLocalLinkage())
|
|
Out << "static ";
|
|
|
|
// Thread Local Storage
|
|
if (I->isThreadLocal())
|
|
Out << "__thread ";
|
|
|
|
Type *ElTy = I->getType()->getElementType();
|
|
unsigned Alignment = I->getAlignment();
|
|
bool IsOveraligned = Alignment &&
|
|
Alignment > TD->getABITypeAlignment(ElTy);
|
|
if (IsOveraligned)
|
|
Out << "__MSALIGN__(" << Alignment << ") ";
|
|
printTypeName(Out, ElTy, false) << ' ' << GetValueName(I);
|
|
if (IsOveraligned)
|
|
Out << " __attribute__((aligned(" << Alignment << ")))";
|
|
|
|
if (I->hasLinkOnceLinkage())
|
|
Out << " __attribute__((common))";
|
|
else if (I->hasWeakLinkage())
|
|
Out << " __ATTRIBUTE_WEAK__";
|
|
else if (I->hasCommonLinkage())
|
|
Out << " __ATTRIBUTE_WEAK__";
|
|
|
|
if (I->hasHiddenVisibility())
|
|
Out << " __HIDDEN__";
|
|
|
|
// If the initializer is not null, emit the initializer. If it is null,
|
|
// we try to avoid emitting large amounts of zeros. The problem with
|
|
// this, however, occurs when the variable has weak linkage. In this
|
|
// case, the assembler will complain about the variable being both weak
|
|
// and common, so we disable this optimization.
|
|
// FIXME common linkage should avoid this problem.
|
|
if (!I->getInitializer()->isNullValue()) {
|
|
Out << " = " ;
|
|
writeOperand(I->getInitializer(), ContextStatic);
|
|
} else if (I->hasWeakLinkage()) {
|
|
// We have to specify an initializer, but it doesn't have to be
|
|
// complete. If the value is an aggregate, print out { 0 }, and let
|
|
// the compiler figure out the rest of the zeros.
|
|
Out << " = " ;
|
|
if (I->getInitializer()->getType()->isStructTy() ||
|
|
I->getInitializer()->getType()->isVectorTy()) {
|
|
Out << "{ 0 }";
|
|
} else if (I->getInitializer()->getType()->isArrayTy()) {
|
|
// As with structs and vectors, but with an extra set of braces
|
|
// because arrays are wrapped in structs.
|
|
Out << "{ { 0 } }";
|
|
} else {
|
|
// Just print it out normally.
|
|
writeOperand(I->getInitializer(), ContextStatic);
|
|
}
|
|
}
|
|
Out << ";\n";
|
|
}
|
|
|
|
/// Output all floating point constants that cannot be printed accurately...
|
|
void CWriter::printFloatingPointConstants(Function &F) {
|
|
// Scan the module for floating point constants. If any FP constant is used
|
|
// in the function, we want to redirect it here so that we do not depend on
|
|
// the precision of the printed form, unless the printed form preserves
|
|
// precision.
|
|
//
|
|
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I)
|
|
for (Instruction::op_iterator I_Op = I->op_begin(), E_Op = I->op_end(); I_Op != E_Op; ++I_Op)
|
|
if (const Constant *C = dyn_cast<Constant>(I_Op))
|
|
printFloatingPointConstants(C);
|
|
Out << '\n';
|
|
}
|
|
|
|
void CWriter::printFloatingPointConstants(const Constant *C) {
|
|
// If this is a constant expression, recursively check for constant fp values.
|
|
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
|
|
for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i)
|
|
printFloatingPointConstants(CE->getOperand(i));
|
|
return;
|
|
}
|
|
|
|
// Otherwise, check for a FP constant that we need to print.
|
|
const ConstantFP *FPC = dyn_cast<ConstantFP>(C);
|
|
if (FPC == 0 ||
|
|
// Do not put in FPConstantMap if safe.
|
|
isFPCSafeToPrint(FPC) ||
|
|
// Already printed this constant?
|
|
FPConstantMap.count(FPC))
|
|
return;
|
|
|
|
FPConstantMap[FPC] = FPCounter; // Number the FP constants
|
|
|
|
if (FPC->getType() == Type::getDoubleTy(FPC->getContext())) {
|
|
double Val = FPC->getValueAPF().convertToDouble();
|
|
uint64_t i = FPC->getValueAPF().bitcastToAPInt().getZExtValue();
|
|
Out << "static const ConstantDoubleTy FPConstant" << FPCounter++
|
|
<< " = 0x" << utohexstr(i)
|
|
<< "ULL; /* " << Val << " */\n";
|
|
} else if (FPC->getType() == Type::getFloatTy(FPC->getContext())) {
|
|
float Val = FPC->getValueAPF().convertToFloat();
|
|
uint32_t i = (uint32_t)FPC->getValueAPF().bitcastToAPInt().
|
|
getZExtValue();
|
|
Out << "static const ConstantFloatTy FPConstant" << FPCounter++
|
|
<< " = 0x" << utohexstr(i)
|
|
<< "U; /* " << Val << " */\n";
|
|
} else if (FPC->getType() == Type::getX86_FP80Ty(FPC->getContext())) {
|
|
// api needed to prevent premature destruction
|
|
const APInt api = FPC->getValueAPF().bitcastToAPInt();
|
|
const uint64_t *p = api.getRawData();
|
|
Out << "static const ConstantFP80Ty FPConstant" << FPCounter++
|
|
<< " = { 0x" << utohexstr(p[0])
|
|
<< "ULL, 0x" << utohexstr((uint16_t)p[1]) << ",{0,0,0}"
|
|
<< "}; /* Long double constant */\n";
|
|
} else if (FPC->getType() == Type::getPPC_FP128Ty(FPC->getContext()) ||
|
|
FPC->getType() == Type::getFP128Ty(FPC->getContext())) {
|
|
const APInt api = FPC->getValueAPF().bitcastToAPInt();
|
|
const uint64_t *p = api.getRawData();
|
|
Out << "static const ConstantFP128Ty FPConstant" << FPCounter++
|
|
<< " = { 0x"
|
|
<< utohexstr(p[0]) << ", 0x" << utohexstr(p[1])
|
|
<< "}; /* Long double constant */\n";
|
|
|
|
} else {
|
|
llvm_unreachable("Unknown float type!");
|
|
}
|
|
}
|
|
|
|
|
|
/// printSymbolTable - Run through symbol table looking for type names. If a
|
|
/// type name is found, emit its declaration...
|
|
///
|
|
void CWriter::printModuleTypes(raw_ostream &Out) {
|
|
Out << "/* Helper union for bitcasts */\n";
|
|
Out << "typedef union {\n";
|
|
Out << " uint32_t Int32;\n";
|
|
Out << " uint64_t Int64;\n";
|
|
Out << " float Float;\n";
|
|
Out << " double Double;\n";
|
|
Out << "} llvmBitCastUnion;\n";
|
|
|
|
// Keep track of which types have been printed so far.
|
|
std::set<Type*> TypesPrinted;
|
|
|
|
// Loop over all structures then push them into the stack so they are
|
|
// printed in the correct order.
|
|
Out << "\n/* Types Declarations */\n";
|
|
|
|
// forward-declare all structs here first
|
|
|
|
{
|
|
std::set<Type*> TypesPrinted;
|
|
for (auto it = TypedefDeclTypes.begin(), end = TypedefDeclTypes.end(); it != end; ++it) {
|
|
forwardDeclareStructs(Out, *it, TypesPrinted);
|
|
}
|
|
}
|
|
|
|
// forward-declare all function pointer typedefs (Issue #2)
|
|
|
|
{
|
|
std::set<Type*> TypesPrinted;
|
|
for (auto it = TypedefDeclTypes.begin(), end = TypedefDeclTypes.end(); it != end; ++it) {
|
|
forwardDeclareFunctionTypedefs(Out, *it, TypesPrinted);
|
|
}
|
|
}
|
|
|
|
|
|
Out << "\n/* Types Definitions */\n";
|
|
|
|
for (auto it = TypedefDeclTypes.begin(), end = TypedefDeclTypes.end(); it != end; ++it) {
|
|
printContainedTypes(Out, *it, TypesPrinted);
|
|
}
|
|
|
|
Out << "\n/* Function definitions */\n";
|
|
|
|
for (DenseMap<std::pair<FunctionType*, std::pair<AttributeList, CallingConv::ID> >, unsigned>::iterator
|
|
I = UnnamedFunctionIDs.begin(), E = UnnamedFunctionIDs.end();
|
|
I != E; ++I) {
|
|
Out << '\n';
|
|
std::pair<FunctionType*, std::pair<AttributeList, CallingConv::ID> > F = I->first;
|
|
if (F.second.first == AttributeList() && F.second.second == CallingConv::C)
|
|
if (!TypesPrinted.insert(F.first).second) continue; // already printed this above
|
|
printFunctionDeclaration(Out, F.first, F.second);
|
|
}
|
|
|
|
// We may have collected some intrinsic prototypes to emit.
|
|
// Emit them now, before the function that uses them is emitted
|
|
for (std::vector<Function*>::iterator
|
|
I = prototypesToGen.begin(), E = prototypesToGen.end();
|
|
I != E; ++I) {
|
|
Out << '\n';
|
|
Function *F = *I;
|
|
printFunctionProto(Out, F);
|
|
Out << ";\n";
|
|
}
|
|
}
|
|
|
|
void CWriter::forwardDeclareStructs(raw_ostream &Out, Type *Ty, std::set<Type*> &TypesPrinted) {
|
|
if (!TypesPrinted.insert(Ty).second) return;
|
|
if (isEmptyType(Ty)) return;
|
|
|
|
for (auto I = Ty->subtype_begin(); I != Ty->subtype_end(); ++I) {
|
|
forwardDeclareStructs(Out, *I, TypesPrinted);
|
|
}
|
|
|
|
if (StructType *ST = dyn_cast<StructType>(Ty)) {
|
|
Out << getStructName(ST) << ";\n";
|
|
}
|
|
}
|
|
|
|
void CWriter::forwardDeclareFunctionTypedefs(raw_ostream &Out, Type *Ty, std::set<Type*> &TypesPrinted) {
|
|
if (!TypesPrinted.insert(Ty).second) return;
|
|
if (isEmptyType(Ty)) return;
|
|
|
|
for (auto I = Ty->subtype_begin(); I != Ty->subtype_end(); ++I) {
|
|
forwardDeclareFunctionTypedefs(Out, *I, TypesPrinted);
|
|
}
|
|
|
|
if (FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
|
|
printFunctionDeclaration(Out, FT);
|
|
}
|
|
}
|
|
|
|
// Push the struct onto the stack and recursively push all structs
|
|
// this one depends on.
|
|
//
|
|
void CWriter::printContainedTypes(raw_ostream &Out, Type *Ty,
|
|
std::set<Type*> &TypesPrinted) {
|
|
// Check to see if we have already printed this struct.
|
|
if (!TypesPrinted.insert(Ty).second) return;
|
|
// Skip empty structs
|
|
if (isEmptyType(Ty)) return;
|
|
|
|
// Print all contained types first.
|
|
for (Type::subtype_iterator I = Ty->subtype_begin(),
|
|
E = Ty->subtype_end(); I != E; ++I)
|
|
printContainedTypes(Out, *I, TypesPrinted);
|
|
|
|
if (StructType *ST = dyn_cast<StructType>(Ty)) {
|
|
// Print structure type out.
|
|
printStructDeclaration(Out, ST);
|
|
} else if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
|
|
// Print array type out.
|
|
printArrayDeclaration(Out, AT);
|
|
} else if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
|
|
// Print vector type out.
|
|
printVectorDeclaration(Out, VT);
|
|
}
|
|
}
|
|
|
|
static inline bool isFPIntBitCast(Instruction &I) {
|
|
if (!isa<BitCastInst>(I))
|
|
return false;
|
|
Type *SrcTy = I.getOperand(0)->getType();
|
|
Type *DstTy = I.getType();
|
|
return (SrcTy->isFloatingPointTy() && DstTy->isIntegerTy()) ||
|
|
(DstTy->isFloatingPointTy() && SrcTy->isIntegerTy());
|
|
}
|
|
|
|
void CWriter::printFunction(Function &F) {
|
|
/// isStructReturn - Should this function actually return a struct by-value?
|
|
bool isStructReturn = F.hasStructRetAttr();
|
|
|
|
assert(!F.isDeclaration());
|
|
if (F.hasDLLImportStorageClass()) Out << "__declspec(dllimport) ";
|
|
if (F.hasDLLExportStorageClass()) Out << "__declspec(dllexport) ";
|
|
if (F.hasLocalLinkage()) Out << "static ";
|
|
|
|
iterator_range<Function::arg_iterator> args = F.args();
|
|
printFunctionProto(Out, F.getFunctionType(), std::make_pair(F.getAttributes(), F.getCallingConv()), GetValueName(&F), &args);
|
|
|
|
Out << " {\n";
|
|
|
|
// If this is a struct return function, handle the result with magic.
|
|
if (isStructReturn) {
|
|
Type *StructTy =
|
|
cast<PointerType>(F.arg_begin()->getType())->getElementType();
|
|
Out << " ";
|
|
printTypeName(Out, StructTy, false) << " StructReturn; /* Struct return temporary */\n";
|
|
|
|
Out << " ";
|
|
printTypeName(Out, F.arg_begin()->getType(), false);
|
|
Out << GetValueName(F.arg_begin()) << " = &StructReturn;\n";
|
|
}
|
|
|
|
bool PrintedVar = false;
|
|
|
|
// print local variable information for the function
|
|
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) {
|
|
if (AllocaInst *AI = isDirectAlloca(&*I)) {
|
|
unsigned Alignment = AI->getAlignment();
|
|
bool IsOveraligned = Alignment &&
|
|
Alignment > TD->getABITypeAlignment(AI->getAllocatedType());
|
|
Out << " ";
|
|
if (IsOveraligned)
|
|
Out << "__MSALIGN__(" << Alignment << ") ";
|
|
printTypeName(Out, AI->getAllocatedType(), false) << ' ';
|
|
Out << GetValueName(AI);
|
|
if (IsOveraligned)
|
|
Out << " __attribute__((aligned(" << Alignment << ")))";
|
|
Out << "; /* Address-exposed local */\n";
|
|
PrintedVar = true;
|
|
} else if (!isEmptyType(I->getType()) &&
|
|
!isInlinableInst(*I)) {
|
|
Out << " ";
|
|
printTypeName(Out, I->getType(), false) << ' ' << GetValueName(&*I);
|
|
Out << ";\n";
|
|
|
|
if (isa<PHINode>(*I)) { // Print out PHI node temporaries as well...
|
|
Out << " ";
|
|
printTypeName(Out, I->getType(), false) << ' ' << (GetValueName(&*I)+"__PHI_TEMPORARY");
|
|
Out << ";\n";
|
|
}
|
|
PrintedVar = true;
|
|
}
|
|
// We need a temporary for the BitCast to use so it can pluck a value out
|
|
// of a union to do the BitCast. This is separate from the need for a
|
|
// variable to hold the result of the BitCast.
|
|
if (isFPIntBitCast(*I)) {
|
|
Out << " llvmBitCastUnion " << GetValueName(&*I)
|
|
<< "__BITCAST_TEMPORARY;\n";
|
|
PrintedVar = true;
|
|
}
|
|
}
|
|
|
|
if (PrintedVar)
|
|
Out << '\n';
|
|
|
|
// print the basic blocks
|
|
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
|
|
if (Loop *L = LI->getLoopFor(&*BB)) {
|
|
if (L->getHeader() == &*BB && L->getParentLoop() == 0)
|
|
printLoop(L);
|
|
} else {
|
|
printBasicBlock(&*BB);
|
|
}
|
|
}
|
|
|
|
Out << "}\n\n";
|
|
}
|
|
|
|
void CWriter::printLoop(Loop *L) {
|
|
Out << " do { /* Syntactic loop '" << L->getHeader()->getName()
|
|
<< "' to make GCC happy */\n";
|
|
for (unsigned i = 0, e = L->getBlocks().size(); i != e; ++i) {
|
|
BasicBlock *BB = L->getBlocks()[i];
|
|
Loop *BBLoop = LI->getLoopFor(BB);
|
|
if (BBLoop == L)
|
|
printBasicBlock(BB);
|
|
else if (BB == BBLoop->getHeader() && BBLoop->getParentLoop() == L)
|
|
printLoop(BBLoop);
|
|
}
|
|
Out << " } while (1); /* end of syntactic loop '"
|
|
<< L->getHeader()->getName() << "' */\n";
|
|
}
|
|
|
|
void CWriter::printBasicBlock(BasicBlock *BB) {
|
|
|
|
// Don't print the label for the basic block if there are no uses, or if
|
|
// the only terminator use is the predecessor basic block's terminator.
|
|
// We have to scan the use list because PHI nodes use basic blocks too but
|
|
// do not require a label to be generated.
|
|
//
|
|
bool NeedsLabel = false;
|
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
|
|
if (isGotoCodeNecessary(*PI, BB)) {
|
|
NeedsLabel = true;
|
|
break;
|
|
}
|
|
|
|
if (NeedsLabel) Out << GetValueName(BB) << ":\n";
|
|
|
|
// Output all of the instructions in the basic block...
|
|
for (BasicBlock::iterator II = BB->begin(), E = --BB->end(); II != E;
|
|
++II) {
|
|
if (!isInlinableInst(*II) && !isDirectAlloca(&*II)) {
|
|
if (!isEmptyType(II->getType()) &&
|
|
!isInlineAsm(*II))
|
|
outputLValue(&*II);
|
|
|
|
else
|
|
Out << " ";
|
|
writeInstComputationInline(*II);
|
|
Out << ";\n";
|
|
}
|
|
}
|
|
|
|
// Don't emit prefix or suffix for the terminator.
|
|
visit(*BB->getTerminator());
|
|
}
|
|
|
|
|
|
// Specific Instruction type classes... note that all of the casts are
|
|
// necessary because we use the instruction classes as opaque types...
|
|
//
|
|
void CWriter::visitReturnInst(ReturnInst &I) {
|
|
// If this is a struct return function, return the temporary struct.
|
|
bool isStructReturn = I.getParent()->getParent()->hasStructRetAttr();
|
|
|
|
if (isStructReturn) {
|
|
Out << " return StructReturn;\n";
|
|
return;
|
|
}
|
|
|
|
// Don't output a void return if this is the last basic block in the function
|
|
// unless that would make the basic block empty
|
|
if (I.getNumOperands() == 0 &&
|
|
&*--I.getParent()->getParent()->end() == I.getParent() &&
|
|
&*I.getParent()->begin() != &I) {
|
|
return;
|
|
}
|
|
|
|
Out << " return";
|
|
if (I.getNumOperands()) {
|
|
Out << ' ';
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
}
|
|
Out << ";\n";
|
|
}
|
|
|
|
void CWriter::visitSwitchInst(SwitchInst &SI) {
|
|
Value* Cond = SI.getCondition();
|
|
unsigned NumBits = cast<IntegerType>(Cond->getType())->getBitWidth();
|
|
|
|
if (SI.getNumCases() == 0) { // unconditional branch
|
|
printPHICopiesForSuccessor (SI.getParent(), SI.getDefaultDest(), 2);
|
|
printBranchToBlock(SI.getParent(), SI.getDefaultDest(), 2);
|
|
Out << "\n";
|
|
|
|
} else if (NumBits <= 64) { // model as a switch statement
|
|
Out << " switch (";
|
|
writeOperand(Cond);
|
|
Out << ") {\n default:\n";
|
|
printPHICopiesForSuccessor (SI.getParent(), SI.getDefaultDest(), 2);
|
|
printBranchToBlock(SI.getParent(), SI.getDefaultDest(), 2);
|
|
|
|
// Skip the first item since that's the default case.
|
|
for (SwitchInst::CaseIt i = SI.case_begin(), e = SI.case_end(); i != e; ++i) {
|
|
ConstantInt* CaseVal = i->getCaseValue();
|
|
BasicBlock* Succ = i->getCaseSuccessor();
|
|
Out << " case ";
|
|
writeOperand(CaseVal);
|
|
Out << ":\n";
|
|
printPHICopiesForSuccessor (SI.getParent(), Succ, 2);
|
|
if (isGotoCodeNecessary(SI.getParent(), Succ))
|
|
printBranchToBlock(SI.getParent(), Succ, 2);
|
|
else
|
|
Out << " break;\n";
|
|
}
|
|
Out << " }\n";
|
|
|
|
} else { // model as a series of if statements
|
|
Out << " ";
|
|
for (SwitchInst::CaseIt i = SI.case_begin(), e = SI.case_end(); i != e; ++i) {
|
|
Out << "if (";
|
|
ConstantInt* CaseVal = i->getCaseValue();
|
|
BasicBlock* Succ = i->getCaseSuccessor();
|
|
ICmpInst *icmp = new ICmpInst(CmpInst::ICMP_EQ, Cond, CaseVal);
|
|
visitICmpInst(*icmp);
|
|
delete icmp;
|
|
Out << ") {\n";
|
|
printPHICopiesForSuccessor (SI.getParent(), Succ, 2);
|
|
printBranchToBlock(SI.getParent(), Succ, 2);
|
|
Out << " } else ";
|
|
}
|
|
Out << "{\n";
|
|
printPHICopiesForSuccessor (SI.getParent(), SI.getDefaultDest(), 2);
|
|
printBranchToBlock(SI.getParent(), SI.getDefaultDest(), 2);
|
|
Out << " }\n";
|
|
}
|
|
Out << "\n";
|
|
}
|
|
|
|
void CWriter::visitIndirectBrInst(IndirectBrInst &IBI) {
|
|
Out << " goto *(void*)(";
|
|
writeOperand(IBI.getOperand(0));
|
|
Out << ");\n";
|
|
}
|
|
|
|
void CWriter::visitUnreachableInst(UnreachableInst &I) {
|
|
Out << " __builtin_unreachable();\n\n";
|
|
}
|
|
|
|
bool CWriter::isGotoCodeNecessary(BasicBlock *From, BasicBlock *To) {
|
|
/// FIXME: This should be reenabled, but loop reordering safe!!
|
|
return true;
|
|
|
|
if (std::next(Function::iterator(From)) != Function::iterator(To))
|
|
return true; // Not the direct successor, we need a goto.
|
|
|
|
//isa<SwitchInst>(From->getTerminator())
|
|
|
|
if (LI->getLoopFor(From) != LI->getLoopFor(To))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void CWriter::printPHICopiesForSuccessor (BasicBlock *CurBlock,
|
|
BasicBlock *Successor,
|
|
unsigned Indent) {
|
|
for (BasicBlock::iterator I = Successor->begin(); isa<PHINode>(I); ++I) {
|
|
PHINode *PN = cast<PHINode>(I);
|
|
// Now we have to do the printing.
|
|
Value *IV = PN->getIncomingValueForBlock(CurBlock);
|
|
if (!isa<UndefValue>(IV) && !isEmptyType(IV->getType())) {
|
|
Out << std::string(Indent, ' ');
|
|
Out << " " << GetValueName(&*I) << "__PHI_TEMPORARY = ";
|
|
writeOperand(IV, ContextCasted);
|
|
Out << "; /* for PHI node */\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWriter::printBranchToBlock(BasicBlock *CurBB, BasicBlock *Succ,
|
|
unsigned Indent) {
|
|
if (isGotoCodeNecessary(CurBB, Succ)) {
|
|
Out << std::string(Indent, ' ') << " goto ";
|
|
writeOperand(Succ);
|
|
Out << ";\n";
|
|
}
|
|
}
|
|
|
|
// Branch instruction printing - Avoid printing out a branch to a basic block
|
|
// that immediately succeeds the current one.
|
|
//
|
|
void CWriter::visitBranchInst(BranchInst &I) {
|
|
|
|
if (I.isConditional()) {
|
|
if (isGotoCodeNecessary(I.getParent(), I.getSuccessor(0))) {
|
|
Out << " if (";
|
|
writeOperand(I.getCondition(), ContextCasted);
|
|
Out << ") {\n";
|
|
|
|
printPHICopiesForSuccessor (I.getParent(), I.getSuccessor(0), 2);
|
|
printBranchToBlock(I.getParent(), I.getSuccessor(0), 2);
|
|
|
|
if (isGotoCodeNecessary(I.getParent(), I.getSuccessor(1))) {
|
|
Out << " } else {\n";
|
|
printPHICopiesForSuccessor (I.getParent(), I.getSuccessor(1), 2);
|
|
printBranchToBlock(I.getParent(), I.getSuccessor(1), 2);
|
|
}
|
|
} else {
|
|
// First goto not necessary, assume second one is...
|
|
Out << " if (!";
|
|
writeOperand(I.getCondition(), ContextCasted);
|
|
Out << ") {\n";
|
|
|
|
printPHICopiesForSuccessor (I.getParent(), I.getSuccessor(1), 2);
|
|
printBranchToBlock(I.getParent(), I.getSuccessor(1), 2);
|
|
}
|
|
|
|
Out << " }\n";
|
|
} else {
|
|
printPHICopiesForSuccessor (I.getParent(), I.getSuccessor(0), 0);
|
|
printBranchToBlock(I.getParent(), I.getSuccessor(0), 0);
|
|
}
|
|
Out << "\n";
|
|
}
|
|
|
|
// PHI nodes get copied into temporary values at the end of predecessor basic
|
|
// blocks. We now need to copy these temporary values into the REAL value for
|
|
// the PHI.
|
|
void CWriter::visitPHINode(PHINode &I) {
|
|
writeOperand(&I);
|
|
Out << "__PHI_TEMPORARY";
|
|
}
|
|
|
|
void CWriter::visitBinaryOperator(BinaryOperator &I) {
|
|
// binary instructions, shift instructions, setCond instructions.
|
|
assert(!I.getType()->isPointerTy());
|
|
|
|
// We must cast the results of binary operations which might be promoted.
|
|
bool needsCast = false;
|
|
if ((I.getType() == Type::getInt8Ty(I.getContext())) ||
|
|
(I.getType() == Type::getInt16Ty(I.getContext()))
|
|
|| (I.getType() == Type::getFloatTy(I.getContext()))) {
|
|
// types too small to work with directly
|
|
needsCast = true;
|
|
} else if (I.getType()->getPrimitiveSizeInBits() > 64) {
|
|
// types too big to work with directly
|
|
needsCast = true;
|
|
}
|
|
bool shouldCast;
|
|
bool castIsSigned;
|
|
opcodeNeedsCast(I.getOpcode(), shouldCast, castIsSigned);
|
|
|
|
if (I.getType()->isVectorTy() || needsCast || shouldCast) {
|
|
Type *VTy = I.getOperand(0)->getType();
|
|
unsigned opcode;
|
|
if (BinaryOperator::isNeg(&I)) {
|
|
opcode = BinaryNeg;
|
|
Out << "llvm_neg_";
|
|
printTypeString(Out, VTy, false);
|
|
Out << "(";
|
|
writeOperand(BinaryOperator::getNegArgument(&I), ContextCasted);
|
|
} else if (BinaryOperator::isFNeg(&I)) {
|
|
opcode = BinaryNeg;
|
|
Out << "llvm_neg_";
|
|
printTypeString(Out, VTy, false);
|
|
Out << "(";
|
|
writeOperand(BinaryOperator::getFNegArgument(&I), ContextCasted);
|
|
} else if (BinaryOperator::isNot(&I)) {
|
|
opcode = BinaryNot;
|
|
Out << "llvm_not_";
|
|
printTypeString(Out, VTy, false);
|
|
Out << "(";
|
|
writeOperand(BinaryOperator::getNotArgument(&I), ContextCasted);
|
|
} else {
|
|
opcode = I.getOpcode();
|
|
Out << "llvm_" << Instruction::getOpcodeName(opcode) << "_";
|
|
printTypeString(Out, VTy, false);
|
|
Out << "(";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getOperand(1), ContextCasted);
|
|
}
|
|
Out << ")";
|
|
InlineOpDeclTypes.insert(std::pair<unsigned, Type*>(opcode, VTy));
|
|
return;
|
|
}
|
|
|
|
// If this is a negation operation, print it out as such. For FP, we don't
|
|
// want to print "-0.0 - X".
|
|
if (BinaryOperator::isNeg(&I)) {
|
|
Out << "-(";
|
|
writeOperand(BinaryOperator::getNegArgument(&I));
|
|
Out << ")";
|
|
} else if (BinaryOperator::isFNeg(&I)) {
|
|
Out << "-(";
|
|
writeOperand(BinaryOperator::getFNegArgument(&I));
|
|
Out << ")";
|
|
} else if (BinaryOperator::isNot(&I)) {
|
|
Out << "~(";
|
|
writeOperand(BinaryOperator::getNotArgument(&I));
|
|
Out << ")";
|
|
} else if (I.getOpcode() == Instruction::FRem) {
|
|
// Output a call to fmod/fmodf instead of emitting a%b
|
|
if (I.getType() == Type::getFloatTy(I.getContext()))
|
|
Out << "fmodf(";
|
|
else if (I.getType() == Type::getDoubleTy(I.getContext()))
|
|
Out << "fmod(";
|
|
else // all 3 flavors of long double
|
|
Out << "fmodl(";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getOperand(1), ContextCasted);
|
|
Out << ")";
|
|
} else {
|
|
|
|
// 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:
|
|
case Instruction::FAdd: Out << " + "; break;
|
|
case Instruction::Sub:
|
|
case Instruction::FSub: Out << " - "; break;
|
|
case Instruction::Mul:
|
|
case Instruction::FMul: 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::Shl : Out << " << "; break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr: Out << " >> "; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid operator type!" << I;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
|
|
writeOperandWithCast(I.getOperand(1), I.getOpcode());
|
|
if (NeedsClosingParens)
|
|
Out << "))";
|
|
}
|
|
}
|
|
|
|
void CWriter::visitICmpInst(ICmpInst &I) {
|
|
if (I.getType()->isVectorTy()
|
|
|| I.getOperand(0)->getType()->getPrimitiveSizeInBits() > 64) {
|
|
Out << "llvm_icmp_" << getCmpPredicateName(I.getPredicate()) << "_";
|
|
printTypeString(Out, I.getOperand(0)->getType(), I.isSigned());
|
|
Out << "(";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getOperand(1), ContextCasted);
|
|
Out << ")";
|
|
if (VectorType *VTy = dyn_cast<VectorType>(I.getOperand(0)->getType())) {
|
|
CmpDeclTypes.insert(std::pair<CmpInst::Predicate, VectorType*>(I.getPredicate(), VTy));
|
|
TypedefDeclTypes.insert(I.getType()); // insert type not necessarily visible above
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Write out the cast of the instruction's value back to the proper type
|
|
// if necessary.
|
|
bool NeedsClosingParens = writeInstructionCast(I);
|
|
|
|
// Certain icmp predicate 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);
|
|
|
|
switch (I.getPredicate()) {
|
|
case ICmpInst::ICMP_EQ: Out << " == "; break;
|
|
case ICmpInst::ICMP_NE: Out << " != "; break;
|
|
case ICmpInst::ICMP_ULE:
|
|
case ICmpInst::ICMP_SLE: Out << " <= "; break;
|
|
case ICmpInst::ICMP_UGE:
|
|
case ICmpInst::ICMP_SGE: Out << " >= "; break;
|
|
case ICmpInst::ICMP_ULT:
|
|
case ICmpInst::ICMP_SLT: Out << " < "; break;
|
|
case ICmpInst::ICMP_UGT:
|
|
case ICmpInst::ICMP_SGT: Out << " > "; break;
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Invalid icmp predicate!" << I;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
|
|
writeOperandWithCast(I.getOperand(1), I);
|
|
if (NeedsClosingParens)
|
|
Out << "))";
|
|
}
|
|
|
|
void CWriter::visitFCmpInst(FCmpInst &I) {
|
|
if (I.getType()->isVectorTy()) {
|
|
Out << "llvm_fcmp_" << getCmpPredicateName(I.getPredicate()) << "_";
|
|
printTypeString(Out, I.getOperand(0)->getType(), I.isSigned());
|
|
Out << "(";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getOperand(1), ContextCasted);
|
|
Out << ")";
|
|
if (VectorType *VTy = dyn_cast<VectorType>(I.getOperand(0)->getType())) {
|
|
CmpDeclTypes.insert(std::pair<CmpInst::Predicate, VectorType*>(I.getPredicate(), VTy));
|
|
TypedefDeclTypes.insert(I.getType()); // insert type not necessarily visible above
|
|
}
|
|
return;
|
|
}
|
|
|
|
Out << "llvm_fcmp_" << getCmpPredicateName(I.getPredicate()) << "(";
|
|
// Write the first operand
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
// Write the second operand
|
|
writeOperand(I.getOperand(1), ContextCasted);
|
|
Out << ")";
|
|
}
|
|
|
|
static const char * getFloatBitCastField(Type *Ty) {
|
|
switch (Ty->getTypeID()) {
|
|
default: llvm_unreachable("Invalid Type");
|
|
case Type::FloatTyID: return "Float";
|
|
case Type::DoubleTyID: return "Double";
|
|
case Type::IntegerTyID: {
|
|
unsigned NumBits = cast<IntegerType>(Ty)->getBitWidth();
|
|
if (NumBits <= 32)
|
|
return "Int32";
|
|
else
|
|
return "Int64";
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWriter::visitCastInst(CastInst &I) {
|
|
Type *DstTy = I.getType();
|
|
Type *SrcTy = I.getOperand(0)->getType();
|
|
|
|
if (DstTy->isVectorTy() || SrcTy->isVectorTy()
|
|
|| DstTy->getPrimitiveSizeInBits() > 64
|
|
|| SrcTy->getPrimitiveSizeInBits() > 64) {
|
|
Out << "llvm_" << I.getOpcodeName() << "_";
|
|
printTypeString(Out, SrcTy, false);
|
|
Out << "_";
|
|
printTypeString(Out, DstTy, false);
|
|
Out << "(";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ")";
|
|
CastOpDeclTypes.insert(std::pair<Instruction::CastOps, std::pair<Type*, Type*> >(I.getOpcode(), std::pair<Type*, Type*>(SrcTy, DstTy)));
|
|
return;
|
|
}
|
|
|
|
if (isFPIntBitCast(I)) {
|
|
Out << '(';
|
|
// These int<->float and long<->double casts need to be handled specially
|
|
Out << GetValueName(&I) << "__BITCAST_TEMPORARY."
|
|
<< getFloatBitCastField(I.getOperand(0)->getType()) << " = ";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", " << GetValueName(&I) << "__BITCAST_TEMPORARY."
|
|
<< getFloatBitCastField(I.getType());
|
|
Out << ')';
|
|
return;
|
|
}
|
|
|
|
Out << '(';
|
|
printCast(I.getOpcode(), SrcTy, DstTy);
|
|
|
|
// Make a sext from i1 work by subtracting the i1 from 0 (an int).
|
|
if (SrcTy == Type::getInt1Ty(I.getContext()) &&
|
|
I.getOpcode() == Instruction::SExt)
|
|
Out << "0-";
|
|
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
|
|
if (DstTy == Type::getInt1Ty(I.getContext()) &&
|
|
(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) {
|
|
Out << "llvm_select_";
|
|
printTypeString(Out, I.getType(), false);
|
|
Out << "(";
|
|
writeOperand(I.getCondition(), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getTrueValue(), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getFalseValue(), ContextCasted);
|
|
Out << ")";
|
|
SelectDeclTypes.insert(I.getType());
|
|
assert(I.getCondition()->getType()->isVectorTy() == I.getType()->isVectorTy()); // TODO: might be scalarty == vectorty
|
|
}
|
|
|
|
// Returns the macro name or value of the max or min of an integer type
|
|
// (as defined in limits.h).
|
|
static void printLimitValue(IntegerType &Ty, bool isSigned, bool isMax,
|
|
raw_ostream &Out) {
|
|
const char* type;
|
|
const char* sprefix = "";
|
|
|
|
unsigned NumBits = Ty.getBitWidth();
|
|
if (NumBits <= 8) {
|
|
type = "CHAR";
|
|
sprefix = "S";
|
|
} else if (NumBits <= 16) {
|
|
type = "SHRT";
|
|
} else if (NumBits <= 32) {
|
|
type = "INT";
|
|
} else if (NumBits <= 64) {
|
|
type = "LLONG";
|
|
} else {
|
|
llvm_unreachable("Bit widths > 64 not implemented yet");
|
|
}
|
|
|
|
if (isSigned)
|
|
Out << sprefix << type << (isMax ? "_MAX" : "_MIN");
|
|
else
|
|
Out << "U" << type << (isMax ? "_MAX" : "0");
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
static bool isSupportedIntegerSize(IntegerType &T) {
|
|
return T.getBitWidth() == 8 || T.getBitWidth() == 16 ||
|
|
T.getBitWidth() == 32 || T.getBitWidth() == 64 ||
|
|
T.getBitWidth() == 128;
|
|
}
|
|
#endif
|
|
|
|
void CWriter::printIntrinsicDefinition(FunctionType *funT,
|
|
unsigned Opcode, std::string OpName, raw_ostream &Out) {
|
|
Type *retT = funT->getReturnType();
|
|
Type *elemT = funT->getParamType(0);
|
|
IntegerType *elemIntT = dyn_cast<IntegerType>(elemT);
|
|
char i, numParams = funT->getNumParams();
|
|
bool isSigned;
|
|
switch (Opcode) {
|
|
default:
|
|
isSigned = false;
|
|
break;
|
|
case Intrinsic::sadd_with_overflow:
|
|
case Intrinsic::ssub_with_overflow:
|
|
case Intrinsic::smul_with_overflow:
|
|
isSigned = true;
|
|
break;
|
|
}
|
|
assert(numParams > 0 && numParams < 26);
|
|
|
|
if (isa<VectorType>(retT)) {
|
|
// this looks general, but is only actually used for ctpop, ctlz, cttz
|
|
Type* *devecFunParams = (Type**)alloca(sizeof(Type*) * numParams);
|
|
for (i = 0; i < numParams; i++) {
|
|
devecFunParams[(int)i] = funT->params()[(int)i]->getScalarType();
|
|
}
|
|
FunctionType *devecFunT = FunctionType::get(funT->getReturnType()->getScalarType(),
|
|
makeArrayRef(devecFunParams, numParams), funT->isVarArg());
|
|
printIntrinsicDefinition(devecFunT, Opcode, OpName + "_devec", Out);
|
|
}
|
|
|
|
// static __forceinline Rty _llvm_op_ixx(unsigned ixx a, unsigned ixx b) {
|
|
// Rty r;
|
|
// <opcode here>
|
|
// return r;
|
|
// }
|
|
Out << "static __forceinline ";
|
|
printTypeName(Out, retT);
|
|
Out << " ";
|
|
Out << OpName;
|
|
Out << "(";
|
|
for (i = 0; i < numParams; i++) {
|
|
switch (Opcode) {
|
|
// optional intrinsic validity assertion checks
|
|
default:
|
|
// default case: assume all parameters must have the same type
|
|
assert(elemT == funT->getParamType(i));
|
|
break;
|
|
case Intrinsic::ctlz:
|
|
case Intrinsic::cttz:
|
|
case Intrinsic::powi:
|
|
break;
|
|
}
|
|
printTypeNameUnaligned(Out, funT->getParamType(i), isSigned);
|
|
Out << " " << (char)('a' + i);
|
|
if (i != numParams - 1) Out << ", ";
|
|
}
|
|
Out << ") {\n ";
|
|
printTypeName(Out, retT);
|
|
Out << " r;\n";
|
|
|
|
if (isa<VectorType>(retT)) {
|
|
for (i = 0; i < numParams; i++) {
|
|
Out << " r.vector[" << (int)i << "] = " << OpName << "_devec(";
|
|
for (char j = 0; j < numParams; j++) {
|
|
Out << (char)('a' + j);
|
|
if (isa<VectorType>(funT->params()[j]))
|
|
Out << ".vector[" << (int)i << "]";
|
|
if (j != numParams - 1) Out << ", ";
|
|
}
|
|
Out << ");\n";
|
|
}
|
|
}
|
|
else if (elemIntT) {
|
|
// handle integer ops
|
|
assert(isSupportedIntegerSize(*elemIntT) &&
|
|
"CBackend does not support arbitrary size integers.");
|
|
switch (Opcode) {
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Unsupported Intrinsic!" << Opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
|
|
case Intrinsic::uadd_with_overflow:
|
|
// r.field0 = a + b;
|
|
// r.field1 = (r.field0 < a);
|
|
assert(cast<StructType>(retT)->getElementType(0) == elemT);
|
|
Out << " r.field0 = a + b;\n";
|
|
Out << " r.field1 = (a >= -b);\n";
|
|
break;
|
|
|
|
case Intrinsic::sadd_with_overflow:
|
|
// r.field0 = a + b;
|
|
// r.field1 = (b > 0 && a > XX_MAX - b) ||
|
|
// (b < 0 && a < XX_MIN - b);
|
|
assert(cast<StructType>(retT)->getElementType(0) == elemT);
|
|
Out << " r.field0 = a + b;\n";
|
|
Out << " r.field1 = (b >= 0 ? a > ";
|
|
printLimitValue(*elemIntT, true, true, Out);
|
|
Out << " - b : a < ";
|
|
printLimitValue(*elemIntT, true, false, Out);
|
|
Out << " - b);\n";
|
|
break;
|
|
|
|
case Intrinsic::usub_with_overflow:
|
|
assert(cast<StructType>(retT)->getElementType(0) == elemT);
|
|
Out << " r.field0 = a - b;\n";
|
|
Out << " r.field1 = (a < b);\n";
|
|
break;
|
|
|
|
case Intrinsic::ssub_with_overflow:
|
|
assert(cast<StructType>(retT)->getElementType(0) == elemT);
|
|
Out << " r.field0 = a - b;\n";
|
|
Out << " r.field1 = (b <= 0 ? a > ";
|
|
printLimitValue(*elemIntT, true, true, Out);
|
|
Out << " + b : a < ";
|
|
printLimitValue(*elemIntT, true, false, Out);
|
|
Out << " + b);\n";
|
|
break;
|
|
|
|
case Intrinsic::umul_with_overflow:
|
|
assert(cast<StructType>(retT)->getElementType(0) == elemT);
|
|
Out << " r.field1 = LLVMMul_uov(8 * sizeof(a), &a, &b, &r.field0);\n";
|
|
break;
|
|
|
|
case Intrinsic::smul_with_overflow:
|
|
assert(cast<StructType>(retT)->getElementType(0) == elemT);
|
|
Out << " r.field1 = LLVMMul_sov(8 * sizeof(a), &a, &b, &r.field0);\n";
|
|
break;
|
|
|
|
case Intrinsic::bswap:
|
|
assert(retT == elemT);
|
|
Out << " LLVMFlipAllBits(8 * sizeof(a), &a, &r);\n";
|
|
break;
|
|
|
|
case Intrinsic::ctpop:
|
|
assert(retT == elemT);
|
|
Out << " r = ";
|
|
if (retT->getPrimitiveSizeInBits() > 64)
|
|
Out << "llvm_ctor_u128(0, ";
|
|
Out << "LLVMCountPopulation(8 * sizeof(a), &a)";
|
|
if (retT->getPrimitiveSizeInBits() > 64)
|
|
Out << ")";
|
|
Out << ";\n";
|
|
break;
|
|
|
|
case Intrinsic::ctlz:
|
|
assert(retT == elemT);
|
|
Out << " (void)b;\n r = ";
|
|
if (retT->getPrimitiveSizeInBits() > 64)
|
|
Out << "llvm_ctor_u128(0, ";
|
|
Out << "LLVMCountLeadingZeros(8 * sizeof(a), &a)";
|
|
if (retT->getPrimitiveSizeInBits() > 64)
|
|
Out << ")";
|
|
Out << ";\n";
|
|
break;
|
|
|
|
case Intrinsic::cttz:
|
|
assert(retT == elemT);
|
|
Out << " (void)b;\n r = ";
|
|
if (retT->getPrimitiveSizeInBits() > 64)
|
|
Out << "llvm_ctor_u128(0, ";
|
|
Out << "LLVMCountTrailingZeros(8 * sizeof(a), &a)";
|
|
if (retT->getPrimitiveSizeInBits() > 64)
|
|
Out << ")";
|
|
Out << ";\n";
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
// handle FP ops
|
|
const char *suffix;
|
|
assert(retT == elemT);
|
|
if (elemT->isFloatTy() || elemT->isHalfTy()) {
|
|
suffix = "f";
|
|
} else if (elemT->isDoubleTy()) {
|
|
suffix = "";
|
|
} else if (elemT->isFP128Ty()) {
|
|
} else if (elemT->isX86_FP80Ty()) {
|
|
} else if (elemT->isPPC_FP128Ty()) {
|
|
suffix = "l";
|
|
} else {
|
|
#ifndef NDEBUG
|
|
errs() << "Unsupported Intrinsic!" << Opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
}
|
|
|
|
switch (Opcode) {
|
|
default:
|
|
#ifndef NDEBUG
|
|
errs() << "Unsupported Intrinsic!" << Opcode;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
|
|
case Intrinsic::ceil:
|
|
Out << " r = ceil" << suffix << "(a);\n";
|
|
break;
|
|
|
|
case Intrinsic::fabs:
|
|
Out << " r = fabs" << suffix << "(a);\n";
|
|
break;
|
|
|
|
case Intrinsic::floor:
|
|
Out << " r = floor" << suffix << "(a);\n";
|
|
break;
|
|
|
|
case Intrinsic::fma:
|
|
Out << " r = fma" << suffix << "(a, b, c);\n";
|
|
break;
|
|
|
|
case Intrinsic::fmuladd:
|
|
Out << " r = a * b + c;\n";
|
|
break;
|
|
|
|
case Intrinsic::pow:
|
|
case Intrinsic::powi:
|
|
Out << " r = pow" << suffix << "(a, b);\n";
|
|
break;
|
|
|
|
case Intrinsic::rint:
|
|
Out << " r = rint" << suffix << "(a);\n";
|
|
break;
|
|
|
|
case Intrinsic::sqrt:
|
|
Out << " r = sqrt" << suffix << "(a);\n";
|
|
break;
|
|
|
|
case Intrinsic::trunc:
|
|
Out << " r = trunc" << suffix << "(a);\n";
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
Out << " return r;\n}\n";
|
|
}
|
|
|
|
void CWriter::printIntrinsicDefinition(Function &F, raw_ostream &Out) {
|
|
FunctionType *funT = F.getFunctionType();
|
|
unsigned Opcode = F.getIntrinsicID();
|
|
std::string OpName = GetValueName(&F);
|
|
printIntrinsicDefinition(funT, Opcode, OpName, Out);
|
|
}
|
|
|
|
void CWriter::lowerIntrinsics(Function &F) {
|
|
// Examine all the instructions in this function to find the intrinsics that
|
|
// need to be lowered.
|
|
for (Function::iterator BB = F.begin(), EE = F.end(); BB != EE; ++BB)
|
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
|
|
if (CallInst *CI = dyn_cast<CallInst>(I++))
|
|
if (Function *F = CI->getCalledFunction())
|
|
switch (F->getIntrinsicID()) {
|
|
case Intrinsic::not_intrinsic:
|
|
case Intrinsic::vastart:
|
|
case Intrinsic::vacopy:
|
|
case Intrinsic::vaend:
|
|
case Intrinsic::returnaddress:
|
|
case Intrinsic::frameaddress:
|
|
case Intrinsic::setjmp:
|
|
case Intrinsic::longjmp:
|
|
case Intrinsic::sigsetjmp:
|
|
case Intrinsic::siglongjmp:
|
|
case Intrinsic::prefetch:
|
|
case Intrinsic::x86_sse_cmp_ss:
|
|
case Intrinsic::x86_sse_cmp_ps:
|
|
case Intrinsic::x86_sse2_cmp_sd:
|
|
case Intrinsic::x86_sse2_cmp_pd:
|
|
case Intrinsic::ppc_altivec_lvsl:
|
|
case Intrinsic::uadd_with_overflow:
|
|
case Intrinsic::sadd_with_overflow:
|
|
case Intrinsic::usub_with_overflow:
|
|
case Intrinsic::ssub_with_overflow:
|
|
case Intrinsic::umul_with_overflow:
|
|
case Intrinsic::smul_with_overflow:
|
|
case Intrinsic::bswap:
|
|
case Intrinsic::ceil:
|
|
case Intrinsic::ctlz:
|
|
case Intrinsic::ctpop:
|
|
case Intrinsic::cttz:
|
|
case Intrinsic::fabs:
|
|
case Intrinsic::floor:
|
|
case Intrinsic::fma:
|
|
case Intrinsic::fmuladd:
|
|
case Intrinsic::pow:
|
|
case Intrinsic::powi:
|
|
case Intrinsic::rint:
|
|
case Intrinsic::sqrt:
|
|
case Intrinsic::trunc:
|
|
case Intrinsic::trap:
|
|
case Intrinsic::stackprotector:
|
|
case Intrinsic::dbg_value:
|
|
case Intrinsic::dbg_declare:
|
|
// We directly implement these intrinsics
|
|
break;
|
|
default:
|
|
// All other intrinsic calls we must lower.
|
|
Instruction *Before = 0;
|
|
if (CI != &BB->front())
|
|
Before = &*std::prev(BasicBlock::iterator(CI));
|
|
|
|
IL->LowerIntrinsicCall(CI);
|
|
if (Before) { // Move iterator to instruction after call
|
|
I = BasicBlock::iterator(Before); ++I;
|
|
} else {
|
|
I = BB->begin();
|
|
}
|
|
// If the intrinsic got lowered to another call, and that call has
|
|
// a definition then we need to make sure its prototype is emitted
|
|
// before any calls to it.
|
|
if (CallInst *Call = dyn_cast<CallInst>(I))
|
|
if (Function *NewF = Call->getCalledFunction())
|
|
if (!NewF->isDeclaration())
|
|
prototypesToGen.push_back(NewF);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CWriter::visitCallInst(CallInst &I) {
|
|
if (isa<InlineAsm>(I.getCalledValue()))
|
|
return visitInlineAsm(I);
|
|
|
|
// Handle intrinsic function calls first...
|
|
if (Function *F = I.getCalledFunction())
|
|
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
|
|
if (visitBuiltinCall(I, ID))
|
|
return;
|
|
|
|
Value *Callee = I.getCalledValue();
|
|
|
|
PointerType *PTy = cast<PointerType>(Callee->getType());
|
|
FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
|
|
|
|
// If this is a call to a struct-return function, assign to the first
|
|
// parameter instead of passing it to the call.
|
|
const AttributeList &PAL = I.getAttributes();
|
|
bool hasByVal = I.hasByValArgument();
|
|
bool isStructRet = I.hasStructRetAttr();
|
|
if (isStructRet) {
|
|
writeOperandDeref(I.getArgOperand(0));
|
|
Out << " = ";
|
|
}
|
|
|
|
if (I.isTailCall()) Out << " /*tail*/ ";
|
|
|
|
// If this is an indirect call to a struct return function, we need to cast
|
|
// the pointer. Ditto for indirect calls with byval arguments.
|
|
bool NeedsCast = (hasByVal || isStructRet || I.getCallingConv() != CallingConv::C) && !isa<Function>(Callee);
|
|
|
|
// GCC is a real PITA. It does not permit codegening casts of functions to
|
|
// function pointers if they are in a call (it generates a trap instruction
|
|
// instead!). We work around this by inserting a cast to void* in between
|
|
// the function and the function pointer cast. Unfortunately, we can't just
|
|
// form the constant expression here, because the folder will immediately
|
|
// nuke it.
|
|
//
|
|
// Note finally, that this is completely unsafe. ANSI C does not guarantee
|
|
// that void* and function pointers have the same size. :( To deal with this
|
|
// in the common case, we handle casts where the number of arguments passed
|
|
// match exactly.
|
|
//
|
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Callee))
|
|
if (CE->isCast())
|
|
if (Function *RF = dyn_cast<Function>(CE->getOperand(0))) {
|
|
NeedsCast = true;
|
|
Callee = RF;
|
|
}
|
|
|
|
if (NeedsCast) {
|
|
// Ok, just cast the pointer type.
|
|
Out << "((";
|
|
printTypeName(Out, I.getCalledValue()->getType()->getPointerElementType(), false, std::make_pair(PAL, I.getCallingConv()));
|
|
Out << "*)(void*)";
|
|
}
|
|
writeOperand(Callee, ContextCasted);
|
|
if (NeedsCast) Out << ')';
|
|
|
|
Out << '(';
|
|
|
|
bool PrintedArg = false;
|
|
if (FTy->isVarArg() && !FTy->getNumParams()) {
|
|
Out << "0 /*dummy arg*/";
|
|
PrintedArg = true;
|
|
}
|
|
|
|
unsigned NumDeclaredParams = FTy->getNumParams();
|
|
CallSite CS(&I);
|
|
CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
|
|
unsigned ArgNo = 0;
|
|
if (isStructRet) { // Skip struct return argument.
|
|
++AI;
|
|
++ArgNo;
|
|
}
|
|
|
|
Function *F = I.getCalledFunction();
|
|
if (F) {
|
|
StringRef Name = F->getName();
|
|
// emit cast for the first argument to type expected by header prototype
|
|
// the jmp_buf type is an array, so the array-to-pointer decay adds the
|
|
// strange extra *'s
|
|
if (Name == "sigsetjmp")
|
|
Out << "*(sigjmp_buf*)";
|
|
else if (Name == "setjmp")
|
|
Out << "*(jmp_buf*)";
|
|
}
|
|
|
|
for (; AI != AE; ++AI, ++ArgNo) {
|
|
if (PrintedArg) Out << ", ";
|
|
if (ArgNo < NumDeclaredParams &&
|
|
(*AI)->getType() != FTy->getParamType(ArgNo)) {
|
|
Out << '(';
|
|
printTypeNameUnaligned(Out, FTy->getParamType(ArgNo),
|
|
/*isSigned=*/PAL.hasAttribute(ArgNo+1, Attribute::SExt));
|
|
Out << ')';
|
|
}
|
|
// Check if the argument is expected to be passed by value.
|
|
if (I.getAttributes().hasAttribute(ArgNo+1, Attribute::ByVal))
|
|
writeOperandDeref(*AI);
|
|
else
|
|
writeOperand(*AI, ContextCasted);
|
|
PrintedArg = true;
|
|
}
|
|
Out << ')';
|
|
}
|
|
|
|
/// visitBuiltinCall - Handle the call to the specified builtin. Returns true
|
|
/// if the entire call is handled, return false if it wasn't handled
|
|
bool CWriter::visitBuiltinCall(CallInst &I, Intrinsic::ID ID) {
|
|
switch (ID) {
|
|
default: {
|
|
#ifndef NDEBUG
|
|
errs() << "Unknown LLVM intrinsic! " << I;
|
|
#endif
|
|
llvm_unreachable(0);
|
|
return false;
|
|
}
|
|
case Intrinsic::dbg_value:
|
|
case Intrinsic::dbg_declare:
|
|
return true; // ignore these intrinsics
|
|
case Intrinsic::vastart:
|
|
Out << "0; ";
|
|
|
|
Out << "va_start(*(va_list*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
// Output the last argument to the enclosing function.
|
|
if (I.getParent()->getParent()->arg_empty())
|
|
Out << "vararg_dummy_arg";
|
|
else {
|
|
Function::arg_iterator arg_end = I.getParent()->getParent()->arg_end();
|
|
writeOperand(--arg_end);
|
|
}
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::vaend:
|
|
if (!isa<ConstantPointerNull>(I.getArgOperand(0))) {
|
|
Out << "0; va_end(*(va_list*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ')';
|
|
} else {
|
|
Out << "va_end(*(va_list*)0)";
|
|
}
|
|
return true;
|
|
case Intrinsic::vacopy:
|
|
Out << "0; ";
|
|
Out << "va_copy(*(va_list*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ", *(va_list*)";
|
|
writeOperand(I.getArgOperand(1), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::returnaddress:
|
|
Out << "__builtin_return_address(";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::frameaddress:
|
|
Out << "__builtin_frame_address(";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::setjmp:
|
|
Out << "setjmp(*(jmp_buf*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::longjmp:
|
|
Out << "longjmp(*(jmp_buf*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getArgOperand(1), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::sigsetjmp:
|
|
Out << "sigsetjmp(*(sigjmp_buf*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ',';
|
|
writeOperand(I.getArgOperand(1), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::siglongjmp:
|
|
Out << "siglongjmp(*(sigjmp_buf*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getArgOperand(1), ContextCasted);
|
|
Out << ')';
|
|
return true;
|
|
case Intrinsic::prefetch:
|
|
Out << "LLVM_PREFETCH((const void *)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getArgOperand(1), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getArgOperand(2), ContextCasted);
|
|
Out << ")";
|
|
return true;
|
|
case Intrinsic::stacksave:
|
|
// Emit this as: Val = 0; *((void**)&Val) = __builtin_stack_save()
|
|
// to work around GCC bugs (see PR1809).
|
|
Out << "0; *((void**)&" << GetValueName(&I)
|
|
<< ") = __builtin_stack_save()";
|
|
return true;
|
|
case Intrinsic::x86_sse_cmp_ss:
|
|
case Intrinsic::x86_sse_cmp_ps:
|
|
case Intrinsic::x86_sse2_cmp_sd:
|
|
case Intrinsic::x86_sse2_cmp_pd:
|
|
Out << '(';
|
|
printTypeName(Out, I.getType());
|
|
Out << ')';
|
|
// Multiple GCC builtins multiplex onto this intrinsic.
|
|
switch (cast<ConstantInt>(I.getArgOperand(2))->getZExtValue()) {
|
|
default: llvm_unreachable("Invalid llvm.x86.sse.cmp!");
|
|
case 0: Out << "__builtin_ia32_cmpeq"; break;
|
|
case 1: Out << "__builtin_ia32_cmplt"; break;
|
|
case 2: Out << "__builtin_ia32_cmple"; break;
|
|
case 3: Out << "__builtin_ia32_cmpunord"; break;
|
|
case 4: Out << "__builtin_ia32_cmpneq"; break;
|
|
case 5: Out << "__builtin_ia32_cmpnlt"; break;
|
|
case 6: Out << "__builtin_ia32_cmpnle"; break;
|
|
case 7: Out << "__builtin_ia32_cmpord"; break;
|
|
}
|
|
if (ID == Intrinsic::x86_sse_cmp_ps || ID == Intrinsic::x86_sse2_cmp_pd)
|
|
Out << 'p';
|
|
else
|
|
Out << 's';
|
|
if (ID == Intrinsic::x86_sse_cmp_ss || ID == Intrinsic::x86_sse_cmp_ps)
|
|
Out << 's';
|
|
else
|
|
Out << 'd';
|
|
|
|
Out << "(";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
writeOperand(I.getArgOperand(1), ContextCasted);
|
|
Out << ")";
|
|
return true;
|
|
case Intrinsic::ppc_altivec_lvsl:
|
|
Out << '(';
|
|
printTypeName(Out, I.getType());
|
|
Out << ')';
|
|
Out << "__builtin_altivec_lvsl(0, (void*)";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
Out << ")";
|
|
return true;
|
|
case Intrinsic::stackprotector:
|
|
writeOperandDeref(I.getArgOperand(1));
|
|
Out << " = ";
|
|
writeOperand(I.getArgOperand(0), ContextCasted);
|
|
return true;
|
|
case Intrinsic::uadd_with_overflow:
|
|
case Intrinsic::sadd_with_overflow:
|
|
case Intrinsic::usub_with_overflow:
|
|
case Intrinsic::ssub_with_overflow:
|
|
case Intrinsic::umul_with_overflow:
|
|
case Intrinsic::smul_with_overflow:
|
|
case Intrinsic::bswap:
|
|
case Intrinsic::ceil:
|
|
case Intrinsic::ctlz:
|
|
case Intrinsic::ctpop:
|
|
case Intrinsic::cttz:
|
|
case Intrinsic::fabs:
|
|
case Intrinsic::floor:
|
|
case Intrinsic::fma:
|
|
case Intrinsic::fmuladd:
|
|
case Intrinsic::pow:
|
|
case Intrinsic::powi:
|
|
case Intrinsic::rint:
|
|
case Intrinsic::sqrt:
|
|
case Intrinsic::trap:
|
|
case Intrinsic::trunc:
|
|
return false; // these use the normal function call emission
|
|
}
|
|
}
|
|
|
|
//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) {
|
|
return TargetLowering::AsmOperandInfo(c).ConstraintCode;
|
|
#if 0
|
|
assert(c.Codes.size() == 1 && "Too many asm constraint codes to handle");
|
|
|
|
// Grab the translation table from MCAsmInfo if it exists.
|
|
const MCRegisterInfo *MRI;
|
|
const MCAsmInfo *TargetAsm;
|
|
std::string Triple = TheModule->getTargetTriple();
|
|
if (Triple.empty())
|
|
Triple = llvm::sys::getDefaultTargetTriple();
|
|
|
|
std::string E;
|
|
if (const Target *Match = TargetRegistry::lookupTarget(Triple, E)) {
|
|
MRI = Match->createMCRegInfo(Triple);
|
|
TargetAsm = Match->createMCAsmInfo(*MRI, Triple);
|
|
} else {
|
|
return c.Codes[0];
|
|
}
|
|
|
|
const char *const *table = TargetAsm->getAsmCBE();
|
|
|
|
// Search the translation table if it exists.
|
|
for (int i = 0; table && table[i]; i += 2)
|
|
if (c.Codes[0] == table[i]) {
|
|
delete TargetAsm;
|
|
delete MRI;
|
|
return table[i+1];
|
|
}
|
|
|
|
// Default is identity.
|
|
delete TargetAsm;
|
|
delete MRI;
|
|
return c.Codes[0];
|
|
#endif
|
|
}
|
|
|
|
//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.getCalledValue());
|
|
InlineAsm::ConstraintInfoVector Constraints = as->ParseConstraints();
|
|
|
|
std::vector<std::pair<Value*, int> > ResultVals;
|
|
if (CI.getType() == Type::getVoidTy(CI.getContext()))
|
|
;
|
|
else if (StructType *ST = dyn_cast<StructType>(CI.getType())) {
|
|
for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i)
|
|
ResultVals.push_back(std::make_pair(&CI, (int)i));
|
|
} else {
|
|
ResultVals.push_back(std::make_pair(&CI, -1));
|
|
}
|
|
|
|
// Fix up the asm string for gcc and emit it.
|
|
Out << "__asm__ volatile (\"" << gccifyAsm(as->getAsmString()) << "\"\n";
|
|
Out << " :";
|
|
|
|
unsigned ValueCount = 0;
|
|
bool IsFirst = true;
|
|
|
|
// Convert over all the output constraints.
|
|
for (InlineAsm::ConstraintInfoVector::iterator I = Constraints.begin(),
|
|
E = Constraints.end(); I != E; ++I) {
|
|
|
|
if (I->Type != InlineAsm::isOutput) {
|
|
++ValueCount;
|
|
continue; // Ignore non-output constraints.
|
|
}
|
|
|
|
assert(I->Codes.size() == 1 && "Too many asm constraint codes to handle");
|
|
std::string C = InterpretASMConstraint(*I);
|
|
if (C.empty()) continue;
|
|
|
|
if (!IsFirst) {
|
|
Out << ", ";
|
|
IsFirst = false;
|
|
}
|
|
|
|
// Unpack the dest.
|
|
Value *DestVal;
|
|
int DestValNo = -1;
|
|
|
|
if (ValueCount < ResultVals.size()) {
|
|
DestVal = ResultVals[ValueCount].first;
|
|
DestValNo = ResultVals[ValueCount].second;
|
|
} else
|
|
DestVal = CI.getArgOperand(ValueCount-ResultVals.size());
|
|
|
|
if (I->isEarlyClobber)
|
|
C = "&"+C;
|
|
|
|
Out << "\"=" << C << "\"(" << GetValueName(DestVal);
|
|
if (DestValNo != -1)
|
|
Out << ".field" << DestValNo; // Multiple retvals.
|
|
Out << ")";
|
|
++ValueCount;
|
|
}
|
|
|
|
|
|
// Convert over all the input constraints.
|
|
Out << "\n :";
|
|
IsFirst = true;
|
|
ValueCount = 0;
|
|
for (InlineAsm::ConstraintInfoVector::iterator I = Constraints.begin(),
|
|
E = Constraints.end(); I != E; ++I) {
|
|
if (I->Type != InlineAsm::isInput) {
|
|
++ValueCount;
|
|
continue; // Ignore non-input constraints.
|
|
}
|
|
|
|
assert(I->Codes.size() == 1 && "Too many asm constraint codes to handle");
|
|
std::string C = InterpretASMConstraint(*I);
|
|
if (C.empty()) continue;
|
|
|
|
if (!IsFirst) {
|
|
Out << ", ";
|
|
IsFirst = false;
|
|
}
|
|
|
|
assert(ValueCount >= ResultVals.size() && "Input can't refer to result");
|
|
Value *SrcVal = CI.getArgOperand(ValueCount-ResultVals.size());
|
|
|
|
Out << "\"" << C << "\"(";
|
|
if (!I->isIndirect)
|
|
writeOperand(SrcVal);
|
|
else
|
|
writeOperandDeref(SrcVal);
|
|
Out << ")";
|
|
}
|
|
|
|
// Convert over the clobber constraints.
|
|
IsFirst = true;
|
|
for (InlineAsm::ConstraintInfoVector::iterator I = Constraints.begin(),
|
|
E = Constraints.end(); I != E; ++I) {
|
|
if (I->Type != InlineAsm::isClobber)
|
|
continue; // Ignore non-input constraints.
|
|
|
|
assert(I->Codes.size() == 1 && "Too many asm constraint codes to handle");
|
|
std::string C = InterpretASMConstraint(*I);
|
|
if (C.empty()) continue;
|
|
|
|
if (!IsFirst) {
|
|
Out << ", ";
|
|
IsFirst = false;
|
|
}
|
|
|
|
Out << '\"' << C << '"';
|
|
}
|
|
|
|
Out << ")";
|
|
}
|
|
|
|
void CWriter::visitAllocaInst(AllocaInst &I) {
|
|
Out << '(';
|
|
printTypeName(Out, I.getType());
|
|
Out << ") alloca(sizeof(";
|
|
printTypeName(Out, I.getType()->getElementType());
|
|
if (I.isArrayAllocation()) {
|
|
Out << ") * (" ;
|
|
writeOperand(I.getArraySize(), ContextCasted);
|
|
}
|
|
Out << "))";
|
|
}
|
|
|
|
void CWriter::printGEPExpression(Value *Ptr, gep_type_iterator I,
|
|
gep_type_iterator E) {
|
|
|
|
// If there are no indices, just print out the pointer.
|
|
if (I == E) {
|
|
writeOperand(Ptr);
|
|
return;
|
|
}
|
|
|
|
// Find out if the last index is into a vector. If so, we have to print this
|
|
// specially. Since vectors can't have elements of indexable type, only the
|
|
// last index could possibly be of a vector element.
|
|
VectorType *LastIndexIsVector = 0;
|
|
{
|
|
for (gep_type_iterator TmpI = I; TmpI != E; ++TmpI)
|
|
LastIndexIsVector = dyn_cast<VectorType>(TmpI.getIndexedType());
|
|
}
|
|
|
|
Out << "(";
|
|
|
|
// If the last index is into a vector, we can't print it as &a[i][j] because
|
|
// we can't index into a vector with j in GCC. Instead, emit this as
|
|
// (((float*)&a[i])+j)
|
|
// TODO: this is no longer true now that we don't represent vectors using gcc-extentions
|
|
if (LastIndexIsVector) {
|
|
Out << "((";
|
|
printTypeName(Out, PointerType::getUnqual(LastIndexIsVector->getElementType()));
|
|
Out << ")(";
|
|
}
|
|
|
|
Out << '&';
|
|
|
|
Type *IntoT = I.getIndexedType();
|
|
|
|
// If the first index is 0 (very typical) we can do a number of
|
|
// simplifications to clean up the code.
|
|
Value *FirstOp = I.getOperand();
|
|
if (!isa<Constant>(FirstOp) || !cast<Constant>(FirstOp)->isNullValue()) {
|
|
// First index isn't simple, print it the hard way.
|
|
writeOperand(Ptr);
|
|
} else {
|
|
++I; // Skip the zero index.
|
|
|
|
// Okay, emit the first operand. If Ptr is something that is already address
|
|
// exposed, like a global, avoid emitting (&foo)[0], just emit foo instead.
|
|
if (isAddressExposed(Ptr)) {
|
|
writeOperandInternal(Ptr);
|
|
} else if (I != E && I.isStruct()) {
|
|
// If we didn't already emit the first operand, see if we can print it as
|
|
// P->f instead of "P[0].f"
|
|
writeOperand(Ptr);
|
|
Out << "->field" << cast<ConstantInt>(I.getOperand())->getZExtValue();
|
|
++I; // eat the struct index as well.
|
|
} else {
|
|
// Instead of emitting P[0][1], emit (*P)[1], which is more idiomatic.
|
|
Out << "(*";
|
|
writeOperand(Ptr);
|
|
Out << ")";
|
|
}
|
|
}
|
|
|
|
|
|
for (; I != E; ++I) {
|
|
assert(I.getOperand()->getType()->isIntegerTy()); // TODO: indexing a Vector with a Vector is valid, but we don't support it here
|
|
if (I.isStruct()) {
|
|
Out << ".field" << cast<ConstantInt>(I.getOperand())->getZExtValue();
|
|
} else if (IntoT->isArrayTy()) {
|
|
Out << ".array[";
|
|
writeOperandWithCast(I.getOperand(), Instruction::GetElementPtr);
|
|
Out << ']';
|
|
} else if (!IntoT->isVectorTy()) {
|
|
Out << '[';
|
|
writeOperandWithCast(I.getOperand(), Instruction::GetElementPtr);
|
|
Out << ']';
|
|
} else {
|
|
// If the last index is into a vector, then print it out as "+j)". This
|
|
// works with the 'LastIndexIsVector' code above.
|
|
if (isa<Constant>(I.getOperand()) &&
|
|
cast<Constant>(I.getOperand())->isNullValue()) {
|
|
Out << "))"; // avoid "+0".
|
|
} else {
|
|
Out << ")+(";
|
|
writeOperandWithCast(I.getOperand(), Instruction::GetElementPtr);
|
|
Out << "))";
|
|
}
|
|
}
|
|
|
|
IntoT = I.getIndexedType();
|
|
}
|
|
Out << ")";
|
|
}
|
|
|
|
void CWriter::writeMemoryAccess(Value *Operand, Type *OperandType,
|
|
bool IsVolatile, unsigned Alignment /*bytes*/) {
|
|
if (isAddressExposed(Operand)) {
|
|
writeOperandInternal(Operand);
|
|
return;
|
|
}
|
|
|
|
bool IsUnaligned = Alignment &&
|
|
Alignment < TD->getABITypeAlignment(OperandType);
|
|
|
|
if (!IsUnaligned)
|
|
Out << '*';
|
|
|
|
else if (IsUnaligned) {
|
|
Out << "__UNALIGNED_LOAD__(";
|
|
printTypeNameUnaligned(Out, OperandType, false);
|
|
if (IsVolatile) Out << " volatile";
|
|
Out << ", " << Alignment << ", ";
|
|
}
|
|
|
|
else if (IsVolatile) {
|
|
Out << "(";
|
|
printTypeName(Out, OperandType, false);
|
|
Out << "volatile";
|
|
Out << "*)";
|
|
}
|
|
|
|
writeOperand(Operand);
|
|
|
|
if (IsUnaligned) {
|
|
Out << ")";
|
|
}
|
|
}
|
|
|
|
void CWriter::visitLoadInst(LoadInst &I) {
|
|
writeMemoryAccess(I.getOperand(0), I.getType(), I.isVolatile(),
|
|
I.getAlignment());
|
|
|
|
}
|
|
|
|
void CWriter::visitStoreInst(StoreInst &I) {
|
|
writeMemoryAccess(I.getPointerOperand(), I.getOperand(0)->getType(),
|
|
I.isVolatile(), I.getAlignment());
|
|
Out << " = ";
|
|
Value *Operand = I.getOperand(0);
|
|
unsigned BitMask = 0;
|
|
if (IntegerType* ITy = dyn_cast<IntegerType>(Operand->getType()))
|
|
if (!ITy->isPowerOf2ByteWidth())
|
|
// We have a bit width that doesn't match an even power-of-2 byte
|
|
// size. Consequently we must & the value with the type's bit mask
|
|
BitMask = ITy->getBitMask();
|
|
if (BitMask)
|
|
Out << "((";
|
|
writeOperand(Operand, BitMask ? ContextNormal : ContextCasted);
|
|
if (BitMask)
|
|
Out << ") & " << BitMask << ")";
|
|
}
|
|
|
|
void CWriter::visitGetElementPtrInst(GetElementPtrInst &I) {
|
|
printGEPExpression(I.getPointerOperand(), gep_type_begin(I),
|
|
gep_type_end(I));
|
|
}
|
|
|
|
void CWriter::visitVAArgInst(VAArgInst &I) {
|
|
Out << "va_arg(*(va_list*)";
|
|
writeOperand(I.getOperand(0), ContextCasted);
|
|
Out << ", ";
|
|
printTypeName(Out, I.getType());
|
|
Out << ");\n ";
|
|
}
|
|
|
|
void CWriter::visitInsertElementInst(InsertElementInst &I) {
|
|
// Start by copying the entire aggregate value into the result variable.
|
|
writeOperand(I.getOperand(0));
|
|
Type *EltTy = I.getType()->getElementType();
|
|
assert(I.getOperand(1)->getType() == EltTy);
|
|
if (isEmptyType(EltTy)) return;
|
|
|
|
// Then do the insert to update the field.
|
|
Out << ";\n ";
|
|
Out << GetValueName(&I) << ".vector[";
|
|
writeOperand(I.getOperand(2));
|
|
Out << "] = ";
|
|
writeOperand(I.getOperand(1), ContextCasted);
|
|
}
|
|
|
|
void CWriter::visitExtractElementInst(ExtractElementInst &I) {
|
|
assert(!isEmptyType(I.getType()));
|
|
if (isa<UndefValue>(I.getOperand(0))) {
|
|
Out << "(";
|
|
printTypeName(Out, I.getType());
|
|
Out << ") 0/*UNDEF*/";
|
|
} else {
|
|
Out << "(";
|
|
writeOperand(I.getOperand(0));
|
|
Out << ").vector[";
|
|
writeOperand(I.getOperand(1));
|
|
Out << "]";
|
|
}
|
|
}
|
|
|
|
// <result> = shufflevector <n x <ty>> <v1>, <n x <ty>> <v2>, <m x i32> <mask>
|
|
// ; yields <m x <ty>>
|
|
void CWriter::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
|
|
VectorType *VT = SVI.getType();
|
|
Type *EltTy = VT->getElementType();
|
|
VectorType *InputVT = cast<VectorType>(SVI.getOperand(0)->getType());
|
|
assert(!isEmptyType(VT));
|
|
assert(InputVT->getElementType() == VT->getElementType());
|
|
|
|
CtorDeclTypes.insert(VT);
|
|
Out << "llvm_ctor_";
|
|
printTypeString(Out, VT, false);
|
|
Out << "(";
|
|
|
|
Constant *Zero = Constant::getNullValue(EltTy);
|
|
unsigned NumElts = VT->getNumElements();
|
|
unsigned NumInputElts = InputVT->getNumElements(); // n
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
|
if (i) Out << ", ";
|
|
int SrcVal = SVI.getMaskValue(i);
|
|
if ((unsigned)SrcVal >= NumInputElts * 2) {
|
|
Out << "/*undef*/";
|
|
printConstant(Zero, ContextCasted);
|
|
} else {
|
|
// If SrcVal belongs [0, n - 1], it extracts value from <v1>
|
|
// If SrcVal belongs [n, 2 * n - 1], it extracts value from <v2>
|
|
// In C++, the value false is converted to zero and the value true is
|
|
// converted to one
|
|
Value *Op = SVI.getOperand((unsigned)SrcVal >= NumInputElts);
|
|
if (isa<Instruction>(Op)) {
|
|
// Do an extractelement of this value from the appropriate input.
|
|
Out << "(";
|
|
writeOperand(Op);
|
|
Out << ").vector[";
|
|
Out << ((unsigned)SrcVal >= NumInputElts ? SrcVal - NumInputElts : SrcVal);
|
|
Out << "]";
|
|
} else if (isa<ConstantAggregateZero>(Op) || isa<UndefValue>(Op)) {
|
|
printConstant(Zero, ContextCasted);
|
|
} else {
|
|
printConstant(cast<ConstantVector>(Op)->getOperand(SrcVal &
|
|
(NumElts-1)),
|
|
ContextNormal);
|
|
}
|
|
}
|
|
}
|
|
Out << ")";
|
|
}
|
|
|
|
void CWriter::visitInsertValueInst(InsertValueInst &IVI) {
|
|
// Start by copying the entire aggregate value into the result variable.
|
|
writeOperand(IVI.getOperand(0));
|
|
Type *EltTy = IVI.getOperand(1)->getType();
|
|
if (isEmptyType(EltTy)) return;
|
|
|
|
// Then do the insert to update the field.
|
|
Out << ";\n ";
|
|
Out << GetValueName(&IVI);
|
|
for (const unsigned *b = IVI.idx_begin(), *i = b, *e = IVI.idx_end();
|
|
i != e; ++i) {
|
|
Type *IndexedTy =
|
|
ExtractValueInst::getIndexedType(IVI.getOperand(0)->getType(),
|
|
makeArrayRef(b, i));
|
|
assert(IndexedTy);
|
|
if (IndexedTy->isArrayTy())
|
|
Out << ".array[" << *i << "]";
|
|
else
|
|
Out << ".field" << *i;
|
|
}
|
|
Out << " = ";
|
|
writeOperand(IVI.getOperand(1), ContextCasted);
|
|
}
|
|
|
|
void CWriter::visitExtractValueInst(ExtractValueInst &EVI) {
|
|
Out << "(";
|
|
if (isa<UndefValue>(EVI.getOperand(0))) {
|
|
Out << "(";
|
|
printTypeName(Out, EVI.getType());
|
|
Out << ") 0/*UNDEF*/";
|
|
} else {
|
|
writeOperand(EVI.getOperand(0));
|
|
for (const unsigned *b = EVI.idx_begin(), *i = b, *e = EVI.idx_end();
|
|
i != e; ++i) {
|
|
Type *IndexedTy =
|
|
ExtractValueInst::getIndexedType(EVI.getOperand(0)->getType(),
|
|
makeArrayRef(b, i));
|
|
if (IndexedTy->isArrayTy())
|
|
Out << ".array[" << *i << "]";
|
|
else
|
|
Out << ".field" << *i;
|
|
}
|
|
}
|
|
Out << ")";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// External Interface declaration
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool CTargetMachine::addPassesToEmitFile(
|
|
PassManagerBase &PM, raw_pwrite_stream &Out,
|
|
#if LLVM_VERSION_MAJOR == 7
|
|
raw_pwrite_stream *DwoOut,
|
|
#endif
|
|
CodeGenFileType FileType, bool DisableVerify, MachineModuleInfo *MMI) {
|
|
|
|
if (FileType != TargetMachine::CGFT_AssemblyFile) return true;
|
|
|
|
PM.add(createGCLoweringPass());
|
|
PM.add(createLowerInvokePass());
|
|
PM.add(createCFGSimplificationPass()); // clean up after lower invoke.
|
|
PM.add(new CWriter(Out));
|
|
return false;
|
|
}
|