[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