You don't say what you want the code to do, but I can see a couple of trouble areas. The first is that you don't have any reset logic in your process. It's important to make sure that you properly initialize everything in order to prevent unusual operation. This however is not likely the cause of your trouble.
What I think is causing the incorrect operation is that you are looking for the clock signal to be high instead of checking for the clock to transition from a low to high. This is called the "rising edge" of the clock. Synchronous logic operates on clock edges rather than clock levels.
You mention that you should not have to look for a rising edge since the clock is in the sensitivity list, and thus if your process is executed you can only check the level of the clock. This may be theoretically true but synthesis tools work by inferring logic from the language used to describe it. Most synthesis tools I have used are designed to produce correct logic when described below.
process(clock, reset)
variable counter : std_logic_vector (15 downto 0) := x"0000";
variable op : std_logic_vector (7 downto 0);
begin
if reset = '1' then
-- reset everything to a known state here
elsif rising_edge(clock) then
op := cw(15 downto 8);
if op = x"20" then
counter := counter + cw(7 downto 0);
end if;
counter := counter + 2;
ia <= counter;
end if;
end process;
Writing good HDL is just as much about getting the logic correct as it is describing it in the way the synthesis tools are expecting to see it. If you decide "it's the same thing" and write things in a non-standard way you may well find that the simulator tells you one thing but the synthesizer fails to see it the same way. This is a fine point to learn, and one that can cause you a lot of headache and frustration should you decide otherwise.
How is a VHDL variable synthesized by synthesis tools has some useful information though it's not exactly a duplicate of your question IMO.
Just because something doesn't have a direct hardware representation doesn't mean it's not synthesizable.
When writing VHDL (and Verilog) for synthesis you typically write program code that defines what happens on each clock cycle. You can also write code that takes input signals and produces outputs from them as soon as any input changes without involving a clock.
The synthesis tool turns that block of code into a combination of logic operations (gates, multiplexers, adders, multipliers, etc which will later be mapped onto target specific resources) and registers. Logically that block of code can be though of as completing "instantly".
How does it do that? Well first off any loops are fully unrolled (you will get errors if you have loops with a number of iterations that can't be statically determined). Some variables (i.e. loop counters) are likely to disappear at this point.
Then the code is turned into a data flow form. The variables at this point are essentially labels telling the compiler what output feeds into what input. Each variable will become one or more signals representing it's value at different points in the code.
"if" statements and similar become multiplexers selecting which version of a signal should feed into later logic and/or registers.
If there is a path through the code where a given variable is read before being set and/or a path where the variable is not set at all then the final value of a variable from one pass through the code must be fed to the input of the next.
How exactly that happens depends on when the code is run. If the code runs on a clock edge then a clocked register will be created to feed the final value from one iteration to the initial value for the next. This is fine, the tools can handle it just like any other register.
If the code is not clock triggered then the output value will be fed directly back to the input creating what is essentially a "transparent latch". This is usually a bad thing! Transparent latches are very sensitive to input glitches and are difficult for timing analysers to handle. While most synthsis tools will synthesize this the results may well not match with simulation results and may be unredictable.
Best Answer
The type definition requires a constant to define the range. This is used during simulator compilation or during synthesis. It is fixed once the circuit, real or simulated, is operating.
Signals can change and are therefore not constant. Their value changes during circuit operation.
So the two are incompatible. Use a constant.
Your question doesn't describe why you want to do such a thing so I can't advise better solutions to it.