[llvm-commits] [gcc-plugin] r81146 - in /gcc-plugin/trunk: llvm-backend.cpp llvm-convert.cpp llvm-internal.h
Duncan Sands
baldrick at free.fr
Mon Sep 7 01:07:02 PDT 2009
Author: baldrick
Date: Mon Sep 7 03:07:02 2009
New Revision: 81146
URL: http://llvm.org/viewvc/llvm-project?rev=81146&view=rev
Log:
Add support for ssa names. I'm not sure I understood
SSA_NAME_IS_DEFAULT_DEF correctly, but this does seem
to work on simple examples. The plugin can now compile
int f(int x) { return x; }
You can't stop progress!
Modified:
gcc-plugin/trunk/llvm-backend.cpp
gcc-plugin/trunk/llvm-convert.cpp
gcc-plugin/trunk/llvm-internal.h
Modified: gcc-plugin/trunk/llvm-backend.cpp
URL: http://llvm.org/viewvc/llvm-project/gcc-plugin/trunk/llvm-backend.cpp?rev=81146&r1=81145&r2=81146&view=diff
==============================================================================
--- gcc-plugin/trunk/llvm-backend.cpp (original)
+++ gcc-plugin/trunk/llvm-backend.cpp Mon Sep 7 03:07:02 2009
@@ -1784,10 +1784,16 @@
// know we want to output it.
DECL_DEFER_OUTPUT(current_function_decl) = 0;
+ // Provide the function convertor with dominators.
+ calculate_dominance_info(CDI_DOMINATORS);
+
// Convert the AST to raw/ugly LLVM code.
TreeToLLVM Emitter(current_function_decl);
Function *Fn = Emitter.EmitFunction();
+ // Free dominator and other ssa data structures.
+ execute_free_datastructures();
+
//TODO performLateBackendInitialization();
createPerFunctionOptimizationPasses();
@@ -1800,8 +1806,6 @@
// Finally, we have written out this function!
TREE_ASM_WRITTEN(current_function_decl) = 1;
- execute_free_datastructures();
-
// When debugging, append the LLVM IR to the dump file.
if (dump_file) {
raw_fd_ostream dump_stream(fileno(dump_file), false);
Modified: gcc-plugin/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/gcc-plugin/trunk/llvm-convert.cpp?rev=81146&r1=81145&r2=81146&view=diff
==============================================================================
--- gcc-plugin/trunk/llvm-convert.cpp (original)
+++ gcc-plugin/trunk/llvm-convert.cpp Mon Sep 7 03:07:02 2009
@@ -72,6 +72,7 @@
#include "tree-flow.h"
#include "tree-pass.h"
#include "rtl.h"
+#include "domwalk.h"
extern int get_pointer_alignment (tree exp, unsigned int max_align);
extern enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
@@ -92,17 +93,6 @@
TREE_CODE(DECL_INITIAL(exp)) == CONSTRUCTOR && \
!TREE_TYPE(DECL_INITIAL(exp)))
-/// isGimpleTemporary - Return true if this is a gimple temporary that we can
-/// directly compile into an LLVM temporary. This saves us from creating an
-/// alloca and creating loads/stores of that alloca (a compile-time win). We
-/// can only do this if the value is a first class llvm value and if it's a
-/// "gimple_formal_tmp_reg".
-static bool isGimpleTemporary(tree decl) {
- return false;
-//FIXME return is_gimple_formal_tmp_reg(decl) &&
-//FIXME !isAggregateTreeType(TREE_TYPE(decl));
-}
-
/// getINTEGER_CSTVal - Return the specified INTEGER_CST value as a uint64_t.
///
uint64_t getINTEGER_CSTVal(tree exp) {
@@ -735,80 +725,83 @@
//TODO // may be deleted when the optimizers run, so would be dangerous to keep.
//TODO eraseLocalLLVMValues();
- // Simplify any values that were uniqued using a no-op bitcast.
- for (std::vector<BitCastInst *>::iterator I = UniquedValues.begin(),
- E = UniquedValues.end(); I != E; ++I) {
- BitCastInst *BI = *I;
- assert(BI->getSrcTy() == BI->getDestTy() && "Not a no-op bitcast!");
- BI->replaceAllUsesWith(BI->getOperand(0));
- // Safe to erase because after the call to eraseLocalLLVMValues.
- BI->eraseFromParent();
- }
- UniquedValues.clear();
-
return Fn;
}
extern "C" tree gimple_to_tree(gimple);
extern "C" void release_stmt_tree (gimple, tree);
-Function *TreeToLLVM::EmitFunction() {
- // Set up parameters and prepare for return, for the function.
- StartFunctionBody();
-
- // Emit the body of the function iterating over all BBs
- basic_block bb;
- edge e;
- edge_iterator ei;
- FOR_EACH_BB (bb) {
- for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
- gsi_next (&gsi)) {
- gimple gimple_stmt = gsi_stmt (gsi);
-
- switch (gimple_code(gimple_stmt)) {
- case GIMPLE_ASSIGN:
- case GIMPLE_COND:
- case GIMPLE_GOTO:
- case GIMPLE_LABEL:
- case GIMPLE_RETURN:
- case GIMPLE_ASM:
- case GIMPLE_CALL:
- case GIMPLE_SWITCH:
- case GIMPLE_NOP:
- case GIMPLE_PREDICT:
- case GIMPLE_RESX: {
- // TODO Handle gimple directly, rather than converting to a tree.
- tree stmt = gimple_to_tree(gimple_stmt);
-
- // If this stmt returns an aggregate value (e.g. a call whose result is
- // ignored), create a temporary to receive the value. Note that we don't
- // do this for MODIFY_EXPRs as an efficiency hack.
- MemRef DestLoc;
- if (isAggregateTreeType(TREE_TYPE(stmt)) &&
- TREE_CODE(stmt)!= MODIFY_EXPR && TREE_CODE(stmt)!=INIT_EXPR)
- DestLoc = CreateTempLoc(ConvertType(TREE_TYPE(stmt)));
+void TreeToLLVM::EmitBasicBlock(basic_block bb) {
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi)) {
+ gimple gimple_stmt = gsi_stmt (gsi);
+
+ switch (gimple_code(gimple_stmt)) {
+ case GIMPLE_ASSIGN:
+ case GIMPLE_COND:
+ case GIMPLE_GOTO:
+ case GIMPLE_LABEL:
+ case GIMPLE_RETURN:
+ case GIMPLE_ASM:
+ case GIMPLE_CALL:
+ case GIMPLE_SWITCH:
+ case GIMPLE_NOP:
+ case GIMPLE_PREDICT:
+ case GIMPLE_RESX: {
+ // TODO Handle gimple directly, rather than converting to a tree.
+ tree stmt = gimple_to_tree(gimple_stmt);
+
+ // If this stmt returns an aggregate value (e.g. a call whose result is
+ // ignored), create a temporary to receive the value. Note that we don't
+ // do this for MODIFY_EXPRs as an efficiency hack.
+ MemRef DestLoc;
+ if (isAggregateTreeType(TREE_TYPE(stmt)) &&
+ TREE_CODE(stmt)!= MODIFY_EXPR && TREE_CODE(stmt)!=INIT_EXPR)
+ DestLoc = CreateTempLoc(ConvertType(TREE_TYPE(stmt)));
- Emit(stmt, DestLoc.Ptr ? &DestLoc : NULL);
-
- release_stmt_tree(gimple_stmt, stmt);
- break;
- }
+ Emit(stmt, DestLoc.Ptr ? &DestLoc : NULL);
- default:
- print_gimple_stmt(stderr, gimple_stmt, 0, TDF_RAW);
- llvm_report_error("Unhandled GIMPLE statement during LLVM emission!");
- }
+ release_stmt_tree(gimple_stmt, stmt);
+ break;
}
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_FALLTHRU)
- break;
- if (e && e->dest != bb->next_bb) {
- Builder.CreateBr(getLabelDeclBlock(gimple_block_label (e->dest)));
- EmitBlock(BasicBlock::Create(Context, ""));
+ default:
+ print_gimple_stmt(stderr, gimple_stmt, 0, TDF_RAW);
+ llvm_unreachable("Unhandled GIMPLE statement during LLVM emission!");
}
}
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (e->flags & EDGE_FALLTHRU)
+ break;
+ if (e && e->dest != bb->next_bb) {
+ Builder.CreateBr(getLabelDeclBlock(gimple_block_label (e->dest)));
+ EmitBlock(BasicBlock::Create(Context, ""));
+ }
+}
+
+static void emit_basic_block(struct dom_walk_data *walk_data, basic_block bb) {
+ ((TreeToLLVM *)walk_data->global_data)->EmitBasicBlock(bb);
+}
+
+Function *TreeToLLVM::EmitFunction() {
+ // Set up parameters and prepare for return, for the function.
+ StartFunctionBody();
+
+ // Emit the body of the function by iterating over all BBs. To ensure that
+ // definitions of ssa names are seen before any uses, the iteration is done
+ // in dominator order.
+ struct dom_walk_data walk_data;
+ memset(&walk_data, 0, sizeof(struct dom_walk_data));
+ walk_data.dom_direction = CDI_DOMINATORS;
+ walk_data.before_dom_children = emit_basic_block;
+ walk_data.global_data = this;
+ init_walk_dominator_tree(&walk_data);
+ walk_dominator_tree(&walk_data, ENTRY_BLOCK_PTR);
+ fini_walk_dominator_tree(&walk_data);
+
// Wrap things up.
return FinishFunctionBody();
}
@@ -832,12 +825,8 @@
switch (TREE_CODE(exp)) {
default:
- DEBUG({
- llvm::errs() << "Unhandled expression!\n"
- << "TREE_CODE: " << TREE_CODE(exp) << "\n";
- debug_tree(exp);
- });
- abort();
+ debug_tree(exp);
+ llvm_unreachable("Unhandled expression!");
// Control flow
case LABEL_EXPR: Result = EmitLABEL_EXPR(exp); break;
@@ -852,6 +841,8 @@
case RESX_EXPR: Result = EmitRESX_EXPR(exp); break;
// Expressions
+ case SSA_NAME:
+ Result = EmitSSA_NAME(exp); break;
case VAR_DECL:
case PARM_DECL:
case RESULT_DECL:
@@ -1030,11 +1021,8 @@
switch (TREE_CODE(exp)) {
default:
- DEBUG({
- errs() << "Unhandled lvalue expression!\n";
- debug_tree(exp);
- });
- abort();
+ debug_tree(exp);
+ llvm_unreachable("Unhandled lvalue expression!");
case PARM_DECL:
case VAR_DECL:
@@ -1115,9 +1103,8 @@
//===----------------------------------------------------------------------===//
void TreeToLLVM::TODO(tree exp) {
- DEBUG(errs() << "Unhandled tree node\n");
if (exp) debug_tree(exp);
- abort();
+ llvm_unreachable("Unhandled tree node");
}
/// CastToType - Cast the specified value to the specified type if it is
@@ -1582,11 +1569,6 @@
TREE_STATIC(decl) || DECL_EXTERNAL(decl) || type == error_mark_node)
return;
- // Gimple temporaries are handled specially: their DECL_LLVM is set when the
- // definition is encountered.
- if (isGimpleTemporary(decl))
- return;
-
// If this is just the rotten husk of a variable that the gimplifier
// eliminated all uses of, but is preserving for debug info, ignore it.
if (TREE_CODE(decl) == VAR_DECL && DECL_VALUE_EXPR(decl))
@@ -2248,30 +2230,22 @@
return false;
}
+/// EmitSSA_NAME - Return the defining value of the given SSA_NAME.
+Value *TreeToLLVM::EmitSSA_NAME(tree exp) {
+ if (SSA_NAME_IS_DEFAULT_DEF(exp))
+ return Emit(SSA_NAME_VAR(exp), 0);
+ return SSANames[exp];
+}
/// EmitLoadOfLValue - When an l-value expression is used in a context that
/// requires an r-value, this method emits the lvalue computation, then loads
/// the result.
Value *TreeToLLVM::EmitLoadOfLValue(tree exp, const MemRef *DestLoc) {
- // If this is a gimple temporary, don't emit a load, just use the result.
- if (isGimpleTemporary(exp)) {
- if (DECL_LLVM_SET_P(exp))
- return DECL_LLVM(exp);
- // Since basic blocks are output in no particular order, it is perfectly
- // possible to encounter a use of a gimple temporary before encountering
- // its definition, which is what has happened here. This happens rarely
- // in practice, so there's no point in trying to do anything clever: just
- // demote to an ordinary variable and create an alloca to hold its value.
-abort(); //FIXME
-//FIXME DECL_GIMPLE_FORMAL_TEMP_P(exp) = 0;
- EmitAutomaticVariableDecl(exp);
- // Fall through.
- } else if (canEmitRegisterVariable(exp)) {
+ if (canEmitRegisterVariable(exp))
// If this is a register variable, EmitLV can't handle it (there is no
// l-value of a register variable). Emit an inline asm node that copies the
// value out of the specified register.
return EmitReadOfRegisterVariable(exp, DestLoc);
- }
LValue LV = EmitLV(exp);
bool isVolatile = TREE_THIS_VOLATILE(exp);
@@ -2868,70 +2842,6 @@
return 0;
}
-/// HandleMultiplyDefinedGimpleTemporary - Gimple temporaries *mostly* have a
-/// single definition, in which case all uses are dominated by the definition.
-/// This routine exists to handle the rare case of a gimple temporary with
-/// multiple definitions. It turns the temporary into an ordinary automatic
-/// variable by creating an alloca for it, initializing the alloca with the
-/// first definition that was seen, and fixing up any existing uses to load
-/// the alloca instead.
-///
-void TreeToLLVM::HandleMultiplyDefinedGimpleTemporary(tree Var) {
- Value *UniqVal = DECL_LLVM(Var);
- assert(isa<CastInst>(UniqVal) && "Invalid value for gimple temporary!");
- Value *FirstVal = cast<CastInst>(UniqVal)->getOperand(0);
-
- // Create a new temporary and set the VAR_DECL to use it as the llvm location.
- Value *NewTmp = CreateTemporary(FirstVal->getType());
- SET_DECL_LLVM(Var, NewTmp);
-
- // Store the already existing initial value into the alloca. If the value
- // being stored is an instruction, emit the store right after the instruction,
- // otherwise, emit it into the entry block.
- StoreInst *SI = new StoreInst(FirstVal, NewTmp);
-
- BasicBlock::iterator InsertPt;
- if (Instruction *I = dyn_cast<Instruction>(FirstVal)) {
- InsertPt = I; // Insert after the init instruction.
-
- // If the instruction is an alloca in the entry block, the insert point
- // will be before the alloca. Advance to the AllocaInsertionPoint if we are
- // before it.
- if (I->getParent() == &Fn->front()) {
- for (BasicBlock::iterator CI = InsertPt, E = Fn->begin()->end();
- CI != E; ++CI) {
- if (&*CI == AllocaInsertionPoint) {
- InsertPt = AllocaInsertionPoint;
- ++InsertPt;
- break;
- }
- }
- }
-
- // If the instruction is an invoke, the init is inserted on the normal edge.
- if (InvokeInst *II = dyn_cast<InvokeInst>(I)) {
- InsertPt = II->getNormalDest()->begin();
- while (isa<PHINode>(InsertPt))
- ++InsertPt;
- } else
- ++InsertPt; // Insert after the init instruction.
- } else {
- InsertPt = AllocaInsertionPoint; // Insert after the allocas.
- ++InsertPt;
- }
- BasicBlock *BB = InsertPt->getParent();
- BB->getInstList().insert(InsertPt, SI);
-
- // Replace any uses of the original value with a load of the alloca.
- for (Value::use_iterator U = UniqVal->use_begin(), E = UniqVal->use_end();
- U != E; ++U)
- U.getUse().set(new LoadInst(NewTmp, "mtmp", cast<Instruction>(*U)));
-
- // Finally, This is no longer a GCC temporary.
-abort(); //FIXME
-//FIXME DECL_GIMPLE_FORMAL_TEMP_P(Var) = 0;
-}
-
/// EmitMODIFY_EXPR - Note that MODIFY_EXPRs are rvalues only!
/// We also handle INIT_EXPRs here; these are built by the C++ FE on rare
/// occasions, and have slightly different semantics that don't affect us here.
@@ -2940,29 +2850,15 @@
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
- // If this is the definition of a gimple temporary, set its DECL_LLVM to the
- // RHS.
bool LHSSigned = !TYPE_UNSIGNED(TREE_TYPE(lhs));
bool RHSSigned = !TYPE_UNSIGNED(TREE_TYPE(rhs));
- if (isGimpleTemporary(lhs)) {
- // If DECL_LLVM is already set, this is a multiply defined gimple temporary.
- if (DECL_LLVM_SET_P(lhs)) {
- HandleMultiplyDefinedGimpleTemporary(lhs);
- return EmitMODIFY_EXPR(exp, DestLoc);
- }
+
+ // If this is the definition of an ssa name, record it in the SSANames map.
+ if (TREE_CODE(lhs) == SSA_NAME) {
+ assert(SSANames.find(lhs) == SSANames.end() && "Multiply defined ssa name!");
Value *RHS = Emit(rhs, 0);
- const Type *LHSTy = ConvertType(TREE_TYPE(lhs));
- // The value may need to be replaced later if this temporary is multiply
- // defined - ensure it can be uniquely identified by not folding the cast.
- Instruction::CastOps opc = CastInst::getCastOpcode(RHS, RHSSigned,
- LHSTy, LHSSigned);
- CastInst *Cast = CastInst::Create(opc, RHS, LHSTy, RHS->getName());
- if (opc == Instruction::BitCast && RHS->getType() == LHSTy)
- // Simplify this no-op bitcast once the function is emitted.
- UniquedValues.push_back(cast<BitCastInst>(Cast));
- Builder.Insert(Cast);
- SET_DECL_LLVM(lhs, Cast);
- return Cast;
+ SSANames[lhs] = RHS;
+ return RHS;
} else if (canEmitRegisterVariable(lhs)) {
// If this is a store to a register variable, EmitLV can't handle the dest
// (there is no l-value of a register variable). Emit an inline asm node
@@ -6801,9 +6697,6 @@
}
}
- assert(!isGimpleTemporary(exp) &&
- "Cannot use a gimple temporary as an l-value");
-
Value *Decl = DECL_LLVM(exp);
if (Decl == 0) {
if (errorcount || sorrycount) {
Modified: gcc-plugin/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/gcc-plugin/trunk/llvm-internal.h?rev=81146&r1=81145&r2=81146&view=diff
==============================================================================
--- gcc-plugin/trunk/llvm-internal.h (original)
+++ gcc-plugin/trunk/llvm-internal.h Mon Sep 7 03:07:02 2009
@@ -30,6 +30,7 @@
// LLVM headers
#include "llvm/CallingConv.h"
#include "llvm/Intrinsics.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SetVector.h"
@@ -322,10 +323,9 @@
// AllocaInsertionPoint - Place to insert alloca instructions. Lazily created
// and managed by CreateTemporary.
Instruction *AllocaInsertionPoint;
-
- /// UniquedValues - Values defined using a no-op bitcast in order to make them
- /// unique. These can be simplified once the function has been emitted.
- std::vector<BitCastInst *> UniquedValues;
+
+ // SSANames - Map from GCC ssa names to the defining LLVM value.
+ DenseMap<tree, Value*> SSANames;
//===---------------------- Exception Handling --------------------------===//
@@ -377,7 +377,10 @@
/// EmitFunction - Convert 'fndecl' to LLVM code.
Function *EmitFunction();
-
+
+ /// EmitBasicBlock - Convert the given basic block.
+ void EmitBasicBlock(basic_block bb);
+
/// EmitLV - Convert the specified l-value tree node to LLVM code, returning
/// the address of the result.
LValue EmitLV(tree_node *exp);
@@ -511,6 +514,7 @@
Value *EmitSWITCH_EXPR(tree_node *exp);
// Expressions.
+ Value *EmitSSA_NAME(tree_node *exp);
Value *EmitLoadOfLValue(tree_node *exp, const MemRef *DestLoc);
Value *EmitOBJ_TYPE_REF(tree_node *exp, const MemRef *DestLoc);
Value *EmitADDR_EXPR(tree_node *exp);
More information about the llvm-commits
mailing list