1
0
mirror of https://github.com/RPCSX/llvm.git synced 2025-04-07 18:51:48 +00:00
Reid Spencer c37a506d44 Make the StackerCompiler and optimizing translator by running specific
optimizations after construction of the Module. The OptLevel argument
to the compile function controls the level of optimization.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16166 91177308-0d34-0410-b5e6-96231b3b80d8
2004-09-04 19:07:32 +00:00

1807 lines
52 KiB
C++

//===-- StackerCompiler.cpp - Parser for llvm assembly files ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and donated to the LLVM research
// group and is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the compiler for the "Stacker" language.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Globasl - Global variables we use
//===----------------------------------------------------------------------===//
#include "llvm/PassManager.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/ADT/Statistic.h"
#include "StackerCompiler.h"
#include "StackerParser.h"
#include <string>
// Lexer/Parser defined variables and functions
extern std::FILE *Stackerin;
extern int Stackerlineno;
extern char* Stackertext;
extern int Stackerleng;
extern int Stackerparse();
StackerCompiler* StackerCompiler::TheInstance = 0;
static Statistic<> NumDefinitions(
"numdefs","The # of definitions encoutered while compiling Stacker");
StackerCompiler::StackerCompiler()
: CurFilename("")
, TheModule(0)
, TheFunction(0)
, DefinitionType(0)
, TheStack(0)
, TheIndex(0)
, TheScanf(0)
, ThePrintf(0)
, TheExit(0)
, StrFormat(0)
, NumFormat(0)
, ChrFormat(0)
, InStrFormat(0)
, InNumFormat(0)
, InChrFormat(0)
, Zero(0)
, One(0)
, Two(0)
, Three(0)
, Four(0)
, Five(0)
, no_arguments()
, echo(false)
, stack_size(256)
, stack_type(0)
{
}
StackerCompiler::~StackerCompiler()
{
// delete TheModule; << don't do this!
// TheModule is passed to caller of the compile() method .. its their
// problem. Likewise for the other allocated objects (which become part
// of TheModule.
TheModule = 0;
DefinitionType = 0;
TheStack = 0;
TheIndex = 0;
}
Module*
StackerCompiler::compile(
const std::string& filename,
bool should_echo,
unsigned optLevel,
size_t the_stack_size
)
{
// TODO: Provide a global lock to protect the singled-threaded compiler
// and its global variables. Should be in guard object on the stack so
// that its destructor causes lock to be released (multiple exits from
// this function).
// Assign parameters
CurFilename = filename;
echo = should_echo;
stack_size = the_stack_size;
/// Default the file to read
FILE *F = stdin;
///
if (filename != "-")
{
F = fopen(filename.c_str(), "r");
if (F == 0)
{
throw ParseException(filename,
"Could not open file '" + filename + "'");
}
}
Module *Result;
try
{
// Create the module we'll return
TheModule = new Module( CurFilename );
// Tell the module about our runtime library
TheModule->addLibrary("stkr_runtime");
// Create a type to represent the stack. This is the same as the LLVM
// Assembly type [ 256 x long ]
stack_type = ArrayType::get( Type::LongTy, stack_size );
// Create a global variable for the stack. Note the use of appending
// linkage linkage so that multiple modules will make the stack larger.
// Also note that the last argument causes the global to be inserted
// automatically into the module.
TheStack = new GlobalVariable(
/*type=*/ stack_type,
/*isConstant=*/ false,
/*Linkage=*/ GlobalValue::LinkOnceLinkage,
/*initializer=*/ Constant::getNullValue(stack_type),
/*name=*/ "_stack_",
/*parent=*/ TheModule
);
// Create a global variable for indexing into the stack. Note the use
// of LinkOnce linkage. Only one copy of _index_ will be retained
// after linking
TheIndex = new GlobalVariable(
/*type=*/Type::LongTy,
/*isConstant=*/false,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/ Constant::getNullValue(Type::LongTy),
/*name=*/"_index_",
/*parent=*/TheModule
);
// Create a function prototype for definitions. No parameters, no
// result. This is used below any time a function is created.
std::vector<const Type*> params; // No parameters
DefinitionType = FunctionType::get( Type::VoidTy, params, false );
// Create a function for printf(3)
params.push_back( PointerType::get( Type::SByteTy ) );
FunctionType* printf_type =
FunctionType::get( Type::IntTy, params, true );
ThePrintf = new Function(
printf_type, GlobalValue::ExternalLinkage, "printf", TheModule);
// Create a function for scanf(3)
TheScanf = new Function(
printf_type, GlobalValue::ExternalLinkage, "scanf", TheModule);
// Create a function for exit(3)
params.clear();
params.push_back( Type::IntTy );
FunctionType* exit_type =
FunctionType::get( Type::VoidTy, params, false );
TheExit = new Function(
exit_type, GlobalValue::ExternalLinkage, "exit", TheModule);
Constant* str_format = ConstantArray::get("%s");
StrFormat = new GlobalVariable(
/*type=*/ArrayType::get( Type::SByteTy, 3 ),
/*isConstant=*/true,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/str_format,
/*name=*/"_str_format_",
/*parent=*/TheModule
);
Constant* in_str_format = ConstantArray::get(" %as");
InStrFormat = new GlobalVariable(
/*type=*/ArrayType::get( Type::SByteTy, 5 ),
/*isConstant=*/true,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/in_str_format,
/*name=*/"_in_str_format_",
/*parent=*/TheModule
);
Constant* num_format = ConstantArray::get("%d");
NumFormat = new GlobalVariable(
/*type=*/ArrayType::get( Type::SByteTy, 3 ),
/*isConstant=*/true,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/num_format,
/*name=*/"_num_format_",
/*parent=*/TheModule
);
Constant* in_num_format = ConstantArray::get(" %d");
InNumFormat = new GlobalVariable(
/*type=*/ArrayType::get( Type::SByteTy, 4 ),
/*isConstant=*/true,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/in_num_format,
/*name=*/"_in_num_format_",
/*parent=*/TheModule
);
Constant* chr_format = ConstantArray::get("%c");
ChrFormat = new GlobalVariable(
/*type=*/ArrayType::get( Type::SByteTy, 3 ),
/*isConstant=*/true,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/chr_format,
/*name=*/"_chr_format_",
/*parent=*/TheModule
);
Constant* in_chr_format = ConstantArray::get(" %c");
InChrFormat = new GlobalVariable(
/*type=*/ArrayType::get( Type::SByteTy, 4 ),
/*isConstant=*/true,
/*Linkage=*/GlobalValue::LinkOnceLinkage,
/*initializer=*/in_chr_format,
/*name=*/"_in_chr_format_",
/*parent=*/TheModule
);
// Get some constants so we aren't always creating them
Zero = ConstantInt::get( Type::LongTy, 0 );
One = ConstantInt::get( Type::LongTy, 1 );
Two = ConstantInt::get( Type::LongTy, 2 );
Three = ConstantInt::get( Type::LongTy, 3 );
Four = ConstantInt::get( Type::LongTy, 4 );
Five = ConstantInt::get( Type::LongTy, 5 );
// Reset the current line number
Stackerlineno = 1;
// Reset the parser's input to F
Stackerin = F; // Set the input file.
// Let the parse know about this instance
TheInstance = this;
// Parse the file. The parser (see StackParser.y) will call back to
// the StackerCompiler via the "handle*" methods
Stackerparse();
// Avoid potential illegal use (TheInstance might be on the stack)
TheInstance = 0;
// Set up a pass manager
PassManager Passes;
// Add in the passes we want to execute
Passes.add(new TargetData("stkrc",TheModule));
// Verify we start with valid
Passes.add(createVerifierPass());
if (optLevel > 0) {
if (optLevel > 1) {
// Clean up disgusting code
Passes.add(createCFGSimplificationPass());
// Mark read-only globals const
Passes.add(createGlobalConstifierPass());
// Remove unused globals
Passes.add(createGlobalDCEPass());
// IP Constant Propagation
Passes.add(createIPConstantPropagationPass());
// Clean up after IPCP
Passes.add(createInstructionCombiningPass());
// Clean up after IPCP
Passes.add(createCFGSimplificationPass());
// Inline small definitions (functions)
Passes.add(createFunctionInliningPass());
// Simplify cfg by copying code
Passes.add(createTailDuplicationPass());
if (optLevel > 2) {
// Merge & remove BBs
Passes.add(createCFGSimplificationPass());
// Compile silly sequences
Passes.add(createInstructionCombiningPass());
// Reassociate expressions
Passes.add(createReassociatePass());
// Combine silly seq's
Passes.add(createInstructionCombiningPass());
// Eliminate tail calls
Passes.add(createTailCallEliminationPass());
// Merge & remove BBs
Passes.add(createCFGSimplificationPass());
// Hoist loop invariants
Passes.add(createLICMPass());
// Clean up after the unroller
Passes.add(createInstructionCombiningPass());
// Canonicalize indvars
Passes.add(createIndVarSimplifyPass());
// Unroll small loops
Passes.add(createLoopUnrollPass());
// Clean up after the unroller
Passes.add(createInstructionCombiningPass());
// GVN for load instructions
Passes.add(createLoadValueNumberingPass());
// Remove common subexprs
Passes.add(createGCSEPass());
// Constant prop with SCCP
Passes.add(createSCCPPass());
}
if (optLevel > 3) {
// Run instcombine again after redundancy elimination
Passes.add(createInstructionCombiningPass());
// Delete dead stores
Passes.add(createDeadStoreEliminationPass());
// SSA based 'Aggressive DCE'
Passes.add(createAggressiveDCEPass());
// Merge & remove BBs
Passes.add(createCFGSimplificationPass());
// Merge dup global constants
Passes.add(createConstantMergePass());
}
}
// Merge & remove BBs
Passes.add(createCFGSimplificationPass());
// Memory To Register
Passes.add(createPromoteMemoryToRegister());
// Compile silly sequences
Passes.add(createInstructionCombiningPass());
// Make sure everything is still good.
Passes.add(createVerifierPass());
}
// Run our queue of passes all at once now, efficiently.
Passes.run(*TheModule);
} catch (...) {
if (F != stdin) fclose(F); // Make sure to close file descriptor
throw; // if an exception is thrown
}
// Close the file
if (F != stdin) fclose(F);
// Return the compiled module to the caller
return TheModule;
}
//===----------------------------------------------------------------------===//
// Internal Functions, used by handleXXX below.
// These represent the basic stack operations.
//===----------------------------------------------------------------------===//
Instruction*
StackerCompiler::incr_stack_index( BasicBlock* bb, Value* ival = 0 )
{
// Load the value from the TheIndex
LoadInst* loadop = new LoadInst( TheIndex );
bb->getInstList().push_back( loadop );
// Increment the loaded index value
if ( ival == 0 ) ival = One;
CastInst* caster = new CastInst( ival, Type::LongTy );
bb->getInstList().push_back( caster );
BinaryOperator* addop = BinaryOperator::create( Instruction::Add,
loadop, caster);
bb->getInstList().push_back( addop );
// Store the incremented value
StoreInst* storeop = new StoreInst( addop, TheIndex );
bb->getInstList().push_back( storeop );
return storeop;
}
Instruction*
StackerCompiler::decr_stack_index( BasicBlock* bb, Value* ival = 0 )
{
// Load the value from the TheIndex
LoadInst* loadop = new LoadInst( TheIndex );
bb->getInstList().push_back( loadop );
// Decrement the loaded index value
if ( ival == 0 ) ival = One;
CastInst* caster = new CastInst( ival, Type::LongTy );
bb->getInstList().push_back( caster );
BinaryOperator* subop = BinaryOperator::create( Instruction::Sub,
loadop, caster);
bb->getInstList().push_back( subop );
// Store the incremented value
StoreInst* storeop = new StoreInst( subop, TheIndex );
bb->getInstList().push_back( storeop );
return storeop;
}
Instruction*
StackerCompiler::get_stack_pointer( BasicBlock* bb, Value* index = 0 )
{
// Load the value of the Stack Index
LoadInst* loadop = new LoadInst( TheIndex );
bb->getInstList().push_back( loadop );
// Index into the stack to get its address. NOTE the use of two
// elements in this vector. The first de-references the pointer that
// "TheStack" represents. The second indexes into the pointed to array.
// Think of the first index as getting the address of the 0th element
// of the array.
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
if ( index == 0 )
{
indexVec.push_back(loadop);
}
else
{
CastInst* caster = new CastInst( index, Type::LongTy );
bb->getInstList().push_back( caster );
BinaryOperator* subop = BinaryOperator::create(
Instruction::Sub, loadop, caster );
bb->getInstList().push_back( subop );
indexVec.push_back(subop);
}
// Get the address of the indexed stack element
GetElementPtrInst* gep = new GetElementPtrInst( TheStack, indexVec );
bb->getInstList().push_back( gep ); // Put GEP in Block
return gep;
}
Instruction*
StackerCompiler::push_value( BasicBlock* bb, Value* val )
{
// Get location of
incr_stack_index(bb);
// Get the stack pointer
GetElementPtrInst* gep = cast<GetElementPtrInst>(
get_stack_pointer( bb ) );
// Cast the value to a long .. hopefully it works
CastInst* cast_inst = new CastInst( val, Type::LongTy );
bb->getInstList().push_back( cast_inst );
// Store the value
StoreInst* storeop = new StoreInst( cast_inst, gep );
bb->getInstList().push_back( storeop );
return storeop;
}
Instruction*
StackerCompiler::push_integer(BasicBlock* bb, int64_t value )
{
// Just push a constant integer value
return push_value( bb, ConstantSInt::get( Type::LongTy, value ) );
}
Instruction*
StackerCompiler::pop_integer( BasicBlock*bb )
{
// Get the stack pointer
GetElementPtrInst* gep = cast<GetElementPtrInst>(
get_stack_pointer( bb ));
// Load the value
LoadInst* load_inst = new LoadInst( gep );
bb->getInstList().push_back( load_inst );
// Decrement the stack index
decr_stack_index( bb );
// Return the value
return load_inst;
}
Instruction*
StackerCompiler::push_string( BasicBlock* bb, const char* value )
{
// Get length of the string
size_t len = strlen( value );
// Create a type for the string constant. Length is +1 for
// the terminating 0.
ArrayType* char_array = ArrayType::get( Type::SByteTy, len + 1 );
// Create an initializer for the value
Constant* initVal = ConstantArray::get( value );
// Create an internal linkage global variable to hold the constant.
GlobalVariable* strconst = new GlobalVariable(
char_array,
/*isConstant=*/true,
GlobalValue::InternalLinkage,
/*initializer=*/initVal,
"",
TheModule
);
// Push the casted value
return push_value( bb, strconst );
}
Instruction*
StackerCompiler::pop_string( BasicBlock* bb )
{
// Get location of stack pointer
GetElementPtrInst* gep = cast<GetElementPtrInst>(
get_stack_pointer( bb ));
// Load the value from the stack
LoadInst* loader = new LoadInst( gep );
bb->getInstList().push_back( loader );
// Cast the integer to a sbyte*
CastInst* caster = new CastInst( loader, PointerType::get(Type::SByteTy) );
bb->getInstList().push_back( caster );
// Decrement stack index
decr_stack_index( bb );
// Return the value
return caster;
}
Instruction*
StackerCompiler::replace_top( BasicBlock* bb, Value* new_top, Value* index = 0 )
{
// Get the stack pointer
GetElementPtrInst* gep = cast<GetElementPtrInst>(
get_stack_pointer( bb, index ));
// Store the value there
StoreInst* store_inst = new StoreInst( new_top, gep );
bb->getInstList().push_back( store_inst );
// Return the value
return store_inst;
}
Instruction*
StackerCompiler::stack_top( BasicBlock* bb, Value* index = 0 )
{
// Get the stack pointer
GetElementPtrInst* gep = cast<GetElementPtrInst>(
get_stack_pointer( bb, index ));
// Load the value
LoadInst* load_inst = new LoadInst( gep );
bb->getInstList().push_back( load_inst );
// Return the value
return load_inst;
}
Instruction*
StackerCompiler::stack_top_string( BasicBlock* bb, Value* index = 0 )
{
// Get location of stack pointer
GetElementPtrInst* gep = cast<GetElementPtrInst>(
get_stack_pointer( bb, index ));
// Load the value from the stack
LoadInst* loader = new LoadInst( gep );
bb->getInstList().push_back( loader );
// Cast the integer to a sbyte*
CastInst* caster = new CastInst( loader, PointerType::get(Type::SByteTy) );
bb->getInstList().push_back( caster );
// Return the value
return caster;
}
static void
add_block( Function*f, BasicBlock* bb )
{
if ( ! f->empty() && f->back().getTerminator() == 0 )
{
BranchInst* branch = new BranchInst(bb);
f->back().getInstList().push_back( branch );
}
f->getBasicBlockList().push_back( bb );
}
//===----------------------------------------------------------------------===//
// handleXXX - Handle semantics of parser productions
//===----------------------------------------------------------------------===//
Module*
StackerCompiler::handle_module_start( )
{
// Return the newly created module
return TheModule;
}
Module*
StackerCompiler::handle_module_end( Module* mod )
{
// Return the module.
return mod;
}
Module*
StackerCompiler::handle_definition_list_start()
{
return TheModule;
}
Module*
StackerCompiler::handle_definition_list_end( Module* mod, Function* definition )
{
if ( ! definition->empty() )
{
BasicBlock& last_block = definition->back();
if ( last_block.getTerminator() == 0 )
{
last_block.getInstList().push_back( new ReturnInst() );
}
}
// Insert the definition into the module
mod->getFunctionList().push_back( definition );
// Bump our (sample) statistic.
++NumDefinitions;
return mod;
}
Function*
StackerCompiler::handle_main_definition( Function* func )
{
// Set the name of the function defined as the Stacker main
// This will get called by the "main" that is defined in
// the runtime library.
func->setName( "_MAIN_");
// Turn "_stack_" into an initialized variable since this is the main
// module. This causes it to not be "external" but defined in this module.
TheStack->setInitializer( Constant::getNullValue(stack_type) );
TheStack->setLinkage( GlobalValue::LinkOnceLinkage );
// Turn "_index_" into an intialized variable for the same reason.
TheIndex->setInitializer( Constant::getNullValue(Type::LongTy) );
TheIndex->setLinkage( GlobalValue::LinkOnceLinkage );
return func;
}
Function*
StackerCompiler::handle_forward( char * name )
{
// Just create a placeholder function
Function* the_function = new Function (
DefinitionType,
GlobalValue::ExternalLinkage,
name );
assert( the_function->isExternal() );
free( name );
return the_function;
}
Function*
StackerCompiler::handle_definition( char * name, Function* f )
{
// Look up the function name in the module to see if it was forward
// declared.
Function* existing_function = TheModule->getNamedFunction( name );
#if 0
// If the function already exists...
if ( existing_function )
{
// Just get rid of the placeholder
existing_function->dropAllReferences();
delete existing_function;
}
#endif
// Just set the name of the function now that we know what it is.
f->setName( name );
free( name );
return f;
}
Function*
StackerCompiler::handle_word_list_start()
{
TheFunction = new Function(DefinitionType, GlobalValue::ExternalLinkage);
return TheFunction;
}
Function*
StackerCompiler::handle_word_list_end( Function* f, BasicBlock* bb )
{
add_block( f, bb );
return f;
}
BasicBlock*
StackerCompiler::handle_if( char* ifTrue, char* ifFalse )
{
// Create a basic block for the preamble
BasicBlock* bb = new BasicBlock((echo?"if":""));
// Get the condition value
LoadInst* cond = cast<LoadInst>( pop_integer(bb) );
// Compare the condition against 0
SetCondInst* cond_inst = new SetCondInst( Instruction::SetNE, cond,
ConstantSInt::get( Type::LongTy, 0) );
bb->getInstList().push_back( cond_inst );
// Create an exit block
BasicBlock* exit_bb = new BasicBlock((echo?"endif":""));
// Create the true_block
BasicBlock* true_bb = new BasicBlock((echo?"then":""));
// Create the false_block
BasicBlock* false_bb = 0;
if ( ifFalse ) false_bb = new BasicBlock((echo?"else":""));
// Create a branch on the SetCond
BranchInst* br_inst = new BranchInst( true_bb,
( ifFalse ? false_bb : exit_bb ), cond_inst );
bb->getInstList().push_back( br_inst );
// Fill the true block
std::vector<Value*> args;
if ( Function* true_func = TheModule->getNamedFunction(ifTrue) )
{
true_bb->getInstList().push_back(
new CallInst( true_func, args ) );
true_bb->getInstList().push_back(
new BranchInst( exit_bb ) );
}
else
{
ThrowException(std::string("Function '") + ifTrue +
"' must be declared first.'");
}
free( ifTrue );
// Fill the false block
if ( false_bb )
{
if ( Function* false_func = TheModule->getNamedFunction(ifFalse) )
{
false_bb->getInstList().push_back(
new CallInst( false_func, args ) );
false_bb->getInstList().push_back(
new BranchInst( exit_bb ) );
}
else
{
ThrowException(std::string("Function '") + ifFalse +
"' must be declared first.'");
}
free( ifFalse );
}
// Add the blocks to the function
add_block( TheFunction, bb );
add_block( TheFunction, true_bb );
if ( false_bb ) add_block( TheFunction, false_bb );
return exit_bb;
}
BasicBlock*
StackerCompiler::handle_while( char* todo )
{
// Create a basic block for the loop test
BasicBlock* test = new BasicBlock((echo?"while":""));
// Create an exit block
BasicBlock* exit = new BasicBlock((echo?"end":""));
// Create a loop body block
BasicBlock* body = new BasicBlock((echo?"do":""));
// Create a root node
BasicBlock* bb = new BasicBlock((echo?"root":""));
BranchInst* root_br_inst = new BranchInst( test );
bb->getInstList().push_back( root_br_inst );
// Pop the condition value
LoadInst* cond = cast<LoadInst>( stack_top(test) );
// Compare the condition against 0
SetCondInst* cond_inst = new SetCondInst(
Instruction::SetNE, cond, ConstantSInt::get( Type::LongTy, 0) );
test->getInstList().push_back( cond_inst );
// Add the branch instruction
BranchInst* br_inst = new BranchInst( body, exit, cond_inst );
test->getInstList().push_back( br_inst );
// Fill in the body
std::vector<Value*> args;
if ( Function* body_func = TheModule->getNamedFunction(todo) )
{
body->getInstList().push_back( new CallInst( body_func, args ) );
body->getInstList().push_back( new BranchInst( test ) );
}
else
{
ThrowException(std::string("Function '") + todo +
"' must be declared first.'");
}
free( todo );
// Add the blocks
add_block( TheFunction, bb );
add_block( TheFunction, test );
add_block( TheFunction, body );
return exit;
}
BasicBlock*
StackerCompiler::handle_identifier( char * name )
{
Function* func = TheModule->getNamedFunction( name );
BasicBlock* bb = new BasicBlock((echo?"call":""));
if ( func )
{
CallInst* call_def = new CallInst( func , no_arguments );
bb->getInstList().push_back( call_def );
}
else
{
ThrowException(std::string("Definition '") + name +
"' must be defined before it can be used.");
}
free( name );
return bb;
}
BasicBlock*
StackerCompiler::handle_string( char * value )
{
// Create a new basic block for the push operation
BasicBlock* bb = new BasicBlock((echo?"string":""));
// Push the string onto the stack
push_string(bb, value);
// Free the strdup'd string
free( value );
return bb;
}
BasicBlock*
StackerCompiler::handle_integer( const int64_t value )
{
// Create a new basic block for the push operation
BasicBlock* bb = new BasicBlock((echo?"int":""));
// Push the integer onto the stack
push_integer(bb, value );
return bb;
}
BasicBlock*
StackerCompiler::handle_word( int tkn )
{
// Create a new basic block to hold the instruction(s)
BasicBlock* bb = new BasicBlock();
/* Fill the basic block with the appropriate instructions */
switch ( tkn )
{
case DUMP : // Dump the stack (debugging aid)
{
if (echo) bb->setName("DUMP");
Function* f = TheModule->getOrInsertFunction(
"_stacker_dump_stack_", DefinitionType);
std::vector<Value*> args;
bb->getInstList().push_back( new CallInst( f, args ) );
break;
}
// Logical Operations
case TRUETOK : // -- -1
{
if (echo) bb->setName("TRUE");
push_integer(bb,-1);
break;
}
case FALSETOK : // -- 0
{
if (echo) bb->setName("FALSE");
push_integer(bb,0);
break;
}
case LESS : // w1 w2 -- w2<w1
{
if (echo) bb->setName("LESS");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetLT, op1, op2 );
bb->getInstList().push_back( cond_inst );
push_value( bb, cond_inst );
break;
}
case MORE : // w1 w2 -- w2>w1
{
if (echo) bb->setName("MORE");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetGT, op1, op2 );
bb->getInstList().push_back( cond_inst );
push_value( bb, cond_inst );
break;
}
case LESS_EQUAL : // w1 w2 -- w2<=w1
{
if (echo) bb->setName("LE");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetLE, op1, op2 );
bb->getInstList().push_back( cond_inst );
push_value( bb, cond_inst );
break;
}
case MORE_EQUAL : // w1 w2 -- w2>=w1
{
if (echo) bb->setName("GE");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetGE, op1, op2 );
bb->getInstList().push_back( cond_inst );
push_value( bb, cond_inst );
break;
}
case NOT_EQUAL : // w1 w2 -- w2!=w1
{
if (echo) bb->setName("NE");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetNE, op1, op2 );
bb->getInstList().push_back( cond_inst );
push_value( bb, cond_inst );
break;
}
case EQUAL : // w1 w2 -- w1==w2
{
if (echo) bb->setName("EQ");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetEQ, op1, op2 );
bb->getInstList().push_back( cond_inst );
push_value( bb, cond_inst );
break;
}
// Arithmetic Operations
case PLUS : // w1 w2 -- w2+w1
{
if (echo) bb->setName("ADD");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* addop =
BinaryOperator::create( Instruction::Add, op1, op2);
bb->getInstList().push_back( addop );
push_value( bb, addop );
break;
}
case MINUS : // w1 w2 -- w2-w1
{
if (echo) bb->setName("SUB");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* subop =
BinaryOperator::create( Instruction::Sub, op1, op2);
bb->getInstList().push_back( subop );
push_value( bb, subop );
break;
}
case INCR : // w1 -- w1+1
{
if (echo) bb->setName("INCR");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* addop =
BinaryOperator::create( Instruction::Add, op1, One );
bb->getInstList().push_back( addop );
push_value( bb, addop );
break;
}
case DECR : // w1 -- w1-1
{
if (echo) bb->setName("DECR");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* subop = BinaryOperator::create( Instruction::Sub, op1,
ConstantSInt::get( Type::LongTy, 1 ) );
bb->getInstList().push_back( subop );
push_value( bb, subop );
break;
}
case MULT : // w1 w2 -- w2*w1
{
if (echo) bb->setName("MUL");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* multop =
BinaryOperator::create( Instruction::Mul, op1, op2);
bb->getInstList().push_back( multop );
push_value( bb, multop );
break;
}
case DIV :// w1 w2 -- w2/w1
{
if (echo) bb->setName("DIV");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* divop =
BinaryOperator::create( Instruction::Div, op1, op2);
bb->getInstList().push_back( divop );
push_value( bb, divop );
break;
}
case MODULUS : // w1 w2 -- w2%w1
{
if (echo) bb->setName("MOD");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* divop =
BinaryOperator::create( Instruction::Rem, op1, op2);
bb->getInstList().push_back( divop );
push_value( bb, divop );
break;
}
case STAR_SLASH : // w1 w2 w3 -- (w3*w2)/w1
{
if (echo) bb->setName("STAR_SLASH");
// Get the operands
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
LoadInst* op3 = cast<LoadInst>(pop_integer(bb));
// Multiply the first two
BinaryOperator* multop =
BinaryOperator::create( Instruction::Mul, op1, op2);
bb->getInstList().push_back( multop );
// Divide by the third operand
BinaryOperator* divop =
BinaryOperator::create( Instruction::Div, multop, op3);
bb->getInstList().push_back( divop );
// Push the result
push_value( bb, divop );
break;
}
case NEGATE : // w1 -- -w1
{
if (echo) bb->setName("NEG");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
// APPARENTLY, the following doesn't work:
// BinaryOperator* negop = BinaryOperator::createNeg( op1 );
// bb->getInstList().push_back( negop );
// So we'll multiply by -1 (ugh)
BinaryOperator* multop = BinaryOperator::create( Instruction::Mul, op1,
ConstantSInt::get( Type::LongTy, -1 ) );
bb->getInstList().push_back( multop );
push_value( bb, multop );
break;
}
case ABS : // w1 -- |w1|
{
if (echo) bb->setName("ABS");
// Get the top of stack value
LoadInst* op1 = cast<LoadInst>(stack_top(bb));
// Determine if its negative
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetLT, op1, Zero );
bb->getInstList().push_back( cond_inst );
// Create a block for storing the result
BasicBlock* exit_bb = new BasicBlock((echo?"exit":""));
// Create a block for making it a positive value
BasicBlock* pos_bb = new BasicBlock((echo?"neg":""));
// Create the branch on the SetCond
BranchInst* br_inst = new BranchInst( pos_bb, exit_bb, cond_inst );
bb->getInstList().push_back( br_inst );
// Fill out the negation block
LoadInst* pop_op = cast<LoadInst>( pop_integer(pos_bb) );
BinaryOperator* neg_op = BinaryOperator::createNeg( pop_op );
pos_bb->getInstList().push_back( neg_op );
push_value( pos_bb, neg_op );
pos_bb->getInstList().push_back( new BranchInst( exit_bb ) );
// Add the new blocks in the correct order
add_block( TheFunction, bb );
add_block( TheFunction, pos_bb );
bb = exit_bb;
break;
}
case MIN : // w1 w2 -- (w2<w1?w2:w1)
{
if (echo) bb->setName("MIN");
// Create the three blocks
BasicBlock* exit_bb = new BasicBlock((echo?"exit":""));
BasicBlock* op1_block = new BasicBlock((echo?"less":""));
BasicBlock* op2_block = new BasicBlock((echo?"more":""));
// Get the two operands
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
// Compare them
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetLT, op1, op2);
bb->getInstList().push_back( cond_inst );
// Create a branch on the SetCond
BranchInst* br_inst =
new BranchInst( op1_block, op2_block, cond_inst );
bb->getInstList().push_back( br_inst );
// Create a block for pushing the first one
push_value(op1_block, op1);
op1_block->getInstList().push_back( new BranchInst( exit_bb ) );
// Create a block for pushing the second one
push_value(op2_block, op2);
op2_block->getInstList().push_back( new BranchInst( exit_bb ) );
// Add the blocks
add_block( TheFunction, bb );
add_block( TheFunction, op1_block );
add_block( TheFunction, op2_block );
bb = exit_bb;
break;
}
case MAX : // w1 w2 -- (w2>w1?w2:w1)
{
if (echo) bb->setName("MAX");
// Get the two operands
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
// Compare them
SetCondInst* cond_inst =
new SetCondInst( Instruction::SetGT, op1, op2);
bb->getInstList().push_back( cond_inst );
// Create an exit block
BasicBlock* exit_bb = new BasicBlock((echo?"exit":""));
// Create a block for pushing the larger one
BasicBlock* op1_block = new BasicBlock((echo?"more":""));
push_value(op1_block, op1);
op1_block->getInstList().push_back( new BranchInst( exit_bb ) );
// Create a block for pushing the smaller or equal one
BasicBlock* op2_block = new BasicBlock((echo?"less":""));
push_value(op2_block, op2);
op2_block->getInstList().push_back( new BranchInst( exit_bb ) );
// Create a banch on the SetCond
BranchInst* br_inst =
new BranchInst( op1_block, op2_block, cond_inst );
bb->getInstList().push_back( br_inst );
// Add the blocks
add_block( TheFunction, bb );
add_block( TheFunction, op1_block );
add_block( TheFunction, op2_block );
bb = exit_bb;
break;
}
// Bitwise Operators
case AND : // w1 w2 -- w2&w1
{
if (echo) bb->setName("AND");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* andop =
BinaryOperator::create( Instruction::And, op1, op2);
bb->getInstList().push_back( andop );
push_value( bb, andop );
break;
}
case OR : // w1 w2 -- w2|w1
{
if (echo) bb->setName("OR");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* orop =
BinaryOperator::create( Instruction::Or, op1, op2);
bb->getInstList().push_back( orop );
push_value( bb, orop );
break;
}
case XOR : // w1 w2 -- w2^w1
{
if (echo) bb->setName("XOR");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
BinaryOperator* xorop =
BinaryOperator::create( Instruction::Xor, op1, op2);
bb->getInstList().push_back( xorop );
push_value( bb, xorop );
break;
}
case LSHIFT : // w1 w2 -- w1<<w2
{
if (echo) bb->setName("SHL");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
CastInst* castop = new CastInst( op1, Type::UByteTy );
bb->getInstList().push_back( castop );
ShiftInst* shlop = new ShiftInst( Instruction::Shl, op2, castop );
bb->getInstList().push_back( shlop );
push_value( bb, shlop );
break;
}
case RSHIFT : // w1 w2 -- w1>>w2
{
if (echo) bb->setName("SHR");
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
CastInst* castop = new CastInst( op1, Type::UByteTy );
bb->getInstList().push_back( castop );
ShiftInst* shrop = new ShiftInst( Instruction::Shr, op2, castop );
bb->getInstList().push_back( shrop );
push_value( bb, shrop );
break;
}
// Stack Manipulation Operations
case DROP: // w --
{
if (echo) bb->setName("DROP");
decr_stack_index(bb, One);
break;
}
case DROP2: // w1 w2 --
{
if (echo) bb->setName("DROP2");
decr_stack_index( bb, Two );
break;
}
case NIP: // w1 w2 -- w2
{
if (echo) bb->setName("NIP");
LoadInst* w2 = cast<LoadInst>( stack_top( bb ) );
decr_stack_index( bb );
replace_top( bb, w2 );
break;
}
case NIP2: // w1 w2 w3 w4 -- w3 w4
{
if (echo) bb->setName("NIP2");
LoadInst* w4 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w3 = cast<LoadInst>( stack_top( bb, One ) );
decr_stack_index( bb, Two );
replace_top( bb, w4 );
replace_top( bb, w3, One );
break;
}
case DUP: // w -- w w
{
if (echo) bb->setName("DUP");
LoadInst* w = cast<LoadInst>( stack_top( bb ) );
push_value( bb, w );
break;
}
case DUP2: // w1 w2 -- w1 w2 w1 w2
{
if (echo) bb->setName("DUP2");
LoadInst* w2 = cast<LoadInst>( stack_top(bb) );
LoadInst* w1 = cast<LoadInst>( stack_top(bb, One ) );
incr_stack_index( bb, Two );
replace_top( bb, w1, One );
replace_top( bb, w2 );
break;
}
case SWAP: // w1 w2 -- w2 w1
{
if (echo) bb->setName("SWAP");
LoadInst* w2 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, One ) );
replace_top( bb, w1 );
replace_top( bb, w2, One );
break;
}
case SWAP2: // w1 w2 w3 w4 -- w3 w4 w1 w2
{
if (echo) bb->setName("SWAP2");
LoadInst* w4 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w3 = cast<LoadInst>( stack_top( bb, One ) );
LoadInst* w2 = cast<LoadInst>( stack_top( bb, Two ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Three ) );
replace_top( bb, w2 );
replace_top( bb, w1, One );
replace_top( bb, w4, Two );
replace_top( bb, w3, Three );
break;
}
case OVER: // w1 w2 -- w1 w2 w1
{
if (echo) bb->setName("OVER");
LoadInst* w1 = cast<LoadInst>( stack_top( bb, One ) );
push_value( bb, w1 );
break;
}
case OVER2: // w1 w2 w3 w4 -- w1 w2 w3 w4 w1 w2
{
if (echo) bb->setName("OVER2");
LoadInst* w2 = cast<LoadInst>( stack_top( bb, Two ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Three ) );
incr_stack_index( bb, Two );
replace_top( bb, w2 );
replace_top( bb, w1, One );
break;
}
case ROT: // w1 w2 w3 -- w2 w3 w1
{
if (echo) bb->setName("ROT");
LoadInst* w3 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w2 = cast<LoadInst>( stack_top( bb, One ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Two ) );
replace_top( bb, w1 );
replace_top( bb, w3, One );
replace_top( bb, w2, Two );
break;
}
case ROT2: // w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2
{
if (echo) bb->setName("ROT2");
LoadInst* w6 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w5 = cast<LoadInst>( stack_top( bb, One ) );
LoadInst* w4 = cast<LoadInst>( stack_top( bb, Two ) );
LoadInst* w3 = cast<LoadInst>( stack_top( bb, Three) );
LoadInst* w2 = cast<LoadInst>( stack_top( bb, Four ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Five ) );
replace_top( bb, w2 );
replace_top( bb, w1, One );
replace_top( bb, w6, Two );
replace_top( bb, w5, Three );
replace_top( bb, w4, Four );
replace_top( bb, w3, Five );
break;
}
case RROT: // w1 w2 w3 -- w3 w1 w2
{
if (echo) bb->setName("RROT2");
LoadInst* w3 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w2 = cast<LoadInst>( stack_top( bb, One ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Two ) );
replace_top( bb, w2 );
replace_top( bb, w1, One );
replace_top( bb, w3, Two );
break;
}
case RROT2: // w1 w2 w3 w4 w5 w6 -- w5 w6 w1 w2 w3 w4
{
if (echo) bb->setName("RROT2");
LoadInst* w6 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w5 = cast<LoadInst>( stack_top( bb, One ) );
LoadInst* w4 = cast<LoadInst>( stack_top( bb, Two ) );
LoadInst* w3 = cast<LoadInst>( stack_top( bb, Three) );
LoadInst* w2 = cast<LoadInst>( stack_top( bb, Four ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Five ) );
replace_top( bb, w4 );
replace_top( bb, w3, One );
replace_top( bb, w2, Two );
replace_top( bb, w1, Three );
replace_top( bb, w6, Four );
replace_top( bb, w5, Five );
break;
}
case TUCK: // w1 w2 -- w2 w1 w2
{
if (echo) bb->setName("TUCK");
LoadInst* w2 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, One ) );
incr_stack_index( bb );
replace_top( bb, w2 );
replace_top( bb, w1, One );
replace_top( bb, w2, Two );
break;
}
case TUCK2: // w1 w2 w3 w4 -- w3 w4 w1 w2 w3 w4
{
if (echo) bb->setName("TUCK2");
LoadInst* w4 = cast<LoadInst>( stack_top( bb ) );
LoadInst* w3 = cast<LoadInst>( stack_top( bb, One ) );
LoadInst* w2 = cast<LoadInst>( stack_top( bb, Two ) );
LoadInst* w1 = cast<LoadInst>( stack_top( bb, Three) );
incr_stack_index( bb, Two );
replace_top( bb, w4 );
replace_top( bb, w3, One );
replace_top( bb, w2, Two );
replace_top( bb, w1, Three );
replace_top( bb, w4, Four );
replace_top( bb, w3, Five );
break;
}
case ROLL: // x0 x1 .. xn n -- x1 .. xn x0
{
/// THIS OEPRATOR IS OMITTED PURPOSEFULLY AND IS LEFT TO THE
/// READER AS AN EXERCISE. THIS IS ONE OF THE MORE COMPLICATED
/// OPERATORS. IF YOU CAN GET THIS ONE RIGHT, YOU COMPLETELY
/// UNDERSTAND HOW BOTH LLVM AND STACKER WOR.
/// HINT: LOOK AT PICK AND SELECT. ROLL IS SIMILAR.
if (echo) bb->setName("ROLL");
break;
}
case PICK: // x0 ... Xn n -- x0 ... Xn x0
{
if (echo) bb->setName("PICK");
LoadInst* n = cast<LoadInst>( stack_top( bb ) );
BinaryOperator* addop =
BinaryOperator::create( Instruction::Add, n, One );
bb->getInstList().push_back( addop );
LoadInst* x0 = cast<LoadInst>( stack_top( bb, addop ) );
replace_top( bb, x0 );
break;
}
case SELECT: // m n X0..Xm Xm+1 .. Xn -- Xm
{
if (echo) bb->setName("SELECT");
LoadInst* m = cast<LoadInst>( stack_top(bb) );
LoadInst* n = cast<LoadInst>( stack_top(bb, One) );
BinaryOperator* index =
BinaryOperator::create( Instruction::Add, m, One );
bb->getInstList().push_back( index );
LoadInst* Xm = cast<LoadInst>( stack_top(bb, index ) );
BinaryOperator* n_plus_1 =
BinaryOperator::create( Instruction::Add, n, One );
bb->getInstList().push_back( n_plus_1 );
decr_stack_index( bb, n_plus_1 );
replace_top( bb, Xm );
break;
}
case MALLOC : // n -- p
{
if (echo) bb->setName("MALLOC");
// Get the number of bytes to mallocate
LoadInst* op1 = cast<LoadInst>( pop_integer(bb) );
// Make sure its a UIntTy
CastInst* caster = new CastInst( op1, Type::UIntTy );
bb->getInstList().push_back( caster );
// Allocate the bytes
MallocInst* mi = new MallocInst( Type::SByteTy, caster );
bb->getInstList().push_back( mi );
// Push the pointer
push_value( bb, mi );
break;
}
case FREE : // p --
{
if (echo) bb->setName("FREE");
// Pop the value off the stack
CastInst* ptr = cast<CastInst>( pop_string(bb) );
// Free the memory
FreeInst* fi = new FreeInst( ptr );
bb->getInstList().push_back( fi );
break;
}
case GET : // p w1 -- p w2
{
if (echo) bb->setName("GET");
// Get the character index
LoadInst* op1 = cast<LoadInst>( stack_top(bb) );
CastInst* chr_idx = new CastInst( op1, Type::LongTy );
bb->getInstList().push_back( chr_idx );
// Get the String pointer
CastInst* ptr = cast<CastInst>( stack_top_string(bb,One) );
// Get address of op1'th element of the string
std::vector<Value*> indexVec;
indexVec.push_back( chr_idx );
GetElementPtrInst* gep = new GetElementPtrInst( ptr, indexVec );
bb->getInstList().push_back( gep );
// Get the value and push it
LoadInst* loader = new LoadInst( gep );
bb->getInstList().push_back( loader );
CastInst* caster = new CastInst( loader, Type::IntTy );
bb->getInstList().push_back( caster );
// Push the result back on stack
replace_top( bb, caster );
break;
}
case PUT : // p w2 w1 -- p
{
if (echo) bb->setName("PUT");
// Get the value to put
LoadInst* w1 = cast<LoadInst>( pop_integer(bb) );
// Get the character index
LoadInst* w2 = cast<LoadInst>( pop_integer(bb) );
CastInst* chr_idx = new CastInst( w2, Type::LongTy );
bb->getInstList().push_back( chr_idx );
// Get the String pointer
CastInst* ptr = cast<CastInst>( stack_top_string(bb) );
// Get address of op2'th element of the string
std::vector<Value*> indexVec;
indexVec.push_back( chr_idx );
GetElementPtrInst* gep = new GetElementPtrInst( ptr, indexVec );
bb->getInstList().push_back( gep );
// Cast the value and put it
CastInst* caster = new CastInst( w1, Type::SByteTy );
bb->getInstList().push_back( caster );
StoreInst* storer = new StoreInst( caster, gep );
bb->getInstList().push_back( storer );
break;
}
case RECURSE :
{
if (echo) bb->setName("RECURSE");
std::vector<Value*> params;
CallInst* call_inst = new CallInst( TheFunction, params );
bb->getInstList().push_back( call_inst );
break;
}
case RETURN :
{
if (echo) bb->setName("RETURN");
bb->getInstList().push_back( new ReturnInst() );
break;
}
case EXIT :
{
if (echo) bb->setName("EXIT");
// Get the result value
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
// Cast down to an integer
CastInst* caster = new CastInst( op1, Type::IntTy );
bb->getInstList().push_back( caster );
// Call exit(3)
std::vector<Value*> params;
params.push_back(caster);
CallInst* call_inst = new CallInst( TheExit, params );
bb->getInstList().push_back( call_inst );
break;
}
case TAB :
{
if (echo) bb->setName("TAB");
// Get the format string for a character
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
indexVec.push_back( Zero );
GetElementPtrInst* format_gep =
new GetElementPtrInst( ChrFormat, indexVec );
bb->getInstList().push_back( format_gep );
// Get the character to print (a tab)
ConstantSInt* newline = ConstantSInt::get(Type::IntTy,
static_cast<int>('\t'));
// Call printf
std::vector<Value*> args;
args.push_back( format_gep );
args.push_back( newline );
bb->getInstList().push_back( new CallInst( ThePrintf, args ) );
break;
}
case SPACE :
{
if (echo) bb->setName("SPACE");
// Get the format string for a character
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
indexVec.push_back( Zero );
GetElementPtrInst* format_gep =
new GetElementPtrInst( ChrFormat, indexVec );
bb->getInstList().push_back( format_gep );
// Get the character to print (a space)
ConstantSInt* newline = ConstantSInt::get(Type::IntTy,
static_cast<int>(' '));
// Call printf
std::vector<Value*> args;
args.push_back( format_gep );
args.push_back( newline );
bb->getInstList().push_back( new CallInst( ThePrintf, args ) );
break;
}
case CR :
{
if (echo) bb->setName("CR");
// Get the format string for a character
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
indexVec.push_back( Zero );
GetElementPtrInst* format_gep =
new GetElementPtrInst( ChrFormat, indexVec );
bb->getInstList().push_back( format_gep );
// Get the character to print (a newline)
ConstantSInt* newline = ConstantSInt::get(Type::IntTy,
static_cast<int>('\n'));
// Call printf
std::vector<Value*> args;
args.push_back( format_gep );
args.push_back( newline );
bb->getInstList().push_back( new CallInst( ThePrintf, args ) );
break;
}
case IN_STR :
{
if (echo) bb->setName("IN_STR");
// Make room for the value result
incr_stack_index(bb);
GetElementPtrInst* gep_value =
cast<GetElementPtrInst>(get_stack_pointer(bb));
CastInst* caster =
new CastInst( gep_value, PointerType::get( Type::SByteTy ) );
// Make room for the count result
incr_stack_index(bb);
GetElementPtrInst* gep_count =
cast<GetElementPtrInst>(get_stack_pointer(bb));
// Call scanf(3)
std::vector<Value*> args;
args.push_back( InStrFormat );
args.push_back( caster );
CallInst* scanf = new CallInst( TheScanf, args );
bb->getInstList().push_back( scanf );
// Store the result
bb->getInstList().push_back( new StoreInst( scanf, gep_count ) );
break;
}
case IN_NUM :
{
if (echo) bb->setName("IN_NUM");
// Make room for the value result
incr_stack_index(bb);
GetElementPtrInst* gep_value =
cast<GetElementPtrInst>(get_stack_pointer(bb));
// Make room for the count result
incr_stack_index(bb);
GetElementPtrInst* gep_count =
cast<GetElementPtrInst>(get_stack_pointer(bb));
// Call scanf(3)
std::vector<Value*> args;
args.push_back( InStrFormat );
args.push_back( gep_value );
CallInst* scanf = new CallInst( TheScanf, args );
bb->getInstList().push_back( scanf );
// Store the result
bb->getInstList().push_back( new StoreInst( scanf, gep_count ) );
break;
}
case IN_CHAR :
{
if (echo) bb->setName("IN_CHAR");
// Make room for the value result
incr_stack_index(bb);
GetElementPtrInst* gep_value =
cast<GetElementPtrInst>(get_stack_pointer(bb));
// Make room for the count result
incr_stack_index(bb);
GetElementPtrInst* gep_count =
cast<GetElementPtrInst>(get_stack_pointer(bb));
// Call scanf(3)
std::vector<Value*> args;
args.push_back( InChrFormat );
args.push_back( gep_value );
CallInst* scanf = new CallInst( TheScanf, args );
bb->getInstList().push_back( scanf );
// Store the result
bb->getInstList().push_back( new StoreInst( scanf, gep_count ) );
break;
}
case OUT_STR :
{
if (echo) bb->setName("OUT_STR");
LoadInst* op1 = cast<LoadInst>(stack_top(bb));
// Get the address of the format string
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
indexVec.push_back( Zero );
GetElementPtrInst* format_gep =
new GetElementPtrInst( StrFormat, indexVec );
bb->getInstList().push_back( format_gep );
// Build function call arguments
std::vector<Value*> args;
args.push_back( format_gep );
args.push_back( op1 );
// Call printf
bb->getInstList().push_back( new CallInst( ThePrintf, args ) );
break;
}
case OUT_NUM :
{
if (echo) bb->setName("OUT_NUM");
// Pop the numeric operand off the stack
LoadInst* op1 = cast<LoadInst>(stack_top(bb));
// Get the address of the format string
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
indexVec.push_back( Zero );
GetElementPtrInst* format_gep =
new GetElementPtrInst( NumFormat, indexVec );
bb->getInstList().push_back( format_gep );
// Build function call arguments
std::vector<Value*> args;
args.push_back( format_gep );
args.push_back( op1 );
// Call printf
bb->getInstList().push_back( new CallInst( ThePrintf, args ) );
break;
}
case OUT_CHAR :
{
if (echo) bb->setName("OUT_CHAR");
// Pop the character operand off the stack
LoadInst* op1 = cast<LoadInst>(stack_top(bb));
// Get the address of the format string
std::vector<Value*> indexVec;
indexVec.push_back( Zero );
indexVec.push_back( Zero );
GetElementPtrInst* format_gep =
new GetElementPtrInst( ChrFormat, indexVec );
bb->getInstList().push_back( format_gep );
// Build function call arguments
std::vector<Value*> args;
args.push_back( format_gep );
args.push_back( op1 );
// Call printf
bb->getInstList().push_back( new CallInst( ThePrintf, args ) );
break;
}
default :
{
ThrowException(std::string("Compiler Error: Unhandled token #"));
}
}
// Return the basic block
return bb;
}