[llvm-commits] CVS: llvm-gcc/gcc/llvm-expand.c
Chris Lattner
lattner at cs.uiuc.edu
Tue Mar 16 01:10:01 PST 2004
Changes in directory llvm-gcc/gcc:
llvm-expand.c updated: 1.25 -> 1.26
---
Log message:
First half of a patch to implement PR273: http://llvm.cs.uiuc.edu/PR273 : [llvm-gcc] "Address of label" GCC extension not implemented
This is not exception correct, but should handle C just fine. I note that this
exposes a bug in the JIT though, which I'll file.
---
Diffs of the changes: (+115 -3)
Index: llvm-gcc/gcc/llvm-expand.c
diff -u llvm-gcc/gcc/llvm-expand.c:1.25 llvm-gcc/gcc/llvm-expand.c:1.26
--- llvm-gcc/gcc/llvm-expand.c:1.25 Mon Mar 15 23:23:37 2004
+++ llvm-gcc/gcc/llvm-expand.c Tue Mar 16 01:09:47 2004
@@ -650,6 +650,21 @@
* TerminateBlock instead of throwing the exception.
*/
int ThrownExceptionsCallTerminate;
+
+ /* NumAddrTakenBlocks - The number of basic blocks whose address has been
+ * taken.
+ */
+ unsigned NumAddrTakenBlocks;
+
+ /* IndirectGotoBlock - This block contains the switch instruction that is used
+ * to implement indirect gotos. This block is *ONLY* allowed to contain a
+ * load (the first entry) and a switch instruction on the load (which must be
+ * from the IndirectGotoValue alloca. The switch instruction contains one
+ * entry for each basic block that has its address taken. This block is
+ * created on demand, then inserted at the end of the function.
+ */
+ llvm_value *IndirectGotoValue; /* The dynamic block id to go to. */
+ llvm_basicblock *IndirectGotoBlock;
} llvm_expand_info;
/* add_scope_stack - Allocate and add a scope to the top of the scope list, with
@@ -1654,7 +1669,7 @@
}
/* getLabelDeclBlock - This is a wrapper function that is used to lazily create
- llvm_basicblock's for labels on demand.
+ * llvm_basicblock's for labels on demand.
*/
static llvm_basicblock* getLabelDeclBlock(tree LD) {
const char *Name;
@@ -1669,6 +1684,41 @@
return BB;
}
+/* EnsureIndirectGotoBlockExists - This function ensures that the specified LLVM
+ * function has a block to be used for computed gotos. If not it creates one.
+ * In any case, it return the switch instruction at the end of the block and
+ * ensures that Fn->IndirectGoto* are not null.
+ */
+static llvm_instruction *EnsureIndirectGotoBlockExists(llvm_function *Fn) {
+ if (Fn->ExpandInfo->IndirectGotoBlock == 0) {
+ /* Create the value that we will load from to determine which destination to
+ * branch to.
+ */
+ llvm_instruction *Load;
+ llvm_instruction *I = create_alloca_inst("computed_dest", UIntTy,
+ llvm_constant_uint_1);
+ insert_alloca_into_entry_block(Fn, I);
+ Fn->ExpandInfo->IndirectGotoValue = D2V(I);
+ Fn->ExpandInfo->IndirectGotoBlock =
+ llvm_basicblock_new("computed_branch_block");
+
+ /* Create and insert the load instruction */
+ Load = create_load_inst("dest_block", Fn->ExpandInfo->IndirectGotoValue, 0);
+ llvm_ilist_push_back(llvm_instruction,
+ Fn->ExpandInfo->IndirectGotoBlock->Instructions, Load);
+ /* Create and insert the switch instruction. */
+ I = llvm_instruction_new(VoidTy, "", O_Switch, 2);
+ I->Operands[0] = D2V(Load);
+ /* The default destination block will be filled in later! */
+ llvm_ilist_push_back(llvm_instruction,
+ Fn->ExpandInfo->IndirectGotoBlock->Instructions, I);
+ return I;
+ }
+ return llvm_ilist_back(llvm_instruction,
+ Fn->ExpandInfo->IndirectGotoBlock->Instructions);
+}
+
+
/* Specify the location in the LLVM code of a label LABEL, which is a LABEL_DECL
tree node.
@@ -2058,8 +2108,20 @@
if (TREE_CODE(dest) == IDENTIFIER_NODE) abort ();
if (TREE_CODE(dest) != LABEL_DECL) {
- fprintf(stderr, "Computed gotos not supported!!!");
- LLVM_TODO_TREE(dest);
+ /* If this is a computed goto, evaluate the condition. */
+ llvm_value *V = llvm_expand_expr(Fn, dest, 0);
+ V = cast_if_type_not_equal(Fn, V, UIntTy);
+
+ /* Make sure the function knows that indirect gotos occur. */
+ EnsureIndirectGotoBlockExists(Fn);
+
+ append_inst(Fn, create_store_inst(V, Fn->ExpandInfo->IndirectGotoValue, 0));
+
+ /* FIXME: This is HORRIBLY INCORRECT in the presence of exception handlers.
+ * There should be one collector block per cleanup level!
+ */
+ llvm_expand_goto_internal(Fn, Fn->ExpandInfo->IndirectGotoBlock, 1, 0);
+ return;
}
TREE_USED(dest) = 1;
@@ -5021,6 +5083,43 @@
LLVM_TODO_TREE(exp);
}
+ case LABEL_DECL: {
+ /* The user took the address of this label. */
+ llvm_basicblock *BB = getLabelDeclBlock(exp);
+ if (DECL_CONTEXT(exp)) {
+ assert(TREE_CODE(DECL_CONTEXT(exp)) == FUNCTION_DECL &&
+ "Address of label in nested function?");
+ if (Fn == 0) {
+ /* We know that we must be expanding the label into the context of the
+ * function, despite the fact that we may have lost the value of Fn
+ * along the way.
+ */
+ Fn = (llvm_function*)DECL_LLVM(DECL_CONTEXT(exp));
+ assert(((llvm_value*)Fn)->VTy == Function);
+ }
+ }
+
+ if (BB->BlockID == 0) {
+ /* If this is the first time the addr of this block is taken, assign it an
+ * ID, and add it to the indirect branch switch block.
+ */
+ llvm_instruction *TheSwitch = EnsureIndirectGotoBlockExists(Fn);
+ llvm_switch_case *Case;
+ unsigned ID = Fn->ExpandInfo->NumAddrTakenBlocks++;
+
+ BB->BlockID = llvm_constant_new_integral(UIntTy, ID);
+
+ /* Update the switch instruction to include an entry for this block. */
+ Case = xmalloc(sizeof(llvm_switch_case));
+ Case->Next = TheSwitch->x.Switch.Cases;
+ TheSwitch->x.Switch.Cases = Case;
+ Case->Value = ID;
+ Case->Dest = BB;
+ }
+ Result = BB->BlockID;
+ break;
+ }
+
case PARM_DECL:
if (!DECL_LLVM_SET_P (exp)) {
error ("%Hprior parameter's size depends on '%D'",
@@ -6642,6 +6741,19 @@
if (end_bindings) {
LLVM_TODO();
expand_end_bindings (0, 0, 0);
+ }
+
+ /* If there are indirect gotos in the function, insert the block for it. */
+ if (Fn->ExpandInfo->IndirectGotoBlock) {
+ llvm_instruction *Switch = EnsureIndirectGotoBlockExists(Fn);
+ llvm_emit_label(Fn, Fn->ExpandInfo->IndirectGotoBlock);
+
+ /* We never set the default destination for the switch instruction in this
+ * block. If there were addresses of blocks taken, make it one of the block
+ * destinations. We know that the default edge can never be taken.
+ */
+ Switch->Operands[1] = Switch->x.Switch.Cases ?
+ Switch->x.Switch.Cases->Dest : Fn->ExpandInfo->IndirectGotoBlock;
}
if (Fn->ExpandInfo->RethrowBlock) {
More information about the llvm-commits
mailing list