Where possible, add I/O components near the top level for design readability. When you infer a component, you provide a description of the function you want to accomplish. The synthesis tool then interprets the HDL code to determine which hardware components to use to perform the function. Components that can be inferred are simple single-ended I/O (IBUF, OBUF, OBUFT and IOBUF) and single data rate registers in the I/O.
When using the tool to infer IOBUF or OBUFT components, make sure that the enable logic and the input/output logic are all in the same hierarchy. If the logic is in different hierarchies and there are KEEP_HIERARCHY or DONT_TOUCH attributes between the hierarchies, the tool will not be able to infer these buffers.
I/O components that need to be instantiated, such as differential I/O (IBUFDS, OBUFDS) and double data-rate registers (IDDR, ODDR, ISERDES, OSERDES), should also be instantiated near the top level. When you instantiate a component, you add an instance of that component to your HDL file. Instantiation gives you full control over how the component is used. Therefore, you know exactly how the logic will be used.