blob: 1cfc91a8c6a3a3c223ce76f41662b1ad3def5227 [file] [log] [blame]
//===-- LLVM Code Emitter Implementation ------------------------*- C++ -*-===//
//
// High Level Virtual Machine (HLVM)
//
// Copyright (C) 2006 Reid Spencer. All Rights Reserved.
//
// This software is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This software is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library in the file named LICENSE.txt; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
//
//===----------------------------------------------------------------------===//
/// @file hlvm/CodeGen/LLVMEmitter.cpp
/// @author Reid Spencer <rspencer@x10sys.com>
/// @date 2006/07/08
/// @since 0.2.0
/// @brief Provides the implementation of the LLVM Code Emitter
//===----------------------------------------------------------------------===//
#include <hlvm/CodeGen/LLVMEmitter.h>
#include <hlvm/Base/Assert.h>
using namespace llvm;
namespace {
class LLVMEmitterImpl : public hlvm::LLVMEmitter
{
/// @name Data
/// @{
private:
// Caches of things to interface with the HLVM Runtime Library
PointerType* hlvm_text; ///< Opaque type for text objects
Function* hlvm_text_create; ///< Create a new text object
Function* hlvm_text_delete; ///< Delete a text object
Function* hlvm_text_to_buffer;///< Convert text to a buffer
PointerType* hlvm_buffer; ///< Pointer To octet
Function* hlvm_buffer_create; ///< Create a new buffer object
Function* hlvm_buffer_delete; ///< Delete a buffer
PointerType* hlvm_stream; ///< Pointer to stream type
Function* hlvm_stream_open; ///< Function for stream_open
Function* hlvm_stream_read; ///< Function for stream_read
Function* hlvm_stream_write_buffer; ///< Write buffer to stream
Function* hlvm_stream_write_text; ///< Write text to stream
Function* hlvm_stream_write_string; ///< Write string to stream
Function* hlvm_stream_close; ///< Function for stream_close
Function* hlvm_f32_ispinf;
Function* hlvm_f32_isninf ;
Function* hlvm_f32_isnan ;
Function* hlvm_f32_trunc ;
Function* hlvm_f32_round ;
Function* hlvm_f32_floor ;
Function* hlvm_f32_ceiling ;
Function* hlvm_f32_loge ;
Function* hlvm_f32_log2 ;
Function* hlvm_f32_log10 ;
Function* hlvm_f32_squareroot ;
Function* hlvm_f32_cuberoot ;
Function* hlvm_f32_factorial ;
Function* hlvm_f32_power ;
Function* hlvm_f32_root ;
Function* hlvm_f32_gcd ;
Function* hlvm_f32_lcm;
Function* hlvm_f64_ispinf;
Function* hlvm_f64_isninf ;
Function* hlvm_f64_isnan ;
Function* hlvm_f64_trunc ;
Function* hlvm_f64_round ;
Function* hlvm_f64_floor ;
Function* hlvm_f64_ceiling ;
Function* hlvm_f64_loge ;
Function* hlvm_f64_log2 ;
Function* hlvm_f64_log10 ;
Function* hlvm_f64_squareroot ;
Function* hlvm_f64_cuberoot ;
Function* hlvm_f64_factorial ;
Function* hlvm_f64_power ;
Function* hlvm_f64_root ;
Function* hlvm_f64_gcd ;
Function* hlvm_f64_lcm;
FunctionType* hlvm_program_signature; ///< The llvm type for programs
// Caches of LLVM Intrinsic functions
Function* llvm_memcpy; ///< llvm.memcpy.i64
Function* llvm_memmove; ///< llvm.memmove.i64
Function* llvm_memset; ///< llvm.memset.i64
/// @}
/// @name Constructor
/// @{
public:
LLVMEmitterImpl() : hlvm::LLVMEmitter(),
hlvm_text(0), hlvm_text_create(0), hlvm_text_delete(0),
hlvm_text_to_buffer(0),
hlvm_buffer(0), hlvm_buffer_create(0), hlvm_buffer_delete(0),
hlvm_stream(0), hlvm_stream_open(0), hlvm_stream_read(0),
hlvm_stream_write_buffer(0), hlvm_stream_write_text(0),
hlvm_stream_write_string(0), hlvm_stream_close(0),
hlvm_f32_ispinf(0), hlvm_f32_isninf(0), hlvm_f32_isnan(0),
hlvm_f32_trunc(0), hlvm_f32_round(0), hlvm_f32_floor (0),
hlvm_f32_ceiling(0), hlvm_f32_loge(0), hlvm_f32_log2(0),
hlvm_f32_log10(0), hlvm_f32_squareroot(0), hlvm_f32_cuberoot(0),
hlvm_f32_factorial(0), hlvm_f32_power(0), hlvm_f32_root(0),
hlvm_f32_gcd(0), hlvm_f32_lcm(0), hlvm_f64_ispinf(0), hlvm_f64_isninf(0),
hlvm_f64_isnan(0), hlvm_f64_trunc(0), hlvm_f64_round(0),
hlvm_f64_floor(0), hlvm_f64_ceiling(0), hlvm_f64_loge(0),
hlvm_f64_log2(0), hlvm_f64_log10(0), hlvm_f64_squareroot(0),
hlvm_f64_cuberoot(0), hlvm_f64_factorial(0), hlvm_f64_power(0),
hlvm_f64_root(0), hlvm_f64_gcd(0), hlvm_f64_lcm(0),
hlvm_program_signature(0),
llvm_memcpy(0), llvm_memmove(0), llvm_memset(0)
{
}
/// @}
/// @name Methods
/// @{
public:
const Type* get_hlvm_size() { return Type::Int64Ty; }
PointerType* get_hlvm_text()
{
if (! hlvm_text) {
// An hlvm_text is a variable length array of signed bytes preceded by
// an
// Arglist args;
// args.push_back(Type::Int32Ty);
// args.push_back(ArrayType::Get(Type::Int8Ty,0));
OpaqueType* opq = OpaqueType::get();
TheModule->addTypeName("hlvm_text_obj", opq);
hlvm_text = PointerType::get(opq);
TheModule->addTypeName("hlvm_text", hlvm_text);
}
return hlvm_text;
}
Function* get_hlvm_text_create()
{
if (! hlvm_text_create) {
Type* result = get_hlvm_text();
std::vector<const Type*> arg_types;
arg_types.push_back(PointerType::get(Type::Int8Ty));
FunctionType* FT =
FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_text_create",FT);
hlvm_text_create =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_text_create", TheModule);
}
return hlvm_text_create;
}
CallInst* call_hlvm_text_create(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_text_create();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "buffer"),
TheBlock);
}
Function* get_hlvm_text_delete()
{
if (! hlvm_text_delete) {
Type* result = get_hlvm_text();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_text());
FunctionType* FT =
FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_text_delete",FT);
hlvm_text_delete =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_text_delete", TheModule);
}
return hlvm_text_delete;
}
CallInst* call_hlvm_text_delete(const hlvm::ArgList& args)
{
Function* F = get_hlvm_text_delete();
return new CallInst(F, args.begin(), args.end(), "hlvm_text_delete",
TheBlock);
}
Function* get_hlvm_text_to_buffer()
{
if (! hlvm_text_to_buffer) {
Type* result = get_hlvm_buffer();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_text());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_text_to_buffer_signature",FT);
hlvm_text_to_buffer =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_text_to_buffer", TheModule);
}
return hlvm_text_to_buffer;
}
CallInst* call_hlvm_text_to_buffer(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_text_to_buffer();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "buffer"),
TheBlock);
}
PointerType* get_hlvm_buffer()
{
if (! hlvm_buffer) {
OpaqueType* opq = OpaqueType::get();
TheModule->addTypeName("hlvm_buffer_obj", opq);
hlvm_buffer = PointerType::get(opq);
TheModule->addTypeName("hlvm_buffer", hlvm_buffer);
}
return hlvm_buffer;
}
Function* get_hlvm_buffer_create()
{
if (! hlvm_buffer_create) {
Type* result = get_hlvm_buffer();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_size());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_buffer_create",FT);
hlvm_buffer_create =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_buffer_create", TheModule);
}
return hlvm_buffer_create;
}
CallInst* call_hlvm_buffer_create(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_buffer_create();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "buffer"),
TheBlock);
}
Function* get_hlvm_buffer_delete()
{
if (! hlvm_buffer_delete) {
Type* result = get_hlvm_buffer();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_buffer());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_buffer_delete",FT);
hlvm_buffer_delete =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_buffer_delete", TheModule);
}
return hlvm_buffer_delete;
}
CallInst* call_hlvm_buffer_delete(const hlvm::ArgList& args)
{
Function* F = get_hlvm_buffer_delete();
return new CallInst(F, args.begin(), args.end(), "", TheBlock);
}
PointerType* get_hlvm_stream()
{
if (! hlvm_stream) {
OpaqueType* opq = OpaqueType::get();
TheModule->addTypeName("hlvm_stream_obj", opq);
hlvm_stream = PointerType::get(opq);
TheModule->addTypeName("hlvm_stream", hlvm_stream);
}
return hlvm_stream;
}
Function* get_hlvm_stream_open()
{
if (!hlvm_stream_open) {
Type* result = get_hlvm_stream();
std::vector<const Type*> arg_types;
arg_types.push_back(PointerType::get(Type::Int8Ty));
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_stream_open_signature",FT);
hlvm_stream_open =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_stream_open", TheModule);
}
return hlvm_stream_open;
}
CallInst* call_hlvm_stream_open(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_stream_open();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "stream"),
TheBlock);
}
Function* get_hlvm_stream_read()
{
if (!hlvm_stream_read) {
const Type* result = get_hlvm_size();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_stream());
arg_types.push_back(get_hlvm_buffer());
arg_types.push_back(get_hlvm_size());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_stream_read_signature",FT);
hlvm_stream_read =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_stream_read", TheModule);
}
return hlvm_stream_read;
}
CallInst* call_hlvm_stream_read(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_stream_read();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "readlen"),
TheBlock);
}
Function* get_hlvm_stream_write_buffer()
{
if (!hlvm_stream_write_buffer) {
const Type* result = get_hlvm_size();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_stream());
arg_types.push_back(get_hlvm_buffer());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_stream_write_buffer_signature",FT);
hlvm_stream_write_buffer =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_stream_write_buffer", TheModule);
}
return hlvm_stream_write_buffer;
}
CallInst* call_hlvm_stream_write_buffer(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_stream_write_buffer();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "writelen"),
TheBlock);
}
Function* get_hlvm_stream_write_string()
{
if (!hlvm_stream_write_string) {
const Type* result = get_hlvm_size();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_stream());
arg_types.push_back(PointerType::get(Type::Int8Ty));
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_stream_write_string_signature",FT);
hlvm_stream_write_string =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_stream_write_string", TheModule);
}
return hlvm_stream_write_string;
}
CallInst* call_hlvm_stream_write_string(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_stream_write_string();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "writelen"),
TheBlock);
}
Function* get_hlvm_stream_write_text()
{
if (!hlvm_stream_write_text) {
const Type* result = get_hlvm_size();
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_stream());
arg_types.push_back(get_hlvm_text());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_stream_write_text_signature",FT);
hlvm_stream_write_text =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_stream_write_text", TheModule);
}
return hlvm_stream_write_text;
}
CallInst* call_hlvm_stream_write_text(const hlvm::ArgList& args, const char* nm)
{
Function* F = get_hlvm_stream_write_text();
return new CallInst(F, args.begin(), args.end(), (nm ? nm : "writelen"),
TheBlock);
}
Function* get_hlvm_stream_close()
{
if (!hlvm_stream_close) {
const Type* result = Type::VoidTy;
std::vector<const Type*> arg_types;
arg_types.push_back(get_hlvm_stream());
FunctionType* FT = FunctionType::get(result,arg_types,false);
TheModule->addTypeName("hlvm_stream_close_signature",FT);
hlvm_stream_close =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_stream_close", TheModule);
}
return hlvm_stream_close;
}
CallInst* call_hlvm_stream_close(const hlvm::ArgList& args)
{
Function* F = get_hlvm_stream_close();
return new CallInst(F, args.begin(), args.end(), "", TheBlock);
}
FunctionType* get_hlvm_program_signature()
{
if (!hlvm_program_signature) {
// Get the type of function that all entry points must have
std::vector<const Type*> arg_types;
arg_types.push_back(Type::Int32Ty);
arg_types.push_back(
PointerType::get(PointerType::get(Type::Int8Ty)));
hlvm_program_signature =
FunctionType::get(Type::Int32Ty,arg_types,false);
TheModule->addTypeName("hlvm_program_signature",hlvm_program_signature);
}
return hlvm_program_signature;
}
Function* get_llvm_memcpy()
{
if (!llvm_memcpy) {
const Type *SBP = PointerType::get(Type::Int8Ty);
llvm_memcpy = cast<Function>(TheModule->getOrInsertFunction(
"llvm.memcpy.i64", Type::VoidTy, SBP, SBP, Type::Int64Ty,
Type::Int32Ty, NULL));
}
return llvm_memcpy;
}
Function* get_llvm_memmove()
{
if (!llvm_memmove) {
const Type *SBP = PointerType::get(Type::Int8Ty);
llvm_memmove = cast<Function>(TheModule->getOrInsertFunction(
"llvm.memmove.i64", Type::VoidTy, SBP, SBP, Type::Int64Ty,
Type::Int32Ty, NULL));
}
return llvm_memmove;
}
Function* get_llvm_memset()
{
if (!llvm_memset) {
const Type *SBP = PointerType::get(Type::Int8Ty);
llvm_memset = cast<Function>(TheModule->getOrInsertFunction(
"llvm.memset.i64", Type::VoidTy, SBP, Type::Int8Ty, Type::Int64Ty,
Type::Int32Ty, NULL));
}
return llvm_memset;
}
Function* get_hlvm_f32_ispinf()
{
if (! hlvm_f32_ispinf) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_ispinf",FT);
hlvm_f32_ispinf =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_ispinf", TheModule);
}
return hlvm_f32_ispinf;
}
Function* get_hlvm_f32_isninf()
{
if (! hlvm_f32_isninf) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_isninf",FT);
hlvm_f32_isninf =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_isninf", TheModule);
}
return hlvm_f32_isninf;
}
Function* get_hlvm_f32_isnan()
{
if (! hlvm_f32_isnan) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_isnan",FT);
hlvm_f32_isnan =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_isnan", TheModule);
}
return hlvm_f32_isnan;
}
Function* get_hlvm_f32_trunc()
{
if (! hlvm_f32_trunc) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_trunc",FT);
hlvm_f32_trunc =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_trunc", TheModule);
}
return hlvm_f32_trunc;
}
Function* get_hlvm_f32_round()
{
if (! hlvm_f32_round) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_round",FT);
hlvm_f32_round =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_round", TheModule);
}
return hlvm_f32_round;
}
Function* get_hlvm_f32_floor()
{
if (! hlvm_f32_floor) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_floor",FT);
hlvm_f32_floor =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_floor", TheModule);
}
return hlvm_f32_floor;
}
Function* get_hlvm_f32_ceiling()
{
if (! hlvm_f32_ceiling) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_ceiling",FT);
hlvm_f32_ceiling =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_ceiling", TheModule);
}
return hlvm_f32_ceiling;
}
Function* get_hlvm_f32_loge()
{
if (! hlvm_f32_loge) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_loge",FT);
hlvm_f32_loge =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_loge", TheModule);
}
return hlvm_f32_loge;
}
Function* get_hlvm_f32_log2()
{
if (! hlvm_f32_log2) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_log2",FT);
hlvm_f32_log2 =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_log2", TheModule);
}
return hlvm_f32_log2;
}
Function* get_hlvm_f32_log10()
{
if (! hlvm_f32_log10) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_log10",FT);
hlvm_f32_log10 =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_log10", TheModule);
}
return hlvm_f32_log10;
}
Function* get_hlvm_f32_squareroot()
{
if (! hlvm_f32_squareroot) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_squareroot",FT);
hlvm_f32_squareroot =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_squareroot", TheModule);
}
return hlvm_f32_squareroot;
}
Function* get_hlvm_f32_cuberoot()
{
if (! hlvm_f32_cuberoot) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_cuberoot",FT);
hlvm_f32_cuberoot =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_cuberoot", TheModule);
}
return hlvm_f32_cuberoot;
}
Function* get_hlvm_f32_factorial()
{
if (! hlvm_f32_factorial) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_factorial",FT);
hlvm_f32_factorial =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_factorial", TheModule);
}
return hlvm_f32_factorial;
}
Function* get_hlvm_f32_power()
{
if (! hlvm_f32_power) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_power",FT);
hlvm_f32_power =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_power", TheModule);
}
return hlvm_f32_ispinf;
}
Function* get_hlvm_f32_root()
{
if (! hlvm_f32_root) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_root",FT);
hlvm_f32_root =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_root", TheModule);
}
return hlvm_f32_ispinf;
}
Function* get_hlvm_f32_gcd()
{
if (! hlvm_f32_gcd) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_gcd",FT);
hlvm_f32_gcd =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_gcd", TheModule);
}
return hlvm_f32_ispinf;
}
Function* get_hlvm_f32_lcm()
{
if (! hlvm_f32_lcm) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::FloatTy);
arg_types.push_back(Type::FloatTy);
FunctionType* FT = FunctionType::get(Type::FloatTy,arg_types,false);
TheModule->addTypeName("hlvm_f32_lcm",FT);
hlvm_f32_lcm =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f32_lcm", TheModule);
}
return hlvm_f32_ispinf;
}
CallInst* call_hlvm_f32_ispinf(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_ispinf(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_isninf(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_isninf(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_isnan(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_isnan(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_trunc(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_trunc(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_round(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_round(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_floor(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_floor(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_ceiling(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_ceiling(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_loge(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_loge(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_log2(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_log2(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_log10(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_log10(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_squareroot(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_squareroot(), args.begin(), args.end(),
"", TheBlock);
}
CallInst* call_hlvm_f32_cuberoot(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_cuberoot(), args.begin(), args.end(),
"", TheBlock);
}
CallInst* call_hlvm_f32_factorial(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_factorial(), args.begin(), args.end(),
"", TheBlock);
}
CallInst* call_hlvm_f32_power(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_power(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_root(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_root(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_gcd(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_gcd(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f32_lcm(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f32_lcm(), args.begin(), args.end(), "",
TheBlock);
}
Function* get_hlvm_f64_ispinf()
{
if (! hlvm_f64_ispinf) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_ispinf",FT);
hlvm_f64_ispinf =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_ispinf", TheModule);
}
return hlvm_f64_ispinf;
}
Function* get_hlvm_f64_isninf()
{
if (! hlvm_f64_isninf) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_isninf",FT);
hlvm_f64_isninf =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_isninf", TheModule);
}
return hlvm_f64_isninf;
}
Function* get_hlvm_f64_isnan()
{
if (! hlvm_f64_isnan) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_isnan",FT);
hlvm_f64_isnan =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_isnan", TheModule);
}
return hlvm_f64_isnan;
}
Function* get_hlvm_f64_trunc()
{
if (! hlvm_f64_trunc) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_trunc",FT);
hlvm_f64_trunc =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_trunc", TheModule);
}
return hlvm_f64_trunc;
}
Function* get_hlvm_f64_round()
{
if (! hlvm_f64_round) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_round",FT);
hlvm_f64_round =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_round", TheModule);
}
return hlvm_f64_round;
}
Function* get_hlvm_f64_floor()
{
if (! hlvm_f64_floor) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_floor",FT);
hlvm_f64_floor =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_floor", TheModule);
}
return hlvm_f64_floor;
}
Function* get_hlvm_f64_ceiling()
{
if (! hlvm_f64_ceiling) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_ceiling",FT);
hlvm_f64_ceiling =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_ceiling", TheModule);
}
return hlvm_f64_ceiling;
}
Function* get_hlvm_f64_loge()
{
if (! hlvm_f64_loge) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_loge",FT);
hlvm_f64_loge =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_loge", TheModule);
}
return hlvm_f64_loge;
}
Function* get_hlvm_f64_log2()
{
if (! hlvm_f64_log2) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_log2",FT);
hlvm_f64_log2 =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_log2", TheModule);
}
return hlvm_f64_log2;
}
Function* get_hlvm_f64_log10()
{
if (! hlvm_f64_log10) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_log10",FT);
hlvm_f64_log10 =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_log10", TheModule);
}
return hlvm_f64_log10;
}
Function* get_hlvm_f64_squareroot()
{
if (! hlvm_f64_squareroot) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_squareroot",FT);
hlvm_f64_squareroot =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_squareroot", TheModule);
}
return hlvm_f64_squareroot;
}
Function* get_hlvm_f64_cuberoot()
{
if (! hlvm_f64_cuberoot) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_cuberoot",FT);
hlvm_f64_cuberoot =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_cuberoot", TheModule);
}
return hlvm_f64_cuberoot;
}
Function* get_hlvm_f64_factorial()
{
if (! hlvm_f64_factorial) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_factorial",FT);
hlvm_f64_factorial =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_factorial", TheModule);
}
return hlvm_f64_factorial;
}
Function* get_hlvm_f64_power()
{
if (! hlvm_f64_power) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_power",FT);
hlvm_f64_power =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_power", TheModule);
}
return hlvm_f64_ispinf;
}
Function* get_hlvm_f64_root()
{
if (! hlvm_f64_root) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_root",FT);
hlvm_f64_root =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_root", TheModule);
}
return hlvm_f64_ispinf;
}
Function* get_hlvm_f64_gcd()
{
if (! hlvm_f64_gcd) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_gcd",FT);
hlvm_f64_gcd =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_gcd", TheModule);
}
return hlvm_f64_ispinf;
}
Function* get_hlvm_f64_lcm()
{
if (! hlvm_f64_lcm) {
std::vector<const Type*> arg_types;
arg_types.push_back(Type::DoubleTy);
arg_types.push_back(Type::DoubleTy);
FunctionType* FT = FunctionType::get(Type::DoubleTy,arg_types,false);
TheModule->addTypeName("hlvm_f64_lcm",FT);
hlvm_f64_lcm =
new Function(FT, GlobalValue::ExternalLinkage,
"hlvm_f64_lcm", TheModule);
}
return hlvm_f64_ispinf;
}
CallInst* call_hlvm_f64_ispinf(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_ispinf(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_isninf(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_isninf(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_isnan(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_isnan(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_trunc(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_trunc(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_round(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_round(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_floor(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_floor(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_ceiling(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_ceiling(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_loge(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_loge(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_log2(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_log2(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_log10(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_log10(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_squareroot(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_squareroot(), args.begin(), args.end(),
"", TheBlock);
}
CallInst* call_hlvm_f64_cuberoot(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_cuberoot(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_factorial(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_factorial(), args.begin(), args.end(),
"", TheBlock);
}
CallInst* call_hlvm_f64_power(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_power(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_root(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_root(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_gcd(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_gcd(), args.begin(), args.end(), "",
TheBlock);
}
CallInst* call_hlvm_f64_lcm(const hlvm::ArgList& args)
{
return new CallInst(get_hlvm_f64_lcm(), args.begin(), args.end(), "",
TheBlock);
}
/// @}
};
}
namespace hlvm {
LLVMEmitter::LLVMEmitter()
: TheModule(0), TheFunction(0), TheEntryBlock(0), TheExitBlock(0),
EntryInsertionPoint(0), TheBlock(0)
{
}
LLVMEmitter*
new_LLVMEmitter()
{
return new LLVMEmitterImpl();
}
Module*
LLVMEmitter::StartModule(const std::string& ID)
{
hlvmAssert(TheModule == 0);
return TheModule = new Module(ID);
}
Module*
LLVMEmitter::FinishModule()
{
hlvmAssert(TheModule != 0);
Module* result = TheModule;
TheModule = 0;
return result;
}
void
LLVMEmitter::StartFunction(Function* F)
{
hlvmAssert(F != 0 && "Null function?");
hlvmAssert(F->empty() && "Function already emitted!");
// Ensure previous state is cleared
// operands.clear();
// enters.clear();
// exits.clear();
blocks.clear();
breaks.clear();
continues.clear();
// lvars.clear();
// Set up for new function
TheFunction = F;
// Instantiate an entry block for the alloca'd variables. This block
// is only used for such variables. By placing the alloca'd variables in
// the entry block, their allocation is free since the stack pointer
// must be adjusted anyway, all that happens is that it gets adjusted
// by a larger amount.
TheBlock = TheEntryBlock = new BasicBlock("entry",F);
// Instantiate a no-op as an insertion point for the entry point stuff such
// as the alloca variables and argument setup. This allows us to fill and
// terminate the entry block as usual while still retaining a point for
// insertion in the entry block that retains declaration order.
EntryInsertionPoint =
new BitCastInst(Constant::getNullValue(Type::Int32Ty),Type::Int32Ty,
"entry_point", TheEntryBlock);
// Create a new block for the return node, but don't insert it yet.
// TheExitBlock = new BasicBlock("exit");
}
void
LLVMEmitter::FinishFunction()
{
// The entry block was created to hold the automatic variables. We now
// need to terminate the block by branching it to the first active block
// in the function.
Function::iterator I = TheFunction->begin();
++I;
new BranchInst(&*I, &TheFunction->front());
hlvmAssert(blocks.empty());
hlvmAssert(breaks.empty());
hlvmAssert(continues.empty());
}
BasicBlock*
LLVMEmitter::pushBlock(const std::string& name)
{
TheBlock = new BasicBlock(name,TheFunction);
blocks.push_back(TheBlock);
return TheBlock;
}
BasicBlock*
LLVMEmitter::popBlock()
{
BasicBlock* result = blocks.back();
blocks.pop_back();
if (blocks.empty())
TheBlock = 0;
else
TheBlock = blocks.back();
return result;
}
BasicBlock*
LLVMEmitter::newBlock(const std::string& name)
{
blocks.pop_back();
TheBlock = new BasicBlock(name,TheFunction);
blocks.push_back(TheBlock);
return TheBlock;
}
Value*
LLVMEmitter::ConvertToBoolean(Value* V) const
{
const Type* Ty = V->getType();
if (Ty == Type::Int1Ty)
return V;
if (Ty->isInteger() || Ty->isFloatingPoint()) {
Constant* CI = Constant::getNullValue(V->getType());
return new ICmpInst(ICmpInst::ICMP_NE, V, CI, "i2b", TheBlock);
} else if (isa<GlobalValue>(V)) {
// GlobalValues always have non-zero constant address values, so always true
return ConstantInt::getTrue();
}
hlvmAssert(!"Don't know how to convert V into bool");
return ConstantInt::getTrue();
}
Value*
LLVMEmitter::Pointer2Value(Value* V) const
{
if (!isa<PointerType>(V->getType()))
return V;
// GetElementPtrInst* GEP = new GetElementPtrIns(V,
// ConstantInt::get(Type::Int32Ty,0),
// ConstantInt::get(Type::Int32Ty,0),
// "ptr2Value", TheBlock);
return new LoadInst(V,"ptr2Value", TheBlock);
}
bool
LLVMEmitter::IsNoopCast(Value* V, const Type* Ty)
{
// check signed to unsigned
const Type *VTy = V->getType();
if (VTy->canLosslesslyBitCastTo(Ty))
return true;
// Constant int to anything, to work around stuff like: "xor short X, int 1".
if (isa<ConstantInt>(V))
return true;
return false;
}
/// CastToType - Cast the specified value to the specified type if it is
/// not already that type.
Value *
LLVMEmitter::CastToType(Value *V, bool srcIsSigned, const Type *Ty,
bool destIsSigned, const std::string& newName)
{
// If they are the same type, no cast needed
if (V->getType() == Ty)
return V;
// Get the opcode necessary for the cast.
Instruction::CastOps Opcode =
CastInst::getCastOpcode(V, srcIsSigned, Ty, destIsSigned);
// If its a constant then we want a constant cast
if (Constant *C = dyn_cast<Constant>(V))
return ConstantExpr::getCast(Opcode, C, Ty);
// If its a cast instruction and we're casting back to the original type,
// which is bool, then just get the operand of the cast instead of emitting
// duplicate cast instructions. This is just an optimization of a frequently
// occurring case.
if (CastInst *CI = dyn_cast<CastInst>(V))
if (Ty == Type::Int1Ty && CI->getOperand(0)->getType() == Type::Int1Ty)
return CI->getOperand(0);
// Otherwise, just issue the cast
return CastInst::create(Opcode, V, Ty,
(newName.empty() ? V->getName() : newName), TheBlock);
}
void
LLVMEmitter::ResolveBreaks(BasicBlock* exit)
{
for (BranchList::iterator I = breaks.begin(), E = breaks.end(); I != E; ++I) {
(*I)->setOperand(0,exit);
}
breaks.clear();
}
void
LLVMEmitter::ResolveContinues(BasicBlock* entry)
{
for (BranchList::iterator I = continues.begin(), E = continues.end();
I != E; ++I) {
(*I)->setOperand(0,entry);
}
continues.clear();
}
/// Return the number of elements in the specified type that will need to be
/// loaded/stored if we copy this one element at a time.
unsigned
LLVMEmitter::getNumElements(const Type *Ty)
{
if (Ty->isFirstClassType()) return 1;
if (const StructType *STy = dyn_cast<StructType>(Ty)) {
unsigned NumElts = 0;
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
NumElts += getNumElements(STy->getElementType(i));
return NumElts;
} else if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
return ATy->getNumElements() * getNumElements(ATy->getElementType());
} else if (const VectorType* VTy = dyn_cast<VectorType>(Ty)) {
return VTy->getNumElements() * getNumElements(VTy->getElementType());
} else
hlvmAssert(!"Don't know how to count elements of this type");
return 0;
}
Constant*
LLVMEmitter::getFirstElement(GlobalVariable* GV)
{
ArgList indices;
TwoZeroIndices(indices);
return ConstantExpr::getGetElementPtr(GV, &indices[0], 2);
}
FunctionType*
LLVMEmitter::getFunctionType(
const std::string& name, const Type* resultTy,
const TypeList& args, bool varargs)
{
// The args might contain non-first-class typed arguments. We build a
// new argument list the contains the argument types after conversion.
TypeList Params;
// We can't have results that are not first class so we use the
// first argument to point to where the result should be stored and
// switch the result type to VoidTy.
if (!resultTy->isFirstClassType()) {
Params.push_back(getFirstClassType(resultTy));
resultTy = Type::VoidTy;
}
for (TypeList::const_iterator I = args.begin(), E = args.end(); I != E; ++I )
{
if ((*I)->isFirstClassType())
Params.push_back(*I);
else
Params.push_back(getFirstClassType(*I));
}
FunctionType* result = FunctionType::get(resultTy, Params, varargs);
if (!name.empty())
TheModule->addTypeName(name,result);
return result;
}
Type*
LLVMEmitter::getTextType()
{
return static_cast<LLVMEmitterImpl*>(this)->get_hlvm_text();
}
Type*
LLVMEmitter::getStreamType()
{
return static_cast<LLVMEmitterImpl*>(this)->get_hlvm_stream();
}
Type*
LLVMEmitter::getBufferType()
{
return static_cast<LLVMEmitterImpl*>(this)->get_hlvm_buffer();
}
FunctionType*
LLVMEmitter::getProgramType()
{
return static_cast<LLVMEmitterImpl*>(this)->get_hlvm_program_signature();
}
llvm::CmpInst* LLVMEmitter::emitNE(llvm::Value* V1, llvm::Value* V2){
if (V1->getType()->isFloatingPoint())
return new llvm::FCmpInst(llvm::FCmpInst::FCMP_ONE, V1, V2, "ne",TheBlock);
else
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, V1, V2, "ne",TheBlock);
}
llvm::CmpInst* LLVMEmitter::emitEQ(llvm::Value* V1, llvm::Value* V2){
if (V1->getType()->isFloatingPoint())
return new llvm::FCmpInst(llvm::FCmpInst::FCMP_OEQ, V1, V2, "eq",TheBlock);
else
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_EQ, V1, V2, "eq",TheBlock);
}
llvm::CmpInst* LLVMEmitter::emitLT(llvm::Value* V1, llvm::Value* V2, bool sign){
if (V1->getType()->isFloatingPoint())
return new llvm::FCmpInst(llvm::FCmpInst::FCMP_OLT, V1, V2,"olt",TheBlock);
else if (sign)
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_ULT, V1, V2,"ult",TheBlock);
else
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_SLT, V1, V2,"slt",TheBlock);
}
llvm::CmpInst* LLVMEmitter::emitGT(llvm::Value* V1, llvm::Value* V2, bool sign){
if (V1->getType()->isFloatingPoint())
return new llvm::FCmpInst(llvm::FCmpInst::FCMP_OGT, V1, V2,"ogt",TheBlock);
else if (sign)
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_SGT, V1, V2,"sgt",TheBlock);
else
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_UGT, V1, V2,"ugt",TheBlock);
}
llvm::CmpInst* LLVMEmitter::emitLE(llvm::Value* V1, llvm::Value* V2, bool sign){
if (V1->getType()->isFloatingPoint())
return new llvm::FCmpInst(llvm::FCmpInst::FCMP_OLE, V1, V2,"ole",TheBlock);
else if (sign)
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_ULE, V1, V2,"ule",TheBlock);
else
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_SLE, V1, V2,"sle",TheBlock);
}
llvm::CmpInst* LLVMEmitter::emitGE(llvm::Value* V1, llvm::Value* V2, bool sign){
if (V1->getType()->isFloatingPoint())
return new llvm::FCmpInst(llvm::FCmpInst::FCMP_OGE, V1, V2,"oge",TheBlock);
else if (sign)
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_SGE, V1, V2,"sge",TheBlock);
else
return new llvm::ICmpInst(llvm::ICmpInst::ICMP_UGE, V1, V2,"uge",TheBlock);
}
void
LLVMEmitter::emitAssign(Value* dest, Value* src)
{
// If the destination is a load instruction then its the result of a previous
// nested block so just get the first operand as the real destination.
if (isa<LoadInst>(dest))
dest = cast<LoadInst>(dest)->getOperand(0);
// The destination must be a pointer type
hlvmAssert(isa<PointerType>(dest->getType()));
// Get the type of the destination and source
const Type* destTy = cast<PointerType>(dest->getType())->getElementType();
const Type* srcTy = src->getType();
if (destTy->isFirstClassType()) {
// Can't store an aggregate to a first class type
hlvmAssert(srcTy->isFirstClassType());
if (destTy == srcTy) {
// simple case, the types match and they are both first class types,
// just emit a store instruction
emitStore(src,dest);
} else if (const PointerType* srcPT = dyn_cast<PointerType>(srcTy)) {
// The source is a pointer to the value to return so just get a
// pointer to its first element and store it since its pointing to
// a first class type. Assert that this is true.
hlvmAssert( srcPT->getElementType() == destTy );
ArgList idx;
TwoZeroIndices(idx);
GetElementPtrInst* GEP =
new GetElementPtrInst(src, &idx[0], 2, "", TheBlock);
emitStore(GEP,dest);
} else {
// they are both first class types and the source is not a pointer, so
// just cast them. FIXME: signedness
Value* V = CastToType(src, false, destTy, false, src->getName());
emitStore(V, dest);
}
}
else if (const PointerType* srcPT = dyn_cast<PointerType>(srcTy))
{
// We have an aggregate to copy
emitAggregateCopy(dest,src);
}
else if (Constant* srcC = dyn_cast<Constant>(src))
{
// We have a constant aggregate to move into an aggregate gvar. We must
// create a temporary gvar based on the constant in order to copy it.
GlobalVariable* GVar = NewGConst(srcTy, srcC, srcC->getName());
// Now we can aggregate copy it
emitAggregateCopy(dest, GVar);
}
}
/// Recursively traverse the potientially aggregate src/dest ptrs, copying all
/// of the elements from src to dest.
static void
CopyAggregate(
Value *DestPtr,
bool DestVolatile,
Value *SrcPtr,
bool SrcVolatile,
BasicBlock *BB)
{
assert(DestPtr->getType() == SrcPtr->getType() &&
"Cannot copy between two pointers of different type!");
const Type *ElTy = cast<PointerType>(DestPtr->getType())->getElementType();
if (ElTy->isFirstClassType()) {
Value *V = new LoadInst(SrcPtr, "tmp", SrcVolatile, BB);
new StoreInst(V, DestPtr, DestVolatile, BB);
} else if (const StructType *STy = dyn_cast<StructType>(ElTy)) {
Constant *Zero = ConstantInt::get(Type::Int32Ty, 0);
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Constant *Idx = ConstantInt::get(Type::Int32Ty, i);
Value *DElPtr = new GetElementPtrInst(DestPtr, Zero, Idx, "tmp", BB);
Value *SElPtr = new GetElementPtrInst(SrcPtr, Zero, Idx, "tmp", BB);
CopyAggregate(DElPtr, DestVolatile, SElPtr, SrcVolatile, BB);
}
} else {
const ArrayType *ATy = cast<ArrayType>(ElTy);
Constant *Zero = ConstantInt::get(Type::Int32Ty, 0);
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
Constant *Idx = ConstantInt::get(Type::Int32Ty, i);
Value *DElPtr = new GetElementPtrInst(DestPtr, Zero, Idx, "tmp", BB);
Value *SElPtr = new GetElementPtrInst(SrcPtr, Zero, Idx, "tmp", BB);
CopyAggregate(DElPtr, DestVolatile, SElPtr, SrcVolatile, BB);
}
}
}
/// EmitAggregateCopy - Copy the elements from SrcPtr to DestPtr, using the
/// GCC type specified by GCCType to know which elements to copy.
void
LLVMEmitter::emitAggregateCopy(
Value *DestPtr,
Value *SrcPtr )
{
// Make sure we're not mixing apples and oranges
hlvmAssert(DestPtr->getType() == SrcPtr->getType());
// Degenerate case, same pointer
if (DestPtr == SrcPtr)
return; // noop copy.
// If the type has just a few elements, then copy the elements directly
// using load/store. Otherwise use the llvm.memcpy.i64 intrinsic. This just
// saves a function call for really small structures and arrays.
const Type* Ty = SrcPtr->getType();
if (getNumElements(Ty) <= 8)
CopyAggregate(DestPtr, false, SrcPtr, false, TheBlock);
else
emitMemCpy(DestPtr, SrcPtr, ConstantExpr::getSizeOf(Ty));
}
ReturnInst*
LLVMEmitter::emitReturn(Value* retVal)
{
// First deal with the degenerate case, a void return
if (retVal == 0) {
hlvmAssert(getReturnType() == Type::VoidTy);
return new ReturnInst(0,TheBlock);
}
// Now, deal with first class result types. Becasue of the way function
// types are generated, a void type at this point indicates an aggregate
// result. If we don't have a void type, then it must be a first class result.
const Type* resultTy = retVal->getType();
if (getReturnType() != Type::VoidTy) {
Value* result = 0;
if (const PointerType* PTy = dyn_cast<PointerType>(resultTy)) {
// must be an autovar or global var, just load the value
hlvmAssert(PTy->getElementType() == getReturnType());
result = emitLoad(retVal,getBlockName() + "_result");
} else if (resultTy != getReturnType()) {
hlvmAssert(resultTy->isFirstClassType());
// FIXME: signedness
result = CastToType(retVal, false, getReturnType(), false,
getBlockName()+"_result");
} else {
hlvmAssert(resultTy->isFirstClassType());
result = retVal;
}
hlvmAssert(result && "No result for function");
return new ReturnInst(result,TheBlock);
}
// Now, deal with the aggregate result case. At this point the function return
// type must be void and the first argument must be a pointer to the storage
// area for the result.
hlvmAssert(getReturnType() == Type::VoidTy);
// Get the first argument.
hlvmAssert(!TheFunction->arg_empty());
Argument* result_arg = TheFunction->arg_begin();
// Both the first argument and the result should have the same type which
// both should be pointer to the aggregate
hlvmAssert(result_arg->getType() == resultTy);
// Copy the aggregate result
emitAggregateCopy(result_arg, retVal);
// Emit the void return
return new ReturnInst(0, TheBlock);
}
CallInst*
LLVMEmitter::emitCall(Function* F, const ArgList& args)
{
// Detect the aggregate result case
if ((F->getReturnType() == Type::VoidTy) &&
(args.size() == F->arg_size() - 1)) {
const Type* arg1Ty = F->arg_begin()->getType();
if (const PointerType* PTy = dyn_cast<PointerType>(arg1Ty))
{
// This is the case where the result is a temporary variable that
// holds the aggregate and is passed as the first argument
const Type* elemTy = PTy->getElementType();
hlvmAssert(!elemTy->isFirstClassType());
// Get a temporary for the result
AllocaInst* result = NewAutoVar(elemTy, F->getName() + "_result");
// Install the temporary result area into a new arg list
ArgList newArgs;
newArgs.push_back(result);
// Copy the other arguments
for (ArgList::const_iterator I = args.begin(), E = args.end();
I != E; ++I)
if (isa<Constant>(*I) && !isa<GlobalValue>(*I) &&
!(*I)->getType()->isFirstClassType())
newArgs.push_back(NewGConst((*I)->getType(),
cast<Constant>(*I), (*I)->getName()));
else
newArgs.push_back(*I);
// Generate the call
return new CallInst(F, newArgs.begin(), newArgs.end(), "", TheBlock);
}
}
// The result must be a first class type at this point, ensure it
hlvmAssert(F->getReturnType()->isFirstClassType());
// Copy the other arguments
ArgList newArgs;
for (ArgList::const_iterator I = args.begin(), E = args.end();
I != E; ++I)
if (isa<Constant>(*I) && !isa<GlobalValue>(*I) &&
!(*I)->getType()->isFirstClassType())
newArgs.push_back(NewGConst((*I)->getType(),
cast<Constant>(*I), (*I)->getName()));
else
newArgs.push_back(*I);
return new CallInst(F, newArgs.begin(), newArgs.end(),
F->getName() + "_result", TheBlock);
}
void
LLVMEmitter::emitMemCpy(
Value *dest,
Value *src,
Value *size
)
{
const Type *SBP = PointerType::get(Type::Int8Ty);
ArgList args;
args.push_back(CastToType(dest, false, SBP, false, ""));
args.push_back(CastToType(src, false, SBP, false, ""));
args.push_back(size);
args.push_back(ConstantInt::get(Type::Int32Ty, 0u));
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
new CallInst(emimp->get_llvm_memcpy(), args.begin(), args.end(), "",
TheBlock);
}
/// Emit an llvm.memmove.i64 intrinsic
void
LLVMEmitter::emitMemMove(
Value *dest,
Value *src,
Value *size
)
{
const Type *SBP = PointerType::get(Type::Int8Ty);
ArgList args;
args.push_back(CastToType(dest, false, SBP, false, ""));
args.push_back(CastToType(src, false, SBP, false, ""));
args.push_back(size);
args.push_back(ConstantInt::get(Type::Int32Ty, 0u));
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
new CallInst(emimp->get_llvm_memmove(), args.begin(), args.end(), "",
TheBlock);
}
/// Emit an llvm.memset.i64 intrinsic
void
LLVMEmitter::emitMemSet(
Value *dest,
Value *val,
Value *size
)
{
const Type *SBP = PointerType::get(Type::Int8Ty);
ArgList args;
args.push_back(CastToType(dest, false, SBP, false, ""));
args.push_back(CastToType(val, false, Type::Int8Ty, false, ""));
args.push_back(size);
args.push_back(ConstantInt::get(Type::Int32Ty, 0u));
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
new CallInst(emimp->get_llvm_memset(), args.begin(), args.end(), "",
TheBlock);
}
CallInst*
LLVMEmitter::emitOpen(llvm::Value* strm)
{
std::vector<llvm::Value*> args;
if (const llvm::PointerType* PT =
llvm::dyn_cast<llvm::PointerType>(strm->getType()))
{
const llvm::Type* Ty = PT->getElementType();
if (Ty == llvm::Type::Int8Ty) {
args.push_back(strm);
} else if (llvm::isa<ArrayType>(Ty) &&
cast<ArrayType>(Ty)->getElementType() == Type::Int8Ty) {
ArgList indices;
this->TwoZeroIndices(indices);
args.push_back(this->emitGEP(strm,indices));
} else
hlvmAssert(!"Array element type is not Int8Ty");
} else
hlvmAssert(!"OpenOp parameter is not a pointer");
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
return emimp->call_hlvm_stream_open(args,"open");
}
CallInst*
LLVMEmitter::emitClose(llvm::Value* strm)
{
std::vector<llvm::Value*> args;
args.push_back(strm);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
return emimp->call_hlvm_stream_close(args);
}
CallInst*
LLVMEmitter::emitRead(llvm::Value* strm,llvm::Value* arg2, llvm::Value* arg3)
{
std::vector<llvm::Value*> args;
args.push_back(strm);
args.push_back(arg2);
args.push_back(arg3);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
return emimp->call_hlvm_stream_read(args,"read");
}
CallInst*
LLVMEmitter::emitWrite(llvm::Value* strm,llvm::Value* arg2)
{
std::vector<llvm::Value*> args;
args.push_back(strm);
args.push_back(arg2);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
CallInst* result = 0;
if (llvm::isa<llvm::PointerType>(arg2->getType()))
if (llvm::cast<llvm::PointerType>(arg2->getType())->getElementType() ==
llvm::Type::Int8Ty)
result = emimp->call_hlvm_stream_write_string(args,"write");
if (arg2->getType() == emimp->get_hlvm_text())
result = emimp->call_hlvm_stream_write_text(args,"write");
else if (arg2->getType() == emimp->get_hlvm_buffer())
result = emimp->call_hlvm_stream_write_buffer(args,"write");
return result;
}
CallInst*
LLVMEmitter::emitIsPInf(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_ispinf(args);
return emimp->call_hlvm_f64_ispinf(args);
}
CallInst*
LLVMEmitter::emitIsNInf(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_isninf(args);
return emimp->call_hlvm_f64_isninf(args);
}
CallInst*
LLVMEmitter::emitIsNan(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_isnan(args);
return emimp->call_hlvm_f64_isnan(args);
}
CallInst*
LLVMEmitter::emitTrunc(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_trunc(args);
return emimp->call_hlvm_f64_trunc(args);
}
CallInst*
LLVMEmitter::emitRound(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_round(args);
return emimp->call_hlvm_f64_round(args);
}
CallInst*
LLVMEmitter::emitFloor(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_floor(args);
return emimp->call_hlvm_f64_floor(args);
}
CallInst*
LLVMEmitter::emitCeiling(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_ceiling(args);
return emimp->call_hlvm_f64_ceiling(args);
}
CallInst*
LLVMEmitter::emitLogE(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_loge(args);
return emimp->call_hlvm_f64_loge(args);
}
CallInst*
LLVMEmitter::emitLog2(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_log2(args);
return emimp->call_hlvm_f64_log2(args);
}
CallInst*
LLVMEmitter::emitLog10(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_log10(args);
return emimp->call_hlvm_f64_log10(args);
}
CallInst*
LLVMEmitter::emitSquareRoot(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_squareroot(args);
return emimp->call_hlvm_f64_squareroot(args);
}
CallInst*
LLVMEmitter::emitCubeRoot(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_cuberoot(args);
return emimp->call_hlvm_f64_cuberoot(args);
}
CallInst*
LLVMEmitter::emitFactorial(Value* V)
{
std::vector<llvm::Value*> args;
args.push_back(V);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V->getType()->isFloatingPoint());
if (Type::FloatTy == V->getType())
return emimp->call_hlvm_f32_factorial(args);
return emimp->call_hlvm_f64_factorial(args);
}
CallInst*
LLVMEmitter::emitPower(Value* V1,Value*V2)
{
std::vector<llvm::Value*> args;
args.push_back(V1);
args.push_back(V2);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V1->getType()->isFloatingPoint());
hlvmAssert(V2->getType()->isFloatingPoint());
if (Type::FloatTy == V1->getType())
return emimp->call_hlvm_f32_power(args);
return emimp->call_hlvm_f64_power(args);
}
CallInst*
LLVMEmitter::emitRoot(Value* V1,Value*V2)
{
std::vector<llvm::Value*> args;
args.push_back(V1);
args.push_back(V2);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V1->getType()->isFloatingPoint());
hlvmAssert(V2->getType()->isFloatingPoint());
if (Type::FloatTy == V1->getType())
return emimp->call_hlvm_f32_root(args);
return emimp->call_hlvm_f64_root(args);
}
CallInst*
LLVMEmitter::emitGCD(Value* V1,Value*V2)
{
std::vector<llvm::Value*> args;
args.push_back(V1);
args.push_back(V2);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V1->getType()->isFloatingPoint());
hlvmAssert(V2->getType()->isFloatingPoint());
if (Type::FloatTy == V1->getType())
return emimp->call_hlvm_f32_gcd(args);
return emimp->call_hlvm_f64_gcd(args);
}
CallInst*
LLVMEmitter::emitLCM(Value* V1,Value*V2)
{
std::vector<llvm::Value*> args;
args.push_back(V1);
args.push_back(V2);
LLVMEmitterImpl* emimp = static_cast<LLVMEmitterImpl*>(this);
hlvmAssert(V1->getType()->isFloatingPoint());
hlvmAssert(V2->getType()->isFloatingPoint());
if (Type::FloatTy == V1->getType())
return emimp->call_hlvm_f32_lcm(args);
return emimp->call_hlvm_f64_lcm(args);
}
}