Skip to content
Browse files

Code generation for case statements with non-scalar values

  • Loading branch information...
1 parent 8a3c76b commit 0f9c5858d3db7862642612e2254df3c3a69cb46c @nickg committed Apr 8, 2012
Showing with 121 additions and 1 deletion.
  1. +62 −1 src/cgen.c
  2. +58 −0 test/regress/case2.vhd
  3. +1 −0 test/regress/testlist.txt
View
63 src/cgen.c
@@ -1971,8 +1971,10 @@ static void cgen_exit(tree_t t, struct cgen_ctx *ctx)
LLVMPositionBuilderAtEnd(builder, not_bb);
}
-static void cgen_case(tree_t t, struct cgen_ctx *ctx)
+static void cgen_case_scalar(tree_t t, struct cgen_ctx *ctx)
{
+ // Case with scalar value maps onto LLVM case
+
LLVMBasicBlockRef exit_bb = LLVMAppendBasicBlock(ctx->fn, "case_exit");
LLVMBasicBlockRef else_bb = exit_bb;
@@ -2014,6 +2016,65 @@ static void cgen_case(tree_t t, struct cgen_ctx *ctx)
LLVMPositionBuilderAtEnd(builder, exit_bb);
}
+static void cgen_case_array(tree_t t, struct cgen_ctx *ctx)
+{
+ // Case with array value must use chain of ifs
+
+ // TODO: multiple calls to cgen_array_rel is very inefficient
+ // replace this with code to compare all values in a single
+ // loop (e.g. build a bit mask of length #assocs)
+
+ LLVMBasicBlockRef exit_bb = LLVMAppendBasicBlock(ctx->fn, "case_exit");
+
+ LLVMValueRef val = cgen_expr(tree_value(t), ctx);
+ type_t type = tree_type(tree_value(t));
+
+ bool have_others = false;
+ for (unsigned i = 0; i < tree_assocs(t); i++) {
+ LLVMBasicBlockRef next_bb = NULL;
+ assoc_t a = tree_assoc(t, i);
+ switch (a.kind) {
+ case A_NAMED:
+ {
+ LLVMBasicBlockRef this_bb =
+ LLVMAppendBasicBlock(ctx->fn, "case_body");
+ next_bb = LLVMAppendBasicBlock(ctx->fn, "case_test");
+ LLVMValueRef eq = cgen_array_rel(val, cgen_expr(a.name, ctx),
+ type, type, LLVMIntEQ, ctx);
+ LLVMBuildCondBr(builder, eq, this_bb, next_bb);
+ LLVMPositionBuilderAtEnd(builder, this_bb);
+ }
+ break;
+
+ case A_OTHERS:
+ next_bb = exit_bb;
+ have_others = true;
+ break;
+
+ default:
+ assert(false);
+ }
+
+ cgen_stmt(a.value, ctx);
+ LLVMBuildBr(builder, exit_bb);
+
+ LLVMPositionBuilderAtEnd(builder, next_bb);
+ }
+
+ if (!have_others)
+ LLVMBuildBr(builder, exit_bb);
+
+ LLVMPositionBuilderAtEnd(builder, exit_bb);
+}
+
+static void cgen_case(tree_t t, struct cgen_ctx *ctx)
+{
+ if (type_is_array(tree_type(tree_value(t))))
+ cgen_case_array(t, ctx);
+ else
+ cgen_case_scalar(t, ctx);
+}
+
static void cgen_pcall(tree_t t, struct cgen_ctx *ctx)
{
tree_t decl = tree_ref(t);
View
58 test/regress/case2.vhd
@@ -0,0 +1,58 @@
+entity case2 is
+end entity;
+
+architecture test of case2 is
+
+ function toint4(b : bit_vector(3 downto 0)) return integer is
+ begin
+ case b is
+ when X"0" => return 0;
+ when X"1" => return 1;
+ when X"2" => return 2;
+ when X"3" => return 3;
+ when X"4" => return 4;
+ when X"5" => return 5;
+ when X"6" => return 6;
+ when X"7" => return 7;
+ when X"8" => return 8;
+ when X"9" => return 9;
+ when X"a" => return 10;
+ when X"b" => return 11;
+ when X"c" => return 12;
+ when X"d" => return 13;
+ when X"e" => return 14;
+ when X"f" => return 15;
+ end case;
+ end function;
+
+ function toint3(b : bit_vector(3 downto 0)) return integer is
+ begin
+ case b is
+ when X"0" => return 0;
+ when X"1" => return 1;
+ when X"2" => return 2;
+ when X"3" => return 3;
+ when X"4" => return 4;
+ when X"5" => return 5;
+ when X"6" => return 6;
+ when X"7" => return 7;
+ when others => return -1;
+ end case;
+ end function;
+
+begin
+
+ process is
+ variable b : bit_vector(3 downto 0);
+ begin
+ assert toint4(X"4") = 4;
+ b := X"a";
+ assert toint4(b) = 10;
+ assert toint4(X"f") = 15;
+ assert toint3(X"5") = 5;
+ assert toint3(X"c") = -1;
+ wait;
+ end process;
+
+end architecture;
+
View
1 test/regress/testlist.txt
@@ -63,3 +63,4 @@ synopsys1 normal
block1 normal
elab3 normal,gold
func6 normal
+case2 normal

0 comments on commit 0f9c585

Please sign in to comment.
Something went wrong with that request. Please try again.